diff --git a/.prettierrc.json b/.prettierrc.json index 1513817e2a..07681f5b0a 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,5 +1,7 @@ { "tabWidth": 2, + "printWidth": 500, + "bracketSpacing": false, "useTabs": false, "semi": false, "singleQuote": true, diff --git a/README.md b/README.md index 00ebb8c51d..a1c4a4e1b6 100644 --- a/README.md +++ b/README.md @@ -279,7 +279,6 @@ parameters: default: true ``` - ## Important Links - Official website: https://remix-project.org diff --git a/apps/compile-details/project.json b/apps/compile-details/project.json new file mode 100644 index 0000000000..7d512b6137 --- /dev/null +++ b/apps/compile-details/project.json @@ -0,0 +1,61 @@ +{ + "name": "compile-details", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "apps/compile-details/src", + "projectType": "application", + "implicitDependencies": [ + ], + "targets": { + "build": { + "executor": "@nrwl/webpack:webpack", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "development", + "options": { + "compiler": "babel", + "outputPath": "dist/apps/compile-details", + "index": "apps/compile-details/src/index.html", + "baseHref": "./", + "main": "apps/compile-details/src/main.tsx", + "tsConfig": "apps/compile-details/tsconfig.app.json", + "assets": [ + "apps/compile-details/src/favicon.ico", + "apps/compile-details/src/profile.json" + ], + "styles": [], + "scripts": [], + "webpackConfig": "apps/compile-details/webpack.config.js" + }, + "configurations": { + "development": { + }, + "production": { + "fileReplacements": [ + { + "replace": "apps/compile-details/src/environments/environment.ts", + "with": "apps/compile-details/src/environments/environment.prod.ts" + } + ] + } + } + }, + "serve": { + "executor": "@nrwl/webpack:dev-server", + "defaultConfiguration": "development", + "options": { + "buildTarget": "compile-details:build", + "hmr": true, + "baseHref": "/" + }, + "configurations": { + "development": { + "buildTarget": "compile-details:build:development", + "port": 6003 + }, + "production": { + "buildTarget": "compile-details:build:production" + } + } + } + }, + "tags": [] +} diff --git a/apps/compile-details/src/index.html b/apps/compile-details/src/index.html new file mode 100644 index 0000000000..6f9d486efb --- /dev/null +++ b/apps/compile-details/src/index.html @@ -0,0 +1,13 @@ + + + + + Compilation Details + + + + + +
+ + diff --git a/apps/compile-details/tsconfig.app.json b/apps/compile-details/tsconfig.app.json new file mode 100644 index 0000000000..af84f21cfc --- /dev/null +++ b/apps/compile-details/tsconfig.app.json @@ -0,0 +1,23 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node"] + }, + "files": [ + "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", + "../../node_modules/@nrwl/react/typings/image.d.ts" + ], + "exclude": [ + "jest.config.ts", + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/apps/compile-details/tsconfig.json b/apps/compile-details/tsconfig.json new file mode 100644 index 0000000000..5aab5e7911 --- /dev/null +++ b/apps/compile-details/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/apps/compile-details/webpack.config.js b/apps/compile-details/webpack.config.js new file mode 100644 index 0000000000..86bcf51395 --- /dev/null +++ b/apps/compile-details/webpack.config.js @@ -0,0 +1,70 @@ +const { composePlugins, withNx } = require('@nrwl/webpack') +const { withReact } = require('@nrwl/react') +const webpack = require('webpack') +const TerserPlugin = require('terser-webpack-plugin') +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') + +// Nx plugins for webpack. +module.exports = composePlugins(withNx(), withReact(), config => { + // Update the webpack config as needed here. + // e.g. `config.plugins.push(new MyPlugin())` + + // add fallback for node modules + config.resolve.fallback = { + ...config.resolve.fallback, + path: require.resolve('path-browserify'), + fs: false, + } + + // add externals + config.externals = { + ...config.externals, + solc: 'solc', + } + + config.module.rules.push({ + test: /\.hbs$/, + type: 'asset/source', + }) + + // add public path + config.output.publicPath = '/' + + // add copy & provide plugin + config.plugins.push( + new webpack.ProvidePlugin({ + Buffer: ['buffer', 'Buffer'], + url: ['url', 'URL'], + process: 'process/browser', + }), + new webpack.DefinePlugin({}), + ) + + // souce-map loader + config.module.rules.push({ + test: /\.js$/, + use: ['source-map-loader'], + enforce: 'pre', + }) + + config.ignoreWarnings = [/Failed to parse source map/] // ignore source-map-loader warnings + + // set minimizer + config.optimization.minimizer = [ + new TerserPlugin({ + parallel: true, + terserOptions: { + ecma: 2015, + compress: false, + mangle: false, + format: { + comments: false, + }, + }, + extractComments: false, + }), + new CssMinimizerPlugin(), + ] + + return config +}) diff --git a/apps/remix-ide-e2e/src/commands/clickInstance.ts b/apps/remix-ide-e2e/src/commands/clickInstance.ts index 4da4b51b05..8255659161 100644 --- a/apps/remix-ide-e2e/src/commands/clickInstance.ts +++ b/apps/remix-ide-e2e/src/commands/clickInstance.ts @@ -5,7 +5,11 @@ class ClickInstance extends EventEmitter { command (this: NightwatchBrowser, index: number): NightwatchBrowser { const selector = `[data-id="universalDappUiTitleExpander${index}"]` - this.api.waitForElementPresent(selector).waitForElementContainsText(selector, '', 60000).scrollAndClick(selector).perform(() => { this.emit('complete') }) + this.api.waitForElementPresent({ + locateStrategy: 'css selector', + selector, + timeout: 60000 + }).waitForElementContainsText(selector, '', 60000).scrollAndClick(selector).perform(() => { this.emit('complete') }) return this } } diff --git a/apps/remix-ide-e2e/src/commands/verifyCallReturnValue.ts b/apps/remix-ide-e2e/src/commands/verifyCallReturnValue.ts index fdc229ccd5..625d3dcac8 100644 --- a/apps/remix-ide-e2e/src/commands/verifyCallReturnValue.ts +++ b/apps/remix-ide-e2e/src/commands/verifyCallReturnValue.ts @@ -15,7 +15,13 @@ class VerifyCallReturnValue extends EventEmitter { } function verifyCallReturnValue (browser: NightwatchBrowser, address: string, checks: string[] | callbackCheckVerifyCallReturnValue, done: VoidFunction) { - browser.execute(function (address: string) { + browser + .waitForElementVisible({ + locateStrategy: 'css selector', + selector: '#instance' + address + ' [data-id="udapp_value"]', + timeout: 240000 + }) + .execute(function (address: string) { const nodes = document.querySelectorAll('#instance' + address + ' [data-id="udapp_value"]') as NodeListOf const ret = [] for (let k = 0; k < nodes.length; k++) { diff --git a/apps/remix-ide-e2e/src/commands/verifyContracts.ts b/apps/remix-ide-e2e/src/commands/verifyContracts.ts index 718b3a84e2..559780fdd7 100644 --- a/apps/remix-ide-e2e/src/commands/verifyContracts.ts +++ b/apps/remix-ide-e2e/src/commands/verifyContracts.ts @@ -25,38 +25,40 @@ function verifyContracts (browser: NightwatchBrowser, compiledContractNames: str .click('*[data-id="compilation-details"]') .waitForElementVisible('*[data-id="remixui_treeviewitem_metadata"]') .pause(2000) - .click('*[data-id="remixui_treeviewitem_metadata"]') .waitForElementVisible('*[data-id="treeViewDivtreeViewItemcompiler"]') .pause(2000) .click('*[data-id="treeViewDivtreeViewItemcompiler"]') .waitForElementVisible('*[data-id="treeViewLiversion"]') - .assert.containsText('*[data-id="treeViewLiversion"]', `${opts.version}`) - .click('[data-id="workspacesModalDialog-modal-footer-cancel-react"]') + .waitForElementContainsText('*[data-id="treeViewLiversion"]', `${opts.version}`) + .waitForElementVisible('*[id="compileDetails"]') + .waitForElementVisible('*[data-path="compilationDetails"]') + .click('*[data-id="close_compilationDetails"]') .perform(() => { done() callback() }) } if (opts.runs) { browser - .click('*[data-id="compilation-details"]') - .waitForElementVisible('*[data-id="remixui_treeviewitem_metadata"]') - .pause(2000) - .click('*[data-id="remixui_treeviewitem_metadata"]') - .waitForElementVisible('*[data-id="treeViewDivtreeViewItemsettings"]') - .pause(2000) - .click('*[data-id="treeViewDivtreeViewItemsettings"]') - .waitForElementVisible('*[data-id="treeViewDivtreeViewItemoptimizer"]') - .click('*[data-id="treeViewDivtreeViewItemoptimizer"]') - .waitForElementVisible('*[data-id="treeViewDivruns"]') - .assert.containsText('*[data-id="treeViewDivruns"]', `${opts.runs}`) - .click('[data-id="workspacesModalDialog-modal-footer-cancel-react"]') - .perform(() => { - done() - callback() - }) + .click('*[data-id="compilation-details"]') + .waitForElementVisible('*[data-id="remixui_treeviewitem_metadata"]') + .pause(2000) + .assert.visible('*[data-id="treeViewDivtreeViewItemsettings"]') + .pause(2000) + .click('*[data-id="treeViewDivtreeViewItemsettings"]') + .waitForElementVisible('*[data-id="treeViewDivtreeViewItemoptimizer"]') + .click('*[data-id="treeViewDivtreeViewItemoptimizer"]') + .waitForElementVisible('*[data-id="treeViewDivruns"]') + .waitForElementContainsText('*[data-id="treeViewDivruns"]', `${opts.runs}`) + .waitForElementVisible('*[id="compileDetails"]') + .waitForElementVisible('*[data-id="close_compilationDetails"]') + .click('*[data-id="close_compilationDetails"]') + .perform(() => { + done() + callback() + }) } else { for (const index in compiledContractNames) { - await browser.waitForElementContainsText('[data-id="compiledContracts"]', compiledContractNames[index], 60000) + await browser.waitForElementContainsText('[data-id="compiledContracts"]', compiledContractNames[index], 60000) } done() callback() diff --git a/apps/remix-ide-e2e/src/tests/ballot.test.ts b/apps/remix-ide-e2e/src/tests/ballot.test.ts index f3f3de3273..c2a79e9490 100644 --- a/apps/remix-ide-e2e/src/tests/ballot.test.ts +++ b/apps/remix-ide-e2e/src/tests/ballot.test.ts @@ -34,7 +34,7 @@ module.exports = { .clickFunction('delegate - transact (not payable)', { types: 'address to', values: '"0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db"' }) .testFunction('last', { - status: 'true Transaction mined and execution succeed', + status: '0x1 Transaction mined and execution succeed', 'decoded input': { 'address to': '0x4B0897b0513fdC7C541B6d9D7E929C4e5364D2dB' } }) }, @@ -87,7 +87,7 @@ module.exports = { .clickFunction('delegate - transact (not payable)', { types: 'address to', values: '"0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db"' }) .testFunction('last', { - status: 'false Transaction mined but execution failed', + status: '0x0 Transaction mined but execution failed', 'decoded input': { 'address to': '0x4B0897b0513fdC7C541B6d9D7E929C4e5364D2dB' } }) }, diff --git a/apps/remix-ide-e2e/src/tests/ballot_0_4_14.test.ts b/apps/remix-ide-e2e/src/tests/ballot_0_4_14.test.ts index 85c7aa75e9..09398a8968 100644 --- a/apps/remix-ide-e2e/src/tests/ballot_0_4_14.test.ts +++ b/apps/remix-ide-e2e/src/tests/ballot_0_4_14.test.ts @@ -43,7 +43,7 @@ module.exports = { .clickFunction('delegate - transact (not payable)', { types: 'address to', values: '"0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db"' }) .testFunction('last', { - status: 'true Transaction mined and execution succeed', + status: '0x1 Transaction mined and execution succeed', 'decoded input': { 'address to': '0x4B0897b0513fdC7C541B6d9D7E929C4e5364D2dB' } }) }, @@ -83,7 +83,7 @@ module.exports = { .clickFunction('delegate - transact (not payable)', { types: 'address to', values: '"0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db"' }) .testFunction('last', { - status: 'true Transaction mined and execution succeed', + status: '0x1 Transaction mined and execution succeed', 'decoded input': { 'address to': '0x4B0897b0513fdC7C541B6d9D7E929C4e5364D2dB' } }) }, diff --git a/apps/remix-ide-e2e/src/tests/erc721.test.ts b/apps/remix-ide-e2e/src/tests/erc721.test.ts index d88e3dae9b..373477f064 100644 --- a/apps/remix-ide-e2e/src/tests/erc721.test.ts +++ b/apps/remix-ide-e2e/src/tests/erc721.test.ts @@ -61,7 +61,7 @@ module.exports = { .createContract('') .testFunction('last', { - status: 'true Transaction mined and execution succeed', + status: '0x1 Transaction mined and execution succeed', 'decoded input': {} }).end() } diff --git a/apps/remix-ide-e2e/src/tests/plugin_api.ts b/apps/remix-ide-e2e/src/tests/plugin_api.ts index 79cc466c76..c0bbb316e9 100644 --- a/apps/remix-ide-e2e/src/tests/plugin_api.ts +++ b/apps/remix-ide-e2e/src/tests/plugin_api.ts @@ -31,12 +31,7 @@ const debugValues = async function (browser: NightwatchBrowser, field: string, e return } browser.waitForElementVisible(`//*[@id="${field}"]`).getText(`//*[@id="${field}"]`, (result) => { - console.log(result) if (!result.value.toString().includes(expected)) { - console.log('Actual result:') - console.log(result.value.toString()) - console.log('Expected result:') - console.log(expected) getBrowserLogs(browser) browser.assert.ok(false, 'Returned value from call does not match expected value.') } else { diff --git a/apps/remix-ide-e2e/src/tests/recorder.test.ts b/apps/remix-ide-e2e/src/tests/recorder.test.ts index 17363edbfc..0d7b038b26 100644 --- a/apps/remix-ide-e2e/src/tests/recorder.test.ts +++ b/apps/remix-ide-e2e/src/tests/recorder.test.ts @@ -96,7 +96,7 @@ module.exports = { .pause(1000) .clickFunction('set2 - transact (not payable)', { types: 'uint256 _po', values: '10' }) .testFunction('last', { - status: 'true Transaction mined and execution succeed', + status: '0x1 Transaction mined and execution succeed', 'decoded input': { 'uint256 _po': '10' } }) }, diff --git a/apps/remix-ide-e2e/src/tests/remixd.test.ts b/apps/remix-ide-e2e/src/tests/remixd.test.ts index e8155e05e6..758e436001 100644 --- a/apps/remix-ide-e2e/src/tests/remixd.test.ts +++ b/apps/remix-ide-e2e/src/tests/remixd.test.ts @@ -250,7 +250,7 @@ module.exports = { .createContract('') .testFunction('last', { - status: 'true Transaction mined and execution succeed' + status: '0x1 Transaction mined and execution succeed' }) diff --git a/apps/remix-ide-e2e/src/tests/runAndDeploy.test.ts b/apps/remix-ide-e2e/src/tests/runAndDeploy.test.ts index 1b382a4290..1cc93342bc 100644 --- a/apps/remix-ide-e2e/src/tests/runAndDeploy.test.ts +++ b/apps/remix-ide-e2e/src/tests/runAndDeploy.test.ts @@ -61,7 +61,7 @@ module.exports = { .click('*[data-id="Deploy - transact (not payable)"]') .pause(5000) .testFunction('last', { - status: 'true Transaction mined and execution succeed' + status: '0x1 Transaction mined and execution succeed' }) }, @@ -95,7 +95,7 @@ module.exports = { .click('*[data-id="pluginManagerSettingsDeployAndRunLLTxSendTransaction"]') .pause(5000) .testFunction('last', { - status: 'true Transaction mined and execution succeed' + status: '0x1 Transaction mined and execution succeed' }) // When this is removed and tests are running by connecting to metamask // Consider adding tests to check return value of contract call diff --git a/apps/remix-ide-e2e/src/tests/terminal.test.ts b/apps/remix-ide-e2e/src/tests/terminal.test.ts index 949cfbf913..aab3f4e944 100644 --- a/apps/remix-ide-e2e/src/tests/terminal.test.ts +++ b/apps/remix-ide-e2e/src/tests/terminal.test.ts @@ -291,6 +291,11 @@ module.exports = { browser .clickLaunchIcon('udapp') .switchEnvironment('vm-mainnet-fork') + .waitForElementPresent({ + locateStrategy: 'css selector', + selector: 'select[data-id="runTabSelectAccount"] option[value="0xdD870fA1b7C4700F2BD7f44238821C26f7392148"]', + timeout: 240000 + }) .executeScriptInTerminal(`web3.eth.getCode('0x180587b00c8642e2c7ac3a758712d97e6f7bdcc7')`) // mainnet contract .waitForElementContainsText('*[data-id="terminalJournal"]', '0x608060405260043610601f5760003560e01c80635c60da1b14603157602b565b36602b576029605f565b005b6029605f565b348015603c57600080fd5b5060436097565b6040516001600160a01b03909116815260200160405180910390f35b609560917f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b60d1565b565b600060c97f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b90565b3660008037600080366000845af43d6000803e80801560ef573d6000f35b3d6000fdfea2646970667358221220969dbb4b1d8aec2bb348e26488dc1a33b6bcf0190f567d161312ab7ca9193d8d64736f6c63430008110033', 120000) }, @@ -298,6 +303,11 @@ module.exports = { 'Should connect to the sepolia fork and run web3.eth.getCode in the terminal #group9': function (browser: NightwatchBrowser) { browser .switchEnvironment('vm-custom-fork') + .waitForElementPresent({ + locateStrategy: 'css selector', + selector: 'select[data-id="runTabSelectAccount"] option[value="0xdD870fA1b7C4700F2BD7f44238821C26f7392148"]', + timeout: 240000 + }) .waitForElementPresent('[data-id="vm-custom-fork-modal-footer-ok-react"]') .execute(() => { (document.querySelector('*[data-id="vm-custom-forkModalDialogContainer-react"] input[data-id="CustomForkNodeUrl"]') as any).focus() @@ -757,7 +767,7 @@ const scriptBlockAndTransaction = ` (async () => { try { web3.eth.getTransaction('0x022ccd55747677ac50f8d9dfd1bf5b843fa2f36438a28c1d0a0958e057bb3e2a').then(console.log) - web3.eth.getBlock('7367447').then(console.log); + web3.eth.getBlock(7367447).then(console.log); let ethersProvider = new ethers.providers.Web3Provider(web3Provider) ethersProvider.getBlock(7367447).then(console.log) } catch (e) { diff --git a/apps/remix-ide-e2e/src/tests/transactionExecution.test.ts b/apps/remix-ide-e2e/src/tests/transactionExecution.test.ts index c5fc0d8815..6bfd310b15 100644 --- a/apps/remix-ide-e2e/src/tests/transactionExecution.test.ts +++ b/apps/remix-ide-e2e/src/tests/transactionExecution.test.ts @@ -20,13 +20,13 @@ module.exports = { .clickFunction('f - transact (not payable)') .testFunction('last', { - status: 'true Transaction mined and execution succeed', + status: '0x1 Transaction mined and execution succeed', 'decoded output': { 0: 'uint256: 8' } }) .clickFunction('g - transact (not payable)') .testFunction('last', { - status: 'true Transaction mined and execution succeed', + status: '0x1 Transaction mined and execution succeed', 'decoded output': { 0: 'uint256: 345', 1: 'string: comment_comment_', @@ -45,7 +45,7 @@ module.exports = { .clickFunction('retunValues1 - transact (not payable)') .testFunction('last', { - status: 'true Transaction mined and execution succeed', + status: '0x1 Transaction mined and execution succeed', 'decoded output': { 0: 'bool: _b true', 1: 'uint256: _u 345', @@ -56,7 +56,7 @@ module.exports = { .clickFunction('retunValues2 - transact (not payable)') .testFunction('last', { - status: 'true Transaction mined and execution succeed', + status: '0x1 Transaction mined and execution succeed', 'decoded output': { 0: 'bytes1: _b 0x12', 1: 'bytes2: _b2 0x1223', @@ -73,7 +73,7 @@ module.exports = { .clickFunction('retunValues3 - transact (not payable)') .testFunction('last', { - status: 'true Transaction mined and execution succeed', + status: '0x1 Transaction mined and execution succeed', 'decoded output': { 0: 'uint8: _en 2', 1: 'int256[5][]: _a1 1,-45,-78,56,60,-1,42,334,-45455,-446,1,10,-5435,45,-7' @@ -89,7 +89,7 @@ module.exports = { .clickFunction('inputValue1 - transact (not payable)', { types: 'uint256 _u, int256 _i, string _str', values: '"2343242", "-4324324", "string _ string _ string _ string _ string _ string _ string _ string _ string _ string _"' }) .testFunction('last', { - status: 'true Transaction mined and execution succeed', + status: '0x1 Transaction mined and execution succeed', 'decoded output': { 0: 'uint256: _uret 2343242', 1: 'int256: _iret -4324324', @@ -99,7 +99,7 @@ module.exports = { .pause(500) .clickFunction('inputValue2 - transact (not payable)', { types: 'uint256[3] _n, bytes8[4] _b8', values: '[1,2,3], ["0x1234000000000000", "0x1234000000000000","0x1234000000000000","0x1234000000000000"]' }) .testFunction('last', { - status: 'true Transaction mined and execution succeed', + status: '0x1 Transaction mined and execution succeed', 'decoded output': { 0: 'uint256[3]: _nret 1,2,3', 1: 'bytes8[4]: _b8ret 0x1234000000000000,0x1234000000000000,0x1234000000000000,0x1234000000000000' @@ -147,7 +147,7 @@ module.exports = { .clickFunction('inputValue3 - transact (not payable)', { types: 'uint256[] _u', values: '["2.445e10", "13e1"]' }) .waitForElementContainsText('*[data-id="terminalJournal"]', '24450000000', 60000) .waitForElementContainsText('*[data-id="terminalJournal"]', '130', 60000) - .click('*[data-id="deployAndRunClearInstances"]') + .click('*[data-id="deployAndRunClearInstances"]') }, 'Should Compile and Deploy a contract which define a custom error, the error should be logged in the terminal #group3': function (browser: NightwatchBrowser) { @@ -222,7 +222,7 @@ module.exports = { .clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '24' }) .testFunction('last', // we check if the contract is actually reachable. { - status: 'true Transaction mined and execution succeed', + status: '0x1 Transaction mined and execution succeed', 'decoded input': { 'uint256 num': '24' } @@ -237,7 +237,11 @@ module.exports = { .setSolidityCompilerVersion('soljson-v0.8.17+commit.8df45f5f.js') .clickLaunchIcon('udapp') .switchEnvironment('vm-mainnet-fork') - .waitForElementPresent('select[data-id="runTabSelectAccount"] option[value="0xdD870fA1b7C4700F2BD7f44238821C26f7392148"]') // wait for the udapp to load the list of accounts + .waitForElementPresent({ + locateStrategy: 'css selector', + selector: 'select[data-id="runTabSelectAccount"] option[value="0xdD870fA1b7C4700F2BD7f44238821C26f7392148"]', + timeout: 250000 + }) // wait for the udapp to load the list of accounts .selectContract('MyResolver') .createContract('') .clickInstance(0) @@ -381,7 +385,7 @@ contract C { content: `// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; - + /// error description /// @param a param1 /// @param b param2 @@ -393,7 +397,7 @@ contract C { } function g() public { revert CustomError(2, 3, "error_string_2"); - } + } }` } }, @@ -402,7 +406,7 @@ contract C { content: `// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; - + library lib { /// error description from library /// @param a param1 from library @@ -411,13 +415,13 @@ contract C { error CustomError(uint a, uint b, string c); function set() public { revert CustomError(48, 46, "error_string_from_library"); - } - } - + } + } + contract D { function h() public { lib.set(); - } + } }` } }, @@ -435,10 +439,10 @@ contract C { contract Owner { address private owner; - + // event for EVM logging event OwnerSet(address indexed oldOwner, address indexed newOwner); - + // modifier to check if caller is owner modifier isOwner() { // If the first argument of 'require' evaluates to 'false', execution terminates and all @@ -449,7 +453,7 @@ contract C { require(msg.sender == owner, "Caller is not owner"); _; } - + /** * @dev Set contract deployer as owner */ @@ -468,7 +472,7 @@ contract C { } /** - * @dev Return owner address + * @dev Return owner address * @return address of owner */ function getOwner() external view returns (address) { @@ -503,7 +507,7 @@ contract C { } /** - * @dev Return value + * @dev Return value * @return value of 'number' */ function retrieve() public view returns (uint256){ @@ -535,7 +539,7 @@ contract C { return resolver.addr(node); } } - ` + ` } }, { "scientific_notation.sol": { @@ -567,7 +571,7 @@ contract C { cake++; } } - ` + ` } } ] diff --git a/apps/remix-ide-e2e/src/tests/txListener.test.ts b/apps/remix-ide-e2e/src/tests/txListener.test.ts index 8a3b5d7999..2bc0b6e391 100644 --- a/apps/remix-ide-e2e/src/tests/txListener.test.ts +++ b/apps/remix-ide-e2e/src/tests/txListener.test.ts @@ -31,7 +31,7 @@ module.exports = { .clickFunction('delegate - transact (not payable)', { types: 'address to', values: '"0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db"' }) .testFunction('last', { - status: 'true Transaction mined and execution succeed', + status: '0x1 Transaction mined and execution succeed', 'decoded input': { 'address to': '0x4B0897b0513fdC7C541B6d9D7E929C4e5364D2dB' } }) .clickLaunchIcon('solidity') @@ -40,7 +40,7 @@ module.exports = { .clickFunction('delegate - transact (not payable)', { types: 'address to', values: '"0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db"' }) .testFunction('last', { - status: 'false Transaction mined but execution failed', + status: '0x0 Transaction mined but execution failed', 'decoded input': { 'address to': '0x4B0897b0513fdC7C541B6d9D7E929C4e5364D2dB' } }) .end() diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index 67d089c466..a81a13c2e9 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -46,6 +46,7 @@ import {InjectedSKALEChaosTestnetProvider} from './app/providers/injected-skale- import { FileDecorator } from './app/plugins/file-decorator' import { CodeFormat } from './app/plugins/code-format' import { SolidityUmlGen } from './app/plugins/solidity-umlgen' +import { CompilationDetailsPlugin } from './app/plugins/compile-details' import { ContractFlattener } from './app/plugins/contractFlattener' import { TemplatesPlugin } from './app/plugins/remix-templates' import { fsPlugin } from './app/plugins/electron/fsPlugin' @@ -199,6 +200,9 @@ class AppComponent { //---------------- Solidity UML Generator ------------------------- const solidityumlgen = new SolidityUmlGen(appManager) + // ----------------- Compilation Details ---------------------------- + const compilationDetails = new CompilationDetailsPlugin(appManager) + // ----------------- ContractFlattener ---------------------------- const contractFlattener = new ContractFlattener() @@ -324,6 +328,7 @@ class AppComponent { this.walkthroughService, search, solidityumlgen, + compilationDetails, contractFlattener, solidityScript, templates, diff --git a/apps/remix-ide/src/app/files/fileManager.ts b/apps/remix-ide/src/app/files/fileManager.ts index ceb39ef969..b267a08cd7 100644 --- a/apps/remix-ide/src/app/files/fileManager.ts +++ b/apps/remix-ide/src/app/files/fileManager.ts @@ -26,7 +26,7 @@ const profile = { version: packageJson.version, methods: ['closeAllFiles', 'closeFile', 'file', 'exists', 'open', 'writeFile', 'writeMultipleFiles', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', 'readdir', 'dirList', 'fileList', 'remove', 'getCurrentFile', 'getFile', 'getFolder', 'setFile', 'switchFile', 'refresh', - 'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath', 'saveCurrentFile', 'setBatchFiles', 'isGitRepo'], + 'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath', 'saveCurrentFile', 'setBatchFiles', 'isGitRepo', 'isFile', 'isDirectory'], kind: 'file-system' } const errorMsg = { diff --git a/apps/remix-ide/src/app/plugins/compile-details.tsx b/apps/remix-ide/src/app/plugins/compile-details.tsx new file mode 100644 index 0000000000..1a19c22cbc --- /dev/null +++ b/apps/remix-ide/src/app/plugins/compile-details.tsx @@ -0,0 +1,84 @@ +import React from 'react' +import { ViewPlugin } from '@remixproject/engine-web' +import {PluginViewWrapper} from '@remix-ui/helper' +import { RemixAppManager } from '../../remixAppManager' +import { RemixUiCompileDetails } from '@remix-ui/solidity-compile-details' + +const _paq = (window._paq = window._paq || []) + +const profile = { + name: 'compilationDetails', + displayName: 'Solidity Compile Details', + description: 'Displays details from solidity compiler', + location: 'mainPanel', + methods: ['showDetails'], + events: [] +} + +export class CompilationDetailsPlugin extends ViewPlugin { + dispatch: React.Dispatch = () => {} + appManager: RemixAppManager + element: HTMLDivElement + payload: any + constructor(appManager: RemixAppManager) { + super(profile) + this.appManager = appManager + this.element = document.createElement('div') + this.element.setAttribute('id', 'compileDetails') + this.payload = { + contractProperties: {} as any, + selectedContract: '', + help: {} as any, + insertValue: {} as any, + saveAs: {} as any, + } + } + + async onActivation() { + await this.call('tabs', 'focus', 'compilationDetails') + this.renderComponent() + _paq.push(['trackEvent', 'plugin', 'activated', 'compilationDetails']) + } + + onDeactivation(): void { + + } + + async showDetails(sentPayload: any) { + await this.call('tabs', 'focus', 'compilationDetails') + this.payload = sentPayload + this.renderComponent() + } + + setDispatch(dispatch: React.Dispatch): void { + this.dispatch = dispatch + } + render() { + return ( +
+ +
+ ) + } + + renderComponent() { + this.dispatch({ + ...this, + ...this.payload + }) + } + + updateComponent(state: any) { + return ( + + ) + } + +} diff --git a/apps/remix-ide/src/app/plugins/solidity-script.tsx b/apps/remix-ide/src/app/plugins/solidity-script.tsx index a19ca834df..4da5425a34 100644 --- a/apps/remix-ide/src/app/plugins/solidity-script.tsx +++ b/apps/remix-ide/src/app/plugins/solidity-script.tsx @@ -2,7 +2,7 @@ import React from 'react' // eslint-disable-line import {format} from 'util' import {Plugin} from '@remixproject/engine' import {compile} from '@remix-project/remix-solidity' -import {TransactionConfig} from 'web3-core' +import {Transaction} from 'web3-types' const _paq = (window._paq = window._paq || []) //eslint-disable-line const profile = { @@ -69,7 +69,7 @@ export class SolidityScript extends Plugin { } // deploy the contract - let tx: TransactionConfig = { + let tx: Transaction = { from: accounts[0], data: bytecode } @@ -81,7 +81,7 @@ export class SolidityScript extends Plugin { } const receiptCall = await web3.eth.sendTransaction(tx) - const hhlogs = await web3.eth.getHHLogsForTx(receiptCall.transactionHash) + const hhlogs = await web3.remix.getHHLogsForTx(receiptCall.transactionHash) if (hhlogs && hhlogs.length) { const finalLogs = ( diff --git a/apps/remix-ide/src/app/providers/injected-provider.tsx b/apps/remix-ide/src/app/providers/injected-provider.tsx index c1ac29256e..1e2482fd6c 100644 --- a/apps/remix-ide/src/app/providers/injected-provider.tsx +++ b/apps/remix-ide/src/app/providers/injected-provider.tsx @@ -86,12 +86,8 @@ export abstract class InjectedProvider extends Plugin implements IProvider { } try { let resultData - if (web3Provider.send) resultData = await web3Provider.send(data.method, data.params) - else if (web3Provider.request) - resultData = await web3Provider.request({ - method: data.method, - params: data.params - }) + if (web3Provider.request) resultData = await web3Provider.request({method: data.method, params: data.params}) + else if (web3Provider.send) resultData = await web3Provider.send(data.method, data.params) else { resolve({jsonrpc: '2.0', error: 'provider not valid', id: data.id}) return diff --git a/apps/remix-ide/src/app/providers/mainnet-vm-fork-provider.tsx b/apps/remix-ide/src/app/providers/mainnet-vm-fork-provider.tsx index 39747d9be1..a593eeee29 100644 --- a/apps/remix-ide/src/app/providers/mainnet-vm-fork-provider.tsx +++ b/apps/remix-ide/src/app/providers/mainnet-vm-fork-provider.tsx @@ -18,7 +18,7 @@ export class MainnetForkVMProvider extends BasicVMProvider { ) this.blockchain = blockchain this.fork = 'shanghai' - this.nodeUrl = 'https://mainnet.infura.io/v3/08b2a484451e4635a28b3d8234f24332' + this.nodeUrl = 'https://mainnet.infura.io/v3/7eed077ab9ee45eebbb3f053af9ecb29' this.blockNumber = 'latest' } diff --git a/apps/remix-ide/src/app/tabs/debugger-tab.js b/apps/remix-ide/src/app/tabs/debugger-tab.js index 03bd672110..9c99051ef8 100644 --- a/apps/remix-ide/src/app/tabs/debugger-tab.js +++ b/apps/remix-ide/src/app/tabs/debugger-tab.js @@ -86,9 +86,9 @@ export class DebuggerTab extends DebuggerApiMixin(ViewPlugin) { 'timestamp': block.timestamp, } if (block.baseFeePerGas) { - blockContext['basefee'] = Web3.utils.toBN(block.baseFeePerGas).toString(10) + ` Wei (${block.baseFeePerGas})` + blockContext['basefee'] = Web3.utils.toBigInt(block.baseFeePerGas).toString(10) + ` Wei (${block.baseFeePerGas})` } - const msg = { + const msg = { 'sender': tx.from, 'sig': tx.input.substring(0, 10), 'value': tx.value + ' Wei' @@ -97,7 +97,7 @@ export class DebuggerTab extends DebuggerApiMixin(ViewPlugin) { const txOrigin = { 'origin': tx.from } - + return { block: blockContext, msg, diff --git a/apps/remix-ide/src/app/tabs/locale-module.js b/apps/remix-ide/src/app/tabs/locale-module.js index 0487f94e96..ad9b3c641f 100644 --- a/apps/remix-ide/src/app/tabs/locale-module.js +++ b/apps/remix-ide/src/app/tabs/locale-module.js @@ -5,11 +5,17 @@ import * as packageJson from '../../../../../package.json' import Registry from '../state/registry' import enJson from './locales/en' import zhJson from './locales/zh' +import esJson from './locales/es' +import frJson from './locales/fr' +import itJson from './locales/it' const _paq = window._paq = window._paq || [] const locales = [ - { code: 'en', name: 'English', localeName: 'English', messages: enJson }, { code: 'zh', name: 'Chinese Simplified', localeName: '简体中文', messages: zhJson }, + { code: 'en', name: 'English', localeName: 'English', messages: enJson }, + { code: 'fr', name: 'French', localeName: 'Français', messages: frJson }, + { code: 'it', name: 'Italian', localeName: 'Italiano', messages: itJson }, + { code: 'es', name: 'Spanish', localeName: 'Español', messages: esJson } ] const profile = { diff --git a/apps/remix-ide/src/app/tabs/locales/en/solidity.json b/apps/remix-ide/src/app/tabs/locales/en/solidity.json index ad83ce89bb..6d845ce618 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/solidity.json +++ b/apps/remix-ide/src/app/tabs/locales/en/solidity.json @@ -59,6 +59,7 @@ "solidity.copyBytecode": "Copy Bytecode to clipboard", "solidity.unableToDisplay": "Unable to display", "solidity.download": "Download", + "solidity.compileDetails": "Download compilation details (JSON format)", "solidity.close": "Close", "solidity.contract": "Contract", "solidity.displayContractDetails": "Display Contract Details", diff --git a/apps/remix-ide/src/app/tabs/locales/es/solidity.json b/apps/remix-ide/src/app/tabs/locales/es/solidity.json index 947bfeae94..4fd24d0836 100644 --- a/apps/remix-ide/src/app/tabs/locales/es/solidity.json +++ b/apps/remix-ide/src/app/tabs/locales/es/solidity.json @@ -1,6 +1,7 @@ { "solidity.displayName": "Solidity compiler", "solidity.compiler": "Compiler", + "solidity.compileDetails": "Descargar detalles de compilación (formato JSON)", "solidity.addACustomCompiler": "Add a custom compiler", "solidity.addACustomCompilerWithURL": "Add a custom compiler with URL", "solidity.includeNightlyBuilds": "Include nightly builds", diff --git a/apps/remix-ide/src/app/tabs/locales/fr/home.json b/apps/remix-ide/src/app/tabs/locales/fr/home.json index 802d22bef4..cfe3e5df99 100644 --- a/apps/remix-ide/src/app/tabs/locales/fr/home.json +++ b/apps/remix-ide/src/app/tabs/locales/fr/home.json @@ -46,7 +46,7 @@ "home.remixLinkedinProfile": "Remix Linkedin Profile", "home.remixMediumPosts": "Remix Medium Posts", "home.remixGitterChannel": "Join us on Discord", - "home.nativeIDE": "The Native IDE for Web3 Development.", + "home.nativeIDE": "L'EDI natif pour le développement Web3.", "home.website": "Website", "home.documentation": "Documentation", "home.remixPlugin": "Remix Plugin", diff --git a/apps/remix-ide/src/app/tabs/locales/fr/solidity.json b/apps/remix-ide/src/app/tabs/locales/fr/solidity.json index 947bfeae94..7aa5a78214 100644 --- a/apps/remix-ide/src/app/tabs/locales/fr/solidity.json +++ b/apps/remix-ide/src/app/tabs/locales/fr/solidity.json @@ -1,6 +1,7 @@ { "solidity.displayName": "Solidity compiler", "solidity.compiler": "Compiler", + "solidity.compileDetails": "Télécharger les détails de la compilation (format JSON)", "solidity.addACustomCompiler": "Add a custom compiler", "solidity.addACustomCompilerWithURL": "Add a custom compiler with URL", "solidity.includeNightlyBuilds": "Include nightly builds", diff --git a/apps/remix-ide/src/app/tabs/locales/it/debugger.json b/apps/remix-ide/src/app/tabs/locales/it/debugger.json new file mode 100644 index 0000000000..2a7d40f1da --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/it/debugger.json @@ -0,0 +1,11 @@ +{ + "debugger.displayName": "Debugger", + "debugger.debuggerConfiguration": "Debugger Configuration", + "debugger.stopDebugging": "Stop debugging", + "debugger.startDebugging": "Start debugging", + "debugger.placeholder": "Transaction hash, should start with 0x", + "debugger.debugLocaNodeLabel": "Force using local node", + "debugger.useGeneratedSources": "Use generated sources", + "debugger.debugWithGeneratedSources": "Debug with generated sources", + "debugger.introduction": "When Debugging with a transaction hash, if the contract is verified, Remix will try to fetch the source code from Sourcify or Etherscan. Put in your Etherscan API key in the Remix settings. For supported networks, please see" +} diff --git a/apps/remix-ide/src/app/tabs/locales/it/filePanel.json b/apps/remix-ide/src/app/tabs/locales/it/filePanel.json new file mode 100644 index 0000000000..ab7222713f --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/it/filePanel.json @@ -0,0 +1,70 @@ +{ + "filePanel.displayName": "File explorer", + "filePanel.workspace": "WORKSPACES", + "filePanel.create": "Create", + "filePanel.clone": "Clone", + "filePanel.download": "Download", + "filePanel.backup": "Backup", + "filePanel.restore": "Restore", + "filePanel.workspace.create": "Create Workspace", + "filePanel.workspace.rename": "Rename Workspace", + "filePanel.workspace.delete": "Delete Workspace", + "filePanel.workspace.deleteConfirm": "Are you sure to delete the current workspace?", + "filePanel.workspace.download": "Download Workspace", + "filePanel.workspace.downloadConfirm": "This will download current workspace in a zip file. Do you want to continue?", + "filePanel.workspace.deleteAll": "Delete All Workspaces", + "filePanel.workspace.deleteAllConfirm1": "Are you absolutely sure you want to delete all your workspaces?", + "filePanel.workspace.deleteAllConfirm2": "Deleted workspaces can not be restored in any manner.", + "filePanel.workspace.name": "Workspace name", + "filePanel.workspace.chooseTemplate": "Choose a template", + "filePanel.workspace.backup": "Backup All Workspaces", + "filePanel.workspace.restore": "Restore Workspaces from the Backup", + "filePanel.workspace.clone": "Clone Git Repository", + "filePanel.workspace.cloneMessage": "Please provide a valid git repository url.", + "filePanel.workspace.enterGitUrl": "Enter git repository url", + "filePanel.workspace.switch": "Switch To Workspace", + "filePanel.workspace.solghaction": "Adds a preset yml file to run solidity unit tests on github actions CI.", + "filePanel.solghaction": "Solidity Test Workflow", + "filePanel.workspace.tssoltestghaction": "Adds a preset yml file to run mocha and chai tests for solidity on github actions CI", + "filePanel.tssoltestghaction": "Mocha Chai Test Workflow", + "filePanel.workspace.addscriptetherscan": "Adds scripts which can be used to interact with the Etherscan API", + "filePanel.addscriptetherscan": "Add Etherscan scripts", + "filePanel.workspace.addscriptdeployer": "Adds scripts which can be used to deploy contracts", + "filePanel.addscriptdeployer": "Add contract deployer scripts", + "filePanel.workspace.slitherghaction": "Adds a preset yml file to run slither analysis on github actions CI", + "filePanel.slitherghaction": "Slither Workflow", + "filePanel.workspace.helperscripts": "Adds convenient scripts to the 'scripts' directory", + "filePanel.helperscripts": "Web3 Scripts", + "filePanel.newFile": "New File", + "filePanel.newFolder": "New Folder", + "filePanel.rename": "Rename", + "filePanel.delete": "Delete", + "filePanel.deleteAll": "Delete All", + "filePanel.run": "Run", + "filePanel.pushChangesToGist": "Push changes to gist", + "filePanel.publishFolderToGist": "Publish folder to gist", + "filePanel.publishFileToGist": "Publish file to gist", + "filePanel.copy": "Copy", + "filePanel.paste": "Paste", + "filePanel.compile": "Compile", + "filePanel.compileForNahmii": "Compile for Nahmii", + "filePanel.createNewFile": "Create new file", + "filePanel.createNewFolder": "Create new folder", + "filePanel.publishToGist": "Publish all files to GitHub gist", + "filePanel.uploadFile": "Upload files", + "filePanel.uploadFolder": "Upload folder", + "filePanel.updateGist": "Update the current [gist] explorer", + "filePanel.viewAllBranches": "View all branches", + "filePanel.createBranch": "Create branch", + "filePanel.switchBranches": "Switch branches", + "filePanel.checkoutGitBranch": "Checkout Git Branch", + "filePanel.findOrCreateABranch": "Find or create a branch.", + "filePanel.initGitRepositoryLabel": "Initialize workspace as a new git repository", + "filePanel.initGitRepositoryWarning": "To use Git features, add username and email to the Github section of the Settings panel.", + "filePanel.workspaceName": "Workspace name", + "filePanel.customizeTemplate": "Customize template", + "filePanel.features": "Features", + "filePanel.upgradeability": "Upgradeability", + "filePanel.ok": "OK", + "filePanel.cancel": "Cancel" +} diff --git a/apps/remix-ide/src/app/tabs/locales/it/home.json b/apps/remix-ide/src/app/tabs/locales/it/home.json new file mode 100644 index 0000000000..802d22bef4 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/it/home.json @@ -0,0 +1,61 @@ +{ + "home.scamAlert": "Scam Alert", + "home.scamAlertText": "The only URL Remix uses is remix.ethereum.org", + "home.scamAlertText2": "Beware of online videos promoting \"liquidity front runner bots\"", + "home.scamAlertText3": "Additional safety tips", + "home.learnMore": "Learn more", + "home.here": "here", + "home.featured": "Featured", + "home.jumpIntoWeb3": "WE NEED YOUR HELP", + "home.jumpIntoWeb3More": "Go to survey", + "home.jumpIntoWeb3Text": "Remixers... Have a spare moment? Please help us improve your Remix experience with this one-minute survey.", + "home.remixYouTube": "WATCH TO LEARN", + "home.remixYouTubeText1": "Video Tips from the Remix Team", + "home.remixYouTubeMore": "Watch", + "home.remixYouTubeText2": "Remix has a growing library of videos containing lots of tips for using the tool. Check them out and subscribe to get our latest uploads.", + "home.betaTesting": "BETA TESTING", + "home.betaTestingText1": "Our community supports us.", + "home.betaTestingText2": "Help us beta test releases now and get a handle on new features!", + "home.betaTestingMore": "Sign up", + "home.featuredPlugins": "Featured Plugins", + "home.solidityPluginDesc": "Compile, test, and analyze smart contracts.", + "home.starkNetPluginDesc": "Compile and deploy contracts with Cairo, a native language for StarkNet.", + "home.solhintPluginDesc": "Solhint is an open source project for linting Solidity code.", + "home.sourcifyPluginDesc": "Solidity contract and metadata verification service.", + "home.unitTestPluginDesc": "Write and run unit tests for your contracts in Solidity.", + "home.dgitPluginDesc": "Add source control to your projects.", + "home.oneClickDappDesc": "Quickly generate smart contract interfaces", + "home.getStarted": "Get Started", + "home.projectTemplates": "Project Templates", + "home.blankTemplateDesc": "Create an empty workspace.", + "home.remixDefaultTemplateDesc": "Create a workspace with sample files.", + "home.ozerc20TemplateDesc": "Create an ERC20 token by importing OpenZeppelin library.", + "home.ozerc721TemplateDesc": "Create an NFT token by importing OpenZeppelin library.", + "home.ozerc1155TemplateDesc": "Create an ERC1155 token by importing OpenZeppelin library.", + "home.gnosisSafeMultisigTemplateDesc": "Create Multi-Signature wallets using this template.", + "home.zeroxErc20TemplateDesc": "Create an ERC20 token by importing 0xProject contract.", + "home.learn": "Learn", + "home.learnEth1": "Remix Basics", + "home.learnEth1Desc": "An introduction to Remix's interface and basic operations.", + "home.learnEth2": "Intro to Solidity", + "home.learnEth2Desc": "Interactively learn Solidity beginner concepts.", + "home.remixAdvanced": "Deploying with Libraries", + "home.remixAdvancedDesc": "Learn to deploy with libraries in Remix", + "home.remixYoutubePlaylist": "Remix Youtube Playlist", + "home.remixTwitterProfile": "Remix Twitter Profile", + "home.remixLinkedinProfile": "Remix Linkedin Profile", + "home.remixMediumPosts": "Remix Medium Posts", + "home.remixGitterChannel": "Join us on Discord", + "home.nativeIDE": "The Native IDE for Web3 Development.", + "home.website": "Website", + "home.documentation": "Documentation", + "home.remixPlugin": "Remix Plugin", + "home.remixDesktop": "Remix Desktop", + "home.searchDocumentation": "Search Documentation", + "home.files": "Files", + "home.newFile": "New File", + "home.openFile": "Open File", + "home.connectToLocalhost": "Access File System", + "home.loadFrom": "Load from", + "home.resources": "Resources" +} diff --git a/apps/remix-ide/src/app/tabs/locales/it/index.js b/apps/remix-ide/src/app/tabs/locales/it/index.js new file mode 100644 index 0000000000..ded9c45b14 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/it/index.js @@ -0,0 +1,36 @@ +import debuggerJson from './debugger.json'; +import filePanelJson from './filePanel.json'; +import homeJson from './home.json'; +import panelJson from './panel.json'; +import pluginManagerJson from './pluginManager.json'; +import searchJson from './search.json'; +import settingsJson from './settings.json'; +import solidityJson from './solidity.json'; +import terminalJson from './terminal.json'; +import udappJson from './udapp.json'; +import solidityUnitTestingJson from './solidityUnitTesting.json'; +import permissionHandlerJson from './permissionHandler.json'; +import solUmlGenJson from './solUmlGen.json' +import remixAppJson from './remixApp.json' +import remixUiTabsJson from './remixUiTabs.json' +import enJson from '../en'; + +// There may have some un-translated content. Always fill in the gaps with EN JSON. +// No need for a defaultMessage prop when render a FormattedMessage component. +export default Object.assign({}, enJson, { + ...debuggerJson, + ...filePanelJson, + ...homeJson, + ...panelJson, + ...pluginManagerJson, + ...searchJson, + ...settingsJson, + ...solidityJson, + ...terminalJson, + ...udappJson, + ...solidityUnitTestingJson, + ...permissionHandlerJson, + ...solUmlGenJson, + ...remixAppJson, + ...remixUiTabsJson, +}) diff --git a/apps/remix-ide/src/app/tabs/locales/it/panel.json b/apps/remix-ide/src/app/tabs/locales/it/panel.json new file mode 100644 index 0000000000..070dbbd57f --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/it/panel.json @@ -0,0 +1,6 @@ +{ + "panel.author": "Author", + "panel.maintainedBy": "Maintained By", + "panel.documentation": "Documentation", + "panel.description": "Description" +} diff --git a/apps/remix-ide/src/app/tabs/locales/it/permissionHandler.json b/apps/remix-ide/src/app/tabs/locales/it/permissionHandler.json new file mode 100644 index 0000000000..d41fe6c68e --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/it/permissionHandler.json @@ -0,0 +1,13 @@ +{ + "permissionHandler.allPermissionsReset": "All permisssions have been reset.", + "permissionHandler.rememberText": "has changed and", + "permissionHandler.permissionHandlerMessage": "\"{from}\" {rememberText} would like to access to \"{method}\" of \"{to}\"`", + "permissionHandler.description": "Description", + "permissionHandler.noDescriptionProvided": "No description Provided", + "permissionHandler.makeSureYouTrustThisPlugin": "Make sure you trust this plugin before processing this call. If you choose to remember the choice for this specific call, the value will be kept only for the current session.", + "permissionHandler.rememberThisChoice": "Remember this choice", + "permissionHandler.resetAllPermissions": "Reset all Permissions", + "permissionHandler.permissionNeededFor": "Permission needed for {to}", + "permissionHandler.accept": "Accept", + "permissionHandler.decline": "Decline" +} diff --git a/apps/remix-ide/src/app/tabs/locales/it/pluginManager.json b/apps/remix-ide/src/app/tabs/locales/it/pluginManager.json new file mode 100644 index 0000000000..01287713d6 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/it/pluginManager.json @@ -0,0 +1,31 @@ +{ + "pluginManager.displayName": "Plugin manager", + "pluginManager.activate": "Activate", + "pluginManager.deactivate": "Deactivate", + "pluginManager.activeModules": "Active Modules", + "pluginManager.inactiveModules": "Inactive Modules", + "pluginManager.connectLocal": "Connect to a Local Plugin", + "pluginManager.localForm.title": "Local Plugin", + "pluginManager.localForm.pluginName": "Plugin Name", + "pluginManager.localForm.shouldBeCamelCase": "Should be camelCase", + "pluginManager.localForm.displayName": "Display Name", + "pluginManager.localForm.nameInTheHeader": "Name in the header", + "pluginManager.localForm.required": "required", + "pluginManager.localForm.commaSeparatedMethod": "comma separated list of method names", + "pluginManager.localForm.commaSeparatedPlugin": "comma separated list of plugin names", + "pluginManager.localForm.pluginsItCanActivate": "Plugins it can activate", + "pluginManager.localForm.typeOfConnection": "Type of connection", + "pluginManager.localForm.locationInRemix": "Location in remix", + "pluginManager.localForm.sidePanel": "Side Panel", + "pluginManager.localForm.mainPanel": "Main Panel", + "pluginManager.localForm.none": "None", + "pluginManager.Permissions": "Permissions", + "pluginManager.permissions": "permissions", + "pluginManager.pluginManagerPermissions": "Plugin Manager Permissions", + "pluginManager.currentPermissionSettings": "Current Permission Settings", + "pluginManager.noPermissionRequestedYet": "No Permission requested yet.", + "pluginManager.allow": "Allow", + "pluginManager.toCall": "to call", + "pluginManager.ok": "OK", + "pluginManager.cancel": "Cancel" +} diff --git a/apps/remix-ide/src/app/tabs/locales/it/remixApp.json b/apps/remix-ide/src/app/tabs/locales/it/remixApp.json new file mode 100644 index 0000000000..a67504f413 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/it/remixApp.json @@ -0,0 +1,3 @@ +{ + "remixApp.scrollToSeeAllTabs": "Scroll to see all tabs" +} diff --git a/apps/remix-ide/src/app/tabs/locales/it/remixUiTabs.json b/apps/remix-ide/src/app/tabs/locales/it/remixUiTabs.json new file mode 100644 index 0000000000..1c60e9592d --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/it/remixUiTabs.json @@ -0,0 +1,7 @@ +{ + "remixUiTabs.tooltipText1": "Run script (CTRL + SHIFT + S)", + "remixUiTabs.tooltipText2": "Compile CTRL + S", + "remixUiTabs.tooltipText3": "Select .sol or .yul file to compile or a .ts or .js file and run it", + "remixUiTabs.zoomOut": "Zoom out", + "remixUiTabs.zoomIn": "Zoom in" +} diff --git a/apps/remix-ide/src/app/tabs/locales/it/search.json b/apps/remix-ide/src/app/tabs/locales/it/search.json new file mode 100644 index 0000000000..5bb29ab8d2 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/it/search.json @@ -0,0 +1,14 @@ +{ + "search.displayName": "Search in files", + "search.replace": "Replace", + "search.replaceAll": "Replace All", + "search.placeholder1": "Search ( Enter to search )", + "search.placeholder2": "Include ie *.sol ( Enter to include )", + "search.placeholder3": "Exclude ie .git/**/* ( Enter to exclude )", + "search.matchCase": "Match Case", + "search.matchWholeWord": "Match Whole Word", + "search.useRegularExpression": "Use Regular Expression", + "search.replaceWithoutConfirmation": "replace without confirmation", + "search.filesToInclude": "Files to include", + "search.filesToExclude": "Files to exclude" +} diff --git a/apps/remix-ide/src/app/tabs/locales/it/settings.json b/apps/remix-ide/src/app/tabs/locales/it/settings.json new file mode 100644 index 0000000000..58af512c35 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/it/settings.json @@ -0,0 +1,26 @@ +{ + "settings.displayName": "Settings", + "settings.reset": "Reset to Default settings", + "settings.general": "General settings", + "settings.generateContractMetadataText": "Generate contract metadata. Generate a JSON file in the contract folder. Allows to specify library addresses the contract depends on. If nothing is specified, Remix deploys libraries automatically.", + "settings.ethereunVMText": "Always use the Remix VM at load", + "settings.wordWrapText": "Word wrap in editor", + "settings.useAutoCompleteText": "Enable code completion in editor.", + "settings.useShowGasInEditorText": "Display gas estimates in editor.", + "settings.displayErrorsText": "Display errors in editor while typing.", + "settings.matomoAnalytics": "Enable Matomo Analytics. We do not collect personally identifiable information (PII). The info is used to improve the site’s UX & UI. See more about ", + "settings.enablePersonalModeText": " Enable Personal Mode for web3 provider. Transaction sent over Web3 will use the web3.personal API.\n", + "settings.warnText": "Be sure the endpoint is opened before enabling it. This mode allows a user to provide a passphrase in the Remix interface without having to unlock the account. Although this is very convenient, you should completely trust the backend you are connected to (Geth, Parity, ...). Remix never persists any passphrase", + "settings.gitAccessTokenTitle": "Github Credentials", + "settings.gitAccessTokenText": "The access token is used to publish a Gist and retrieve GitHub contents. You may need to input username/email.", + "settings.gitAccessTokenText2": "Go to github token page (link below) to create a new token and save it in Remix. Make sure this token has only 'create gist' permission", + "settings.etherscanTokenTitle": "EtherScan Access Token", + "settings.etherscanAccessTokenText": "Manage the api key used to interact with Etherscan.", + "settings.etherscanAccessTokenText2": "Go to Etherscan api key page (link below) to create a new api key and save it in Remix.", + "settings.save": "Save", + "settings.remove": "Remove", + "settings.themes": "Themes", + "settings.locales": "Language", + "settings.swarm": "Swarm Settings", + "settings.ipfs": "IPFS Settings" +} diff --git a/apps/remix-ide/src/app/tabs/locales/it/solUmlGen.json b/apps/remix-ide/src/app/tabs/locales/it/solUmlGen.json new file mode 100644 index 0000000000..5816659c8b --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/it/solUmlGen.json @@ -0,0 +1,10 @@ +{ + "solUmlGen.pngDownload": "Download as PNG", + "solUmlGen.pdfDownload": "Download as PDF", + "solUmlGen.pngDownloadTooltip": "Download UML diagram as a PNG file", + "solUmlGen.pdfDownloadTooltip": "Download UML diagram as a PDF file", + "solUmlGen.text1": "To view your contract as a UML Diagram", + "solUmlGen.text2": "Right click on your contract file", + "solUmlGen.clickOn": "Click on", + "solUmlGen.generateUML": "Generate UML" +} diff --git a/apps/remix-ide/src/app/tabs/locales/it/solidity.json b/apps/remix-ide/src/app/tabs/locales/it/solidity.json new file mode 100644 index 0000000000..4fd24d0836 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/it/solidity.json @@ -0,0 +1,42 @@ +{ + "solidity.displayName": "Solidity compiler", + "solidity.compiler": "Compiler", + "solidity.compileDetails": "Descargar detalles de compilación (formato JSON)", + "solidity.addACustomCompiler": "Add a custom compiler", + "solidity.addACustomCompilerWithURL": "Add a custom compiler with URL", + "solidity.includeNightlyBuilds": "Include nightly builds", + "solidity.autoCompile": "Auto compile", + "solidity.hideWarnings": "Hide warnings", + "solidity.enableHardhat": "Enable Hardhat Compilation", + "solidity.learnHardhat": "Learn how to use Hardhat Compilation", + "solidity.enableTruffle": "Enable Truffle Compilation", + "solidity.learnTruffle": "Learn how to use Truffle Compilation", + "solidity.advancedConfigurations": "Advanced Configurations", + "solidity.compilerConfiguration": "Compiler configuration", + "solidity.compilationDetails": "Compilation Details", + "solidity.language": "Language", + "solidity.evmVersion": "EVM Version", + "solidity.enableOptimization": "Enable optimization", + "solidity.useConfigurationFile": "Use configuration file", + "solidity.change": "Change", + "solidity.compile": "Compile", + "solidity.noFileSelected": "no file selected", + "solidity.compileAndRunScript": "Compile and Run script", + "solidity.publishOn": "Publish on", + "solidity.flatten": "Flatten contracts before UML generation.", + "solidity.generateUML": "Generate a UML diagram of your contract.", + "solidity.flattenLabel": "Flatten", + "solidity.generateUMLLabel": "Generate UML Diagram", + "solidity.Assembly": "Assembly opcodes describing the contract including corresponding solidity source code", + "solidity.Opcodes": "Assembly opcodes describing the contract", + "solidity.name": "Name of the compiled contract", + "solidity.metadata": "Contains all informations related to the compilation", + "solidity.bytecode": "Bytecode being executed during contract creation", + "solidity.abi": "ABI: describing all the functions (input/output params, scope, ...)", + "solidity.web3Deploy": "Copy/paste this code to any JavaScript/Web3 console to deploy this contract", + "solidity.metadataHash": "Hash representing all metadata information", + "solidity.functionHashes": "List of declared function and their corresponding hash", + "solidity.gasEstimates": "Gas estimation for each function call", + "solidity.Runtime Bytecode": "Bytecode storing the state and being executed during normal contract call", + "solidity.swarmLocation": "Swarm url where all metadata information can be found (contract needs to be published first)" +} diff --git a/apps/remix-ide/src/app/tabs/locales/it/solidityUnitTesting.json b/apps/remix-ide/src/app/tabs/locales/it/solidityUnitTesting.json new file mode 100644 index 0000000000..f1080804b6 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/it/solidityUnitTesting.json @@ -0,0 +1,35 @@ +{ + "solidityUnitTesting.displayName": "Solidity unit testing", + "solidityUnitTesting.testDirectory": "Test directory", + "solidityUnitTesting.testYourSmartContract": "Test your smart contract in Solidity.", + "solidityUnitTesting.selectDirectory": "Select directory to load and generate test files.", + "solidityUnitTesting.uiPathInputTooltip": "Press 'Enter' to change the path for test files.", + "solidityUnitTesting.uiPathInputButtonTooltip": "Create a test folder", + "solidityUnitTesting.create": "Create", + "solidityUnitTesting.generateTestsButtonTooltip": "Generate a sample test file", + "solidityUnitTesting.generate": "Generate", + "solidityUnitTesting.generateTestsLinkTooltip": "Check out documentation.", + "solidityUnitTesting.howToUse": "How to use...", + "solidityUnitTesting.runButtonTitle1": "Run tests", + "solidityUnitTesting.runButtonTitle2": "Please select Solidity compiler version greater than 0.4.12.", + "solidityUnitTesting.runButtonTitle3": "No solidity file selected", + "solidityUnitTesting.runButtonTitle4": "The \"Solidity Plugin\" should be activated", + "solidityUnitTesting.runButtonTitle5": "No test file selected", + "solidityUnitTesting.stopButtonLabel1": "Stop", + "solidityUnitTesting.stopButtonLabel2": "Stopping", + "solidityUnitTesting.run": "Run", + "solidityUnitTesting.runTestsTabStopActionTooltip": "Stop running tests", + "solidityUnitTesting.selectAll": "Select all", + "solidityUnitTesting.testTabTestsExecutionStopped": "The test execution has been stopped", + "solidityUnitTesting.testTabTestsExecutionStoppedError": "The test execution has been stopped because of error(s) in your test file", + "solidityUnitTesting.progress": "Progress: {readyTestsNumber} finished (of {runningTestsNumber})", + "solidityUnitTesting.resultFor": "Result for", + "solidityUnitTesting.passed": "Passed", + "solidityUnitTesting.failed": "Failed", + "solidityUnitTesting.timeTaken": "Time Taken", + "solidityUnitTesting.errorMessage": "Error Message", + "solidityUnitTesting.assertion": "Assertion", + "solidityUnitTesting.expectedValueShouldBe": "Expected value should be", + "solidityUnitTesting.receivedValue": "Received value", + "solidityUnitTesting.skippingTheRemainingTests": "Skipping the remaining tests of the function." +} diff --git a/apps/remix-ide/src/app/tabs/locales/it/terminal.json b/apps/remix-ide/src/app/tabs/locales/it/terminal.json new file mode 100644 index 0000000000..a175436686 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/it/terminal.json @@ -0,0 +1,17 @@ +{ + "terminal.listen": "listen on all transactions", + "terminal.listenTitle": "If checked Remix will listen on all transactions mined in the current environment and not only transactions created by you", + "terminal.search": "Search with transaction hash or address", + "terminal.used": "used", + "terminal.debug": "Debug", + "terminal.welcomeText1": "Welcome to", + "terminal.welcomeText2": "Your files are stored in", + "terminal.welcomeText3": "You can use this terminal to", + "terminal.welcomeText4": "Check transactions details and start debugging", + "terminal.welcomeText5": "Execute JavaScript scripts", + "terminal.welcomeText6": "Input a script directly in the command line interface", + "terminal.welcomeText7": "Select a Javascript file in the file explorer and then run `remix.execute()` or `remix.exeCurrent()` in the command line interface", + "terminal.welcomeText8": "Right click on a JavaScript file in the file explorer and then click `Run`", + "terminal.welcomeText9": "The following libraries are accessible", + "terminal.welcomeText10": "Type the library name to see available commands" +} diff --git a/apps/remix-ide/src/app/tabs/locales/it/udapp.json b/apps/remix-ide/src/app/tabs/locales/it/udapp.json new file mode 100644 index 0000000000..48090ab631 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/it/udapp.json @@ -0,0 +1,64 @@ +{ + "udapp.displayName": "Deploy & run transactions", + "udapp.gasLimit": "Gas limit", + "udapp.account": "Account", + "udapp.value": "Value", + "udapp.contract": "Contract", + "udapp.compiledBy": "compiled by {compilerName}", + "udapp.infoSyncCompiledContractTooltip": "Click here to import contracts compiled from an external framework.This action is enabled when Remix is connected to an external framework (hardhat, truffle, foundry) through remixd.", + "udapp.remixIpfsUdappTooltip": "Publishing the source code and metadata to IPFS facilitates source code verification using Sourcify and will greatly foster contract adoption (auditing, debugging, calling it, etc...)", + "udapp.signAMessage": "Sign a message", + "udapp.enterAMessageToSign": "Enter a message to sign", + "udapp.hash": "hash", + "udapp.signature": "signature", + "udapp.signedMessage": "Signed Message", + "udapp.environment": "Environment", + "udapp.environmentDocs": "Click for docs about Environment", + "udapp.deploy": "Deploy", + "udapp.publishTo": "Publish to", + "udapp.or": "or", + "udapp.atAddress": "At Address", + "udapp.atAddressOptionsTitle1": "address of contract", + "udapp.atAddressOptionsTitle2": "Interact with the deployed contract - requires the .abi file or compiled .sol file to be selected in the editor (with the same compiler configuration)", + "udapp.atAddressOptionsTitle3": "Compile a *.sol file or select a *.abi file.", + "udapp.atAddressOptionsTitle4": "To interact with a deployed contract, either enter its address and compile its source *.sol file (with the same compiler settings) or select its .abi file in the editor. ", + "udapp.contractOptionsTitle1": "Please compile *.sol file to deploy or access a contract", + "udapp.contractOptionsTitle2": "Select a compiled contract to deploy or to use with At Address.", + "udapp.contractOptionsTitle3": "Select and compile *.sol file to deploy or access a contract.", + "udapp.contractOptionsTitle4": "When there is a compiled .sol file, choose the contract to deploy or to use with At Address.", + "udapp.checkSumWarning": "It seems you are not using a checksumed address.A checksummed address is an address that contains uppercase letters, as specified in {a}.Checksummed addresses are meant to help prevent users from sending transactions to the wrong address.", + "udapp.isOverSizePromptEip170": "Contract creation initialization returns data with length of more than 24576 bytes. The deployment will likely fail if the current network has activated the eip 170. More info: {a}", + "udapp.isOverSizePromptEip3860": "Contract creation init code exceeds the allowed max code size of 49152 bytes. The deployment will likely fail if the current network has activated the eip 3860. More info: {a}", + "udapp.thisContractMayBeAbstract": "This contract may be abstract, it may not implement an abstract parent's methods completely or it may not invoke an inherited contract's constructor correctly.", + "udapp.noCompiledContracts": "No compiled contracts", + "udapp.addressOfContract": "Address of contract", + "udapp.loadContractFromAddress": "Load contract from Address", + "udapp.deployedContracts": "Deployed Contracts", + "udapp.deployAndRunClearInstances": "Clear instances list and reset recorder", + "udapp.deployAndRunNoInstanceText": "Currently you have no contract instances to interact with.", + "udapp.transactionsRecorded": "Transactions recorded", + "udapp.transactionsCountTooltip": "The number of recorded transactions", + "udapp.transactionSaveTooltip1": "No transactions to save", + "udapp.transactionSaveTooltip2": "Save {count} transaction as scenario file", + "udapp.transactionSaveTooltip3": "Save {count} transactions as scenario file", + "udapp.infoRecorderTooltip": "Save transactions (deployed contracts and function executions) and replay them in another environment e.g Transactions created in Remix VM can be replayed in the Injected Provider.", + "udapp.livemodeRecorderTooltip": "If contracts are updated after recording transactions, checking this box will run recorded transactions with the latest copy of the compiled contracts", + "udapp.livemodeRecorderLabel": "Run transactions using the latest compilation result", + "udapp.runRecorderTooltip": "Run transaction(s) from the current scenario file", + "udapp.save": "Save", + "udapp.run": "Run", + "udapp.ok": "OK", + "udapp.alert": "Alert", + "udapp.proceed": "Proceed", + "udapp.cancel": "Cancel", + "udapp.parameters": "Parameters", + "udapp.copyParameters": "Copy encoded input parameters to clipboard", + "udapp.copyCalldata": "Copy calldata to clipboard", + "udapp.deployWithProxy": "Deploy with Proxy", + "udapp.upgradeWithProxy": "Upgrade with Proxy", + "udapp.useLastDeployedERC1967Contract": "Use last deployed ERC1967 contract", + "udapp.proxyAddressLabel": "Proxy Address", + "udapp.proxyAddressPlaceholder": "proxy address", + "udapp.proxyAddressInputTooltip": "Enter previously deployed proxy address on the selected network", + "udapp.proxyAddressTooltip": "Select this option to use the last deployed ERC1967 contract on the current network." +} diff --git a/apps/remix-ide/src/app/tabs/locales/zh/solidity.json b/apps/remix-ide/src/app/tabs/locales/zh/solidity.json index 1ffe38907a..9374c2f07c 100644 --- a/apps/remix-ide/src/app/tabs/locales/zh/solidity.json +++ b/apps/remix-ide/src/app/tabs/locales/zh/solidity.json @@ -4,6 +4,7 @@ "solidity.addACustomCompiler": "添加一个自定义编译器", "solidity.addACustomCompilerWithURL": "通过URL添加一个自定义编译器", "solidity.includeNightlyBuilds": "包含每日构造版本", + "solidity.compileDetails": "下载编译详细信息(JSON 格式", "solidity.autoCompile": "自动编译", "solidity.hideWarnings": "隐藏警告", "solidity.enableHardhat": "启用 Hardhat 编译", diff --git a/apps/remix-ide/src/app/tabs/network-module.js b/apps/remix-ide/src/app/tabs/network-module.js index ea7a1c0c6e..10520e679d 100644 --- a/apps/remix-ide/src/app/tabs/network-module.js +++ b/apps/remix-ide/src/app/tabs/network-module.js @@ -1,6 +1,7 @@ import { Plugin } from '@remixproject/engine' import * as packageJson from '../../../../../package.json' import { Web3 } from 'web3' +import IpcProvider from 'web3-providers-ipc' export const profile = { name: 'network', @@ -49,7 +50,7 @@ export class NetworkModule extends Plugin { /** Add a custom network to the list of available networks */ addNetwork (network) { // { name, url } - const provider = network.url === 'ipc' ? new Web3.providers.IpcProvider() : new Web3.providers.HttpProvider(network.url) + const provider = network.url === 'ipc' ? new IpcProvider() : new Web3.providers.HttpProvider(network.url) this.blockchain.addProvider({ name: network.name, provider }) } diff --git a/apps/remix-ide/src/app/tabs/web3-provider.js b/apps/remix-ide/src/app/tabs/web3-provider.js index 0158ff11f9..1d4655667b 100644 --- a/apps/remix-ide/src/app/tabs/web3-provider.js +++ b/apps/remix-ide/src/app/tabs/web3-provider.js @@ -1,5 +1,6 @@ import { Plugin } from '@remixproject/engine' import * as packageJson from '../../../../../package.json' +import {isBigInt} from 'web3-validator' export const profile = { name: 'web3Provider', @@ -10,6 +11,11 @@ export const profile = { kind: 'provider' } +const replacer = (key, value) => { + if (isBigInt(value)) value = value.toString() + return value +} + export class Web3ProviderModule extends Plugin { constructor(blockchain) { super(profile) @@ -23,12 +29,11 @@ export class Web3ProviderModule extends Plugin { sendAsync(payload) { return new Promise((resolve, reject) => { - this.askUserPermission('sendAsync', `Calling ${payload.method} with parameters ${JSON.stringify(payload.params, null, '\t')}`).then( + this.askUserPermission('sendAsync', `Calling ${payload.method} with parameters ${JSON.stringify(payload.params, replacer, '\t')}`).then( async (result) => { if (result) { const provider = this.blockchain.web3().currentProvider - // see https://github.com/ethereum/web3.js/pull/1018/files#diff-d25786686c1053b786cc2626dc6e048675050593c0ebaafbf0814e1996f22022R129 - provider[provider.sendAsync ? 'sendAsync' : 'send'](payload, async (error, message) => { + const resultFn = async (error, message) => { if (error) { // Handle 'The method "debug_traceTransaction" does not exist / is not available.' error if(error.message && error.code && error.code === -32601) { @@ -55,7 +60,12 @@ export class Web3ProviderModule extends Plugin { } } resolve(message) - }) + } + try { + resultFn(null, await provider.sendAsync(payload)) + } catch (e) { + resultFn(e.message) + } } else { reject(new Error('User denied permission')) } diff --git a/apps/remix-ide/src/app/udapp/make-udapp.js b/apps/remix-ide/src/app/udapp/make-udapp.js index 0b8b13433a..f2980e0263 100644 --- a/apps/remix-ide/src/app/udapp/make-udapp.js +++ b/apps/remix-ide/src/app/udapp/make-udapp.js @@ -10,13 +10,21 @@ export function makeUdapp (blockchain, compilersArtefacts, logHtmlCallback) { if (_transactionReceipts[tx.hash]) { return cb(null, _transactionReceipts[tx.hash]) } - blockchain.web3().eth.getTransactionReceipt(tx.hash, (error, receipt) => { + let res = blockchain.web3().eth.getTransactionReceipt(tx.hash, (error, receipt) => { if (error) { return cb(error) } _transactionReceipts[tx.hash] = receipt cb(null, receipt) }) + if(res && typeof res.then ==='function'){ + res.then((receipt)=>{ + _transactionReceipts[tx.hash] = receipt + cb(null, receipt) + }).catch((error)=>{ + cb(error) + }) + } } const txlistener = blockchain.getTxListener({ diff --git a/apps/remix-ide/src/app/udapp/run-tab.js b/apps/remix-ide/src/app/udapp/run-tab.js index cb6a47b835..6352e9636f 100644 --- a/apps/remix-ide/src/app/udapp/run-tab.js +++ b/apps/remix-ide/src/app/udapp/run-tab.js @@ -133,13 +133,9 @@ export class RunTab extends ViewPlugin { } }, provider: { - async sendAsync(payload, callback) { - try { - const result = await udapp.call(name, 'sendAsync', payload) - callback(null, result) - } catch (e) { - callback(e) - } + + async sendAsync (payload) { + return udapp.call(name, 'sendAsync', payload) } } }) diff --git a/apps/remix-ide/src/blockchain/blockchain.tsx b/apps/remix-ide/src/blockchain/blockchain.tsx index c698fd9c40..3abd4ce1e2 100644 --- a/apps/remix-ide/src/blockchain/blockchain.tsx +++ b/apps/remix-ide/src/blockchain/blockchain.tsx @@ -1,5 +1,5 @@ import React from 'react' // eslint-disable-line -import Web3 from 'web3' +import {fromWei, toBigInt, toWei} from 'web3-utils' import {Plugin} from '@remixproject/engine' import {toBuffer, addHexPrefix} from '@ethereumjs/util' import {EventEmitter} from 'events' @@ -244,7 +244,7 @@ export class Blockchain extends Plugin { const proxyModal = { id: 'confirmProxyDeployment', title: 'Confirm Deploy Proxy (ERC1967)', - message: `Confirm you want to deploy an ERC1967 proxy contract that is connected to your implementation. + message: `Confirm you want to deploy an ERC1967 proxy contract that is connected to your implementation. For more info on ERC1967, see: https://docs.openzeppelin.com/contracts/4.x/api/proxy#ERC1967Proxy`, modalType: 'modal', okLabel: 'OK', @@ -477,17 +477,17 @@ export class Blockchain extends Plugin { fromWei(value, doTypeConversion, unit) { if (doTypeConversion) { - return Web3.utils.fromWei(typeConversion.toInt(value), unit || 'ether') + return fromWei(typeConversion.toInt(value), unit || 'ether') } - return Web3.utils.fromWei(value.toString(10), unit || 'ether') + return fromWei(value.toString(10), unit || 'ether') } toWei(value, unit) { - return Web3.utils.toWei(value, unit || 'gwei') + return toWei(value, unit || 'gwei') } calculateFee(gas, gasPrice, unit?) { - return Web3.utils.toBN(gas).mul(Web3.utils.toBN(Web3.utils.toWei(gasPrice.toString(10) as string, unit || 'gwei'))) + return toBigInt(gas) * toBigInt(toWei(gasPrice.toString(10) as string, unit || 'gwei')) } determineGasFees(tx) { @@ -552,7 +552,6 @@ export class Blockchain extends Plugin { } web3() { - // @todo(https://github.com/ethereum/remix-project/issues/431) const isVM = this.executionContext.isVM() if (isVM) { return (this.providers.vm as VMProvider).web3 @@ -749,7 +748,7 @@ export class Blockchain extends Plugin { if (error) return reject(error) try { if (this.executionContext.isVM()) { - const execResult = await this.web3().eth.getExecutionResultFromSimulator(result.transactionHash) + const execResult = await this.web3().remix.getExecutionResultFromSimulator(result.transactionHash) resolve(resultToRemixTx(result, execResult)) } else resolve(resultToRemixTx(result)) } catch (e) { @@ -870,7 +869,7 @@ export class Blockchain extends Plugin { const isVM = this.executionContext.isVM() if (isVM && tx.useCall) { try { - result.transactionHash = await this.web3().eth.getHashFromTagBySimulator(timestamp) + result.transactionHash = await this.web3().remix.getHashFromTagBySimulator(timestamp) } catch (e) { console.log('unable to retrieve back the "call" hash', e) } @@ -911,7 +910,7 @@ export class Blockchain extends Plugin { let execResult let returnValue = null if (isVM) { - const hhlogs = await this.web3().eth.getHHLogsForTx(txResult.transactionHash) + const hhlogs = await this.web3().remix.getHHLogsForTx(txResult.transactionHash) if (hhlogs && hhlogs.length) { const finalLogs = ( @@ -937,7 +936,8 @@ export class Blockchain extends Plugin { _paq.push(['trackEvent', 'udapp', 'hardhat', 'console.log']) this.call('terminal', 'logHtml', finalLogs) } - execResult = await this.web3().eth.getExecutionResultFromSimulator(txResult.transactionHash) + execResult = await this.web3().remix.getExecutionResultFromSimulator(txResult.transactionHash) + if (execResult) { // if it's not the VM, we don't have return value. We only have the transaction, and it does not contain the return value. returnValue = execResult diff --git a/apps/remix-ide/src/blockchain/execution-context.js b/apps/remix-ide/src/blockchain/execution-context.js index d730a130e3..85c68a2160 100644 --- a/apps/remix-ide/src/blockchain/execution-context.js +++ b/apps/remix-ide/src/blockchain/execution-context.js @@ -36,7 +36,7 @@ export class ExecutionContext { init (config) { this.executionContext = 'vm-shanghai' this.event.trigger('contextChanged', [this.executionContext]) - } + } getProvider () { return this.executionContext @@ -74,7 +74,7 @@ export class ExecutionContext { if (!web3.currentProvider) { return callback('No provider set') } - web3.eth.net.getId((err, id) => { + const cb = (err, id) => { let name = null if (err) name = 'Unknown' // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md @@ -95,7 +95,11 @@ export class ExecutionContext { } else { callback(err, { id, name, lastBlock: this.lastBlock, currentFork: this.currentFork }) } - }) + } + const res = web3.eth.net.getId(cb) + if(res && typeof res.then ==='function'){ + res.then(id=>cb(null,id)).catch(err=>cb(err)) + } } } @@ -117,7 +121,7 @@ export class ExecutionContext { internalWeb3 () { return web3 } - + setContext (context, endPointUrl, confirmCb, infoCb) { this.executionContext = context this.executionContextChange(context, endPointUrl, confirmCb, infoCb, null) @@ -128,9 +132,9 @@ export class ExecutionContext { const context = value.context if (!cb) cb = () => { /* Do nothing. */ } if (!confirmCb) confirmCb = () => { /* Do nothing. */ } - if (!infoCb) infoCb = () => { /* Do nothing. */ } + if (!infoCb) infoCb = () => { /* Do nothing. */ } if (this.customNetWorks[context]) { - var network = this.customNetWorks[context] + var network = this.customNetWorks[context] await network.init() this.currentFork = network.fork this.executionContext = context @@ -156,7 +160,7 @@ export class ExecutionContext { try { const block = await web3.eth.getBlock('latest') // we can't use the blockGasLimit cause the next blocks could have a lower limit : https://github.com/ethereum/remix/issues/506 - this.blockGasLimit = (block && block.gasLimit) ? Math.floor(block.gasLimit - (5 * block.gasLimit) / 1024) : this.blockGasLimitDefault + this.blockGasLimit = (block && block.gasLimit) ? Math.floor(web3.utils.toNumber(block.gasLimit) - (5 * web3.utils.toNumber(block.gasLimit) / 1024)) : web3.utils.toNumber(this.blockGasLimitDefault) this.lastBlock = block try { this.currentFork = execution.forkAt(await web3.eth.net.getId(), block.number) diff --git a/apps/remix-ide/src/blockchain/providers/injected.ts b/apps/remix-ide/src/blockchain/providers/injected.ts index bc6ab49e7f..ce6ae9912b 100644 --- a/apps/remix-ide/src/blockchain/providers/injected.ts +++ b/apps/remix-ide/src/blockchain/providers/injected.ts @@ -1,5 +1,5 @@ import Web3 from 'web3' -import { hashPersonalMessage } from '@ethereumjs/util' +import { hashPersonalMessage, isHexString } from '@ethereumjs/util' import { ExecutionContext } from '../execution-context' export class InjectedProvider { @@ -20,7 +20,7 @@ export class InjectedProvider { } async resetEnvironment () { - /* Do nothing. */ + /* Do nothing. */ } async getBalanceInEther (address) { @@ -35,6 +35,7 @@ export class InjectedProvider { signMessage (message, account, _passphrase, cb) { const messageHash = hashPersonalMessage(Buffer.from(message)) try { + message = isHexString(message) ? message : Web3.utils.utf8ToHex(message) this.executionContext.web3().eth.personal.sign(message, account, (error, signedData) => { cb(error, '0x' + messageHash.toString('hex'), signedData) }) diff --git a/apps/remix-ide/src/blockchain/providers/node.ts b/apps/remix-ide/src/blockchain/providers/node.ts index 65116b4923..1dcf1b6c40 100644 --- a/apps/remix-ide/src/blockchain/providers/node.ts +++ b/apps/remix-ide/src/blockchain/providers/node.ts @@ -1,5 +1,5 @@ import Web3 from 'web3' -import { hashPersonalMessage } from '@ethereumjs/util' +import { hashPersonalMessage, isHexString } from '@ethereumjs/util' import { Personal } from 'web3-eth-personal' import { ExecutionContext } from '../execution-context' import Config from '../../config' @@ -15,9 +15,9 @@ export class NodeProvider { getAccounts (cb) { if (this.config.get('settings/personal-mode')) { - return this.executionContext.web3().eth.personal.getAccounts(cb) + return this.executionContext.web3().eth.personal.getAccounts().then(res => cb(null, res)).catch(err => cb(err)) } - return this.executionContext.web3().eth.getAccounts(cb) + return this.executionContext.web3().eth.getAccounts().then(res => cb(null, res)).catch(err => cb(err)) } newAccount (passwordPromptCb, cb) { @@ -25,7 +25,7 @@ export class NodeProvider { return cb('Not running in personal mode') } passwordPromptCb((passphrase) => { - this.executionContext.web3().eth.personal.newAccount(passphrase, cb) + this.executionContext.web3().eth.personal.newAccount(passphrase).then(res => cb(null, res)).catch(err => cb(err)) }) } @@ -39,16 +39,17 @@ export class NodeProvider { } getGasPrice (cb) { - this.executionContext.web3().eth.getGasPrice(cb) + this.executionContext.web3().eth.getGasPrice().then(res => cb(null, res)).catch(err => cb(err)) } signMessage (message, account, passphrase, cb) { const messageHash = hashPersonalMessage(Buffer.from(message)) try { const personal = new Personal(this.executionContext.web3().currentProvider) - personal.sign(message, account, passphrase, (error, signedData) => { - cb(error, '0x' + messageHash.toString('hex'), signedData) - }) + message = isHexString(message) ? message : Web3.utils.utf8ToHex(message) + personal.sign(message, account, passphrase) + .then(signedData => cb(undefined, '0x' + messageHash.toString('hex'), signedData)) + .catch(error => cb(error, '0x' + messageHash.toString('hex'), undefined)) } catch (e) { cb(e.message) } diff --git a/apps/remix-ide/src/blockchain/providers/vm.ts b/apps/remix-ide/src/blockchain/providers/vm.ts index 4234e42616..da6731d696 100644 --- a/apps/remix-ide/src/blockchain/providers/vm.ts +++ b/apps/remix-ide/src/blockchain/providers/vm.ts @@ -1,6 +1,6 @@ -import Web3 from 'web3' -import { privateToAddress, hashPersonalMessage } from '@ethereumjs/util' -import BN from 'bn.js' +import Web3, { FMT_BYTES, FMT_NUMBER, LegacySendAsyncProvider } from 'web3' +import { fromWei, toBigInt } from 'web3-utils' +import { privateToAddress, hashPersonalMessage, isHexString } from '@ethereumjs/util' import { extend, JSONRPCRequestPayload, JSONRPCResponseCallback } from '@remix-project/remix-simulator' import { ExecutionContext } from '../execution-context' @@ -14,6 +14,7 @@ export class VMProvider { newAccountCallback: {[stamp: number]: (error: Error, address: string) => void} constructor (executionContext: ExecutionContext) { + this.executionContext = executionContext this.worker = null this.provider = null @@ -21,12 +22,11 @@ export class VMProvider { } getAccounts (cb) { - this.web3.eth.getAccounts((err, accounts) => { - if (err) { - return cb('No accounts?') - } - return cb(null, accounts) - }) + this.web3.eth.getAccounts() + .then(accounts => cb(null, accounts)) + .catch(err => { + cb('No accounts?') + }) } async resetEnvironment () { @@ -36,22 +36,32 @@ export class VMProvider { let incr = 0 const stamps = {} - - return new Promise((resolve, reject) => { + + return new Promise((resolve, reject) => { this.worker.addEventListener('message', (msg) => { if (msg.data.cmd === 'sendAsyncResult' && stamps[msg.data.stamp]) { - stamps[msg.data.stamp](msg.data.error, msg.data.result) + if (stamps[msg.data.stamp].callback) { + stamps[msg.data.stamp].callback(msg.data.error, msg.data.result) + return + } + if (msg.data.error) { + stamps[msg.data.stamp].reject(msg.data.error) + } else { + stamps[msg.data.stamp].resolve(msg.data.result) + } } else if (msg.data.cmd === 'initiateResult') { if (!msg.data.error) { this.provider = { sendAsync: (query, callback) => { - const stamp = Date.now() + incr - incr++ - stamps[stamp] = callback - this.worker.postMessage({ cmd: 'sendAsync', query, stamp }) + return new Promise((resolve, reject) => { + const stamp = Date.now() + incr + incr++ + stamps[stamp] = { callback, resolve, reject } + this.worker.postMessage({ cmd: 'sendAsync', query, stamp }) + }) } } - this.web3 = new Web3(this.provider) + this.web3 = new Web3(this.provider as LegacySendAsyncProvider) extend(this.web3) this.executionContext.setWeb3(this.executionContext.getProvider(), this.web3) resolve({}) @@ -85,8 +95,8 @@ export class VMProvider { } async getBalanceInEther (address) { - const balance = await this.web3.eth.getBalance(address) - return Web3.utils.fromWei(new BN(balance).toString(10), 'ether') + const balance = await this.web3.eth.getBalance(address, undefined, { number: FMT_NUMBER.HEX, bytes: FMT_BYTES.HEX }) + return fromWei(toBigInt(balance).toString(10), 'ether') } getGasPrice (cb) { @@ -95,12 +105,10 @@ export class VMProvider { signMessage (message, account, _passphrase, cb) { const messageHash = hashPersonalMessage(Buffer.from(message)) - this.web3.eth.sign(message, account, (error, signedData) => { - if (error) { - return cb(error) - } - cb(null, '0x' + messageHash.toString('hex'), signedData) - }) + message = isHexString(message) ? message : Web3.utils.utf8ToHex(message) + this.web3.eth.sign(message, account) + .then(signedData => cb(null, '0x' + messageHash.toString('hex'), signedData)) + .catch(error => cb(error)) } getProvider () { diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index c64a92be85..3eae7a18f7 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -72,6 +72,7 @@ let requiredModules = [ 'codeParser', 'codeFormatter', 'solidityumlgen', + 'compilationDetails', 'contractflattener', 'solidity-script', 'openaigpt' @@ -85,7 +86,7 @@ if (isElectron()) { // dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd) const dependentModules = ['foundry', 'hardhat', 'truffle', 'slither'] -const loadLocalPlugins = ['doc-gen', 'doc-viewer', 'etherscan', 'vyper', 'solhint', 'walletconnect', 'circuit-compiler'] +const loadLocalPlugins = ['doc-gen', 'doc-viewer', 'etherscan', 'vyper', 'solhint', 'walletconnect', 'circuit-compiler', 'compilationDetails'] const sensitiveCalls = { fileManager: ['writeFile', 'copyFile', 'rename', 'copyDir'], diff --git a/libs/ghaction-helper/package.json b/libs/ghaction-helper/package.json index bf4fe18c4c..317bde707e 100644 --- a/libs/ghaction-helper/package.json +++ b/libs/ghaction-helper/package.json @@ -28,8 +28,9 @@ "@remix-project/remix-simulator": "^0.2.33", "chai": "^4.3.7", "ethers": "^5.7.2", - "web3": "^1.5.3" + "web3": "^4.1.1" }, "types": "./src/index.d.ts", "gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220" -} \ No newline at end of file +} + diff --git a/libs/remix-analyzer/package.json b/libs/remix-analyzer/package.json index 781a3a3bdc..c1934128e8 100644 --- a/libs/remix-analyzer/package.json +++ b/libs/remix-analyzer/package.json @@ -31,7 +31,7 @@ "ethers": "^5.4.2", "ethjs-util": "^0.1.6", "string-similarity": "^4.0.4", - "web3": "^1.5.1" + "web3": "^4.1.1" }, "publishConfig": { "access": "public" @@ -52,4 +52,4 @@ "typings": "src/index.d.ts", "gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220", "main": "./src/index.js" -} \ No newline at end of file +} diff --git a/libs/remix-astwalker/package.json b/libs/remix-astwalker/package.json index 636700b360..b0ed444540 100644 --- a/libs/remix-astwalker/package.json +++ b/libs/remix-astwalker/package.json @@ -47,7 +47,7 @@ "tape": "^4.10.1", "ts-node": "^8.0.3", "typescript": "^3.4.3", - "web3": "^1.5.1" + "web3": "^4.1.1" }, "devDependencies": { "tap-spec": "^5.0.0" @@ -55,4 +55,4 @@ "typings": "src/index.d.ts", "gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220", "types": "./src/index.d.ts" -} \ No newline at end of file +} diff --git a/libs/remix-debug/package.json b/libs/remix-debug/package.json index 32799caf49..4061d3349b 100644 --- a/libs/remix-debug/package.json +++ b/libs/remix-debug/package.json @@ -41,7 +41,7 @@ "merge": "^2.1.1", "string-similarity": "^4.0.4", "time-stamp": "^2.2.0", - "web3": "^1.5.1" + "web3": "^4.1.1" }, "devDependencies": { "@babel/core": "^7.4.5", @@ -71,4 +71,4 @@ "typings": "src/index.d.ts", "gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220", "types": "./src/index.d.ts" -} \ No newline at end of file +} diff --git a/libs/remix-debug/src/code/codeManager.ts b/libs/remix-debug/src/code/codeManager.ts index 6d644a8eba..5dd998a70e 100644 --- a/libs/remix-debug/src/code/codeManager.ts +++ b/libs/remix-debug/src/code/codeManager.ts @@ -26,12 +26,9 @@ export class CodeManager { this.codeResolver = new CodeResolver({ getCode: async (address) => { return new Promise((resolve, reject) => { - this.traceManager.web3.eth.getCode(address, (error, code) => { - if (error) { - return reject(error) - } - return resolve(code) - }) + this.traceManager.web3.eth.getCode(address) + .then(code => resolve(code)) + .catch(error => reject(error)) }) }, fork: this.traceManager.getCurrentFork() diff --git a/libs/remix-debug/src/init.ts b/libs/remix-debug/src/init.ts index fab25c5039..2cd616226d 100644 --- a/libs/remix-debug/src/init.ts +++ b/libs/remix-debug/src/init.ts @@ -1,18 +1,20 @@ 'use strict' -import Web3 from 'web3' +import Web3, { Web3PluginBase } from 'web3' + +export function extendWeb3 (web3) { + if(!web3.debug){ + web3.registerPlugin(new Web3DebugPlugin()) + } +} export function loadWeb3 (url) { if (!url) url = 'http://localhost:8545' const web3 = new Web3() web3.setProvider(new Web3.providers.HttpProvider(url)) - extend(web3) + extendWeb3(web3) return web3 } -export function extendWeb3 (web3) { - extend(web3) -} - export function setProvider (web3, url) { web3.setProvider(new web3.providers.HttpProvider(url)) } @@ -31,43 +33,33 @@ export function web3DebugNode (network) { return null } -export function extend (web3) { - if (!web3.extend) { - return - } - // DEBUG - const methods = [] - if (!(web3.debug && web3.debug.preimage)) { - methods.push(new web3.extend.Method({ - name: 'preimage', - call: 'debug_preimage', - inputFormatter: [null], - params: 1 - })) - } +class Web3DebugPlugin extends Web3PluginBase { + public pluginNamespace = 'debug' - if (!(web3.debug && web3.debug.traceTransaction)) { - methods.push(new web3.extend.Method({ - name: 'traceTransaction', - call: 'debug_traceTransaction', - inputFormatter: [null, null], - params: 2 - })) + public preimage(key, cb) { + this.requestManager.send({ + method: 'debug_preimage', + params: [key] + }) + .then(result => cb(null, result)) + .catch(error => cb(error)) } - if (!(web3.debug && web3.debug.storageRangeAt)) { - methods.push(new web3.extend.Method({ - name: 'storageRangeAt', - call: 'debug_storageRangeAt', - inputFormatter: [null, null, null, null, null], - params: 5 - })) + public traceTransaction(txHash, options, cb) { + this.requestManager.send({ + method: 'debug_traceTransaction', + params: [txHash, options] + }) + .then(result => cb(null, result)) + .catch(error => cb(error)) } - if (methods.length > 0) { - web3.extend({ - property: 'debug', - methods: methods, - properties: [] + + public storageRangeAt(txBlockHash, txIndex, address, start, maxSize, cb) { + this.requestManager.send({ + method: 'debug_storageRangeAt', + params: [txBlockHash, txIndex, address, start, maxSize] }) + .then(result => cb(null, result)) + .catch(error => cb(error)) } } diff --git a/libs/remix-debug/src/solidity-decoder/internalCallTree.ts b/libs/remix-debug/src/solidity-decoder/internalCallTree.ts index 4233ec9cbb..4f74ad4585 100644 --- a/libs/remix-debug/src/solidity-decoder/internalCallTree.ts +++ b/libs/remix-debug/src/solidity-decoder/internalCallTree.ts @@ -165,7 +165,6 @@ export class InternalCallTree { const scope = this.findScope(vmtraceIndex) if (!scope) return [] let scopeId = this.scopeStarts[scope.firstStep] - const scopeDetail = this.scopes[scopeId] const functions = [] if (!scopeId) return functions let i = 0 @@ -174,6 +173,7 @@ export class InternalCallTree { i += 1 if (i > 1000) throw new Error('retrieFunctionStack: recursion too deep') const functionDefinition = this.functionDefinitionsByScope[scopeId] + const scopeDetail = this.scopes[scopeId] if (functionDefinition !== undefined) { functions.push({ ...functionDefinition, ...scopeDetail }) } @@ -280,7 +280,10 @@ async function buildTree (tree, step, scopeId, isCreation, functionDefinition?, const stepDetail: StepDetail = tree.traceManager.trace[step] const nextStepDetail: StepDetail = tree.traceManager.trace[step + 1] if (stepDetail && nextStepDetail) { + // for complicated opcodes which don't have a static gas cost: stepDetail.gasCost = parseInt(stepDetail.gas as string) - parseInt(nextStepDetail.gas as string) + } else { + stepDetail.gasCost = parseInt(stepDetail.gasCost as unknown as string) } // gas per line diff --git a/libs/remix-debug/test/debugger.ts b/libs/remix-debug/test/debugger.ts index e573f3e137..4c93d17f18 100644 --- a/libs/remix-debug/test/debugger.ts +++ b/libs/remix-debug/test/debugger.ts @@ -156,15 +156,13 @@ contract Ballot { output = JSON.parse(output) const param = '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000148656c6c6f20576f726c64210000000000000000000000000000000000000000' const web3 = await vmCall.getWeb3() - vmCall.sendTx(web3, {nonce: 0, privateKey: privateKey}, null, 0, output.contracts['test.sol']['Ballot'].evm.bytecode.object + param, (error, hash) => { + vmCall.sendTx(web3, {nonce: 0, privateKey: privateKey}, undefined, 0, output.contracts['test.sol']['Ballot'].evm.bytecode.object + param, (error, hash) => { console.log(error, hash) if (error) { throw error } else { - web3.eth.getTransaction(hash, (error, tx) => { - if (error) { - throw error - } else { + web3.eth.getTransaction(hash) + .then(tx => { const sources = { target: 'test.sol', sources: { 'test.sol': { content: ballot } } @@ -193,8 +191,8 @@ contract Ballot { }) debugManager.debug(tx) - } - }) + }) + .catch(error => { throw error }) } }) })() diff --git a/libs/remix-debug/test/decoder/localsTests/calldata.ts b/libs/remix-debug/test/decoder/localsTests/calldata.ts index c198840b7a..213fd5d96b 100644 --- a/libs/remix-debug/test/decoder/localsTests/calldata.ts +++ b/libs/remix-debug/test/decoder/localsTests/calldata.ts @@ -15,7 +15,7 @@ module.exports = async function (st, privateKey, contractBytecode, compilationRe let web3 try { web3 = await (vmCall as any).getWeb3() - const hash = await (vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode) + const hash = await (vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, undefined, 0, contractBytecode) const receipt = await web3.eth.getTransactionReceipt(hash) const to = receipt.contractAddress console.log('to', to) @@ -25,52 +25,51 @@ module.exports = async function (st, privateKey, contractBytecode, compilationRe return st.fail(e) } return new Promise((resolve) => { - web3.eth.getTransaction(txHash, function (error, tx) { - if (error) { - return st.fail(error) - } - const traceManager = new TraceManager({ web3 }) - const codeManager = new CodeManager(traceManager) - codeManager.clear() - const solidityProxy = new SolidityProxy({ - getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), - getCode: codeManager.getCode.bind(codeManager), - compilationResult: () => compilationResult - }) - const debuggerEvent = new EventManager() - const offsetToLineColumnConverter = { - offsetToLineColumn: (rawLocation) => { - return new Promise((resolve) => { - const lineBreaks = sourceMappingDecoder.getLinebreakPositions(contractCode) - resolve(sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, lineBreaks)) - }) - } - } - const callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true }, offsetToLineColumnConverter) - callTree.event.register('callTreeBuildFailed', (error) => { - st.fail(error) - }) - callTree.event.register('callTreeNotReady', (reason) => { - st.fail(reason) - }) - callTree.event.register('callTreeReady', (scopes, scopeStarts) => { - helper.decodeLocals(st, 140, traceManager, callTree, function (locals) { - try { - const expected = {"p":{"value":"45","type":"uint256"},"foo":{"length":"1","value":[{"value":"3","type":"uint8"}],"type":"uint8[1]"},"boo":{"length":"1","value":[{"length":"2","value":[{"value":"R","type":"string"},{"value":"T","type":"string"}],"type":"string[2]"}],"type":"string[2][1]"}} - st.deepEqual(locals, expected) - } catch (e) { - st.fail(e.message) + web3.eth.getTransaction(txHash) + .then(tx => { + const traceManager = new TraceManager({ web3 }) + const codeManager = new CodeManager(traceManager) + codeManager.clear() + const solidityProxy = new SolidityProxy({ + getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), + getCode: codeManager.getCode.bind(codeManager), + compilationResult: () => compilationResult + }) + const debuggerEvent = new EventManager() + const offsetToLineColumnConverter = { + offsetToLineColumn: (rawLocation) => { + return new Promise((resolve) => { + const lineBreaks = sourceMappingDecoder.getLinebreakPositions(contractCode) + resolve(sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, lineBreaks)) + }) } - resolve({}) + } + const callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true }, offsetToLineColumnConverter) + callTree.event.register('callTreeBuildFailed', (error) => { + st.fail(error) }) - }) - + callTree.event.register('callTreeNotReady', (reason) => { + st.fail(reason) + }) + callTree.event.register('callTreeReady', (scopes, scopeStarts) => { + helper.decodeLocals(st, 140, traceManager, callTree, function (locals) { + try { + const expected = {"p":{"value":"45","type":"uint256"},"foo":{"length":"1","value":[{"value":"3","type":"uint8"}],"type":"uint8[1]"},"boo":{"length":"1","value":[{"length":"2","value":[{"value":"R","type":"string"},{"value":"T","type":"string"}],"type":"string[2]"}],"type":"string[2][1]"}} + st.deepEqual(locals, expected) + } catch (e) { + st.fail(e.message) + } + resolve({}) + }) + }) + - traceManager.resolveTrace(tx).then(() => { - debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) - }).catch((error) => { - st.fail(error) + traceManager.resolveTrace(tx).then(() => { + debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) + }).catch((error) => { + st.fail(error) + }) }) - }) + .catch(error => st.fail(error)) }) } \ No newline at end of file diff --git a/libs/remix-debug/test/decoder/localsTests/int.ts b/libs/remix-debug/test/decoder/localsTests/int.ts index 72d02c145b..fa52b55714 100644 --- a/libs/remix-debug/test/decoder/localsTests/int.ts +++ b/libs/remix-debug/test/decoder/localsTests/int.ts @@ -14,136 +14,140 @@ module.exports = function (st, privateKey, contractBytecode, compilationResult, // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve) => { const web3 = await (vmCall as any).getWeb3(); - (vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode, function (error, hash) { + (vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, undefined, 0, contractBytecode, function (error, hash) { if (error) { return st.fail(error) } - web3.eth.getTransaction(hash, function (error, tx) { - if (error) { - return st.fail(error) - } - tx.to = contractCreationToken('0') - const traceManager = new TraceManager({ web3 }) - const codeManager = new CodeManager(traceManager) - codeManager.clear() - const solidityProxy = new SolidityProxy({ - getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), - getCode: codeManager.getCode.bind(codeManager), - compilationResult: () => compilationResult - }) - const debuggerEvent = new EventManager() - const offsetToLineColumnConverter = { - offsetToLineColumn: (rawLocation) => { - return new Promise((resolve) => { - const lineBreaks = sourceMappingDecoder.getLinebreakPositions(contractCode) - resolve(sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, lineBreaks)) - }) + web3.eth.getTransaction(hash) + .then(tx => { + tx.to = contractCreationToken('0') + const traceManager = new TraceManager({ web3 }) + const codeManager = new CodeManager(traceManager) + codeManager.clear() + const solidityProxy = new SolidityProxy({ + getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), + getCode: codeManager.getCode.bind(codeManager), + compilationResult: () => compilationResult + }) + const debuggerEvent = new EventManager() + const offsetToLineColumnConverter = { + offsetToLineColumn: (rawLocation) => { + return new Promise((resolve) => { + const lineBreaks = sourceMappingDecoder.getLinebreakPositions(contractCode) + resolve(sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, lineBreaks)) + }) + } } - } - const callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true }, offsetToLineColumnConverter) - callTree.event.register('callTreeBuildFailed', (error) => { - st.fail(error) - }) - callTree.event.register('callTreeNotReady', (reason) => { - st.fail(reason) - }) - callTree.event.register('callTreeReady', async (scopes, scopeStarts) => { - try { - - // test gas cost per line - st.equals((await callTree.getGasCostPerLine(0, 16)).gasCost, 11) - st.equals((await callTree.getGasCostPerLine(0, 32)).gasCost, 84) - - const functions1 = callTree.retrieveFunctionsStack(103) - const functions2 = callTree.retrieveFunctionsStack(116) - const functions3 = callTree.retrieveFunctionsStack(13) - - st.equals(functions1.length, 2) - st.equals(functions2.length, 3) - st.equals(functions3.length, 1) - - st.equal(functions1[0].gasCost, 54) - - st.equals(Object.keys(functions1[0])[0], 'functionDefinition') - st.equals(Object.keys(functions1[0])[1], 'inputs') - st.equals(functions1[0].inputs[0], 'foo') - st.equals(Object.keys(functions2[0])[0], 'functionDefinition') - st.equals(Object.keys(functions2[0])[1], 'inputs') - st.equals(Object.keys(functions2[1])[0], 'functionDefinition') - st.equals(Object.keys(functions2[1])[1], 'inputs') - st.equals(functions2[0].inputs[0], 'asd') - st.equals(functions2[1].inputs[0], 'foo') + const callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true }, offsetToLineColumnConverter) + callTree.event.register('callTreeBuildFailed', (error) => { + st.fail(error) + }) + callTree.event.register('callTreeNotReady', (reason) => { + st.fail(reason) + }) + callTree.event.register('callTreeReady', async (scopes, scopeStarts) => { + try { - st.equals(functions1[0].functionDefinition.name, 'level11') - st.equals(functions2[0].functionDefinition.name, 'level12') - st.equals(functions2[1].functionDefinition.name, 'level11') - - st.equals(scopeStarts[0], '1') - st.equals(scopeStarts[10], '1.1') - st.equals(scopeStarts[102], '1.1.1') - st.equals(scopeStarts[115], '1.1.1.1') - st.equals(scopeStarts[136], '1.1.2') - st.equals(scopeStarts[153], '1.1.3') - st.equals(scopeStarts[166], '1.1.3.1') - st.equals(scopes['1.1'].locals['ui8'].type.typeName, 'uint8') - st.equals(scopes['1.1'].locals['ui16'].type.typeName, 'uint16') - st.equals(scopes['1.1'].locals['ui32'].type.typeName, 'uint32') - st.equals(scopes['1.1'].locals['ui64'].type.typeName, 'uint64') - st.equals(scopes['1.1'].locals['ui128'].type.typeName, 'uint128') - st.equals(scopes['1.1'].locals['ui256'].type.typeName, 'uint256') - st.equals(scopes['1.1'].locals['ui'].type.typeName, 'uint256') - st.equals(scopes['1.1'].locals['i8'].type.typeName, 'int8') - st.equals(scopes['1.1'].locals['i16'].type.typeName, 'int16') - st.equals(scopes['1.1'].locals['i32'].type.typeName, 'int32') - st.equals(scopes['1.1'].locals['i64'].type.typeName, 'int64') - st.equals(scopes['1.1'].locals['i128'].type.typeName, 'int128') - st.equals(scopes['1.1'].locals['i256'].type.typeName, 'int256') - st.equals(scopes['1.1'].locals['i'].type.typeName, 'int256') - st.equals(scopes['1.1'].locals['ishrink'].type.typeName, 'int32') - st.equals(scopes['1.1.1'].locals['ui8'].type.typeName, 'uint8') - st.equals(scopes['1.1.1.1'].locals['ui81'].type.typeName, 'uint8') - st.equals(scopes['1.1.2'].locals['ui81'].type.typeName, 'uint8') - st.equals(scopes['1.1.3'].locals['ui8'].type.typeName, 'uint8') - st.equals(scopes['1.1.3.1'].locals['ui81'].type.typeName, 'uint8') - } catch (e) { - st.fail(e.message) - } + // test gas cost per line + st.equals((await callTree.getGasCostPerLine(0, 16)).gasCost, 11) + st.equals((await callTree.getGasCostPerLine(0, 32)).gasCost, 84) + + const functions1 = callTree.retrieveFunctionsStack(103) + const functions2 = callTree.retrieveFunctionsStack(116) + const functions3 = callTree.retrieveFunctionsStack(13) - helper.decodeLocals(st, 95, traceManager, callTree, function (locals) { - st.equals(Object.keys(locals).length, 16) - st.equals(locals['ui8'].value, '130') - st.equals(locals['ui16'].value, '456') - st.equals(locals['ui32'].value, '4356') - st.equals(locals['ui64'].value, '3543543543') - st.equals(locals['ui128'].value, '234567') - st.equals(locals['ui256'].value, '115792089237316195423570985008687907853269984665640564039457584007880697216513') - st.equals(locals['ui'].value, '123545666') - st.equals(locals['i8'].value, '-45') - st.equals(locals['i16'].value, '-1234') - st.equals(locals['i32'].value, '3455') - st.equals(locals['i64'].value, '-35566') - st.equals(locals['i128'].value, '-444444') - st.equals(locals['i256'].value, '3434343') - st.equals(locals['i'].value, '-32432423423') - st.equals(locals['ishrink'].value, '2') - }) + st.equals(functions1.length, 2) + st.equals(functions2.length, 3) + st.equals(functions3.length, 1) - helper.decodeLocals(st, 106, traceManager, callTree, function (locals) { - try { - st.equals(locals['ui8'].value, '123') - st.equals(Object.keys(locals).length, 2) + st.equal(functions1[0].gasCost, 54) + st.equal(functions1[1].gasCost, 436) + + st.equal(functions2[0].gasCost, 23) + st.equal(functions2[1].gasCost, 54) + st.equal(functions2[2].gasCost, 436) + + st.equals(Object.keys(functions1[0])[0], 'functionDefinition') + st.equals(Object.keys(functions1[0])[1], 'inputs') + st.equals(functions1[0].inputs[0], 'foo') + st.equals(Object.keys(functions2[0])[0], 'functionDefinition') + st.equals(Object.keys(functions2[0])[1], 'inputs') + st.equals(Object.keys(functions2[1])[0], 'functionDefinition') + st.equals(Object.keys(functions2[1])[1], 'inputs') + st.equals(functions2[0].inputs[0], 'asd') + st.equals(functions2[1].inputs[0], 'foo') + + st.equals(functions1[0].functionDefinition.name, 'level11') + st.equals(functions2[0].functionDefinition.name, 'level12') + st.equals(functions2[1].functionDefinition.name, 'level11') + + st.equals(scopeStarts[0], '1') + st.equals(scopeStarts[10], '1.1') + st.equals(scopeStarts[102], '1.1.1') + st.equals(scopeStarts[115], '1.1.1.1') + st.equals(scopeStarts[136], '1.1.2') + st.equals(scopeStarts[153], '1.1.3') + st.equals(scopeStarts[166], '1.1.3.1') + st.equals(scopes['1.1'].locals['ui8'].type.typeName, 'uint8') + st.equals(scopes['1.1'].locals['ui16'].type.typeName, 'uint16') + st.equals(scopes['1.1'].locals['ui32'].type.typeName, 'uint32') + st.equals(scopes['1.1'].locals['ui64'].type.typeName, 'uint64') + st.equals(scopes['1.1'].locals['ui128'].type.typeName, 'uint128') + st.equals(scopes['1.1'].locals['ui256'].type.typeName, 'uint256') + st.equals(scopes['1.1'].locals['ui'].type.typeName, 'uint256') + st.equals(scopes['1.1'].locals['i8'].type.typeName, 'int8') + st.equals(scopes['1.1'].locals['i16'].type.typeName, 'int16') + st.equals(scopes['1.1'].locals['i32'].type.typeName, 'int32') + st.equals(scopes['1.1'].locals['i64'].type.typeName, 'int64') + st.equals(scopes['1.1'].locals['i128'].type.typeName, 'int128') + st.equals(scopes['1.1'].locals['i256'].type.typeName, 'int256') + st.equals(scopes['1.1'].locals['i'].type.typeName, 'int256') + st.equals(scopes['1.1'].locals['ishrink'].type.typeName, 'int32') + st.equals(scopes['1.1.1'].locals['ui8'].type.typeName, 'uint8') + st.equals(scopes['1.1.1.1'].locals['ui81'].type.typeName, 'uint8') + st.equals(scopes['1.1.2'].locals['ui81'].type.typeName, 'uint8') + st.equals(scopes['1.1.3'].locals['ui8'].type.typeName, 'uint8') + st.equals(scopes['1.1.3.1'].locals['ui81'].type.typeName, 'uint8') } catch (e) { st.fail(e.message) } - resolve({}) + + helper.decodeLocals(st, 95, traceManager, callTree, function (locals) { + st.equals(Object.keys(locals).length, 16) + st.equals(locals['ui8'].value, '130') + st.equals(locals['ui16'].value, '456') + st.equals(locals['ui32'].value, '4356') + st.equals(locals['ui64'].value, '3543543543') + st.equals(locals['ui128'].value, '234567') + st.equals(locals['ui256'].value, '115792089237316195423570985008687907853269984665640564039457584007880697216513') + st.equals(locals['ui'].value, '123545666') + st.equals(locals['i8'].value, '-45') + st.equals(locals['i16'].value, '-1234') + st.equals(locals['i32'].value, '3455') + st.equals(locals['i64'].value, '-35566') + st.equals(locals['i128'].value, '-444444') + st.equals(locals['i256'].value, '3434343') + st.equals(locals['i'].value, '-32432423423') + st.equals(locals['ishrink'].value, '2') + }) + + helper.decodeLocals(st, 106, traceManager, callTree, function (locals) { + try { + st.equals(locals['ui8'].value, '123') + st.equals(Object.keys(locals).length, 2) + } catch (e) { + st.fail(e.message) + } + resolve({}) + }) + }) + traceManager.resolveTrace(tx).then(() => { + debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) + }).catch((error) => { + st.fail(error) }) }) - traceManager.resolveTrace(tx).then(() => { - debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) - }).catch((error) => { - st.fail(error) - }) - }) + .catch(error => st.fail(error)) }) }) } diff --git a/libs/remix-debug/test/decoder/localsTests/misc.ts b/libs/remix-debug/test/decoder/localsTests/misc.ts index 6ea357fc42..c7f7c329bf 100644 --- a/libs/remix-debug/test/decoder/localsTests/misc.ts +++ b/libs/remix-debug/test/decoder/localsTests/misc.ts @@ -13,77 +13,76 @@ module.exports = function (st, privateKey, contractBytecode, compilationResult, // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve) => { const web3 = await (vmCall as any).getWeb3(); - (vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode, function (error, hash) { + (vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, undefined, 0, contractBytecode, function (error, hash) { if (error) { return st.fail(error) } - web3.eth.getTransaction(hash, function (error, tx) { - if (error) { - return st.fail(error) - } - tx.to = contractCreationToken('0') - const traceManager = new TraceManager({ web3 }) - const codeManager = new CodeManager(traceManager) - codeManager.clear() - const solidityProxy = new SolidityProxy({ - getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), - getCode: codeManager.getCode.bind(codeManager), - compilationResult: () => compilationResult - }) - const debuggerEvent = new EventManager() - const offsetToLineColumnConverter = { - offsetToLineColumn: (rawLocation) => { - return new Promise((resolve) => { - const lineBreaks = sourceMappingDecoder.getLinebreakPositions(contractCode) - resolve(sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, lineBreaks)) - }) - } - } - const callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true }, offsetToLineColumnConverter) - callTree.event.register('callTreeBuildFailed', (error) => { - st.fail(error) - }) - callTree.event.register('callTreeReady', (scopes, scopeStarts) => { - helper.decodeLocals(st, 70, traceManager, callTree, function (locals) { - try { - st.equals(locals['boolFalse'].value, false) - st.equals(locals['boolTrue'].value, true) - st.equals(locals['testEnum'].value, 'three') - st.equals(locals['sender'].value, '0x5B38DA6A701C568545DCFCB03FCB875F56BEDDC4') - st.equals(locals['_bytes1'].value, '0x99') - st.equals(locals['__bytes1'].value, '0x99') - st.equals(locals['__bytes2'].value, '0x99AB') - st.equals(locals['__bytes4'].value, '0x99FA0000') - st.equals(locals['__bytes6'].value, '0x990000000000') - st.equals(locals['__bytes7'].value, '0x99356700000000') - st.equals(locals['__bytes8'].value, '0x99ABD41700000000') - st.equals(locals['__bytes9'].value, '0x99156744AF00000000') - st.equals(locals['__bytes13'].value, '0x99123423425300000000000000') - st.equals(locals['__bytes16'].value, '0x99AFAD23432400000000000000000000') - st.equals(locals['__bytes24'].value, '0x99AFAD234324000000000000000000000000000000000000') - st.equals(locals['__bytes32'].value, '0x9999ABD41799ABD4170000000000000000000000000000000000000000000000') - st.equals(Object.keys(locals).length, 16) - } catch (e) { - st.fail(e.message) - } + web3.eth.getTransaction(hash) + .then(tx => { + tx.to = contractCreationToken('0') + const traceManager = new TraceManager({ web3 }) + const codeManager = new CodeManager(traceManager) + codeManager.clear() + const solidityProxy = new SolidityProxy({ + getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), + getCode: codeManager.getCode.bind(codeManager), + compilationResult: () => compilationResult }) - - helper.decodeLocals(st, 7, traceManager, callTree, function (locals) { - try { - // st.equals(Object.keys(locals).length, 0) - st.equals(0, 0) - } catch (e) { - st.fail(e.message) + const debuggerEvent = new EventManager() + const offsetToLineColumnConverter = { + offsetToLineColumn: (rawLocation) => { + return new Promise((resolve) => { + const lineBreaks = sourceMappingDecoder.getLinebreakPositions(contractCode) + resolve(sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, lineBreaks)) + }) } - resolve({}) + } + const callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true }, offsetToLineColumnConverter) + callTree.event.register('callTreeBuildFailed', (error) => { + st.fail(error) + }) + callTree.event.register('callTreeReady', (scopes, scopeStarts) => { + helper.decodeLocals(st, 70, traceManager, callTree, function (locals) { + try { + st.equals(locals['boolFalse'].value, false) + st.equals(locals['boolTrue'].value, true) + st.equals(locals['testEnum'].value, 'three') + st.equals(locals['sender'].value, '0x5B38DA6A701C568545DCFCB03FCB875F56BEDDC4') + st.equals(locals['_bytes1'].value, '0x99') + st.equals(locals['__bytes1'].value, '0x99') + st.equals(locals['__bytes2'].value, '0x99AB') + st.equals(locals['__bytes4'].value, '0x99FA0000') + st.equals(locals['__bytes6'].value, '0x990000000000') + st.equals(locals['__bytes7'].value, '0x99356700000000') + st.equals(locals['__bytes8'].value, '0x99ABD41700000000') + st.equals(locals['__bytes9'].value, '0x99156744AF00000000') + st.equals(locals['__bytes13'].value, '0x99123423425300000000000000') + st.equals(locals['__bytes16'].value, '0x99AFAD23432400000000000000000000') + st.equals(locals['__bytes24'].value, '0x99AFAD234324000000000000000000000000000000000000') + st.equals(locals['__bytes32'].value, '0x9999ABD41799ABD4170000000000000000000000000000000000000000000000') + st.equals(Object.keys(locals).length, 16) + } catch (e) { + st.fail(e.message) + } + }) + + helper.decodeLocals(st, 7, traceManager, callTree, function (locals) { + try { + // st.equals(Object.keys(locals).length, 0) + st.equals(0, 0) + } catch (e) { + st.fail(e.message) + } + resolve({}) + }) + }) + traceManager.resolveTrace(tx).then(() => { + debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) + }).catch((error) => { + st.fail(error) }) }) - traceManager.resolveTrace(tx).then(() => { - debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) - }).catch((error) => { - st.fail(error) - }) - }) + .catch(error => st.fail(error)) }) }) } diff --git a/libs/remix-debug/test/decoder/localsTests/misc2.ts b/libs/remix-debug/test/decoder/localsTests/misc2.ts index 4f4342c8b5..d92d2c59a9 100644 --- a/libs/remix-debug/test/decoder/localsTests/misc2.ts +++ b/libs/remix-debug/test/decoder/localsTests/misc2.ts @@ -13,63 +13,62 @@ module.exports = function (st, privateKey, contractBytecode, compilationResult, // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve) => { const web3 = await (vmCall as any).getWeb3(); - (vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode, function (error, hash) { + (vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, undefined, 0, contractBytecode, function (error, hash) { if (error) { return st.fail(error) } - web3.eth.getTransaction(hash, function (error, tx) { - if (error) { - return st.fail(error) - } - tx.to = contractCreationToken('0') - const traceManager = new TraceManager({ web3 }) - const codeManager = new CodeManager(traceManager) - codeManager.clear() - const solidityProxy = new SolidityProxy({ - getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), - getCode: codeManager.getCode.bind(codeManager), - compilationResult: () => compilationResult - }) - const debuggerEvent = new EventManager() - const offsetToLineColumnConverter = { - offsetToLineColumn: (rawLocation) => { - return new Promise((resolve) => { - const lineBreaks = sourceMappingDecoder.getLinebreakPositions(contractCode) - resolve(sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, lineBreaks)) - }) - } - } - const callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true }, offsetToLineColumnConverter) - callTree.event.register('callTreeBuildFailed', (error) => { - st.fail(error) - }) - callTree.event.register('callTreeReady', (scopes, scopeStarts) => { - helper.decodeLocals(st, 49, traceManager, callTree, function (locals) { - try { - st.equals(locals['dynbytes'].value, '0x64796e616d69636279746573') - st.equals(locals['smallstring'].value, 'test_test_test') - st.equals(Object.keys(locals).length, 2) - } catch (e) { - st.fail(e.message) - } + web3.eth.getTransaction(hash) + .then(tx => { + tx.to = contractCreationToken('0') + const traceManager = new TraceManager({ web3 }) + const codeManager = new CodeManager(traceManager) + codeManager.clear() + const solidityProxy = new SolidityProxy({ + getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), + getCode: codeManager.getCode.bind(codeManager), + compilationResult: () => compilationResult }) - - helper.decodeLocals(st, 7, traceManager, callTree, function (locals) { - try { - // st.equals(Object.keys(locals).length, 0) - st.equals(0, 0) - } catch (e) { - st.fail(e.message) + const debuggerEvent = new EventManager() + const offsetToLineColumnConverter = { + offsetToLineColumn: (rawLocation) => { + return new Promise((resolve) => { + const lineBreaks = sourceMappingDecoder.getLinebreakPositions(contractCode) + resolve(sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, lineBreaks)) + }) } - resolve({}) + } + const callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true }, offsetToLineColumnConverter) + callTree.event.register('callTreeBuildFailed', (error) => { + st.fail(error) + }) + callTree.event.register('callTreeReady', (scopes, scopeStarts) => { + helper.decodeLocals(st, 49, traceManager, callTree, function (locals) { + try { + st.equals(locals['dynbytes'].value, '0x64796e616d69636279746573') + st.equals(locals['smallstring'].value, 'test_test_test') + st.equals(Object.keys(locals).length, 2) + } catch (e) { + st.fail(e.message) + } + }) + + helper.decodeLocals(st, 7, traceManager, callTree, function (locals) { + try { + // st.equals(Object.keys(locals).length, 0) + st.equals(0, 0) + } catch (e) { + st.fail(e.message) + } + resolve({}) + }) + }) + traceManager.resolveTrace(tx).then(() => { + debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) + }).catch((error) => { + st.fail(error) }) }) - traceManager.resolveTrace(tx).then(() => { - debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) - }).catch((error) => { - st.fail(error) - }) - }) + .catch(error => st.fail(error)) }) }) } diff --git a/libs/remix-debug/test/decoder/localsTests/structArray.ts b/libs/remix-debug/test/decoder/localsTests/structArray.ts index f060199cbe..6324377a48 100644 --- a/libs/remix-debug/test/decoder/localsTests/structArray.ts +++ b/libs/remix-debug/test/decoder/localsTests/structArray.ts @@ -13,123 +13,122 @@ module.exports = function (st, privateKey, contractBytecode, compilationResult,c // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve) => { const web3 = await (vmCall as any).getWeb3(); - (vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode, function (error, hash) { + (vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, undefined, 0, contractBytecode, function (error, hash) { if (error) { return st.fail(error) } - web3.eth.getTransaction(hash, function (error, tx) { - if (error) { - return st.fail(error) - } - tx.to = contractCreationToken('0') - const traceManager = new TraceManager({ web3 }) - const codeManager = new CodeManager(traceManager) - codeManager.clear() - const solidityProxy = new SolidityProxy({ - getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), - getCode: codeManager.getCode.bind(codeManager), - compilationResult: () => compilationResult - }) - const debuggerEvent = new EventManager() - const offsetToLineColumnConverter = { - offsetToLineColumn: (rawLocation) => { - return new Promise((resolve) => { - const lineBreaks = sourceMappingDecoder.getLinebreakPositions(contractCode) - resolve(sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, lineBreaks)) - }) + web3.eth.getTransaction(hash) + .then(tx => { + tx.to = contractCreationToken('0') + const traceManager = new TraceManager({ web3 }) + const codeManager = new CodeManager(traceManager) + codeManager.clear() + const solidityProxy = new SolidityProxy({ + getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), + getCode: codeManager.getCode.bind(codeManager), + compilationResult: () => compilationResult + }) + const debuggerEvent = new EventManager() + const offsetToLineColumnConverter = { + offsetToLineColumn: (rawLocation) => { + return new Promise((resolve) => { + const lineBreaks = sourceMappingDecoder.getLinebreakPositions(contractCode) + resolve(sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, lineBreaks)) + }) + } } - } - const callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true }, offsetToLineColumnConverter) - callTree.event.register('callTreeBuildFailed', (error) => { - st.fail(error) - }) - callTree.event.register('callTreeReady', (scopes, scopeStarts) => { - helper.decodeLocals(st, 1622, traceManager, callTree, function (locals) { - try { - console.log('at 1622', locals) - st.equals(locals['bytesSimple'].length, '0x14') - st.equals(locals['bytesSimple'].value, '0x746573745f7375706572') - st.equals(locals['e'].value['a'].value, 'test') - st.equals(locals['e'].value['a'].length, '0x8') - st.equals(locals['e'].value['a'].raw, '0x74657374') - st.equals(locals['e'].value['b'].value, '5') - st.equals(locals['e'].value['c'].length, '0x220') - st.equals(locals['e'].value['c'].raw, '0x746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374') - st.equals(locals['e'].value['c'].value, 'test_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_test') - st.equals(locals['e'].value['d'].value, '3') - st.equals(locals['f'].length, '0x1b8') - st.equals(locals['f'].raw, '0x746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f') - st.equals(locals['f'].value, 'test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_') - st.equals(locals['e'].value['e'].value, true) - - st.equals(locals['simpleArray'].value[0].value, '45') - st.equals(locals['simpleArray'].value[1].value, '324324') - st.equals(locals['simpleArray'].value[2].value, '-333') - st.equals(locals['simpleArray'].value[3].value, '5656') - st.equals(locals['simpleArray'].value[4].value, '-1111') - - st.equals(locals['stringArray'].value[0].value, 'long_one_long_one_long_one_long_one_long_one_long_one_long_one_long_one_long_one_long_one_long_one_long_one_long_one_long_one_long_one_') - st.equals(locals['stringArray'].value[1].value, 'two') - st.equals(locals['stringArray'].value[2].value, 'three') - - st.equals(locals['dynArray'].value[0].value[0].value, '3423423532') - st.equals(locals['dynArray'].value[1].value[0].value, '-342343323532') - st.equals(locals['dynArray'].value[1].value[1].value, '23432') - st.equals(locals['dynArray'].value[2].value[0].value, '-432432') - st.equals(locals['dynArray'].value[2].value[1].value, '3423423532') - st.equals(locals['dynArray'].value[2].value[2].value, '-432432') - - st.equals(locals['structArray'].value[0].value['a'].value, 'test') - st.equals(locals['structArray'].value[0].value['a'].length, '0x8') - st.equals(locals['structArray'].value[0].value['a'].raw, '0x74657374') - st.equals(locals['structArray'].value[0].value['b'].value, '5') - st.equals(locals['structArray'].value[0].value['c'].length, '0x220') - st.equals(locals['structArray'].value[0].value['c'].raw, '0x746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374') - st.equals(locals['structArray'].value[0].value['c'].value, 'test_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_test') - st.equals(locals['structArray'].value[0].value['d'].value, '3') - st.equals(locals['structArray'].value[0].value['e'].value, true) - - st.equals(locals['structArray'].value[1].value['a'].value, 'item1 a') - st.equals(locals['structArray'].value[1].value['b'].value, '20') - st.equals(locals['structArray'].value[1].value['c'].value, 'item1 c') - st.equals(locals['structArray'].value[1].value['d'].value, '-45') - st.equals(locals['structArray'].value[1].value['e'].value, false) - - st.equals(locals['structArray'].value[2].value['a'].value, 'item2 a') - st.equals(locals['structArray'].value[2].value['b'].value, '200') - st.equals(locals['structArray'].value[2].value['c'].value, 'item2 c') - st.equals(locals['structArray'].value[2].value['d'].value, '-450') - st.equals(locals['structArray'].value[2].value['e'].value, true) - - st.equals(locals['arrayStruct'].value.a.value[0].value, 'string') - st.equals(locals['arrayStruct'].value.b.value[0].value, '34') - st.equals(locals['arrayStruct'].value.b.value[1].value, '-23') - st.equals(locals['arrayStruct'].value.b.value[2].value, '-3') - st.equals(locals['arrayStruct'].value.c.value, 'three') + const callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true }, offsetToLineColumnConverter) + callTree.event.register('callTreeBuildFailed', (error) => { + st.fail(error) + }) + callTree.event.register('callTreeReady', (scopes, scopeStarts) => { + helper.decodeLocals(st, 1622, traceManager, callTree, function (locals) { + try { + console.log('at 1622', locals) + st.equals(locals['bytesSimple'].length, '0x14') + st.equals(locals['bytesSimple'].value, '0x746573745f7375706572') + st.equals(locals['e'].value['a'].value, 'test') + st.equals(locals['e'].value['a'].length, '0x8') + st.equals(locals['e'].value['a'].raw, '0x74657374') + st.equals(locals['e'].value['b'].value, '5') + st.equals(locals['e'].value['c'].length, '0x220') + st.equals(locals['e'].value['c'].raw, '0x746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374') + st.equals(locals['e'].value['c'].value, 'test_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_test') + st.equals(locals['e'].value['d'].value, '3') + st.equals(locals['f'].length, '0x1b8') + st.equals(locals['f'].raw, '0x746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f') + st.equals(locals['f'].value, 'test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_test_long_') + st.equals(locals['e'].value['e'].value, true) + + st.equals(locals['simpleArray'].value[0].value, '45') + st.equals(locals['simpleArray'].value[1].value, '324324') + st.equals(locals['simpleArray'].value[2].value, '-333') + st.equals(locals['simpleArray'].value[3].value, '5656') + st.equals(locals['simpleArray'].value[4].value, '-1111') + + st.equals(locals['stringArray'].value[0].value, 'long_one_long_one_long_one_long_one_long_one_long_one_long_one_long_one_long_one_long_one_long_one_long_one_long_one_long_one_long_one_') + st.equals(locals['stringArray'].value[1].value, 'two') + st.equals(locals['stringArray'].value[2].value, 'three') + + st.equals(locals['dynArray'].value[0].value[0].value, '3423423532') + st.equals(locals['dynArray'].value[1].value[0].value, '-342343323532') + st.equals(locals['dynArray'].value[1].value[1].value, '23432') + st.equals(locals['dynArray'].value[2].value[0].value, '-432432') + st.equals(locals['dynArray'].value[2].value[1].value, '3423423532') + st.equals(locals['dynArray'].value[2].value[2].value, '-432432') + + st.equals(locals['structArray'].value[0].value['a'].value, 'test') + st.equals(locals['structArray'].value[0].value['a'].length, '0x8') + st.equals(locals['structArray'].value[0].value['a'].raw, '0x74657374') + st.equals(locals['structArray'].value[0].value['b'].value, '5') + st.equals(locals['structArray'].value[0].value['c'].length, '0x220') + st.equals(locals['structArray'].value[0].value['c'].raw, '0x746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374746573745f6c6f6e675f746573745f6c6f6e675f746573745f6c6f6e675f74657374') + st.equals(locals['structArray'].value[0].value['c'].value, 'test_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_testtest_long_test_long_test_long_test') + st.equals(locals['structArray'].value[0].value['d'].value, '3') + st.equals(locals['structArray'].value[0].value['e'].value, true) + + st.equals(locals['structArray'].value[1].value['a'].value, 'item1 a') + st.equals(locals['structArray'].value[1].value['b'].value, '20') + st.equals(locals['structArray'].value[1].value['c'].value, 'item1 c') + st.equals(locals['structArray'].value[1].value['d'].value, '-45') + st.equals(locals['structArray'].value[1].value['e'].value, false) + + st.equals(locals['structArray'].value[2].value['a'].value, 'item2 a') + st.equals(locals['structArray'].value[2].value['b'].value, '200') + st.equals(locals['structArray'].value[2].value['c'].value, 'item2 c') + st.equals(locals['structArray'].value[2].value['d'].value, '-450') + st.equals(locals['structArray'].value[2].value['e'].value, true) + + st.equals(locals['arrayStruct'].value.a.value[0].value, 'string') + st.equals(locals['arrayStruct'].value.b.value[0].value, '34') + st.equals(locals['arrayStruct'].value.b.value[1].value, '-23') + st.equals(locals['arrayStruct'].value.b.value[2].value, '-3') + st.equals(locals['arrayStruct'].value.c.value, 'three') + + st.equals(Object.keys(locals).length, 8) + } catch (e) { + st.fail(e.message) + } + }) - st.equals(Object.keys(locals).length, 8) - } catch (e) { - st.fail(e.message) - } + helper.decodeLocals(st, 7, traceManager, callTree, function (locals) { + try { + console.log('at 7', locals) + st.equals(0, 0) + // st.equals(Object.keys(locals).length, 0) + } catch (e) { + st.fail(e.message) + } + resolve({}) + }) }) - - helper.decodeLocals(st, 7, traceManager, callTree, function (locals) { - try { - console.log('at 7', locals) - st.equals(0, 0) - // st.equals(Object.keys(locals).length, 0) - } catch (e) { - st.fail(e.message) - } - resolve({}) + traceManager.resolveTrace(tx).then(() => { + debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) + }).catch((error) => { + st.fail(error) }) }) - traceManager.resolveTrace(tx).then(() => { - debuggerEvent.trigger('newTraceLoaded', [traceManager.trace]) - }).catch((error) => { - st.fail(error) - }) - }) + .catch(error => st.fail(error)) }) }) } diff --git a/libs/remix-debug/test/decoder/stateTests/mapping.ts b/libs/remix-debug/test/decoder/stateTests/mapping.ts index 52b457e8ce..09056d3693 100644 --- a/libs/remix-debug/test/decoder/stateTests/mapping.ts +++ b/libs/remix-debug/test/decoder/stateTests/mapping.ts @@ -23,23 +23,22 @@ module.exports = async function testMappingStorage (st, cb) { } const compilationResults = new CompilerAbstract('json', output, sources) const web3 = await (vmCall as any).getWeb3(); - (vmCall as any).sendTx(web3, {nonce: 0, privateKey: privateKey}, null, 0, output.contracts['test.sol']['SimpleMappingState'].evm.bytecode.object, function (error, hash) { + (vmCall as any).sendTx(web3, {nonce: 0, privateKey: privateKey}, undefined, 0, output.contracts['test.sol']['SimpleMappingState'].evm.bytecode.object, function (error, hash) { if (error) { console.log(error) st.end(error) } else { - web3.eth.getTransactionReceipt(hash, (error, tx) => { - if (error) { - console.log(error) - st.end(error) - } else { + web3.eth.getTransactionReceipt(hash) + .then(tx => // const storage = await this.vm.stateManager.dumpStorage(data.to) // (vmCall as any).web3().eth.getCode(tx.contractAddress).then((code) => console.log('code:', code)) // (vmCall as any).web3().debug.traceTransaction(hash).then((code) => console.log('trace:', code)) testMapping(st, privateKey, tx.contractAddress, output, compilationResults, web3, cb) // st.end() - } - }) + ) + .catch(error => { + st.end(error) + }) } }) } @@ -50,18 +49,15 @@ function testMapping (st, privateKey, contractAddress, output, compilationResult if (error) { console.log(error) st.end(error) - } else { - web3.eth.getTransaction(hash, (error, tx) => { - if (error) { - console.log(error) - st.end(error) - } else { + } else { + web3.eth.getTransaction(hash) + .then(tx => { const traceManager = new TraceManager({ web3 }) const codeManager = new CodeManager(traceManager) codeManager.clear() console.log(compilationResults) - const solidityProxy = new SolidityProxy({ - getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), + const solidityProxy = new SolidityProxy({ + getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), getCode: codeManager.getCode.bind(codeManager), compilationResult: () => compilationResults }) @@ -101,8 +97,11 @@ function testMapping (st, privateKey, contractAddress, output, compilationResult }).catch((error) => { st.fail(error) }) - } - }) + }) + .catch(error => { + console.log(error) + st.end(error) + }) } }) } diff --git a/libs/remix-debug/test/vmCall.ts b/libs/remix-debug/test/vmCall.ts index 56d15729e9..b00a506983 100644 --- a/libs/remix-debug/test/vmCall.ts +++ b/libs/remix-debug/test/vmCall.ts @@ -1,8 +1,8 @@ 'use strict' import { extendWeb3 } from '../src/init' import { Address } from '@ethereumjs/util' +import { Web3 } from 'web3'; const { Provider } = require('@remix-project/remix-simulator') -const Web3 = require('web3') async function getWeb3 () { diff --git a/libs/remix-lib/package.json b/libs/remix-lib/package.json index afec35ad63..7e357fd524 100644 --- a/libs/remix-lib/package.json +++ b/libs/remix-lib/package.json @@ -25,7 +25,8 @@ "from-exponential": "1.1.1", "solc": "^0.7.4", "string-similarity": "^4.0.4", - "web3": "^1.5.1" + "web3": "^4.1.1", + "web3-validator": "^2.0.0" }, "devDependencies": { "@babel/core": "^7.4.5", @@ -54,4 +55,4 @@ "typings": "src/index.d.ts", "gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220", "types": "./src/index.d.ts" -} \ No newline at end of file +} diff --git a/libs/remix-lib/src/execution/logsManager.ts b/libs/remix-lib/src/execution/logsManager.ts index a8ae3ec3c8..7d9bba2c6b 100644 --- a/libs/remix-lib/src/execution/logsManager.ts +++ b/libs/remix-lib/src/execution/logsManager.ts @@ -20,12 +20,10 @@ export class LogsManager { checkBlock (blockNumber, block, web3) { eachOf(block.transactions, (tx: any, i, next) => { const txHash = '0x' + tx.hash().toString('hex') - web3.eth.getTransactionReceipt(txHash, (_error, receipt) => { for (const log of receipt.logs) { this.oldLogs.push({ type: 'block', blockNumber, block, tx, log, txNumber: i, receipt }) const subscriptions = this.getSubscriptionsFor({ type: 'block', blockNumber, block, tx, log, receipt}) - for (const subscriptionId of subscriptions) { const result = { logIndex: '0x1', // 1 diff --git a/libs/remix-lib/src/execution/txListener.ts b/libs/remix-lib/src/execution/txListener.ts index d4251f0297..203a0b9b66 100644 --- a/libs/remix-lib/src/execution/txListener.ts +++ b/libs/remix-lib/src/execution/txListener.ts @@ -33,7 +33,7 @@ export class TxListener { _listenOnNetwork:boolean _loopId blocks - + constructor (opt, executionContext) { this.event = new EventManager() // has a default for now for backwards compatibility @@ -63,7 +63,7 @@ export class TxListener { let returnValue let execResult if (this.executionContext.isVM()) { - execResult = await this.executionContext.web3().eth.getExecutionResultFromSimulator(txResult.transactionHash) + execResult = await this.executionContext.web3().remix.getExecutionResultFromSimulator(txResult.transactionHash) returnValue = toBuffer(execResult.returnValue) } else { returnValue = toBuffer(addHexPrefix(txResult.result)) @@ -94,19 +94,17 @@ export class TxListener { // in web3 mode && listen remix txs only if (!this._isListening) return // we don't listen if (this._loopId) return // we seems to already listen on a "web3" network - this.executionContext.web3().eth.getTransaction(txResult.transactionHash, async (error, tx) => { - if (error) return console.log(error) - + this.executionContext.web3().eth.getTransaction(txResult.transactionHash).then(async tx=>{ let execResult if (this.executionContext.isVM()) { - execResult = await this.executionContext.web3().eth.getExecutionResultFromSimulator(txResult.transactionHash) + execResult = await this.executionContext.web3().remix.getExecutionResultFromSimulator(txResult.transactionHash) } addExecutionCosts(txResult, tx, execResult) tx.envMode = this.executionContext.getProvider() tx.status = txResult.receipt.status this._resolve([tx]) - }) + }).catch(error=>console.log(error)) }) } @@ -159,7 +157,7 @@ export class TxListener { } async _startListenOnNetwork () { - let lastSeenBlock = this.executionContext.lastBlock?.number - 1 + let lastSeenBlock = this.executionContext.lastBlock?.number - BigInt(1) let processingBlock = false const processBlocks = async () => { @@ -204,7 +202,7 @@ export class TxListener { async _manageBlock (blockNumber) { try { const result = await this.executionContext.web3().eth.getBlock(blockNumber, true) - return await this._newBlock(Object.assign({ type: 'web3' }, result)) + return await this._newBlock(Object.assign({ type: 'web3' }, result)) } catch (e) {} } @@ -285,8 +283,7 @@ export class TxListener { // first check known contract, resolve against the `runtimeBytecode` if not known contract = this._resolvedContracts[tx.to] if (!contract) { - this.executionContext.web3().eth.getCode(tx.to, (error, code) => { - if (error) return cb(error) + this.executionContext.web3().eth.getCode(tx.to).then(code=>{ if (code) { const contract = this._tryResolveContract(code, contracts, false) if (contract) { @@ -296,7 +293,7 @@ export class TxListener { } } return cb() - }) + }).catch(error=>cb(error)) return } if (contract) { diff --git a/libs/remix-lib/src/execution/txRunnerVM.ts b/libs/remix-lib/src/execution/txRunnerVM.ts index 31364c045a..c71f8778a0 100644 --- a/libs/remix-lib/src/execution/txRunnerVM.ts +++ b/libs/remix-lib/src/execution/txRunnerVM.ts @@ -72,12 +72,12 @@ export class TxRunnerVM { if (!from && useCall && Object.keys(this.vmaccounts).length) { from = Object.keys(this.vmaccounts)[0] account = this.vmaccounts[from] - } else account = this.vmaccounts[from] - + } else account = this.vmaccounts[from] + if (!account) { return callback('Invalid account selected') } - + this.getVMObject().stateManager.getAccount(Address.fromString(from)).then((res: Account) => { const EIP1559 = this.commonContext.hardfork() !== 'berlin' // berlin is the only pre eip1559 fork that we handle. let tx @@ -106,7 +106,7 @@ export class TxRunnerVM { const coinbases = ['0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a', '0x8945a1288dc78a6d8952a92c77aee6730b414778', '0x94d76e24f818426ae84aa404140e8d5f60e10e7e'] const difficulties = [69762765929000, 70762765929000, 71762765929000] const difficulty = this.commonContext.consensusType() === ConsensusType.ProofOfStake ? 0 : difficulties[this.blockNumber % difficulties.length] - + const blocknumber = this.blockNumber + 1 const block = Block.fromBlockData({ header: { diff --git a/libs/remix-lib/src/execution/txRunnerWeb3.ts b/libs/remix-lib/src/execution/txRunnerWeb3.ts index ab754c0fef..78e13f2e2b 100644 --- a/libs/remix-lib/src/execution/txRunnerWeb3.ts +++ b/libs/remix-lib/src/execution/txRunnerWeb3.ts @@ -2,6 +2,7 @@ import { EventManager } from '../eventManager' import type { Transaction as InternalTransaction } from './txRunner' import Web3 from 'web3' +import {toBigInt} from 'web3-utils' export class TxRunnerWeb3 { event @@ -16,11 +17,13 @@ export class TxRunnerWeb3 { this._api = api } - _executeTx (tx, network, txFee, api, promptCb, callback) { + async _executeTx (tx, network, txFee, api, promptCb, callback) { if (network && network.lastBlock && network.lastBlock.baseFeePerGas) { // the sending stack (web3.js / metamask need to have the type defined) // this is to avoid the following issue: https://github.com/MetaMask/metamask-extension/issues/11824 tx.type = '0x2' + } else { + tx.type = '0x1' } if (txFee) { if (txFee.baseFeePerGas) { @@ -33,21 +36,6 @@ export class TxRunnerWeb3 { } } - if (api.personalMode()) { - promptCb( - (value) => { - this._sendTransaction((this.getWeb3() as any).personal.sendTransaction, tx, value, callback) - }, - () => { - return callback('Canceled by user.') - } - ) - } else { - this._sendTransaction(this.getWeb3().eth.sendTransaction, tx, null, callback) - } - } - - _sendTransaction (sendTx, tx, pass, callback) { let currentDateTime = new Date(); const start = currentDateTime.getTime() / 1000 const cb = (err, resp) => { @@ -72,11 +60,30 @@ export class TxRunnerWeb3 { } listenOnResponse().then((txData) => { callback(null, txData) }).catch((error) => { callback(error) }) } - const args = pass !== null ? [tx, pass, cb] : [tx, cb] - try { - sendTx.apply({}, args) - } catch (e) { - return callback(`Send transaction failed: ${e.message} . if you use an injected provider, please check it is properly unlocked. `) + + if (api.personalMode()) { + promptCb( + async (value) => { + try { + const res = await (this.getWeb3() as any).eth.personal.sendTransaction({...tx, value}) + cb(null, res.transactionHash) + } catch (e) { + console.log(`Send transaction failed: ${e.message} . if you use an injected provider, please check it is properly unlocked. `) + cb(null, e.receipt.transactionHash) + } + }, + () => { + return callback('Canceled by user.') + } + ) + } else { + try { + const res = await this.getWeb3().eth.sendTransaction(tx) + cb(null, res.transactionHash) + } catch (e) { + console.log(`Send transaction failed: ${e.message} . if you use an injected provider, please check it is properly unlocked. `) + cb(null, e.receipt.transactionHash) + } } } @@ -94,13 +101,15 @@ export class TxRunnerWeb3 { if (!from) return callback('the value of "from" is not defined. Please make sure an account is selected.') if (useCall) { tx['gas'] = gasLimit - if (this._api && this._api.isVM()) tx['timestamp'] = timestamp - return this.getWeb3().eth.call(tx, function (error, result: any) { - if (error) return callback(error) - callback(null, { + if (this._api && this._api.isVM()) { + (this.getWeb3() as any).remix.registerCallId(timestamp) + } + this.getWeb3().eth.call(tx) + .then((result: any) => callback(null, { result: result - }) - }) + })) + .catch(error => callback(error)) + return } this._api.detectNetwork((errNetWork, network) => { if (errNetWork) { @@ -113,48 +122,49 @@ export class TxRunnerWeb3 { // the sending stack (web3.js / metamask need to have the type defined) // this is to avoid the following issue: https://github.com/MetaMask/metamask-extension/issues/11824 txCopy.type = '0x2' - txCopy.maxFeePerGas = Math.ceil(network.lastBlock.baseFeePerGas + network.lastBlock.baseFeePerGas / 3) + txCopy.maxFeePerGas = Math.ceil(Number((toBigInt(network.lastBlock.baseFeePerGas) + toBigInt(network.lastBlock.baseFeePerGas) / BigInt(3)).toString())) } else { txCopy.type = '0x1' - txCopy.gasPrice = network.lastBlock.baseFeePerGas - } - } - this.getWeb3().eth.estimateGas(txCopy, (err, gasEstimation) => { - if (err && err.message.indexOf('Invalid JSON RPC response') !== -1) { - // // @todo(#378) this should be removed when https://github.com/WalletConnect/walletconnect-monorepo/issues/334 is fixed - callback(new Error('Gas estimation failed because of an unknown internal error. This may indicated that the transaction will fail.')) + txCopy.gasPrice = undefined } - err = network.name === 'VM' ? null : err // just send the tx if "VM" - gasEstimationForceSend(err, () => { - // callback is called whenever no error - tx['gas'] = !gasEstimation ? gasLimit : gasEstimation - - if (this._api.config.getUnpersistedProperty('doNotShowTransactionConfirmationAgain')) { - return this._executeTx(tx, network, null, this._api, promptCb, callback) - } + } + this.getWeb3().eth.estimateGas(txCopy) + .then(gasEstimation => { + gasEstimationForceSend(null, () => { + // callback is called whenever no error + tx['gas'] = !gasEstimation ? gasLimit : gasEstimation - confirmCb(network, tx, tx['gas'], (txFee) => { - return this._executeTx(tx, network, txFee, this._api, promptCb, callback) - }, (error) => { - callback(error) + if (this._api.config.getUnpersistedProperty('doNotShowTransactionConfirmationAgain')) { + return this._executeTx(tx, network, null, this._api, promptCb, callback) + } + + confirmCb(network, tx, tx['gas'], (txFee) => { + return this._executeTx(tx, network, txFee, this._api, promptCb, callback) + }, (error) => { + callback(error) + }) }) - }, () => { - const blockGasLimit = this.currentblockGasLimit() - // NOTE: estimateGas very likely will return a large limit if execution of the code failed - // we want to be able to run the code in order to debug and find the cause for the failure - if (err) return callback(err) - - let warnEstimation = ' An important gas estimation might also be the sign of a problem in the contract code. Please check loops and be sure you did not sent value to a non payable function (that\'s also the reason of strong gas estimation). ' - warnEstimation += ' ' + err - - if (gasEstimation > gasLimit) { - return callback('Gas required exceeds limit: ' + gasLimit + '. ' + warnEstimation) - } - if (gasEstimation > blockGasLimit) { - return callback('Gas required exceeds block gas limit: ' + gasLimit + '. ' + warnEstimation) + }) + .catch(err => { + if (err && err.message.indexOf('Invalid JSON RPC response') !== -1) { + // // @todo(#378) this should be removed when https://github.com/WalletConnect/walletconnect-monorepo/issues/334 is fixed + callback(new Error('Gas estimation failed because of an unknown internal error. This may indicated that the transaction will fail.')) } + err = network.name === 'VM' ? null : err // just send the tx if "VM" + gasEstimationForceSend(err, () => { + tx['gas'] = gasLimit + + if (this._api.config.getUnpersistedProperty('doNotShowTransactionConfirmationAgain')) { + return this._executeTx(tx, network, null, this._api, promptCb, callback) + } + + confirmCb(network, tx, tx['gas'], (txFee) => { + return this._executeTx(tx, network, txFee, this._api, promptCb, callback) + }, (error) => { + callback(error) + }) + }) }) - }) }) } } diff --git a/libs/remix-lib/src/execution/typeConversion.ts b/libs/remix-lib/src/execution/typeConversion.ts index 46a25bff8a..5d7bf97084 100644 --- a/libs/remix-lib/src/execution/typeConversion.ts +++ b/libs/remix-lib/src/execution/typeConversion.ts @@ -1,11 +1,12 @@ 'use strict' import { BN } from 'bn.js' import { bufferToHex } from '@ethereumjs/util' +import { isBigInt } from 'web3-validator' export function toInt (h) { if (h.indexOf && h.indexOf('0x') === 0) { return (new BN(h.replace('0x', ''), 16)).toString(10) - } else if ((h.constructor && h.constructor.name === 'BigNumber') || BN.isBN(h)) { + } else if ((h.constructor && h.constructor.name === 'BigNumber') || BN.isBN(h) || isBigInt(h)) { return h.toString(10) } return h @@ -21,7 +22,7 @@ function convertToString (v) { ret.push(convertToString(v[k])) } return ret - } else if (BN.isBN(v) || (v.constructor && v.constructor.name === 'BigNumber')) { + } else if (BN.isBN(v) || (v.constructor && v.constructor.name === 'BigNumber') || isBigInt(v)) { return v.toString(10) } else if (v._isBuffer) { return bufferToHex(v) diff --git a/libs/remix-lib/src/init.ts b/libs/remix-lib/src/init.ts index b59d10b4a4..c3e30f269d 100644 --- a/libs/remix-lib/src/init.ts +++ b/libs/remix-lib/src/init.ts @@ -1,54 +1,46 @@ 'use strict' -import Web3 from 'web3' +import Web3, { Web3PluginBase } from 'web3' + +export function extendWeb3 (web3) { + if(!web3.debug){ + web3.registerPlugin(new Web3DebugPlugin()) + } +} export function loadWeb3 (url = 'http://localhost:8545') { const web3 = new Web3() web3.setProvider(new Web3.providers.HttpProvider(url)) - extend(web3) + extendWeb3(web3) return web3 } -export function extendWeb3 (web3) { - extend(web3) -} +class Web3DebugPlugin extends Web3PluginBase { + public pluginNamespace = 'debug' -export function extend (web3) { - if (!web3.extend) { - return - } - // DEBUG - const methods = [] - if (!(web3.debug && web3.debug.preimage)) { - methods.push(new web3.extend.Method({ - name: 'preimage', - call: 'debug_preimage', - inputFormatter: [null], - params: 1 - })) + public preimage(key, cb) { + this.requestManager.send({ + method: 'debug_preimage', + params: [key] + }) + .then(result => cb(null, result)) + .catch(error => cb(error)) } - if (!(web3.debug && web3.debug.traceTransaction)) { - methods.push(new web3.extend.Method({ - name: 'traceTransaction', - call: 'debug_traceTransaction', - inputFormatter: [null, null], - params: 2 - })) + public traceTransaction(txHash, options, cb) { + this.requestManager.send({ + method: 'debug_traceTransaction', + params: [txHash, options] + }) + .then(result => cb(null, result)) + .catch(error => cb(error)) } - if (!(web3.debug && web3.debug.storageRangeAt)) { - methods.push(new web3.extend.Method({ - name: 'storageRangeAt', - call: 'debug_storageRangeAt', - inputFormatter: [null, null, null, null, null], - params: 5 - })) - } - if (methods.length > 0) { - web3.extend({ - property: 'debug', - methods: methods, - properties: [] + public storageRangeAt(txBlockHash, txIndex, address, start, maxSize, cb) { + this.requestManager.send({ + method: 'debug_storageRangeAt', + params: [txBlockHash, txIndex, address, start, maxSize] }) + .then(result => cb(null, result)) + .catch(error => cb(error)) } } diff --git a/libs/remix-simulator/package.json b/libs/remix-simulator/package.json index 594f82c8f2..62a74be1e0 100644 --- a/libs/remix-simulator/package.json +++ b/libs/remix-simulator/package.json @@ -36,7 +36,8 @@ "merge": "^1.2.0", "string-similarity": "^4.0.4", "time-stamp": "^2.0.0", - "web3": "^1.5.1" + "web3": "^4.1.1", + "web3-utils": "^4.0.5" }, "devDependencies": { "@babel/core": "^7.4.5", @@ -69,4 +70,4 @@ "typings": "src/index.d.ts", "gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220", "types": "./src/index.d.ts" -} \ No newline at end of file +} diff --git a/libs/remix-simulator/src/VmProxy.ts b/libs/remix-simulator/src/VmProxy.ts index 90d7ebfbf7..d0a5e634e2 100644 --- a/libs/remix-simulator/src/VmProxy.ts +++ b/libs/remix-simulator/src/VmProxy.ts @@ -3,10 +3,9 @@ const { toHexPaddedString, formatMemory } = util import { helpers } from '@remix-project/remix-lib' const { normalizeHexAddress } = helpers.ui import { ConsoleLogs, hash } from '@remix-project/remix-lib' -import BN from 'bn.js' -import { isBigNumber } from 'web3-utils' import { toChecksumAddress, bufferToHex, Address, toBuffer } from '@ethereumjs/util' -import utils from 'web3-utils' +import utils, {toBigInt} from 'web3-utils' +import {isBigInt} from 'web3-validator' import { ethers } from 'ethers' import { VMContext } from './vm-context' import type { StateManager } from '@ethereumjs/statemanager' @@ -47,7 +46,7 @@ export class VmProxy { stateCopy: StateManager flagDoNotRecordEVMSteps: boolean lastMemoryUpdate: Array - + constructor (vmContext: VMContext) { this.vmContext = vmContext this.stateCopy @@ -84,7 +83,7 @@ export class VmProxy { this.fromDecimal = (...args) => utils.fromDecimal.apply(this, args) this.fromWei = (...args) => utils.fromWei.apply(this, args) this.toWei = (...args) => utils.toWei.apply(this, args) - this.toBigNumber = (...args) => utils.toBN.apply(this, args) + this.toBigNumber = (...args) => toBigInt.apply(this, args) this.isAddress = (...args) => utils.isAddress.apply(this, args) this.utils = utils this.txsMapBlock = {} @@ -176,6 +175,7 @@ export class VmProxy { const topics = [] if (log[1].length > 0) { for (const k in log[1]) { + // @ts-ignore topics.push('0x' + log[1][k].toString('hex')) } } else { @@ -278,7 +278,8 @@ export class VmProxy { } let consoleArgs = iface.decodeFunctionData(functionDesc, payload) consoleArgs = consoleArgs.map((value) => { - if (isBigNumber(value)) { + // Copied from: https://github.com/web3/web3.js/blob/e68194bdc590d811d4bf66dde12f99659861a110/packages/web3-utils/src/utils.js#L48C10-L48C10 + if (value && ((value.constructor && value.constructor.name === 'BigNumber') || isBigInt(value))) { return value.toString() } return value @@ -347,7 +348,7 @@ export class VmProxy { getStorageAt (address: string, position: string, blockNumber: string, cb) { // we don't use the range params here address = toChecksumAddress(address) - + blockNumber = blockNumber === 'latest' ? this.vmContext.latestBlockNumber : blockNumber const block = this.vmContext.blocks[blockNumber] @@ -425,10 +426,10 @@ export class VmProxy { getSha3Input (stack, memory) { const memoryStart = toHexPaddedString(stack[stack.length - 1]) const memoryLength = toHexPaddedString(stack[stack.length - 2]) - const memStartDec = (new BN(memoryStart.replace('0x', ''), 16)).toString(10) + const memStartDec = toBigInt(memoryStart).toString(10) const memoryStartInt = parseInt(memStartDec) * 2 - const memLengthDec = (new BN(memoryLength.replace('0x', ''), 16).toString(10)) - const memoryLengthInt = parseInt(memLengthDec) * 2 + const memLengthDec = toBigInt(memoryLength).toString(10) + const memoryLengthInt = parseInt(memLengthDec.toString()) * 2 let i = Math.floor(memoryStartInt / 32) const maxIndex = Math.floor(memoryLengthInt / 32) + i diff --git a/libs/remix-simulator/src/methods/accounts.ts b/libs/remix-simulator/src/methods/accounts.ts index ffbfc89a3a..00b8701da3 100644 --- a/libs/remix-simulator/src/methods/accounts.ts +++ b/libs/remix-simulator/src/methods/accounts.ts @@ -1,19 +1,17 @@ import { privateToAddress, toChecksumAddress, isValidPrivate, Address } from '@ethereumjs/util' -import BN from 'bn.js' -const Web3EthAccounts = require('web3-eth-accounts'); +import { privateKeyToAccount } from 'web3-eth-accounts' +import { toBigInt } from 'web3-utils' import * as crypto from 'crypto' export class Web3Accounts { accounts: Record accountsKeys: Record - web3Accounts: any vmContext constructor (vmContext) { this.vmContext = vmContext // TODO: make it random and/or use remix-libs - this.web3Accounts = new Web3EthAccounts() this.accounts = {} this.accountsKeys = {} } @@ -48,7 +46,7 @@ export class Web3Accounts { const stateManager = this.vmContext.vm().stateManager stateManager.getAccount(Address.fromString(addressStr)).then((account) => { - account.balance = new BN(balance.replace('0x', '') || 'f00000000000000001', 16) + account.balance = toBigInt(balance || '0xf00000000000000001') stateManager.putAccount(Address.fromString(addressStr), account).catch((error) => { reject(error) }).then(() => { @@ -85,7 +83,7 @@ export class Web3Accounts { const address = payload.params[0] this.vmContext.vm().stateManager.getAccount(Address.fromString(address)).then((account) => { - cb(null, new BN(account.balance).toString(10)) + cb(null, toBigInt(account.balance).toString(10)) }).catch((error) => { cb(error) }) @@ -99,7 +97,7 @@ export class Web3Accounts { if (!privateKey) { return cb(new Error('unknown account')) } - const account = this.web3Accounts.privateKeyToAccount(privateKey as string) + const account = privateKeyToAccount(privateKey as string) const data = account.sign(message) diff --git a/libs/remix-simulator/src/methods/transactions.ts b/libs/remix-simulator/src/methods/transactions.ts index dc6d940e65..25c751ed4d 100644 --- a/libs/remix-simulator/src/methods/transactions.ts +++ b/libs/remix-simulator/src/methods/transactions.ts @@ -1,5 +1,4 @@ -import { toHex, toDecimal } from 'web3-utils' -import BN from 'bn.js' +import { toHex, toNumber, toBigInt } from 'web3-utils' import { toChecksumAddress, Address, bigIntToHex } from '@ethereumjs/util' import { processTx } from './txProcess' import { execution } from '@remix-project/remix-lib' @@ -26,6 +25,7 @@ export class Transactions { txRunnerVMInstance txRunnerInstance TX_INDEX = '0x0' // currently there's always only 1 tx per block, so the transaction index will always be 0x0 + comingCallId constructor (vmContext) { this.vmContext = vmContext @@ -73,7 +73,8 @@ export class Transactions { eth_getTransactionByBlockNumberAndIndex: this.eth_getTransactionByBlockNumberAndIndex.bind(this), eth_getExecutionResultFromSimulator: this.eth_getExecutionResultFromSimulator.bind(this), eth_getHHLogsForTx: this.eth_getHHLogsForTx.bind(this), - eth_getHashFromTagBySimulator: this.eth_getHashFromTagBySimulator.bind(this) + eth_getHashFromTagBySimulator: this.eth_getHashFromTagBySimulator.bind(this), + eth_registerCallId: this.eth_registerCallId.bind(this) } } @@ -154,9 +155,8 @@ export class Transactions { } payload.params[0].gas = 10000000 * 10 - this.vmContext.web3().flagNextAsDoNotRecordEvmSteps() - processTx(this.txRunnerInstance, payload, true, (error, value: VMexecutionResult) => { + processTx(this.txRunnerInstance, payload, true, (error, value: VMexecutionResult) => { if (error) return cb(error) const result: RunTxResult = value.result if ((result as any).receipt?.status === '0x0' || (result as any).receipt?.status === 0) { @@ -169,12 +169,12 @@ export class Transactions { return cb(e.message) } } - let gasUsed = result.execResult.executionGasUsed + let gasUsed = Number(toNumber(result.execResult.executionGasUsed)) if (result.execResult.gasRefund) { - gasUsed += result.execResult.gasRefund + gasUsed += Number(toNumber(result.execResult.gasRefund)) } - gasUsed = gasUsed + value.tx.getBaseFee() - cb(null, Math.ceil(Number(gasUsed) + (15 * Number(gasUsed)) / 100)) + gasUsed = gasUsed + Number(toNumber(value.tx.getBaseFee())) + cb(null, Math.ceil(gasUsed + (15 * gasUsed) / 100)) }) } @@ -190,6 +190,11 @@ export class Transactions { }) } + eth_registerCallId (payload, cb) { + this.comingCallId = payload.params[0] + cb() + } + eth_call (payload, cb) { // from might be lowercased address (web3) if (payload.params && payload.params.length > 0 && payload.params[0].from) { @@ -200,12 +205,10 @@ export class Transactions { } payload.params[0].value = undefined - - const tag = payload.params[0].timestamp // e2e reference - + const tag = payload.params[0].timestamp processTx(this.txRunnerInstance, payload, true, (error, result: VMexecutionResult) => { if (!error && result) { - this.vmContext.addBlock(result.block) + this.vmContext.addBlock(result.block, null, true) const hash = '0x' + result.tx.hash().toString('hex') this.vmContext.trackTx(hash, result.block, result.tx) const returnValue = `0x${result.result.execResult.returnValue.toString('hex') || '0'}` @@ -217,9 +220,14 @@ export class Transactions { logs: result.result.execResult.logs, returnValue: returnValue } - this.vmContext.trackExecResult(hash, execResult) - this.tags[tag] = result.transactionHash // calls are not supposed to return a transaction hash. we do this for keeping track of it and allowing debugging calls. + // either the tag is specified as a timestamp in a tx or the caller should call registerCallId before calling the call. + if (tag) this.tags[tag] = result.transactionHash + else if (this.comingCallId) { + this.tags[this.comingCallId] = result.transactionHash + this.comingCallId = null + } + this.vmContext.trackExecResult(hash, execResult) return cb(null, returnValue) } cb(error) @@ -234,7 +242,7 @@ export class Transactions { const address = payload.params[0] this.vmContext.vm().stateManager.getAccount(Address.fromString(address)).then((account) => { - const nonce = new BN(account.nonce).toString(10) + const nonce = toBigInt(account.nonce).toString(10) cb(null, nonce) }).catch((error) => { cb(error) @@ -292,7 +300,7 @@ export class Transactions { const txIndex = payload.params[1] const txBlock = this.vmContext.blocks[payload.params[0]] - const txHash = '0x' + txBlock.transactions[toDecimal(txIndex)].hash().toString('hex') + const txHash = '0x' + txBlock.transactions[toNumber(txIndex) as number].hash().toString('hex') this.vmContext.web3().eth.getTransactionReceipt(txHash, (error, receipt) => { if (error) { @@ -337,7 +345,7 @@ export class Transactions { const txIndex = payload.params[1] const txBlock = this.vmContext.blocks[payload.params[0]] - const txHash = '0x' + txBlock.transactions[toDecimal(txIndex)].hash().toString('hex') + const txHash = '0x' + txBlock.transactions[toNumber(txIndex) as number].hash().toString('hex') this.vmContext.web3().eth.getTransactionReceipt(txHash, (error, receipt) => { if (error) { diff --git a/libs/remix-simulator/src/methods/txProcess.ts b/libs/remix-simulator/src/methods/txProcess.ts index f269ca1baf..61a9821ab5 100644 --- a/libs/remix-simulator/src/methods/txProcess.ts +++ b/libs/remix-simulator/src/methods/txProcess.ts @@ -35,7 +35,7 @@ function createContract (payload, from, data, value, gasLimit, txRunner, callbac } export function processTx (txRunnerInstance, payload, isCall, callback) { - let { from, to, data, value, gas } = payload.params[0] // eslint-disable-line + let { from, to, data, input, value, gas } = payload.params[0] // eslint-disable-line gas = gas || 3000000 const callbacks = { @@ -54,10 +54,10 @@ export function processTx (txRunnerInstance, payload, isCall, callback) { } if (isCall) { - runCall(payload, from, to, data, value, gas, txRunnerInstance, callbacks, callback) + runCall(payload, from, to, data||input, value, gas, txRunnerInstance, callbacks, callback) } else if (to) { - runTx(payload, from, to, data, value, gas, txRunnerInstance, callbacks, callback) + runTx(payload, from, to, data||input, value, gas, txRunnerInstance, callbacks, callback) } else { - createContract(payload, from, data, value, gas, txRunnerInstance, callbacks, callback) + createContract(payload, from, data||input, value, gas, txRunnerInstance, callbacks, callback) } } diff --git a/libs/remix-simulator/src/provider.ts b/libs/remix-simulator/src/provider.ts index 997accddf9..2d2da213f1 100644 --- a/libs/remix-simulator/src/provider.ts +++ b/libs/remix-simulator/src/provider.ts @@ -10,6 +10,7 @@ import { methods as netMethods } from './methods/net' import { Transactions } from './methods/transactions' import { Debug } from './methods/debug' import { VMContext } from './vm-context' +import { Web3PluginBase } from 'web3' export interface JSONRPCRequestPayload { params: any[]; @@ -69,7 +70,7 @@ export class Provider { } } - sendAsync (payload: JSONRPCRequestPayload, callback: (err: Error, result?: JSONRPCResponsePayload) => void) { + _send(payload: JSONRPCRequestPayload, callback: (err: Error, result?: JSONRPCResponsePayload) => void) { // log.info('payload method is ', payload.method) // commented because, this floods the IDE console if (!this.initialized) { this.pendingRequests.push({ payload, callback }) @@ -95,8 +96,23 @@ export class Provider { callback(new Error('unknown method ' + payload.method)) } + sendAsync (payload: JSONRPCRequestPayload, callback: (err: Error, result?: JSONRPCResponsePayload) => void) { + return new Promise((resolve,reject)=>{ + const cb = (err, result) => { + if(typeof callback==='function'){ + callback(err,result) + } + if(err){ + return reject(err) + } + return resolve(result) + } + this._send(payload, cb) + }) + } + send (payload, callback) { - this.sendAsync(payload, callback || function () {}) + return this.sendAsync(payload,callback) } isConnected () { @@ -117,43 +133,39 @@ export class Provider { } export function extend (web3) { - if (!web3.extend) { - return + if(!web3.remix){ + web3.registerPlugin(new Web3TestPlugin()) } - // DEBUG - const methods = [] - if (!(web3.eth && web3.eth.getExecutionResultFromSimulator)) { - methods.push(new web3.extend.Method({ - name: 'getExecutionResultFromSimulator', - call: 'eth_getExecutionResultFromSimulator', - inputFormatter: [null], - params: 1 - })) +} + +class Web3TestPlugin extends Web3PluginBase { + public pluginNamespace = 'remix' + + public getExecutionResultFromSimulator(transactionHash) { + return this.requestManager.send({ + method: 'eth_getExecutionResultFromSimulator', + params: [transactionHash] + }) } - if (!(web3.eth && web3.eth.getHHLogsForTx)) { - methods.push(new web3.extend.Method({ - name: 'getHHLogsForTx', - call: 'eth_getHHLogsForTx', - inputFormatter: [null], - params: 1 - })) + public getHHLogsForTx(transactionHash) { + return this.requestManager.send({ + method: 'eth_getHHLogsForTx', + params: [transactionHash] + }) } - if (!(web3.eth && web3.eth.getHashFromTagBySimulator)) { - methods.push(new web3.extend.Method({ - name: 'getHashFromTagBySimulator', - call: 'eth_getHashFromTagBySimulator', - inputFormatter: [null], - params: 1 - })) + public getHashFromTagBySimulator(timestamp) { + return this.requestManager.send({ + method: 'eth_getHashFromTagBySimulator', + params: [timestamp] + }) } - if (methods.length > 0) { - web3.extend({ - property: 'eth', - methods: methods, - properties: [] + public registerCallId(id) { + return this.requestManager.send({ + method: 'eth_registerCallId', + params: [id] }) } } diff --git a/libs/remix-simulator/src/vm-context.ts b/libs/remix-simulator/src/vm-context.ts index 62122a61c9..224dbb96e5 100644 --- a/libs/remix-simulator/src/vm-context.ts +++ b/libs/remix-simulator/src/vm-context.ts @@ -374,7 +374,7 @@ export class VMContext { return this.currentVm } - addBlock (block: Block, genesis?: boolean) { + addBlock (block: Block, genesis?: boolean, isCall?: boolean) { let blockNumber = bigIntToHex(block.header.number) if (blockNumber === '0x') { blockNumber = '0x0' @@ -384,7 +384,7 @@ export class VMContext { this.blocks[blockNumber] = block this.latestBlockNumber = blockNumber - if (!genesis) this.logsManager.checkBlock(blockNumber, block, this.web3()) + if (!isCall && !genesis) this.logsManager.checkBlock(blockNumber, block, this.web3()) } trackTx (txHash, block, tx) { diff --git a/libs/remix-simulator/test/accounts.ts b/libs/remix-simulator/test/accounts.ts index 336d438380..cb923e209a 100644 --- a/libs/remix-simulator/test/accounts.ts +++ b/libs/remix-simulator/test/accounts.ts @@ -1,5 +1,5 @@ /* global describe, before, it */ -import Web3 from 'web3' +import Web3, { FMT_BYTES, FMT_NUMBER } from 'web3' import { Provider } from '../src/index' const web3 = new Web3() import * as assert from 'assert' @@ -21,9 +21,9 @@ describe('Accounts', () => { describe('eth_getBalance', () => { it('should get a account balance', async () => { const accounts: string[] = await web3.eth.getAccounts() - const balance0: string = await web3.eth.getBalance(accounts[0]) - const balance1: string = await web3.eth.getBalance(accounts[1]) - const balance2: string = await web3.eth.getBalance(accounts[2]) + const balance0: string = await web3.eth.getBalance(accounts[0], undefined, { number: FMT_NUMBER.STR, bytes: FMT_BYTES.HEX }) + const balance1: string = await web3.eth.getBalance(accounts[1], undefined, { number: FMT_NUMBER.STR, bytes: FMT_BYTES.HEX }) + const balance2: string = await web3.eth.getBalance(accounts[2], undefined, { number: FMT_NUMBER.STR, bytes: FMT_BYTES.HEX }) assert.deepEqual(balance0, '100000000000000000000') assert.deepEqual(balance1, '100000000000000000000') @@ -34,9 +34,9 @@ describe('Accounts', () => { describe('eth_sign', () => { it('should sign payloads', async () => { const accounts: string[] = await web3.eth.getAccounts() - const signature: string = await web3.eth.sign('Hello world', accounts[0]) + const signature = await web3.eth.sign(web3.utils.utf8ToHex('Hello world'), accounts[0]) - assert.deepEqual(signature.length, 132) + assert.deepEqual(typeof signature === 'string' ? signature.length : signature.signature.length, 132) }) }) }) diff --git a/libs/remix-simulator/test/blocks.ts b/libs/remix-simulator/test/blocks.ts index 72b454b8dd..08c5fe2e10 100644 --- a/libs/remix-simulator/test/blocks.ts +++ b/libs/remix-simulator/test/blocks.ts @@ -18,23 +18,22 @@ describe('blocks', () => { const block = await web3.eth.getBlock(0) const expectedBlock = { - baseFeePerGas: 1, - difficulty: 0, + baseFeePerGas: '1', + difficulty: '0', extraData: '0x0', - gasLimit: 8000000, - gasUsed: 0, + gasLimit: '8000000', + gasUsed: '0', hash: block.hash.toString(), - logsBloom: '0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331', + logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331', miner: '0x0000000000000000000000000000000000000001', - nonce: '0x0000000000000000', - number: 0, + nonce: '0', + number: '0', parentHash: '0x0000000000000000000000000000000000000000000000000000000000000000', sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', - size: 163591, + size: '163591', stateRoot: '0x0000000000000000000000000000000000000000000000000000000000000000', timestamp: block.timestamp, totalDifficulty: '0', - transactions: [], transactionsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', uncles: [] } @@ -94,10 +93,9 @@ describe('blocks', () => { it('should get block given its hash', async () => { const correctBlock = await web3.eth.getBlock(0) const numberTransactions = await (new Promise((resolve, reject) => { - web3['_requestManager'].send({method: 'eth_getUncleCountByBlockHash', params: [correctBlock.hash]}, (err, numberTransactions) => { - if (err) return reject(err) - resolve(numberTransactions) - }) + web3['_requestManager'].send({method: 'eth_getUncleCountByBlockHash', params: [correctBlock.hash]}) + .then(numberTransactions => resolve(numberTransactions)) + .catch(err => reject(err)) })) assert.deepEqual(numberTransactions, correctBlock.uncles.length) }) @@ -107,17 +105,16 @@ describe('blocks', () => { it('should get block given its number', async () => { const correctBlock = await web3.eth.getBlock(0) const numberTransactions = await (new Promise((resolve, reject) => { - web3['_requestManager'].send({method: 'eth_getUncleCountByBlockHash', params: [0]}, (err, numberTransactions) => { - if (err) return reject(err) - resolve(numberTransactions) - }) + web3['_requestManager'].send({method: 'eth_getUncleCountByBlockHash', params: [0]}) + .then(numberTransactions => resolve(numberTransactions)) + .catch(err => reject(err)) })) assert.deepEqual(numberTransactions, correctBlock.uncles.length) }) }) describe('eth_getStorageAt', () => { it('should get storage at position at given address', async () => { - const abi: any = [ + const abi = [ { 'constant': false, 'inputs': [ @@ -197,16 +194,16 @@ describe('blocks', () => { 'stateMutability': 'view', 'type': 'function' } - ] + ] as const const code = '0x608060405234801561001057600080fd5b506040516020806102018339810180604052602081101561003057600080fd5b810190808051906020019092919050505080600081905550506101a9806100586000396000f3fe60806040526004361061005c576000357c0100000000000000000000000000000000000000000000000000000000900480632a1afcd91461006157806360fe47b11461008c5780636d4ce63c146100c7578063ce01e1ec146100f2575b600080fd5b34801561006d57600080fd5b5061007661012d565b6040518082815260200191505060405180910390f35b34801561009857600080fd5b506100c5600480360360208110156100af57600080fd5b8101908080359060200190929190505050610133565b005b3480156100d357600080fd5b506100dc61013d565b6040518082815260200191505060405180910390f35b3480156100fe57600080fd5b5061012b6004803603602081101561011557600080fd5b8101908080359060200190929190505050610146565b005b60005481565b8060008190555050565b60008054905090565b80600081905550807f63a242a632efe33c0e210e04e4173612a17efa4f16aa4890bc7e46caece80de060405160405180910390a25056fea165627a7a7230582063160eb16dc361092a85ced1a773eed0b63738b83bea1e1c51cf066fa90e135d0029' const contract = new web3.eth.Contract(abi) const accounts = await web3.eth.getAccounts() - const contractInstance: any = await contract.deploy({ data: code, arguments: [100] }).send({ from: accounts[0], gas: 400000 }) + const contractInstance: any = await contract.deploy({ data: code, arguments: [100] }).send({ from: accounts[0], gas: '400000' }) contractInstance.currentProvider = web3.eth.currentProvider - contractInstance.givenProvider = web3.eth.currentProvider + // contractInstance.givenProvider = web3.eth.currentProvider await contractInstance.methods.set(100).send({ from: accounts[0].toLowerCase(), gas: 400000 }) let storage = await web3.eth.getStorageAt(contractInstance.options.address, 0) @@ -223,7 +220,7 @@ describe('blocks', () => { }) describe('eth_call', () => { it('should get a value', async () => { - const abi: any = [ + const abi = [ { 'constant': false, 'inputs': [ @@ -303,16 +300,15 @@ describe('blocks', () => { 'stateMutability': 'view', 'type': 'function' } - ] + ] as const const code = '0x608060405234801561001057600080fd5b506040516020806102018339810180604052602081101561003057600080fd5b810190808051906020019092919050505080600081905550506101a9806100586000396000f3fe60806040526004361061005c576000357c0100000000000000000000000000000000000000000000000000000000900480632a1afcd91461006157806360fe47b11461008c5780636d4ce63c146100c7578063ce01e1ec146100f2575b600080fd5b34801561006d57600080fd5b5061007661012d565b6040518082815260200191505060405180910390f35b34801561009857600080fd5b506100c5600480360360208110156100af57600080fd5b8101908080359060200190929190505050610133565b005b3480156100d357600080fd5b506100dc61013d565b6040518082815260200191505060405180910390f35b3480156100fe57600080fd5b5061012b6004803603602081101561011557600080fd5b8101908080359060200190929190505050610146565b005b60005481565b8060008190555050565b60008054905090565b80600081905550807f63a242a632efe33c0e210e04e4173612a17efa4f16aa4890bc7e46caece80de060405160405180910390a25056fea165627a7a7230582063160eb16dc361092a85ced1a773eed0b63738b83bea1e1c51cf066fa90e135d0029' const contract = new web3.eth.Contract(abi) const accounts = await web3.eth.getAccounts() - const contractInstance: any = await contract.deploy({ data: code, arguments: [100] }).send({ from: accounts[0], gas: 400000 }) + const contractInstance: any = await contract.deploy({ data: code, arguments: [100] }).send({ from: accounts[0], gas: '400000' }) contractInstance.currentProvider = web3.eth.currentProvider - contractInstance.givenProvider = web3.eth.currentProvider const value = await contractInstance.methods.get().call({ from: accounts[0] }) assert.deepEqual(value, 100) diff --git a/libs/remix-simulator/test/misc.ts b/libs/remix-simulator/test/misc.ts index a339910996..785cc3dd55 100644 --- a/libs/remix-simulator/test/misc.ts +++ b/libs/remix-simulator/test/misc.ts @@ -12,26 +12,21 @@ describe('Misc', () => { }) describe('web3_clientVersion', () => { - it('should get correct remix simulator version', async (done) => { - web3['_requestManager'].send({ method: 'web3_clientVersion', params: [] }, (err, version) => { - if (err) { - throw new Error(err) - } - const remixVersion = require('../package.json').version - assert.equal(version, 'Remix Simulator/' + remixVersion) - done() - }) + it('should get correct remix simulator version', async () => { + web3['_requestManager'].send({ method: 'web3_clientVersion', params: [] }) + .then(version => { + const remixVersion = require('../package.json').version + assert.equal(version, 'Remix Simulator/' + remixVersion) + }) + .catch(err => { throw new Error(err) }) }) }) describe('eth_protocolVersion', () => { it('should get protocol version', async () => { - web3['_requestManager'].send({ method: 'eth_protocolVersion', params: [] }, (err, result) => { - if (err) { - throw new Error(err) - } - assert.equal(result, '0x3f') - }) + web3['_requestManager'].send({ method: 'eth_protocolVersion', params: [] }) + .then(result => assert.equal(result, '0x3f')) + .catch(err => { throw new Error(err) }) }) }) @@ -58,56 +53,41 @@ describe('Misc', () => { describe('web3_sha3', () => { it('should get result of a sha3', async () => { - web3['_requestManager'].send({ method: 'web3_sha3', params: ['0x68656c6c6f20776f726c64'] }, (err, result) => { - if (err) { - throw new Error(err) - } - assert.equal(result, '0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad') - }) + web3['_requestManager'].send({ method: 'web3_sha3', params: ['0x68656c6c6f20776f726c64'] }) + .then(result => assert.equal(result, '0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad')) + .catch(err => { throw new Error(err)} ) }) }) describe('eth_getCompilers', () => { it('should get list of compilers', async () => { - web3['_requestManager'].send({ method: 'eth_getCompilers', params: [] }, (err, result) => { - if (err) { - throw new Error(err) - } - assert.equal(result, 0) - }) + web3['_requestManager'].send({ method: 'eth_getCompilers', params: [] }) + .then(result => assert.equal(result, 0)) + .catch(err => { throw new Error(err) }) }) }) describe('eth_compileSolidity', () => { it('get unsupported result when requesting solidity compiler', async () => { - web3['_requestManager'].send({ method: 'eth_compileSolidity', params: [] }, (err, result) => { - if (err) { - throw new Error(err) - } - assert.equal(result, 'unsupported') - }) + web3['_requestManager'].send({ method: 'eth_compileSolidity', params: [] }) + .then(result => assert.equal(result, 'unsupported')) + .catch(err => { throw new Error(err) }) }) }) describe('eth_compileLLL', () => { it('get unsupported result when requesting LLL compiler', async () => { - web3['_requestManager'].send({ method: 'eth_compileLLL', params: [] }, (err, result) => { - if (err) { - throw new Error(err) - } - assert.equal(result, 'unsupported') - }) + web3['_requestManager'].send({ method: 'eth_compileLLL', params: [] }) + .then(result => assert.equal(result, 'unsupported')) + .catch(err => { throw new Error(err) }) }) }) describe('eth_compileSerpent', () => { it('get unsupported result when requesting serpent compiler', async () => { - web3['_requestManager'].send({ method: 'eth_compileSerpent', params: [] }, (err, result) => { - if (err) { - throw new Error(err) - } - assert.equal(result, 'unsupported') - }) + web3['_requestManager'].send({ method: 'eth_compileSerpent', params: [] }) + .then(result => assert.equal(result, 'unsupported')) + .catch(err => { throw new Error(err)} ) }) }) }) diff --git a/libs/remix-solidity/package.json b/libs/remix-solidity/package.json index 5a9ecbc020..bc2626e33b 100644 --- a/libs/remix-solidity/package.json +++ b/libs/remix-solidity/package.json @@ -28,7 +28,7 @@ "semver": "^6.3.0", "solc": "^0.7.4", "string-similarity": "^4.0.4", - "web3": "^1.5.1", + "web3": "^4.1.1", "webworkify-webpack": "^2.1.5" }, "devDependencies": { @@ -58,4 +58,4 @@ "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-solidity#readme", "typings": "src/index.d.ts", "gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220" -} \ No newline at end of file +} diff --git a/libs/remix-tests/package.json b/libs/remix-tests/package.json index a9462d0075..a33fc54f27 100644 --- a/libs/remix-tests/package.json +++ b/libs/remix-tests/package.json @@ -62,7 +62,7 @@ "string-similarity": "^4.0.4", "time-stamp": "^2.2.0", "tslib": "^2.3.0", - "web3": "^1.5.1", + "web3": "^4.1.1", "winston": "^3.0.0" }, "devDependencies": { @@ -79,4 +79,4 @@ }, "typings": "src/index.d.ts", "gitHead": "b6db2a29c223e423c70f06b87d9b245e26f0b220" -} \ No newline at end of file +} diff --git a/libs/remix-tests/src/deployer.ts b/libs/remix-tests/src/deployer.ts index d3164eb285..991847a051 100644 --- a/libs/remix-tests/src/deployer.ts +++ b/libs/remix-tests/src/deployer.ts @@ -1,6 +1,6 @@ import async from 'async' import { execution } from '@remix-project/remix-lib' -import Web3 from 'web3' +import Web3, { FMT_BYTES, FMT_NUMBER } from 'web3' import { compilationInterface } from './types' /** @@ -58,7 +58,7 @@ export function deployAll (compileResult: compilationInterface, web3: Web3, test }, function deployContracts (contractsToDeploy: string[], next) { const deployRunner = (deployObject, contractObject, contractName, filename, callback) => { - deployObject.estimateGas().then((gasValue) => { + deployObject.estimateGas(undefined, { number: FMT_NUMBER.NUMBER, bytes: FMT_BYTES.HEX }).then((gasValue) => { const gasBase = Math.ceil(gasValue * 1.2) const gas = withDoubleGas ? gasBase * 2 : gasBase deployObject.send({ diff --git a/libs/remix-tests/src/run.ts b/libs/remix-tests/src/run.ts index 116da1cb28..83fc6c1dc9 100644 --- a/libs/remix-tests/src/run.ts +++ b/libs/remix-tests/src/run.ts @@ -127,10 +127,9 @@ commander nodeUrl: options.nodeUrl || null, blockNumber: options.blockNumber || null } - const web3 = new Web3() const provider: any = new Provider(providerConfig) await provider.init() - web3.setProvider(provider) + const web3 = new Web3(provider) extend(web3) runTestFiles(path.resolve(file_path), isDirectory, web3, compilerConfig, (error, totalPassing, totalFailing) => { if (error) process.exit(1) diff --git a/libs/remix-tests/src/runTestFiles.ts b/libs/remix-tests/src/runTestFiles.ts index a811f9b441..3ac058857b 100644 --- a/libs/remix-tests/src/runTestFiles.ts +++ b/libs/remix-tests/src/runTestFiles.ts @@ -62,10 +62,12 @@ export function runTestFiles (filepath: string, isDirectory: boolean, web3: Web3 async.waterfall([ function getAccountList (next) { if (accounts) return next(null) - web3.eth.getAccounts((_err: Error | null | undefined, _accounts) => { - accounts = _accounts - next(null) - }) + web3.eth.getAccounts() + .then(_accounts => { + accounts = _accounts + next(null) + }) + .catch((_err: Error | null | undefined) => next(null)) }, function compile (next) { compileFileOrFiles(filepath, isDirectory, { accounts }, compilerConfig, next) @@ -82,10 +84,10 @@ export function runTestFiles (filepath: string, isDirectory: boolean, web3: Web3 // accept deployment params from UI if (err.message.includes('The contract code couldn\'t be stored, please check your gas limit')) { deployAll(compilationResult, web3, accounts, true, null, (error, contracts) => { - if (error) next([{ message: 'contract deployment failed after trying twice: ' + error.message, severity: 'error' }]) // IDE expects errors in array + if (error) next([{ message: 'contract deployment failed after trying twice: ' + error.innerError || error.message, severity: 'error' }]) // IDE expects errors in array else next(null, compilationResult, contracts) }) - } else { next([{ message: 'contract deployment failed: ' + err.message, severity: 'error' }]) } // IDE expects errors in array + } else { next([{ message: 'contract deployment failed: ' + err.innerError || err.message, severity: 'error' }]) } // IDE expects errors in array } else { next(null, compilationResult, contracts) } }) }, diff --git a/libs/remix-tests/src/runTestSources.ts b/libs/remix-tests/src/runTestSources.ts index f6cb8cbcf3..7b97b2851c 100644 --- a/libs/remix-tests/src/runTestSources.ts +++ b/libs/remix-tests/src/runTestSources.ts @@ -64,10 +64,10 @@ export class UnitTestRunner { // accept deployment params from UI if (err.message.includes('The contract code couldn\'t be stored, please check your gas limit')) { deployAll(compilationResult, this.web3, this.testsAccounts, true, deployCb, (error, contracts) => { - if (error) next([{ message: 'contract deployment failed after trying twice: ' + error.message, severity: 'error' }]) // IDE expects errors in array + if (error) next([{ message: 'contract deployment failed after trying twice: ' + error.innerError || error.message, severity: 'error' }]) // IDE expects errors in array else next(null, compilationResult, contracts) }) - } else { next([{ message: 'contract deployment failed: ' + err.message, severity: 'error' }]) } // IDE expects errors in array + } else { next([{ message: 'contract deployment failed: ' + err.innerError || err.message, severity: 'error' }]) } // IDE expects errors in array } else { next(null, compilationResult, contracts) } }) }, diff --git a/libs/remix-tests/src/testRunner.ts b/libs/remix-tests/src/testRunner.ts index 7731786068..3f59dd1f12 100644 --- a/libs/remix-tests/src/testRunner.ts +++ b/libs/remix-tests/src/testRunner.ts @@ -214,6 +214,7 @@ export function runTest (testName: string, testObject: any, contractDetails: Com let passingNum = 0 let failureNum = 0 let timePassed = 0 + const failedTransactions = {} const isJSONInterfaceAvailable = testObject && testObject.options && testObject.options.jsonInterface if (!isJSONInterfaceAvailable) { return resultsCallback(new Error('Contract interface not available'), { passingNum, failureNum, timePassed }) } const runList: RunListInterface[] = createRunList(testObject.options.jsonInterface, fileAST, testName) @@ -249,12 +250,12 @@ export function runTest (testName: string, testObject: any, contractDetails: Com if (func.constant) { sendParams = {} const tagTimestamp = 'remix_tests_tag' + Date.now() - sendParams.timestamp = tagTimestamp + if (web3.remix && web3.remix.registerCallId) web3.remix.registerCallId(tagTimestamp) method.call(sendParams).then(async (result) => { const time = (Date.now() - startTime) / 1000.0 let tagTxHash - if (web3.eth && web3.eth.getHashFromTagBySimulator) tagTxHash = await web3.eth.getHashFromTagBySimulator(tagTimestamp) - if (web3.eth && web3.eth.getHHLogsForTx) hhLogs = await web3.eth.getHHLogsForTx(tagTxHash) + if (web3.remix && web3.remix.getHashFromTagBySimulator) tagTxHash = await web3.remix.getHashFromTagBySimulator(tagTimestamp) + if (web3.remix && web3.remix.getHHLogsForTx) hhLogs = await web3.remix.getHHLogsForTx(tagTxHash) debugTxHash = tagTxHash if (result) { const resp: TestResultInterface = { @@ -301,17 +302,17 @@ export function runTest (testName: string, testObject: any, contractDetails: Com method.send(sendParams).on('receipt', async (receipt) => { try { debugTxHash = receipt.transactionHash - if (web3.eth && web3.eth.getHHLogsForTx) hhLogs = await web3.eth.getHHLogsForTx(receipt.transactionHash) + if (web3.remix && web3.remix.getHHLogsForTx) hhLogs = await web3.remix.getHHLogsForTx(receipt.transactionHash) const time: number = (Date.now() - startTime) / 1000.0 const assertionEventHashes = assertionEvents.map(e => Web3.utils.sha3(e.name + '(' + e.params.join() + ')')) let testPassed = false - for (const i in receipt.events) { - let events = receipt.events[i] + for (const i in receipt.logs) { + let events = receipt.logs[i] if (!Array.isArray(events)) events = [events] for (const event of events) { - const eIndex = assertionEventHashes.indexOf(event.raw.topics[0]) // event name topic will always be at index 0 + const eIndex = assertionEventHashes.indexOf(event.topics[0]) // event name topic will always be at index 0 if (eIndex >= 0) { - const testEvent = web3.eth.abi.decodeParameters(assertionEvents[eIndex].params, event.raw.data) + const testEvent = web3.eth.abi.decodeParameters(assertionEvents[eIndex].params, event.data) if (!testEvent[0]) { const assertMethod = testEvent[2] if (assertMethod === 'ok') { // for 'Assert.ok' method @@ -378,9 +379,11 @@ export function runTest (testName: string, testObject: any, contractDetails: Com } }).on('error', async (err) => { const time: number = (Date.now() - startTime) / 1000.0 + if (failedTransactions[err.receipt.transactionHash]) return // we are already aware of this transaction failing. + failedTransactions[err.receipt.transactionHash] = time let errMsg = err.message let txHash - if (err.reason) errMsg = `transaction reverted with the reason: ${err.reason}` + if (err.reason) errMsg = `transaction reverted with the reason: ${err.reason}` const resp: TestResultInterface = { type: 'testFailure', value: changeCase.sentenceCase(func.name), @@ -394,7 +397,7 @@ export function runTest (testName: string, testObject: any, contractDetails: Com else if (err.message.includes('Transaction has been reverted by the EVM')) { txHash = JSON.parse(err.message.replace('Transaction has been reverted by the EVM:', '')).transactionHash } - if (web3.eth && web3.eth.getHHLogsForTx && txHash) hhLogs = await web3.eth.getHHLogsForTx(txHash) + if (web3.remix && web3.remix.getHHLogsForTx && txHash) hhLogs = await web3.remix.getHHLogsForTx(txHash) if (hhLogs && hhLogs.length) resp.hhLogs = hhLogs resp.debugTxHash = txHash testCallback(undefined, resp) diff --git a/libs/remix-tests/tests/testRunner.cli.spec.ts b/libs/remix-tests/tests/testRunner.cli.spec.ts index 8ac5505f10..f9686ca073 100644 --- a/libs/remix-tests/tests/testRunner.cli.spec.ts +++ b/libs/remix-tests/tests/testRunner.cli.spec.ts @@ -4,10 +4,10 @@ import { expect } from 'chai'; describe('testRunner: remix-tests CLI', function(){ this.timeout(120000) - // remix-tests binary, after build, is used as executable - + // remix-tests binary, after build, is used as executable + const executablePath = resolve(__dirname + '/../../../dist/libs/remix-tests/bin/remix-tests') - + const result = spawnSync('ls', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') }) if(result) { const dirContent = result.stdout.toString() @@ -20,7 +20,7 @@ describe('testRunner: remix-tests CLI', function(){ execSync('yarn install', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') }) } } - + describe('test various CLI options', function() { it('remix-tests version', () => { @@ -74,10 +74,10 @@ Commands: expect(res.stdout.toString().trim()).to.match(/Expected value should be ok to: true/) expect(res.stdout.toString().trim()).to.match(/Received: false/) expect(res.stdout.toString().trim()).to.match(/Message: okFailTest fails/) - + }) - + it('remix-tests running a test file with custom compiler version', () => { const res = spawnSync(executablePath, ['--compiler', '0.7.4', resolve(__dirname + '/examples_0/assert_ok_test.sol')]) @@ -92,13 +92,13 @@ Commands: // match fail test details expect(res.stdout.toString().trim()).to.match(/Message: okFailTest fails/) }) - + it('remix-tests running a test file with unavailable custom compiler version (should fail)', () => { const res = spawnSync(executablePath, ['--compiler', '1.10.4', resolve(__dirname + '/examples_0/assert_ok_test.sol')]) // match initial lines expect(res.stdout.toString().trim()).to.contain('No compiler found in releases with version 1.10.4') }) - + it('remix-tests running a test file with custom EVM', () => { const res = spawnSync(executablePath, ['--evm', 'petersburg', resolve(__dirname + '/examples_0/assert_ok_test.sol')]) // match initial lines @@ -111,7 +111,7 @@ Commands: // match fail test details expect(res.stdout.toString().trim()).to.match(/Message: okFailTest fails/) }) - + it('remix-tests running a test file by enabling optimization', () => { const res = spawnSync(executablePath, ['--optimize', 'true', resolve(__dirname + '/examples_0/assert_ok_test.sol')]) // match initial lines @@ -124,7 +124,7 @@ Commands: // match fail test details expect(res.stdout.toString().trim()).to.match(/Message: okFailTest fails/) }) - + it('remix-tests running a test file by enabling optimization and setting runs', () => { const res = spawnSync(executablePath, ['--optimize', 'true', '--runs', '300', resolve(__dirname + '/examples_0/assert_ok_test.sol')]) // match initial lines @@ -161,6 +161,6 @@ Commands: // match fail test details expect(res.stdout.toString().trim()).to.match(/Message: okFailTest fails/) }) - + }) -}) \ No newline at end of file +}) diff --git a/libs/remix-tests/tests/testRunner.spec.ts b/libs/remix-tests/tests/testRunner.spec.ts index cbdc1c4aa1..fd84bca172 100644 --- a/libs/remix-tests/tests/testRunner.spec.ts +++ b/libs/remix-tests/tests/testRunner.spec.ts @@ -53,14 +53,16 @@ async function compileAndDeploy(filename: string, callback: any) { let compilationData: any async.waterfall([ function getAccountList(next: any): void { - web3.eth.getAccounts((_err: Error | null | undefined, _accounts: string[]) => { - accounts = _accounts - web3.eth.defaultAccount = accounts[0] - next(_err) - }) + web3.eth.getAccounts() + .then(( _accounts: string[]) => { + accounts = _accounts + web3.eth.defaultAccount = accounts[0] + next(undefined) + }) + .catch((_err: Error | null | undefined) => next(_err)) }, function compile(next: any): void { - compileFileOrFiles(filename, false, { accounts }, null, next) + compileFileOrFiles(filename, false, { accounts, web3 }, null, next) }, function deployAllContracts(compilationResult: compilationInterface, asts, next: any): void { for (const filename in asts) { @@ -131,8 +133,8 @@ describe('testRunner', function () { { type: 'contract', value: 'AssertOkTest', filename: __dirname + '/examples_0/assert_ok_test.sol' }, { type: 'testPass', debugTxHash: '0x5b665752a4faf83229259b9b2811d3295be0af633b0051d4b90042283ef55707', value: 'Ok pass test', filename: __dirname + '/examples_0/assert_ok_test.sol', context: 'AssertOkTest', hhLogs: hhLogs1 }, { type: 'testFailure', debugTxHash: '0xa0a30ad042a7fc3495f72be7ba788d705888ffbbec7173f60bb27e07721510f2', value: 'Ok fail test', filename: __dirname + '/examples_0/assert_ok_test.sol', errMsg: 'okFailTest fails', context: 'AssertOkTest', hhLogs: hhLogs2, assertMethod: 'ok', location: '366:36:0', expected: 'true', returned: 'false' }, - - ], ['time', 'web3']) + // + ], ['time','type','debugTxHash','location','expected','returned','errMsg','assertMethod','web3']) }) }) @@ -141,7 +143,7 @@ describe('testRunner', function () { before((done) => { compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) => { - runTest('AssertEqualTest', contracts.AssertEqualTest, compilationData[filename]['AssertEqualTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) + runTest('AssertEqualTest', contracts.AssertEqualTest, compilationData[filename]['AssertEqualTest'], asts[filename], { accounts, web3 }, testCallback, resultsCallback(done)) }) }) @@ -182,7 +184,7 @@ describe('testRunner', function () { before((done) => { compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) => { - runTest('AssertNotEqualTest', contracts.AssertNotEqualTest, compilationData[filename]['AssertNotEqualTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) + runTest('AssertNotEqualTest', contracts.AssertNotEqualTest, compilationData[filename]['AssertNotEqualTest'], asts[filename], { accounts, web3 }, testCallback, resultsCallback(done)) }) }) @@ -222,7 +224,7 @@ describe('testRunner', function () { before((done) => { compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) => { - runTest('AssertGreaterThanTest', contracts.AssertGreaterThanTest, compilationData[filename]['AssertGreaterThanTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) + runTest('AssertGreaterThanTest', contracts.AssertGreaterThanTest, compilationData[filename]['AssertGreaterThanTest'], asts[filename], { accounts, web3 }, testCallback, resultsCallback(done)) }) }) @@ -256,7 +258,7 @@ describe('testRunner', function () { before((done) => { compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) => { - runTest('AssertLesserThanTest', contracts.AssertLesserThanTest, compilationData[filename]['AssertLesserThanTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) + runTest('AssertLesserThanTest', contracts.AssertLesserThanTest, compilationData[filename]['AssertLesserThanTest'], asts[filename], { accounts, web3 }, testCallback, resultsCallback(done)) }) }) @@ -291,7 +293,7 @@ describe('testRunner', function () { before((done) => { compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) => { - runTest('MyTest', contracts.MyTest, compilationData[filename]['MyTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) + runTest('MyTest', contracts.MyTest, compilationData[filename]['MyTest'], asts[filename], { accounts, web3 }, testCallback, resultsCallback(done)) }) }) @@ -322,7 +324,7 @@ describe('testRunner', function () { before(done => { compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { - runTest('MyTest', contracts.MyTest, compilationData[filename]['MyTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) + runTest('MyTest', contracts.MyTest, compilationData[filename]['MyTest'], asts[filename], { accounts, web3 }, testCallback, resultsCallback(done)) }) }) @@ -352,7 +354,7 @@ describe('testRunner', function () { before(done => { compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { - runTest('StringTest', contracts.StringTest, compilationData[filename]['StringTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) + runTest('StringTest', contracts.StringTest, compilationData[filename]['StringTest'], asts[filename], { accounts, web3 }, testCallback, resultsCallback(done)) }) }) @@ -378,7 +380,7 @@ describe('testRunner', function () { before(done => { compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { - runTest('StorageResolveTest', contracts.StorageResolveTest, compilationData[filename]['StorageResolveTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) + runTest('StorageResolveTest', contracts.StorageResolveTest, compilationData[filename]['StorageResolveTest'], asts[filename], { accounts, web3 }, testCallback, resultsCallback(done)) }) }) @@ -405,7 +407,7 @@ describe('testRunner', function () { before(done => { compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { - runTest('SafeMathTest', contracts.SafeMathTest, compilationData[filename]['SafeMathTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) + runTest('SafeMathTest', contracts.SafeMathTest, compilationData[filename]['SafeMathTest'], asts[filename], { accounts, web3 }, testCallback, resultsCallback(done)) }) }) @@ -425,7 +427,7 @@ describe('testRunner', function () { before(done => { compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { - runTest('IntegerTest', contracts.IntegerTest, compilationData[filename]['IntegerTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) + runTest('IntegerTest', contracts.IntegerTest, compilationData[filename]['IntegerTest'], asts[filename], { accounts, web3 }, testCallback, resultsCallback(done)) }) }) @@ -445,7 +447,7 @@ describe('testRunner', function () { before(done => { compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { - runTest('SenderAndValueTest', contracts.SenderAndValueTest, compilationData[filename]['SenderAndValueTest'], asts[filename], { accounts }, testCallback, resultsCallback(done)) + runTest('SenderAndValueTest', contracts.SenderAndValueTest, compilationData[filename]['SenderAndValueTest'], asts[filename], { accounts, web3 }, testCallback, resultsCallback(done)) }) }) @@ -473,7 +475,7 @@ describe('testRunner', function () { } before(done => { compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: any, contracts: any, asts: any, accounts: string[], web3: any) { - runTest('SenderAndValueTest', undefined, compilationData[filename]['SenderAndValueTest'], asts[filename], { accounts }, testCallback, errorCallback(done)) + runTest('SenderAndValueTest', undefined, compilationData[filename]['SenderAndValueTest'], asts[filename], { accounts, web3 }, testCallback, errorCallback(done)) }) }) @@ -486,4 +488,4 @@ describe('testRunner', function () { }) }) -}) \ No newline at end of file +}) diff --git a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx index 578ab4a100..3771acfcf2 100644 --- a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx @@ -15,7 +15,6 @@ import { RemixUiXterminals } from '@remix-ui/xterm' interface IRemixAppUi { app: any } - const RemixApp = (props: IRemixAppUi) => { const [appReady, setAppReady] = useState(false) const [hideSidePanel, setHideSidePanel] = useState(false) diff --git a/libs/remix-ui/debugger-ui/src/lib/api/debugger-api.ts b/libs/remix-ui/debugger-ui/src/lib/api/debugger-api.ts index 0879471fe8..a8fed04499 100644 --- a/libs/remix-ui/debugger-ui/src/lib/api/debugger-api.ts +++ b/libs/remix-ui/debugger-ui/src/lib/api/debugger-api.ts @@ -14,9 +14,7 @@ export const DebuggerApiMixin = (Base) => class extends Base { const self = this this.web3Provider = { sendAsync (payload, callback) { - self.call('web3Provider', 'sendAsync', payload) - .then(result => callback(null, result)) - .catch(e => callback(e)) + return self.call('web3Provider', 'sendAsync', payload) } } this._web3 = new Web3(this.web3Provider) diff --git a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.css b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.css index 1a5e4926a9..01754f6ca3 100644 --- a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.css +++ b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.css @@ -20,4 +20,7 @@ .debuggerPanels { overflow-y: auto; height: fit-content; +} +.jumpToFunctionClick span { + cursor: pointer; } \ No newline at end of file diff --git a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx index 73333e01a5..6ea35adb1c 100644 --- a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx @@ -461,7 +461,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { {state.debugging && }
- {state.debugging && } + {state.debugging && } {state.debugging && ( { @@ -19,6 +20,8 @@ export const DropdownPanel = (props: DropdownPanelProps) => { extractFunc, formatSelfFunc, registerEvent, + handleExpandFunc, + formatClassNamesFunc, triggerEvent, loadMoreEvent, loadMoreCompletedEvent, @@ -53,6 +56,7 @@ export const DropdownPanel = (props: DropdownPanelProps) => { } const formatSelfDefault = (key: string | number, data: ExtractData) => { let value + if (isBigInt(data.self)) data.self = data.self.toString() if (hexHighlight && typeof data.self === 'string') { const isHex = data.self.startsWith('0x') || hexHighlight if (isHex) { @@ -133,9 +137,9 @@ export const DropdownPanel = (props: DropdownPanelProps) => { toggleDropdown: !prevState.toggleDropdown } }) - } + }; - const handleExpand = (keyPath) => { + const handleExpand = handleExpandFunc || function (keyPath) { if (!state.expandPath.includes(keyPath)) { state.expandPath.push(keyPath) } else { @@ -182,6 +186,10 @@ export const DropdownPanel = (props: DropdownPanelProps) => { else if (calldata && Object.keys(calldata).length === 0 && calldata.constructor === Object) isEmpty = true setState((prevState) => { + const copiableContent = JSON.stringify(calldata, (key, value) => { + if (isBigInt(value)) value = value.toString() + return value + }, '\t').replace(/0xNaN/g, '0x0') return { ...prevState, dropdownContent: { @@ -189,7 +197,7 @@ export const DropdownPanel = (props: DropdownPanelProps) => { display: 'block' }, // replace 0xNaN with 0x0 - copiableContent: JSON.stringify(calldata, null, '\t').replace(/0xNaN/g, '0x0'), + copiableContent, message: { innerText: isEmpty ? intl.formatMessage({id: 'debugger.noDataAvailable'}) : '', display: isEmpty ? 'block' : 'none' @@ -215,6 +223,7 @@ export const DropdownPanel = (props: DropdownPanelProps) => { label={formatSelfFunc ? formatSelfFunc(key, data) : formatSelfDefault(key, data)} onClick={() => handleExpand(keyPath)} expand={state.expandPath.includes(keyPath)} + labelClass={formatClassNamesFunc && formatClassNamesFunc(key, data)} > {children} @@ -240,6 +249,7 @@ export const DropdownPanel = (props: DropdownPanelProps) => { label={formatSelfFunc ? formatSelfFunc(key, data) : formatSelfDefault(key, data)} onClick={() => handleExpand(keyPath)} expand={state.expandPath.includes(keyPath)} + labelClass={formatClassNamesFunc && formatClassNamesFunc(key, data)} /> ) } diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/function-panel.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/function-panel.tsx index 6450536f5a..d2106977ed 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/function-panel.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/function-panel.tsx @@ -2,16 +2,31 @@ import React, {useState, useEffect} from 'react' // eslint-disable-line import DropdownPanel from './dropdown-panel' // eslint-disable-line import {default as deepequal} from 'deep-equal' // eslint-disable-line -export const FunctionPanel = ({data, className}) => { - const [calldata, setCalldata] = useState(null) +export const FunctionPanel = ({data, className, stepManager}) => { + const [functionData, setFunctionData] = useState(null) useEffect(() => { - if (!deepequal(calldata, data)) setCalldata(data) + if (!deepequal(functionData, data)) { + setFunctionData(data.map(el => el.label)) + } }, [data]) + const formatSelfFunc = (key, data) => { + return data.self + } + + const handleExpandFunc = (keyPath) => { + stepManager.jumpTo(data[parseInt(keyPath)].function.firstStep) + } + + const formatClassNamesFunc = (keyPath, data) => { + return 'jumpToFunctionClick' + } + return ( +
- +
) } diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/global-variables.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/global-variables.tsx index 9c01778615..a649cc73b3 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/global-variables.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/global-variables.tsx @@ -1,7 +1,6 @@ import React from 'react' // eslint-disable-line import DropdownPanel from './dropdown-panel' // eslint-disable-line -import {BN} from 'bn.js' -import Web3 from 'web3' +import {toBigInt} from 'web3-utils' // eslint-disable-line export const GlobalVariables = ({block, receipt, tx, className}) => { // see https://docs.soliditylang.org/en/latest/units-and-global-variables.html#block-and-transaction-properties @@ -18,7 +17,7 @@ export const GlobalVariables = ({block, receipt, tx, className}) => { 'tx.origin': tx && tx.from } if (block && block.baseFeePerGas) { - globals['block.basefee'] = Web3.utils.toBN(block.baseFeePerGas).toString(10) + ` Wei (${block.baseFeePerGas})` + globals['block.basefee'] = toBigInt(block.baseFeePerGas).toString(10) + ` Wei (${block.baseFeePerGas})` } return ( diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx index 67ae5677fe..035d5f619a 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx @@ -5,7 +5,7 @@ import StepDetail from './step-detail' // eslint-disable-line import SolidityState from './solidity-state' // eslint-disable-line import SolidityLocals from './solidity-locals' // eslint-disable-line -export const VmDebuggerHead = ({vmDebugger: {registerEvent, triggerEvent}, debugging}) => { +export const VmDebuggerHead = ({vmDebugger: {registerEvent, triggerEvent}, debugging, stepManager}) => { const [functionPanel, setFunctionPanel] = useState(null) const [stepDetail, setStepDetail] = useState({ 'vm trace step': '-', @@ -32,7 +32,11 @@ export const VmDebuggerHead = ({vmDebugger: {registerEvent, triggerEvent}, debug const functions = [] for (const func of stack) { - functions.push((func.functionDefinition.name || func.functionDefinition.kind) + '(' + func.inputs.join(', ') + ')' + ' - ' + func.gasCost + ' gas') + const label = (func.functionDefinition.name || func.functionDefinition.kind) + '(' + func.inputs.join(', ') + ')' + ' - ' + func.gasCost + ' gas' + functions.push({ + label, + function: func + }) } setFunctionPanel(() => functions) }) @@ -127,7 +131,7 @@ export const VmDebuggerHead = ({vmDebugger: {registerEvent, triggerEvent}, debug return (
- +
diff --git a/libs/remix-ui/debugger-ui/src/types/index.ts b/libs/remix-ui/debugger-ui/src/types/index.ts index a319e354be..a5893905e7 100644 --- a/libs/remix-ui/debugger-ui/src/types/index.ts +++ b/libs/remix-ui/debugger-ui/src/types/index.ts @@ -18,6 +18,8 @@ export type ExtractFunc = (json: any, parent?: any) => ExtractData export type FormatSelfFunc = (key: string | number, data: ExtractData) => JSX.Element export type RegisterEventType = (type: string, listener: any) => void // listener is a function export type TriggerEventType = (type: string, payload: Array) => void +export type HandleExpandFunc = (keyPath: string) => void +export type FormatClassNamesFunc = (key: string | number, data: ExtractData) => string export interface DropdownPanelProps { dropdownName: string, className?: string, @@ -30,6 +32,8 @@ export interface DropdownPanelProps { extractFunc?: ExtractFunc, formatSelfFunc?: FormatSelfFunc, registerEvent?: RegisterEventType, + handleExpandFunc?: HandleExpandFunc, + formatClassNamesFunc?: FormatClassNamesFunc triggerEvent?: TriggerEventType, loadMoreEvent?: string, loadMoreCompletedEvent?: string, diff --git a/libs/remix-ui/editor/src/lib/web-types.ts b/libs/remix-ui/editor/src/lib/web-types.ts index dd70a43bc0..9d95f1440e 100644 --- a/libs/remix-ui/editor/src/lib/web-types.ts +++ b/libs/remix-ui/editor/src/lib/web-types.ts @@ -184,40 +184,32 @@ export const loadTypes = async (monaco) => { // Web3 // @ts-ignore - const indexWeb3 = await import('raw-loader!web3/types/index.d.ts') - monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3.default, `file:///node_modules/@types/web3/index.d.ts`) + const indexWeb3 = await import('raw-loader!web3') + monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3.default, `file:///node_modules/web3/lib/types/index.d.ts`) // @ts-ignore - const indexWeb3Bzz = await import('raw-loader!web3-bzz/types/index.d.ts') - monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3Bzz.default, `file:///node_modules/@types/web3-bzz/index.d.ts`) + const indexWeb3Core = await import('raw-loader!web3-core') + monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3Core.default, `file:///node_modules/web3-core/lib/types/index.d.ts`) // @ts-ignore - const indexWeb3Core = await import('raw-loader!web3-core/types/index.d.ts') - monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3Core.default, `file:///node_modules/@types/web3-core/index.d.ts`) + const indexWeb3Eth = await import('raw-loader!web3-eth') + monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3Eth.default, `file:///node_modules/web3-eth/lib/types/index.d.ts`) // @ts-ignore - const indexWeb3Eth = await import('raw-loader!web3-eth/types/index.d.ts') - monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3Eth.default, `file:///node_modules/@types/web3-eth/index.d.ts`) + const indexWeb3Personal = await import('raw-loader!web3-eth-personal') + monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3Personal.default, `file:///node_modules/web3-eth-personal/lib/types/index.d.ts`) // @ts-ignore - const indexWeb3Personal = await import('raw-loader!web3-eth-personal/types/index.d.ts') - monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3Personal.default, `file:///node_modules/@types/web3-eth-personal/index.d.ts`) + const indexWeb3Contract = await import('raw-loader!web3-eth-contract') + monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3Contract.default, `file:///node_modules/web3-eth-contract/lib/types/index.d.ts`) // @ts-ignore - const indexWeb3Contract = await import('raw-loader!web3-eth-contract/types/index.d.ts') - monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3Contract.default, `file:///node_modules/@types/web3-eth-contract/index.d.ts`) + const indexWeb3Net = await import('raw-loader!web3-net') + monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3Net.default, `file:///node_modules/web3-net/lib/types/index.d.ts`) // @ts-ignore - const indexWeb3Net = await import('raw-loader!web3-net/types/index.d.ts') - monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3Net.default, `file:///node_modules/@types/web3-net/index.d.ts`) - - // @ts-ignore - const indexWeb3Shh = await import('raw-loader!web3-shh/types/index.d.ts') - monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3Shh.default, `file:///node_modules/@types/web3-shh/index.d.ts`) - - // @ts-ignore - const indexWeb3Util = await import('raw-loader!web3-utils/types/index.d.ts') - monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3Util.default, `file:///node_modules/@types/web3-utils/index.d.ts`) + const indexWeb3Util = await import('raw-loader!web3-utils') + monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3Util.default, `file:///node_modules/web3-utils/lib/types/index.d.ts`) // remix const indexRemixApi = remixTypes + `\n declare global { diff --git a/libs/remix-ui/locale-module/src/lib/remix-ui-locale-module.tsx b/libs/remix-ui/locale-module/src/lib/remix-ui-locale-module.tsx index 465803be9c..4ca7e07cd2 100644 --- a/libs/remix-ui/locale-module/src/lib/remix-ui-locale-module.tsx +++ b/libs/remix-ui/locale-module/src/lib/remix-ui-locale-module.tsx @@ -1,13 +1,13 @@ -import React, {useEffect, useState} from 'react' -import {FormattedMessage} from 'react-intl' -import {LocaleModule} from '../../types/locale-module' +import React, { useEffect, useState } from 'react' +import { FormattedMessage } from 'react-intl' +import { LocaleModule } from '../../types/locale-module' import './remix-ui-locale-module.module.css' export interface RemixUiLocaleModuleProps { localeModule: LocaleModule } -export function RemixUiLocaleModule({localeModule}: RemixUiLocaleModuleProps) { +export function RemixUiLocaleModule({ localeModule }: RemixUiLocaleModuleProps) { const [localeCode, setLocaleCode] = useState('') useEffect(() => { diff --git a/libs/remix-ui/run-tab/src/lib/components/mainnet.tsx b/libs/remix-ui/run-tab/src/lib/components/mainnet.tsx index 8d7b8046f4..06fc44ebd8 100644 --- a/libs/remix-ui/run-tab/src/lib/components/mainnet.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/mainnet.tsx @@ -2,7 +2,7 @@ import React, {useEffect, useState} from 'react' import {FormattedMessage, useIntl} from 'react-intl' import {CopyToClipboard} from '@remix-ui/clipboard' -import Web3 from 'web3' +import {fromWei, toBigInt, toWei} from 'web3-utils' import {MainnetProps} from '../types' export function MainnetPrompt(props: MainnetProps) { @@ -15,7 +15,7 @@ export function MainnetPrompt(props: MainnetProps) { if (txFeeText) setTransactionFee(txFeeText) if (gasPriceValue) onGasPriceChange(gasPriceValue) if (props.network && props.network.lastBlock && props.network.lastBlock.baseFeePerGas) { - const baseFee = Web3.utils.fromWei(Web3.utils.toBN(props.network.lastBlock.baseFeePerGas), 'Gwei') + const baseFee = fromWei(toBigInt(props.network.lastBlock.baseFeePerGas), 'Gwei') setBaseFee(baseFee) onMaxFeeChange(baseFee) @@ -27,7 +27,7 @@ export function MainnetPrompt(props: MainnetProps) { const onMaxFeeChange = (value: string) => { const maxFee = value // @ts-ignore - if (Web3.utils.toBN(props.network.lastBlock.baseFeePerGas).gt(Web3.utils.toBN(Web3.utils.toWei(maxFee, 'Gwei')))) { + if (toBN(props.network.lastBlock.baseFeePerGas).gt(toBN(toWei(maxFee, 'Gwei')))) { setTransactionFee(intl.formatMessage({id: 'udapp.transactionFeeText'})) props.updateGasPriceStatus(false) props.updateConfirmSettings(true) @@ -125,7 +125,7 @@ export function MainnetPrompt(props: MainnetProps) {
- : + : { + _paq.push(['trackEvent', 'compiler', 'compilerDetails', 'download']) + saveAs(new Blob([JSON.stringify(contractProperties, null, '\t')]), `${selectedContract}_compData.json`) + } + return ( + <> +
+ {selectedContract} + + Download + +
+
+ + {Object.keys(contractProperties).map((propertyName: ContractPropertyName, index) => { + const copyDetails = ( + + + + ) + const questionMark = ( + + + + ) + + return ( +
+ + {propertyName} {copyDetails} {questionMark} +
+ } + expand={propertyName === 'metadata' || propertyName === 'bytecode' ? true : false} + iconY='fas fa-caret-down' + > + {insertValue(contractProperties, propertyName)} + +
+ ) + })} + +
+ + ) +} diff --git a/libs/remix-ui/solidity-compiler/src/index.ts b/libs/remix-ui/solidity-compiler/src/index.ts index 386d3792be..1842ab506b 100644 --- a/libs/remix-ui/solidity-compiler/src/index.ts +++ b/libs/remix-ui/solidity-compiler/src/index.ts @@ -1,4 +1,5 @@ export * from './lib/solidity-compiler' export * from './lib/logic' export * from './lib/logic/flattenerUtilities' -export * from './lib/api/compiler-api' \ No newline at end of file +export * from './lib/api/compiler-api' +export * from './lib/types' diff --git a/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx b/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx index 3fc8418c6b..99d6871e67 100644 --- a/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx +++ b/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx @@ -38,8 +38,11 @@ export const CompilerContainer = (props: CompilerContainerProps) => { isFoundryProject, workspaceName, configFilePath, - setConfigFilePath + setConfigFilePath, + //@ts-ignore + pluginProps } = props // eslint-disable-line + const [state, setState] = useState({ hideWarnings: false, autoCompile: false, diff --git a/libs/remix-ui/solidity-compiler/src/lib/contract-selection.tsx b/libs/remix-ui/solidity-compiler/src/lib/contract-selection.tsx index eb2fb58495..a6436db88b 100644 --- a/libs/remix-ui/solidity-compiler/src/lib/contract-selection.tsx +++ b/libs/remix-ui/solidity-compiler/src/lib/contract-selection.tsx @@ -1,6 +1,6 @@ import React, {useState, useEffect} from 'react' // eslint-disable-line import {FormattedMessage, useIntl} from 'react-intl' -import {ContractSelectionProps} from './types' +import {ContractPropertyName, ContractSelectionProps} from './types' import {PublishToStorage} from '@remix-ui/publish-to-storage' // eslint-disable-line import {TreeView, TreeViewItem} from '@remix-ui/tree-view' // eslint-disable-line import {CopyToClipboard} from '@remix-ui/clipboard' // eslint-disable-line @@ -122,7 +122,7 @@ export const ContractSelection = (props: ContractSelectionProps) => { return ret } - const insertValue = (details, propertyName) => { + const insertValue = (details, propertyName: ContractPropertyName) => { let node if (propertyName === 'web3Deploy' || propertyName === 'name' || propertyName === 'Assembly') { node =
{details[propertyName]}
@@ -156,6 +156,14 @@ export const ContractSelection = (props: ContractSelectionProps) => { return
{node || ''}
} + const payload = { + saveAs: saveAs, + contractProperties: {}, + selectedContract: '', + help: {}, + insertValue: insertValue + } + const details = () => { _paq.push(['trackEvent', 'compiler', 'compilerDetails', 'display']) if (!selectedContract) throw new Error('No contract compiled yet') @@ -182,10 +190,14 @@ export const ContractSelection = (props: ContractSelectionProps) => { // Make 'compilerInput' first field to display it as first item in 'Compilation Details' modal if (compilerInput) contractProperties.compilerInput = compilerInput contractProperties = Object.assign(contractProperties, contractsDetails[selectedContract]) + payload.contractProperties = contractProperties + payload.selectedContract = selectedContract + payload.help = help + payload.insertValue = insertValue const log = (
- {Object.keys(contractProperties).map((propertyName, index) => { + {Object.keys(contractProperties).map((propertyName: ContractPropertyName, index) => { const copyDetails = ( @@ -225,7 +237,7 @@ export const ContractSelection = (props: ContractSelectionProps) => { _paq.push(['trackEvent', 'compiler', 'compilerDetails', 'download']) saveAs(new Blob([JSON.stringify(contractProperties, null, '\t')]), `${selectedContract}_compData.json`) } - modal(selectedContract, log, intl.formatMessage({id: 'solidity.download'}), downloadFn, true, intl.formatMessage({id: 'solidity.close'}), null) + // modal(selectedContract, log, intl.formatMessage({id: 'solidity.download'}), downloadFn, true, intl.formatMessage({id: 'solidity.close'}), null) } const copyBytecode = () => { @@ -301,8 +313,9 @@ export const ContractSelection = (props: ContractSelectionProps) => {