diff --git a/.eslintrc.json b/.eslintrc.json index 226848ea37..7993021f1f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -29,7 +29,9 @@ "@typescript-eslint/no-this-alias": "off", "@typescript-eslint/no-empty-function": "off", "eslint-disable-next-line no-empty": "off", - "no-empty": "off" + "no-empty": "off", + "jsx-a11y/anchor-is-valid": "off", + "@typescript-eslint/no-inferrable-types": "off" } }, { diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index d0b804da2a..0000000000 --- a/.prettierignore +++ /dev/null @@ -1,4 +0,0 @@ -# Add files here to ignore them from prettier formatting - -/dist -/coverage diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 544138be45..0000000000 --- a/.prettierrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "singleQuote": true -} diff --git a/apps/remix-ide-e2e/src/commands/createContract.ts b/apps/remix-ide-e2e/src/commands/createContract.ts index 015a4f2012..44ff4780c7 100644 --- a/apps/remix-ide-e2e/src/commands/createContract.ts +++ b/apps/remix-ide-e2e/src/commands/createContract.ts @@ -2,7 +2,7 @@ import { NightwatchBrowser } from 'nightwatch' import EventEmitter from 'events' class CreateContract extends EventEmitter { - command (this: NightwatchBrowser, inputParams: string): NightwatchBrowser { + command (this: NightwatchBrowser, inputParams: string[]): NightwatchBrowser { this.api.perform((done) => { createContract(this.api, inputParams, () => { done() @@ -13,11 +13,19 @@ class CreateContract extends EventEmitter { } } -function createContract (browser: NightwatchBrowser, inputParams: string, callback: VoidFunction) { - if (inputParams) { - browser.setValue('.udapp_contractActionsContainerSingle > input', inputParams, function () { +function createContract (browser: NightwatchBrowser, inputParams: string[], callback: VoidFunction) { + if (inputParams.length === 1) { + browser.setValue('.udapp_contractActionsContainerSingle > input', inputParams[0], function () { browser.click('.udapp_contractActionsContainerSingle > button').pause(500).perform(function () { callback() }) }) + } else if (inputParams.length > 1) { + browser.perform((done) => { + for (let i = 0; i < inputParams.length; i++) { + browser.setValue(`div.udapp_multiArg:nth-child(${i + 1}) > input`, inputParams[i]) + } + done() + }) + .click('div.udapp_multiArg > button').pause(500).perform(function () { callback() }) } else { browser .click('.udapp_contractActionsContainerSingle > button') diff --git a/apps/remix-ide-e2e/src/tests/debugger.test.ts b/apps/remix-ide-e2e/src/tests/debugger.test.ts index 9010b79b58..d46c1020ce 100644 --- a/apps/remix-ide-e2e/src/tests/debugger.test.ts +++ b/apps/remix-ide-e2e/src/tests/debugger.test.ts @@ -86,7 +86,7 @@ module.exports = { .clickLaunchIcon('udapp') .waitForElementPresent('*[title="Deploy - transact (not payable)"]', 35000) .selectContract('ERC20') - .createContract('"tokenName", "symbol"') + .createContract(["tokenName", "symbol"]) .debugTransaction(0) .pause(2000) .waitForElementVisible('#stepdetail') @@ -115,7 +115,7 @@ module.exports = { .testContracts('withABIEncoderV2.sol', sources[2]['withABIEncoderV2.sol'], ['test']) .clickLaunchIcon('udapp') .selectContract('test') - .createContract('') + .createContract([]) .clearConsole() .clickInstance(0) .clickFunction('test1 - transact (not payable)', { types: 'bytes userData', values: '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000015b38da6a701c568545dcfcb03fcb875f56beddc4' }) @@ -148,7 +148,7 @@ module.exports = { .testContracts('locals.sol', sources[3]['locals.sol'], ['testLocals']) .clickLaunchIcon('udapp') .waitForElementPresent('*[title="Deploy - transact (not payable)"]', 40000) - .createContract('') + .createContract([]) .pause(2000) .clearConsole() .clickInstance(0) @@ -173,7 +173,7 @@ module.exports = { .pause(2000) .testContracts('withGeneratedSources.sol', sources[4]['withGeneratedSources.sol'], ['A']) .clickLaunchIcon('udapp') - .createContract('') + .createContract([]) .clearConsole() .clickInstance(0) .clickFunction('f - transact (not payable)', { types: 'uint256[] ', values: '[]' }) @@ -235,7 +235,7 @@ module.exports = { .testContracts('reverted.sol', sources[6]['reverted.sol'], ['A', 'B', 'C']) .clickLaunchIcon('udapp') .selectContract('A') - .createContract('') + .createContract([]) .pause(500) .clickInstance(0) .clickFunction('callA - transact (not payable)') diff --git a/apps/remix-ide-e2e/src/tests/defaultLayout.test.ts b/apps/remix-ide-e2e/src/tests/defaultLayout.test.ts index 5d5f90de45..d79515020f 100644 --- a/apps/remix-ide-e2e/src/tests/defaultLayout.test.ts +++ b/apps/remix-ide-e2e/src/tests/defaultLayout.test.ts @@ -17,7 +17,7 @@ module.exports = { 'Loads Side Panel': function (browser: NightwatchBrowser) { browser.waitForElementVisible('div[data-id="remixIdeSidePanel"]') - .assert.containsText('h6[data-id="sidePanelSwapitTitle"]', 'FILE EXPLORERS') + .assert.containsText('h6[data-id="sidePanelSwapitTitle"]', 'FILE EXPLORER') .waitForElementVisible('div[data-id="filePanelFileExplorerTree"]') .waitForElementVisible('[data-id="treeViewLitreeViewItemcontracts"]') .waitForElementVisible('[data-id="treeViewLitreeViewItemscripts"]') @@ -40,12 +40,12 @@ module.exports = { 'Toggles Side Panel': function (browser: NightwatchBrowser) { browser.waitForElementVisible('div[data-id="remixIdeSidePanel"]') - .assert.containsText('h6[data-id="sidePanelSwapitTitle"]', 'FILE EXPLORERS') + .assert.containsText('h6[data-id="sidePanelSwapitTitle"]', 'FILE EXPLORER') .clickLaunchIcon('filePanel') .assert.hidden('div[data-id="remixIdeSidePanel"]') .clickLaunchIcon('filePanel') .assert.visible('div[data-id="remixIdeSidePanel"]') - .assert.containsText('h6[data-id="sidePanelSwapitTitle"]', 'FILE EXPLORERS') + .assert.containsText('h6[data-id="sidePanelSwapitTitle"]', 'FILE EXPLORER') }, 'Toggles Terminal': function (browser: NightwatchBrowser) { diff --git a/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts b/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts index 663c1bb791..7b26d84679 100644 --- a/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts +++ b/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts @@ -18,7 +18,7 @@ module.exports = { 'Should create a new file `5_New_contract.sol` in file explorer': function (browser: NightwatchBrowser) { browser.waitForElementVisible('div[data-id="remixIdeSidePanel"]') .clickLaunchIcon('filePanel') - .assert.containsText('h6[data-id="sidePanelSwapitTitle"]', 'FILE EXPLORERS') + .assert.containsText('h6[data-id="sidePanelSwapitTitle"]', 'FILE EXPLORER') .click('li[data-id="treeViewLitreeViewItemREADME.txt"]') // focus on root directory .click('*[data-id="fileExplorerNewFilecreateNewFile"]') .pause(1000) diff --git a/apps/remix-ide-e2e/src/tests/libraryDeployment.test.ts b/apps/remix-ide-e2e/src/tests/libraryDeployment.test.ts index 4b3c4528c4..276e9136d5 100644 --- a/apps/remix-ide-e2e/src/tests/libraryDeployment.test.ts +++ b/apps/remix-ide-e2e/src/tests/libraryDeployment.test.ts @@ -22,7 +22,7 @@ module.exports = { browser.verifyContracts(['test']) .clickLaunchIcon('udapp') .selectContract('test') - .createContract('') + .createContract([]) .getAddressAtPosition(0, (address) => { console.log('testAutoDeployLib ' + address) addressRef = address @@ -46,7 +46,7 @@ module.exports = { .verifyContracts(['test']) .clickLaunchIcon('udapp') .selectContract('lib') // deploy lib - .createContract('') + .createContract([]) .perform((done) => { browser.getAddressAtPosition(0, (address) => { console.log(address) @@ -74,7 +74,7 @@ function checkDeployShouldFail (browser: NightwatchBrowser, callback: VoidFuncti .openFile('Untitled5.sol') .clickLaunchIcon('udapp') .selectContract('test') // deploy lib - .createContract('') + .createContract([]) .pause(2000) .getText('div[class^="terminal"]', (value) => { console.log('value: ', value) @@ -98,7 +98,7 @@ function checkDeployShouldSucceed (browser: NightwatchBrowser, address: string, .openFile('Untitled5.sol') .clickLaunchIcon('udapp') .selectContract('test') // deploy lib - .createContract('') + .createContract([]) .getAddressAtPosition(1, (address) => { addressRef = address }) diff --git a/apps/remix-ide-e2e/src/tests/providers.test.ts b/apps/remix-ide-e2e/src/tests/providers.test.ts index 8bbfa7636b..b2c883fd53 100644 --- a/apps/remix-ide-e2e/src/tests/providers.test.ts +++ b/apps/remix-ide-e2e/src/tests/providers.test.ts @@ -29,5 +29,31 @@ module.exports = { .waitForElementVisible('*[data-id="ganache-providerModalDialogModalBody-react"]') .modalFooterOKClick('ganache-provider') .waitForElementContainsText('*[data-id="settingsNetworkEnv"]', 'Custom (') + }, + + 'Should switch to foundry provider, set a custom URL and fail to connect': function (browser: NightwatchBrowser) { + browser.waitForElementVisible('div[data-id="remixIdeIconPanel"]', 10000) + .click('*[data-id="Foundry Provider"]') + .waitForElementVisible('*[data-id="foundry-providerModalDialogModalBody-react"]') + .execute(() => { + (document.querySelector('*[data-id="foundry-providerModalDialogModalBody-react"] input') as any).focus() + }, [], () => {}) + .clearValue('*[data-id="foundry-providerModalDialogModalBody-react"] input') + .setValue('*[data-id="foundry-providerModalDialogModalBody-react"] input', 'http://127.0.0.1:8084') + .modalFooterOKClick('foundry-provider') + .waitForElementContainsText('*[data-id="foundry-providerModalDialogModalBody-react"]', 'Error while connecting to the provider') + .modalFooterOKClick('foundry-provider') + .waitForElementNotVisible('*[data-id="foundry-providerModalDialogModalBody-react"]') + .waitForElementVisible('*[data-id="PermissionHandler-modal-footer-ok-react"]') + .click('*[data-id="PermissionHandler-modal-footer-ok-react"]') + .waitForElementNotVisible('*[data-id="PermissionHandler-modal-footer-ok-react"]') + .pause(1000) + +}, + 'Should switch to foundry provider, use the default foundry URL and succeed to connect': function (browser: NightwatchBrowser) { + browser.click('*[data-id="Foundry Provider"]') + .waitForElementVisible('*[data-id="foundry-providerModalDialogModalBody-react"]') + .modalFooterOKClick('foundry-provider') + .waitForElementContainsText('*[data-id="settingsNetworkEnv"]', 'Custom (') } } diff --git a/apps/remix-ide-e2e/src/tests/recorder.test.ts b/apps/remix-ide-e2e/src/tests/recorder.test.ts index 7e1c0859a7..7e8748b737 100644 --- a/apps/remix-ide-e2e/src/tests/recorder.test.ts +++ b/apps/remix-ide-e2e/src/tests/recorder.test.ts @@ -39,10 +39,10 @@ module.exports = { 'Save scenario': function (browser: NightwatchBrowser) { browser.testContracts('testRecorder.sol', sources[0]['testRecorder.sol'], ['testRecorder']) .clickLaunchIcon('udapp') - .createContract('12') + .createContract(['12']) .clickInstance(0) .clickFunction('set - transact (not payable)', { types: 'uint256 _p', values: '34' }) - .click('i.savetransaction') + .click('.savetransaction') .waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]') .execute(function () { const modalOk = document.querySelector('[data-id="udappNotify-modal-footer-ok-react"]') as any @@ -72,12 +72,12 @@ module.exports = { .clickLaunchIcon('udapp') .selectContract('t1est') .pause(1000) - .createContract('') + .createContract([]) .clickInstance(0) .selectContract('t2est') .pause(1000) - .createContract('') - .click('i.savetransaction') + .createContract([]) + .click('.savetransaction') .waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]') .execute(function () { const modalOk = document.querySelector('[data-id="udappNotify-modal-footer-ok-react"]') as any @@ -95,6 +95,50 @@ module.exports = { status: 'true Transaction mined and execution succeed', 'decoded input': { 'uint256 _po': '10' } }) + + }, + + 'Run with live "mode"': function (browser: NightwatchBrowser) { + let addressRef: string + browser.addFile('scenario_live_mode.json', { content: JSON.stringify(liveModeScenario, null, '\t') }) + .addFile('scenario_live_mode_storage.sol', { content: testStorageForLiveMode }) + .clickLaunchIcon('solidity') + .click('*[data-id="compilerContainerCompileBtn"]') + .openFile('scenario_live_mode.json') + .clickLaunchIcon('udapp') + .click('*[data-id="deployAndRunClearInstances"]') + .click('*[data-id="runtabLivemodeInput"]') + .click('.runtransaction') + .pause(1000) + .clickInstance(0) + .getAddressAtPosition(0, (address) => { + addressRef = address + }) + .clickFunction('retrieve - call') + .perform((done) => { + browser.verifyCallReturnValue(addressRef, ['', '0:uint256: 350']) + .perform(() => done()) + }) + // change the init state and recompile the same contract. + .openFile('scenario_live_mode_storage.sol') + .setEditorValue(testStorageForLiveMode.replace('number = 350', 'number = 300')) + .pause(5000) + .clickLaunchIcon('solidity') + .click('*[data-id="compilerContainerCompileBtn"]') + .openFile('scenario_live_mode.json') + .clickLaunchIcon('udapp') + .click('*[data-id="deployAndRunClearInstances"]') + .click('.runtransaction') + .pause(5000) + .clickInstance(0) + .getAddressAtPosition(0, (address) => { + addressRef = address + }) + .clickFunction('retrieve - call') + .perform((done) => { + browser.verifyCallReturnValue(addressRef, ['', '0:uint256: 300']) + .perform(() => done()) + }) .end() } } @@ -364,3 +408,91 @@ const scenario = { ] } } + +const liveModeScenario = { + "accounts": { + "account{0}": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4" + }, + "linkReferences": {}, + "transactions": [ + { + "timestamp": 1656329164297, + "record": { + "value": "0", + "parameters": [], + "abi": "0x8b8c9c14c8e1442e90dd6ff82bb9889ccfe5a54d88ef30776f11047ecce5fedb", + "contractName": "Storage", + "bytecode": "608060405234801561001057600080fd5b5060c88061001f6000396000f3fe6080604052348015600f57600080fd5b5060043610604e577c010000000000000000000000000000000000000000000000000000000060003504632e64cec1811460535780636057361d146068575b600080fd5b60005460405190815260200160405180910390f35b60786073366004607a565b600055565b005b600060208284031215608b57600080fd5b503591905056fea264697066735822122091f1bc250ccda7caf2b0d9f67b0314d92233fdb5952b72cece72bd2a5d43cfc264736f6c63430008070033", + "linkReferences": {}, + "name": "", + "inputs": "()", + "type": "constructor", + "from": "account{0}" + } + } + ], + "abis": { + "0x8b8c9c14c8e1442e90dd6ff82bb9889ccfe5a54d88ef30776f11047ecce5fedb": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "num", + "type": "uint256" + } + ], + "name": "store", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "retrieve", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ] + } +} + +const testStorageForLiveMode = `// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.7.0 <0.9.0; + +/** + * @title Storage + * @dev Store & retrieve value in a variable + * @custom:dev-run-script ./scripts/deploy_with_ethers.ts + */ +contract Storage { + + uint256 number; + + constructor () { + number = 350; + } + + /** + * @dev Store value in variable + * @param num value to store + */ + function store(uint256 num) public { + number = num; + } + + /** + * @dev Return value + * @return value of 'number' + */ + function retrieve() public view returns (uint256){ + return number; + } +}` diff --git a/apps/remix-ide-e2e/src/tests/search.test.ts b/apps/remix-ide-e2e/src/tests/search.test.ts index b2cff57b7c..9791bae4c5 100644 --- a/apps/remix-ide-e2e/src/tests/search.test.ts +++ b/apps/remix-ide-e2e/src/tests/search.test.ts @@ -33,11 +33,11 @@ module.exports = { .clearValue('*[id="search_include"]').pause(2000) .setValue('*[id="search_include"]', '**').sendKeys('*[id="search_include"]', browser.Keys.ENTER).pause(4000) .elements('css selector', '.search_plugin_search_line', (res) => { - Array.isArray(res.value) && browser.assert.equal(res.value.length, 61) + Array.isArray(res.value) && browser.assert.equal(res.value.length, 62) }) .setValue('*[id="search_exclude"]', ',contracts/**').sendKeys('*[id="search_exclude"]', browser.Keys.ENTER).pause(4000) .elements('css selector', '.search_plugin_search_line', (res) => { - Array.isArray(res.value) && browser.assert.equal(res.value.length, 55) + Array.isArray(res.value) && browser.assert.equal(res.value.length, 56) }) .clearValue('*[id="search_include"]').setValue('*[id="search_include"]', '*.sol, *.js, *.txt') .clearValue('*[id="search_exclude"]').setValue('*[id="search_exclude"]', '.*/**/*') @@ -78,7 +78,7 @@ module.exports = { .clearValue('*[id="search_input"]') .setValue('*[id="search_input"]', 'contract').sendKeys('*[id="search_input"]', browser.Keys.ENTER).pause(4000) .elements('css selector', '.search_plugin_search_line', (res) => { - Array.isArray(res.value) && browser.assert.equal(res.value.length, 13) + Array.isArray(res.value) && browser.assert.equal(res.value.length, 15) }) }, 'Should replace text': function (browser: NightwatchBrowser) { diff --git a/apps/remix-ide-e2e/src/tests/signingMessage.test.ts b/apps/remix-ide-e2e/src/tests/signingMessage.test.ts index 913851fa38..177dac88a0 100644 --- a/apps/remix-ide-e2e/src/tests/signingMessage.test.ts +++ b/apps/remix-ide-e2e/src/tests/signingMessage.test.ts @@ -33,7 +33,7 @@ module.exports = { .clickLaunchIcon('udapp') .pause(5000) .selectContract('ECVerify') - .createContract('') + .createContract([]) .clickInstance(0) .perform((done) => { browser.getAddressAtPosition(0, (address) => { diff --git a/apps/remix-ide-e2e/src/tests/specialFunctions.test.ts b/apps/remix-ide-e2e/src/tests/specialFunctions.test.ts index bcdc3c4977..48137e3b8b 100644 --- a/apps/remix-ide-e2e/src/tests/specialFunctions.test.ts +++ b/apps/remix-ide-e2e/src/tests/specialFunctions.test.ts @@ -24,7 +24,7 @@ module.exports = { .clickLaunchIcon('udapp') .selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite .selectContract('CheckSpecials') - .createContract('') // deploy + .createContract([]) // deploy .clickInstance(0) .perform((done) => { browser.getAddressAtPosition(0, (address) => { @@ -92,7 +92,7 @@ module.exports = { .testContracts('receiveOnly.sol', sources[1]['receiveOnly.sol'], ['CheckSpecials']) .clickLaunchIcon('udapp') .selectContract('CheckSpecials') - .createContract('') + .createContract([]) .clickInstance(0) .perform((done) => { browser.getAddressAtPosition(0, (address) => { @@ -122,7 +122,7 @@ module.exports = { .testContracts('fallbackOnlyPayable.sol', sources[2]['fallbackOnlyPayable.sol'], ['CheckSpecials']) .clickLaunchIcon('udapp') .selectContract('CheckSpecials') - .createContract('') + .createContract([]) .clickInstance(0) .perform((done) => { browser.getAddressAtPosition(0, (address) => { @@ -153,7 +153,7 @@ module.exports = { .testContracts('fallbackOnlyNotPayable.sol', sources[3]['fallbackOnlyNotPayable.sol'], ['CheckSpecials']) .clickLaunchIcon('udapp') .selectContract('CheckSpecials') - .createContract('') + .createContract([]) .clickInstance(0) .perform((done) => { browser.getAddressAtPosition(0, (address) => { @@ -174,7 +174,7 @@ module.exports = { .clearValue('#value') .setValue('#value', '0') .pause(2000) - .createContract('') + .createContract([]) .pause(1000) .clickInstance(0).pause(1000) .perform((done) => { @@ -208,7 +208,7 @@ module.exports = { .waitForElementVisible('#value') .clearValue('#value') .setValue('#value', '0').pause(2000) - .createContract('') + .createContract([]) .clickInstance(0) .pause(1000) .perform((done) => { diff --git a/apps/remix-ide-e2e/src/tests/terminal.test.ts b/apps/remix-ide-e2e/src/tests/terminal.test.ts index a824c7871f..40c59875da 100644 --- a/apps/remix-ide-e2e/src/tests/terminal.test.ts +++ b/apps/remix-ide-e2e/src/tests/terminal.test.ts @@ -172,7 +172,7 @@ module.exports = { .clickLaunchIcon('udapp') .click('*[data-id="deployAndRunClearInstances"]') .selectContract('OwnerTest') - .createContract('') + .createContract([]) .pause(1000) .journalChildIncludes('constructor', { shouldHaveOnlyOneOccurence: true }) .pause(5000) diff --git a/apps/remix-ide-e2e/src/tests/transactionExecution.test.ts b/apps/remix-ide-e2e/src/tests/transactionExecution.test.ts index da26b27793..3eac406fcd 100644 --- a/apps/remix-ide-e2e/src/tests/transactionExecution.test.ts +++ b/apps/remix-ide-e2e/src/tests/transactionExecution.test.ts @@ -202,10 +202,10 @@ module.exports = { .addFile('Storage.sol', sources[6]['Storage.sol']) .addFile('Owner.sol', sources[6]['Owner.sol']) .clickLaunchIcon('udapp') - .createContract('42, 24') + .createContract(['42', '24']) .openFile('Storage.sol') .clickLaunchIcon('udapp') - .createContract('102') // this creation will fail if the component hasn't been properly reset. + .createContract(['102']) // this creation will fail if the component hasn't been properly reset. .clickInstance(1) .clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '24' }) .testFunction('last', // we check if the contract is actually reachable. diff --git a/apps/remix-ide-e2e/src/types/index.d.ts b/apps/remix-ide-e2e/src/types/index.d.ts index 7fbcb174d5..f17e6b17de 100644 --- a/apps/remix-ide-e2e/src/types/index.d.ts +++ b/apps/remix-ide-e2e/src/types/index.d.ts @@ -34,7 +34,7 @@ declare module 'nightwatch' { getModalBody(callback: (value: string, cb: VoidFunction) => void): NightwatchBrowser, modalFooterCancelClick(id?: string): NightwatchBrowser, selectContract(contractName: string): NightwatchBrowser, - createContract(inputParams: string): NightwatchBrowser, + createContract(inputParams: string[]): NightwatchBrowser, getAddressAtPosition(index: number, cb: (pos: string) => void): NightwatchBrowser, testConstantFunction(address: string, fnFullName: string, expectedInput: NightwatchTestConstantFunctionExpectedInput | null, expectedOutput: string): NightwatchBrowser, getEditorValue(callback: (content: string) => void): NightwatchBrowser, diff --git a/apps/remix-ide/.babelrc b/apps/remix-ide/.babelrc index e60d3036a3..58a023dfd5 100644 --- a/apps/remix-ide/.babelrc +++ b/apps/remix-ide/.babelrc @@ -1,4 +1,4 @@ { "presets": ["@babel/preset-env", "@babel/preset-react"], - "plugins": ["@babel/plugin-proposal-class-properties"] + "plugins": ["@babel/plugin-proposal-class-properties", "@babel/plugin-transform-runtime"] } diff --git a/apps/remix-ide/README.md b/apps/remix-ide/README.md deleted file mode 100644 index 8f84d6771f..0000000000 --- a/apps/remix-ide/README.md +++ /dev/null @@ -1,174 +0,0 @@ -[![CircleCI](https://circleci.com/gh/ethereum/remix-project.svg?style=svg)](https://circleci.com/gh/ethereum/remix-project) - -# Remix - -Remix is a browser-based compiler and IDE that enables users to build **Ethereum contracts with Solidity language** and to debug transactions. - -To try it out, visit [https://remix.ethereum.org](https://remix.ethereum.org). - -https://github.com/ethereum/remix-ide/releases also gives others ways to use Remix locally. Please check it out. - -Remix consists of many modules and in this repository you will find the Remix IDE (aka. Browser-Solidity). - -![Remix screenshot](https://github.com/ethereum/remix-ide/raw/master/remix_screenshot.png) - -## Offline Usage - -The `gh-pages` branch has always the latest stable build of Remix. It also contains a ZIP file with the entire build. Download it to use offline. - -Note: It contains the latest release of Solidity available at the time of the packaging. No other compiler versions are supported. - - -## INSTALLATION: - -Install **npm** and **node.js** (see https://docs.npmjs.com/getting-started/installing-node), then do: - -Remix-ide has been published as an npm module: - -```bash -yarn global add remix-ide -remix-ide -``` -Or if you want to clone the github repository (`wget` need to be installed first) : - -```bash -git clone https://github.com/ethereum/remix-ide.git -git clone https://github.com/ethereum/remix.git # only if you plan to link remix and remix-ide repositories and develop on it. - -cd remix # only if you plan to link remix and remix-ide repositories and develop on it. -yarn install # only if you plan to link remix and remix-ide repositories and develop on it. -yarn run bootstrap # only if you plan to link remix and remix-ide repositories and develop on it. - -cd remix-ide -yarn install -yarn run setupremix # only if you plan to link remix and remix-ide repositories and develop on it. -npm start -``` - -## Docker: - -Prerequisites: -* Docker (https://docs.docker.com/desktop/) -* Docker-compose (https://docs.docker.com/compose/install/) - -### Run with docker - -If you want to run latest changes that are merged into master branch then run: - -``` -docker pull remixproject/remix-ide:latest -docker run -p 8080:80 remixproject/remix-ide:latest -``` - -If you want to run latest remix-live release run. -``` -docker pull remixproject/remix-ide:remix_live -docker run -p 8080:80 remixproject/remix-ide:remix_live -``` - -### Run with docker-compose: - -To run locally without building you only need docker-compose.yaml file and you can run: - -``` -docker-compose pull -docker-compose up -d -``` - -Then go to http://localhost:8080 and you can use you Remix instance. - -To fetch docker-compose file without cloning this repo run: -``` -curl https://raw.githubusercontent.com/ethereum/remix-ide/master/docker-compose.yaml > docker-compose.yaml -``` - -## DEVELOPING: - -Run `npm start` and open `http://127.0.0.1:8080` in your browser. - -Then open your `text editor` and start developing. -The browser will automatically refresh when files are saved. - -Most of the the time working with other modules (like debugger etc.) hosted in the [Remix repository](https://github.com/ethereum/remix) is not needed. - -### Troubleshooting building - -Some things to consider if you have trouble building the package: - -- Make sure that you have the correct version of `node`, `npm` and `nvm`. You can find the version that is tested on Travis CI by looking at the log in the [build results](https://travis-ci.org/ethereum/remix-ide). - -Run: - -```bash -node --version -npm --version -nvm --version -``` - -- In Debian based OS such as Ubuntu 14.04LTS you may need to run `apt-get install build-essential`. After installing `build-essential` run `npm rebuild`. - -## Unit Testing - -Register new unit test files in `test/index.js`. -The tests are written using [tape](https://www.npmjs.com/package/tape). - -Run the unit tests via: `yarn test` - -For local headless browser tests run `yarn run test-browser` -(requires Selenium to be installed - can be done with `yarn run selenium-install`) - -Running unit tests via `yarn test` requires at least node v7.0.0 - -## Browser Testing - -To run the Selenium tests via Nightwatch: - - - Build Remix IDE and serve it: `yarn run build && yarn run serve` # starts web server at localhost:8080 - - Make sure Selenium is installed `yarn run selenium-install` # don't need to repeat - - Run a selenium server `yarn run selenium` - - Run all the tests `yarn run nightwatch_local_firefox` or `yarn run nightwatch_local_chrome` - - Or run a specific test case: - - - yarn run nightwatch_local_ballot - - - yarn run nightwatch_local_libraryDeployment - - - yarn run nightwatch_local_solidityImport - - - yarn run nightwatch_local_recorder - - - yarn run nightwatch_local_transactionExecution - - - yarn run nightwatch_local_staticAnalysis - - - yarn run nightwatch_local_signingMessage - - - yarn run nightwatch_local_console - - - yarn run nightwatch_local_remixd # remixd needs to be run -**NOTE:** - -- **the `ballot` tests suite** requires to run `ganache-cli` locally. - -- **the `remixd` tests suite** requires to run `remixd` locally. - -- **the `gist` tests suite** requires specifying a github access token in **.env file**. -``` - gist_token = -``` -**note that this token should have permission to create a gist.** - - -## Usage as a Chrome Extension - -If you would like to use this as a Chrome extension, you must either build it first or pull from the `gh-pages` branch, both described above. -After that, follow these steps: - -- Browse to `chrome://extensions/` -- Make sure 'Developer mode' has been checked -- Click 'Load unpacked extension...' to pop up a file-selection dialog -- Select your `remix-ide` folder - -## Documentation - -To see details about how to use Remix for developing and/or debugging Solidity contracts, please see [our documentation page](https://remix-ide.readthedocs.io/en/latest/) diff --git a/apps/remix-ide/bin/remix-ide b/apps/remix-ide/bin/remix-ide deleted file mode 100755 index 887bab51fa..0000000000 --- a/apps/remix-ide/bin/remix-ide +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env node -var path = require('path') -var httpServer = require('http-server') -var remixd = require('remixd') - -var server = httpServer.createServer({ - root: path.join(__dirname, '/../') -}) - -var folder = process.argv.length > 2 ? process.argv[2] : process.cwd() - -server.listen(8080, '127.0.0.1', function () {}) -var router = new remixd.Router(65520, remixd.services.sharedFolder, { remixIdeUrl: 'http://localhost:8080' }, (webSocket) => { - remixd.services.sharedFolder.setWebSocket(webSocket) - remixd.services.sharedFolder.setupNotifications(folder) - remixd.services.sharedFolder.sharedFolder(folder, false) -}) - -router.start() - -console.log('\x1b[33m%s\x1b[0m', 'Starting Remix IDE at http://localhost:8080 and sharing ' + folder) diff --git a/apps/remix-ide/docs/FAQ.md b/apps/remix-ide/docs/FAQ.md deleted file mode 100644 index 5bdfad1b72..0000000000 --- a/apps/remix-ide/docs/FAQ.md +++ /dev/null @@ -1,87 +0,0 @@ -FAQ -=== - -### Solidity compiler - -**Q: Error: compiler might be in a non-sane state** -``` -error: "Uncaught JavaScript exception: RangeError: Maximum call stack size exceeded. -The compiler might be in a non-sane state, please be careful and do not use further compilation data to deploy to mainnet. -It is heavily recommended to use another browser not affected by this issue (Firefox is known to not be affected)." -``` - -**A:** Old versions of solidity compiler had this problem with chrome. -Please change the compiler version in Solidity Plugin to the newer one or use another browser. - -**Q:** I’m getting an issue with Maximum call stack exceed and various other errors, can't compile. - -**A:** Try a different browser or a newer solidity compiler version. - -**Q:** How to verify a contract that imports other contracts? - -**A:** The verification tool does not recursively go through the import statments in a contract. So can only verify a 'flattened' contract. - -There is a plugin called `Flattener` which will stuff all the original code and the imported code into a single file. - -### Deploy & Run - -**Q:** I am using an Infura endpoint in my app, but when I try to deploy against that endpoint in remix IDE selecting "web3 provider" and putting my endpoint in, it's telling me that it can't connect - -**A:** If the endpoint you are using is http, it won't work. - -**Q:** Where is deploy button? - -**A:** Its in the Deploy & Run module. If you haven't activated that module, you should do that by clicking Deploy & Run module in the Plugin Manager. -You could also activate everything you need to work with solidity on the landing page ( click the remix logo at the top left for the screen) and click the "Solidity" button in the environment section. - -**Q:** How to pass a tuple to a public function in Remix? - -**A:** Pass it as an array []. - -**Q:** How to input a struct as input to a parameter of a function in the Deploy & Run module? - -**A:** For inputting a struct, just like a tuple, pass it in as an array []. Also you need to put in the line: - -`pragma experimental ABIEncoderV2;` at the top of the solidity file. - -For example, here's a solidity file with a struct is an input parameter. - -``` -pragma solidity >=0.4.22 <0.6.0; -pragma experimental ABIEncoderV2; - -contract daPeeps { - struct Peep {uint a; uint b;} // declaration of Peep type - Peep peep; //declaration of an object of Peep type - - constructor () public - { - peep.a = 0; // definition/initialisation of object - peep.b = 0; // - } - - function initPeepToPeep(Peep memory i) public payable { - peep.a = i.a; - peep.b = i.b; - } - function setPeep(uint a, uint b) public payable { - peep.a = a; - peep.b = b; - } - - function getPeep() public view returns(Peep memory) - { - return peep; - } -} -``` - -The input of initPeepToPeeps takes a struct. If you input -`[1,2]` the transaction will go through. - - -### General - -**Q:** Where do plugin developers go with their questions? - -**A:** The Gitter Remix plugin developers room https://gitter.im/ethereum/remix-dev-plugin diff --git a/apps/remix-ide/docs/Makefile b/apps/remix-ide/docs/Makefile deleted file mode 100644 index a04587262d..0000000000 --- a/apps/remix-ide/docs/Makefile +++ /dev/null @@ -1,216 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " applehelp to make an Apple Help Book" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - @echo " coverage to run coverage check of the documentation (if enabled)" - -.PHONY: clean -clean: - rm -rf $(BUILDDIR)/* - -.PHONY: html -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -.PHONY: dirhtml -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -.PHONY: singlehtml -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -.PHONY: pickle -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -.PHONY: json -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -.PHONY: htmlhelp -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -.PHONY: qthelp -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Remix.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Remix.qhc" - -.PHONY: applehelp -applehelp: - $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp - @echo - @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." - @echo "N.B. You won't be able to view it unless you put it in" \ - "~/Library/Documentation/Help or install it in your application" \ - "bundle." - -.PHONY: devhelp -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/Remix" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Remix" - @echo "# devhelp" - -.PHONY: epub -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -.PHONY: latex -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -.PHONY: latexpdf -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -.PHONY: latexpdfja -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -.PHONY: text -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -.PHONY: man -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -.PHONY: texinfo -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -.PHONY: info -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -.PHONY: gettext -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -.PHONY: changes -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -.PHONY: linkcheck -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -.PHONY: doctest -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -.PHONY: coverage -coverage: - $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage - @echo "Testing of coverage in the sources finished, look at the " \ - "results in $(BUILDDIR)/coverage/python.txt." - -.PHONY: xml -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -.PHONY: pseudoxml -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/apps/remix-ide/docs/assert_library.md b/apps/remix-ide/docs/assert_library.md deleted file mode 100644 index 8b33971294..0000000000 --- a/apps/remix-ide/docs/assert_library.md +++ /dev/null @@ -1,95 +0,0 @@ -Remix Assert Library -==================== - -* [Assert.ok(value[, message])](#assert-ok-value-message) -* [Assert.equal(actual, expected[, message])](#assert-equal-actual-expected-message) -* [Assert.notEqual(actual, expected[, message])](#assert-notequal-actual-expected-message) -* [Assert.greaterThan(value1, value2[, message])](#assert-greaterthan-value1-value2-message) -* [Assert.lesserThan(value1, value2[, message])](#assert-lesserthan-value1-value2-message) - - -## Assert - -### Assert.ok(value[, message]) -* `value`: \ -* `message`: \ - -Tests if value is truthy. `message` is returned in case of failure. - -Examples: -``` -Assert.ok(true); -// OK -Assert.ok(false, "it\'s false"); -// error: it's false -``` - -### Assert.equal(actual, expected[, message]) -* `actual`: \ -* `expected`: \ -* `message`: \ - -Tests if `actual` & `expected` values are same. `message` is returned in case of failure. - -Examples: -``` -Assert.equal(string("a"), "a"); -// OK -Assert.equal(uint(100), 100); -// OK -foo.set(200) -Assert.equal(foo.get(), 200); -// OK -Assert.equal(foo.get(), 100, "value should be 200"); -// error: value should be 200 -``` - -### Assert.notEqual(actual, expected[, message]) -* `actual`: \ -* `expected`: \ -* `message`: \ - -Tests if `actual` & `expected` values are not same. `message` is returned in case of failure. - -Examples: -``` -Assert.notEqual(string("a"), "b"); -// OK -foo.set(200) -Assert.notEqual(foo.get(), 200, "value should not be 200"); -// error: value should not be 200 -``` - -### Assert.greaterThan(value1, value2[, message]) -* `value1`: \ -* `value2`: \ -* `message`: \ - -Tests if `value1` is greater than `value2`. `message` is returned in case of failure. - -Examples: -``` -Assert.greaterThan(uint(2), uint(1)); -// OK -Assert.greaterThan(uint(-2), uint(1)); -// OK -Assert.greaterThan(int(2), int(1)); -// OK -Assert.greaterThan(int(-2), int(-1), "-2 is not greater than -1"); -// error: -2 is not greater than -1 -``` - -### Assert.lesserThan(value1, value2[, message]) -* `value1`: \ -* `value2`: \ -* `message`: \ - -Tests if `value1` is lesser than `value2`. `message` is returned in case of failure. - -Examples: -``` -Assert.lesserThan(int(-2), int(-1)); -// OK -Assert.lesserThan(int(2), int(1), "2 is not lesser than 1"); -// error: 2 is not greater than 1 -``` \ No newline at end of file diff --git a/apps/remix-ide/docs/code_contribution_guide.md b/apps/remix-ide/docs/code_contribution_guide.md deleted file mode 100644 index 5553b87c21..0000000000 --- a/apps/remix-ide/docs/code_contribution_guide.md +++ /dev/null @@ -1,11 +0,0 @@ -Code Contribution Guide -======================= - -Remix is an open source tool and we encourage anyone to help us improve our tool. -You can do that by opening issues, giving feedback or by contributing a pull request -to our codebase. - -The Remix application is built with JavaScript and React. -Check out the `package.json` files in the Remix submodules to learn more about the stack. - -To learn more, please visit our [GitHub page](https://github.com/ethereum/remix-ide). diff --git a/apps/remix-ide/docs/community.md b/apps/remix-ide/docs/community.md deleted file mode 100644 index 9d1ca262e8..0000000000 --- a/apps/remix-ide/docs/community.md +++ /dev/null @@ -1,14 +0,0 @@ -Community Support -======================= - -We know that blockchain ecosystem is very new and that lots of information is scattered around the web. -That is why we created a community support channel where we and other users try to answer your questions if -you get stuck using Remix. Please, join [the community](https://gitter.im/ethereum/remix) and ask for help. - -For anyone who is interested in developing a custom plugin for Remix or who wants to contribute to the codebase, -we opened a [contributors' channel](https://gitter.im/ethereum/remix-dev) especially for developers working on Remix tools. - -We would kindly ask you to respect the space and to use it for -getting help with your work and the developers' channel for discussions related to working on Remix codebase. If you have -ideas for collaborations or you want to promote your project, try to find some more appropriate channels to do so. Or you can contact -the main contributors directly on Gitter or Twitter. diff --git a/apps/remix-ide/docs/compile.md b/apps/remix-ide/docs/compile.md deleted file mode 100644 index 66453f0836..0000000000 --- a/apps/remix-ide/docs/compile.md +++ /dev/null @@ -1,34 +0,0 @@ -Compiler (Solidity) -=================== - -Clicking the Solidity icon in the icon panel brings you to the Solidty Compiler. - -Compiling is triggered when you click the compile button ( **D. in image below**). If you want the file to be compiled each time the file is saved or when another file is selected - check the auto compile checkbox ( **E. in image below**). - -Since the Solidity version `0.5.7`, it is possible to compile `Yul` files. Please read the ([solidity documentation about Yul](https://solidity.readthedocs.io/en/latest/yul.html)) which contain some code examples. -You can use the language dropdown ( **B. in image below**) to switch the language. **This dropdown list is only available for versions greater than or equal to `0.5.7`.** - -The fork selection dropdown list ( **C. in image below**) allows to compile code against a specific ethereum hard fork. -The `compiler default` corresponds to the default hard fork used by a specific version. Please go to "Compilation Details" ( **G. in image below**) in the settings of `Metadata` section to see the harfork name used for the current compilation. - -If the contract has a lot of dependencies it can take a while to compile - so you use autocompilation at your discretion. - -![](images/a-sol-compiler.png) - -After each compilation, a list is updated with all newly compiled -contracts. A compiled contract can be selected with the Contract pulldown menu ( **F. in the image**). Multiple contracts are compiled when one contract imports other contracts. Selecting a contract will show information about that one. - -When the "Compilation Details" button is clicked ( **G. in image**), a modal opens displaying detailed information about the current selected contract. - -For those writing your own custom solidity compiler, you can import that by clicking the **+** button (**X. in the image**) to open a modal where you can input the url of the compiler to be loaded. - -From the Solidity Compiler module you can also publish your contract to Swarm (only non -abstract contracts can be published) & IPFS. - -Published data notably contains the `abi` and the solidity source code. - -After a contract is published, you can find its metadata information -using the bzz URL located in the details modal dialog `SWARM LOCATION`. - -Compilation Errors and Warning are displayed below the contract section. -At each compilation, the static analysis tab builds a report. It is important to address reported issues even if the compiler doesn't complain. ([see more](static_analysis.html)) diff --git a/apps/remix-ide/docs/conf.py b/apps/remix-ide/docs/conf.py deleted file mode 100644 index 4d4ccac4eb..0000000000 --- a/apps/remix-ide/docs/conf.py +++ /dev/null @@ -1,305 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Remix documentation build configuration file, created by -# sphinx-quickstart on Mon Feb 20 12:16:16 2017. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os - - - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ['recommonmark'] # required for sphinx v3.0.0 - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -source_suffix = ['.rst', '.md'] - - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Remix, Ethereum-IDE' -copyright = u'2019, Remix' -author = u'Remix team' - -github_doc_root = 'https://github.com/ethereum/remix/tree/master/docs/' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = u'1' -# The full version, including alpha/beta/rc tags. -release = u'1' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -highlight_language = 'JavaScript' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'sphinx_rtd_theme' - - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (relative to this directory) to use as a favicon of -# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Language to be used for generating the HTML full-text search index. -# Sphinx supports the following languages: -# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' -# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' -#html_search_language = 'en' - -# A dictionary with options for the search language support, empty by default. -# Now only 'ja' uses this config value -#html_search_options = {'type': 'default'} - -# The name of a javascript file (relative to the configuration directory) that -# implements a search results scorer. If empty, the default will be used. -#html_search_scorer = 'scorer.js' - -# Output file base name for HTML help builder. -htmlhelp_basename = 'Remixdoc' - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', - -# Latex figure (float) alignment -#'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'Remix.tex', u'Remix Documentation', - u'yann300', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'remix', u'Remix Documentation', - [author], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'Remix', u'Remix Documentation', - author, 'Remix', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False - -# Uncomment these two lines with sphinx version 1.0.0 -# from recommonmark.parser import CommonMarkParser -# source_parsers = {'.md': CommonMarkParser} - - -# app setup hook -# def setup(app): -# app.add_config_value('recommonmark_config', { -# 'url_resolver': lambda url: github_doc_root + url, -# 'enable_auto_toc_tree': True, -# 'enable_eval_rst': True, -# 'enable_auto_doc_ref': True, -# }, True) -# app.add_transform(AutoStructify) diff --git a/apps/remix-ide/docs/contract_metadata.md b/apps/remix-ide/docs/contract_metadata.md deleted file mode 100644 index 8258b78c8f..0000000000 --- a/apps/remix-ide/docs/contract_metadata.md +++ /dev/null @@ -1,183 +0,0 @@ -Build Artifact -============== - -When a compilation succeeds, Remix creates a JSON file for each compiled contract. -The JSON file contains the compilation's artifact. Actually, for this to happen, you need to check the **Generate contract metadata** box in the **General settings** section of the **Settings** module. The .JSON file with the metadata will appear in the file explorer where the compiled file is located. - -This JSON file contains the link to the libraries, the bytecode, the deployed bytecode, the gas estimation, the method identifiers, and the ABI. - -You can write scripts that can access this file. - -Library Deployment ------------------- - -By default Remix automatically deploys needed libraries. - -`linkReferences` contains a map representing libraries which depend on the current contract. -Values are addresses of libraries used for linking the contract. - -`autoDeployLib` defines if the libraries should be auto deployed by Remix or if the contract should be linked with libraries described in `linkReferences` - -Note that Remix will resolve addresses corresponding to the current network. -By default, a configuration key follow the form: `:`, but it is also possible -to define `` or `` as keys. - - - -``` -{ - "VM:-": { - "linkReferences": { - "browser/Untitled.sol": { - "lib": "
", - "lib2": "
" - } - }, - "autoDeployLib": true - }, - "main:1": { - "linkReferences": { - "browser/Untitled.sol": { - "lib": "
", - "lib2": "
" - } - }, - "autoDeployLib": true - }, - "ropsten:3": { - "linkReferences": { - "browser/Untitled.sol": { - "lib": "
", - "lib2": "
" - } - }, - "autoDeployLib": true - }, - "rinkeby:4": { - "linkReferences": { - "browser/Untitled.sol": { - "lib": "
", - "lib2": "
" - } - }, - "autoDeployLib": true - }, - "kovan:42": { - "linkReferences": { - "browser/Untitled.sol": { - "lib": "
", - "lib2": "
" - } - }, - "autoDeployLib": true - }, - "data": { - "bytecode": { - "linkReferences": {}, - "object": "608060405234801561001057600080fd5b506040516108723803806108728339818101604052602081101561003357600080fd5b8101908080519060200190929190505050336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060018060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001819055508060ff166002816100fd9190610104565b5050610157565b81548183558181111561012b5781836000526020600020918201910161012a9190610130565b5b505050565b61015491905b808211156101505760008082016000905550600101610136565b5090565b90565b61070c806101666000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80635c19a95c14610051578063609ff1bd146100955780639e7b8d61146100b9578063b3f98adc146100fd575b600080fd5b6100936004803603602081101561006757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061012e565b005b61009d610481565b604051808260ff1660ff16815260200191505060405180910390f35b6100fb600480360360208110156100cf57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506104f9565b005b61012c6004803603602081101561011357600080fd5b81019080803560ff1690602001909291905050506105f6565b005b6000600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060010160009054906101000a900460ff161561018e575061047e565b5b600073ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160029054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141580156102bc57503373ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160029054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b1561032b57600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160029054906101000a900473ffffffffffffffffffffffffffffffffffffffff16915061018f565b3373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610365575061047e565b60018160010160006101000a81548160ff021916908315150217905550818160010160026101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060010160009054906101000a900460ff161561046457816000015460028260010160019054906101000a900460ff1660ff168154811061044557fe5b906000526020600020016000016000828254019250508190555061047b565b816000015481600001600082825401925050819055505b50505b50565b6000806000905060008090505b6002805490508160ff1610156104f4578160028260ff16815481106104af57fe5b906000526020600020016000015411156104e75760028160ff16815481106104d357fe5b906000526020600020016000015491508092505b808060010191505061048e565b505090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415806105a15750600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160009054906101000a900460ff165b156105ab576105f3565b60018060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001819055505b50565b6000600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060010160009054906101000a900460ff168061065e57506002805490508260ff1610155b1561066957506106d4565b60018160010160006101000a81548160ff021916908315150217905550818160010160016101000a81548160ff021916908360ff160217905550806000015460028360ff16815481106106b857fe5b9060005260206000200160000160008282540192505081905550505b5056fea265627a7a72315820457d09494a1d1d64ebd9b931a6c692e671dc1f14d4a0c6600f7aa00fed36011064736f6c634300050b0032", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH2 0x872 CODESIZE SUB DUP1 PUSH2 0x872 DUP4 CODECOPY DUP2 DUP2 ADD PUSH1 0x40 MSTORE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x33 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 MLOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP CALLER PUSH1 0x0 DUP1 PUSH2 0x100 EXP DUP2 SLOAD DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF MUL NOT AND SWAP1 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND MUL OR SWAP1 SSTORE POP PUSH1 0x1 DUP1 PUSH1 0x0 DUP1 PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x0 ADD DUP2 SWAP1 SSTORE POP DUP1 PUSH1 0xFF AND PUSH1 0x2 DUP2 PUSH2 0xFD SWAP2 SWAP1 PUSH2 0x104 JUMP JUMPDEST POP POP PUSH2 0x157 JUMP JUMPDEST DUP2 SLOAD DUP2 DUP4 SSTORE DUP2 DUP2 GT ISZERO PUSH2 0x12B JUMPI DUP2 DUP4 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x12A SWAP2 SWAP1 PUSH2 0x130 JUMP JUMPDEST JUMPDEST POP POP POP JUMP JUMPDEST PUSH2 0x154 SWAP2 SWAP1 JUMPDEST DUP1 DUP3 GT ISZERO PUSH2 0x150 JUMPI PUSH1 0x0 DUP1 DUP3 ADD PUSH1 0x0 SWAP1 SSTORE POP PUSH1 0x1 ADD PUSH2 0x136 JUMP JUMPDEST POP SWAP1 JUMP JUMPDEST SWAP1 JUMP JUMPDEST PUSH2 0x70C DUP1 PUSH2 0x166 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x4C JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x5C19A95C EQ PUSH2 0x51 JUMPI DUP1 PUSH4 0x609FF1BD EQ PUSH2 0x95 JUMPI DUP1 PUSH4 0x9E7B8D61 EQ PUSH2 0xB9 JUMPI DUP1 PUSH4 0xB3F98ADC EQ PUSH2 0xFD JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x93 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x67 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x12E JUMP JUMPDEST STOP JUMPDEST PUSH2 0x9D PUSH2 0x481 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 PUSH1 0xFF AND PUSH1 0xFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0xFB PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0xCF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x4F9 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x12C PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x113 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH1 0xFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x5F6 JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 PUSH1 0x1 PUSH1 0x0 CALLER PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SWAP1 POP DUP1 PUSH1 0x1 ADD PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH1 0xFF AND ISZERO PUSH2 0x18E JUMPI POP PUSH2 0x47E JUMP JUMPDEST JUMPDEST PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH1 0x1 PUSH1 0x0 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x1 ADD PUSH1 0x2 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO DUP1 ISZERO PUSH2 0x2BC JUMPI POP CALLER PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH1 0x1 PUSH1 0x0 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x1 ADD PUSH1 0x2 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO JUMPDEST ISZERO PUSH2 0x32B JUMPI PUSH1 0x1 PUSH1 0x0 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x1 ADD PUSH1 0x2 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP2 POP PUSH2 0x18F JUMP JUMPDEST CALLER PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0x365 JUMPI POP PUSH2 0x47E JUMP JUMPDEST PUSH1 0x1 DUP2 PUSH1 0x1 ADD PUSH1 0x0 PUSH2 0x100 EXP DUP2 SLOAD DUP2 PUSH1 0xFF MUL NOT AND SWAP1 DUP4 ISZERO ISZERO MUL OR SWAP1 SSTORE POP DUP2 DUP2 PUSH1 0x1 ADD PUSH1 0x2 PUSH2 0x100 EXP DUP2 SLOAD DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF MUL NOT AND SWAP1 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND MUL OR SWAP1 SSTORE POP PUSH1 0x0 PUSH1 0x1 PUSH1 0x0 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SWAP1 POP DUP1 PUSH1 0x1 ADD PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH1 0xFF AND ISZERO PUSH2 0x464 JUMPI DUP2 PUSH1 0x0 ADD SLOAD PUSH1 0x2 DUP3 PUSH1 0x1 ADD PUSH1 0x1 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH1 0xFF AND PUSH1 0xFF AND DUP2 SLOAD DUP2 LT PUSH2 0x445 JUMPI INVALID JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 ADD PUSH1 0x0 ADD PUSH1 0x0 DUP3 DUP3 SLOAD ADD SWAP3 POP POP DUP2 SWAP1 SSTORE POP PUSH2 0x47B JUMP JUMPDEST DUP2 PUSH1 0x0 ADD SLOAD DUP2 PUSH1 0x0 ADD PUSH1 0x0 DUP3 DUP3 SLOAD ADD SWAP3 POP POP DUP2 SWAP1 SSTORE POP JUMPDEST POP POP JUMPDEST POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 SWAP1 POP PUSH1 0x0 DUP1 SWAP1 POP JUMPDEST PUSH1 0x2 DUP1 SLOAD SWAP1 POP DUP2 PUSH1 0xFF AND LT ISZERO PUSH2 0x4F4 JUMPI DUP2 PUSH1 0x2 DUP3 PUSH1 0xFF AND DUP2 SLOAD DUP2 LT PUSH2 0x4AF JUMPI INVALID JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 ADD PUSH1 0x0 ADD SLOAD GT ISZERO PUSH2 0x4E7 JUMPI PUSH1 0x2 DUP2 PUSH1 0xFF AND DUP2 SLOAD DUP2 LT PUSH2 0x4D3 JUMPI INVALID JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 ADD PUSH1 0x0 ADD SLOAD SWAP2 POP DUP1 SWAP3 POP JUMPDEST DUP1 DUP1 PUSH1 0x1 ADD SWAP2 POP POP PUSH2 0x48E JUMP JUMPDEST POP POP SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO DUP1 PUSH2 0x5A1 JUMPI POP PUSH1 0x1 PUSH1 0x0 DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x1 ADD PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH1 0xFF AND JUMPDEST ISZERO PUSH2 0x5AB JUMPI PUSH2 0x5F3 JUMP JUMPDEST PUSH1 0x1 DUP1 PUSH1 0x0 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x0 ADD DUP2 SWAP1 SSTORE POP JUMPDEST POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x1 PUSH1 0x0 CALLER PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SWAP1 POP DUP1 PUSH1 0x1 ADD PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH1 0xFF AND DUP1 PUSH2 0x65E JUMPI POP PUSH1 0x2 DUP1 SLOAD SWAP1 POP DUP3 PUSH1 0xFF AND LT ISZERO JUMPDEST ISZERO PUSH2 0x669 JUMPI POP PUSH2 0x6D4 JUMP JUMPDEST PUSH1 0x1 DUP2 PUSH1 0x1 ADD PUSH1 0x0 PUSH2 0x100 EXP DUP2 SLOAD DUP2 PUSH1 0xFF MUL NOT AND SWAP1 DUP4 ISZERO ISZERO MUL OR SWAP1 SSTORE POP DUP2 DUP2 PUSH1 0x1 ADD PUSH1 0x1 PUSH2 0x100 EXP DUP2 SLOAD DUP2 PUSH1 0xFF MUL NOT AND SWAP1 DUP4 PUSH1 0xFF AND MUL OR SWAP1 SSTORE POP DUP1 PUSH1 0x0 ADD SLOAD PUSH1 0x2 DUP4 PUSH1 0xFF AND DUP2 SLOAD DUP2 LT PUSH2 0x6B8 JUMPI INVALID JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 ADD PUSH1 0x0 ADD PUSH1 0x0 DUP3 DUP3 SLOAD ADD SWAP3 POP POP DUP2 SWAP1 SSTORE POP POP JUMPDEST POP JUMP INVALID LOG2 PUSH6 0x627A7A723158 KECCAK256 GASLIMIT PUSH30 0x9494A1D1D64EBD9B931A6C692E671DC1F14D4A0C6600F7AA00FED360110 PUSH5 0x736F6C6343 STOP SDIV SIGNEXTEND STOP ORIGIN ", - "sourceMap": "33:2130:0:-;;;382:163;8:9:-1;5:2;;;30:1;27;20:12;5:2;382:163:0;;;;;;;;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;382:163:0;;;;;;;;;;;;;;;;446:10;432:11;;:24;;;;;;;;;;;;;;;;;;495:1;466:6;:19;473:11;;;;;;;;;;;466:19;;;;;;;;;;;;;;;:26;;:30;;;;525:13;506:32;;:9;:32;;;;;:::i;:::-;;382:163;33:2130;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;" - }, - "deployedBytecode": { - "linkReferences": {}, - "object": "608060405234801561001057600080fd5b506004361061004c5760003560e01c80635c19a95c14610051578063609ff1bd146100955780639e7b8d61146100b9578063b3f98adc146100fd575b600080fd5b6100936004803603602081101561006757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061012e565b005b61009d610481565b604051808260ff1660ff16815260200191505060405180910390f35b6100fb600480360360208110156100cf57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506104f9565b005b61012c6004803603602081101561011357600080fd5b81019080803560ff1690602001909291905050506105f6565b005b6000600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060010160009054906101000a900460ff161561018e575061047e565b5b600073ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160029054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141580156102bc57503373ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160029054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b1561032b57600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160029054906101000a900473ffffffffffffffffffffffffffffffffffffffff16915061018f565b3373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610365575061047e565b60018160010160006101000a81548160ff021916908315150217905550818160010160026101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060010160009054906101000a900460ff161561046457816000015460028260010160019054906101000a900460ff1660ff168154811061044557fe5b906000526020600020016000016000828254019250508190555061047b565b816000015481600001600082825401925050819055505b50505b50565b6000806000905060008090505b6002805490508160ff1610156104f4578160028260ff16815481106104af57fe5b906000526020600020016000015411156104e75760028160ff16815481106104d357fe5b906000526020600020016000015491508092505b808060010191505061048e565b505090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415806105a15750600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160009054906101000a900460ff165b156105ab576105f3565b60018060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001819055505b50565b6000600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060010160009054906101000a900460ff168061065e57506002805490508260ff1610155b1561066957506106d4565b60018160010160006101000a81548160ff021916908315150217905550818160010160016101000a81548160ff021916908360ff160217905550806000015460028360ff16815481106106b857fe5b9060005260206000200160000160008282540192505081905550505b5056fea265627a7a72315820457d09494a1d1d64ebd9b931a6c692e671dc1f14d4a0c6600f7aa00fed36011064736f6c634300050b0032", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x4C JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x5C19A95C EQ PUSH2 0x51 JUMPI DUP1 PUSH4 0x609FF1BD EQ PUSH2 0x95 JUMPI DUP1 PUSH4 0x9E7B8D61 EQ PUSH2 0xB9 JUMPI DUP1 PUSH4 0xB3F98ADC EQ PUSH2 0xFD JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x93 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x67 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x12E JUMP JUMPDEST STOP JUMPDEST PUSH2 0x9D PUSH2 0x481 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 PUSH1 0xFF AND PUSH1 0xFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0xFB PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0xCF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x4F9 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x12C PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x113 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD PUSH1 0xFF AND SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH2 0x5F6 JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 PUSH1 0x1 PUSH1 0x0 CALLER PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SWAP1 POP DUP1 PUSH1 0x1 ADD PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH1 0xFF AND ISZERO PUSH2 0x18E JUMPI POP PUSH2 0x47E JUMP JUMPDEST JUMPDEST PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH1 0x1 PUSH1 0x0 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x1 ADD PUSH1 0x2 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO DUP1 ISZERO PUSH2 0x2BC JUMPI POP CALLER PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH1 0x1 PUSH1 0x0 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x1 ADD PUSH1 0x2 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO JUMPDEST ISZERO PUSH2 0x32B JUMPI PUSH1 0x1 PUSH1 0x0 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x1 ADD PUSH1 0x2 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP2 POP PUSH2 0x18F JUMP JUMPDEST CALLER PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0x365 JUMPI POP PUSH2 0x47E JUMP JUMPDEST PUSH1 0x1 DUP2 PUSH1 0x1 ADD PUSH1 0x0 PUSH2 0x100 EXP DUP2 SLOAD DUP2 PUSH1 0xFF MUL NOT AND SWAP1 DUP4 ISZERO ISZERO MUL OR SWAP1 SSTORE POP DUP2 DUP2 PUSH1 0x1 ADD PUSH1 0x2 PUSH2 0x100 EXP DUP2 SLOAD DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF MUL NOT AND SWAP1 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND MUL OR SWAP1 SSTORE POP PUSH1 0x0 PUSH1 0x1 PUSH1 0x0 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SWAP1 POP DUP1 PUSH1 0x1 ADD PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH1 0xFF AND ISZERO PUSH2 0x464 JUMPI DUP2 PUSH1 0x0 ADD SLOAD PUSH1 0x2 DUP3 PUSH1 0x1 ADD PUSH1 0x1 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH1 0xFF AND PUSH1 0xFF AND DUP2 SLOAD DUP2 LT PUSH2 0x445 JUMPI INVALID JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 ADD PUSH1 0x0 ADD PUSH1 0x0 DUP3 DUP3 SLOAD ADD SWAP3 POP POP DUP2 SWAP1 SSTORE POP PUSH2 0x47B JUMP JUMPDEST DUP2 PUSH1 0x0 ADD SLOAD DUP2 PUSH1 0x0 ADD PUSH1 0x0 DUP3 DUP3 SLOAD ADD SWAP3 POP POP DUP2 SWAP1 SSTORE POP JUMPDEST POP POP JUMPDEST POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 SWAP1 POP PUSH1 0x0 DUP1 SWAP1 POP JUMPDEST PUSH1 0x2 DUP1 SLOAD SWAP1 POP DUP2 PUSH1 0xFF AND LT ISZERO PUSH2 0x4F4 JUMPI DUP2 PUSH1 0x2 DUP3 PUSH1 0xFF AND DUP2 SLOAD DUP2 LT PUSH2 0x4AF JUMPI INVALID JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 ADD PUSH1 0x0 ADD SLOAD GT ISZERO PUSH2 0x4E7 JUMPI PUSH1 0x2 DUP2 PUSH1 0xFF AND DUP2 SLOAD DUP2 LT PUSH2 0x4D3 JUMPI INVALID JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 ADD PUSH1 0x0 ADD SLOAD SWAP2 POP DUP1 SWAP3 POP JUMPDEST DUP1 DUP1 PUSH1 0x1 ADD SWAP2 POP POP PUSH2 0x48E JUMP JUMPDEST POP POP SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO DUP1 PUSH2 0x5A1 JUMPI POP PUSH1 0x1 PUSH1 0x0 DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x1 ADD PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH1 0xFF AND JUMPDEST ISZERO PUSH2 0x5AB JUMPI PUSH2 0x5F3 JUMP JUMPDEST PUSH1 0x1 DUP1 PUSH1 0x0 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 PUSH1 0x0 ADD DUP2 SWAP1 SSTORE POP JUMPDEST POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x1 PUSH1 0x0 CALLER PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 KECCAK256 SWAP1 POP DUP1 PUSH1 0x1 ADD PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH1 0xFF AND DUP1 PUSH2 0x65E JUMPI POP PUSH1 0x2 DUP1 SLOAD SWAP1 POP DUP3 PUSH1 0xFF AND LT ISZERO JUMPDEST ISZERO PUSH2 0x669 JUMPI POP PUSH2 0x6D4 JUMP JUMPDEST PUSH1 0x1 DUP2 PUSH1 0x1 ADD PUSH1 0x0 PUSH2 0x100 EXP DUP2 SLOAD DUP2 PUSH1 0xFF MUL NOT AND SWAP1 DUP4 ISZERO ISZERO MUL OR SWAP1 SSTORE POP DUP2 DUP2 PUSH1 0x1 ADD PUSH1 0x1 PUSH2 0x100 EXP DUP2 SLOAD DUP2 PUSH1 0xFF MUL NOT AND SWAP1 DUP4 PUSH1 0xFF AND MUL OR SWAP1 SSTORE POP DUP1 PUSH1 0x0 ADD SLOAD PUSH1 0x2 DUP4 PUSH1 0xFF AND DUP2 SLOAD DUP2 LT PUSH2 0x6B8 JUMPI INVALID JUMPDEST SWAP1 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 KECCAK256 ADD PUSH1 0x0 ADD PUSH1 0x0 DUP3 DUP3 SLOAD ADD SWAP3 POP POP DUP2 SWAP1 SSTORE POP POP JUMPDEST POP JUMP INVALID LOG2 PUSH6 0x627A7A723158 KECCAK256 GASLIMIT PUSH30 0x9494A1D1D64EBD9B931A6C692E671DC1F14D4A0C6600F7AA00FED360110 PUSH5 0x736F6C6343 STOP SDIV SIGNEXTEND STOP ORIGIN ", - "sourceMap": "33:2130:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;33:2130:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;872:577;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;872:577:0;;;;;;;;;;;;;;;;;;;:::i;:::-;;1801:360;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;655:164;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;655:164:0;;;;;;;;;;;;;;;;;;;:::i;:::-;;1509:286;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;1509:286:0;;;;;;;;;;;;;;;;;;;:::i;:::-;;872:577;919:20;942:6;:18;949:10;942:18;;;;;;;;;;;;;;;919:41;;995:6;:12;;;;;;;;;;;;991:25;;;1009:7;;;991:25;1025:115;1063:1;1032:33;;:6;:10;1039:2;1032:10;;;;;;;;;;;;;;;:19;;;;;;;;;;;;:33;;;;:70;;;;;1092:10;1069:33;;:6;:10;1076:2;1069:10;;;;;;;;;;;;;;;:19;;;;;;;;;;;;:33;;;;1032:70;1025:115;;;1121:6;:10;1128:2;1121:10;;;;;;;;;;;;;;;:19;;;;;;;;;;;;1116:24;;1025:115;;;1160:10;1154:16;;:2;:16;;;1150:29;;;1172:7;;;1150:29;1203:4;1188:6;:12;;;:19;;;;;;;;;;;;;;;;;;1235:2;1217:6;:15;;;:20;;;;;;;;;;;;;;;;;;1247:24;1274:6;:10;1281:2;1274:10;;;;;;;;;;;;;;;1247:37;;1298:10;:16;;;;;;;;;;;;1294:148;;;1368:6;:13;;;1328:9;1338:10;:15;;;;;;;;;;;;1328:26;;;;;;;;;;;;;;;;;:36;;;:53;;;;;;;;;;;1294:148;;;1429:6;:13;;;1408:10;:17;;;:34;;;;;;;;;;;1294:148;872:577;;;;:::o;1801:360::-;1849:22;1883:24;1910:1;1883:28;;1926:10;1939:1;1926:14;;1921:234;1949:9;:16;;;;1942:4;:23;;;1921:234;;;2019:16;1991:9;2001:4;1991:15;;;;;;;;;;;;;;;;;:25;;;:44;1987:168;;;2074:9;2084:4;2074:15;;;;;;;;;;;;;;;;;:25;;;2055:44;;2136:4;2117:23;;1987:168;1967:6;;;;;;;1921:234;;;;1801:360;;:::o;655:164::-;732:11;;;;;;;;;;;718:25;;:10;:25;;;;:50;;;;747:6;:15;754:7;747:15;;;;;;;;;;;;;;;:21;;;;;;;;;;;;718:50;714:63;;;770:7;;714:63;811:1;786:6;:15;793:7;786:15;;;;;;;;;;;;;;;:22;;:26;;;;655:164;;:::o;1509:286::-;1558:20;1581:6;:18;1588:10;1581:18;;;;;;;;;;;;;;;1558:41;;1613:6;:12;;;;;;;;;;;;:46;;;;1643:9;:16;;;;1629:10;:30;;;;1613:46;1609:59;;;1661:7;;;1609:59;1692:4;1677:6;:12;;;:19;;;;;;;;;;;;;;;;;;1720:10;1706:6;:11;;;:24;;;;;;;;;;;;;;;;;;1775:6;:13;;;1740:9;1750:10;1740:21;;;;;;;;;;;;;;;;;:31;;;:48;;;;;;;;;;;1509:286;;;:::o" - }, - "gasEstimates": { - "creation": { - "codeDepositCost": "360800", - "executionCost": "infinite", - "totalCost": "infinite" - }, - "external": { - "delegate(address)": "infinite", - "giveRightToVote(address)": "20997", - "vote(uint8)": "62215", - "winningProposal()": "infinite" - } - }, - "methodIdentifiers": { - "delegate(address)": "5c19a95c", - "giveRightToVote(address)": "9e7b8d61", - "vote(uint8)": "b3f98adc", - "winningProposal()": "609ff1bd" - } - }, - "abi": [ - { - "constant": false, - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "delegate", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "winningProposal", - "outputs": [ - { - "internalType": "uint8", - "name": "_winningProposal", - "type": "uint8" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "internalType": "address", - "name": "toVoter", - "type": "address" - } - ], - "name": "giveRightToVote", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "internalType": "uint8", - "name": "toProposal", - "type": "uint8" - } - ], - "name": "vote", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "_numProposals", - "type": "uint8" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "constructor" - } - ] - -} -``` diff --git a/apps/remix-ide/docs/create_deploy.md b/apps/remix-ide/docs/create_deploy.md deleted file mode 100644 index 6934c71998..0000000000 --- a/apps/remix-ide/docs/create_deploy.md +++ /dev/null @@ -1,107 +0,0 @@ -Creating and Deploying a Contract -================================ - -There are 3 type of environments Remix can be plugged to: -`Javascript VM`, `Injected provider`, or `Web3 provider`. (for details see [Running transactions](https://remix-ide.readthedocs.io/en/latest/run.html)) - -Both `Web3 provider` and `Injected provider` require the use of an -external tool. - -The external tool for `Web3 provider` is an Ethereum node and for -`Injected provider` Metamask. - -The `JavaScript VM` mode is convenient because each execution runs in -your browser and you don't need any other software or Ethereum node to run it. - -So, it is the easiest test environment - **no setup required!** - -But keep in mind that reloading the browser when you are in the Javascript VM will restart Remix in an empty state. - -For performance purposes ( which is to say - for testing in an environment that is closest to the mainnet), it might also be better to use an external node. - -Selecting the VM mode ---------------------- - -Make sure the VM mode is selected. All accounts displayed in `Accounts` -should have 100 ether. - -Sample contract ---------------- - -``` -pragma solidity ^0.5.1; - -contract testContract { - - uint value; - - constructor (uint _p) public { - value = _p; - } - - function setP(uint _n) payable public { - value = _n; - } - - function setNP(uint _n) public { - value = _n; - } - - function get () view public returns (uint) { - return value; - } -} - -``` - -This contract is very basic. The goal is to quickly start to create and -to interact with a sample contract. - -Deploying an instance ---------------------- - -The `Compile tab` displays information related to the current contract -(note that there can be more than one) ([see compile](compile.html)). - -Moving on, in the `Run tab` select, `JavaScript VM` to specify that you -are going to deploy an instance of the contract in the `JavaScript VM` -state. - -![](images/a-jvm.png) - -The constructor of `Ballot.sol` needs a parameter (of type `uint8`). -Give any value and click on `Deploy`. - -The transaction which deploys the instance of `Ballot` is created. - -In a "normal" blockchain, it can take several seconds to execute. This -is the time for the transaction to be mined. However, because we are -using the `JavaScript VM`, our execution is immediate. - -The terminal will inform you about the transaction. You can see details -there and start debugging. - -The newly created instance is displayed in the `run tab`. - -![](images/a-jvm-instance.png) - -Interacting with an instance ----------------------------- - -This new instance contains 3 actions which corresponds to the 3 -functions (`setP`, `setPN`, `get`). Clicking on `SetP` or `SetPN` will -create a new transaction. - -Note that `SetP` is `payable` (red button) : it is possible to send -value (Ether) to the contract. - -`SetPN` is not payable (orange button - depending on the theme) : it is not possible to send -value (Ether) to the contract. - -Clicking on `get` will not execute a transaction (usually its a blue button - depending on the theme). It doesn't execute a transaction because a `get` does not modify the state (variable -`value`) of this instance. - -As `get` is `view` you can see the return value just below the -action. - -![](images/a-jvm-calling-instance.png) diff --git a/apps/remix-ide/docs/debugger.md b/apps/remix-ide/docs/debugger.md deleted file mode 100644 index 456e9ba45a..0000000000 --- a/apps/remix-ide/docs/debugger.md +++ /dev/null @@ -1,14 +0,0 @@ -Debugger -======== - -This module allows you to debug the transaction. It can be used to -deploy transactions created from Remix and already mined transactions. -(debugging works only if the current environment provides the necessary -features). - -To get to the debugger - you can click the debug button in the terminal when a successful or failed transaction appears there. You can also load the module from the plugin manager and then click the bug in the icon panel. Or you can get to the debugger by running the debug command in the console. - - -![](images/a-debugger.png) - -To learn more about how to use this tool go to the [debugger tutorial](tutorial_debug.html). diff --git a/apps/remix-ide/docs/file_explorer.md b/apps/remix-ide/docs/file_explorer.md deleted file mode 100644 index 008b044307..0000000000 --- a/apps/remix-ide/docs/file_explorer.md +++ /dev/null @@ -1,59 +0,0 @@ -File Explorers -============= - -To get to the File Explorers module - click the file explorers icon. - -![](images/a-file-explorer1.png) - -The basic files explorer lists all the files stored in your browser's **browser storage**. -You can see them in the **browser** folder. - -**Important Note:** Clearing the browser storage will **permanently delete** all the -solidity files stored there. This is an inherent limitation of a browser-based IDE. However, if you want to store files outside of the browser and on your computer's filesystem, use [Remixd](remixd.html) or use the [desktop version of Remix-IDE](https://github.com/ethereum/remix-desktop/releases/). RemixD enables you to have access to a selected folder on your hard drive. Remix Desktop is a version of Remix-IDE in an Electron app. - -You can rename, remove or -add new files to the file explorer. - -![](images/a-file-explorer-buttons.png) - -We will start by reviewing the icons in the image above. - -The book icon - **A.** is the link to the module's documentation. - -The icons to the right of the **browser** file explorer in the image above only appear for browser storage. - -Create new File ---------------- - -The icon marked **B.** above. Creates a new file. - -Publish to Gist ---------------- - -The icon marked **C.** above. Publishes all files from the browser folder to a gist. Only file in the root of **browser** will be published. Files in subfolders will not be publish to the Gist. -Gist API has changed in 2018 and **requires** users to be authenticated to be able to publish a gist. - -Click [this link](https://github.com/settings/tokens) to GitHub tokens setup and select Generate new token. Then check the **Create gists** checkbox and generate a new token. - -Take the token and paste it in Remix's **Settings** module in the **GitHub Access Token** section. And then click Save. Now you should be able to use the feature. - -Create a folder ---------------- - -The icon marked **D.** above. Creates a new folder in **browser** file explorer. - -Context Menu (Right Click) ------------------------------ -Right click on a file or a folder and the **context menu** will appear. - -![](images/a-file-ex-rt-click.png) - -You can rename or delete a selected file or a folder. You can also create a folder. - -To create a file with the context menu, right click on a folder to get the **Create File** option. A file will be created inside that folder. - -![](images/a-file-ex-rt-click-folder.png) - -The functionality of the context menu also works with RemixD (which gives you have access to a folder on your hard drive). - -**Note:** When working with RemixD, you need to open and close the **localhost** folder to refresh the view. diff --git a/apps/remix-ide/docs/images/a-Runtab-deploy-atAddress.png b/apps/remix-ide/docs/images/a-Runtab-deploy-atAddress.png deleted file mode 100644 index 89d3e77ef6..0000000000 Binary files a/apps/remix-ide/docs/images/a-Runtab-deploy-atAddress.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-contract-inputs.png b/apps/remix-ide/docs/images/a-contract-inputs.png deleted file mode 100644 index abf2a1aeae..0000000000 Binary files a/apps/remix-ide/docs/images/a-contract-inputs.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-debug1-deploy.png b/apps/remix-ide/docs/images/a-debug1-deploy.png deleted file mode 100644 index f2dedaf456..0000000000 Binary files a/apps/remix-ide/docs/images/a-debug1-deploy.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-debug2-udapp1.png b/apps/remix-ide/docs/images/a-debug2-udapp1.png deleted file mode 100644 index e2f35b3b56..0000000000 Binary files a/apps/remix-ide/docs/images/a-debug2-udapp1.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-debug2-udapp1a.png b/apps/remix-ide/docs/images/a-debug2-udapp1a.png deleted file mode 100644 index 0b57f61709..0000000000 Binary files a/apps/remix-ide/docs/images/a-debug2-udapp1a.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-debug3-udapp2.png b/apps/remix-ide/docs/images/a-debug3-udapp2.png deleted file mode 100644 index 56ae6a0dc7..0000000000 Binary files a/apps/remix-ide/docs/images/a-debug3-udapp2.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-debug4-value-loc.png b/apps/remix-ide/docs/images/a-debug4-value-loc.png deleted file mode 100644 index 61cdcab9ac..0000000000 Binary files a/apps/remix-ide/docs/images/a-debug4-value-loc.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-debug5-term-debug-but.png b/apps/remix-ide/docs/images/a-debug5-term-debug-but.png deleted file mode 100644 index 96bf3ca56e..0000000000 Binary files a/apps/remix-ide/docs/images/a-debug5-term-debug-but.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-debug6-term-txn-hash.png b/apps/remix-ide/docs/images/a-debug6-term-txn-hash.png deleted file mode 100644 index f7553d3cfc..0000000000 Binary files a/apps/remix-ide/docs/images/a-debug6-term-txn-hash.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-debug7-debugger.png b/apps/remix-ide/docs/images/a-debug7-debugger.png deleted file mode 100644 index 59fe56538d..0000000000 Binary files a/apps/remix-ide/docs/images/a-debug7-debugger.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-debug8-top3.png b/apps/remix-ide/docs/images/a-debug8-top3.png deleted file mode 100644 index c1b1166e99..0000000000 Binary files a/apps/remix-ide/docs/images/a-debug8-top3.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-debug9-buttons.png b/apps/remix-ide/docs/images/a-debug9-buttons.png deleted file mode 100644 index 951cf59006..0000000000 Binary files a/apps/remix-ide/docs/images/a-debug9-buttons.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-debugger.png b/apps/remix-ide/docs/images/a-debugger.png deleted file mode 100644 index 2756ab6c47..0000000000 Binary files a/apps/remix-ide/docs/images/a-debugger.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-file-ex-rt-click-folder.png b/apps/remix-ide/docs/images/a-file-ex-rt-click-folder.png deleted file mode 100644 index 501bea2c18..0000000000 Binary files a/apps/remix-ide/docs/images/a-file-ex-rt-click-folder.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-file-ex-rt-click.png b/apps/remix-ide/docs/images/a-file-ex-rt-click.png deleted file mode 100644 index 122b1ead45..0000000000 Binary files a/apps/remix-ide/docs/images/a-file-ex-rt-click.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-file-explorer-buttons-big.png b/apps/remix-ide/docs/images/a-file-explorer-buttons-big.png deleted file mode 100644 index 5f16de4d01..0000000000 Binary files a/apps/remix-ide/docs/images/a-file-explorer-buttons-big.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-file-explorer-buttons.png b/apps/remix-ide/docs/images/a-file-explorer-buttons.png deleted file mode 100644 index a7be0bb5a1..0000000000 Binary files a/apps/remix-ide/docs/images/a-file-explorer-buttons.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-file-explorer1.png b/apps/remix-ide/docs/images/a-file-explorer1.png deleted file mode 100644 index 336fbdfdb5..0000000000 Binary files a/apps/remix-ide/docs/images/a-file-explorer1.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-home-page.png b/apps/remix-ide/docs/images/a-home-page.png deleted file mode 100644 index f4ca8b0537..0000000000 Binary files a/apps/remix-ide/docs/images/a-home-page.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-hometab.png b/apps/remix-ide/docs/images/a-hometab.png deleted file mode 100644 index a48d9f61c0..0000000000 Binary files a/apps/remix-ide/docs/images/a-hometab.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-icon-swap.png b/apps/remix-ide/docs/images/a-icon-swap.png deleted file mode 100644 index 53cf741bd1..0000000000 Binary files a/apps/remix-ide/docs/images/a-icon-swap.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-icons-at-load.png b/apps/remix-ide/docs/images/a-icons-at-load.png deleted file mode 100644 index ce859729ed..0000000000 Binary files a/apps/remix-ide/docs/images/a-icons-at-load.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-jvm-calling-instance.png b/apps/remix-ide/docs/images/a-jvm-calling-instance.png deleted file mode 100644 index f12dcce662..0000000000 Binary files a/apps/remix-ide/docs/images/a-jvm-calling-instance.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-jvm-instance.png b/apps/remix-ide/docs/images/a-jvm-instance.png deleted file mode 100644 index 5ed6615c9d..0000000000 Binary files a/apps/remix-ide/docs/images/a-jvm-instance.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-jvm.png b/apps/remix-ide/docs/images/a-jvm.png deleted file mode 100644 index 851236b457..0000000000 Binary files a/apps/remix-ide/docs/images/a-jvm.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-layout1.png b/apps/remix-ide/docs/images/a-layout1.png deleted file mode 100644 index bb8ebbeda0..0000000000 Binary files a/apps/remix-ide/docs/images/a-layout1.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-layout1c.png b/apps/remix-ide/docs/images/a-layout1c.png deleted file mode 100644 index cba77e4ded..0000000000 Binary files a/apps/remix-ide/docs/images/a-layout1c.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-old-tuto_basicimport.png b/apps/remix-ide/docs/images/a-old-tuto_basicimport.png deleted file mode 100644 index 81a8009336..0000000000 Binary files a/apps/remix-ide/docs/images/a-old-tuto_basicimport.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-old-tuto_importgit.png b/apps/remix-ide/docs/images/a-old-tuto_importgit.png deleted file mode 100644 index 022eb4b011..0000000000 Binary files a/apps/remix-ide/docs/images/a-old-tuto_importgit.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-old-tuto_importswarm.png b/apps/remix-ide/docs/images/a-old-tuto_importswarm.png deleted file mode 100644 index 01fba3e646..0000000000 Binary files a/apps/remix-ide/docs/images/a-old-tuto_importswarm.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-plug.png b/apps/remix-ide/docs/images/a-plug.png deleted file mode 100644 index cde70b2d92..0000000000 Binary files a/apps/remix-ide/docs/images/a-plug.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-plugin-man-local.png b/apps/remix-ide/docs/images/a-plugin-man-local.png deleted file mode 100644 index b760bab001..0000000000 Binary files a/apps/remix-ide/docs/images/a-plugin-man-local.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-receive-fun.png b/apps/remix-ide/docs/images/a-receive-fun.png deleted file mode 100644 index 556bc2806f..0000000000 Binary files a/apps/remix-ide/docs/images/a-receive-fun.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-remixd-success.png b/apps/remix-ide/docs/images/a-remixd-success.png deleted file mode 100644 index bef13de555..0000000000 Binary files a/apps/remix-ide/docs/images/a-remixd-success.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-run-icon.png b/apps/remix-ide/docs/images/a-run-icon.png deleted file mode 100644 index 4aad1a9f0b..0000000000 Binary files a/apps/remix-ide/docs/images/a-run-icon.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-runtab-recorder.png b/apps/remix-ide/docs/images/a-runtab-recorder.png deleted file mode 100644 index 36d6b0528b..0000000000 Binary files a/apps/remix-ide/docs/images/a-runtab-recorder.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-runtab1a.png b/apps/remix-ide/docs/images/a-runtab1a.png deleted file mode 100644 index 2206479ca6..0000000000 Binary files a/apps/remix-ide/docs/images/a-runtab1a.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-sol-compiler.png b/apps/remix-ide/docs/images/a-sol-compiler.png deleted file mode 100644 index ad470ec8e1..0000000000 Binary files a/apps/remix-ide/docs/images/a-sol-compiler.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-sol-editor.png b/apps/remix-ide/docs/images/a-sol-editor.png deleted file mode 100644 index b6c0cd5c58..0000000000 Binary files a/apps/remix-ide/docs/images/a-sol-editor.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-static-analysis.png b/apps/remix-ide/docs/images/a-static-analysis.png deleted file mode 100644 index f204c3128d..0000000000 Binary files a/apps/remix-ide/docs/images/a-static-analysis.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-terminal-and-more.png b/apps/remix-ide/docs/images/a-terminal-and-more.png deleted file mode 100644 index 45d41644ca..0000000000 Binary files a/apps/remix-ide/docs/images/a-terminal-and-more.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-themes.png b/apps/remix-ide/docs/images/a-themes.png deleted file mode 100644 index bc48776de1..0000000000 Binary files a/apps/remix-ide/docs/images/a-themes.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-udapp-inputs.png b/apps/remix-ide/docs/images/a-udapp-inputs.png deleted file mode 100644 index ec68350135..0000000000 Binary files a/apps/remix-ide/docs/images/a-udapp-inputs.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-udapp-multi-param-man.png b/apps/remix-ide/docs/images/a-udapp-multi-param-man.png deleted file mode 100644 index afb7e4f3a8..0000000000 Binary files a/apps/remix-ide/docs/images/a-udapp-multi-param-man.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-udapp1.png b/apps/remix-ide/docs/images/a-udapp1.png deleted file mode 100644 index d6aa53add7..0000000000 Binary files a/apps/remix-ide/docs/images/a-udapp1.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-udapp2.png b/apps/remix-ide/docs/images/a-udapp2.png deleted file mode 100644 index 8a5a74aefe..0000000000 Binary files a/apps/remix-ide/docs/images/a-udapp2.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-unit-testing-custom-compiler-config.png b/apps/remix-ide/docs/images/a-unit-testing-custom-compiler-config.png deleted file mode 100644 index 8e3719c284..0000000000 Binary files a/apps/remix-ide/docs/images/a-unit-testing-custom-compiler-config.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-unit-testing-feature.png b/apps/remix-ide/docs/images/a-unit-testing-feature.png deleted file mode 100644 index 9047c15f14..0000000000 Binary files a/apps/remix-ide/docs/images/a-unit-testing-feature.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-unit-testing-from-pm.png b/apps/remix-ide/docs/images/a-unit-testing-from-pm.png deleted file mode 100644 index 80f70e51b7..0000000000 Binary files a/apps/remix-ide/docs/images/a-unit-testing-from-pm.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-unit-testing-run-result.png b/apps/remix-ide/docs/images/a-unit-testing-run-result.png deleted file mode 100644 index 911599e990..0000000000 Binary files a/apps/remix-ide/docs/images/a-unit-testing-run-result.png and /dev/null differ diff --git a/apps/remix-ide/docs/images/a-user-testing-icon.png b/apps/remix-ide/docs/images/a-user-testing-icon.png deleted file mode 100644 index 53db354e77..0000000000 Binary files a/apps/remix-ide/docs/images/a-user-testing-icon.png and /dev/null differ diff --git a/apps/remix-ide/docs/import.md b/apps/remix-ide/docs/import.md deleted file mode 100644 index 333a710185..0000000000 --- a/apps/remix-ide/docs/import.md +++ /dev/null @@ -1,74 +0,0 @@ -Importing Source Files in Solidity -================================== - -There are multiple techniques for importing files into Remix. - -For a tutorial about importing files click [here](https://github.com/ethereum/remix-workshops/tree/master/LoadingContent). You can also find this tutorial in the Remix Workshops plugin. - -For a detailed explanation of the `import` keyword see the -[Solidity documentation](https://solidity.readthedocs.io/en/develop/layout-of-source-files.html?highlight=import#importing-other-source-files) - -Here are a some of the main methods of importing a file: - -Importing a file from the browser's local storage -------------------------------------------------- - -Files in Remix can be imported with the `import` key word with the path to the file. Use ```./``` for relative paths to increase portability. -``` -pragma solidity >=0.4.22 <0.6.0; - -import "./ballot.sol"; -``` - - -Importing a file from your computer's filesystem -------------------------------------------------- - -This method uses **remixd** - the remix daemon. Please go to the [remixd tutorial](remixd.html) for instructions about how to bridge the divide between the browser and your computers filesystem. - - -Importing from GitHub ---------------------- - -It is possible to import files directly from GitHub. You should specify the release tag (where available), otherwise you will get the latest code in the master branch. For OpenZeppelin Contracts you should only use code published in an official release, the example below imports from OpenZeppelin Contracts v2.5.0. - -``` -pragma solidity >=0.4.22 <0.6.0; - -import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.0/contracts/math/SafeMath.sol"; - -``` - -Importing from Swarm --------------------- - -Files can be imported using all URLs supported by swarm. -If you do not have a swarm node, then use swarm-gateways.net. - -``` -import 'bzz-raw://5766400e5d6d822f2029b827331b354c41e0b61f73440851dd0d06f603dd91e5'; -``` - -Importing from IPFS --------------------- - -Files can be imported from IPFS. - -``` -import 'ipfs://Qmdyq9ZmWcaryd1mgGZ4PttRNctLGUSAMpPqufsk6uRMKh'; -``` - -Importing from the console --------------------------- - -You can also use a remix command remix.loadurl('')in the console. You should specify the release tag (where available), otherwise you will get the latest code in the master branch. For OpenZeppelin Contracts you should only use code published in an official release, the example below imports from OpenZeppelin Contracts v2.5.0. - -``` -remix.loadurl('https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.0/contracts/math/SafeMath.sol') -``` - -Notice that this will create a `github` folder in the file explorer. To load a file in the `github` folder, you would use a command like this: - -``` -import "github/OpenZeppelin/openzeppelin-contracts/contracts/math/SafeMath.sol"; -``` diff --git a/apps/remix-ide/docs/index.rst b/apps/remix-ide/docs/index.rst deleted file mode 100644 index eb8488799e..0000000000 --- a/apps/remix-ide/docs/index.rst +++ /dev/null @@ -1,83 +0,0 @@ -Welcome to Remix documentation! -=============================== - -Remix is a powerful, open source tool that helps you write Solidity contracts straight from the browser. -Written in JavaScript, Remix supports both usage in the browser and locally. - -Remix also supports testing, debugging and deploying of smart contracts and much more. - -Our Remix project with all its features is available -at `remix.ethereum.org `__ and more information can be found in these -docs. Our IDE tool is available at `our GitHub repository -`__. - -This set of documents covers instructions on how to use Remix and some tutorials to help you get started. - -Useful links: - -- `Solidity documentation `__ - -- `Remix alpha `__ - The version where we test new Remix release (not stable!). - -- `Remix on Medium `__ - -- `Ethereum StackExchange for Remix `__ - -- `Community support channel `__ - -- `Ðapp Developer resources (Ethereum wiki) `__ - -.. toctree:: - :maxdepth: 2 - :caption: New Layout Intro - - layout - -.. toctree:: - :maxdepth: 2 - :caption: Tour of default modules - - file_explorer - plugin_manager - settings - solidity_editor - terminal - -.. toctree:: - :maxdepth: 2 - :caption: Tour of typical solidity modules - - compile - run - udapp - debugger - static_analysis - -.. toctree:: - :maxdepth: 2 - :caption: Solidity Unit Testing - - unittesting - assert_library - unittesting_examples - -.. toctree:: - :maxdepth: 2 - :caption: Using Remix - - contract_metadata - create_deploy - tutorial_debug - import - remix_commands - remixd - FAQ - -.. toctree:: - :maxdepth: 2 - :caption: Miscellaneous - - locations - remix_tutorials_github - code_contribution_guide - community diff --git a/apps/remix-ide/docs/layout.md b/apps/remix-ide/docs/layout.md deleted file mode 100644 index 722065e59c..0000000000 --- a/apps/remix-ide/docs/layout.md +++ /dev/null @@ -1,54 +0,0 @@ -Remix-IDE Layout -============== - -The new structure --------------------- -![](images/a-layout1c.png) - -1. Icon Panel - click to change which plugin appears in the Side Panel -2. Side Panel - Most but not all plugins will have their GUI here. -3. Main Panel - In the old layout this was just for editing files. In the tabs can be plugins or files for the IDE to compile. -4. Terminal - where you will see the results of your interactions with the GUI's. Also you can run scripts here. - -Icon Panel at Page Load ------------------------ -When you load remix - the icon panel show these icons by default. - -![](images/a-icons-at-load.png) - -Everything in remix is now a plugin... so the **[Plugin Manager](#plugin-manager)** is very important. -In the old layout, each basic task in remix was separated into the tabs. Now these tabs are plugins. - -But to activate a half a dozen plugins - (or however many you are using) each time the page load is **tedious**. So learn about the **[Environments](#environments)**. - -Homepage --------- - -![](images/a-hometab.png) - -The homepage is located in a tab in the Main Panel. - -You can also get there by clicking the remix logo at the top of the icon panel. - -### Environments -Clicking on one of the environment buttons loads up a collection of plugins. We currently have a **Solidity** Button and a **Vyper** button. In the future you will be able to save your own environment. - -To see all the plugins go to the **plugin manager** - by selecting the plug in the icon panel. -![](images/a-plug.png) - -The environment buttons are time & sanity savers - so you don't need to go to the plugin manager to get started everytime you load the page. - - -Plugin Manager ---------------- - -In order to make Remix flexible for integrating changes into its functionality and for integrating remix into other projects (your's for example), we've now made everything a plugin. This means that you only load the functionality you need. It also means that you need a place to turn off and on plugins - as your needs change. This all happens in the plug manager. - -The Plugin Manager is also the place you go when you are creating your own plugin and you want to load your local plugin into Remix. In that case you'd click on the "Connect to a Local Plugin" link at the top of the Plugin Manager panel. - -Themes ---------------- - -So you want to work on Remix with a dark theme or a gray theme or just a different theme that the one you are currently looking at? Go to the settings tab and at the bottom is a choice of lots of bootstrap based themes. - -![](images/a-themes.png) diff --git a/apps/remix-ide/docs/locations.md b/apps/remix-ide/docs/locations.md deleted file mode 100644 index ae806e3c0e..0000000000 --- a/apps/remix-ide/docs/locations.md +++ /dev/null @@ -1,14 +0,0 @@ -Finding Remix -============= - -So if you've found the documentation to Remix but don't know where to find Remix or if you want to run the remix-ide locally and want to find out where to download it - this page is here to help. - -- An online version is available at [https://remix.ethereum.org](https://remix.ethereum.org). This version is stable and is updated at almost every release. -- An alpha online version is available at [https://remix-alpha.ethereum.org](https://remix-alpha.ethereum.org). This is not a stable version. -- npm `remix-ide` package `yarn global add remix-ide`. `remix-ide` create a new instance of `Remix IDE` available at [http://127.0.0.1:8080](http://127.0.0.1:8080) and make the current folder available to Remix IDE by automatically starting `remixd`. -see [Connection to `remixd`](https://remix-ide.readthedocs.io/en/latest/remixd.html) for more information about sharing local file with `Remix IDE`. - -- GitHub release: [https://github.com/ethereum/remix-ide/releases](https://github.com/ethereum/remix-ide/releases) . The source code is packaged at every release but still need to be built using `npm run build`. - -- GitHub release: [https://github.com/ethereum/remix-ide/releases](https://github.com/ethereum/remix-ide/releases) . The source code is packaged at every release but still need to be built using `yarn run build`. - diff --git a/apps/remix-ide/docs/make.bat b/apps/remix-ide/docs/make.bat deleted file mode 100755 index 963594cac0..0000000000 --- a/apps/remix-ide/docs/make.bat +++ /dev/null @@ -1,263 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=_build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . -set I18NSPHINXOPTS=%SPHINXOPTS% . -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. xml to make Docutils-native XML files - echo. pseudoxml to make pseudoxml-XML files for display purposes - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - echo. coverage to run coverage check of the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - - -REM Check if sphinx-build is available and fallback to Python version if any -%SPHINXBUILD% 1>NUL 2>NUL -if errorlevel 9009 goto sphinx_python -goto sphinx_ok - -:sphinx_python - -set SPHINXBUILD=python -m sphinx.__init__ -%SPHINXBUILD% 2> nul -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -:sphinx_ok - - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Remix.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Remix.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdf" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf - cd %~dp0 - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdfja" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf-ja - cd %~dp0 - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -if "%1" == "coverage" ( - %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage - if errorlevel 1 exit /b 1 - echo. - echo.Testing of coverage in the sources finished, look at the ^ -results in %BUILDDIR%/coverage/python.txt. - goto end -) - -if "%1" == "xml" ( - %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The XML files are in %BUILDDIR%/xml. - goto end -) - -if "%1" == "pseudoxml" ( - %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. - goto end -) - -:end diff --git a/apps/remix-ide/docs/plugin_manager.md b/apps/remix-ide/docs/plugin_manager.md deleted file mode 100644 index 9a5e8d8ead..0000000000 --- a/apps/remix-ide/docs/plugin_manager.md +++ /dev/null @@ -1,22 +0,0 @@ -Plugin Manager -=================== - -## Everything is a PLUGIN in Remix - -In order to integrate new tools made by us and by ...you into Remix, we've now made everything a plugin. -This architecture will also allow Remix or just parts of Remix to be integrated into other projects (your's for example). - -This means that you only load the functionality you need. - -It also means that you can turn off and on plugins - as your needs change. - -This all happens in the plug manager. - -The Plugin Manager is also the place you go when you are creating your own plugin and you want to load your local plugin into Remix. - -To load your local plugin, you'd click on the "Connect to a Local Plugin" link at the top of the Plugin Manager panel. - -![](images/a-plugin-man-local.png) - -To learn more about how to create your own plugin, go to -[the README of remix-plugin repo](https://github.com/ethereum/remix-plugin). diff --git a/apps/remix-ide/docs/remix_commands.md b/apps/remix-ide/docs/remix_commands.md deleted file mode 100644 index 78ddd0758a..0000000000 --- a/apps/remix-ide/docs/remix_commands.md +++ /dev/null @@ -1,93 +0,0 @@ -Remix Commands -============== - -In the console, you can run the commands listed below. Once you start to type a command, there is *auto completion*. These commands are using the following libraries: - -+ *ethers*: The [ethers.js](https://docs.ethers.io/ethers.js/html/getting-started.html) library is a compact and complete JavaScript library for Ethereum. - -+ *remix*: Ethereum IDE and tools for the web. - -+ *web3*: The [web3.js](https://web3js.readthedocs.io/en/1.0/) library is a collection of modules which contain specific functionality for the ethereum ecosystem. - -+ *swarmgw*: This library can be used to upload/download files to Swarm via https://swarm-gateways.net/. - -#### Here's the list of commands -**remix.debug(hash)**: Start debugging a transaction. - -**remix.debugHelp()**: Display help message for debugging - -**remix.execute(filepath)**: Run the script specified by file path. If filepath is empty, script currently displayed in the editor is executed. - -**remix.exeCurrent()**: Run the script currently displayed in the editor. - -**remix.getFile(path)**: Returns the content of the file located at the given path - -**remix.help()**: Display this help message. - -**remix.loadgist(id)**: Load a gist in the file explorer. - -**remix.loadurl(url)**: Load the given url in the file explorer. The url can be of type github, swarm or ipfs. - -**remix.setFile(path, content)**: set the content of the file located at the given path - -**remix.setproviderurl(url)**: Change the current provider to Web3 provider and set the url endpoint. - -**swarmgw.get(url, cb)**: Download files from Swarm via https**://swarm-gateways.net/ - -**swarmgw.put(content, cb)**: Upload files to Swarm via https**://swarm-gateways.net/ - -**ethers.Contract**: This API provides a graceful connection to a contract deployed on the blockchain, simplifying calling and querying its functions and handling all the binary protocol and conversion as necessarily. - -**ethers.HDNode**: A Hierarchical Deterministic Wallet represents a large tree of private keys which can reliably be reproduced from an initial seed. - -**ethers.Interface**: The Interface Object is a meta-class that accepts a Solidity (or compatible) Application Binary Interface (ABI) and populates functions to deal with encoding and decoding the parameters to pass in and results returned. - -**ethers.providers**: A Provider abstracts a connection to the Ethereum blockchain, for issuing queries and sending state changing transactions. - -**ethers.SigningKey**: The SigningKey interface provides an abstraction around the secp256k1 elliptic curve cryptography library. - -**ethers.utils**: The utility functions exposed in both the ethers umbrella package and the ethers-utils. - -**ethers.utils.AbiCoder**: Create a new ABI Coder object - -**ethers.utils.RLP**: This encoding method is used internally for several aspects of Ethereum, such as encoding transactions and determining contract addresses. - -**ethers.Wallet**: A wallet manages a private/public key pair which is used to cryptographically sign transactions and prove ownership on the Ethereum network. - -**ethers.version**: Contains the version of the ethers container object. - -**web3.bzz**: Bzz module for interacting with the swarm network. - -**web3.eth**: Eth module for interacting with the Ethereum network. - -**web3.eth.accounts**: The web3.eth.accounts contains functions to generate Ethereum accounts and sign transactions and data. - -**web3.eth.abi**: The web3.eth.abi functions let you de- and encode parameters to ABI (Application Binary Interface) for function calls to the EVM (Ethereum Virtual Machine). - -**web3.eth.ens**: The web3.eth.ens functions let you interacting with ENS. - -**web3.eth.Iban**: The web3.eth.Iban function lets convert Ethereum addresses from and to IBAN and BBAN. - -**web3.eth.net**: Net module for interacting with network properties. - -**web3.eth.personal**: Personal module for interacting with the Ethereum accounts. - -**web3.eth.subscribe**: The web3.eth.subscribe function lets you subscribe to specific events in the blockchain. - -**web3.givenProvider**: When using web3.js in an Ethereum compatible browser, it will set with the current native provider by that browser. Will return the given provider by the (browser) environment, otherwise null. - -**web3.modules**: Contains the version of the web3 container object. - -**web3.providers**: Contains the current available providers. - -**web3.shh**: Shh module for interacting with the whisper protocol - -**web3.utils**: This package provides utility functions for Ethereum dapps and other **web3.js packages. - -**web3.version**: Contains the version of the web3 container object. - -**web3.eth.clearSubscriptions();**: Resets subscriptions. - -**web3.eth.Contract(jsonInterface[, address][, options])**: The **web3.eth.Contract object makes it easy to interact with smart contracts on the ethereum blockchain. - -**web3.eth.accounts.create([entropy]);**: The web3.eth.accounts contains functions to generate Ethereum accounts and sign transactions and data. diff --git a/apps/remix-ide/docs/remix_tutorials_github.md b/apps/remix-ide/docs/remix_tutorials_github.md deleted file mode 100644 index 1bb31de1e1..0000000000 --- a/apps/remix-ide/docs/remix_tutorials_github.md +++ /dev/null @@ -1,37 +0,0 @@ -Remix GitHub Tutorials -======================= - -There are a series of tutorials in our github repo [remix-workshops](https://github.com/ethereum/remix-workshops). - -We are in the process of upgrading these tutorials to use the new Remix layout. - -In this repo there tutorials for all levels. - -There are tutorials for specific remix functionalities like: - -***Deploying*** - - Multiple ways of loading files in Remix - Deploying with libraries - Deploying a proxy contract - -***Testing*** - - Testing Examples - Continuous integration - -***Remix Plugin Development*** - - Developing a plugin for Remix and deploying it to swarm - -***Other*** - - EtherAtom (walkthrough slides + screencast) - Debugging transactions with Remix IDE - Recording and replaying transactions - Using a Pipeline plugin for developing Solidity contracts with demo video - Running scripts in the Remix terminal (batch deployment) (proxy deployment) - -***Additional external workshops*** - - Using Oraclize plugin in Remix diff --git a/apps/remix-ide/docs/remixd.md b/apps/remix-ide/docs/remixd.md deleted file mode 100644 index 3fc7b1bdb3..0000000000 --- a/apps/remix-ide/docs/remixd.md +++ /dev/null @@ -1,57 +0,0 @@ -Remixd: Access your Local Filesystem -========================================= - -`remixd` is an npm module. Its purpose is to give the remix web -application access to a folder on your local computer. - -The code of `remixd` is -[here](https://github.com/ethereum/remixd) . - -`remixd` can be globally installed using the following command: -`yarn global add @remix-project/remixd` - -Then from the terminal, the command `remixd -s --remix-ide ` will start `remixd` and will share the given folder with remix-ide. - -For example, to use remixd with Remix IDE ( and not the alpha version) use this command: -`remixd -s --remix-ide https://remix.ethereum.org` - -Make sure that if you use https://remix.ethereum.org (secure http) in the remixd command (like in the example above), that you are also pointing your browser to https://remix.ethereum.org and not to http://remix.ethereum.org (plain old insecure http). Or if you want to use http in the browser use http in the remixd command. - - -The folder is shared using a websocket connection between `Remix IDE` -and `remixd`. - -Be sure the user executing `remixd` has read/write permission on the -folder. - -There is an option to run remixd in read-only mode, use `--read-only` flag. - -**Warning!** - -`remixd` provides `full read and write access` to the given folder for `any -application` that can access the `TCP port 65520` on your local host. - -From `Remix IDE`, in the Plugin Manager you need to activate the remixd plugin. - -A modal dialog will ask confirmation - -Accepting this dialog will start a session. - -If you do not have `remixd` running in the background - another modal will open up and it will say: - -``` -Cannot connect to the remixd daemon. -Please make sure you have the remixd running in the background. -``` - -Assuming you don't get the 2nd modal, your connection to the remixd daemon is successful. The shared folder will be available in the file explorer. - -**When you click the activation of remixd is successful - there will NOT be an icon that loads in the icon panel.** - -Click the File Explorers icon and in the swap panel you should now see the folder for `localhost`. - -Click on the `localhost connection` icon: - -![](images/a-remixd-success.png) - - diff --git a/apps/remix-ide/docs/run.md b/apps/remix-ide/docs/run.md deleted file mode 100644 index d067fa53e1..0000000000 --- a/apps/remix-ide/docs/run.md +++ /dev/null @@ -1,309 +0,0 @@ -Deploy & Run -============ - -![](images/a-run-icon.png) The Deploy & Run module allows you to send transactions to the current environment. - -To use this module, you need to have a contract compiled. So, if there is a contract name in the CONTRACT select box (the select box is under the VALUE input field), you can use this module. If nothing is there or you do not see the contract you want, you need to select a contract in the editor to make it active, go to a compiler module and compile it, and then come back to Deploy & Run. - -![](images/a-runtab1a.png) - -Environment ---------- - -- `JavaScript VM`: All the transactions will be executed in - a sandbox blockchain in the browser. This means nothing - will be persisted when you reload the page. The JsVM is its own blockchain and on each reload it will start a new blockchain, the old one will not be saved. - -- `Injected Provider`: Remix will connect to an injected - web3 provider. `Metamask` is an example of a provider that inject web3. - -- `Web3 Provider`: Remix will connect to a remote node. You will need to provide the URL to the selected provider: geth, parity or any Ethereum client. - -More about Web3 Provider -------------- -If you are using Geth & https://remix.ethereum.org, please use the following Geth command to allow requests from Remix: - -**geth --rpc --rpccorsdomain https://remix.ethereum.org** - -Also see [Geth Docs about the rpc server](https://geth.ethereum.org/docs/rpc/server) - -To run Remix using https://remix.ethereum.org & a local test node, use this Geth command: - -**geth --rpc --rpccorsdomain="https://remix.ethereum.org" --rpcapi web3,eth,debug,personal,net --vmdebug --datadir --dev console** - -If you are using remix-alpha or a local version of remix - replace the url of the --rpccorsdomain with the url of Remix that you are using. - -To run Remix Desktop & a local test node, use this Geth command: - -**geth --rpc --rpccorsdomain="package://a7df6d3c223593f3550b35e90d7b0b1f.mod" --rpcapi web3,eth,debug,personal,net --vmdebug --datadir --dev console** - -Also see [Geth Docs on Dev mode](https://geth.ethereum.org/getting-started/dev-mode) - -The Web3 Provider Endpoint for a local node is **http://localhost:8545** - ---- - -**WARNING:** Don't get lazy. It is a bad idea to use the Geth flag --rpccorsdomain with a wildcard: `--rpccorsdomain *` - -If you put the wildcard `*`, it means everyone can request the node. Whereas, if you put a URL, it restricts the urls to just that one - e.g. `--rpccorsdomain 'https://remix-alpha.ethereum.org'` - -Only use `--rpccorsdomain *` when using a **test chain** AND using only **test accounts**. For real accounts or on the mainchain **specify the url**. - ---- - - -Account: --------- -- Account: the list of accounts associated with the current - environment (and their associated balances). On the JsVM, you have a choice of 5 accounts. If using Injected Web3 with MetaMask, you need to change the account in MetaMask. - -Gas Limit: ---------- -- This sets the maximum amount of gas that will be allowed for all the - transactions created in Remix. - -Value: ------ -- This sets the amount of ETH, WEI, GWEI etc that is sent to a contract or a payable function. ( Note: payable functions have a red button). The value is always reset to 0 after each transaction execution). The Value field is **NOT** for gas. - - ![](images/a-Runtab-deploy-atAddress.png) - -Initiate Instance ------------------ - -- In the image above, the select box is set to Ballot. This select box will contain the list of compiled contracts. - -- `Deploy` send a transaction that deploys the selected contract. When - the transaction is mined, the newly created instance will be added - (this might take several seconds). Note that if the `constructor` - has parameters, you need to specify them. - -- `At Address` this is used at access a contract that has already been deployed. It assumes that the given address is an instance of the selected contract. **Note:** There's no check at this point, so be careful when using this feature, and be sure you trust the contract at that address. - - -Pending Instances ------------------ - -Validating a transaction takes several seconds. During this time, the GUI -shows it in a pending mode. When the transaction is mined, the number of -pending transactions is updated and the transaction is added to the log -([see terminal](terminal.html)). - -Using the ABI ------------- - -Using `Deploy` or `At Address` is a classic use case of Remix. However, it is -possible to interact with a contract by using its ABI. The ABI is -a JSON array which describe its interface. - -To interact with a contract using the ABI, create a new file in Remix -with extension `*.abi` and copy the ABI content to it. Then, in the input -next to `At Address`, put the Address of the contract you want to -interact with. Click on `At Address`, a new "connection" with the -contract will popup below. - -Using the Recorder ------------------- - -The Recorder is a tool used to save a bunch of transactions in a JSON file and -rerun them later either in the same environment or in another. - -Saving to the JSON file ( by default its called scenario.json) allows one to easily check the transaction list, tweak input parameters, change linked library, etc... - -There are many use cases for the recorder. - -For instance: - -- After having coded and tested contracts in a constrained - environment (like the JavaScript VM), you could then change the environment and redeploy it to a more realistic environment like a test net with an **injected web3** or to a Geth node. By using the generated **scenario.json** file, you will be using all the same settings that you used in the Javascript VM. And this mean that you won't need to click the interface 100 times or whatever to get the state that you achieved originally. So the recorder could be a tool to protect your sanity. - - You can also change the settings in the scenario.json file to customize the playback. - -- Deploying contract does often require more than creating one - transaction and so the recorder will automate this deployment. - -- Working in a dev environment often requires to setup the - state in a first place. - -![](images/a-runtab-recorder.png) - -### scenario.json -To create this file in the recorder, you first of course need to have run some transactions. In the image above - it has a `0` next to **Transactions Recorded**. So this isn't the right moment to save transactions because - well because there aren't any. Each time you make a transaction, that number will increment. Then when you are ready, click the floppy disk icon and the scenario.json file will be created. - -The JSON file below is an example of the scenario.json file. - -In it, 3 transactions are executed: - -The first corresponds to the deployment of the lib `testLib`. - -The second corresponds to the deployment of the contract `test` with the -first parameter of the constructor set to 11. That contract depends -on a library. The linkage is done using the property `linkReferences`. -In that case we use the address of the previously created library : -`created{1512830014773}`. The number is the id (timestamp) of the -transaction that led to the creation of the library. - -The third record corresponds to the call to the function `set` of the -contract `test` (the property to is set to: `created{1512830015080}`) . -Input parameters are `1` and -`0xca35b7d915458ef540ade6068dfe2f44e8fa733c` - -All these transactions are created using the value of the accounts -`account{0}`. - -``` -{ -"accounts": { - "account{0}": "0xca35b7d915458ef540ade6068dfe2f44e8fa733c" -}, -"linkReferences": { - "testLib": "created{1512830014773}" -}, -"transactions": [ - { - "timestamp": 1512830014773, - "record": { - "value": "0", - "parameters": [], - "abi": "0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a", - "contractName": "testLib", - "bytecode": "60606040523415600e57600080fd5b60968061001c6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636d4ce63c146044575b600080fd5b604a6060565b6040518082815260200191505060405180910390f35b6000610d809050905600a165627a7a7230582022d123b15248b8176151f8d45c2dc132063bcc9bb8d5cd652aea7efae362c8050029", - "linkReferences": {}, - "type": "constructor", - "from": "account{0}" - } - }, - { - "timestamp": 1512830015080, - "record": { - "value": "100", - "parameters": [ - 11 - ], - "abi": "0xc41589e7559804ea4a2080dad19d876a024ccb05117835447d72ce08c1d020ec", - "contractName": "test", - "bytecode": "60606040526040516020806102b183398101604052808051906020019091905050806000819055505061027a806100376000396000f300606060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632f30c6f61461006757806338cc48311461009e57806362738998146100f357806387cc10e11461011c575b600080fd5b61009c600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610145565b005b34156100a957600080fd5b6100b1610191565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156100fe57600080fd5b6101066101bb565b6040518082815260200191505060405180910390f35b341561012757600080fd5b61012f6101c4565b6040518082815260200191505060405180910390f35b8160008190555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008054905090565b600073__browser/ballot.sol:testLib____________636d4ce63c6000604051602001526040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160206040518083038186803b151561022e57600080fd5b6102c65a03f4151561023f57600080fd5b505050604051805190509050905600a165627a7a72305820e0b2510bb2890a0334bfe5613d96db3e72442e63b514cdeaee8fc2c6bbd19d3a0029", - "linkReferences": { - "browser/ballot.sol": { - "testLib": [ - { - "length": 20, - "start": 511 - } - ] - } - }, - "name": "", - "type": "constructor", - "from": "account{0}" - } - }, - { - "timestamp": 1512830034180, - "record": { - "value": "1000000000000000000", - "parameters": [ - 1, - "0xca35b7d915458ef540ade6068dfe2f44e8fa733c" - ], - "to": "created{1512830015080}", - "abi": "0xc41589e7559804ea4a2080dad19d876a024ccb05117835447d72ce08c1d020ec", - "name": "set", - "type": "function", - "from": "account{0}" - } - } -], -"abis": { - "0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a": [ - { - "constant": true, - "inputs": [], - "name": "get", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - } - ], - "0xc41589e7559804ea4a2080dad19d876a024ccb05117835447d72ce08c1d020ec": [ - { - "constant": true, - "inputs": [], - "name": "getInt", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getFromLib", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "getAddress", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_t", - "type": "uint256" - }, - { - "name": "_add", - "type": "address" - } - ], - "name": "set", - "outputs": [], - "payable": true, - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "name": "_r", - "type": "uint256" - } - ], - "payable": true, - "stateMutability": "payable", - "type": "constructor" - } - ] -} -} -``` diff --git a/apps/remix-ide/docs/settings.md b/apps/remix-ide/docs/settings.md deleted file mode 100644 index 2f78eb52f0..0000000000 --- a/apps/remix-ide/docs/settings.md +++ /dev/null @@ -1,14 +0,0 @@ -Settings -======== - -To get to **Settings** click the gear a the very bottom of the icon panel. - -You can find a link to the homepage (if you closed it) as well as a link to our Gitter Channel and for you aesthetes out there, we now have a rather large list of themes. - -![](images/a-themes.png) - -Another important settings: - -- Text wrap: controls if the text in the editor should be wrapped. - -- Enable optimization: defines if the compiler should enable optimization during compilation. Enabling this option saves execution gas. It is useful to enable optimization for contracts ready to be deployed in production but could lead to some inconsistencies when debugging such a contract. diff --git a/apps/remix-ide/docs/solidity_editor.md b/apps/remix-ide/docs/solidity_editor.md deleted file mode 100644 index f492dab9a9..0000000000 --- a/apps/remix-ide/docs/solidity_editor.md +++ /dev/null @@ -1,18 +0,0 @@ -Solidity Editor -=============== - -The Remix editor recompiles the code each time the current file is -changed or another file is selected. It also provides syntax -highlighting mapped to solidity keywords. - -![](images/a-sol-editor.png) - -Here's the list of some important features: - -- It display opened files as tabs. -- Compilation Warning and Error are displayed in the gutter -- Remix saves the current file continuously (5s after the last - changes) -- +/- on the top left corner enable you to increase/decrease the font - size of the editor - diff --git a/apps/remix-ide/docs/static_analysis.md b/apps/remix-ide/docs/static_analysis.md deleted file mode 100644 index 7a777ef525..0000000000 --- a/apps/remix-ide/docs/static_analysis.md +++ /dev/null @@ -1,296 +0,0 @@ -Solidity Static Analysis -======================== - -Static code analysis is a process to debug the code by examining it and without actually executing the code. - -`Solidity Static Analysis` plugin performs static analysis on Solidity smart contracts once they are compiled. It checks for security vulnerabilities and bad development practices, among other issues. This plugin comes with `Solidity` environment of Remix IDE. It can also be activated individually from `Plugin Manager`. - -How to use ------------- - -If you select this plugin, you will see a number of modules listed along with checkboxes, one `Auto run` checkbox and a `Run` button. - -![](images/a-static-analysis.png) - -By default, all modules are selected for analysis and a new analysis is performed at each compilation. - -One can select/deselect the modules under which contract should be analyzed and can run the analysis again for last compiled contract by clicking on `Run`. - -If you don't want to run analysis each time you compile a contract, just uncheck the checkbox near to `Auto run`. - -Analysis Modules ------------------ -Currently, with Remix IDE v0.10.1, there are 21 analysis modules listed under 4 categories. Categories are: `Security`, `Gas & Economy`, `ERC` & `Miscellaneous`. - -Here is the list of modules under each category along with the example code which **should be avoided or used very carefully while development**: - -### Category: Security -- **Transaction origin: 'tx.origin' is used** - -`tx.origin` is useful only in very exceptional cases. If you use it for authentication, you usually want to replace it by "msg.sender", because otherwise any contract you call can act on your behalf. - -_Example:_ -``` -require(tx.origin == owner); -``` - -- **Check effects: Potential reentrancy bugs** - -Potential Violation of Checks-Effects-Interaction pattern can lead to re-entrancy vulnerability. - -_Example:_ -``` -// sending ether first -msg.sender.transfer(amount); - -// updating state afterwards -balances[msg.sender] -= amount; -``` - -- **Inline assembly: Inline assembly used** - -Use of inline assembly is advised only in rare cases. - -_Example:_ -``` -assembly { - // retrieve the size of the code, this needs assembly - let size := extcodesize(_addr) -} -``` -- **Block timestamp: Semantics maybe unclear** - -`now` does not mean current time. `now` is an alias for `block.timestamp`. `block.timestamp` can be influenced by miners to a certain degree, be careful. - -_Example:_ -``` -// using now for date comparison -if(startDate > now) - isStarted = true; - -// using block.timestamp -uint c = block.timestamp; -``` -- **Low level calls: Semantics maybe unclear** - -Use of low level `call`, `callcode` or `delegatecall` should be avoided whenever possible. `send` does not throw an exception when not successful, make sure you deal with the failure case accordingly. Use `transfer` whenever failure of the ether transfer should rollback the whole transaction. - -_Example:_ -``` -x.call('something'); -x.send(1 wei); -``` -- **Blockhash usage: Semantics maybe unclear** - -`blockhash` is used to access the last 256 block hashes. A miner computes the block hash by "summing up" the information in the current block mined. By summing up the information in a clever way a miner can try to influence the outcome of a transaction in the current block. - -_Example:_ -``` -bytes32 b = blockhash(100); -``` -- **Selfdestruct: Beware of caller contracts** - -`selfdestruct` can block calling contracts unexpectedly. Be especially careful if this contract is planned to be used by other contracts (i.e. library contracts, interactions). Selfdestruction of the callee contract can leave callers in an inoperable state. - -_Example:_ -``` -selfdestruct(address(0x123abc..)); -``` - -### Category: Gas & Economy -- **Gas costs: Too high gas requirement of functions** - -If the gas requirement of a function is higher than the block gas limit, it cannot be executed. Please avoid loops in your functions or actions that modify large areas of storage - -_Example:_ -``` -for (uint8 proposal = 0; proposal < proposals.length; proposal++) { - if (proposals[proposal].voteCount > winningVoteCount) { - winningVoteCount = proposals[proposal].voteCount; - winningProposal = proposal; - } -} -``` - -- **This on local calls: Invocation of local functions via 'this'** - -Never use `this` to call functions in the same contract, it only consumes more gas than normal local calls. - -_Example:_ -``` -contract test { - - function callb() public { - address x; - this.b(x); - } - - function b(address a) public returns (bool) {} -} -``` - -- **Delete on dynamic Array: Use require/assert appropriately** - -The `delete` operation when applied to a dynamically sized array in Solidity generates code to delete each of the elements contained. If the array is large, this operation can surpass the block gas limit and raise an OOG exception. Also nested dynamically sized objects can produce the same results. - -_Example:_ -``` -contract arr { - uint[] users; - function resetState() public{ - delete users; - } -} -``` - -- **For loop over dynamic array: Iterations depend on dynamic array's size** - -Loops that do not have a fixed number of iterations, for example, loops that depend on storage values, have to be used carefully: Due to the block gas limit, transactions can only consume a certain amount of gas. The number of iterations in a loop can grow beyond the block gas limit which can stall the complete contract at a certain point. Additionally, using unbounded loops can incur in a lot of avoidable gas costs. Carefully test how many items at maximum you can pass to such functions to make it successful. - -_Example:_ -``` -contract forLoopArr { - uint[] array; - - function shiftArrItem(uint index) public returns(uint[] memory) { - for (uint i = index; i < array.length; i++) { - array[i] = array[i+1]; - } - return array; - } -} -``` - -- **Ether transfer in loop: Transferring Ether in a for/while/do-while loop** - -Ether payout should not be done in a loop. Due to the block gas limit, transactions can only consume a certain amount of gas. The number of iterations in a loop can grow beyond the block gas limit which can cause the complete contract to be stalled at a certain point. If required, make sure that number of iterations are low and you trust each address involved. - -_Example:_ -``` -contract etherTransferInLoop { - address payable owner; - - function transferInForLoop(uint index) public { - for (uint i = index; i < 100; i++) { - owner.transfer(i); - } - } - - function transferInWhileLoop(uint index) public { - uint i = index; - while (i < 100) { - owner.transfer(i); - i++; - } - } -} -``` - -### Category: ERC -- **ERC20: 'decimals' should be 'uint8'** - -ERC20 Contracts `decimals` function should have `uint8` as return type. - -_Example:_ -``` -contract EIP20 { - - uint public decimals = 12; -} -``` - -### Category: Miscellaneous -- **Constant/View/Pure functions: Potentially constant/view/pure functions** - -It warns for the methods which potentially should be constant/view/pure but are not. - -_Example:_ -``` -function b(address a) public returns (bool) { - return true; -} -``` -- **Similar variable names: Variable names are too similar** - -It warns on the usage of similar variable names. - -_Example:_ -``` -// Variables have very similar names voter and voters. -function giveRightToVote(address voter) public { - require(voters[voter].weight == 0); - voters[voter].weight = 1; -} -``` -- **No return: Function with 'returns' not returning** - -It warns for the methods which define a return type but never explicitly return a value. - -_Example:_ -``` -function noreturn(string memory _dna) public returns (bool) { - dna = _dna; - } -``` -- **Guard conditions: Use 'require' and 'assert' appropriately** - -Use `assert(x)` if you never ever want x to be false, not in any circumstance (apart from a bug in your code). Use `require(x)` if x can be false, due to e.g. invalid input or a failing external component. - -_Example:_ -``` -assert(a.balance == 0); -``` -- **Result not used: The result of an operation not used** - -A binary operation yields a value that is not used in the following. This is often caused by confusing assignment (=) and comparison (==). - -_Example:_ -``` -c == 5; -or -a + b; -``` -- **String Length: Bytes length != String length** - -Bytes and string length are not the same since strings are assumed to be UTF-8 encoded (according to the ABI defintion) therefore one character is not nessesarily encoded in one byte of data. - -_Example:_ -``` -function length(string memory a) public pure returns(uint) { - bytes memory x = bytes(a); - - return x.length; -} -``` -- **Delete from dynamic array: 'delete' on an array leaves a gap** - -Using `delete` on an array leaves a gap. The length of the array remains the same. If you want to remove the empty position you need to shift items manually and update the length property. - -_Example:_ -``` -contract arr { - uint[] array = [1,2,3]; - - function removeAtIndex() public returns (uint[] memory) { - delete array[1]; - return array; - } -} -``` -- **Data Truncated: Division on int/uint values truncates the result** - -Division of integer values yields an integer value again. That means e.g. 10 / 100 = 0 instead of 0.1 since the result is an integer again. This does not hold for division of (only) literal values since those yield rational constants. - -_Example:_ -``` -function contribute() payable public { - uint fee = msg.value * uint256(feePercentage / 100); - fee = msg.value * (p2 / 100); -} -``` - -Remix-analyzer ------------------ -`remix-analyzer` is the library which works underneath of remix-ide `Solidity Static Analysis` plugin. - -`remix-analyzer` is an [NPM package](https://www.npmjs.com/package/remix-analyzer). It can be used as a library in a solution supporting node.js. Find more information about this type of usage in the [remix-analyzer repository](https://github.com/ethereum/remix/tree/master/remix-analyzer#how-to-use) \ No newline at end of file diff --git a/apps/remix-ide/docs/support.md b/apps/remix-ide/docs/support.md deleted file mode 100644 index 85dfb873c5..0000000000 --- a/apps/remix-ide/docs/support.md +++ /dev/null @@ -1,9 +0,0 @@ -Support chat -======================= - -We know that blockchain ecosystem is very new and that lots of information is scattered around the web. -That is why we created a community support chat where we and other users try to answer your questions if -you get stuck using Remix. Please, join [the Remix channel](https://gitter.im/ethereum/remix) and ask the community for help. - -For anyone who is interested in developing a custom plugin for Remix or who wants to contribute to the codebase, -we've opened [another channel](https://gitter.im/ethereum/remix-dev) specially for developers working on Remix tool. diff --git a/apps/remix-ide/docs/terminal.md b/apps/remix-ide/docs/terminal.md deleted file mode 100644 index 56fdb7c2fd..0000000000 --- a/apps/remix-ide/docs/terminal.md +++ /dev/null @@ -1,21 +0,0 @@ -Terminal -======== - -![](images/a-terminal-and-more.png) - -Features, available in the terminal: - -- It integrates a JavaScript interpreter and the `web3` object. It - enables the execution of the JavaScript script which interacts with - the current context. (note that `web3` is only available if the - `web provider` or `injected provider` mode is selected). -- It displays important actions made while interacting with the Remix - IDE (i.e. sending a new transaction). -- It displays transactions that are mined in the current context. You - can choose to display all transactions or only transactions that - refers to the contracts Remix knows (e.g transaction created from - the Remix IDE). -- It allows searching for the data and clearing the logs from the - terminal. -- You can run scripts by inputting them at the bottom after the `>`. - diff --git a/apps/remix-ide/docs/tutorial_debug.md b/apps/remix-ide/docs/tutorial_debug.md deleted file mode 100644 index dbf951504e..0000000000 --- a/apps/remix-ide/docs/tutorial_debug.md +++ /dev/null @@ -1,225 +0,0 @@ -Debugging Transactions -====================== - -There are two ways to start debugging, each one corresponds to a different use case. -* from the transaction log in the Terminal - use this when you want to debug a transaction. -* from the Debugger - use this if you have a *transaction hash*. - -### Initiate Debugging from the transaction log in the Terminal -Let's start with a basic contract ( or replace this one by your own ) : -- create a blank file in the file explorer (by clicking the + icon) and give it a name. -- copy the code below. -- compile the code. -- click the Run & Deploy icon in the icon panel. - -``` -pragma solidity >=0.5.1 <0.6.0; -contract Donation { - address owner; - event fundMoved(address _to, uint _amount); - modifier onlyowner { if (msg.sender == owner) _; } - address[] _giver; - uint[] _values; - - constructor() public { - owner = msg.sender; - } - - function donate() payable public { - addGiver(msg.value); - } - - function moveFund(address payable _to, uint _amount) onlyowner public { - uint balance = address(this).balance; - uint amount = _amount; - if (_amount <= balance) { - if (_to.send(balance)) { - emit fundMoved(_to, _amount); - } else { - revert(); - } - } else { - revert(); - } - } - - function addGiver(uint _amount) internal { - _giver.push(msg.sender); - _values.push(_amount); - } -} -``` - -For the purpose of this tutorial, we will run the `JavaScript VM`. -This simulates a custom blockchain. You could do the same using a proper backend node. - -Let's deploy the contract: - -Click the `Deploy` button - -![](images/a-debug1-deploy.png) - -You'll see the deployed instance (AKA the udapp). - -![](images/a-debug2-udapp1a.png) - -Then open it up (by clicking the caret). - -![](images/a-debug3-udapp2.png) - - -We are going to call the `Donate` function and will send it ether. - -To do this: in the value input box put in **2** and select Ether as the unit (and not wei like I did in the image below - well you could - it won't really change anything). - -![](images/a-debug4-value-loc.png) - -Then click the `Donate` button. - -This will send Ether to the this function. - -Because we are using the `JavaScript VM`, everything happens almost instantly. (If we had been using Injected Web 3, then we would have to need to approve the transaction, pay for gas and wait for the transaction to get mined.) - -Remix displays information related to each transaction result in the terminal. - -Check in the **terminal** where the transaction you just made is logged. - -Click the debug button to start debugging it. - -![](images/a-debug5-term-debug-but.png) - -Before we get to the actual debugging tool, the next section show how to start debugging session directly from the Debugger. - -### Initiate Debugging from the Debugger - -Click the bug icon in the icon panel to get to the debugger in the side panel. - -If you don't see the bug icon, go to the plugin manager and activate the debugger. - -You can start a debug session by providing a `transaction hash`. - -To find a transaction hash: -1. Go to a transaction in the terminal. -2. Click a line with a transaction - to exand the log. -3. The transaction hash is there - copy it. - -![](images/a-debug6-term-txn-hash.png) - -Then click in the debugger paste the hash and click on the `Start debugging` button. - -![](images/a-debug7-debugger.png) - -Using the debugger ------------------- - -![](images/a-debug8-top3.png) - -The debugger allows one to see detailed informations about the -transaction's execution. It uses the editor to display the -location in the source code where the current execution is. - -The navigation part contains a slider and buttons that can be used to -step through the transaction execution. - - -### More explaination of what these buttons do. -1. Step Into -2. Step Over Into - - -11 panels give detailed information about the execution: - -### Instructions - -The Instructions panel displays the bytecode of the current executing -contract- with the current step highlighted. - -Important note: When this panel is hidden, the slider will have a -courser granularity and only stop at *expression boundaries*, even if they -are compiled into multiple EVM instructions. When the panel is -displayed, it will be possible to step over every instruction, even -those that refers to the same expression. - -### Solidity Locals - -The Solidity Locals panel displays local variables associated with the -current context. - -### Solidity State - -The Solidity State panel displays state variables of the current -executing contract. - -### Low level panels - -These panels display low level informations about the execution: - -> - Stack -> - Storages Changes -> - Memory -> - Call Data -> - Call Stack -> - Return Value (only if the current step is a RETURN opcode) -> - Full Storages Changes (only at the end of the execution - display -> every storage change of every modified contract) - -### Reverted Transaction - -A transaction can be `reverted` (because of an *out of gas exception* or -Solidity `revert` statement or because of a low level exception). - -It is important to be aware of the exception and to locate -where the exception is in the source code. - -Remix will warn you when the execution throws an exception. The -`warning` button will jump to the last opcode before the exception -happened. - -### Breakpoints - -The two last buttons from the navigation area are used to jump either -back to the previous breakpoint or forward to the next breakpoint. - -Breakpoints can be added and removed by clicking on the line number in the *Editor*. - -When using debug session with breakpoints, the execution will jump to the first -encountered breakpoint. - -**Important note:** If you add a breakpoint to a line that declares a -variable, it might be triggered twice: Once for initializing the -variable to zero and second time for assigning the actual value. As an -example, assume you are debugging the following contract: - -``` -pragma solidity >=0.5.1 <0.6.0; - -contract ctr { - function hid () public { - uint p = 45; - uint m; - m = 89; - uint l = 34; - } -} -``` - -And let's says that breakpoints are set for the lines - -`uint p = 45;` - -`m = 89;` - -`uint l = 34;` - -then clicking on `Jump to next breakpoint` will stop at the following -lines in the given order: - -> `uint p = 45;` (declaration of p) -> -> `uint l = 34;` (declaration of l) -> -> `uint p = 45;` (45 assigned to p) -> -> `m = 89;` (89 assigned to m) -> -> `uint l = 34;` (34 assigned to l) diff --git a/apps/remix-ide/docs/udapp.md b/apps/remix-ide/docs/udapp.md deleted file mode 100644 index 86ddb721e6..0000000000 --- a/apps/remix-ide/docs/udapp.md +++ /dev/null @@ -1,139 +0,0 @@ -Run & Deploy (part 2) -===================== - -## Deployed contracts - -This section in the Run tab contains a list of deployed contracts to interact with through autogenerated UI of the deployed contract (also called udapp). - -The deployed contract appears but is in its collapsed form. - -![](images/a-debug2-udapp1a.png) - -Click the sideways caret to open it up. - -![](images/a-udapp1.png) - -You will see the functions in the contract. The functions buttons can have different color buttons. - -- Functions that are `constant` or `pure` functions in Solidity have a blue buttons. Clicking one of this type does not create a new transaction. So clicking will not cause state changes - it will only return a value stored in the contract - so it won't cost you anything in gas fees. - -- Functions that change the state of the contract AND that do not accept Ether are called `non-payable` functions and have an orange button. Clicking on them will create a transaction and thus cost gas. - -- Functions that have red buttons are `payable` functions in Solidity. Clicking one of these will create a new transaction and this transaction can accept a **value**. The **value** is put in in the Value field which is under the Gas Limit field. - -![](images/a-jvm-calling-instance.png) - - -See more information about [Solidity -modifiers](http://solidity.readthedocs.io/en/develop/miscellaneous.html?highlight=pure#modifiers) in the Solidity docs. -. - -If a function requires input parameters, well.. you gotta put them in. - -## Inputting parameters - -![](images/a-udapp-inputs.png) - -### Inputting parameters in the collapsed view - -(Inputting all the parameters in a single input box) -+ The input box tells you what type each parameter needs to be. -+ Numbers and addresses do not need to be wrapped in double quotes. -+ Strings need to be wrapped. -+ Parameters are separated by commas. - -In the example above the "delegate" function has 3 parameters. - -### Inputting parameters in the expanded view -Clicking the 'down' caret brings you to the *Multi-param Manager* - where you can input the parameters one at a time. **Much less confusing!** - -![](images/a-udapp-multi-param-man.png) - -In the expanded view, strings do not need to be wrapped. - -Clicking the clipboard icon will encode the inputs and will copy them. Only a valid set of inputs can be encoded. - -So if you made a mistake and put a uint8 where an address should have been, clicking the clipboard here will give you an error. - -## Low level interactions - -Low level interactions are used to send funds or calldata or funds & calldata to a contract through the **recieve()** or **fallback()** function. Typically, you should only need to implement the fallback function if you are following an upgrade or proxy pattern. - -The low level interactions section is below the functions in each deployed contract. - -![](images/a-udapp1.png) - - -Please note the following: - -- If you are executing a plain Ether transfer to a contract, you need to have the receive() function in your contract. If your contract has been deployed and you want to send it funds, you would input the amount of Ether or Wei etc. (see **A** in graphic below), and then input **NOTHING** in the calldata field of **Low level interactions** (see **B** in graphic) and click the Transact button (see **C** in graphic below). - -![](images/a-receive-fun.png) - -- If you are sending calldata to your contract with Ether, then you need to use the fallback() function and have it with the state mutability of **payable**. - -- If you are not sending ether to the contract but **are** sending call data then you need to use the fallback() function. - -- If you break the rules when using the **Low level interactions** you will be slapped with a warning. - -Please see the [solidity docs](https://solidity.readthedocs.io/en/latest/contracts.html#receive-ether-function) for more specifics about using the **fallback** and **receive** functions. - -### Passing in a tuple or a struct to a function -To pass a tuple in, you need to put in an array []. - -Similarly, to pass in a struct as a parameter of a function, it needs to be put in as an array []. Also note that the line -`pragma experimental ABIEncoderV2;` -needs to put in at the top of the solidity file. - -### Example of passing nested struct to a function -Consider a nested struct defined like this: -``` -struct gardenPlot { - uint slugCount; - uint wormCount; - Flower[] theFlowers; -} -struct Flower { - uint flowerNum; - string color; -} -``` -If a function has the signature `fertilizer(Garden memory gardenPlot)` then the correct syntax is: -``` -[1,2,[[3,"Petunia"]]] -``` - -To continue on this example, here's a sample contract: - -``` -pragma solidity >=0.4.22 <0.7.0; -pragma experimental ABIEncoderV2; - -contract Sunshine { - struct Garden { - uint slugCount; - uint wormCount; - Flower[] theFlowers; - } - struct Flower { - uint flowerNum; - string color; - } - - function picker(Garden memory gardenPlot) public { - uint a = gardenPlot.slugCount; - uint b = gardenPlot.wormCount; - Flower[] memory cFlowers = gardenPlot.theFlowers; - uint d = gardenPlot.theFlowers[0].flowerNum; - string memory e = gardenPlot.theFlowers[0].color; - } -} -``` - -After compiling, deploying the contract and opening up the deployed instance, we can then add the following input parameters to the function named **fertilizer** : - -``` -[1,2,[[3,"Black-eyed Susan"],[4,"Pansy"]]] -``` - -The function **fertilizer** accepts a single parameter of the type **Garden**. The type **Garden** is a **struct**. Structs are wrapped in **square brackets**. Inside **Garden** is an array that is an array of structs named **theFlowers**. It gets a set of brackets for the array and another set for the struct. Thus the double square brackets. diff --git a/apps/remix-ide/docs/unittesting.md b/apps/remix-ide/docs/unittesting.md deleted file mode 100644 index e2fc3f0a44..0000000000 --- a/apps/remix-ide/docs/unittesting.md +++ /dev/null @@ -1,100 +0,0 @@ -Unit Testing Plugin -============ - -Click the -![double check](images/a-user-testing-icon.png) - icon to get to the `Solidity Unit Testing` plugin. - - If you haven't used this plugin before and are not seeing `double check` icon, you have to activate it from Remix plugin manager. - -Go to the plugin manager (by click the ![plug](images/a-plug.png) icon) and load up the unit testing plugin. - -![](images/a-unit-testing-from-pm.png) - -Now `double check` icon will appear on the left side icon bar. Clicking on icon will load the unit testing module in the side panel. - -Alternatively, just select `Solidity` environment from remix IDE home page. This will activate `Solidity Unit Testing` plugin along with `Solidity Compiler`, `Deploy & Run Transactions` & `Solidity Static Analysis` plugins. - -![](images/a-unit-testing-feature.png) - -Generate ----------- -Select a solidity file which you want to test and click on the button `Generate`. It will generate a new sample solidity test file **in the current folder** suffixed with `_test`. This file contains the minimum you need for running unit testing. - -Write Tests ------------ -Write tests to check the functionality of your contract. Remix injects a built-in `assert` library which can be used for testing. Visit the library documentation [here](./assert_library). - -Apart from this, Remix allows usage of some special functions to make testing more structural. They are: - -* `beforeEach()` - Runs before each test -* `beforeAll()` - Runs before all tests -* `afterEach()` - Runs after each test -* `afterAll()` - Runs after all tests - -To get started, see [this simple example](./unittesting_examples.html#simple-example). - -Run ------ -Once you are done with writing tests, select the _test.sol files in the list and click on the button `Run` to execute the tests in the selected files. The execution will run in a separate environment and the result will be displayed below. - -![](images/a-unit-testing-run-result.png) - -Stop ------ -If you have selected multiple files to run the tests and want to stop the execution, click on `Stop` button. It will stop execution after running the tests for current file. - -Customization ------------------- -Remix facilitates users with various types of customizations to test a contract properly. - -**1. Custom Compiler Context** - -`Solidity Unit Testing` refers `Solidity Compiler` plugin for compiler configurations. One can provide customized inputs for `Compiler`, `EVM Version` & `Enable Optimization` and these will be the configuration settings used for contract compilation before running unit tests. - -![](images/a-unit-testing-custom-compiler-config.png) - -**2. Custom Transaction Context** - -For a contract method interaction, prime parameters of transaction are `from` address, `value` & `gas`. Usually, we need to test a method's behaviour under different values of these parameters. - -Remix provides the functionality of custom `msg.sender` & `msg.value` of transaction using method devdoc like: - -``` -/// #sender: account-0 -/// #value: 10 -function checkSenderIs0AndValueis10 () public payable { - Assert.equal(msg.sender, TestsAccounts.getAccount(0), "wrong sender in checkSenderIs0AndValueis10"); - Assert.equal(msg.value, 10, "wrong value in checkSenderIs0AndValueis10"); -} -``` -Things to keep in mind while using custom transaction context: - -1. Parameters must be defined in devdoc of related method -2. Each parameter key should be prefixed with a hash (**#**) and end with a colon following a space (**: **) like `#sender: ` & `#value: ` -3. For now, customization is available for parameters `sender` & `value` only -4. Sender is `from` address of a transaction which is accessed using `msg.sender` inside a contract method. It should be defined in a fixed format as '**account-**' -5. `` varies from `0-2` before remix-ide release v0.10.0 and `0-9` afterwards -6. `remix_accounts.sol` must be imported in your test file to use custom `sender` -7. Value is `value` sent along with a transaction in `wei` which is accessed using `msg.value` inside a contract method. It should be a number. - -Regarding `gas`, Remix estimates the required gas for each transaction internally. Still if a contract deployment fails with `Out-of-Gas` error, it tries to redeploy it by doubling the gas. Deployment failing with double gas will show error: ```contract deployment failed after trying twice: The contract code couldn't be stored, please check your gas limit``` - -Various test examples can be seen in [examples](./unittesting_examples) section. - - -Points to remember ------------------- - -* A test contract cannot have a method with parameters. Having one such method will show error: `Method 'methodname' can not have parameters inside a test contract` -* Number of test accounts are `3` before remix-ide release v0.10.0 and `10` afterwards -* A test file which imports `remix_accounts.sol` might not compile successfully with `Solidity Compiler` plugin but it will work fine with Solidity Unit Testing plugin. - -Remix-tests ----------------------- - -`remix-tests` is the module which works underneath of remix-ide `Solidity Unit Testing` plugin. - -`remix-tests` is an [NPM package](https://www.npmjs.com/package/remix-tests). It can also be used as a CLI/CI solution, supporting node.js. Find more information about this type of usage in the [remix-tests repository](https://github.com/ethereum/remix/tree/master/remix-tests#as-command-line-interface) - -For CI implementation example, see [Su Squares contract](https://github.com/su-squares/ethereum-contract/tree/e542f37d4f8f6c7b07d90a6554424268384a4186) and [Travis build](https://travis-ci.org/su-squares/ethereum-contract/builds/446186067) that uses `remix-tests` for continuous integration testing. diff --git a/apps/remix-ide/docs/unittesting_examples.md b/apps/remix-ide/docs/unittesting_examples.md deleted file mode 100644 index 94b6c6fa65..0000000000 --- a/apps/remix-ide/docs/unittesting_examples.md +++ /dev/null @@ -1,329 +0,0 @@ -Testing by Example -============ - -Here are some examples which can give you better understanding to plan your tests. - -**Note:** Examples in this section are intended to give you a push for development. We don't recommend to rely on them without verifying at your end. - -### 1. Simple example -In this example, we test setting & getting variables. - -Contract/Program to be tested: `Simple_storage.sol` - -``` -pragma solidity >=0.4.22 <0.7.0; - -contract SimpleStorage { - uint public storedData; - - constructor() public { - storedData = 100; - } - - function set(uint x) public { - storedData = x; - } - - function get() public view returns (uint retVal) { - return storedData; - } -} -``` -Test contract/program: `simple_storage_test.sol` - -``` -pragma solidity >=0.4.22 <0.7.0; -import "remix_tests.sol"; -import "./Simple_storage.sol"; - -contract MyTest { - SimpleStorage foo; - - // beforeEach works before running each test - function beforeEach() public { - foo = new SimpleStorage(); - } - - /// Test if initial value is set correctly - function initialValueShouldBe100() public returns (bool) { - return Assert.equal(foo.get(), 100, "initial value is not correct"); - } - - /// Test if value is set as expected - function valueIsSet200() public returns (bool) { - foo.set(200); - return Assert.equal(foo.get(), 200, "value is not 200"); - } -} -``` - -### 2. Testing a method involving `msg.sender` -In Solidity, `msg.sender` plays a great role in access management of a smart contract methods interaction. Different `msg.sender` can help to test a contract involving multiple accounts with different roles. Here is an example for testing such case: - -Contract/Program to be tested: `Sender.sol` - -``` -pragma solidity >=0.4.22 <0.7.0; -contract Sender { - address private owner; - - constructor() public { - owner = msg.sender; - } - - function updateOwner(address newOwner) public { - require(msg.sender == owner, "only current owner can update owner"); - owner = newOwner; - } - - function getOwner() public view returns (address) { - return owner; - } -} -``` - -Test contract/program: `Sender_test.sol` - -``` -pragma solidity >=0.4.22 <0.7.0; -import "remix_tests.sol"; // this import is automatically injected by Remix -import "remix_accounts.sol"; -import "./Sender.sol"; - -// Inherit 'Sender' contract -contract SenderTest is Sender { - /// Define variables referring to different accounts - address acc0; - address acc1; - address acc2; - - /// Initiate accounts variable - function beforeAll() public { - acc0 = TestsAccounts.getAccount(0); - acc1 = TestsAccounts.getAccount(1); - acc2 = TestsAccounts.getAccount(2); - } - - /// Test if initial owner is set correctly - function testInitialOwner() public { - // account at zero index (account-0) is default account, so current owner should be acc0 - Assert.equal(getOwner(), acc0, 'owner should be acc0'); - } - - /// Update owner first time - /// This method will be called by default account(account-0) as there is no custom sender defined - function updateOwnerOnce() public { - // check method caller is as expected - Assert.ok(msg.sender == acc0, 'caller should be default account i.e. acc0'); - // update owner address to acc1 - updateOwner(acc1); - // check if owner is set to expected account - Assert.equal(getOwner(), acc1, 'owner should be updated to acc1'); - } - - /// Update owner again by defining custom sender - /// #sender: account-1 (sender is account at index '1') - function updateOwnerOnceAgain() public { - // check if caller is custom and is as expected - Assert.ok(msg.sender == acc1, 'caller should be custom account i.e. acc1'); - // update owner address to acc2. This will be successful because acc1 is current owner & caller both - updateOwner(acc2); - // check if owner is set to expected account i.e. account2 - Assert.equal(getOwner(), acc2, 'owner should be updated to acc2'); - } -} -``` - -### 3. Testing method execution - -With Solidity, one can directly verify the changes made by a method in storage by retrieving those variables from a contract. But testing for a successful method execution takes some strategy. Well that is not entirely true, when a test is successful - it is usually obvious why it passed. However, when a test fails, it is essential to understand why it failed. - -To help in such cases, Solidity introduced the `try-catch` statement in version `0.6.0`. Previously, we had to use low-level calls to track down what was going on. - -Here is an example test file that use both **try-catch** blocks and **low level calls**: - -Contract/Program to be tested: `AttendanceRegister.sol` - -``` -pragma solidity >=0.4.22 <0.7.0; -contract AttendanceRegister { - struct Student{ - string name; - uint class; - } - - event Added(string name, uint class, uint time); - - mapping(uint => Student) public register; // roll number => student details - - function add(uint rollNumber, string memory name, uint class) public returns (uint256){ - require(class > 0 && class <= 12, "Invalid class"); - require(register[rollNumber].class == 0, "Roll number not available"); - Student memory s = Student(name, class); - register[rollNumber] = s; - emit Added(name, class, now); - return rollNumber; - } - - function getStudentName(uint rollNumber) public view returns (string memory) { - return register[rollNumber].name; - } -} -``` - -Test contract/program: `AttendanceRegister_test.sol` - -``` -pragma solidity >=0.4.22 <0.7.0; -import "remix_tests.sol"; // this import is automatically injected by Remix. -import "./AttendanceRegister.sol"; - -contract AttendanceRegisterTest { - - AttendanceRegister ar; - - /// 'beforeAll' runs before all other tests - function beforeAll () public { - // Create an instance of contract to be tested - ar = new AttendanceRegister(); - } - - /// For solidity version greater or equal to 0.6.0, - /// See: https://solidity.readthedocs.io/en/v0.6.0/control-structures.html#try-catch - /// Test 'add' using try-catch - function testAddSuccessUsingTryCatch() public { - // This will pass - try ar.add(101, 'secondStudent', 11) returns (uint256 r) { - Assert.equal(r, 101, 'wrong rollNumber'); - } catch Error(string memory /*reason*/) { - // This is executed in case - // revert was called inside getData - // and a reason string was provided. - Assert.ok(false, 'failed with reason'); - } catch (bytes memory /*lowLevelData*/) { - // This is executed in case revert() was used - // or there was a failing assertion, division - // by zero, etc. inside getData. - Assert.ok(false, 'failed unexpected'); - } - } - - /// Test failure case of 'add' using try-catch - function testAddFailureUsingTryCatch1() public { - // This will revert on 'require(class > 0 && class <= 12, "Invalid class");' for class '13' - try ar.add(101, 'secondStudent', 13) returns (uint256 r) { - Assert.ok(false, 'method execution should fail'); - } catch Error(string memory reason) { - // Compare failure reason, check if it is as expected - Assert.equal(reason, 'Invalid class', 'failed with unexpected reason'); - } catch (bytes memory /*lowLevelData*/) { - Assert.ok(false, 'failed unexpected'); - } - } - - /// Test another failure case of 'add' using try-catch - function testAddFailureUsingTryCatch2() public { - // This will revert on 'require(register[rollNumber].class == 0, "Roll number not available");' for rollNumber '101' - try ar.add(101, 'secondStudent', 11) returns (uint256 r) { - Assert.ok(false, 'method execution should fail'); - } catch Error(string memory reason) { - // Compare failure reason, check if it is as expected - Assert.equal(reason, 'Roll number not available', 'failed with unexpected reason'); - } catch (bytes memory /*lowLevelData*/) { - Assert.ok(false, 'failed unexpected'); - } - } - - /// For solidity version less than 0.6.0, low level call can be used - /// See: https://solidity.readthedocs.io/en/v0.6.0/units-and-global-variables.html#members-of-address-types - /// Test success case of 'add' using low level call - function testAddSuccessUsingCall() public { - bytes memory methodSign = abi.encodeWithSignature('add(uint256,string,uint256)', 102, 'firstStudent', 10); - (bool success, bytes memory data) = address(ar).call(methodSign); - // 'success' stores the result in bool, this can be used to check whether method call was successful - Assert.equal(success, true, 'execution should be successful'); - // 'data' stores the returned data which can be decoded to get the actual result - uint rollNumber = abi.decode(data, (uint256)); - // check if result is as expected - Assert.equal(rollNumber, 102, 'wrong rollNumber'); - } - - /// Test failure case of 'add' using low level call - function testAddFailureUsingCall() public { - bytes memory methodSign = abi.encodeWithSignature('add(uint256,string,uint256)', 102, 'duplicate', 10); - (bool success, bytes memory data) = address(ar).call(methodSign); - // 'success' will be false if method execution is not successful - Assert.equal(success, false, 'execution should be successful'); - } -} -``` - - -### 4. Testing a method involving `msg.value` -In Solidity, ether can be passed along with a method call which is accessed inside contract as `msg.value`. Sometimes, multiple calculations in a method are performed based on `msg.value` which can be tested with various values using Remix's Custom transaction context. See the example: - -Contract/Program to be tested: `Value.sol` - -``` -pragma solidity >=0.4.22 <0.7.0; -contract Value { - uint256 public tokenBalance; - - constructor() public { - tokenBalance = 0; - } - - function addValue() payable public { - tokenBalance = tokenBalance + (msg.value/10); - } - - function getTokenBalance() view public returns (uint256) { - return tokenBalance; - } -} -``` -Test contract/program: `Value_test.sol` - -``` -pragma solidity >=0.4.22 <0.7.0; -import "remix_tests.sol"; -import "./Value.sol"; - -contract ValueTest{ - Value v; - - function beforeAll() public { - // create a new instance of Value contract - v = new Value(); - } - - /// Test initial balance - function testInitialBalance() public { - // initially token balance should be 0 - Assert.equal(v.getTokenBalance(), 0, 'token balance should be 0 initially'); - } - - /// For Solidity version greater than 0.6.1 - /// Test 'addValue' execution by passing custom ether amount - /// #value: 200 - function addValueOnce() public payable { - // check if value is same as provided through devdoc - Assert.equal(msg.value, 200, 'value should be 200'); - // execute 'addValue' - v.addValue{gas: 40000, value: 200}(); // introduced in Solidity version 0.6.2 - // As per the calculation, check the total balance - Assert.equal(v.getTokenBalance(), 20, 'token balance should be 20'); - } - - /// For Solidity version less than 0.6.2 - /// Test 'addValue' execution by passing custom ether amount again using low level call - /// #value: 100 - function addValueAgain() public payable { - Assert.equal(msg.value, 100, 'value should be 100'); - bytes memory methodSign = abi.encodeWithSignature('addValue()'); - (bool success, bytes memory data) = address(v).call.gas(40000).value(100)(methodSign); - Assert.equal(success, true, 'execution should be successful'); - Assert.equal(v.getTokenBalance(), 30, 'token balance should be 30'); - } -} -``` diff --git a/apps/remix-ide/embark/README.md b/apps/remix-ide/embark/README.md deleted file mode 100644 index bea37e1f35..0000000000 --- a/apps/remix-ide/embark/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# embark-remix -An Embark plugin that allows Remix to connect to a local DApp via [`remixd`](https://github.com/ethereum/remixd). This plugin serves a local copy of Remix IDE from the machine running the plugin or alternatively allows connection from the public [Remix IDE](https://remix.ethereum.org). The URL of the Remix IDE can be specified in the Embark plugin options, specified below. - -## Options -To configure options for the `embark-remix` plugin, modify the `plugins` property of `embark.json` in the DApp. - -### How to use default options -To pass no options to the plugin and use the defaults, simply use an empty object: -``` -"plugins": { - "embark-remix": {} -} -``` -This will provide the default options to the plugin (shown below). - -### Available options -The available options for this plugin are below. Default options are shown below. This is equivalent to passing an empty object `{}`. -``` -"plugins": { - "embark-remix": { - "readOnly": false, - "remixIde": { - "protocol": "http", - "host": "localhost", - "port": 8088 - } - } -} -``` - - -`readOnly` does not let Remix update the contents on the local filesystem. - - Default: `false` - -`remixIde` specifies the URL that the Remix IDE will be served from. If this is a `localhost` URL, the plugin creates a server that is responsible for listening on this URL. - - Default: `(see above)` - -If it is preferred to connect to the public Remix IDE at https://remix.ethereum.org, set the `remixIde` config to: -``` -"remixIde": { - "protocol": "https", - "host": "remix.ethereum.org", - "port": false -} -``` \ No newline at end of file diff --git a/apps/remix-ide/embark/index.js b/apps/remix-ide/embark/index.js deleted file mode 100644 index dcd0b64b39..0000000000 --- a/apps/remix-ide/embark/index.js +++ /dev/null @@ -1,66 +0,0 @@ -const httpServer = require('http-server') -const remixd = require('remixd') -const path = require('path') -const merge = require('merge') -const colors = require('colors') - -const DEFAULT_OPTIONS = { - protocol: 'http', - host: 'localhost', - port: '8088' -} - -module.exports = (embark) => { - // plugin options - const readOnly = embark.pluginConfig.readOnly || false - const { protocol, host, port } = merge.recursive(DEFAULT_OPTIONS, embark.pluginConfig.remixIde) - - // globals - const remixIdeUrl = `${protocol}://${host}` + `${port ? `:${port}` : ''}` - const sharedFolder = path.join(__dirname, '../../') - const sharedFolderService = remixd.services.sharedFolder - let server - - // setup HTTP server - if (['localhost', '127.0.0.1', '0.0.0.0'].includes(host)) { - server = httpServer.createServer({ - root: path.join(__dirname, '../../node_modules/remix-ide') - }) - server.listen(port, '127.0.0.1', function () { - embark.logger.info('Remix IDE (via embark-remix plugin) available at ' + colors.underline(remixIdeUrl)) - }) - } else { - embark.logger.info('embark-remix is set to connect to a Remix IDE at ' + colors.underline(remixIdeUrl)) - } - - // setup Embark service check - embark.registerServiceCheck('Remix IDE', (cb) => { - return cb({ name: `Remix IDE ${host}:${port}`, status: 'on' }) - }) - - // setup remixd shared folder service - const sharedFolderRouter = new remixd.Router(65520, sharedFolderService, { remixIdeUrl }, (webSocket) => { - sharedFolderService.setWebSocket(webSocket) - sharedFolderService.setupNotifications(sharedFolder) - sharedFolderService.sharedFolder(sharedFolder, readOnly) - }) - const killRemixD = sharedFolderRouter.start() - const kill = () => { - if (server) server.close() - embark.logger.info(colors.red('embark-remix stopped')) - process.exit() - } - - if (process.platform === 'win32') { - require('readline').createInterface({ - input: process.stdin, - output: process.stdout - }).on('SIGINT', function () { - process.emit('SIGINT') - }) - } - - process.on('SIGINT', kill) // catch ctrl-c - process.on('SIGTERM', kill) // catch kill - process.on('exit', killRemixD) -} diff --git a/apps/remix-ide/embark/package.json b/apps/remix-ide/embark/package.json deleted file mode 100644 index b665450219..0000000000 --- a/apps/remix-ide/embark/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "embark-remix", - "version": "0.0.2", - "description": "load remix IDE from embark environment", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "MIT", - "dependencies": { - "remix-ide": "latest", - "remixd": "latest", - "http-server": "latest" - } -} diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index 30e653731d..1b7c7b483a 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -27,6 +27,7 @@ import { NotificationPlugin } from './app/plugins/notification' import { Blockchain } from './blockchain/blockchain.js' import { HardhatProvider } from './app/tabs/hardhat-provider' import { GanacheProvider } from './app/tabs/ganache-provider' +import { FoundryProvider } from './app/tabs/foundry-provider' const isElectron = require('is-electron') @@ -177,6 +178,7 @@ class AppComponent { const web3Provider = new Web3ProviderModule(blockchain) const hardhatProvider = new HardhatProvider(blockchain) const ganacheProvider = new GanacheProvider(blockchain) + const foundryProvider = new FoundryProvider(blockchain) // ----------------- convert offset to line/column service ----------- const offsetToLineColumnConverter = new OffsetToLineColumnConverter() Registry.getInstance().put({ @@ -233,6 +235,7 @@ class AppComponent { storagePlugin, hardhatProvider, ganacheProvider, + foundryProvider, this.walkthroughService, search ]) @@ -318,7 +321,8 @@ class AppComponent { filePanel.slitherHandle, linkLibraries, deployLibraries, - openZeppelinProxy + openZeppelinProxy, + run.recorder ]) this.layout.panels = { @@ -352,7 +356,7 @@ class AppComponent { await this.appManager.activatePlugin(['settings', 'config']) await this.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'contextualListener', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport', 'gistHandler']) await this.appManager.activatePlugin(['settings']) - await this.appManager.activatePlugin(['walkthrough','storage', 'search','compileAndRun']) + await this.appManager.activatePlugin(['walkthrough','storage', 'search','compileAndRun', 'recorder']) this.appManager.on( 'filePanel', diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js index f2a423264b..b25fe16c82 100644 --- a/apps/remix-ide/src/app/panels/file-panel.js +++ b/apps/remix-ide/src/app/panels/file-panel.js @@ -29,7 +29,7 @@ const { SlitherHandle } = require('../files/slither-handle.js') const profile = { name: 'filePanel', - displayName: 'File explorers', + displayName: 'File explorer', methods: ['createNewFile', 'uploadFile', 'getCurrentWorkspace', 'getWorkspaces', 'createWorkspace', 'setWorkspace', 'registerContextMenuItem', 'renameWorkspace', 'deleteWorkspace'], events: ['setWorkspace', 'workspaceRenamed', 'workspaceDeleted', 'workspaceCreated'], icon: 'assets/img/fileManager.webp', diff --git a/apps/remix-ide/src/app/tabs/foundry-provider.tsx b/apps/remix-ide/src/app/tabs/foundry-provider.tsx new file mode 100644 index 0000000000..47e899865a --- /dev/null +++ b/apps/remix-ide/src/app/tabs/foundry-provider.tsx @@ -0,0 +1,33 @@ +import * as packageJson from '../../../../../package.json' +import { Plugin } from '@remixproject/engine' +import { AppModal, AlertModal, ModalTypes } from '@remix-ui/app' +import React from 'react' // eslint-disable-line +import { Blockchain } from '../../blockchain/blockchain' +import { ethers } from 'ethers' +import { AbstractProvider } from './abstract-provider' + +const profile = { + name: 'foundry-provider', + displayName: 'Foundry Provider', + kind: 'provider', + description: 'Anvil', + methods: ['sendAsync'], + version: packageJson.version +} + +export class FoundryProvider extends AbstractProvider { + constructor (blockchain) { + super(profile, blockchain, 'http://127.0.0.1:8545') + } + + body (): JSX.Element { + return ( +
Note: To run Anvil on your system, run +
curl -L https://foundry.paradigm.xyz | bash
+
anvil
+ For more info, visit: Foundry Documentation +
Anvil JSON-RPC Endpoint:
+
+ ) + } +} \ No newline at end of file diff --git a/apps/remix-ide/src/app/tabs/runTab/model/recorder.js b/apps/remix-ide/src/app/tabs/runTab/model/recorder.js index 6178063843..550cf5fa26 100644 --- a/apps/remix-ide/src/app/tabs/runTab/model/recorder.js +++ b/apps/remix-ide/src/app/tabs/runTab/model/recorder.js @@ -1,16 +1,28 @@ var async = require('async') var ethutil = require('ethereumjs-util') var remixLib = require('@remix-project/remix-lib') +import { Plugin } from '@remixproject/engine' +import * as packageJson from '../../../../.././../../package.json' var EventManager = remixLib.EventManager var format = remixLib.execution.txFormat var txHelper = remixLib.execution.txHelper const helper = require('../../../../lib/helper') +const _paq = window._paq = window._paq || [] //eslint-disable-line + +const profile = { + name: 'recorder', + displayName: 'Recorder', + description: '', + version: packageJson.version, + methods: [ ] +} /** * Record transaction as long as the user create them. */ -class Recorder { +class Recorder extends Plugin { constructor (blockchain) { + super(profile) this.event = new EventManager() this.blockchain = blockchain this.data = { _listen: true, _replay: false, journal: [], _createdContracts: {}, _createdContractsReverse: {}, _usedAccounts: {}, _abis: {}, _contractABIReferences: {}, _linkReferences: {} } @@ -169,16 +181,30 @@ class Recorder { /** * run the list of records * + * @param {Object} records * @param {Object} accounts * @param {Object} options * @param {Object} abis + * @param {Object} linkReferences + * @param {Function} confirmationCb + * @param {Function} continueCb + * @param {Function} promptCb + * @param {Function} alertCb + * @param {Function} logCallBack + * @param {Function} liveMode * @param {Function} newContractFn * */ - run (records, accounts, options, abis, linkReferences, confirmationCb, continueCb, promptCb, alertCb, logCallBack, newContractFn) { + run (records, accounts, options, abis, linkReferences, confirmationCb, continueCb, promptCb, alertCb, logCallBack, liveMode, newContractFn) { this.setListen(false) - logCallBack(`Running ${records.length} transaction(s) ...`) - async.eachOfSeries(records, (tx, index, cb) => { + const liveMsg = liveMode ? ' in live mode' : '' + logCallBack(`Running ${records.length} transaction(s)${liveMsg} ...`) + async.eachOfSeries(records, async (tx, index, cb) => { + if (liveMode && tx.record.type === 'constructor') { + // resolve the bytecode using the contract name, this ensure getting the last compiled one. + const data = await this.call('compilerArtefacts', 'getArtefactsByContractName', tx.record.contractName) + tx.record.bytecode = data.artefact.evm.bytecode.object + } var record = this.resolveAddress(tx.record, accounts, options) var abi = abis[tx.record.abi] if (!abi) { @@ -257,8 +283,10 @@ class Recorder { }, () => { this.setListen(true) }) } - runScenario (json, continueCb, promptCb, alertCb, confirmationCb, logCallBack, cb) { + runScenario (liveMode, json, continueCb, promptCb, alertCb, confirmationCb, logCallBack, cb) { + _paq.push(['trackEvent', 'run', 'recorder', 'start']) if (!json) { + _paq.push(['trackEvent', 'run', 'recorder', 'wrong-json']) return cb('a json content must be provided') } if (typeof json === 'string') { @@ -269,12 +297,17 @@ class Recorder { } } + let txArray + let accounts + let options + let abis + let linkReferences try { - var txArray = json.transactions || [] - var accounts = json.accounts || [] - var options = json.options || {} - var abis = json.abis || {} - var linkReferences = json.linkReferences || {} + txArray = json.transactions || [] + accounts = json.accounts || [] + options = json.options || {} + abis = json.abis || {} + linkReferences = json.linkReferences || {} } catch (e) { return cb('Invalid Scenario File. Please try again') } @@ -283,7 +316,7 @@ class Recorder { return } - this.run(txArray, accounts, options, abis, linkReferences, confirmationCb, continueCb, promptCb, alertCb, logCallBack, (abi, address, contractName) => { + this.run(txArray, accounts, options, abis, linkReferences, confirmationCb, continueCb, promptCb, alertCb, logCallBack, liveMode, (abi, address, contractName) => { cb(null, abi, address, contractName) }) } diff --git a/apps/remix-ide/src/app/udapp/run-tab.js b/apps/remix-ide/src/app/udapp/run-tab.js index 0f59ddd962..8a1e30324e 100644 --- a/apps/remix-ide/src/app/udapp/run-tab.js +++ b/apps/remix-ide/src/app/udapp/run-tab.js @@ -1,6 +1,7 @@ import React from 'react' // eslint-disable-line import { RunTabUI } from '@remix-ui/run-tab' import { ViewPlugin } from '@remixproject/engine-web' +import { addressToString } from '@remix-ui/helper' import * as packageJson from '../../../../../package.json' const EventManager = require('../../lib/events') @@ -18,7 +19,7 @@ const profile = { version: packageJson.version, permission: true, events: ['newTransaction'], - methods: ['createVMAccount', 'sendTransaction', 'getAccounts', 'pendingTransactionsCount', 'getSettings', 'setEnvironmentMode', 'clearAllInstances', 'addInstance'] + methods: ['createVMAccount', 'sendTransaction', 'getAccounts', 'pendingTransactionsCount', 'getSettings', 'setEnvironmentMode', 'clearAllInstances', 'addInstance', 'resolveContractAndAddInstance'] } export class RunTab extends ViewPlugin { @@ -127,6 +128,20 @@ export class RunTab extends ViewPlugin { } }) + await this.call('blockchain', 'addProvider', { + name: 'Foundry Provider', + provider: { + async sendAsync (payload, callback) { + try { + const result = await udapp.call('foundry-provider', 'sendAsync', payload) + callback(null, result) + } catch (e) { + callback(e) + } + } + } + }) + await this.call('blockchain', 'addProvider', { name: 'Wallet Connect', provider: { @@ -149,4 +164,11 @@ export class RunTab extends ViewPlugin { readFile (fileName) { return this.call('fileManager', 'readFile', fileName) } + + resolveContractAndAddInstance (contractObject, address) { + const data = this.compilersArtefacts.getCompilerAbstract(contractObject.contract.file) + + this.compilersArtefacts.addResolvedContract(addressToString(address), data) + this.addInstance(address, contractObject.abi, contractObject.name) + } } diff --git a/apps/remix-ide/src/blockchain/blockchain.js b/apps/remix-ide/src/blockchain/blockchain.js index b49b5b3ef2..5f6d3ad6c6 100644 --- a/apps/remix-ide/src/blockchain/blockchain.js +++ b/apps/remix-ide/src/blockchain/blockchain.js @@ -3,7 +3,6 @@ import React from 'react' // eslint-disable-line import Web3 from 'web3' import { Plugin } from '@remixproject/engine' import { toBuffer, addHexPrefix } from 'ethereumjs-util' -import { waterfall } from 'async' import { EventEmitter } from 'events' import { format } from 'util' import { ExecutionContext } from './execution-context' @@ -12,6 +11,8 @@ import InjectedProvider from './providers/injected.js' import NodeProvider from './providers/node.js' import { execution, EventManager, helpers } from '@remix-project/remix-lib' import { etherScanLink } from './helper' +import { logBuilder, confirmProxyMsg } from "@remix-ui/helper" +import { cancelProxyMsg } from '@remix-ui/helper' const { txFormat, txExecution, typeConversion, txListener: Txlistener, TxRunner, TxRunnerWeb3, txHelper } = execution const { txResultHelper: resultToRemixTx } = helpers const packageJson = require('../../../../package.json') @@ -113,7 +114,9 @@ export class Blockchain extends Plugin { const { continueCb, promptCb, statusCb, finalCb } = callbacks const constructor = selectedContract.getConstructorInterface() txFormat.buildData(selectedContract.name, selectedContract.object, compilerContracts, true, constructor, args, (error, data) => { - if (error) return statusCb(`creation of ${selectedContract.name} errored: ${error.message ? error.message : error}`) + if (error) { + return statusCb(`creation of ${selectedContract.name} errored: ${error.message ? error.message : error}`) + } statusCb(`creation of ${selectedContract.name} pending...`) this.createContract(selectedContract, data, continueCb, promptCb, confirmationCb, finalCb) @@ -127,13 +130,73 @@ export class Blockchain extends Plugin { const { continueCb, promptCb, statusCb, finalCb } = callbacks const constructor = selectedContract.getConstructorInterface() txFormat.encodeConstructorCallAndLinkLibraries(selectedContract.object, args, constructor, contractMetadata.linkReferences, selectedContract.bytecodeLinkReferences, (error, data) => { - if (error) return statusCb(`creation of ${selectedContract.name} errored: ${error.message ? error.message : error}`) + if (error) { + return statusCb(`creation of ${selectedContract.name} errored: ${error.message ? error.message : error}`) + } statusCb(`creation of ${selectedContract.name} pending...`) this.createContract(selectedContract, data, continueCb, promptCb, confirmationCb, finalCb) }) } + async deployProxy (proxyData, implementationContractObject) { + const proxyModal = { + id: 'confirmProxyDeployment', + title: 'ERC1967', + 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', + cancelLabel: 'Cancel', + okFn: () => { + this.runProxyTx(proxyData, implementationContractObject) + }, + cancelFn: () => { + this.call('notification', 'toast', cancelProxyMsg()) + }, + hideFn: () => null + } + this.call('notification', 'modal', proxyModal) + } + + async runProxyTx (proxyData, implementationContractObject) { + const args = { useCall: false, data: proxyData } + const confirmationCb = (network, tx, gasEstimation, continueTxExecution, cancelCb) => { + // continue using original authorization given by user + continueTxExecution(null) + } + const continueCb = (error, continueTxExecution, cancelCb) => { continueTxExecution() } + const promptCb = (okCb, cancelCb) => { okCb() } + const finalCb = (error, txResult, address, returnValue) => { + if (error) { + const log = logBuilder(error) + + return this.call('terminal', 'logHtml', log) + } + return this.call('udapp', 'resolveContractAndAddInstance', implementationContractObject, address) + } + + this.runTx(args, confirmationCb, continueCb, promptCb, finalCb) + } + + async getEncodedFunctionHex (args, funABI) { + return new Promise((resolve, reject) => { + txFormat.encodeFunctionCall(args, funABI, (error, data) => { + if (error) return reject(error) + resolve(data.dataHex) + }) + }) + } + + async getEncodedParams (args, funABI) { + return new Promise((resolve, reject) => { + txFormat.encodeParams(args, funABI, (error, encodedParams) => { + if (error) return reject(error) + return resolve(encodedParams.dataHex) + }) + }) + } + createContract (selectedContract, data, continueCb, promptCb, confirmationCb, finalCb) { if (data) { data.contractName = selectedContract.name @@ -433,55 +496,71 @@ export class Blockchain extends Plugin { }) } - runTx (args, confirmationCb, continueCb, promptCb, cb) { - waterfall([ - (next) => { // getGasLimit + async runTx (args, confirmationCb, continueCb, promptCb, cb) { + const getGasLimit = () => { + return new Promise((resolve, reject) => { if (this.transactionContextAPI.getGasLimit) { - return this.transactionContextAPI.getGasLimit(next) + return this.transactionContextAPI.getGasLimit((err, value) => { + if (err) return reject(err) + return resolve(value) + }) } - next(null, 3000000) - }, - (gasLimit, next) => { // queryValue + return resolve(3000000) + }) + } + const queryValue = () => { + return new Promise((resolve, reject) => { if (args.value) { - return next(null, args.value, gasLimit) + return resolve(args.value) } if (args.useCall || !this.transactionContextAPI.getValue) { - return next(null, 0, gasLimit) + return resolve(0) } - this.transactionContextAPI.getValue(function (err, value) { - next(err, value, gasLimit) + this.transactionContextAPI.getValue((err, value) => { + if (err) return reject(err) + return resolve(value) }) - }, - (value, gasLimit, next) => { // getAccount + }) + } + const getAccount = () => { + return new Promise((resolve, reject) => { if (args.from) { - return next(null, args.from, value, gasLimit) + return resolve(args.from) } if (this.transactionContextAPI.getAddress) { return this.transactionContextAPI.getAddress(function (err, address) { - next(err, address, value, gasLimit) + if (err) return reject(err) + return resolve(address) }) } this.getAccounts(function (err, accounts) { + if (err) return reject(err) const address = accounts[0] - if (err) return next(err) - if (!address) return next('No accounts available') + if (!address) return reject('No accounts available') if (this.executionContext.isVM() && !this.providers.vm.RemixSimulatorProvider.Accounts.accounts[address]) { - return next('Invalid account selected') + return reject('Invalid account selected') } - next(null, address, value, gasLimit) + return resolve(address) }) - }, - (fromAddress, value, gasLimit, next) => { // runTransaction + }) + } + const runTransaction = async () => { + // eslint-disable-next-line no-async-promise-executor + return new Promise(async (resolve, reject) => { + const fromAddress = await getAccount() + const value = await queryValue() + const gasLimit = await getGasLimit() const tx = { to: args.to, data: args.data.dataHex, useCall: args.useCall, from: fromAddress, value: value, gasLimit: gasLimit, timestamp: args.data.timestamp } const payLoad = { funAbi: args.data.funAbi, funArgs: args.data.funArgs, contractBytecode: args.data.contractBytecode, contractName: args.data.contractName, contractABI: args.data.contractABI, linkReferences: args.data.linkReferences } - if (!tx.timestamp) tx.timestamp = Date.now() + if (!tx.timestamp) tx.timestamp = Date.now() const timestamp = tx.timestamp + this.event.trigger('initiatingTransaction', [timestamp, tx, payLoad]) this.txRunner.rawRun(tx, confirmationCb, continueCb, promptCb, async (error, result) => { - if (error) return next(error) + if (error) return reject(error) const isVM = this.executionContext.isVM() if (isVM && tx.useCall) { @@ -500,16 +579,15 @@ export class Blockchain extends Plugin { try { error = 'error: ' + JSON.stringify(error) } catch (e) { console.log(e) } } } - next(error, result, tx) + return resolve({ result, tx }) } ) - } - ], - async (error, txResult, tx) => { - if (error) { - return cb(error) - } - + }) + } + try { + const transaction = await runTransaction() + const txResult = transaction.result + const tx = transaction.tx /* value of txResult is inconsistent: - transact to contract: @@ -517,12 +595,12 @@ export class Blockchain extends Plugin { - call to contract: {"result":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionHash":"0x5236a76152054a8aad0c7135bcc151f03bccb773be88fbf4823184e47fc76247"} */ - const isVM = this.executionContext.isVM() let execResult let returnValue = null if (isVM) { const hhlogs = await this.web3().eth.getHHLogsForTx(txResult.transactionHash) + if (hhlogs && hhlogs.length) { let finalLogs = 'console.log:\n' for (const log of hhlogs) { @@ -552,17 +630,19 @@ export class Blockchain extends Plugin { } } } - + if (!isVM && tx && tx.useCall) { returnValue = toBuffer(addHexPrefix(txResult.result)) } - + let address = null if (txResult && txResult.receipt) { address = txResult.receipt.contractAddress } - - cb(error, txResult, address, returnValue) - }) + + cb(null, txResult, address, returnValue) + } catch (error) { + cb(error) + } } } diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index 0868ef8689..bf8c5dccd3 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -19,8 +19,7 @@ const sensitiveCalls = { } export function isNative(name) { - const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'solidity-logic', - 'hardhat-provider', 'solidityStaticAnalysis', 'solidityUnitTesting', 'layout', 'notification', 'hardhat-provider', 'ganache-provider'] + const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'solidity-logic', 'solidityStaticAnalysis', 'solidityUnitTesting', 'layout', 'notification', 'hardhat-provider', 'ganache-provider'] return nativePlugins.includes(name) || requiredModules.includes(name) } diff --git a/apps/remix-ide/src/walkthroughService.js b/apps/remix-ide/src/walkthroughService.js index b9ffab4416..8f088c443c 100644 --- a/apps/remix-ide/src/walkthroughService.js +++ b/apps/remix-ide/src/walkthroughService.js @@ -33,7 +33,7 @@ export class WalkthroughService extends Plugin { { element: document.querySelector('#verticalIconsKindsolidity'), title: 'Solidity Compiler', - intro: 'Having selected a .sol file in the File Explorers (the icon above), compile it with the Solidity Compiler.', + intro: 'Having selected a .sol file in the File Explorer (the icon above), compile it with the Solidity Compiler.', tooltipClass: 'bg-light text-dark', position: 'right' }, diff --git a/libs/remix-core-plugin/src/lib/constants/uups.ts b/libs/remix-core-plugin/src/lib/constants/uups.ts new file mode 100644 index 0000000000..2fb521a999 --- /dev/null +++ b/libs/remix-core-plugin/src/lib/constants/uups.ts @@ -0,0 +1,91 @@ +export const UUPS = 'UUPSUpgradeable.sol' +export const UUPSBytecode = '608060405260405162000d8638038062000d86833981810160405281019062000029919062000467565b60017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd60001c6200005b9190620006a5565b60001b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b146200009357620000926200078a565b5b620000a782826000620000af60201b60201c565b5050620008f4565b620000c083620000f260201b60201c565b600082511180620000ce5750805b15620000ed57620000eb83836200014960201b620000371760201c565b505b505050565b62000103816200017f60201b60201c565b8073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b606062000177838360405180606001604052806027815260200162000d5f602791396200025560201b60201c565b905092915050565b62000195816200033960201b620000641760201c565b620001d7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620001ce90620005d0565b60405180910390fd5b80620002117f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b6200035c60201b620000871760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b606062000268846200033960201b60201c565b620002aa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620002a190620005f2565b60405180910390fd5b6000808573ffffffffffffffffffffffffffffffffffffffff1685604051620002d4919062000593565b600060405180830381855af49150503d806000811462000311576040519150601f19603f3d011682016040523d82523d6000602084013e62000316565b606091505b50915091506200032e8282866200036660201b60201c565b925050509392505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000819050919050565b606083156200037857829050620003cb565b6000835111156200038c5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620003c29190620005ac565b60405180910390fd5b9392505050565b6000620003e9620003e3846200063d565b62000614565b9050828152602081018484840111156200040857620004076200081c565b5b620004158482856200071e565b509392505050565b6000815190506200042e81620008da565b92915050565b600082601f8301126200044c576200044b62000817565b5b81516200045e848260208601620003d2565b91505092915050565b6000806040838503121562000481576200048062000826565b5b600062000491858286016200041d565b925050602083015167ffffffffffffffff811115620004b557620004b462000821565b5b620004c38582860162000434565b9150509250929050565b6000620004da8262000673565b620004e6818562000689565b9350620004f88185602086016200071e565b80840191505092915050565b600062000511826200067e565b6200051d818562000694565b93506200052f8185602086016200071e565b6200053a816200082b565b840191505092915050565b600062000554602d8362000694565b915062000561826200083c565b604082019050919050565b60006200057b60268362000694565b915062000588826200088b565b604082019050919050565b6000620005a18284620004cd565b915081905092915050565b60006020820190508181036000830152620005c8818462000504565b905092915050565b60006020820190508181036000830152620005eb8162000545565b9050919050565b600060208201905081810360008301526200060d816200056c565b9050919050565b60006200062062000633565b90506200062e828262000754565b919050565b6000604051905090565b600067ffffffffffffffff8211156200065b576200065a620007e8565b5b62000666826200082b565b9050602081019050919050565b600081519050919050565b600081519050919050565b600081905092915050565b600082825260208201905092915050565b6000620006b28262000714565b9150620006bf8362000714565b925082821015620006d557620006d4620007b9565b5b828203905092915050565b6000620006ed82620006f4565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60005b838110156200073e57808201518184015260208101905062000721565b838111156200074e576000848401525b50505050565b6200075f826200082b565b810181811067ffffffffffffffff82111715620007815762000780620007e8565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60008201527f6f74206120636f6e747261637400000000000000000000000000000000000000602082015250565b7f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60008201527f6e74726163740000000000000000000000000000000000000000000000000000602082015250565b620008e581620006e0565b8114620008f157600080fd5b50565b61045b80620009046000396000f3fe6080604052366100135761001161001d565b005b61001b61001d565b005b610025610091565b610035610030610093565b6100a2565b565b606061005c83836040518060600160405280602781526020016103ff602791396100c8565b905092915050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000819050919050565b565b600061009d610195565b905090565b3660008037600080366000845af43d6000803e80600081146100c3573d6000f35b3d6000fd5b60606100d384610064565b610112576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161010990610319565b60405180910390fd5b6000808573ffffffffffffffffffffffffffffffffffffffff168560405161013a91906102e0565b600060405180830381855af49150503d8060008114610175576040519150601f19603f3d011682016040523d82523d6000602084013e61017a565b606091505b509150915061018a8282866101ec565b925050509392505050565b60006101c37f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b610087565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606083156101fc5782905061024c565b60008351111561020f5782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161024391906102f7565b60405180910390fd5b9392505050565b600061025e82610339565b610268818561034f565b935061027881856020860161036b565b80840191505092915050565b600061028f82610344565b610299818561035a565b93506102a981856020860161036b565b6102b28161039e565b840191505092915050565b60006102ca60268361035a565b91506102d5826103af565b604082019050919050565b60006102ec8284610253565b915081905092915050565b600060208201905081810360008301526103118184610284565b905092915050565b60006020820190508181036000830152610332816102bd565b9050919050565b600081519050919050565b600081519050919050565b600081905092915050565b600082825260208201905092915050565b60005b8381101561038957808201518184015260208101905061036e565b83811115610398576000848401525b50505050565b6000601f19601f8301169050919050565b7f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60008201527f6e7472616374000000000000000000000000000000000000000000000000000060208201525056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212201fbb70b81fbc37a0d465e50bdaf6c661d6411918ae96ccedacef32b393f9533964736f6c63430008070033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564' +export const UUPSABI = [ + { + "inputs": [ + { + "internalType": "address", + "name": "_logic", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] +export const UUPSfunAbi = { + name: "", + inputs: [ + { + "internalType": "address", + "name": "_logic", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + type: "constructor", + outputs: [], + stateMutability: "payable" +} \ No newline at end of file diff --git a/libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts b/libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts index 13d5075670..2de757f4d2 100644 --- a/libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts +++ b/libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts @@ -1,26 +1,77 @@ import { Plugin } from '@remixproject/engine'; -import { ContractData } from '../types/contract'; +import { ContractABI, ContractAST, DeployOption } from '../types/contract'; +import { UUPS, UUPSABI, UUPSBytecode, UUPSfunAbi } from './constants/uups'; const proxyProfile = { name: 'openzeppelin-proxy', displayName: 'openzeppelin-proxy', description: 'openzeppelin-proxy', - methods: ['isConcerned', 'execute'] + methods: ['isConcerned', 'execute', 'getDeployOptions'] }; - export class OpenZeppelinProxy extends Plugin { blockchain: any + kind: 'UUPS' | 'Transparent' constructor(blockchain) { super(proxyProfile) this.blockchain = blockchain } - async isConcerned(contractData: ContractData): Promise { + async isConcerned(ast: ContractAST = {} as ContractAST): Promise { // check in the AST if it's an upgradable contract + if (ast.nodes && ast.nodes.find(node => node.absolutePath && node.absolutePath.includes(UUPS))) { + this.kind = 'UUPS' + return true + } + // + // else if transparent contract run check true/false + // return false } - async execute(contractData: ContractData, contractMetadata: any, compiledContracts: any) { + async getDeployOptions (contracts: ContractABI): Promise<{ [name: string]: DeployOption }> { + const inputs = {} + + if (this.kind === 'UUPS') { + Object.keys(contracts).map(name => { + const abi = contracts[name].abi + const initializeInput = abi.find(node => node.name === 'initialize') + + if (initializeInput) { + inputs[name] = { + inputs: initializeInput, + initializeInputs: this.blockchain.getInputs(initializeInput) + } + } + }) + } + return inputs + } + + async execute(implAddress: string, args: string | string [] = '', initializeABI, implementationContractObject): Promise { // deploy the proxy, or use an existing one + if (!initializeABI) throw new Error('Cannot deploy proxy: Missing initialize ABI') + args = args === '' ? [] : args + const _data = await this.blockchain.getEncodedFunctionHex(args || [], initializeABI) + + if (this.kind === 'UUPS') this.deployUUPSProxy(implAddress, _data, implementationContractObject) + } + + async deployUUPSProxy (implAddress: string, _data: string, implementationContractObject): Promise { + const args = [implAddress, _data] + const constructorData = await this.blockchain.getEncodedParams(args, UUPSfunAbi) + const proxyName = 'ERC1967Proxy' + const data = { + contractABI: UUPSABI, + contractByteCode: UUPSBytecode, + contractName: proxyName, + funAbi: UUPSfunAbi, + funArgs: args, + linkReferences: {}, + dataHex: UUPSBytecode + constructorData.replace('0x', '') + } + + // re-use implementation contract's ABI for UI display in udapp and change name to proxy name. + implementationContractObject.name = proxyName + this.blockchain.deployProxy(data, implementationContractObject) } } diff --git a/libs/remix-core-plugin/src/types/contract.ts b/libs/remix-core-plugin/src/types/contract.ts index 9903f92b98..92c32653b5 100644 --- a/libs/remix-core-plugin/src/types/contract.ts +++ b/libs/remix-core-plugin/src/types/contract.ts @@ -3,8 +3,8 @@ export interface FuncABI { type: string, inputs: { name: string, type: string }[], stateMutability: string, - payable: boolean, - constant: any + payable?: boolean, + constant?: any } export interface ContractData { @@ -20,4 +20,135 @@ export interface ContractData { getConstructorInputs: () => any, isOverSizeLimit: () => boolean, metadata: any -} \ No newline at end of file +} + +export interface ContractAST { + id: number, + absolutePath: string, + exportedSymbols: { + [key: string]: number[] + }, + license: string, + nodeType: string, + src: string, + nodes: { + id: number, + literals: string[], + nodeType: string, + src: string, + absolutePath?: string, + file?: string, + nameLocation?: string, + scope?: number, + srcUnit?: number, + unitAlias?: string, + symbolAliases?: any[], + abstract?: boolean, + baseContracts?: any[], + contractDependencies?: any[], + contractKind?: string, + fullyImplemented?: boolean, + linearizedBaseContracts?: number[], + name?: string, + usedErrors?: any[] + }[] +} + +export interface ContractABI { + [key: string]: { + abi: ({ + inputs: never[]; + stateMutability: string; + type: string; + anonymous?: undefined; + name?: undefined; + outputs?: undefined; + } | { + anonymous: boolean; + inputs: { + indexed: boolean; + internalType: string; + name: string; + type: string; + }[]; + name: string; + type: string; + stateMutability?: undefined; + outputs?: undefined; + } | { + inputs: { + internalType: string; + name: string; + type: string; + }[]; + name: string; + outputs: { + internalType: string; + name: string; + type: string; + }[]; + stateMutability: string; + type: string; + anonymous?: undefined; + })[]; + devdoc: { + kind: string; + methods: { + [key: string]: { + [key: string]: string + } + }; + version: number; + }; + evm: any + metadata: string; + storageLayout: { + storage: { + astId: number; + contract: string; + label: string; + offset: number; + slot: string; + type: string; + }[]; + types: { + [key: string]: { + base: string; + encoding: string; + label: string; + numberOfBytes: string; + members?: { + astId: number; + contract: string; + label: string; + offset: number; + slot: string; + type: string; + }[]; + }; + }; + }; + userdoc: { + kind: string; + methods: any; + version: number; + }; + }; +} + +export type DeployOption = { + initializeInputs: string, + inputs: { + inputs: { + internalType?: string, + name: string, + type: string + }[], + name: "initialize", + outputs?: any[], + stateMutability: string, + type: string, + payable?: boolean, + constant?: any + } + } diff --git a/libs/remix-lib/src/execution/forkAt.ts b/libs/remix-lib/src/execution/forkAt.ts index c5f1a1e981..8e45ce9acf 100644 --- a/libs/remix-lib/src/execution/forkAt.ts +++ b/libs/remix-lib/src/execution/forkAt.ts @@ -50,6 +50,14 @@ const forks = { { number: 12965000, name: 'london' + }, + { + number: 13773000, + name: 'arrowGlacier' + }, + { + number: 15050000, + name: 'grayGlacier' } ], 3: [ diff --git a/libs/remix-lib/src/execution/txFormat.ts b/libs/remix-lib/src/execution/txFormat.ts index 531eb99270..e8be0bafcd 100644 --- a/libs/remix-lib/src/execution/txFormat.ts +++ b/libs/remix-lib/src/execution/txFormat.ts @@ -38,26 +38,40 @@ export function encodeData (funABI, values, contractbyteCode) { export function encodeParams (params, funAbi, callback) { let data: Buffer | string = '' let dataHex = '' - let funArgs - if (params.indexOf('raw:0x') === 0) { + let funArgs = [] + if (Array.isArray(params)) { + funArgs = params + if (funArgs.length > 0) { + try { + data = encodeParamsHelper(funAbi, funArgs) + dataHex = data.toString() + } catch (e) { + return callback('Error encoding arguments: ' + e) + } + } + if (data.slice(0, 9) === 'undefined') { + dataHex = data.slice(9) + } + if (data.slice(0, 2) === '0x') { + dataHex = data.slice(2) + } + } else if (params.indexOf('raw:0x') === 0) { // in that case we consider that the input is already encoded and *does not* contain the method signature dataHex = params.replace('raw:0x', '') data = Buffer.from(dataHex, 'hex') } else { try { - params = params.replace(/(^|,\s+|,)(\d+)(\s+,|,|$)/g, '$1"$2"$3') // replace non quoted number by quoted number - params = params.replace(/(^|,\s+|,)(0[xX][0-9a-fA-F]+)(\s+,|,|$)/g, '$1"$2"$3') // replace non quoted hex string by quoted hex string - funArgs = JSON.parse('[' + params + ']') + funArgs = parseFunctionParams(params) } catch (e) { return callback('Error encoding arguments: ' + e) } - if (funArgs.length > 0) { - try { + try { + if (funArgs.length > 0) { data = encodeParamsHelper(funAbi, funArgs) dataHex = data.toString() - } catch (e) { - return callback('Error encoding arguments: ' + e) } + } catch (e) { + return callback('Error encoding arguments: ' + e) } if (data.slice(0, 9) === 'undefined') { dataHex = data.slice(9) @@ -396,7 +410,7 @@ export function decodeResponse (response, fnabi) { } export function parseFunctionParams (params) { - let args = [] + const args = [] // Check if parameter string starts with array or string let startIndex = isArrayOrStringStart(params, 0) ? -1 : 0 for (let i = 0; i < params.length; i++) { @@ -431,29 +445,27 @@ export function parseFunctionParams (params) { if (bracketCount !== 0 && j === params.length - 1) { throw new Error('invalid tuple params') } + if (bracketCount === 0) break } - // If bracketCount = 0, it means complete array/nested array parsed, push it to the arguments list - args.push(JSON.parse(params.substring(i, j))) + args.push(parseFunctionParams(params.substring(i + 1, j))) i = j - 1 - } else if (params.charAt(i) === ',') { - // if startIndex >= 0, it means a parameter was being parsed, it can be first or other parameter + } else if (params.charAt(i) === ',' || i === params.length - 1) { // , or end of string + // if startIndex >= 0, it means a parameter was being parsed, it can be first or other parameter if (startIndex >= 0) { - args.push(params.substring(startIndex, i)) + let param = params.substring(startIndex, i === params.length - 1 ? undefined : i) + const trimmed = param.trim() + if (param.startsWith('0x')) param = `${param}` + if (/[0-9]/g.test(trimmed)) param = `${trimmed}` + if (typeof param === 'string') { + if (trimmed === 'true') param = true + if (trimmed === 'false') param = false + } + args.push(param) } // Register start index of a parameter to parse startIndex = isArrayOrStringStart(params, i + 1) ? -1 : i + 1 - } else if (startIndex >= 0 && i === params.length - 1) { - // If start index is registered and string is completed (To handle last parameter) - args.push(params.substring(startIndex, params.length)) } } - args = args.map(e => { - if (!Array.isArray(e)) { - return e.trim() - } else { - return e - } - }) return args } diff --git a/libs/remix-lib/test/txFormat.ts b/libs/remix-lib/test/txFormat.ts index 8bff069fc2..364af74ae7 100644 --- a/libs/remix-lib/test/txFormat.ts +++ b/libs/remix-lib/test/txFormat.ts @@ -35,7 +35,7 @@ tape('ContractParameters - (TxFormat.buildData) - format input parameters', func function testWithInput (st, params, expected) { txFormat.buildData('uintContractTest', context.contract, context.output.contracts, true, context.contract.abi[0], params, (error, data) => { - if (error) { return st.fails(error) } + if (error) { return st.fail(error) } console.log(data) if (!data.dataHex.endsWith(expected)) { st.fail(`result of buildData ${data.dataHex} should end with ${expected} . `) @@ -62,7 +62,7 @@ tape('ContractStringParameters - (TxFormat.buildData) - format string input para function testWithStringInput (st, params, expected) { txFormat.buildData('stringContractTest', context.contract, context.output.contracts, true, context.contract.abi[0], params, (error, data) => { - if (error) { return st.fails(error) } + if (error) { return st.fail(error) } console.log(data) if (!data.dataHex.endsWith(expected)) { st.fail(`result of buildData ${data.dataHex} should end with ${expected} . `) @@ -88,7 +88,7 @@ tape('ContractArrayParameters - (TxFormat.buildData) - format array input parame function testWithArrayInput (st, params, expected) { txFormat.buildData('arrayContractTest', context.contract, context.output.contracts, true, context.contract.abi[0], params, (error, data) => { - if (error) { return st.fails(error) } + if (error) { return st.fail(error) } console.log(data) if (!data.dataHex.endsWith(expected)) { st.fail(`result of buildData ${data.dataHex} should end with ${expected} . `) @@ -113,7 +113,7 @@ tape('ContractNestedArrayParameters - (TxFormat.buildData) - format nested array function testWithNestedArrayInput (st, params, expected) { txFormat.buildData('nestedArrayContractTest', context.contract, context.output.contracts, true, context.contract.abi[4], params, (error, data) => { if (error) { - return st.fails(error) + return st.fail(error) } console.log(data) if (!data.dataHex.endsWith(expected)) { @@ -185,7 +185,7 @@ function testLinkLibrary (st, fakeDeployedContracts, callbackDeployLibraries) { const deployMsg = ['creation of library test.sol:lib1 pending...', 'creation of library test.sol:lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2 pending...'] txFormat.buildData('testContractLinkLibrary', context.contract, context.output.contracts, true, context.contract.abi[0], '', (error, data) => { - if (error) { return st.fails(error) } + if (error) { return st.fail(error) } console.log(data) const linkedbyteCode = data.dataHex let libReference = context.contract.evm.bytecode.linkReferences['test.sol']['lib1'] 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 25dd08705b..bd8008d0e3 100644 --- a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx @@ -331,7 +331,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { return { ...prevState, opt: { ...prevState.opt, debugWithGeneratedSources: checked } } }) }} type="checkbox" title="Debug with generated sources" /> - + { state.isLocalNodeUsed &&
{ diff --git a/libs/remix-ui/helper/src/lib/helper-components.tsx b/libs/remix-ui/helper/src/lib/helper-components.tsx index c290f7bdf9..7cf79c9a46 100644 --- a/libs/remix-ui/helper/src/lib/helper-components.tsx +++ b/libs/remix-ui/helper/src/lib/helper-components.tsx @@ -84,3 +84,13 @@ export const recursivePasteToastMsg = () => ( File(s) to paste is an ancestor of the destination folder
) + +export const logBuilder = (msg: string) => { + return
{msg}
+} + +export const cancelProxyMsg = () => ( +
+ Proxy deployment cancelled. +
+) diff --git a/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx b/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx index 05f7c32125..2690dfc840 100644 --- a/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx +++ b/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx @@ -54,13 +54,16 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => { contentImport.import( state.importSource, (loadingMsg) => dispatch({ tooltip: loadingMsg }), - (error, content, cleanUrl, type, url) => { + async (error, content, cleanUrl, type, url) => { if (error) { toast(error.message || error) } else { try { - workspace.addExternal(type + '/' + cleanUrl, content, url) - plugin.call('menuicons', 'select', 'filePanel') + if (await workspace.exists(type + '/' + cleanUrl)) toast('File already exists in workspace') + else { + workspace.addExternal(type + '/' + cleanUrl, content, url) + plugin.call('menuicons', 'select', 'filePanel') + } } catch (e) { toast(e.message) } diff --git a/libs/remix-ui/run-tab/src/lib/actions/account.ts b/libs/remix-ui/run-tab/src/lib/actions/account.ts new file mode 100644 index 0000000000..9fba9a0723 --- /dev/null +++ b/libs/remix-ui/run-tab/src/lib/actions/account.ts @@ -0,0 +1,135 @@ +import { shortenAddress, web3Dialog } from "@remix-ui/helper" +import { RunTab } from "../types/run-tab" +import { clearInstances, setAccount, setExecEnv } from "./actions" +import { displayNotification, displayPopUp, fetchAccountsListFailed, fetchAccountsListRequest, fetchAccountsListSuccess, setExternalEndpoint, setMatchPassphrase, setPassphrase } from "./payload" + +export const updateAccountBalances = (plugin: RunTab, dispatch: React.Dispatch) => { + const accounts = plugin.REACT_API.accounts.loadedAccounts + + Object.keys(accounts).map((value) => { + plugin.blockchain.getBalanceInEther(value, (err, balance) => { + if (err) return + const updated = shortenAddress(value, balance) + + accounts[value] = updated + }) + }) + dispatch(fetchAccountsListSuccess(accounts)) +} + +export const fillAccountsList = async (plugin: RunTab, dispatch: React.Dispatch) => { + try { + dispatch(fetchAccountsListRequest()) + const promise = plugin.blockchain.getAccounts() + + promise.then(async (accounts: string[]) => { + const loadedAccounts = {} + + if (!accounts) accounts = [] + // allSettled is undefined.. + // so the current promise (all) will finish when: + // - all the promises resolve + // - at least one reject + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all + await (Promise as any).all(accounts.map((account) => { + return new Promise((resolve, reject) => { + plugin.blockchain.getBalanceInEther(account, (err, balance) => { + if (err) return reject(err) + const updated = shortenAddress(account, balance) + + loadedAccounts[account] = updated + resolve(account) + }) + }) + })) + const provider = plugin.blockchain.getProvider() + + if (provider === 'injected') { + const selectedAddress = plugin.blockchain.getInjectedWeb3Address() + + if (!(Object.keys(loadedAccounts).includes(selectedAddress))) setAccount(dispatch, null) + } + dispatch(fetchAccountsListSuccess(loadedAccounts)) + }).catch((e) => { + dispatch(fetchAccountsListFailed(e.message)) + }) + } catch (e) { + dispatch(displayPopUp(`Cannot get account list: ${e}`)) + } +} + +export const setFinalContext = (plugin: RunTab, dispatch: React.Dispatch) => { + // set the final context. Cause it is possible that this is not the one we've originaly selected + const value = _getProviderDropdownValue(plugin) + + setExecEnv(dispatch, value) + clearInstances(dispatch) +} + +const _getProviderDropdownValue = (plugin: RunTab): string => { + const provider = plugin.blockchain.getProvider() + const fork = plugin.blockchain.getCurrentFork() + + return provider === 'vm' ? provider + '-' + fork : provider +} + +export const setExecutionContext = (plugin: RunTab, dispatch: React.Dispatch, executionContext: { context: string, fork: string }) => { + const displayContent = web3Dialog(plugin.REACT_API.externalEndpoint, (endpoint: string) => { + dispatch(setExternalEndpoint(endpoint)) + }) + + plugin.blockchain.changeExecutionContext(executionContext, () => { + plugin.call('notification', 'modal', { + id: 'envNotification', + title: 'External node request', + message: displayContent, + okLabel: 'OK', + cancelLabel: 'Cancel', + okFn: () => { + plugin.blockchain.setProviderFromEndpoint(plugin.REACT_API.externalEndpoint, executionContext, (alertMsg) => { + if (alertMsg) plugin.call('notification', 'toast', alertMsg) + setFinalContext(plugin, dispatch) + }) + }, + cancelFn: () => { + setFinalContext(plugin, dispatch) + } + }) + }, (alertMsg) => { + plugin.call('notification', 'toast', alertMsg) + }, () => { setFinalContext(plugin, dispatch) }) +} + +export const createNewBlockchainAccount = async (plugin: RunTab, dispatch: React.Dispatch, cbMessage: JSX.Element) => { + plugin.blockchain.newAccount( + '', + (cb) => { + dispatch(displayNotification('Enter Passphrase', cbMessage, 'OK', 'Cancel', async () => { + if (plugin.REACT_API.passphrase === plugin.REACT_API.matchPassphrase) { + cb(plugin.REACT_API.passphrase) + } else { + dispatch(displayNotification('Error', 'Passphase does not match', 'OK', null)) + } + setPassphrase('') + setMatchPassphrase('') + }, () => {})) + }, + async (error, address) => { + if (error) { + return dispatch(displayPopUp('Cannot create an account: ' + error)) + } + dispatch(displayPopUp(`account ${address} created`)) + await fillAccountsList(plugin, dispatch) + } + ) +} + + +export const signMessageWithAddress = (plugin: RunTab, dispatch: React.Dispatch, account: string, message: string, modalContent: (hash: string, data: string) => JSX.Element, passphrase?: string) => { + plugin.blockchain.signMessage(message, account, passphrase, (err, msgHash, signedData) => { + if (err) { + return displayPopUp(err) + } + dispatch(displayNotification('Signed Message', modalContent(msgHash, signedData), 'OK', null, () => {}, null)) + }) +} \ No newline at end of file diff --git a/libs/remix-ui/run-tab/src/lib/actions/actions.ts b/libs/remix-ui/run-tab/src/lib/actions/actions.ts new file mode 100644 index 0000000000..a99a8b3800 --- /dev/null +++ b/libs/remix-ui/run-tab/src/lib/actions/actions.ts @@ -0,0 +1,96 @@ +import { ContractData } from "@remix-project/core-plugin" +import { addNewInstance, addProvider, clearAllInstances, clearRecorderCount, hidePopUp, removeExistingInstance, removeProvider, setBaseFeePerGas, setConfirmSettings, setCurrentContract, setExecutionEnvironment, setExternalEndpoint, setGasLimit, setGasPrice, setGasPriceStatus, setMatchPassphrase, setMaxFee, setMaxPriorityFee, setNetworkName, setPassphrase, setPathToScenario, setSelectedAccount, setSendUnit, setSendValue, setTxFeeContent } from "./payload" + +export const setAccount = (dispatch: React.Dispatch, account: string) => { + dispatch(setSelectedAccount(account)) +} + +export const setUnit = (dispatch: React.Dispatch, unit: 'ether' | 'finney' | 'gwei' | 'wei') => { + dispatch(setSendUnit(unit)) +} + +export const setGasFee = (dispatch: React.Dispatch, value: number) => { + dispatch(setGasLimit(value)) +} + +export const setExecEnv = (dispatch: React.Dispatch, env: string) => { + dispatch(setExecutionEnvironment(env)) +} + +export const setNetworkNameFromProvider = (dispatch: React.Dispatch, networkName: string) => { + dispatch(setNetworkName(networkName)) +} + +export const addExternalProvider = (dispatch: React.Dispatch, network) => { + dispatch(addProvider(network)) +} + +export const removeExternalProvider = (dispatch: React.Dispatch, name) => { + dispatch(removeProvider(name)) +} + +export const clearPopUp = async (dispatch: React.Dispatch) => { + dispatch(hidePopUp()) +} + +export const setPassphrasePrompt = (dispatch: React.Dispatch, passphrase: string) => { + dispatch(setPassphrase(passphrase)) +} + +export const setMatchPassphrasePrompt = (dispatch: React.Dispatch, passphrase: string) => { + dispatch(setMatchPassphrase(passphrase)) +} + +export const updateGasPriceStatus = (dispatch: React.Dispatch, status: boolean) => { + dispatch(setGasPriceStatus(status)) +} + +export const updateConfirmSettings = (dispatch: React.Dispatch, confirmation: boolean) => { + dispatch(setConfirmSettings(confirmation)) +} + +export const updateMaxFee = (dispatch: React.Dispatch, fee: string) => { + dispatch(setMaxFee(fee)) +} + +export const updateMaxPriorityFee = (dispatch: React.Dispatch, fee: string) => { + dispatch(setMaxPriorityFee(fee)) +} + +export const updateBaseFeePerGas = (dispatch: React.Dispatch, baseFee: string) => { + dispatch(setBaseFeePerGas(baseFee)) +} + +export const updateGasPrice = (dispatch: React.Dispatch, price: string) => { + dispatch(setGasPrice(price)) +} + +export const updateTxFeeContent = (dispatch: React.Dispatch, content: string) => { + dispatch(setTxFeeContent(content)) +} + +export const addInstance = (dispatch: React.Dispatch, instance: { contractData?: ContractData, address: string, name: string, abi?: any, decodedResponse?: Record }) => { + instance.decodedResponse = {} + dispatch(addNewInstance(instance)) +} + +export const removeInstance = (dispatch: React.Dispatch, index: number) => { + dispatch(removeExistingInstance(index)) +} + +export const clearInstances = (dispatch: React.Dispatch) => { + dispatch(clearAllInstances()) + dispatch(clearRecorderCount()) +} + +export const setSelectedContract = (dispatch: React.Dispatch, contractName: string) => { + dispatch(setCurrentContract(contractName)) +} + +export const updateScenarioPath = (dispatch: React.Dispatch, path: string) => { + dispatch(setPathToScenario(path)) +} + +export const setSendTransactionValue = (dispatch: React.Dispatch, value: string) => { + dispatch(setSendValue(value)) +} \ No newline at end of file diff --git a/libs/remix-ui/run-tab/src/lib/actions/deploy.ts b/libs/remix-ui/run-tab/src/lib/actions/deploy.ts new file mode 100644 index 0000000000..ce7f5f9567 --- /dev/null +++ b/libs/remix-ui/run-tab/src/lib/actions/deploy.ts @@ -0,0 +1,300 @@ +import { ContractData, FuncABI } from "@remix-project/core-plugin" +import { RunTab } from "../types/run-tab" +import { CompilerAbstract as CompilerAbstractType } from '@remix-project/remix-solidity-ts' +import * as remixLib from '@remix-project/remix-lib' +import { DeployMode, MainnetPrompt } from "../types" +import { displayNotification, displayPopUp, setDecodedResponse } from "./payload" +import { addInstance } from "./actions" +import { addressToString, logBuilder } from "@remix-ui/helper" + +declare global { + interface Window { + _paq: any + } +} + +const _paq = window._paq = window._paq || [] //eslint-disable-line +const txHelper = remixLib.execution.txHelper +const txFormat = remixLib.execution.txFormat + +const loadContractFromAddress = (plugin: RunTab, address, confirmCb, cb) => { + if (/.(.abi)$/.exec(plugin.config.get('currentFile'))) { + confirmCb(() => { + let abi + try { + abi = JSON.parse(plugin.editor.currentContent()) + } catch (e) { + return cb('Failed to parse the current file as JSON ABI.') + } + _paq.push(['trackEvent', 'udapp', 'AtAddressLoadWithABI']) + cb(null, 'abi', abi) + }) + } else { + _paq.push(['trackEvent', 'udapp', 'AtAddressLoadWithArtifacts']) + cb(null, 'instance') + } +} + +export const getSelectedContract = (contractName: string, compiler: CompilerAbstractType): ContractData => { + if (!contractName) return null + // const compiler = plugin.compilersArtefacts[compilerAtributeName] + + if (!compiler) return null + + const contract = compiler.getContract(contractName) + + return { + name: contractName, + contract: contract, + compiler: compiler, + abi: contract.object.abi, + bytecodeObject: contract.object.evm.bytecode.object, + bytecodeLinkReferences: contract.object.evm.bytecode.linkReferences, + object: contract.object, + deployedBytecode: contract.object.evm.deployedBytecode, + getConstructorInterface: () => { + return txHelper.getConstructorInterface(contract.object.abi) + }, + getConstructorInputs: () => { + const constructorInteface = txHelper.getConstructorInterface(contract.object.abi) + + return txHelper.inputParametersDeclarationToString(constructorInteface.inputs) + }, + isOverSizeLimit: () => { + const deployedBytecode = contract.object.evm.deployedBytecode + + return (deployedBytecode && deployedBytecode.object.length / 2 > 24576) + }, + metadata: contract.object.metadata + } +} + +const getCompilerContracts = (plugin: RunTab) => { + return plugin.compilersArtefacts.__last.getData().contracts +} + +export const terminalLogger = (plugin: RunTab, view: JSX.Element) => { + plugin.call('terminal', 'logHtml', view) +} + +export const confirmationHandler = (plugin: RunTab, dispatch: React.Dispatch, confirmDialogContent: MainnetPrompt, network, tx, gasEstimation, continueTxExecution, cancelCb) => { + if (network.name !== 'Main') { + return continueTxExecution(null) + } + const amount = plugin.blockchain.fromWei(tx.value, true, 'ether') + const content = confirmDialogContent(tx, network, amount, gasEstimation, plugin.blockchain.determineGasFees(tx), plugin.blockchain.determineGasPrice.bind(plugin.blockchain)) + + dispatch(displayNotification('Confirm transaction', content, 'Confirm', 'Cancel', () => { + plugin.blockchain.config.setUnpersistedProperty('doNotShowTransactionConfirmationAgain', plugin.REACT_API.confirmSettings) + // TODO: check if this is check is still valid given the refactor + if (!plugin.REACT_API.gasPriceStatus) { + cancelCb('Given transaction fee is not correct') + } else { + continueTxExecution({ maxFee: plugin.REACT_API.maxFee, maxPriorityFee: plugin.REACT_API.maxPriorityFee, baseFeePerGas: plugin.REACT_API.baseFeePerGas, gasPrice: plugin.REACT_API.gasPrice }) + } + }, () => { + return cancelCb('Transaction canceled by user.') + })) +} + +const getConfirmationCb = (plugin: RunTab, dispatch: React.Dispatch, confirmDialogContent: MainnetPrompt) => { + // this code is the same as in recorder.js. TODO need to be refactored out + return (network, tx, gasEstimation, continueTxExecution, cancelCb) => { + confirmationHandler(plugin, dispatch, confirmDialogContent, network, tx, gasEstimation, continueTxExecution, cancelCb) + } +} + +export const continueHandler = (dispatch: React.Dispatch, gasEstimationPrompt: (msg: string) => JSX.Element, error, continueTxExecution, cancelCb) => { + if (error) { + const msg = typeof error !== 'string' ? error.message : error + + dispatch(displayNotification('Gas estimation failed', gasEstimationPrompt(msg), 'Send Transaction', 'Cancel Transaction', () => { + continueTxExecution() + }, () => { + cancelCb() + })) + } else { + continueTxExecution() + } +} + +export const promptHandler = (dispatch: React.Dispatch, passphrasePrompt, okCb, cancelCb) => { + dispatch(displayNotification('Passphrase requested', passphrasePrompt('Personal mode is enabled. Please provide passphrase of account'), 'OK', 'Cancel', okCb, cancelCb)) +} + +export const createInstance = async ( + plugin: RunTab, + dispatch: React.Dispatch, + selectedContract: ContractData, + gasEstimationPrompt: (msg: string) => JSX.Element, + passphrasePrompt: (msg: string) => JSX.Element, + publishToStorage: (storage: 'ipfs' | 'swarm', + contract: ContractData) => void, + mainnetPrompt: MainnetPrompt, + isOverSizePrompt: () => JSX.Element, + args, + deployMode: DeployMode[]) => { + const isProxyDeployment = (deployMode || []).find(mode => mode === 'Deploy with Proxy') + const statusCb = (msg: string) => { + const log = logBuilder(msg) + + return terminalLogger(plugin, log) + } + + const finalCb = (error, contractObject, address) => { + if (error) { + const log = logBuilder(error) + + return terminalLogger(plugin, log) + } + addInstance(dispatch, { contractData: contractObject, address, name: contractObject.name }) + const data = plugin.compilersArtefacts.getCompilerAbstract(contractObject.contract.file) + + plugin.compilersArtefacts.addResolvedContract(addressToString(address), data) + if (plugin.REACT_API.ipfsChecked) { + _paq.push(['trackEvent', 'udapp', 'DeployAndPublish', plugin.REACT_API.networkName]) + publishToStorage('ipfs', selectedContract) + } else { + _paq.push(['trackEvent', 'udapp', 'DeployOnly', plugin.REACT_API.networkName]) + } + if (isProxyDeployment) { + const initABI = contractObject.abi.find(abi => abi.name === 'initialize') + + plugin.call('openzeppelin-proxy', 'execute', addressToString(address), args, initABI, contractObject) + } + } + + let contractMetadata + try { + contractMetadata = await plugin.call('compilerMetadata', 'deployMetadataOf', selectedContract.name, selectedContract.contract.file) + } catch (error) { + return statusCb(`creation of ${selectedContract.name} errored: ${error.message ? error.message : error}`) + } + + const compilerContracts = getCompilerContracts(plugin) + const confirmationCb = getConfirmationCb(plugin, dispatch, mainnetPrompt) + + if (selectedContract.isOverSizeLimit()) { + return dispatch(displayNotification('Contract code size over limit', isOverSizePrompt(), 'Force Send', 'Cancel', () => { + deployContract(plugin, selectedContract, !isProxyDeployment ? args : '', contractMetadata, compilerContracts, { + continueCb: (error, continueTxExecution, cancelCb) => { + continueHandler(dispatch, gasEstimationPrompt, error, continueTxExecution, cancelCb) + }, + promptCb: (okCb, cancelCb) => { + promptHandler(dispatch, passphrasePrompt, okCb, cancelCb) + }, + statusCb, + finalCb + }, confirmationCb) + }, () => { + const log = logBuilder(`creation of ${selectedContract.name} canceled by user.`) + + return terminalLogger(plugin, log) + })) + } + deployContract(plugin, selectedContract, !isProxyDeployment ? args : '', contractMetadata, compilerContracts, { + continueCb: (error, continueTxExecution, cancelCb) => { + continueHandler(dispatch, gasEstimationPrompt, error, continueTxExecution, cancelCb) + }, + promptCb: (okCb, cancelCb) => { + promptHandler(dispatch, passphrasePrompt, okCb, cancelCb) + }, + statusCb, + finalCb + }, confirmationCb) +} + +const deployContract = (plugin: RunTab, selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb) => { + _paq.push(['trackEvent', 'udapp', 'DeployContractTo', plugin.REACT_API.networkName]) + const { statusCb } = callbacks + + if (!contractMetadata || (contractMetadata && contractMetadata.autoDeployLib)) { + return plugin.blockchain.deployContractAndLibraries(selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb) + } + if (Object.keys(selectedContract.bytecodeLinkReferences).length) statusCb(`linking ${JSON.stringify(selectedContract.bytecodeLinkReferences, null, '\t')} using ${JSON.stringify(contractMetadata.linkReferences, null, '\t')}`) + plugin.blockchain.deployContractWithLibrary(selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb) +} + +export const loadAddress = (plugin: RunTab, dispatch: React.Dispatch, contract: ContractData, address: string) => { + loadContractFromAddress(plugin, address, + (cb) => { + dispatch(displayNotification('At Address', `Do you really want to interact with ${address} using the current ABI definition?`, 'OK', 'Cancel', cb, null)) + }, + (error, loadType, abi) => { + if (error) { + return dispatch(displayNotification('Alert', error, 'OK', null)) + } + if (loadType === 'abi') { + return addInstance(dispatch, { abi, address, name: '' }) + } else if (loadType === 'instance') { + if (!contract) return dispatch(displayPopUp('No compiled contracts found.')) + const currentFile = plugin.REACT_API.contracts.currentFile + const compiler = plugin.REACT_API.contracts.contractList[currentFile].find(item => item.alias === contract.name) + const contractData = getSelectedContract(contract.name, compiler.compiler) + return addInstance(dispatch, { contractData, address, name: contract.name }) + } + } + ) + } + +export const getContext = (plugin: RunTab) => { + return plugin.blockchain.context() +} + +export const runTransactions = ( + plugin: RunTab, + dispatch: React.Dispatch, + instanceIndex: number, + lookupOnly: boolean, + funcABI: FuncABI, + inputsValues: string, + contractName: string, + contractABI, contract, + address, + logMsg:string, + mainnetPrompt: MainnetPrompt, + gasEstimationPrompt: (msg: string) => JSX.Element, + passphrasePrompt: (msg: string) => JSX.Element, + funcIndex?: number) => { + let callinfo = '' + if (lookupOnly) callinfo = 'call' + else if (funcABI.type === 'fallback' || funcABI.type === 'receive') callinfo = 'lowLevelInteracions' + else callinfo = 'transact' + _paq.push(['trackEvent', 'udapp', callinfo, plugin.blockchain.getCurrentNetworkStatus().network.name]) + + const params = funcABI.type !== 'fallback' ? inputsValues : '' + plugin.blockchain.runOrCallContractMethod( + contractName, + contractABI, + funcABI, + contract, + inputsValues, + address, + params, + lookupOnly, + logMsg, + (msg) => { + const log = logBuilder(msg) + + return terminalLogger(plugin, log) + }, + (returnValue) => { + const response = txFormat.decodeResponse(returnValue, funcABI) + + dispatch(setDecodedResponse(instanceIndex, response, funcIndex)) + }, + (network, tx, gasEstimation, continueTxExecution, cancelCb) => { + confirmationHandler(plugin, dispatch, mainnetPrompt, network, tx, gasEstimation, continueTxExecution, cancelCb) + }, + (error, continueTxExecution, cancelCb) => { + continueHandler(dispatch, gasEstimationPrompt, error, continueTxExecution, cancelCb) + }, + (okCb, cancelCb) => { + promptHandler(dispatch, passphrasePrompt, okCb, cancelCb) + } + ) +} + +export const getFuncABIInputs = (plugin: RunTab, funcABI: FuncABI) => { + return plugin.blockchain.getInputs(funcABI) +} \ No newline at end of file diff --git a/libs/remix-ui/run-tab/src/lib/actions/events.ts b/libs/remix-ui/run-tab/src/lib/actions/events.ts new file mode 100644 index 0000000000..f8d74dc359 --- /dev/null +++ b/libs/remix-ui/run-tab/src/lib/actions/events.ts @@ -0,0 +1,153 @@ +import { envChangeNotification } from "@remix-ui/helper" +import { RunTab } from "../types/run-tab" +import { setExecutionContext, setFinalContext, updateAccountBalances } from "./account" +import { addExternalProvider, addInstance, removeExternalProvider, setNetworkNameFromProvider } from "./actions" +import { clearAllInstances, clearRecorderCount, fetchContractListSuccess, resetUdapp, setCurrentContract, setCurrentFile, setDeployOptions, setLoadType, setRecorderCount, setSendValue } from "./payload" +import { CompilerAbstract } from '@remix-project/remix-solidity' +import * as ethJSUtil from 'ethereumjs-util' +import Web3 from 'web3' + +export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch) => { + plugin.blockchain.events.on('newTransaction', (tx, receipt) => { + plugin.emit('newTransaction', tx, receipt) + }) + + plugin.blockchain.event.register('transactionExecuted', (error, from, to, data, lookupOnly, txResult) => { + if (!lookupOnly) dispatch(setSendValue('0')) + if (error) return + updateAccountBalances(plugin, dispatch) + }) + + plugin.blockchain.event.register('contextChanged', (context, silent) => { + setFinalContext(plugin, dispatch) + }) + + plugin.blockchain.event.register('networkStatus', ({ error, network }) => { + if (error) { + const netUI = 'can\'t detect network ' + setNetworkNameFromProvider(dispatch, netUI) + + return + } + const networkProvider = plugin.networkModule.getNetworkProvider.bind(plugin.networkModule) + const netUI = (networkProvider() !== 'vm') ? `${network.name} (${network.id || '-'}) network` : 'VM' + + setNetworkNameFromProvider(dispatch, netUI) + }) + + plugin.blockchain.event.register('addProvider', provider => addExternalProvider(dispatch, provider)) + + plugin.blockchain.event.register('removeProvider', name => removeExternalProvider(dispatch, name)) + + plugin.on('solidity', 'compilationFinished', (file, source, languageVersion, data, input, version) => broadcastCompilationResult(plugin, dispatch, file, source, languageVersion, data, input)) + + plugin.on('vyper', 'compilationFinished', (file, source, languageVersion, data) => broadcastCompilationResult(plugin, dispatch, file, source, languageVersion, data)) + + plugin.on('lexon', 'compilationFinished', (file, source, languageVersion, data) => broadcastCompilationResult(plugin, dispatch, file, source, languageVersion, data)) + + plugin.on('yulp', 'compilationFinished', (file, source, languageVersion, data) => broadcastCompilationResult(plugin, dispatch, file, source, languageVersion, data)) + + plugin.on('nahmii-compiler', 'compilationFinished', (file, source, languageVersion, data) => broadcastCompilationResult(plugin, dispatch, file, source, languageVersion, data)) + + plugin.on('udapp', 'setEnvironmentModeReducer', (env: { context: string, fork: string }, from: string) => { + plugin.call('notification', 'toast', envChangeNotification(env, from)) + setExecutionContext(plugin, dispatch, env) + }) + + plugin.on('udapp', 'clearAllInstancesReducer', () => { + dispatch(clearAllInstances()) + }) + + plugin.on('udapp', 'addInstanceReducer', (address, abi, name) => { + addInstance(dispatch, { abi, address, name }) + }) + + plugin.on('filePanel', 'setWorkspace', () => { + dispatch(resetUdapp()) + resetAndInit(plugin) + }) + + plugin.fileManager.events.on('currentFileChanged', (currentFile: string) => { + if (/.(.abi)$/.exec(currentFile)) { + dispatch(setLoadType('abi')) + } else if (/.(.sol)$/.exec(currentFile) || + /.(.vy)$/.exec(currentFile) || // vyper + /.(.lex)$/.exec(currentFile) || // lexon + /.(.contract)$/.exec(currentFile)) { + dispatch(setLoadType('sol')) + } else { + dispatch(setLoadType('other')) + } + dispatch(setCurrentFile(currentFile)) + }) + + plugin.recorder.event.register('recorderCountChange', (count) => { + dispatch(setRecorderCount(count)) + }) + + plugin.event.register('cleared', () => { + dispatch(clearRecorderCount()) + }) +} + +const broadcastCompilationResult = async (plugin: RunTab, dispatch: React.Dispatch, file, source, languageVersion, data, input?) => { + // TODO check whether the tab is configured + const compiler = new CompilerAbstract(languageVersion, data, source, input) + + plugin.compilersArtefacts[languageVersion] = compiler + plugin.compilersArtefacts.__last = compiler + + const contracts = getCompiledContracts(compiler).map((contract) => { + return { name: languageVersion, alias: contract.name, file: contract.file, compiler } + }) + const index = contracts.findIndex(contract => contract.alias === plugin.REACT_API.contracts.currentContract) + + if ((index < 0) && (contracts.length > 0)) dispatch(setCurrentContract(contracts[0].alias)) + const isUpgradeable = await plugin.call('openzeppelin-proxy', 'isConcerned', data.sources[file] ? data.sources[file].ast : {}) + + if (isUpgradeable) { + const options = await plugin.call('openzeppelin-proxy', 'getDeployOptions', data.contracts[file]) + + dispatch(setDeployOptions({ options: [{ title: 'Deploy with Proxy', active: false }], initializeOptions: options })) + } + else dispatch(setDeployOptions({} as any)) + dispatch(fetchContractListSuccess({ [file]: contracts })) + dispatch(setCurrentFile(file)) + // TODO: set current contract +} + +const getCompiledContracts = (compiler) => { + const contracts = [] + + compiler.visitContracts((contract) => { + contracts.push(contract) + }) + return contracts +} + +export const resetAndInit = (plugin: RunTab) => { + plugin.blockchain.resetAndInit(plugin.config, { + getAddress: (cb) => { + cb(null, plugin.REACT_API.accounts.selectedAccount) + }, + getValue: (cb) => { + try { + const number = plugin.REACT_API.sendValue + const unit = plugin.REACT_API.sendUnit + + cb(null, Web3.utils.toWei(number, unit)) + } catch (e) { + cb(e) + } + }, + getGasLimit: (cb) => { + try { + const gasLimit = '0x' + new ethJSUtil.BN(plugin.REACT_API.gasLimit, 10).toString(16) + + cb(null, gasLimit) + } catch (e) { + cb(e.message) + } + } + }) +} \ No newline at end of file diff --git a/libs/remix-ui/run-tab/src/lib/actions/index.ts b/libs/remix-ui/run-tab/src/lib/actions/index.ts index 030f0669fa..5dc0eb2de7 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/index.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/index.ts @@ -1,17 +1,15 @@ // eslint-disable-next-line no-unused-vars import React from 'react' -import * as ethJSUtil from 'ethereumjs-util' -import Web3 from 'web3' -import { addressToString, createNonClashingNameAsync, envChangeNotification, extractNameFromKey, shortenAddress, web3Dialog } from '@remix-ui/helper' -import { addNewInstance, addProvider, clearAllInstances, clearRecorderCount, displayNotification, displayPopUp, fetchAccountsListFailed, fetchAccountsListRequest, fetchAccountsListSuccess, fetchContractListSuccess, hidePopUp, removeExistingInstance, removeProvider, resetUdapp, setBaseFeePerGas, setConfirmSettings, setCurrentFile, setDecodedResponse, setEnvToasterContent, setExecutionEnvironment, setExternalEndpoint, setGasLimit, setGasPrice, setGasPriceStatus, setLoadType, setMatchPassphrase, setMaxFee, setMaxPriorityFee, setNetworkName, setPassphrase, setPathToScenario, setRecorderCount, setSelectedAccount, setSendUnit, setSendValue, setTxFeeContent } from './payload' import { RunTab } from '../types/run-tab' -import { CompilerAbstract } from '@remix-project/remix-solidity' -import * as remixLib from '@remix-project/remix-lib' -import { MainnetPrompt } from '../types' -import { ContractData, FuncABI, } from '@remix-project/core-plugin' +import { resetAndInit, setupEvents } from './events' +import { createNewBlockchainAccount, fillAccountsList, setExecutionContext, signMessageWithAddress } from './account' +import { clearInstances, clearPopUp, removeInstance, setAccount, setGasFee, setMatchPassphrasePrompt, setNetworkNameFromProvider, setPassphrasePrompt, setSelectedContract, setSendTransactionValue, setUnit, updateBaseFeePerGas, updateConfirmSettings, updateGasPrice, updateGasPriceStatus, updateMaxFee, updateMaxPriorityFee, updateScenarioPath, updateTxFeeContent } from './actions' +import { createInstance, getContext, getFuncABIInputs, getSelectedContract, loadAddress, runTransactions } from './deploy' import { CompilerAbstract as CompilerAbstractType } from '@remix-project/remix-solidity-ts' +import { ContractData, FuncABI } from "@remix-project/core-plugin" +import { DeployMode, MainnetPrompt } from '../types' +import { runCurrentScenario, storeScenario } from './recorder' -const txFormat = remixLib.execution.txFormat declare global { interface Window { _paq: any @@ -19,709 +17,45 @@ declare global { } const _paq = window._paq = window._paq || [] //eslint-disable-line -const txHelper = remixLib.execution.txHelper let plugin: RunTab, dispatch: React.Dispatch export const initRunTab = (udapp: RunTab) => async (reducerDispatch: React.Dispatch) => { plugin = udapp dispatch = reducerDispatch - resetAndInit() - setupEvents() + resetAndInit(plugin) + setupEvents(plugin, dispatch) setInterval(() => { - fillAccountsList() + fillAccountsList(plugin, dispatch) }, 1000) } -const setupEvents = () => { - plugin.blockchain.events.on('newTransaction', (tx, receipt) => { - plugin.emit('newTransaction', tx, receipt) - }) - - plugin.blockchain.event.register('transactionExecuted', (error, from, to, data, lookupOnly, txResult) => { - if (!lookupOnly) dispatch(setSendValue('0')) - if (error) return - updateAccountBalances() - }) - - plugin.blockchain.event.register('contextChanged', (context, silent) => { - setFinalContext() - }) - - plugin.blockchain.event.register('networkStatus', ({ error, network }) => { - if (error) { - const netUI = 'can\'t detect network ' - setNetworkNameFromProvider(netUI) - - return - } - const networkProvider = plugin.networkModule.getNetworkProvider.bind(plugin.networkModule) - const netUI = (networkProvider() !== 'vm') ? `${network.name} (${network.id || '-'}) network` : 'VM' - - setNetworkNameFromProvider(netUI) - }) - - plugin.blockchain.event.register('addProvider', provider => addExternalProvider(provider)) - - plugin.blockchain.event.register('removeProvider', name => removeExternalProvider(name)) - - plugin.on('solidity', 'compilationFinished', (file, source, languageVersion, data, input, version) => broadcastCompilationResult(file, source, languageVersion, data, input)) - - plugin.on('vyper', 'compilationFinished', (file, source, languageVersion, data) => broadcastCompilationResult(file, source, languageVersion, data)) - - plugin.on('lexon', 'compilationFinished', (file, source, languageVersion, data) => broadcastCompilationResult(file, source, languageVersion, data)) - - plugin.on('yulp', 'compilationFinished', (file, source, languageVersion, data) => broadcastCompilationResult(file, source, languageVersion, data)) - - plugin.on('nahmii-compiler', 'compilationFinished', (file, source, languageVersion, data) => broadcastCompilationResult(file, source, languageVersion, data)) - - plugin.on('udapp', 'setEnvironmentModeReducer', (env: { context: string, fork: string }, from: string) => { - plugin.call('notification', 'toast', envChangeNotification(env, from)) - setExecutionContext(env) - }) - - plugin.on('udapp', 'clearAllInstancesReducer', () => { - dispatch(clearAllInstances()) - }) - - plugin.on('udapp', 'addInstanceReducer', (address, abi, name) => { - addInstance({ abi, address, name }) - }) - - plugin.on('filePanel', 'setWorkspace', () => { - dispatch(resetUdapp()) - resetAndInit() - }) - - plugin.fileManager.events.on('currentFileChanged', (currentFile: string) => { - if (/.(.abi)$/.exec(currentFile)) { - dispatch(setLoadType('abi')) - } else if (/.(.sol)$/.exec(currentFile) || - /.(.vy)$/.exec(currentFile) || // vyper - /.(.lex)$/.exec(currentFile) || // lexon - /.(.contract)$/.exec(currentFile)) { - dispatch(setLoadType('sol')) - } else { - dispatch(setLoadType('other')) - } - dispatch(setCurrentFile(currentFile)) - }) - - plugin.recorder.event.register('recorderCountChange', (count) => { - dispatch(setRecorderCount(count)) - }) - - plugin.event.register('cleared', () => { - dispatch(clearRecorderCount()) - }) -} - -const updateAccountBalances = () => { - const accounts = plugin.REACT_API.accounts.loadedAccounts - - Object.keys(accounts).map((value) => { - plugin.blockchain.getBalanceInEther(value, (err, balance) => { - if (err) return - const updated = shortenAddress(value, balance) - - accounts[value] = updated - }) - }) - dispatch(fetchAccountsListSuccess(accounts)) -} - -const fillAccountsList = async () => { - try { - dispatch(fetchAccountsListRequest()) - const promise = plugin.blockchain.getAccounts() - - promise.then(async (accounts: string[]) => { - const loadedAccounts = {} - - if (!accounts) accounts = [] - // allSettled is undefined.. - // so the current promise (all) will finish when: - // - all the promises resolve - // - at least one reject - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all - await (Promise as any).all(accounts.map((account) => { - return new Promise((resolve, reject) => { - plugin.blockchain.getBalanceInEther(account, (err, balance) => { - if (err) return reject(err) - const updated = shortenAddress(account, balance) - - loadedAccounts[account] = updated - resolve(account) - }) - }) - })) - const provider = plugin.blockchain.getProvider() - - if (provider === 'injected') { - const selectedAddress = plugin.blockchain.getInjectedWeb3Address() - - if (!(Object.keys(loadedAccounts).includes(selectedAddress))) setAccount(null) - } - dispatch(fetchAccountsListSuccess(loadedAccounts)) - }).catch((e) => { - dispatch(fetchAccountsListFailed(e.message)) - }) - } catch (e) { - dispatch(displayPopUp(`Cannot get account list: ${e}`)) - } -} - -export const setAccount = (account: string) => { - dispatch(setSelectedAccount(account)) -} - -export const setUnit = (unit: 'ether' | 'finney' | 'gwei' | 'wei') => { - dispatch(setSendUnit(unit)) -} - -export const setGasFee = (value: number) => { - dispatch(setGasLimit(value)) -} - -const setFinalContext = () => { - // set the final context. Cause it is possible that this is not the one we've originaly selected - const value = _getProviderDropdownValue() - - setExecEnv(value) - clearInstances() -} - -const _getProviderDropdownValue = (): string => { - const provider = plugin.blockchain.getProvider() - const fork = plugin.blockchain.getCurrentFork() - - return provider === 'vm' ? provider + '-' + fork : provider -} - -const setExecEnv = (env: string) => { - dispatch(setExecutionEnvironment(env)) -} - -export const setNetworkNameFromProvider = (networkName: string) => { - dispatch(setNetworkName(networkName)) -} - -const addExternalProvider = (network) => { - dispatch(addProvider(network)) -} - -const removeExternalProvider = (name) => { - dispatch(removeProvider(name)) -} - -export const setExecutionContext = (executionContext: { context: string, fork: string }) => { - const displayContent = web3Dialog(plugin.REACT_API.externalEndpoint, setWeb3Endpoint) - - plugin.blockchain.changeExecutionContext(executionContext, () => { - plugin.call('notification', 'modal', { - id: 'envNotification', - title: 'External node request', - message: displayContent, - okLabel: 'OK', - cancelLabel: 'Cancel', - okFn: () => { - plugin.blockchain.setProviderFromEndpoint(plugin.REACT_API.externalEndpoint, executionContext, (alertMsg) => { - if (alertMsg) plugin.call('notification', 'toast', alertMsg) - setFinalContext() - }) - }, - cancelFn: () => { - setFinalContext() - } - }) - }, (alertMsg) => { - plugin.call('notification', 'toast', alertMsg) - }, () => { setFinalContext() }) -} - -export const setWeb3Endpoint = (endpoint: string) => { - dispatch(setExternalEndpoint(endpoint)) -} - -export const clearPopUp = async () => { - dispatch(hidePopUp()) -} - -export const createNewBlockchainAccount = async (cbMessage: JSX.Element) => { - plugin.blockchain.newAccount( - '', - (cb) => { - dispatch(displayNotification('Enter Passphrase', cbMessage, 'OK', 'Cancel', async () => { - if (plugin.REACT_API.passphrase === plugin.REACT_API.matchPassphrase) { - cb(plugin.REACT_API.passphrase) - } else { - dispatch(displayNotification('Error', 'Passphase does not match', 'OK', null)) - } - setPassphrase('') - setMatchPassphrase('') - }, () => {})) - }, - async (error, address) => { - if (error) { - return dispatch(displayPopUp('Cannot create an account: ' + error)) - } - dispatch(displayPopUp(`account ${address} created`)) - await fillAccountsList() - } - ) -} - -export const setPassphrasePrompt = (passphrase: string) => { - dispatch(setPassphrase(passphrase)) -} - -export const setMatchPassphrasePrompt = (passphrase: string) => { - dispatch(setMatchPassphrase(passphrase)) -} - -export const signMessageWithAddress = (account: string, message: string, modalContent: (hash: string, data: string) => JSX.Element, passphrase?: string) => { - plugin.blockchain.signMessage(message, account, passphrase, (err, msgHash, signedData) => { - if (err) { - return displayPopUp(err) - } - dispatch(displayNotification('Signed Message', modalContent(msgHash, signedData), 'OK', null, () => {}, null)) - }) -} - -const broadcastCompilationResult = (file, source, languageVersion, data, input?) => { - // TODO check whether the tab is configured - const compiler = new CompilerAbstract(languageVersion, data, source, input) - - plugin.compilersArtefacts[languageVersion] = compiler - plugin.compilersArtefacts.__last = compiler - - const contracts = getCompiledContracts(compiler).map((contract) => { - return { name: languageVersion, alias: contract.name, file: contract.file, compiler } - }) - - dispatch(fetchContractListSuccess({ [file]: contracts })) - dispatch(setCurrentFile(file)) -} - -const loadContractFromAddress = (address, confirmCb, cb) => { - if (/.(.abi)$/.exec(plugin.config.get('currentFile'))) { - confirmCb(() => { - let abi - try { - abi = JSON.parse(plugin.editor.currentContent()) - } catch (e) { - return cb('Failed to parse the current file as JSON ABI.') - } - _paq.push(['trackEvent', 'udapp', 'AtAddressLoadWithABI']) - cb(null, 'abi', abi) - }) - } else { - _paq.push(['trackEvent', 'udapp', 'AtAddressLoadWithArtifacts']) - cb(null, 'instance') - } -} - -const getCompiledContracts = (compiler) => { - const contracts = [] - - compiler.visitContracts((contract) => { - contracts.push(contract) - }) - return contracts -} - -export const getSelectedContract = (contractName: string, compiler: CompilerAbstractType): ContractData => { - if (!contractName) return null - // const compiler = plugin.compilersArtefacts[compilerAtributeName] - - if (!compiler) return null - - const contract = compiler.getContract(contractName) - - return { - name: contractName, - contract: contract, - compiler: compiler, - abi: contract.object.abi, - bytecodeObject: contract.object.evm.bytecode.object, - bytecodeLinkReferences: contract.object.evm.bytecode.linkReferences, - object: contract.object, - deployedBytecode: contract.object.evm.deployedBytecode, - getConstructorInterface: () => { - return txHelper.getConstructorInterface(contract.object.abi) - }, - getConstructorInputs: () => { - const constructorInteface = txHelper.getConstructorInterface(contract.object.abi) - - return txHelper.inputParametersDeclarationToString(constructorInteface.inputs) - }, - isOverSizeLimit: () => { - const deployedBytecode = contract.object.evm.deployedBytecode - - return (deployedBytecode && deployedBytecode.object.length / 2 > 24576) - }, - metadata: contract.object.metadata - } -} - -const getCompilerContracts = () => { - return plugin.compilersArtefacts.__last.getData().contracts -} - -const terminalLogger = (view: JSX.Element) => { - plugin.call('terminal', 'logHtml', view) -} - -const confirmationHandler = (confirmDialogContent: MainnetPrompt, network, tx, gasEstimation, continueTxExecution, cancelCb) => { - if (network.name !== 'Main') { - return continueTxExecution(null) - } - const amount = plugin.blockchain.fromWei(tx.value, true, 'ether') - const content = confirmDialogContent(tx, network, amount, gasEstimation, plugin.blockchain.determineGasFees(tx), plugin.blockchain.determineGasPrice.bind(plugin.blockchain)) - - dispatch(displayNotification('Confirm transaction', content, 'Confirm', 'Cancel', () => { - plugin.blockchain.config.setUnpersistedProperty('doNotShowTransactionConfirmationAgain', plugin.REACT_API.confirmSettings) - // TODO: check if this is check is still valid given the refactor - if (!plugin.REACT_API.gasPriceStatus) { - cancelCb('Given transaction fee is not correct') - } else { - continueTxExecution({ maxFee: plugin.REACT_API.maxFee, maxPriorityFee: plugin.REACT_API.maxPriorityFee, baseFeePerGas: plugin.REACT_API.baseFeePerGas, gasPrice: plugin.REACT_API.gasPrice }) - } - }, () => { - return cancelCb('Transaction canceled by user.') - })) -} - -const getConfirmationCb = (confirmDialogContent: MainnetPrompt) => { - // this code is the same as in recorder.js. TODO need to be refactored out - return (network, tx, gasEstimation, continueTxExecution, cancelCb) => { - confirmationHandler(confirmDialogContent, network, tx, gasEstimation, continueTxExecution, cancelCb) - } -} - -const continueHandler = (gasEstimationPrompt: (msg: string) => JSX.Element, error, continueTxExecution, cancelCb) => { - if (error) { - const msg = typeof error !== 'string' ? error.message : error - - dispatch(displayNotification('Gas estimation failed', gasEstimationPrompt(msg), 'Send Transaction', 'Cancel Transaction', () => { - continueTxExecution() - }, () => { - cancelCb() - })) - } else { - continueTxExecution() - } -} - -const promptHandler = (passphrasePrompt, okCb, cancelCb) => { - dispatch(displayNotification('Passphrase requested', passphrasePrompt('Personal mode is enabled. Please provide passphrase of account'), 'OK', 'Cancel', okCb, cancelCb)) -} - -export const createInstance = async ( - selectedContract: ContractData, - gasEstimationPrompt: (msg: string) => JSX.Element, - passphrasePrompt: (msg: string) => JSX.Element, - logBuilder: (msg: string) => JSX.Element, - publishToStorage: (storage: 'ipfs' | 'swarm', - contract: ContractData) => void, - mainnetPrompt: MainnetPrompt, - isOverSizePrompt: () => JSX.Element, - args) => { - const statusCb = (msg: string) => { - const log = logBuilder(msg) - - return terminalLogger(log) - } - - const finalCb = (error, contractObject, address) => { - if (error) { - const log = logBuilder(error) - - return terminalLogger(log) - } - addInstance({ contractData: contractObject, address, name: contractObject.name }) - - const data = plugin.compilersArtefacts.getCompilerAbstract(contractObject.contract.file) - - plugin.compilersArtefacts.addResolvedContract(addressToString(address), data) - if (plugin.REACT_API.ipfsChecked) { - _paq.push(['trackEvent', 'udapp', 'DeployAndPublish', plugin.REACT_API.networkName]) - publishToStorage('ipfs', selectedContract) - } else { - _paq.push(['trackEvent', 'udapp', 'DeployOnly', plugin.REACT_API.networkName]) - } - } - - let contractMetadata - try { - contractMetadata = await plugin.call('compilerMetadata', 'deployMetadataOf', selectedContract.name, selectedContract.contract.file) - } catch (error) { - return statusCb(`creation of ${selectedContract.name} errored: ${error.message ? error.message : error}`) - } - - const compilerContracts = getCompilerContracts() - const confirmationCb = getConfirmationCb(mainnetPrompt) - - if (selectedContract.isOverSizeLimit()) { - return dispatch(displayNotification('Contract code size over limit', isOverSizePrompt(), 'Force Send', 'Cancel', () => { - deployContract(selectedContract, args, contractMetadata, compilerContracts, { - continueCb: (error, continueTxExecution, cancelCb) => { - continueHandler(gasEstimationPrompt, error, continueTxExecution, cancelCb) - }, - promptCb: (okCb, cancelCb) => { - promptHandler(passphrasePrompt, okCb, cancelCb) - }, - statusCb, - finalCb - }, confirmationCb) - }, () => { - const log = logBuilder(`creation of ${selectedContract.name} canceled by user.`) - - return terminalLogger(log) - })) - } - deployContract(selectedContract, args, contractMetadata, compilerContracts, { - continueCb: (error, continueTxExecution, cancelCb) => { - continueHandler(gasEstimationPrompt, error, continueTxExecution, cancelCb) - }, - promptCb: (okCb, cancelCb) => { - promptHandler(passphrasePrompt, okCb, cancelCb) - }, - statusCb, - finalCb - }, confirmationCb) -} - -const deployContract = (selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb) => { - _paq.push(['trackEvent', 'udapp', 'DeployContractTo', plugin.REACT_API.networkName]) - const { statusCb } = callbacks - - if (!contractMetadata || (contractMetadata && contractMetadata.autoDeployLib)) { - return plugin.blockchain.deployContractAndLibraries(selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb) - } - if (Object.keys(selectedContract.bytecodeLinkReferences).length) statusCb(`linking ${JSON.stringify(selectedContract.bytecodeLinkReferences, null, '\t')} using ${JSON.stringify(contractMetadata.linkReferences, null, '\t')}`) - plugin.blockchain.deployContractWithLibrary(selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb) -} - -export const updateGasPriceStatus = (status: boolean) => { - dispatch(setGasPriceStatus(status)) -} - -export const updateConfirmSettings = (confirmation: boolean) => { - dispatch(setConfirmSettings(confirmation)) -} - -export const updateMaxFee = (fee: string) => { - dispatch(setMaxFee(fee)) -} - -export const updateMaxPriorityFee = (fee: string) => { - dispatch(setMaxPriorityFee(fee)) -} - -export const updateBaseFeePerGas = (baseFee: string) => { - dispatch(setBaseFeePerGas(baseFee)) -} - -export const updateGasPrice = (price: string) => { - dispatch(setGasPrice(price)) -} - -export const updateTxFeeContent = (content: string) => { - dispatch(setTxFeeContent(content)) -} - -export const addInstance = (instance: { contractData?: ContractData, address: string, name: string, abi?: any, decodedResponse?: Record }) => { - instance.decodedResponse = {} - dispatch(addNewInstance(instance)) -} - -export const removeInstance = (index: number) => { - dispatch(removeExistingInstance(index)) -} - -export const clearInstances = () => { - dispatch(clearAllInstances()) - dispatch(clearRecorderCount()) -} - -export const loadAddress = (contract: ContractData, address: string) => { - loadContractFromAddress(address, - (cb) => { - dispatch(displayNotification('At Address', `Do you really want to interact with ${address} using the current ABI definition?`, 'OK', 'Cancel', cb, null)) - }, - (error, loadType, abi) => { - if (error) { - return dispatch(displayNotification('Alert', error, 'OK', null)) - } - if (loadType === 'abi') { - return addInstance({ abi, address, name: '' }) - } else if (loadType === 'instance') { - if (!contract) return dispatch(displayPopUp('No compiled contracts found.')) - const currentFile = plugin.REACT_API.contracts.currentFile - const compiler = plugin.REACT_API.contracts.contractList[currentFile].find(item => item.alias === contract.name) - const contractData = getSelectedContract(contract.name, compiler.compiler) - return addInstance({ contractData, address, name: contract.name }) - } - } - ) - } - -export const getContext = () => { - return plugin.blockchain.context() -} - -export const runTransactions = ( - instanceIndex: number, - lookupOnly: boolean, - funcABI: FuncABI, - inputsValues: string, - contractName: string, - contractABI, contract, - address, - logMsg:string, - logBuilder: (msg: string) => JSX.Element, - mainnetPrompt: MainnetPrompt, - gasEstimationPrompt: (msg: string) => JSX.Element, - passphrasePrompt: (msg: string) => JSX.Element, - funcIndex?: number) => { - let callinfo = '' - if (lookupOnly) callinfo = 'call' - else if (funcABI.type === 'fallback' || funcABI.type === 'receive') callinfo = 'lowLevelInteracions' - else callinfo = 'transact' - _paq.push(['trackEvent', 'udapp', callinfo, plugin.blockchain.getCurrentNetworkStatus().network.name]) - - const params = funcABI.type !== 'fallback' ? inputsValues : '' - plugin.blockchain.runOrCallContractMethod( - contractName, - contractABI, - funcABI, - contract, - inputsValues, - address, - params, - lookupOnly, - logMsg, - (msg) => { - const log = logBuilder(msg) - - return terminalLogger(log) - }, - (returnValue) => { - const response = txFormat.decodeResponse(returnValue, funcABI) - - dispatch(setDecodedResponse(instanceIndex, response, funcIndex)) - }, - (network, tx, gasEstimation, continueTxExecution, cancelCb) => { - confirmationHandler(mainnetPrompt, network, tx, gasEstimation, continueTxExecution, cancelCb) - }, - (error, continueTxExecution, cancelCb) => { - continueHandler(gasEstimationPrompt, error, continueTxExecution, cancelCb) - }, - (okCb, cancelCb) => { - promptHandler(passphrasePrompt, okCb, cancelCb) - } - ) -} - -const saveScenario = async (newPath: string, provider, promptCb, cb) => { - const txJSON = JSON.stringify(plugin.recorder.getAll(), null, 2) - - promptCb(async () => { - try { - await provider.set(newPath, txJSON) - await plugin.fileManager.open(newPath) - } catch (error) { - if (error) return cb('Failed to create file. ' + newPath + ' ' + error) - } - }) -} - -export const storeScenario = async (prompt: (msg: string, defaultValue: string) => JSX.Element) => { - const path = plugin.fileManager.currentPath() - const fileProvider = await plugin.fileManager.fileProviderOf(path) - - if (!fileProvider) return displayNotification('Alert', 'Invalid File Provider', 'OK', null) - const newPath = await createNonClashingNameAsync(path + '/' + plugin.REACT_API.recorder.pathToScenario, plugin.fileManager) - const newName = extractNameFromKey(newPath) - - saveScenario(newPath, fileProvider, - (cb) => { - dispatch(displayNotification('Save transactions as scenario', prompt('Transactions will be saved in a file under ' + path, newName), 'OK', 'Cancel', cb, null)) - }, - (error) => { - if (error) return dispatch(displayNotification('Alert', error, 'OK', null)) - } - ) -} - -const runScenario = (file: string, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, confirmDialogContent: MainnetPrompt, logBuilder: (msg: string) => JSX.Element) => { - if (!file) return dispatch(displayNotification('Alert', 'Unable to run scenerio, no specified scenario file', 'OK', null)) - - plugin.fileManager.readFile(file).then((json) => { - // TODO: there is still a UI dependency to remove here, it's still too coupled at this point to remove easily - plugin.recorder.runScenario( - json, - (error, continueTxExecution, cancelCb) => { - continueHandler(gasEstimationPrompt, error, continueTxExecution, cancelCb) - }, (okCb, cancelCb) => { - promptHandler(passphrasePrompt, okCb, cancelCb) - }, (msg) => { - dispatch(displayNotification('Alert', msg, 'OK', null)) - }, (network, tx, gasEstimation, continueTxExecution, cancelCb) => { - confirmationHandler(confirmDialogContent, network, tx, gasEstimation, continueTxExecution, cancelCb) - }, (msg: string) => { - const log = logBuilder(msg) - - return terminalLogger(log) - }, (error, abi, address, contractName) => { - if (error) { - return dispatch(displayNotification('Alert', error, 'OK', null)) - } - addInstance({ name: contractName, address, abi }) - }) - }).catch((error) => dispatch(displayNotification('Alert', error, 'OK', null))) -} - -export const runCurrentScenario = (gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, confirmDialogContent: MainnetPrompt, logBuilder: (msg: string) => JSX.Element) => { - const file = plugin.config.get('currentFile') - - if (!file) return dispatch(displayNotification('Alert', 'A scenario file has to be selected', 'Ok', null)) - runScenario(file, gasEstimationPrompt, passphrasePrompt, confirmDialogContent, logBuilder) -} - -export const updateScenarioPath = (path: string) => { - dispatch(setPathToScenario(path)) -} - -export const getFuncABIInputs = (funcABI: FuncABI) => { - return plugin.blockchain.getInputs(funcABI) -} - -export const setSendTransactionValue = (value: string) => { - dispatch(setSendValue(value)) -} - -const resetAndInit = () => { - plugin.blockchain.resetAndInit(plugin.config, { - getAddress: (cb) => { - cb(null, plugin.REACT_API.accounts.selectedAccount) - }, - getValue: (cb) => { - try { - const number = plugin.REACT_API.sendValue - const unit = plugin.REACT_API.sendUnit - - cb(null, Web3.utils.toWei(number, unit)) - } catch (e) { - cb(e) - } - }, - getGasLimit: (cb) => { - try { - cb(null, '0x' + new ethJSUtil.BN(plugin.REACT_API.gasLimit, 10).toString(16)) - } catch (e) { - cb(e.message) - } - } - }) -} +export const setAccountAddress = (account: string) => setAccount(dispatch, account) +export const setUnitValue = (unit: 'ether' | 'finney' | 'gwei' | 'wei') => setUnit(dispatch, unit) +export const setGasFeeAmount = (value: number) => setGasFee(dispatch, value) +export const setExecutionEnvironment = (executionContext: { context: string, fork: string }) => setExecutionContext(plugin, dispatch, executionContext) +export const hideToaster = () => clearPopUp(dispatch) +export const createNewAddress = (cbMessage: JSX.Element) => createNewBlockchainAccount(plugin, dispatch, cbMessage) +export const setPassphraseModal = (passphrase: string) => setPassphrasePrompt(dispatch, passphrase) +export const setMatchPassphraseModal = (passphrase: string) => setMatchPassphrasePrompt(dispatch, passphrase) +export const signMessage = (account: string, message: string, modalContent: (hash: string, data: string) => JSX.Element, passphrase?: string) => signMessageWithAddress(plugin, dispatch, account, message, modalContent, passphrase) +export const fetchSelectedContract = (contractName: string, compiler: CompilerAbstractType) => getSelectedContract(contractName, compiler) +export const createNewInstance = async (selectedContract: ContractData, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, publishToStorage: (storage: 'ipfs' | 'swarm', contract: ContractData) => void, mainnetPrompt: MainnetPrompt, isOverSizePrompt: () => JSX.Element, args, deployMode: DeployMode[]) => createInstance(plugin, dispatch, selectedContract, gasEstimationPrompt, passphrasePrompt, publishToStorage, mainnetPrompt, isOverSizePrompt, args, deployMode) +export const setSendValue = (value: string) => setSendTransactionValue(dispatch, value) +export const setBaseFeePerGas = (baseFee: string) => updateBaseFeePerGas(dispatch, baseFee) +export const setConfirmSettings = (confirmation: boolean) => updateConfirmSettings(dispatch, confirmation) +export const setGasPrice = (price: string) => updateGasPrice(dispatch, price) +export const setGasPriceStatus = (status: boolean) => updateGasPriceStatus(dispatch, status) +export const setMaxFee = (fee: string) => updateMaxFee(dispatch, fee) +export const setMaxPriorityFee = (fee: string) => updateMaxPriorityFee(dispatch, fee) +export const setTxFeeContent = (content: string) => updateTxFeeContent(dispatch, content) +export const removeInstances = () => clearInstances(dispatch) +export const removeSingleInstance = (index: number) => removeInstance(dispatch, index) +export const getExecutionContext = () => getContext(plugin) +export const executeTransactions = (instanceIndex: number, lookupOnly: boolean, funcABI: FuncABI, inputsValues: string, contractName: string, contractABI, contract, address, logMsg:string, mainnetPrompt: MainnetPrompt, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, funcIndex?: number) => runTransactions(plugin, dispatch, instanceIndex, lookupOnly, funcABI, inputsValues, contractName, contractABI, contract, address, logMsg, mainnetPrompt, gasEstimationPrompt, passphrasePrompt, funcIndex) +export const loadFromAddress = (contract: ContractData, address: string) => loadAddress(plugin, dispatch, contract, address) +export const storeNewScenario = async (prompt: (msg: string, defaultValue: string) => JSX.Element) => storeScenario(plugin, dispatch, prompt) +export const runScenario = (liveMode: boolean, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, confirmDialogContent: MainnetPrompt) => runCurrentScenario(liveMode, plugin, dispatch, gasEstimationPrompt, passphrasePrompt, confirmDialogContent) +export const setScenarioPath = (path: string) => updateScenarioPath(dispatch, path) +export const getFuncABIValues = (funcABI: FuncABI) => getFuncABIInputs(plugin, funcABI) +export const setNetworkName = (networkName: string) => setNetworkNameFromProvider(dispatch, networkName) +export const updateSelectedContract = (contractName) => setSelectedContract(dispatch, contractName) \ No newline at end of file diff --git a/libs/remix-ui/run-tab/src/lib/actions/payload.ts b/libs/remix-ui/run-tab/src/lib/actions/payload.ts index 08e7f22b63..64545368b6 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/payload.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/payload.ts @@ -1,249 +1,251 @@ import { ContractList } from '../reducers/runTab' import { ContractData } from '@remix-project/core-plugin' +import { ADD_DEPLOY_OPTION, ADD_INSTANCE, ADD_PROVIDER, CLEAR_INSTANCES, CLEAR_RECORDER_COUNT, DISPLAY_NOTIFICATION, DISPLAY_POPUP_MESSAGE, FETCH_ACCOUNTS_LIST_FAILED, FETCH_ACCOUNTS_LIST_REQUEST, FETCH_ACCOUNTS_LIST_SUCCESS, FETCH_CONTRACT_LIST_FAILED, FETCH_CONTRACT_LIST_REQUEST, FETCH_CONTRACT_LIST_SUCCESS, HIDE_NOTIFICATION, HIDE_POPUP_MESSAGE, REMOVE_DEPLOY_OPTION, REMOVE_INSTANCE, REMOVE_PROVIDER, RESET_STATE, SET_BASE_FEE_PER_GAS, SET_CONFIRM_SETTINGS, SET_CURRENT_CONTRACT, SET_CURRENT_FILE, SET_DECODED_RESPONSE, SET_DEPLOY_OPTIONS, SET_EXECUTION_ENVIRONMENT, SET_EXTERNAL_WEB3_ENDPOINT, SET_GAS_LIMIT, SET_GAS_PRICE, SET_GAS_PRICE_STATUS, SET_IPFS_CHECKED_STATE, SET_LOAD_TYPE, SET_MATCH_PASSPHRASE, SET_MAX_FEE, SET_MAX_PRIORITY_FEE, SET_NETWORK_NAME, SET_PASSPHRASE, SET_PATH_TO_SCENARIO, SET_PERSONAL_MODE, SET_RECORDER_COUNT, SET_SELECTED_ACCOUNT, SET_SEND_UNIT, SET_SEND_VALUE, SET_TX_FEE_CONTENT } from '../constants' +import { DeployMode, DeployOptions } from '../types' export const fetchAccountsListRequest = () => { return { - type: 'FETCH_ACCOUNTS_LIST_REQUEST', + type: FETCH_ACCOUNTS_LIST_REQUEST, payload: null } } export const fetchAccountsListSuccess = (accounts: Record) => { return { - type: 'FETCH_ACCOUNTS_LIST_SUCCESS', + type: FETCH_ACCOUNTS_LIST_SUCCESS, payload: accounts } } export const fetchAccountsListFailed = (error: string) => { return { - type: 'FETCH_ACCOUNTS_LIST_FAILED', + type: FETCH_ACCOUNTS_LIST_FAILED, payload: error } } export const setSendValue = (value: string) => { return { - type: 'SET_SEND_VALUE', + type: SET_SEND_VALUE, payload: value } } export const setSelectedAccount = (account: string) => { return { - type: 'SET_SELECTED_ACCOUNT', + type: SET_SELECTED_ACCOUNT, payload: account } } export const setSendUnit = (unit: 'ether' | 'finney' | 'gwei' | 'wei') => { return { - type: 'SET_SEND_UNIT', + type: SET_SEND_UNIT, payload: unit } } export const setGasLimit = (gasLimit: number) => { return { - type: 'SET_GAS_LIMIT', + type: SET_GAS_LIMIT, payload: gasLimit } } export const setExecutionEnvironment = (executionEnvironment: string) => { return { - type: 'SET_EXECUTION_ENVIRONMENT', + type: SET_EXECUTION_ENVIRONMENT, payload: executionEnvironment } } export const setPersonalMode = (mode: boolean) => { return { - type: 'SET_PERSONAL_MODE', + type: SET_PERSONAL_MODE, payload: mode } } export const setNetworkName = (networkName: string) => { return { - type: 'SET_NETWORK_NAME', + type: SET_NETWORK_NAME, payload: networkName } } export const addProvider = (provider: string) => { return { - type: 'ADD_PROVIDER', + type: ADD_PROVIDER, payload: provider } } export const removeProvider = (provider: string) => { return { - type: 'REMOVE_PROVIDER', + type: REMOVE_PROVIDER, payload: provider } } export const displayNotification = (title: string, message: string | JSX.Element, labelOk: string, labelCancel: string, actionOk?: (...args) => void, actionCancel?: (...args) => void) => { return { - type: 'DISPLAY_NOTIFICATION', + type: DISPLAY_NOTIFICATION, payload: { title, message, labelOk, labelCancel, actionOk, actionCancel } } } export const hideNotification = () => { return { - type: 'HIDE_NOTIFICATION' + type: HIDE_NOTIFICATION } } export const setExternalEndpoint = (endpoint: string) => { return { - type: 'SET_EXTERNAL_WEB3_ENDPOINT', + type: SET_EXTERNAL_WEB3_ENDPOINT, payload: endpoint } } export const displayPopUp = (message: string | JSX.Element) => { return { - type: 'DISPLAY_POPUP_MESSAGE', + type: DISPLAY_POPUP_MESSAGE, payload: message } } export const hidePopUp = () => { return { - type: 'HIDE_POPUP_MESSAGE' + type: HIDE_POPUP_MESSAGE } } export const setPassphrase = (passphrase: string) => { return { - type: 'SET_PASSPHRASE', + type: SET_PASSPHRASE, payload: passphrase } } export const setMatchPassphrase = (passphrase: string) => { return { - type: 'SET_MATCH_PASSPHRASE', + type: SET_MATCH_PASSPHRASE, payload: passphrase } } export const fetchContractListRequest = () => { return { - type: 'FETCH_CONTRACT_LIST_REQUEST' + type: FETCH_CONTRACT_LIST_REQUEST } } export const fetchContractListSuccess = (contracts: ContractList) => { return { - type: 'FETCH_CONTRACT_LIST_SUCCESS', + type: FETCH_CONTRACT_LIST_SUCCESS, payload: contracts } } export const fetchContractListFailed = (error: string) => { return { - type: 'FETCH_CONTRACT_LIST_FAILED', + type: FETCH_CONTRACT_LIST_FAILED, payload: error } } export const setLoadType = (type: 'abi' | 'sol' | 'other') => { return { - type: 'SET_LOAD_TYPE', + type: SET_LOAD_TYPE, payload: type } } export const setCurrentFile = (file: string) => { return { - type: 'SET_CURRENT_FILE', + type: SET_CURRENT_FILE, payload: file } } export const setIpfsCheckedState = (state: boolean) => { return { - type: 'SET_IPFS_CHECKED_STATE', + type: SET_IPFS_CHECKED_STATE, payload: state } } export const setGasPriceStatus = (status: boolean) => { return { - type: 'SET_GAS_PRICE_STATUS', + type: SET_GAS_PRICE_STATUS, payload: status } } export const setConfirmSettings = (confirmation: boolean) => { return { - type: 'SET_CONFIRM_SETTINGS', + type: SET_CONFIRM_SETTINGS, payload: confirmation } } export const setMaxFee = (fee: string) => { return { - type: 'SET_MAX_FEE', + type: SET_MAX_FEE, payload: fee } } export const setMaxPriorityFee = (fee: string) => { return { - type: 'SET_MAX_PRIORITY_FEE', + type: SET_MAX_PRIORITY_FEE, payload: fee } } export const setBaseFeePerGas = (baseFee: string) => { return { - type: 'SET_BASE_FEE_PER_GAS', + type: SET_BASE_FEE_PER_GAS, payload: baseFee } } export const setGasPrice = (price: string) => { return { - type: 'SET_GAS_PRICE', + type: SET_GAS_PRICE, payload: price } } export const setTxFeeContent = (content: string) => { return { - type: 'SET_TX_FEE_CONTENT', + type: SET_TX_FEE_CONTENT, payload: content } } export const addNewInstance = (instance: { contractData?: ContractData, address: string, name: string, abi?: any }) => { return { - type: 'ADD_INSTANCE', + type: ADD_INSTANCE, payload: instance } } export const removeExistingInstance = (index: number) => { return { - type: 'REMOVE_INSTANCE', + type: REMOVE_INSTANCE, payload: index } } export const clearAllInstances = () => { return { - type: 'CLEAR_INSTANCES' + type: CLEAR_INSTANCES } } export const setDecodedResponse = (instanceIndex: number, response, funcIndex?: number) => { return { - type: 'SET_DECODED_RESPONSE', + type: SET_DECODED_RESPONSE, payload: { instanceIndex, funcIndex, @@ -254,33 +256,54 @@ export const setDecodedResponse = (instanceIndex: number, response, funcIndex?: export const setPathToScenario = (path: string) => { return { - type: 'SET_PATH_TO_SCENARIO', + type: SET_PATH_TO_SCENARIO, payload: path } } export const setRecorderCount = (count: number) => { return { - type: 'SET_RECORDER_COUNT', + type: SET_RECORDER_COUNT, payload: count } } export const clearRecorderCount = () => { return { - type: 'CLEAR_RECORDER_COUNT' + type: CLEAR_RECORDER_COUNT } } -export const setEnvToasterContent = (content: (env: { context: string, fork: string }, from: string) => void) => { +export const resetUdapp = () => { return { - type: 'SET_ENV_TOASTER_CONTENT', - payload: content + type: RESET_STATE } } -export const resetUdapp = () => { +export const addDeployOption = (deployOption: DeployOptions) => { + return { + payload: deployOption, + type: ADD_DEPLOY_OPTION + } +} + +export const removeDeployOption = (title: DeployMode) => { + return { + payload: title, + type: REMOVE_DEPLOY_OPTION + } +} + +export const setDeployOptions = (deployOptions: DeployOptions) => { + return { + payload: deployOptions, + type: SET_DEPLOY_OPTIONS + } +} + +export const setCurrentContract = (contractName: string) => { return { - type: 'RESET_STATE' + payload: contractName, + type: SET_CURRENT_CONTRACT } } diff --git a/libs/remix-ui/run-tab/src/lib/actions/recorder.ts b/libs/remix-ui/run-tab/src/lib/actions/recorder.ts new file mode 100644 index 0000000000..2bf910650b --- /dev/null +++ b/libs/remix-ui/run-tab/src/lib/actions/recorder.ts @@ -0,0 +1,73 @@ +import { createNonClashingNameAsync, extractNameFromKey, logBuilder } from "@remix-ui/helper" +import { MainnetPrompt } from "../types" +import { RunTab } from "../types/run-tab" +import { addInstance } from "./actions" +import { confirmationHandler, continueHandler, promptHandler, terminalLogger } from "./deploy" +import { displayNotification } from "./payload" + +const saveScenario = async (plugin: RunTab, newPath: string, provider, promptCb, cb) => { + const txJSON = JSON.stringify(plugin.recorder.getAll(), null, 2) + + promptCb(async () => { + try { + await provider.set(newPath, txJSON) + await plugin.fileManager.open(newPath) + } catch (error) { + if (error) return cb('Failed to create file. ' + newPath + ' ' + error) + } + }) +} + +export const storeScenario = async (plugin: RunTab, dispatch: React.Dispatch, prompt: (msg: string, defaultValue: string) => JSX.Element) => { + const path = plugin.fileManager.currentPath() + const fileProvider = await plugin.fileManager.fileProviderOf(path) + + if (!fileProvider) return displayNotification('Alert', 'Invalid File Provider', 'OK', null) + const newPath = await createNonClashingNameAsync(path + '/' + plugin.REACT_API.recorder.pathToScenario, plugin.fileManager) + const newName = extractNameFromKey(newPath) + + saveScenario(plugin, newPath, fileProvider, + (cb) => { + dispatch(displayNotification('Save transactions as scenario', prompt('Transactions will be saved in a file under ' + path, newName), 'OK', 'Cancel', cb, null)) + }, + (error) => { + if (error) return dispatch(displayNotification('Alert', error, 'OK', null)) + } + ) +} + +const runScenario = (liveMode: boolean, plugin: RunTab, dispatch: React.Dispatch, file: string, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, confirmDialogContent: MainnetPrompt) => { + if (!file) return dispatch(displayNotification('Alert', 'Unable to run scenerio, no specified scenario file', 'OK', null)) + + plugin.fileManager.readFile(file).then((json) => { + // TODO: there is still a UI dependency to remove here, it's still too coupled at this point to remove easily + plugin.recorder.runScenario( + liveMode, + json, + (error, continueTxExecution, cancelCb) => { + continueHandler(dispatch, gasEstimationPrompt, error, continueTxExecution, cancelCb) + }, (okCb, cancelCb) => { + promptHandler(dispatch, passphrasePrompt, okCb, cancelCb) + }, (msg) => { + dispatch(displayNotification('Alert', msg, 'OK', null)) + }, (network, tx, gasEstimation, continueTxExecution, cancelCb) => { + confirmationHandler(plugin, dispatch, confirmDialogContent, network, tx, gasEstimation, continueTxExecution, cancelCb) + }, (msg: string) => { + const log = logBuilder(msg) + + return terminalLogger(plugin, log) + }, (error, abi, address, contractName) => { + if (error) { + return dispatch(displayNotification('Alert', error, 'OK', null)) + } + addInstance(dispatch, { name: contractName, address, abi }) + }) + }).catch((error) => dispatch(displayNotification('Alert', error, 'OK', null))) +} + +export const runCurrentScenario = (liveMode: boolean, plugin: RunTab, dispatch: React.Dispatch, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, confirmDialogContent: MainnetPrompt) => { + const file = plugin.config.get('currentFile') + + if (!file) return dispatch(displayNotification('Alert', 'A scenario file has to be selected', 'Ok', null)) + runScenario(liveMode, plugin, dispatch, file, gasEstimationPrompt, passphrasePrompt, confirmDialogContent) +} \ No newline at end of file diff --git a/libs/remix-ui/run-tab/src/lib/components/account.tsx b/libs/remix-ui/run-tab/src/lib/components/account.tsx index f8a74a1a34..1cb7aebc4c 100644 --- a/libs/remix-ui/run-tab/src/lib/components/account.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/account.tsx @@ -160,8 +160,8 @@ export function AccountUI (props: AccountProps) { accounts.map((value, index) => ) } -
- +
+ ) diff --git a/libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx b/libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx index 123dc9903d..900b7dc2c4 100644 --- a/libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx @@ -1,6 +1,6 @@ // eslint-disable-next-line no-use-before-define import React, { useEffect, useRef, useState } from 'react' -import { ContractDropdownProps } from '../types' +import { ContractDropdownProps, DeployMode } from '../types' import { ContractData, FuncABI } from '@remix-project/core-plugin' import * as ethJSUtil from 'ethereumjs-util' import { ContractGUI } from './contractGUI' @@ -22,13 +22,12 @@ export function ContractDropdownUI (props: ContractDropdownProps) { title: 'Please compile *.sol file to deploy or access a contract', disabled: true }) - const [selectedContract, setSelectedContract] = useState('') const [compFails, setCompFails] = useState<'none' | 'block'>('none') const [loadedContractData, setLoadedContractData] = useState(null) const [constructorInterface, setConstructorInterface] = useState(null) const [constructorInputs, setConstructorInputs] = useState(null) const contractsRef = useRef(null) - const { contractList, loadType, currentFile, compilationCount } = props.contracts + const { contractList, loadType, currentFile, currentContract, compilationCount, deployOptions } = props.contracts useEffect(() => { enableAtAddress(false) @@ -66,13 +65,13 @@ export function ContractDropdownUI (props: ContractDropdownProps) { display: 'none', content: '' }) - if (!selectedContract) enableAtAddress(false) + if (!currentContract) enableAtAddress(false) } else { setAbiLabel({ display: 'none', content: '' }) - if (!selectedContract) enableAtAddress(false) + if (!currentContract) enableAtAddress(false) } if (currentFile) { enableContractNames(true) @@ -85,11 +84,11 @@ export function ContractDropdownUI (props: ContractDropdownProps) { }, [loadType, currentFile, compilationCount]) useEffect(() => { - if (selectedContract && contractList[currentFile]) { - const contract = contractList[currentFile].find(contract => contract.alias === selectedContract) + if (currentContract && contractList[currentFile]) { + const contract = contractList[currentFile].find(contract => contract.alias === currentContract) if (contract) { - const loadedContractData = props.getSelectedContract(selectedContract, contract.compiler) + const loadedContractData = props.getSelectedContract(currentContract, contract.compiler) if (loadedContractData) { setLoadedContractData(loadedContractData) @@ -98,7 +97,7 @@ export function ContractDropdownUI (props: ContractDropdownProps) { } } } - }, [selectedContract, compilationCount]) + }, [currentContract, compilationCount]) useEffect(() => { initSelectedContract() @@ -108,9 +107,10 @@ export function ContractDropdownUI (props: ContractDropdownProps) { const contracts = contractList[currentFile] if (contracts && contracts.length > 0) { - const contract = contracts.find(contract => contract.alias === selectedContract) + const contract = contracts.find(contract => contract.alias === currentContract) - if (!selectedContract || !contract) setSelectedContract(contracts[0].alias) + if (!currentContract) props.setSelectedContract(contracts[0].alias) + else if (!contract) props.setSelectedContract(currentContract) // TODO highlight contractlist box with css. } } @@ -119,12 +119,12 @@ export function ContractDropdownUI (props: ContractDropdownProps) { if (enable) { setAtAddressOptions({ disabled: false, - title: 'Interact with the given contract.' + title: 'Interact with the deployed contract - requires the .abi file or compiled .sol file to be selected in the editor (with the same compiler configuration)' }) } else { setAtAddressOptions({ disabled: true, - title: loadedAddress ? '⚠ Compile *.sol file or select *.abi file.' : '⚠ Compile *.sol file or select *.abi file & then enter the address of deployed contract.' + title: loadedAddress ? 'Compile a *.sol file or select a *.abi file.' : 'To interact with a deployed contract, enter its address and compile its source *.sol file (with the same compiler settings) or select its .abi file in the editor. ' }) } } @@ -133,25 +133,25 @@ export function ContractDropdownUI (props: ContractDropdownProps) { if (enable) { setContractOptions({ disabled: false, - title: 'Select contract for Deploy or At Address.' + title: 'Select a compiled contract to deploy or to use with At Address.' }) } else { setContractOptions({ disabled: true, - title: loadType === 'sol' ? '⚠ Select and compile *.sol file to deploy or access a contract.' : '⚠ Selected *.abi file allows accessing contracts, select and compile *.sol file to deploy and access one.' + title: loadType === 'sol' ? 'Select and compile *.sol file to deploy or access a contract.' : 'When there is a compiled .sol file, the choice of contracts to deploy or to use with AtAddress is made here.' }) } } - const clickCallback = (inputs, value) => { - createInstance(loadedContractData, value) + const clickCallback = (inputs, value, deployMode?: DeployMode[]) => { + createInstance(loadedContractData, value, deployMode) } - const createInstance = (selectedContract, args) => { + const createInstance = (selectedContract, args, deployMode?: DeployMode[]) => { if (selectedContract.bytecodeObject.length === 0) { return props.modal('Alert', '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.', 'OK', () => {}) } - props.createInstance(loadedContractData, props.gasEstimationPrompt, props.passphrasePrompt, props.logBuilder, props.publishToStorage, props.mainnetPrompt, isOverSizePrompt, args) + props.createInstance(loadedContractData, props.gasEstimationPrompt, props.passphrasePrompt, props.publishToStorage, props.mainnetPrompt, isOverSizePrompt, args, deployMode) } const atAddressChanged = (event) => { @@ -189,7 +189,7 @@ export function ContractDropdownUI (props: ContractDropdownProps) { const handleContractChange = (e) => { const value = e.target.value - setSelectedContract(value) + props.setSelectedContract(value) } const checkSumWarning = () => { @@ -214,19 +214,29 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
- { (contractList[currentFile] || []).map((contract, index) => { return }) } - { (contractList[currentFile] || []).length <= 0 && } { abiLabel.content }
{ ((contractList[currentFile] && contractList[currentFile].filter(contract => contract)) || []).length <= 0 ? 'No compiled contracts' : loadedContractData ?
- +
({ title: '', content: '', classList: '', dataId: '' }) + dataId: string, + widthClass: string + }>({ title: '', content: '', classList: '', dataId: '', widthClass: '' }) + const [selectedDeployIndex, setSelectedDeployIndex] = useState(null) + const [showOptions, setShowOptions] = useState(false) + const [hasArgs, setHasArgs] = useState(false) + const [isMultiField, setIsMultiField] = useState(false) + const [deployInputs, setDeployInputs] = useState<{ + internalType?: string, + name: string, + type: string + }[]>([]) + const [deployPlaceholder, setDeployPlaceholder] = useState('') const multiFields = useRef>([]) const basicInputRef = useRef() @@ -28,7 +41,7 @@ export function ContractGUI (props: ContractGUIProps) { } setBasicInput('') // we have the reset the fields before reseting the previous references. - basicInputRef.current.value = '' + if (basicInputRef.current) basicInputRef.current.value = '' multiFields.current.filter((el) => el !== null && el !== undefined).forEach((el) => el.value = '') multiFields.current = [] }, [props.title, props.funcABI]) @@ -40,7 +53,8 @@ export function ContractGUI (props: ContractGUIProps) { title: title + ' - call', content: 'call', classList: 'btn-info', - dataId: title + ' - call' + dataId: title + ' - call', + widthClass: props.widthClass }) } else if (props.funcABI.stateMutability === 'payable' || props.funcABI.payable) { // // transact. stateMutability = payable @@ -48,7 +62,8 @@ export function ContractGUI (props: ContractGUIProps) { title: title + ' - transact (payable)', content: 'transact', classList: 'btn-danger', - dataId: title + ' - transact (payable)' + dataId: title + ' - transact (payable)', + widthClass: props.widthClass }) } else { // // transact. stateMutability = nonpayable @@ -56,13 +71,59 @@ export function ContractGUI (props: ContractGUIProps) { title: title + ' - transact (not payable)', content: 'transact', classList: 'btn-warning', - dataId: title + ' - transact (not payable)' + dataId: title + ' - transact (not payable)', + widthClass: props.widthClass }) } }, [props.lookupOnly, props.funcABI, title]) - const getContentOnCTC = () => { - const multiString = getMultiValsString() + useEffect(() => { + if (props.deployOption && props.deployOption[selectedDeployIndex]) { + if (props.deployOption[selectedDeployIndex].title === 'Deploy with Proxy') { + if (props.initializerOptions) { + setDeployInputs(props.initializerOptions.inputs.inputs) + setDeployPlaceholder(props.initializerOptions.initializeInputs) + setHasArgs(true) + if (props.initializerOptions.inputs.inputs.length > 1) setIsMultiField(true) + else setIsMultiField(false) + } else { + setDeployInputs([]) + setDeployPlaceholder('') + setHasArgs(false) + setIsMultiField(false) + } + } else { + if (props.funcABI) { + setDeployInputs(props.funcABI.inputs) + setDeployPlaceholder(props.inputs) + setHasArgs(true) + if (props.funcABI.inputs.length > 1) setIsMultiField(true) + else setIsMultiField(false) + } else { + setDeployInputs([]) + setDeployPlaceholder('') + setHasArgs(false) + setIsMultiField(false) + } + } + } else { + if (props.funcABI) { + setDeployInputs(props.funcABI.inputs) + setDeployPlaceholder(props.inputs) + setHasArgs(true) + if (props.funcABI.inputs.length > 1) setIsMultiField(true) + else setIsMultiField(false) + } else { + setDeployInputs([]) + setDeployPlaceholder('') + setHasArgs(false) + setIsMultiField(false) + } + } + }, [selectedDeployIndex, props.funcABI, props.initializerOptions]) + + const getContentOnCTC = (fields: HTMLInputElement[]) => { + const multiString = getMultiValsString(fields) // copy-to-clipboard icon is only visible for method requiring input params if (!multiString) { return 'cannot encode empty arguments' @@ -89,13 +150,13 @@ export function ContractGUI (props: ContractGUIProps) { const switchMethodViewOff = () => { setToggleContainer(false) - const multiValString = getMultiValsString() + const multiValString = getMultiValsString(multiFields.current) if (multiValString) setBasicInput(multiValString) } - const getMultiValsString = () => { - const valArray = multiFields.current + const getMultiValsString = (fields: HTMLInputElement[]) => { + const valArray = fields let ret = '' const valArrayTest = [] @@ -130,7 +191,8 @@ export function ContractGUI (props: ContractGUIProps) { if (inputString) { inputString = inputString.replace(/(^|,\s+|,)(\d+)(\s+,|,|$)/g, '$1"$2"$3') // replace non quoted number by quoted number inputString = inputString.replace(/(^|,\s+|,)(0[xX][0-9a-fA-F]+)(\s+,|,|$)/g, '$1"$2"$3') // replace non quoted hex string by quoted hex string - const inputJSON = JSON.parse('[' + inputString + ']') + inputString = JSON.stringify([inputString]) + const inputJSON = JSON.parse(inputString) const multiInputs = multiFields.current for (let k = 0; k < multiInputs.length; k++) { @@ -142,7 +204,9 @@ export function ContractGUI (props: ContractGUIProps) { } const handleActionClick = () => { - props.clickCallBack(props.funcABI.inputs, basicInput) + const deployMode = selectedDeployIndex !== null ? [props.deployOption[selectedDeployIndex].title] : [] + + props.clickCallBack(props.funcABI.inputs, basicInput, deployMode) } const handleBasicInput = (e) => { @@ -151,55 +215,90 @@ export function ContractGUI (props: ContractGUIProps) { setBasicInput(value) } - const handleExpandMultiClick = () => { - const valsString = getMultiValsString() + const handleMultiValsSubmit = (fields: HTMLInputElement[]) => { + const valsString = getMultiValsString(fields) + const deployMode = selectedDeployIndex !== null ? [props.deployOption[selectedDeployIndex].title] : [] if (valsString) { - props.clickCallBack(props.funcABI.inputs, valsString) + props.clickCallBack(props.funcABI.inputs, valsString, deployMode) } else { - props.clickCallBack(props.funcABI.inputs, '') + props.clickCallBack(props.funcABI.inputs, '', deployMode) } } + const setSelectedDeploy = (index: number) => { + setSelectedDeployIndex(index !== selectedDeployIndex ? index : null) + if (basicInputRef.current) basicInputRef.current.value = '' + setBasicInput('') + } + + const toggleOptions = () => { + setShowOptions(!showOptions) + } + return ( -
0) || (props.funcABI.type === 'fallback') || (props.funcABI.type === 'receive') ? 'udapp_hasArgs' : ''}`}> -
- - 0) || (props.funcABI.type === 'fallback') || (props.funcABI.type === 'receive')) ? 'hidden' : 'visible' }} /> - 0) ? 'hidden' : 'visible' }}> -
-
-
-
-
{title}
- -
-
- {props.funcABI.inputs.map((inp, index) => { - return ( -
- - { multiFields.current[index] = el }} className="form-control" placeholder={inp.type} title={inp.name} data-id={`multiParamManagerInput${inp.name}`} /> -
) - })} -
-
- - +
+ { + props.isDeploy ? !isMultiField ? + : : + <> +
+ + 0) || (props.funcABI.type === 'fallback') || (props.funcABI.type === 'receive')) ? 'hidden' : 'visible' }} /> + 0) ? 'hidden' : 'visible' }}> +
+
+
+
+
{title}
+ +
+
+ {props.funcABI.inputs.map((inp, index) => { + return ( +
+ + { multiFields.current[index] = el }} className="form-control" placeholder={inp.type} title={inp.name} data-id={`multiParamManagerInput${inp.name}`} /> +
) + })} +
+
+ getContentOnCTC(multiFields.current)} /> + +
-
+ + }
) } diff --git a/libs/remix-ui/run-tab/src/lib/components/deployButton.tsx b/libs/remix-ui/run-tab/src/lib/components/deployButton.tsx new file mode 100644 index 0000000000..ced72344d5 --- /dev/null +++ b/libs/remix-ui/run-tab/src/lib/components/deployButton.tsx @@ -0,0 +1,33 @@ +import React, { useState } from 'react' +import { DeployButtonProps } from '../types' +import { ButtonGroup, Dropdown } from 'react-bootstrap' + +export function DeployButton (props: DeployButtonProps) { + const [showOptions, setShowOptions] = useState(false) + + const toggleOptions = () => { + setShowOptions(!showOptions) + } + + return ( + <> + { props.deployOptions && (props.deployOptions || []).length > 0 ? + + + + + { + (props.deployOptions).map(({ title, active }, index) => { + props.setSelectedIndex(index) + toggleOptions() + }} key={index}> { props.selectedIndex === index ? ✓ {title} : {title} }) + } + + : + + } + + ) +} diff --git a/libs/remix-ui/run-tab/src/lib/components/deployInput.tsx b/libs/remix-ui/run-tab/src/lib/components/deployInput.tsx new file mode 100644 index 0000000000..26fcf2a164 --- /dev/null +++ b/libs/remix-ui/run-tab/src/lib/components/deployInput.tsx @@ -0,0 +1,20 @@ +import React from 'react' +import { DeployInputProps } from '../types' +import { DeployButton } from './deployButton' + +export function DeployInput (props: DeployInputProps) { + return ( +
+ + +
+ ) +} diff --git a/libs/remix-ui/run-tab/src/lib/components/environment.tsx b/libs/remix-ui/run-tab/src/lib/components/environment.tsx index 4853f6f12b..c63f1ba88f 100644 --- a/libs/remix-ui/run-tab/src/lib/components/environment.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/environment.tsx @@ -29,7 +29,7 @@ export function EnvironmentUI (props: EnvironmentProps) { ) } - +
) diff --git a/libs/remix-ui/run-tab/src/lib/components/gasPrice.tsx b/libs/remix-ui/run-tab/src/lib/components/gasPrice.tsx index 19e7876a75..a7c5335abd 100644 --- a/libs/remix-ui/run-tab/src/lib/components/gasPrice.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/gasPrice.tsx @@ -10,7 +10,7 @@ export function GasPriceUI (props: GasPriceProps) { return (
- +
) } diff --git a/libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx b/libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx index afc97b9dac..5c2800ef4d 100644 --- a/libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx @@ -12,7 +12,7 @@ export function InstanceContainerUI (props: InstanceContainerProps) { return (
-
-
-
- All transactions (deployed contracts and function executions) can be saved and replayed in - another environment. e.g Transactions created in Javascript VM can be replayed in the Injected Web3. -
-
- - -
+
+
+ + +
+
+ + Save {props.count} transaction(s) as scenario file. + + + }> + + + + Run transaction(s) from the current scenario file. + + + }> + + +
) diff --git a/libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx b/libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx index 4719fe2a88..ad3c48cabc 100644 --- a/libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx @@ -119,7 +119,6 @@ export function UniversalDappUI (props: UdappProps) { props.instance.contractData, address, logMsg, - props.logBuilder, props.mainnetPrompt, props.gasEstimationPrompt, props.passphrasePrompt, @@ -184,7 +183,7 @@ export function UniversalDappUI (props: UdappProps) { const renderData = (item, parent, key: string | number, keyPath: string) => { const data = extractDataDefault(item, parent) - const children = (data.children || []).map((child) => { + const children = (data.children || []).map((child, index) => { return ( renderData(child.value, data, child.key, keyPath + '/' + child.key) ) @@ -206,9 +205,9 @@ export function UniversalDappUI (props: UdappProps) { return (
- +
@@ -237,7 +236,7 @@ export function UniversalDappUI (props: UdappProps) { const lookupOnly = funcABI.stateMutability === 'view' || funcABI.stateMutability === 'pure' || isConstant const inputs = props.getFuncABIInputs(funcABI) - return <> + return
{ @@ -255,14 +254,14 @@ export function UniversalDappUI (props: UdappProps) { const funcIndex = index.toString() const response = props.instance.decodedResponse[key] - return key === funcIndex ? Object.keys(response || {}).map((innerkey) => { + return key === funcIndex ? Object.keys(response || {}).map((innerkey, index) => { return renderData(props.instance.decodedResponse[key][innerkey], response, innerkey, innerkey) }) : null }) }
- +
}) }
diff --git a/libs/remix-ui/run-tab/src/lib/components/value.tsx b/libs/remix-ui/run-tab/src/lib/components/value.tsx index 3b2008a5f1..6728639a45 100644 --- a/libs/remix-ui/run-tab/src/lib/components/value.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/value.tsx @@ -58,7 +58,7 @@ export function ValueUI (props: ValueProps) { className="form-control udapp_gasNval udapp_col2" id="value" data-id="dandrValue" - title="Enter the value and choose the unit" + title="Enter an amount and choose its unit" onKeyPress={validateInputKey} onChange={validateValue} value={props.sendValue} diff --git a/libs/remix-ui/run-tab/src/lib/constants/index.ts b/libs/remix-ui/run-tab/src/lib/constants/index.ts new file mode 100644 index 0000000000..ae8af3c708 --- /dev/null +++ b/libs/remix-ui/run-tab/src/lib/constants/index.ts @@ -0,0 +1,47 @@ +export const FETCH_ACCOUNTS_LIST_REQUEST = 'FETCH_ACCOUNTS_LIST_REQUEST' +export const FETCH_ACCOUNTS_LIST_SUCCESS = 'FETCH_ACCOUNTS_LIST_SUCCESS' +export const FETCH_ACCOUNTS_LIST_FAILED = 'FETCH_ACCOUNTS_LIST_FAILED' +export const SET_SEND_VALUE = 'SET_SEND_VALUE' +export const SET_SELECTED_ACCOUNT = 'SET_SELECTED_ACCOUNT' +export const SET_SEND_UNIT = 'SET_SEND_UNIT' +export const SET_GAS_LIMIT = 'SET_GAS_LIMIT' +export const SET_EXECUTION_ENVIRONMENT = 'SET_EXECUTION_ENVIRONMENT' +export const SET_PERSONAL_MODE = 'SET_PERSONAL_MODE' +export const SET_NETWORK_NAME = 'SET_NETWORK_NAME' +export const FETCH_PROVIDER_LIST_REQUEST = 'FETCH_PROVIDER_LIST_REQUEST' +export const FETCH_PROVIDER_LIST_SUCCESS = 'FETCH_PROVIDER_LIST_SUCCESS' +export const FETCH_PROVIDER_LIST_FAILED = 'FETCH_PROVIDER_LIST_FAILED' +export const ADD_PROVIDER = 'ADD_PROVIDER' +export const REMOVE_PROVIDER = 'REMOVE_PROVIDER' +export const DISPLAY_NOTIFICATION = 'DISPLAY_NOTIFICATION' +export const HIDE_NOTIFICATION = 'HIDE_NOTIFICATION' +export const SET_EXTERNAL_WEB3_ENDPOINT = 'SET_EXTERNAL_WEB3_ENDPOINT' +export const DISPLAY_POPUP_MESSAGE = 'DISPLAY_POPUP_MESSAGE' +export const HIDE_POPUP_MESSAGE = 'HIDE_POPUP_MESSAGE' +export const SET_PASSPHRASE = 'SET_PASSPHRASE' +export const SET_MATCH_PASSPHRASE = 'SET_MATCH_PASSPHRASE' +export const FETCH_CONTRACT_LIST_REQUEST = 'FETCH_CONTRACT_LIST_REQUEST' +export const FETCH_CONTRACT_LIST_SUCCESS = 'FETCH_CONTRACT_LIST_SUCCESS' +export const FETCH_CONTRACT_LIST_FAILED = 'FETCH_CONTRACT_LIST_FAILED' +export const SET_LOAD_TYPE = 'SET_LOAD_TYPE' +export const SET_CURRENT_FILE = 'SET_CURRENT_FILE' +export const SET_IPFS_CHECKED_STATE = 'SET_IPFS_CHECKED_STATE' +export const SET_GAS_PRICE_STATUS = 'SET_GAS_PRICE_STATUS' +export const SET_CONFIRM_SETTINGS = 'SET_CONFIRM_SETTINGS' +export const SET_MAX_FEE = 'SET_MAX_FEE' +export const SET_MAX_PRIORITY_FEE = 'SET_MAX_PRIORITY_FEE' +export const SET_BASE_FEE_PER_GAS = 'SET_BASE_FEE_PER_GAS' +export const SET_GAS_PRICE = 'SET_GAS_PRICE' +export const SET_TX_FEE_CONTENT = 'SET_TX_FEE_CONTENT' +export const ADD_INSTANCE = 'ADD_INSTANCE' +export const REMOVE_INSTANCE = 'REMOVE_INSTANCE' +export const CLEAR_INSTANCES = 'CLEAR_INSTANCES' +export const SET_DECODED_RESPONSE = 'SET_DECODED_RESPONSE' +export const SET_PATH_TO_SCENARIO = 'SET_PATH_TO_SCENARIO' +export const SET_RECORDER_COUNT = 'SET_RECORDER_COUNT' +export const CLEAR_RECORDER_COUNT = 'CLEAR_RECORDER_COUNT' +export const RESET_STATE = 'RESET_STATE' +export const ADD_DEPLOY_OPTION = 'ADD_DEPLOY_OPTION' +export const REMOVE_DEPLOY_OPTION = 'REMOVE_DEPLOY_OPTION' +export const SET_DEPLOY_OPTIONS = 'SET_DEPLOY_OPTIONS' +export const SET_CURRENT_CONTRACT = 'SET_CURRENT_CONTRACT' \ No newline at end of file diff --git a/libs/remix-ui/run-tab/src/lib/css/run-tab.css b/libs/remix-ui/run-tab/src/lib/css/run-tab.css index 5ad8e6774c..60cf8ad00f 100644 --- a/libs/remix-ui/run-tab/src/lib/css/run-tab.css +++ b/libs/remix-ui/run-tab/src/lib/css/run-tab.css @@ -276,7 +276,7 @@ color: var(--primary); } .udapp_titleExpander { - padding: 5px 7px; + margin-top: 2px; } .udapp_nameNbuts { display: contents; @@ -401,7 +401,6 @@ } .udapp_contractActionsContainerMultiInner { width: 100%; - padding: 16px 8px 16px 14px; border-radius: 3px; margin-bottom: 8px; } @@ -513,4 +512,22 @@ white-space: -o-pre-wrap; /* Opera 7 */ word-wrap: break-word; /* Internet Explorer 5.5+ */ } +.deploy-items { + padding: 0.25rem 0.25rem; + border-radius: .25rem; +} +.deploy-items a { + border-radius: .25rem; + text-transform: none; + text-decoration: none; + font-weight: normal; + font-size: .8rem; + padding: 0.25rem 0.25rem; + width:auto; +} +.dropdown-item.hover, .dropdown-item:hover { + color: #fff; + text-decoration: none; + background-color: #007aa6; +} diff --git a/libs/remix-ui/run-tab/src/lib/reducers/runTab.ts b/libs/remix-ui/run-tab/src/lib/reducers/runTab.ts index 174cef7fe0..20ecb8b1ef 100644 --- a/libs/remix-ui/run-tab/src/lib/reducers/runTab.ts +++ b/libs/remix-ui/run-tab/src/lib/reducers/runTab.ts @@ -1,5 +1,7 @@ import { CompilerAbstract } from '@remix-project/remix-solidity-ts' import { ContractData } from '@remix-project/core-plugin' +import { DeployMode, DeployOption, DeployOptions } from '../types' +import { ADD_DEPLOY_OPTION, ADD_INSTANCE, ADD_PROVIDER, CLEAR_INSTANCES, CLEAR_RECORDER_COUNT, DISPLAY_NOTIFICATION, DISPLAY_POPUP_MESSAGE, FETCH_ACCOUNTS_LIST_FAILED, FETCH_ACCOUNTS_LIST_REQUEST, FETCH_ACCOUNTS_LIST_SUCCESS, FETCH_CONTRACT_LIST_FAILED, FETCH_CONTRACT_LIST_REQUEST, FETCH_CONTRACT_LIST_SUCCESS, FETCH_PROVIDER_LIST_FAILED, FETCH_PROVIDER_LIST_REQUEST, FETCH_PROVIDER_LIST_SUCCESS, HIDE_NOTIFICATION, HIDE_POPUP_MESSAGE, REMOVE_DEPLOY_OPTION, REMOVE_INSTANCE, REMOVE_PROVIDER, RESET_STATE, SET_BASE_FEE_PER_GAS, SET_CONFIRM_SETTINGS, SET_CURRENT_CONTRACT, SET_CURRENT_FILE, SET_DECODED_RESPONSE, SET_DEPLOY_OPTIONS, SET_EXECUTION_ENVIRONMENT, SET_EXTERNAL_WEB3_ENDPOINT, SET_GAS_LIMIT, SET_GAS_PRICE, SET_GAS_PRICE_STATUS, SET_IPFS_CHECKED_STATE, SET_LOAD_TYPE, SET_MATCH_PASSPHRASE, SET_MAX_FEE, SET_MAX_PRIORITY_FEE, SET_NETWORK_NAME, SET_PASSPHRASE, SET_PATH_TO_SCENARIO, SET_PERSONAL_MODE, SET_RECORDER_COUNT, SET_SELECTED_ACCOUNT, SET_SEND_UNIT, SET_SEND_VALUE, SET_TX_FEE_CONTENT } from '../constants' interface Action { type: string payload: any @@ -62,8 +64,10 @@ export interface RunTabState { compiler: CompilerAbstract }[] }, + deployOptions: DeployOptions loadType: 'abi' | 'sol' | 'other' currentFile: string, + currentContract: string, compilationCount: number, isRequesting: boolean, isSuccessful: boolean, @@ -111,14 +115,14 @@ export const runTabInitialState: RunTabState = { providerList: [{ id: 'vm-mode-london', dataId: 'settingsVMLondonMode', - title: 'Execution environment does not connect to any node, everything is local and in memory only.', + title: 'Execution environment is local to Remix. Data is only saved to browser memory and will vanish upon reload.', value: 'vm-london', fork: 'london', content: 'JavaScript VM (London)' }, { id: 'vm-mode-berlin', dataId: 'settingsVMBerlinMode', - title: 'Execution environment does not connect to any node, everything is local and in memory only.', + title: 'Execution environment is local to Remix. Data is only saved to browser memory and will vanish upon reload.', value: 'vm-berlin', fork: 'berlin', content: 'JavaScript VM (Berlin)' @@ -131,8 +135,7 @@ export const runTabInitialState: RunTabState = { }, { id: 'web3-mode', dataId: 'settingsWeb3Mode', - title: `Execution environment connects to node at localhost (or via IPC if available), transactions will be sent to the network and can cause loss of money or worse! - If this page is served via https and you access your node via http, it might not work. In this case, try cloning the repository and serving it via http.`, + title: `Execution environment connects to an external node. For security, only connect to trusted networks. If Remix is served via https and your node is accessed via http, it might not work. In this case, try cloning the repository and serving it via http.`, value: 'web3', content: 'Web3 Provider' }], @@ -154,8 +157,10 @@ export const runTabInitialState: RunTabState = { matchPassphrase: '', contracts: { contractList: {}, + deployOptions: {} as any, loadType: 'other', currentFile: '', + currentContract: '', compilationCount: 0, isRequesting: false, isSuccessful: false, @@ -186,7 +191,7 @@ type AddProvider = { export const runTabReducer = (state: RunTabState = runTabInitialState, action: Action) => { switch (action.type) { - case 'FETCH_ACCOUNTS_LIST_REQUEST': { + case FETCH_ACCOUNTS_LIST_REQUEST: { return { ...state, accounts: { @@ -198,7 +203,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'FETCH_ACCOUNTS_LIST_SUCCESS': { + case FETCH_ACCOUNTS_LIST_SUCCESS: { const payload: Record = action.payload return { @@ -213,7 +218,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'FETCH_ACCOUNTS_LIST_FAILED': { + case FETCH_ACCOUNTS_LIST_FAILED: { const payload: string = action.payload return { @@ -227,7 +232,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_SEND_VALUE': { + case SET_SEND_VALUE: { const payload: string = action.payload return { @@ -236,7 +241,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_SELECTED_ACCOUNT': { + case SET_SELECTED_ACCOUNT: { const payload: string = action.payload return { @@ -248,7 +253,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_SEND_UNIT': { + case SET_SEND_UNIT: { const payload: 'ether' | 'finney' | 'gwei' | 'wei' = action.payload return { @@ -257,7 +262,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_GAS_LIMIT': { + case SET_GAS_LIMIT: { const payload: number = action.payload return { @@ -266,7 +271,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_EXECUTION_ENVIRONMENT': { + case SET_EXECUTION_ENVIRONMENT: { const payload: string = action.payload return { @@ -281,7 +286,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_PERSONAL_MODE': { + case SET_PERSONAL_MODE: { const payload: boolean = action.payload return { @@ -290,7 +295,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_NETWORK_NAME': { + case SET_NETWORK_NAME: { const payload: string = action.payload return { @@ -299,7 +304,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'FETCH_PROVIDER_LIST_REQUEST': { + case FETCH_PROVIDER_LIST_REQUEST: { return { ...state, providers: { @@ -311,7 +316,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'FETCH_PROVIDER_LIST_SUCCESS': { + case FETCH_PROVIDER_LIST_SUCCESS: { const payload: { id?: string, dataId?: string, title?: string, value: string, fork?: string, content: string }[] = action.payload return { @@ -326,7 +331,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'FETCH_PROVIDER_LIST_FAILED': { + case FETCH_PROVIDER_LIST_FAILED: { const payload: string = action.payload return { @@ -340,7 +345,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'ADD_PROVIDER': { + case ADD_PROVIDER: { const payload: AddProvider = action.payload const id = action.payload.name state.providers.providerList.push({ @@ -359,7 +364,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'REMOVE_PROVIDER': { + case REMOVE_PROVIDER: { const id: string = action.payload const providers = state.providers.providerList.filter((el) => el.id !== id) return { @@ -371,7 +376,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'DISPLAY_NOTIFICATION': { + case DISPLAY_NOTIFICATION: { const payload = action.payload as { title: string, message: string, actionOk: () => void, actionCancel: () => void, labelOk: string, labelCancel: string } return { @@ -387,14 +392,14 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'HIDE_NOTIFICATION': { + case HIDE_NOTIFICATION: { return { ...state, notification: runTabInitialState.notification } } - case 'SET_EXTERNAL_WEB3_ENDPOINT': { + case SET_EXTERNAL_WEB3_ENDPOINT: { const payload: string = action.payload return { @@ -403,7 +408,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'DISPLAY_POPUP_MESSAGE': { + case DISPLAY_POPUP_MESSAGE: { const payload = action.payload as string return { @@ -412,14 +417,14 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'HIDE_POPUP_MESSAGE': { + case HIDE_POPUP_MESSAGE: { return { ...state, popup: '' } } - case 'SET_PASSPHRASE': { + case SET_PASSPHRASE: { const passphrase: string = action.payload return { @@ -428,7 +433,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_MATCH_PASSPHRASE': { + case SET_MATCH_PASSPHRASE: { const passphrase: string = action.payload return { @@ -437,7 +442,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'FETCH_CONTRACT_LIST_REQUEST': { + case FETCH_CONTRACT_LIST_REQUEST: { return { ...state, contracts: { @@ -449,7 +454,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'FETCH_CONTRACT_LIST_SUCCESS': { + case FETCH_CONTRACT_LIST_SUCCESS: { const payload: ContractList = action.payload return { @@ -464,7 +469,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'FETCH_CONTRACT_LIST_FAILED': { + case FETCH_CONTRACT_LIST_FAILED: { const payload: string = action.payload return { @@ -478,7 +483,19 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_LOAD_TYPE': { + case SET_CURRENT_CONTRACT: { + const payload: string = action.payload + + return { + ...state, + contracts: { + ...state.contracts, + currentContract: payload + } + } + } + + case SET_LOAD_TYPE: { const payload: 'abi' | 'sol' | 'other' = action.payload return { @@ -490,7 +507,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_CURRENT_FILE': { + case SET_CURRENT_FILE: { const payload: string = action.payload return { @@ -503,7 +520,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_IPFS_CHECKED_STATE': { + case SET_IPFS_CHECKED_STATE: { const payload: boolean = action.payload return { @@ -512,7 +529,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_GAS_PRICE_STATUS': { + case SET_GAS_PRICE_STATUS: { const payload: boolean = action.payload return { @@ -521,7 +538,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_CONFIRM_SETTINGS': { + case SET_CONFIRM_SETTINGS: { const payload: boolean = action.payload return { @@ -530,7 +547,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_MAX_FEE': { + case SET_MAX_FEE: { const payload: string = action.payload return { @@ -539,7 +556,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_MAX_PRIORITY_FEE': { + case SET_MAX_PRIORITY_FEE: { const payload: string = action.payload return { @@ -548,7 +565,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_BASE_FEE_PER_GAS': { + case SET_BASE_FEE_PER_GAS: { const payload: string = action.payload return { @@ -557,7 +574,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_GAS_PRICE': { + case SET_GAS_PRICE: { const payload: string = action.payload return { @@ -566,7 +583,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_TX_FEE_CONTENT': { + case SET_TX_FEE_CONTENT: { const payload: string = action.payload return { @@ -575,7 +592,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'ADD_INSTANCE': { + case ADD_INSTANCE: { const payload: { contractData: ContractData, address: string, name: string, abi?: any, decodedResponse?: Record } = action.payload return { @@ -587,7 +604,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'REMOVE_INSTANCE': { + case REMOVE_INSTANCE: { const payload: number = action.payload return { @@ -599,7 +616,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'CLEAR_INSTANCES': { + case CLEAR_INSTANCES: { return { ...state, instances: { @@ -609,7 +626,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_DECODED_RESPONSE': { + case SET_DECODED_RESPONSE: { const payload: { instanceIndex: number, funcIndex: number, response: any } = action.payload return { @@ -624,7 +641,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_PATH_TO_SCENARIO': { + case SET_PATH_TO_SCENARIO: { const payload: string = action.payload return { @@ -636,7 +653,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'SET_RECORDER_COUNT': { + case SET_RECORDER_COUNT: { const payload: number = action.payload return { @@ -648,7 +665,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'CLEAR_RECORDER_COUNT': { + case CLEAR_RECORDER_COUNT: { return { ...state, recorder: { @@ -658,13 +675,57 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } - case 'RESET_STATE': { + case RESET_STATE: { return { ...runTabInitialState, ipfsChecked: state.ipfsChecked } } + case ADD_DEPLOY_OPTION: { + const payload: { title: DeployMode, active: boolean } = action.payload + + return { + ...state, + contracts: { + ...state.contracts, + deployOptions: { + ...state.contracts.deployOptions, + options: [...state.contracts.deployOptions.options, payload] + } + } + } + } + + case REMOVE_DEPLOY_OPTION: { + const payload: string = action.payload + const options = state.contracts.deployOptions.options.filter(val => val.title !== payload) + + + return { + ...state, + contracts: { + ...state.contracts, + deployOptions: { + ...state.contracts.deployOptions, + options + } + } + } + } + + case SET_DEPLOY_OPTIONS: { + const payload: DeployOptions = action.payload + + return { + ...state, + contracts: { + ...state.contracts, + deployOptions: payload + } + } + } + default: return state } diff --git a/libs/remix-ui/run-tab/src/lib/run-tab.tsx b/libs/remix-ui/run-tab/src/lib/run-tab.tsx index 45e343fdbc..f8715ac16e 100644 --- a/libs/remix-ui/run-tab/src/lib/run-tab.tsx +++ b/libs/remix-ui/run-tab/src/lib/run-tab.tsx @@ -11,22 +11,22 @@ import { Modal, Network, RunTabProps, Tx } from './types' import { ContractData } from '@remix-project/core-plugin' import { runTabInitialState, runTabReducer } from './reducers/runTab' import { - initRunTab, setAccount, - setUnit, setGasFee, - setExecutionContext, setWeb3Endpoint, - clearPopUp, createNewBlockchainAccount, - setPassphrasePrompt, setMatchPassphrasePrompt, - signMessageWithAddress, getSelectedContract, - createInstance, setSendTransactionValue, - updateBaseFeePerGas, updateConfirmSettings, - updateGasPrice, updateGasPriceStatus, - updateMaxFee, updateMaxPriorityFee, - updateTxFeeContent, clearInstances, - removeInstance, getContext, - runTransactions, loadAddress, - storeScenario, runCurrentScenario, - updateScenarioPath, getFuncABIInputs, - setNetworkNameFromProvider + initRunTab, setAccountAddress, + setUnitValue, setGasFeeAmount, + setExecutionEnvironment, + hideToaster, createNewAddress, + setPassphraseModal, setMatchPassphraseModal, + signMessage, fetchSelectedContract, + createNewInstance, setSendValue, + setBaseFeePerGas, setConfirmSettings, + setGasPrice, setGasPriceStatus, + setMaxFee, setMaxPriorityFee, + setTxFeeContent, removeInstances, + removeSingleInstance, getExecutionContext, + executeTransactions, loadFromAddress, + storeNewScenario, runScenario, + setScenarioPath, getFuncABIValues, + setNetworkName, updateSelectedContract } from './actions' import './css/run-tab.css' import { PublishToStorage } from '@remix-ui/publish-to-storage' @@ -134,7 +134,7 @@ export function RunTabUI (props: RunTabProps) { const handleToaster = () => { setFocusToaster('') - clearPopUp() + hideToaster() } const toast = (toasterMsg: string) => { @@ -166,16 +166,12 @@ export function RunTabUI (props: RunTabProps) { ) } - const logBuilder = (msg: string) => { - return
{msg}
- } - const passphrasePrompt = (message: string) => { - return + return } const scenarioPrompt = (message: string, defaultValue) => { - return + return } const mainnetPrompt = (tx: Tx, network: Network, amount: string, gasEstimation: string, gasFees: (maxFee: string, cb: (txFeeText: string, priceStatus: boolean) => void) => void, determineGasPrice: (cb: (txFeeText: string, gasPriceValue: string, gasPriceStatus: boolean) => void) => void) => { @@ -186,13 +182,13 @@ export function RunTabUI (props: RunTabProps) { amount={amount} gasEstimation={gasEstimation} setNewGasPrice={gasFees} - updateBaseFeePerGas={updateBaseFeePerGas} - updateConfirmSettings={updateConfirmSettings} - updateGasPrice={updateGasPrice} - updateGasPriceStatus={updateGasPriceStatus} - updateMaxFee={updateMaxFee} - updateMaxPriorityFee={updateMaxPriorityFee} - setTxFeeContent={updateTxFeeContent} + updateBaseFeePerGas={setBaseFeePerGas} + updateConfirmSettings={setConfirmSettings} + updateGasPrice={setGasPrice} + updateGasPriceStatus={setGasPriceStatus} + updateMaxFee={setMaxFee} + updateMaxPriorityFee={setMaxPriorityFee} + setTxFeeContent={setTxFeeContent} txFeeContent={runTab.txFeeContent} maxFee={runTab.maxFee} maxPriorityFee={runTab.maxPriorityFee} @@ -207,67 +203,64 @@ export function RunTabUI (props: RunTabProps) { networkName={runTab.networkName} personalMode={runTab.personalMode} selectExEnv={runTab.selectExEnv} - setWeb3Endpoint={setWeb3Endpoint} accounts={runTab.accounts} - setAccount={setAccount} - setUnit={setUnit} + setAccount={setAccountAddress} + setUnit={setUnitValue} sendValue={runTab.sendValue} - setSendValue={setSendTransactionValue} + setSendValue={setSendValue} sendUnit={runTab.sendUnit} gasLimit={runTab.gasLimit} - setGasFee={setGasFee} + setGasFee={setGasFeeAmount} providers={runTab.providers} - setExecutionContext={setExecutionContext} - createNewBlockchainAccount={createNewBlockchainAccount} - setPassphrase={setPassphrasePrompt} - setMatchPassphrase={setMatchPassphrasePrompt} + setExecutionContext={setExecutionEnvironment} + createNewBlockchainAccount={createNewAddress} + setPassphrase={setPassphraseModal} + setMatchPassphrase={setMatchPassphraseModal} modal={modal} tooltip={toast} - signMessageWithAddress={signMessageWithAddress} + signMessageWithAddress={signMessage} passphrase={runTab.passphrase} />
diff --git a/libs/remix-ui/run-tab/src/lib/types/index.ts b/libs/remix-ui/run-tab/src/lib/types/index.ts index 5f1d2fb496..c304d8815f 100644 --- a/libs/remix-ui/run-tab/src/lib/types/index.ts +++ b/libs/remix-ui/run-tab/src/lib/types/index.ts @@ -1,3 +1,4 @@ +import { Ref } from 'react' import { CompilerAbstract } from '@remix-project/remix-solidity-ts' import { ContractData, FuncABI } from '@remix-project/core-plugin' import { ContractList } from '../reducers/runTab' @@ -21,7 +22,6 @@ export interface SettingsProps { sendUnit: string, gasLimit: number, setGasFee: (value: number) => void, - setWeb3Endpoint: (endpoint: string) => void, personalMode: boolean, networkName: string, providers: { @@ -128,8 +128,10 @@ export interface ContractDropdownProps { exEnvironment: string, contracts: { contractList: ContractList, + deployOptions: DeployOptions, loadType: 'abi' | 'sol' | 'other', currentFile: string, + currentContract: string, compilationCount: number, isRequesting: boolean, isSuccessful: boolean, @@ -143,29 +145,28 @@ export interface ContractDropdownProps { selectedContract: ContractData, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, - logBuilder: (msg: string) => JSX.Element, publishToStorage: (storage: 'ipfs' | 'swarm', contract: ContractData) => void, mainnetPrompt: MainnetPrompt, isOverSizePrompt: () => JSX.Element, - args) => void, + args, + deployMode: DeployMode[]) => void, ipfsCheckedState: boolean, setIpfsCheckedState: (value: boolean) => void, publishToStorage: (storage: 'ipfs' | 'swarm', contract: ContractData) => void, gasEstimationPrompt: (msg: string) => JSX.Element, - logBuilder: (msg: string) => JSX.Element, passphrasePrompt: (message: string) => JSX.Element, mainnetPrompt: (tx: Tx, network: Network, amount: string, gasEstimation: string, gasFees: (maxFee: string, cb: (txFeeText: string, priceStatus: boolean) => void) => void, determineGasPrice: (cb: (txFeeText: string, gasPriceValue: string, gasPriceStatus: boolean) => void) => void) => JSX.Element, tooltip: (toasterMsg: string | JSX.Element) => void, loadAddress: (contract: ContractData, address: string) => void, networkName: string, - setNetworkName: (name: string) => void + setNetworkName: (name: string) => void, + setSelectedContract: (contractName: string) => void } export interface RecorderProps { storeScenario: (prompt: (msg: string, defaultValue: string) => JSX.Element) => void, - runCurrentScenario: (gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, confirmDialogContent: MainnetPrompt, logBuilder: (msg: string) => JSX.Element) => void, - logBuilder: (msg: string) => JSX.Element, + runCurrentScenario: (liveMode: boolean, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, confirmDialogContent: MainnetPrompt) => void, mainnetPrompt: MainnetPrompt, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, @@ -196,13 +197,11 @@ export interface InstanceContainerProps { contractABI, contract, address, logMsg:string, - logBuilder: (msg: string) => JSX.Element, mainnetPrompt: MainnetPrompt, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, funcIndex?: number) => void, gasEstimationPrompt: (msg: string) => JSX.Element, - logBuilder: (msg: string) => JSX.Element, passphrasePrompt: (message: string) => JSX.Element, mainnetPrompt: (tx: Tx, network: Network, amount: string, gasEstimation: string, gasFees: (maxFee: string, cb: (txFeeText: string, priceStatus: boolean) => void) => void, determineGasPrice: (cb: (txFeeText: string, gasPriceValue: string, gasPriceStatus: boolean) => void) => void) => JSX.Element, sendValue: string, @@ -220,15 +219,43 @@ export interface Modal { cancelFn: () => void } +export type DeployMode = 'Deploy with Proxy' | 'Upgrade Proxy' + +export type DeployOption = { + initializeInputs: string, + inputs: { + inputs: { + internalType?: string, + name: string, + type: string + }[], + name: "initialize", + outputs?: any[], + stateMutability: string, + type: string, + payable?: boolean, + constant?: any + } +} +export interface DeployOptions { + initializeOptions: { + [key: string]: DeployOption + }, + options: { title: DeployMode, active: boolean }[], +} + export interface ContractGUIProps { title?: string, funcABI: FuncABI, - inputs: any, - clickCallBack: (inputs: { name: string, type: string }[], input: string) => void, + inputs: string, + clickCallBack: (inputs: { name: string, type: string }[], input: string, deployMode?: DeployMode[]) => void, widthClass?: string, evmBC: any, lookupOnly: boolean, - disabled?: boolean + disabled?: boolean, + isDeploy?: boolean, + deployOption?: { title: DeployMode, active: boolean }[], + initializerOptions?: DeployOption } export interface MainnetProps { network: Network, @@ -261,7 +288,6 @@ export interface UdappProps { removeInstance: (index: number) => void, index: number, gasEstimationPrompt: (msg: string) => JSX.Element, - logBuilder: (msg: string) => JSX.Element, passphrasePrompt: (message: string) => JSX.Element, mainnetPrompt: (tx: Tx, network: Network, amount: string, gasEstimation: string, gasFees: (maxFee: string, cb: (txFeeText: string, priceStatus: boolean) => void) => void, determineGasPrice: (cb: (txFeeText: string, gasPriceValue: string, gasPriceStatus: boolean) => void) => void) => JSX.Element, runTransactions: ( @@ -273,7 +299,6 @@ export interface UdappProps { contractABI, contract, address, logMsg:string, - logBuilder: (msg: string) => JSX.Element, mainnetPrompt: MainnetPrompt, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, @@ -281,3 +306,55 @@ export interface UdappProps { sendValue: string, getFuncABIInputs: (funcABI: FuncABI) => string } + +export interface DeployButtonProps { + deployOptions: { title: DeployMode, active: boolean }[], + buttonOptions: { + title: string, + content: string, + classList: string, + dataId: string, + widthClass: string + }, + selectedIndex: number, + setSelectedIndex: (index: number) => void, + handleActionClick: () => void +} + +export interface DeployInputProps { + funcABI: FuncABI, + inputs: string, + handleBasicInput: (e) => void, + basicInputRef: Ref, + buttonOptions: { + title: string, + content: string, + classList: string, + dataId: string, + widthClass: string + }, + selectedIndex: number, + setSelectedIndex: (index: number) => void, + handleActionClick: (fields?: HTMLInputElement[]) => void, + deployOptions: { title: DeployMode, active: boolean }[] +} + +export interface MultiDeployInputProps { + deployOptions?: { title: DeployMode, active: boolean }[], + buttonOptions: { + title: string, + content: string, + classList: string, + dataId: string, + widthClass: string + }, + selectedIndex: number, + setSelectedIndex: (index: number) => void, + handleMultiValsSubmit: (fields?: HTMLInputElement[]) => void, + inputs: { + internalType?: string, + name: string, + type: string + }[], + getMultiValsString: (fields: HTMLInputElement[]) => void +} diff --git a/libs/remix-ui/run-tab/src/lib/types/recorder.d.ts b/libs/remix-ui/run-tab/src/lib/types/recorder.d.ts index 44f79bda4f..3c4ec18c20 100644 --- a/libs/remix-ui/run-tab/src/lib/types/recorder.d.ts +++ b/libs/remix-ui/run-tab/src/lib/types/recorder.d.ts @@ -9,7 +9,7 @@ export class Recorder { getAll: () => void; clearAll: () => void; run: (records, accounts, options, abis, linkReferences, confirmationCb, continueCb, promptCb, alertCb, logCallBack, newContractFn) => void - runScenario: (json, continueCb, promptCb, alertCb, confirmationCb, logCallBack, cb) => void + runScenario: (liveMode, json, continueCb, promptCb, alertCb, confirmationCb, logCallBack, cb) => void } import { Blockchain } from "./blockchain"; 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 bc06aae822..26a526e510 100644 --- a/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx +++ b/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx @@ -754,7 +754,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
- handleLanguageChange(e.target.value)} disabled={state.useFileConfiguration} value={state.language} className="custom-select" id="compilierLanguageSelector" title="Language specification available from Compiler >= v0.5.7"> @@ -789,7 +789,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
{ (!showFilePathInput && state.useFileConfiguration) && {} : openFile} className="py-2 remixui_compilerConfigPath" >{configFilePath === '' ? 'No file selected.' : configFilePath} } @@ -861,7 +861,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => { }> - '@custom:dev-run-script file_path'} direction='top'> + '@custom:dev-run-script file_path'} direction='top'> diff --git a/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx b/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx index 30f1b2e0df..8f55fe2ea7 100644 --- a/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx +++ b/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx @@ -677,7 +677,7 @@ export const SolidityUnitTesting = (props: Record) => { // eslint-d