diff --git a/dapps/templates/boilerplate/app/js/index.js b/dapps/templates/boilerplate/app/js/index.js index fc58b25d8..712199926 100644 --- a/dapps/templates/boilerplate/app/js/index.js +++ b/dapps/templates/boilerplate/app/js/index.js @@ -4,7 +4,14 @@ import EmbarkJS from 'Embark/EmbarkJS'; // e.g if you have a contract named SimpleStorage: //import SimpleStorage from 'Embark/contracts/SimpleStorage'; - EmbarkJS.onReady((err) => { // You can execute contract calls after the connection }); + +// OR if using "library: 'web3'" in config/contracts.js + +// import web3 from '../../embarkArtifacts/web3.js'; +// import SimpleStorage from '../embarkArtifacts/contracts/SimpleStorage'; +// web3.onReady(async () => { +// let accounts = await web3.eth.getAccounts(); +//}) diff --git a/dapps/templates/boilerplate/config/contracts.js b/dapps/templates/boilerplate/config/contracts.js index 381f53c76..be2ecfa9c 100644 --- a/dapps/templates/boilerplate/config/contracts.js +++ b/dapps/templates/boilerplate/config/contracts.js @@ -1,6 +1,8 @@ module.exports = { // default applies to all environments default: { + library: 'embarkjs', // can also be 'web3' + // order of connections the dapp should connect to dappConnection: [ "$EMBARK", diff --git a/dapps/templates/demo/config/contracts.js b/dapps/templates/demo/config/contracts.js index 9b0e36811..6ad40d66d 100644 --- a/dapps/templates/demo/config/contracts.js +++ b/dapps/templates/demo/config/contracts.js @@ -1,6 +1,8 @@ module.exports = { // default applies to all environments default: { + library: 'embarkjs', // can be also be 'web3' + // order of connections the dapp should connect to dappConnection: [ "$EMBARK", diff --git a/packages/core/core/src/configDefaults.ts b/packages/core/core/src/configDefaults.ts index d03fee8f8..35ab261c4 100644 --- a/packages/core/core/src/configDefaults.ts +++ b/packages/core/core/src/configDefaults.ts @@ -47,6 +47,7 @@ export function getContractDefaults(embarkConfigVersions) { return { default: { + library: "embarkjs", versions, dappConnection: [ "$WEB3", diff --git a/packages/core/engine/tsconfig.json b/packages/core/engine/tsconfig.json index 524505074..21885e9d0 100644 --- a/packages/core/engine/tsconfig.json +++ b/packages/core/engine/tsconfig.json @@ -22,6 +22,9 @@ { "path": "../../plugins/debugger" }, + { + "path": "../../plugins/embarkjs" + }, { "path": "../../plugins/ens" }, @@ -88,9 +91,6 @@ { "path": "../../stack/deployment" }, - { - "path": "../../stack/embarkjs" - }, { "path": "../../stack/library-manager" }, diff --git a/packages/embark/src/test/config.js b/packages/embark/src/test/config.js index 0b3e281e4..c5e4e03d2 100644 --- a/packages/embark/src/test/config.js +++ b/packages/embark/src/test/config.js @@ -212,6 +212,7 @@ describe('embark.Config', function () { dappConnection: ['$WEB3', 'ws://localhost:8546', 'localhost:8545'], dappAutoEnable: true, "gas": "400000", + "library": "embarkjs", "strategy": "implicit", "contracts": { "SimpleStorage": { @@ -234,6 +235,7 @@ describe('embark.Config', function () { dappConnection: ['$WEB3', 'ws://localhost:8546', 'localhost:8545'], dappAutoEnable: true, "gas": "auto", + "library": "embarkjs", "strategy": "implicit", "contracts": { "SimpleStorage": { diff --git a/packages/stack/embarkjs/.babelrc.js b/packages/plugins/embarkjs/.babelrc.js similarity index 100% rename from packages/stack/embarkjs/.babelrc.js rename to packages/plugins/embarkjs/.babelrc.js diff --git a/packages/stack/embarkjs/.npmrc b/packages/plugins/embarkjs/.npmrc similarity index 100% rename from packages/stack/embarkjs/.npmrc rename to packages/plugins/embarkjs/.npmrc diff --git a/packages/stack/embarkjs/CHANGELOG.md b/packages/plugins/embarkjs/CHANGELOG.md similarity index 100% rename from packages/stack/embarkjs/CHANGELOG.md rename to packages/plugins/embarkjs/CHANGELOG.md diff --git a/packages/stack/embarkjs/README.md b/packages/plugins/embarkjs/README.md similarity index 100% rename from packages/stack/embarkjs/README.md rename to packages/plugins/embarkjs/README.md diff --git a/packages/plugins/embarkjs/index.js b/packages/plugins/embarkjs/index.js new file mode 100644 index 000000000..cce693358 --- /dev/null +++ b/packages/plugins/embarkjs/index.js @@ -0,0 +1 @@ +module.exports = require('./dist'); diff --git a/packages/stack/embarkjs/package.json b/packages/plugins/embarkjs/package.json similarity index 91% rename from packages/stack/embarkjs/package.json rename to packages/plugins/embarkjs/package.json index c13c27115..35419fa4e 100644 --- a/packages/stack/embarkjs/package.json +++ b/packages/plugins/embarkjs/package.json @@ -4,7 +4,7 @@ "author": "Iuri Matias ", "contributors": [], "description": "EmbarkJS APIs for Embark", - "homepage": "https://github.com/embarklabs/embark/tree/master/packages/stack/embarkjs#readme", + "homepage": "https://github.com/embarklabs/embark/tree/master/packages/plugins/embarkjs#readme", "bugs": "https://github.com/embarklabs/embark/issues", "keywords": [ "blockchain", @@ -21,7 +21,7 @@ ], "license": "MIT", "repository": { - "directory": "packages/stack/embarkjs", + "directory": "packages/plugins/embarkjs", "type": "git", "url": "https://github.com/embarklabs/embark.git" }, @@ -50,7 +50,8 @@ "ejs": "2.6.1", "embark-core": "^5.3.0-nightly.7", "embark-i18n": "^5.3.0-nightly.5", - "embarkjs": "^5.3.0-nightly.6" + "embarkjs": "^5.3.0-nightly.6", + "web3": "1.2.6" }, "devDependencies": { "embark-solo": "^5.2.3", diff --git a/packages/stack/embarkjs/src/embarkjs-artifact.js.ejs b/packages/plugins/embarkjs/src/embarkjs-artifact.js.ejs similarity index 100% rename from packages/stack/embarkjs/src/embarkjs-artifact.js.ejs rename to packages/plugins/embarkjs/src/embarkjs-artifact.js.ejs diff --git a/packages/stack/embarkjs/src/embarkjs-console-contract.js.ejs b/packages/plugins/embarkjs/src/embarkjs-console-contract.js.ejs similarity index 100% rename from packages/stack/embarkjs/src/embarkjs-console-contract.js.ejs rename to packages/plugins/embarkjs/src/embarkjs-console-contract.js.ejs diff --git a/packages/stack/embarkjs/src/embarkjs-contract-artifact.js.ejs b/packages/plugins/embarkjs/src/embarkjs-contract-artifact.js.ejs similarity index 100% rename from packages/stack/embarkjs/src/embarkjs-contract-artifact.js.ejs rename to packages/plugins/embarkjs/src/embarkjs-contract-artifact.js.ejs diff --git a/packages/stack/embarkjs/src/index.js b/packages/plugins/embarkjs/src/index.js similarity index 74% rename from packages/stack/embarkjs/src/index.js rename to packages/plugins/embarkjs/src/index.js index 65487d1a1..7398b0375 100644 --- a/packages/stack/embarkjs/src/index.js +++ b/packages/plugins/embarkjs/src/index.js @@ -1,4 +1,5 @@ import {__} from 'embark-i18n'; +import Web3 from 'web3'; require('ejs'); const Templates = { @@ -9,17 +10,21 @@ const Templates = { class EmbarkJS { - constructor(embark, _options) { + constructor(embark) { this.embark = embark; this.embarkConfig = embark.config.embarkConfig; this.blockchainConfig = embark.config.blockchainConfig; this.events = embark.events; this.logger = embark.logger; + this.config = embark.config; this.contractArtifacts = {}; + this.enabled = true; - this.events.request("runcode:whitelist", 'embarkjs', () => { - this.registerEmbarkJS(); - }); + // note: since other plugins like ens currently expect these command handlers to exist + // we used a condition instead just returning immediatly so that the handlers still exist + if (!this.config.blockchainConfig.enabled || this.config.contractsConfig.library !== 'embarkjs') { + this.enabled = false; + } this.embarkJSPlugins = {}; this.customEmbarkJSPlugins = {}; @@ -46,11 +51,61 @@ class EmbarkJS { this.events.setCommandHandler("embarkjs:contract:generate", this.addContractArtifact.bind(this)); this.events.setCommandHandler("embarkjs:contract:runInVm", this.runInVm.bind(this)); + if (!this.enabled) return; + + this.events.request("runcode:whitelist", 'embarkjs', () => { + this.registerEmbarkJS(); + }); + embark.registerActionForEvent("pipeline:generateAll:before", this.addEmbarkJSArtifact.bind(this)); embark.registerActionForEvent("pipeline:generateAll:before", this.addContractIndexArtifact.bind(this)); + + this.setupEmbarkJS(); + + embark.registerActionForEvent("deployment:contract:deployed", {priority: 40}, this.registerInVm.bind(this)); + embark.registerActionForEvent("deployment:contract:undeployed", this.registerInVm.bind(this)); + embark.registerActionForEvent("deployment:contract:deployed", this.registerArtifact.bind(this)); + embark.registerActionForEvent("deployment:contract:undeployed", this.registerArtifact.bind(this)); + } + + async setupEmbarkJS() { + this.events.on("blockchain:started", async () => { + await this.registerWeb3Object(); + this.events.request("embarkjs:console:setProvider", 'blockchain', 'web3', '{web3}'); + }); + this.events.request("embarkjs:plugin:register", 'blockchain', 'web3', 'embarkjs-web3'); + await this.events.request2("embarkjs:console:register", 'blockchain', 'web3', 'embarkjs-web3'); + } + + async registerWeb3Object() { + if (!this.enabled) return; + const provider = await this.events.request2("blockchain:client:provider", "ethereum"); + const web3 = new Web3(provider); + this.events.request("runcode:whitelist", 'web3', () => {}); + await this.events.request2("runcode:register", 'web3', web3); + const accounts = await web3.eth.getAccounts(); + if (accounts.length) { + await this.events.request2('runcode:eval', `web3.eth.defaultAccount = '${accounts[0]}'`); + } + + this.events.request('console:register:helpCmd', { + cmdName: "web3", + cmdHelp: __("instantiated web3.js object configured to the current environment") + }, () => {}); + } + + async registerInVm(params, cb) { + if (!this.enabled) return; + this.events.request("embarkjs:contract:runInVm", params.contract, cb); + } + + registerArtifact(params, cb) { + if (!this.enabled) return; + this.events.request("embarkjs:contract:generate", params.contract, cb); } async registerEmbarkJS() { + if (!this.enabled) return; const checkEmbarkJS = `return (typeof EmbarkJS === 'undefined');`; const embarkJSNotDefined = await this.events.request2('runcode:eval', checkEmbarkJS); @@ -59,6 +114,7 @@ class EmbarkJS { } async registerEmbarkJSPlugin(stackName, pluginName, packageName, cb) { + if (!this.enabled) return cb(); await this.registerEmbarkJS(); let moduleName = stackName; @@ -77,6 +133,7 @@ class EmbarkJS { } async registerCustomEmbarkJSPluginInVm(stackName, pluginName, packageName, options, cb) { + if (!this.enabled) return cb(); await this.registerEmbarkJS(); const customPluginCode = ` @@ -92,6 +149,7 @@ class EmbarkJS { } addEmbarkJSArtifact(_params, cb) { + if (!this.enabled) return cb(); const embarkjsCode = Templates.embarkjs_artifact({ plugins: this.embarkJSPlugins, hasWebserver: this.embark.config.webServerConfig.enabled, @@ -108,6 +166,7 @@ class EmbarkJS { } async setProvider(stackName, pluginName, config) { + if (!this.enabled) return; let moduleName = stackName; if (moduleName === 'messages') moduleName = 'Messages'; if (moduleName === 'storage') moduleName = 'Storage'; @@ -136,6 +195,7 @@ class EmbarkJS { } async addContractArtifact(contract, cb) { + if (!this.enabled) return cb(); const abi = JSON.stringify(contract.abiDefinition); const gasLimit = 6000000; this.contractArtifacts[contract.className] = contract.className + '.js'; @@ -151,6 +211,7 @@ class EmbarkJS { } async addContractIndexArtifact(_options, cb) { + if (!this.enabled) return cb(); let indexCode = 'module.exports = {'; Object.keys(this.contractArtifacts).forEach(className => { indexCode += `\n"${className}": require('./${this.contractArtifacts[className]}').default,`; @@ -166,6 +227,7 @@ class EmbarkJS { } async runInVm(contract, cb) { + if (!this.enabled) return cb(); const abi = contract.abiDefinition; const gasLimit = 6000000; const provider = await this.events.request2("blockchain:client:provider", "ethereum"); diff --git a/packages/stack/embarkjs/tsconfig.json b/packages/plugins/embarkjs/tsconfig.json similarity index 100% rename from packages/stack/embarkjs/tsconfig.json rename to packages/plugins/embarkjs/tsconfig.json diff --git a/packages/plugins/specialconfigs/src/functionConfigs.js b/packages/plugins/specialconfigs/src/functionConfigs.js index 00adc358d..83769dacb 100644 --- a/packages/plugins/specialconfigs/src/functionConfigs.js +++ b/packages/plugins/specialconfigs/src/functionConfigs.js @@ -99,12 +99,6 @@ class FunctionConfigs { // TODO: for this to work correctly we need to add a default from address to the contract if (contract.deploy === false) continue; // eslint-disable-next-line no-await-in-loop - const contractRegisteredInVM = await this.checkContractRegisteredInVM(contract); - if (!contractRegisteredInVM) { - // eslint-disable-next-line no-await-in-loop - await this.events.request2("embarkjs:contract:runInVm", contract); - } - // eslint-disable-next-line no-await-in-loop let contractInstance = await this.events.request2("runcode:eval", contract.className); args.contracts[contract.className] = contractInstance; } diff --git a/packages/plugins/web3/src/vanilla-contract.js.ejs b/packages/plugins/web3/src/console-contract.js.ejs similarity index 78% rename from packages/plugins/web3/src/vanilla-contract.js.ejs rename to packages/plugins/web3/src/console-contract.js.ejs index 908d5769e..00f027868 100644 --- a/packages/plugins/web3/src/vanilla-contract.js.ejs +++ b/packages/plugins/web3/src/console-contract.js.ejs @@ -1,4 +1,5 @@ -<%- className %>Abi = <%- abi %>; +<%- className %>Config = <%- JSON.stringify(contract) %>; +<%- className %>Abi = <%- JSON.stringify(abi) %>; <%- className %> = new web3.eth.Contract(<%- className %>Abi); <%- className %>.options.address = '<%- contract.deployedAddress %>'; <%- className %>.address = '<%- contract.deployedAddress %>'; diff --git a/packages/plugins/web3/src/contract-artifact.js.ejs b/packages/plugins/web3/src/contract-artifact.js.ejs index 8dbdccd40..787baa75c 100644 --- a/packages/plugins/web3/src/contract-artifact.js.ejs +++ b/packages/plugins/web3/src/contract-artifact.js.ejs @@ -1,4 +1,4 @@ -const web3 = require("./web3_init.js").default +const web3 = require("../web3.js").default let <%- className %>Abi = <%- abi %>; let <%- className %> = new web3.eth.Contract(<%- className %>Abi); @@ -6,7 +6,7 @@ let <%- className %> = new web3.eth.Contract(<%- className %>Abi); <%- className %>.address = '<%- contract.deployedAddress %>'; <%- className %>.options.from = web3.eth.defaultAccount; -web3.execWhenReady(() => { +web3.onReady(() => { <%- className %>.options.from = web3.eth.defaultAccount; if (!<%- className %>.currentProvider) { <%- className %>.setProvider(web3.currentProvider); diff --git a/packages/plugins/web3/src/embarkjs-contract-artifact.js.ejs b/packages/plugins/web3/src/embarkjs-contract-artifact.js.ejs deleted file mode 100644 index b913a39bd..000000000 --- a/packages/plugins/web3/src/embarkjs-contract-artifact.js.ejs +++ /dev/null @@ -1,6 +0,0 @@ -import EmbarkJS from '../embarkjs': - -const <%- className %>Config = <%- JSON.stringify(contract) %>; -const <%- className %> = new EmbarkJS.Blockchain.Contract(<%- className %>Config); - -export default <%- className %>; diff --git a/packages/plugins/web3/src/index.js b/packages/plugins/web3/src/index.js index 955953334..9ff16acb7 100644 --- a/packages/plugins/web3/src/index.js +++ b/packages/plugins/web3/src/index.js @@ -2,39 +2,40 @@ const {__} = require('embark-i18n'); const Web3 = require('web3'); require('ejs'); -// const Templates = { -// vanilla_contract: require('./vanilla-contract.js.ejs'), -// contract_artifact: require('./contract-artifact.js.ejs'), -// web3_init: require('./web3_init.js.ejs') -// }; +const Templates = { + contract_artifact: require('./contract-artifact.js.ejs'), + web3_init: require('./web3_init.js.ejs'), + console_contract: require('./console-contract.js.ejs') +}; + +const GAS_LIMIT = 6000000; class EmbarkWeb3 { - constructor(embark, _options) { + constructor(embark) { this.embarkConfig = embark.config.embarkConfig; + this.contractsConfig = embark.config.contractsConfig; this.embark = embark; this.logger = embark.logger; this.events = embark.events; this.config = embark.config; + this.contractArtifacts = {}; - if (this.config.blockchainConfig.enabled) { - this.setupEmbarkJS(); + if (!this.config.blockchainConfig.enabled || this.config.contractsConfig.library !== 'web3') { + return; } + this.events.on("blockchain:started", async () => { + await this.registerWeb3Object(); + }); + + embark.registerActionForEvent("pipeline:generateAll:before", this.addWeb3JSArtifact.bind(this)); + embark.registerActionForEvent("deployment:contract:deployed", {priority: 40}, this.registerInVm.bind(this)); embark.registerActionForEvent("deployment:contract:undeployed", this.registerInVm.bind(this)); embark.registerActionForEvent("deployment:contract:deployed", this.registerArtifact.bind(this)); embark.registerActionForEvent("deployment:contract:undeployed", this.registerArtifact.bind(this)); } - async setupEmbarkJS() { - this.events.on("blockchain:started", async () => { - await this.registerWeb3Object(); - this.events.request("embarkjs:console:setProvider", 'blockchain', 'web3', '{web3}'); - }); - this.events.request("embarkjs:plugin:register", 'blockchain', 'web3', 'embarkjs-web3'); - await this.events.request2("embarkjs:console:register", 'blockchain', 'web3', 'embarkjs-web3'); - } - async registerWeb3Object() { const provider = await this.events.request2("blockchain:client:provider", "ethereum"); const web3 = new Web3(provider); @@ -52,11 +53,59 @@ class EmbarkWeb3 { } async registerInVm(params, cb) { - this.events.request("embarkjs:contract:runInVm", params.contract, cb); + const contract = params.contract; + const abi = contract.abiDefinition; + const gasLimit = GAS_LIMIT; + const provider = await this.events.request2("blockchain:client:provider", "ethereum"); + const contractCode = Templates.console_contract({ className: contract.className, abi: abi, contract: contract, gasLimit: gasLimit, provider: provider }); + + try { + await this.events.request2('runcode:eval', contractCode); + const result = await this.events.request2('runcode:eval', contract.className); + result.currentProvider = provider; + await this.events.request2("runcode:register", contract.className, result); + } catch (err) { + return cb(err); + } + cb(); } registerArtifact(params, cb) { - this.events.request("embarkjs:contract:generate", params.contract, cb); + const contract = params.contract; + const abi = JSON.stringify(contract.abiDefinition); + const gasLimit = GAS_LIMIT; + this.contractArtifacts[contract.className] = contract.className + '.js'; + + const contractCode = Templates.contract_artifact({ className: contract.className, abi: abi, contract: contract, gasLimit: gasLimit }); + + this.events.request("pipeline:register", { + path: [this.embarkConfig.generationDir, 'contracts'], + file: contract.className + '.js', + format: 'js', + content: contractCode + }, cb); + } + + async addWeb3JSArtifact(_params, cb) { + const dappConnection = this.contractsConfig.dappConnection; + + if (dappConnection.includes('$EMBARK')) { + let endpoint = await this.events.request2('proxy:endpoint:get'); + dappConnection[dappConnection.indexOf('$EMBARK')] = endpoint; + } + + const web3jsCode = Templates.web3_init({ + connectionList: this.contractsConfig.dappConnection, + autoEnable: this.contractsConfig.dappAutoEnable + }); + + // TODO: generate a .node file + this.events.request("pipeline:register", { + path: [this.embarkConfig.generationDir], + file: 'web3.js', + format: 'js', + content: web3jsCode + }, cb); } } diff --git a/packages/plugins/web3/src/web3_init.js.ejs b/packages/plugins/web3/src/web3_init.js.ejs index e5d0e2f2f..5d8aaaa59 100644 --- a/packages/plugins/web3/src/web3_init.js.ejs +++ b/packages/plugins/web3/src/web3_init.js.ejs @@ -5,7 +5,7 @@ let web3 = new Web3(); let todo = []; let done = false; -web3.execWhenReady = function(cb) { +web3.onReady = function(cb) { if (done) { return cb(); } @@ -46,7 +46,7 @@ let doConnect = function(connectionList, opts, doneCb) { if (typeof window !== 'undefined' && window.ethereum) { try { - if (Blockchain.autoEnable) { + if (opts.autoEnable) { await ethereum.enable(); } blockchainConnector.setProvider(ethereum); @@ -138,6 +138,7 @@ __whenEnvIsLoaded(() => { let connectList = [<%- connectionList.map(x => "'" + x + "'").join(",") %>]; doConnect(connectList, { + autoEnable: <%- autoEnable %>, warnAboutMetamask: false, // TODO: can/should be part as the code generation instead... }, () => { todo.forEach((x) => x.apply(x)) diff --git a/packages/stack/blockchain/src/index.js b/packages/stack/blockchain/src/index.js index bb2fb2143..317968c70 100644 --- a/packages/stack/blockchain/src/index.js +++ b/packages/stack/blockchain/src/index.js @@ -198,7 +198,8 @@ export default class Blockchain { return cb(err); } const config = { - provider: contractsConfig.library || 'web3', + provider: 'web3', + library: contractsConfig.library || 'embarkjs', dappConnection: results, dappAutoEnable: contractsConfig.dappAutoEnable, warnIfMetamask: this.blockchainConfig.isDev, diff --git a/tsconfig.json b/tsconfig.json index df745aef6..b0148a302 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -64,6 +64,9 @@ { "path": "packages/plugins/deploy-tracker" }, + { + "path": "packages/plugins/embarkjs" + }, { "path": "packages/plugins/ens" }, @@ -166,9 +169,6 @@ { "path": "packages/stack/deployment" }, - { - "path": "packages/stack/embarkjs" - }, { "path": "packages/stack/library-manager" },