diff --git a/.circleci/config.yml b/.circleci/config.yml index 8bcbed1fca..988b8940ea 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -323,7 +323,7 @@ jobs: environment: - COMMIT_AUTHOR_EMAIL: "yann@ethereum.org" - COMMIT_AUTHOR: "Circle CI" - - FILES_TO_PACKAGE: "dist/apps/remix-ide/index.html dist/apps/remix-ide/raw-loader*.js dist/apps/remix-ide/assets dist/apps/remix-ide/main*.js dist/apps/remix-ide/polyfills*.js dist/apps/remix-ide/favicon.ico dist/apps/remix-ide/vendors~app*.js dist/apps/remix-ide/app*.js" + - FILES_TO_PACKAGE: "dist/apps/remix-ide/index.html dist/apps/remix-ide/404.html dist/apps/remix-ide/raw-loader*.js dist/apps/remix-ide/assets dist/apps/remix-ide/main*.js dist/apps/remix-ide/polyfills*.js dist/apps/remix-ide/favicon.ico dist/apps/remix-ide/vendors~app*.js dist/apps/remix-ide/app*.js" working_directory: ~/remix-project steps: @@ -352,7 +352,7 @@ jobs: environment: - COMMIT_AUTHOR_EMAIL: "yann@ethereum.org" - COMMIT_AUTHOR: "Circle CI" - - FILES_TO_PACKAGE: "dist/apps/remix-ide/index.html dist/apps/remix-ide/raw-loader*.js dist/apps/remix-ide/assets dist/apps/remix-ide/main*.js dist/apps/remix-ide/polyfills*.js dist/apps/remix-ide/favicon.ico dist/apps/remix-ide/vendors~app*.js dist/apps/remix-ide/app*.js" + - FILES_TO_PACKAGE: "dist/apps/remix-ide/index.html dist/apps/remix-ide/404.html dist/apps/remix-ide/raw-loader*.js dist/apps/remix-ide/assets dist/apps/remix-ide/main*.js dist/apps/remix-ide/polyfills*.js dist/apps/remix-ide/favicon.ico dist/apps/remix-ide/vendors~app*.js dist/apps/remix-ide/app*.js" working_directory: ~/remix-project steps: @@ -380,7 +380,7 @@ jobs: environment: - COMMIT_AUTHOR_EMAIL: "yann@ethereum.org" - COMMIT_AUTHOR: "Circle CI" - - FILES_TO_PACKAGE: "dist/apps/remix-ide/index.html dist/apps/remix-ide/raw-loader*.js dist/apps/remix-ide/assets dist/apps/remix-ide/main*.js dist/apps/remix-ide/polyfills*.js dist/apps/remix-ide/favicon.ico dist/apps/remix-ide/vendors~app*.js dist/apps/remix-ide/app*.js" + - FILES_TO_PACKAGE: "dist/apps/remix-ide/index.html dist/apps/remix-ide/404.html dist/apps/remix-ide/raw-loader*.js dist/apps/remix-ide/assets dist/apps/remix-ide/main*.js dist/apps/remix-ide/polyfills*.js dist/apps/remix-ide/favicon.ico dist/apps/remix-ide/vendors~app*.js dist/apps/remix-ide/app*.js" working_directory: ~/remix-project steps: diff --git a/README.md b/README.md index 06fd3fbe16..84cc44a09b 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ Note: It contains the latest supported version of Solidity available at the time "npm": "^6.14.15" } ``` -* Install [Nx CLI](https://nx.dev/react/cli/overview) globally to enable running **nx executable commands**. +* Install [Nx CLI](https://nx.dev/using-nx/nx-cli) globally to enable running **nx executable commands**. ```bash yarn global add @nrwl/cli ``` @@ -127,7 +127,7 @@ curl https://raw.githubusercontent.com/ethereum/remix-project/master/docker-comp ### Troubleshooting -If you have trouble building the project, make sure that you have the correct version of `node`, `npm` and `nvm`. Also ensure [Nx CLI](https://nx.dev/react/cli/overview) is installed globally. +If you have trouble building the project, make sure that you have the correct version of `node`, `npm` and `nvm`. Also ensure [Nx CLI](https://nx.dev/using-nx/nx-cli) is installed globally. Run: diff --git a/apps/remix-ide-e2e/src/commands/createContract.ts b/apps/remix-ide-e2e/src/commands/createContract.ts index 44ff4780c7..015a4f2012 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,19 +13,11 @@ class CreateContract extends EventEmitter { } } -function createContract (browser: NightwatchBrowser, inputParams: string[], callback: VoidFunction) { - if (inputParams.length === 1) { - browser.setValue('.udapp_contractActionsContainerSingle > input', inputParams[0], function () { +function createContract (browser: NightwatchBrowser, inputParams: string, callback: VoidFunction) { + if (inputParams) { + browser.setValue('.udapp_contractActionsContainerSingle > input', inputParams, 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 19aa196b60..c3541d2163 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/libraryDeployment.test.ts b/apps/remix-ide-e2e/src/tests/libraryDeployment.test.ts index 276e9136d5..4b3c4528c4 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/recorder.test.ts b/apps/remix-ide-e2e/src/tests/recorder.test.ts index 7e8748b737..3cdea544c3 100644 --- a/apps/remix-ide-e2e/src/tests/recorder.test.ts +++ b/apps/remix-ide-e2e/src/tests/recorder.test.ts @@ -3,6 +3,7 @@ import { NightwatchBrowser } from 'nightwatch' import init from '../helpers/init' module.exports = { + '@disabled': true, before: function (browser: NightwatchBrowser, done: VoidFunction) { init(browser, done) }, @@ -11,7 +12,7 @@ module.exports = { return sources }, - 'Run Scenario': function (browser: NightwatchBrowser) { + 'Run Scenario #group1': function (browser: NightwatchBrowser) { let addressRef browser.addFile('scenario.json', { content: records }) .pause(5000) @@ -36,10 +37,10 @@ module.exports = { .click('*[data-id="deployAndRunClearInstances"]') }, - 'Save scenario': function (browser: NightwatchBrowser) { + 'Save scenario #group1': 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('.savetransaction') @@ -64,7 +65,7 @@ module.exports = { }) }, - 'Record more than one contract': function (browser: NightwatchBrowser) { + 'Record more than one contract #group1': function (browser: NightwatchBrowser) { // deploy 2 contracts (2 different ABIs), save the record, reexecute and test one of the function. browser .click('*[data-id="deployAndRunClearInstances"]') @@ -72,11 +73,11 @@ module.exports = { .clickLaunchIcon('udapp') .selectContract('t1est') .pause(1000) - .createContract([]) + .createContract('') .clickInstance(0) .selectContract('t2est') .pause(1000) - .createContract([]) + .createContract('') .click('.savetransaction') .waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]') .execute(function () { @@ -84,6 +85,7 @@ module.exports = { modalOk.click() }) + .pause(1000) .click('*[data-id="deployAndRunClearInstances"]') // clear udapp .click('*[data-id="terminalClearConsole"]') // clear terminal .click('[data-id="runtransaction"]') @@ -98,7 +100,7 @@ module.exports = { }, - 'Run with live "mode"': function (browser: NightwatchBrowser) { + 'Run with live "mode" #group1': 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 }) @@ -116,7 +118,7 @@ module.exports = { }) .clickFunction('retrieve - call') .perform((done) => { - browser.verifyCallReturnValue(addressRef, ['', '0:uint256: 350']) + browser.verifyCallReturnValue(addressRef, ['0:uint256: 350']) .perform(() => done()) }) // change the init state and recompile the same contract. @@ -136,7 +138,7 @@ module.exports = { }) .clickFunction('retrieve - call') .perform((done) => { - browser.verifyCallReturnValue(addressRef, ['', '0:uint256: 300']) + browser.verifyCallReturnValue(addressRef, ['0:uint256: 300']) .perform(() => done()) }) .end() diff --git a/apps/remix-ide-e2e/src/tests/signingMessage.test.ts b/apps/remix-ide-e2e/src/tests/signingMessage.test.ts index 177dac88a0..913851fa38 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 48137e3b8b..bcdc3c4977 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 b958b7d42d..7cc5268933 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 842da3b3c7..635218881f 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 9ba94f470b..c45c1d4d3d 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/ci/deploy_from_travis_remix-alpha.sh b/apps/remix-ide/ci/deploy_from_travis_remix-alpha.sh index 19860c9c1c..9ea9fa20ee 100755 --- a/apps/remix-ide/ci/deploy_from_travis_remix-alpha.sh +++ b/apps/remix-ide/ci/deploy_from_travis_remix-alpha.sh @@ -14,7 +14,7 @@ echo "To use an offline copy, download \`remix-$SHA.zip\`." >> README.md cp -r $FILES_TO_PACKAGE "./" rm -rf dist ls -FILES_TO_DEPLOY="assets index.html main*.js polyfills*.js favicon.ico vendors~app*.js app*.js raw-loader*.js" +FILES_TO_DEPLOY="assets index.html 404.html main*.js polyfills*.js favicon.ico vendors~app*.js app*.js raw-loader*.js" # ZIP the whole directory zip -r remix-$SHA.zip $FILES_TO_DEPLOY # -f is needed because "build" is part of .gitignore diff --git a/apps/remix-ide/ci/deploy_from_travis_remix-beta.sh b/apps/remix-ide/ci/deploy_from_travis_remix-beta.sh index 441a127410..9eb72f1d4d 100755 --- a/apps/remix-ide/ci/deploy_from_travis_remix-beta.sh +++ b/apps/remix-ide/ci/deploy_from_travis_remix-beta.sh @@ -14,7 +14,7 @@ echo "To use an offline copy, download \`remix-$SHA.zip\`." >> README.md cp -r $FILES_TO_PACKAGE "./" rm -rf dist ls -FILES_TO_DEPLOY="assets index.html main*.js polyfills*.js favicon.ico vendors~app*.js app*.js raw-loader*.js" +FILES_TO_DEPLOY="assets index.html 404.html main*.js polyfills*.js favicon.ico vendors~app*.js app*.js raw-loader*.js" # ZIP the whole directory zip -r remix-$SHA.zip $FILES_TO_DEPLOY # -f is needed because "build" is part of .gitignore diff --git a/apps/remix-ide/ci/deploy_from_travis_remix-live.sh b/apps/remix-ide/ci/deploy_from_travis_remix-live.sh index 3460d25fa2..9a82fbb26a 100755 --- a/apps/remix-ide/ci/deploy_from_travis_remix-live.sh +++ b/apps/remix-ide/ci/deploy_from_travis_remix-live.sh @@ -14,7 +14,7 @@ echo "To use an offline copy, download \`remix-$SHA.zip\`." >> README.md cp -r $FILES_TO_PACKAGE "./" rm -rf dist ls -FILES_TO_DEPLOY="assets index.html main*.js polyfills*.js vendors~app*.js app*.js raw-loader*.js" +FILES_TO_DEPLOY="assets index.html 404.html main*.js polyfills*.js vendors~app*.js app*.js raw-loader*.js" # ZIP the whole directory zip -r remix-$SHA.zip $FILES_TO_DEPLOY # -f is needed because "build" is part of .gitignore diff --git a/apps/remix-ide/src/404.html b/apps/remix-ide/src/404.html new file mode 100644 index 0000000000..28268a1ab1 --- /dev/null +++ b/apps/remix-ide/src/404.html @@ -0,0 +1,15 @@ + + + + + + + + \ No newline at end of file diff --git a/apps/remix-ide/src/app/components/hidden-panel.tsx b/apps/remix-ide/src/app/components/hidden-panel.tsx index 31c7a0cb0b..6aa78a4052 100644 --- a/apps/remix-ide/src/app/components/hidden-panel.tsx +++ b/apps/remix-ide/src/app/components/hidden-panel.tsx @@ -8,7 +8,7 @@ import { PluginViewWrapper } from '@remix-ui/helper' const profile = { name: 'hiddenPanel', displayName: 'Hidden Panel', - description: '', + description: 'Remix IDE hidden panel', version: packageJson.version, methods: ['addView', 'removeView'] } diff --git a/apps/remix-ide/src/app/components/main-panel.tsx b/apps/remix-ide/src/app/components/main-panel.tsx index 615e03690d..d6dee613fd 100644 --- a/apps/remix-ide/src/app/components/main-panel.tsx +++ b/apps/remix-ide/src/app/components/main-panel.tsx @@ -7,7 +7,7 @@ import { PluginViewWrapper } from '@remix-ui/helper' const profile = { name: 'mainPanel', displayName: 'Main Panel', - description: '', + description: 'Remix IDE main panel', version: packageJson.version, methods: ['addView', 'removeView', 'showContent'] } diff --git a/apps/remix-ide/src/app/components/side-panel.tsx b/apps/remix-ide/src/app/components/side-panel.tsx index bf82defe55..54e56dd210 100644 --- a/apps/remix-ide/src/app/components/side-panel.tsx +++ b/apps/remix-ide/src/app/components/side-panel.tsx @@ -10,7 +10,7 @@ import { PluginViewWrapper } from '@remix-ui/helper' const sidePanel = { name: 'sidePanel', displayName: 'Side Panel', - description: '', + description: 'Remix IDE side panel', version: packageJson.version, methods: ['addView', 'removeView'] } diff --git a/apps/remix-ide/src/app/components/vertical-icons.tsx b/apps/remix-ide/src/app/components/vertical-icons.tsx index d8fe5706f8..24d5b93b2b 100644 --- a/apps/remix-ide/src/app/components/vertical-icons.tsx +++ b/apps/remix-ide/src/app/components/vertical-icons.tsx @@ -10,7 +10,7 @@ import { PluginViewWrapper } from '@remix-ui/helper' const profile = { name: 'menuicons', displayName: 'Vertical Icons', - description: '', + description: 'Remix IDE vertical icons', version: packageJson.version, methods: ['select', 'unlinkContent', 'linkContent'], events: ['toggleContent', 'showContent'] diff --git a/apps/remix-ide/src/app/files/dgitProvider.js b/apps/remix-ide/src/app/files/dgitProvider.js index 8b5ce925c5..aa5b98dfa1 100644 --- a/apps/remix-ide/src/app/files/dgitProvider.js +++ b/apps/remix-ide/src/app/files/dgitProvider.js @@ -18,7 +18,7 @@ const axios = require('axios') const profile = { name: 'dGitProvider', displayName: 'Decentralized git', - description: '', + description: 'Decentralized git provider', icon: 'assets/img/fileManager.webp', version: '0.0.1', methods: ['init', 'localStorageUsed', 'addremote', 'delremote', 'remotes', 'fetch', 'clone', 'export', 'import', 'status', 'log', 'commit', 'add', 'remove', 'rm', 'lsfiles', 'readblob', 'resolveref', 'branches', 'branch', 'checkout', 'currentbranch', 'push', 'pin', 'pull', 'pinList', 'unPin', 'setIpfsConfig', 'zip', 'setItem', 'getItem'], diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js index 7b46d54504..07a9d1c3ef 100644 --- a/apps/remix-ide/src/app/panels/file-panel.js +++ b/apps/remix-ide/src/app/panels/file-panel.js @@ -34,11 +34,12 @@ const profile = { methods: ['createNewFile', 'uploadFile', 'getCurrentWorkspace', 'getWorkspaces', 'createWorkspace', 'setWorkspace', 'registerContextMenuItem', 'renameWorkspace', 'deleteWorkspace'], events: ['setWorkspace', 'workspaceRenamed', 'workspaceDeleted', 'workspaceCreated'], icon: 'assets/img/fileManager.webp', - description: ' - ', + description: 'Remix IDE file explorer', kind: 'fileexplorer', location: 'sidePanel', documentation: 'https://remix-ide.readthedocs.io/en/latest/file_explorer.html', - version: packageJson.version + version: packageJson.version, + maintainedBy: 'Remix' } module.exports = class Filepanel extends ViewPlugin { constructor (appManager) { diff --git a/apps/remix-ide/src/app/panels/terminal.js b/apps/remix-ide/src/app/panels/terminal.js index 6eaa65f6e9..bd89f2d7ce 100644 --- a/apps/remix-ide/src/app/panels/terminal.js +++ b/apps/remix-ide/src/app/panels/terminal.js @@ -20,7 +20,7 @@ const profile = { name: 'terminal', methods: ['log', 'logHtml'], events: [], - description: ' - ', + description: 'Remix IDE terminal', version: packageJson.version } diff --git a/apps/remix-ide/src/app/plugins/permission-handler-plugin.tsx b/apps/remix-ide/src/app/plugins/permission-handler-plugin.tsx index 29f7535066..3bec429d25 100644 --- a/apps/remix-ide/src/app/plugins/permission-handler-plugin.tsx +++ b/apps/remix-ide/src/app/plugins/permission-handler-plugin.tsx @@ -7,7 +7,7 @@ import { Profile } from '@remixproject/plugin-utils' const profile = { name: 'permissionhandler', displayName: 'permissionhandler', - description: 'permissionhandler', + description: 'Plugin to handle permissions', methods: ['askPermission'] } diff --git a/apps/remix-ide/src/app/tabs/analysis-tab.js b/apps/remix-ide/src/app/tabs/analysis-tab.js index f17b0da52b..21c123c9bf 100644 --- a/apps/remix-ide/src/app/tabs/analysis-tab.js +++ b/apps/remix-ide/src/app/tabs/analysis-tab.js @@ -18,7 +18,8 @@ const profile = { kind: 'analysis', location: 'sidePanel', documentation: 'https://remix-ide.readthedocs.io/en/latest/static_analysis.html', - version: packageJson.version + version: packageJson.version, + maintainedBy: 'Remix' } class AnalysisTab extends ViewPlugin { diff --git a/apps/remix-ide/src/app/tabs/compile-and-run.ts b/apps/remix-ide/src/app/tabs/compile-and-run.ts index d5b298e966..e90d9f5844 100644 --- a/apps/remix-ide/src/app/tabs/compile-and-run.ts +++ b/apps/remix-ide/src/app/tabs/compile-and-run.ts @@ -10,7 +10,7 @@ const _paq = window._paq = window._paq || [] export const profile = { name: 'compileAndRun', displayName: 'Compile and Run', - description: 'after each compilation, run the script defined in Natspec.', + description: 'After each compilation, run the script defined in Natspec.', methods: ['runScriptAfterCompilation'], version: packageJson.version, kind: 'none' diff --git a/apps/remix-ide/src/app/tabs/compile-tab.js b/apps/remix-ide/src/app/tabs/compile-tab.js index c263a67bf6..5ba04d95a9 100644 --- a/apps/remix-ide/src/app/tabs/compile-tab.js +++ b/apps/remix-ide/src/app/tabs/compile-tab.js @@ -20,6 +20,7 @@ const profile = { location: 'sidePanel', documentation: 'https://remix-ide.readthedocs.io/en/latest/solidity_editor.html', version: packageJson.version, + maintainedBy: 'Remix', methods: ['getCompilationResult', 'compile', 'compileWithParameters', 'setCompilerConfig', 'compileFile', 'getCompilerState'] } diff --git a/apps/remix-ide/src/app/tabs/debugger-tab.js b/apps/remix-ide/src/app/tabs/debugger-tab.js index b9bc4773ec..dd876630ec 100644 --- a/apps/remix-ide/src/app/tabs/debugger-tab.js +++ b/apps/remix-ide/src/app/tabs/debugger-tab.js @@ -18,7 +18,8 @@ const profile = { kind: 'debugging', location: 'sidePanel', documentation: 'https://remix-ide.readthedocs.io/en/latest/debugger.html', - version: packageJson.version + version: packageJson.version, + maintainedBy: 'Remix' } export class DebuggerTab extends DebuggerApiMixin(ViewPlugin) { diff --git a/apps/remix-ide/src/app/tabs/external-http-provider.tsx b/apps/remix-ide/src/app/tabs/external-http-provider.tsx index 71c7c249c0..9483989843 100644 --- a/apps/remix-ide/src/app/tabs/external-http-provider.tsx +++ b/apps/remix-ide/src/app/tabs/external-http-provider.tsx @@ -6,7 +6,7 @@ const profile = { name: 'basic-http-provider', displayName: 'External Http Provider', kind: 'provider', - description: '', + description: 'External Http Provider', methods: ['sendAsync'], version: packageJson.version } diff --git a/apps/remix-ide/src/app/tabs/foundry-provider.tsx b/apps/remix-ide/src/app/tabs/foundry-provider.tsx index 47e899865a..3c1fbb6256 100644 --- a/apps/remix-ide/src/app/tabs/foundry-provider.tsx +++ b/apps/remix-ide/src/app/tabs/foundry-provider.tsx @@ -10,7 +10,7 @@ const profile = { name: 'foundry-provider', displayName: 'Foundry Provider', kind: 'provider', - description: 'Anvil', + description: 'Foundry Anvil provider', methods: ['sendAsync'], version: packageJson.version } diff --git a/apps/remix-ide/src/app/tabs/ganache-provider.tsx b/apps/remix-ide/src/app/tabs/ganache-provider.tsx index 002e31a3a2..97adac1574 100644 --- a/apps/remix-ide/src/app/tabs/ganache-provider.tsx +++ b/apps/remix-ide/src/app/tabs/ganache-provider.tsx @@ -10,7 +10,7 @@ const profile = { name: 'ganache-provider', displayName: 'Ganache Provider', kind: 'provider', - description: 'Ganache', + description: 'Truffle Ganache provider', methods: ['sendAsync'], version: packageJson.version } 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 caa758b180..244d61690f 100644 --- a/apps/remix-ide/src/app/tabs/runTab/model/recorder.js +++ b/apps/remix-ide/src/app/tabs/runTab/model/recorder.js @@ -13,7 +13,7 @@ const _paq = window._paq = window._paq || [] //eslint-disable-line const profile = { name: 'recorder', displayName: 'Recorder', - description: '', + description: 'Records transactions to save and run', version: packageJson.version, methods: [ ] } @@ -200,13 +200,16 @@ class Recorder extends Plugin { */ run (records, accounts, options, abis, linkReferences, confirmationCb, continueCb, promptCb, alertCb, logCallBack, liveMode, newContractFn) { this.setListen(false) - const liveMsg = liveMode ? ' in live mode' : '' + const liveMsg = liveMode ? ' with updated contracts' : '' 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. + // resolve the bytecode and ABI 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 + const updatedABIKeccak = ethutil.bufferToHex(ethutil.keccakFromString(JSON.stringify(data.artefact.abi))) + abis[updatedABIKeccak] = data.artefact.abi + tx.record.abi = updatedABIKeccak } var record = this.resolveAddress(tx.record, accounts, options) var abi = abis[tx.record.abi] @@ -312,11 +315,11 @@ class Recorder extends Plugin { abis = json.abis || {} linkReferences = json.linkReferences || {} } catch (e) { - return cb('Invalid Scenario File. Please try again') + return cb('Invalid scenario file. Please try again') } if (!txArray.length) { - return + return cb('No transactions found in scenario file') } this.run(txArray, accounts, options, abis, linkReferences, confirmationCb, continueCb, promptCb, alertCb, logCallBack, liveMode, (abi, address, contractName) => { diff --git a/apps/remix-ide/src/app/tabs/search.tsx b/apps/remix-ide/src/app/tabs/search.tsx index 5ae3ebea85..d561b4e38c 100644 --- a/apps/remix-ide/src/app/tabs/search.tsx +++ b/apps/remix-ide/src/app/tabs/search.tsx @@ -9,11 +9,12 @@ const profile = { methods: [''], events: [], icon: 'assets/img/search_icon.webp', - description: '', + description: 'Find and replace in file explorer', kind: '', location: 'sidePanel', documentation: '', - version: packageJson.version + version: packageJson.version, + maintainedBy: 'Remix' } export class SearchPlugin extends ViewPlugin { diff --git a/apps/remix-ide/src/app/tabs/test-tab.js b/apps/remix-ide/src/app/tabs/test-tab.js index 960e2a93ce..b5c9518d23 100644 --- a/apps/remix-ide/src/app/tabs/test-tab.js +++ b/apps/remix-ide/src/app/tabs/test-tab.js @@ -16,9 +16,10 @@ const profile = { methods: ['testFromPath', 'testFromSource', 'setTestFolderPath', 'getTestlibs', 'createTestLibs'], events: [], icon: 'assets/img/unitTesting.webp', - description: 'Fast tool to generate unit tests for your contracts', + description: 'Write and run unit tests for your contracts in Solidity', location: 'sidePanel', - documentation: 'https://remix-ide.readthedocs.io/en/latest/unittesting.html' + documentation: 'https://remix-ide.readthedocs.io/en/latest/unittesting.html', + maintainedBy: 'Remix' } module.exports = class TestTab extends ViewPlugin { diff --git a/apps/remix-ide/src/app/udapp/run-tab.js b/apps/remix-ide/src/app/udapp/run-tab.js index 8475a92848..a5d403fb4a 100644 --- a/apps/remix-ide/src/app/udapp/run-tab.js +++ b/apps/remix-ide/src/app/udapp/run-tab.js @@ -13,11 +13,12 @@ const profile = { displayName: 'Deploy & run transactions', intlId: 'udapp.displayName', icon: 'assets/img/deployAndRun.webp', - description: 'execute and save transactions', + description: 'Execute, save and replay transactions', kind: 'udapp', location: 'sidePanel', documentation: 'https://remix-ide.readthedocs.io/en/latest/run.html', version: packageJson.version, + maintainedBy: 'Remix', permission: true, events: ['newTransaction'], methods: ['createVMAccount', 'sendTransaction', 'getAccounts', 'pendingTransactionsCount', 'getSettings', 'setEnvironmentMode', 'clearAllInstances', 'addInstance', 'resolveContractAndAddInstance'] diff --git a/apps/remix-ide/src/app/ui/landing-page/landing-page.js b/apps/remix-ide/src/app/ui/landing-page/landing-page.js index 2f8819fc5f..978c4fdb1c 100644 --- a/apps/remix-ide/src/app/ui/landing-page/landing-page.js +++ b/apps/remix-ide/src/app/ui/landing-page/landing-page.js @@ -9,7 +9,7 @@ const profile = { displayName: 'Home', methods: [], events: [], - description: ' - ', + description: 'Remix home tab ', icon: 'assets/img/remixLogo.webp', location: 'mainPanel', version: packageJson.version diff --git a/apps/remix-ide/src/blockchain/blockchain.js b/apps/remix-ide/src/blockchain/blockchain.js index 3d6e885cec..47ece52eb2 100644 --- a/apps/remix-ide/src/blockchain/blockchain.js +++ b/apps/remix-ide/src/blockchain/blockchain.js @@ -11,8 +11,7 @@ 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' +import { logBuilder, cancelUpgradeMsg, cancelProxyMsg } from "@remix-ui/helper" const { txFormat, txExecution, typeConversion, txListener: Txlistener, TxRunner, TxRunnerWeb3, txHelper } = execution const { txResultHelper: resultToRemixTx } = helpers const packageJson = require('../../../../package.json') @@ -142,17 +141,19 @@ export class Blockchain extends Plugin { async deployProxy (proxyData, implementationContractObject) { const proxyModal = { id: 'confirmProxyDeployment', - title: 'ERC1967', + title: 'Confirm Deploy Proxy (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`, + 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) + _paq.push(['trackEvent', 'blockchain', 'Deploy With Proxy', 'modal ok confirmation']) }, cancelFn: () => { this.call('notification', 'toast', cancelProxyMsg()) + _paq.push(['trackEvent', 'blockchain', 'Deploy With Proxy', 'cancel proxy deployment']) }, hideFn: () => null } @@ -161,7 +162,9 @@ export class Blockchain extends Plugin { async runProxyTx (proxyData, implementationContractObject) { const args = { useCall: false, data: proxyData } + let networkInfo const confirmationCb = (network, tx, gasEstimation, continueTxExecution, cancelCb) => { + networkInfo = network // continue using original authorization given by user continueTxExecution(null) } @@ -171,14 +174,60 @@ export class Blockchain extends Plugin { if (error) { const log = logBuilder(error) + _paq.push(['trackEvent', 'blockchain', 'Deploy With Proxy', 'Proxy deployment failed: ' + error]) return this.call('terminal', 'logHtml', log) } + if (networkInfo.name === 'VM') this.config.set('vm/proxy', address) + else this.config.set(`${networkInfo.name}/${networkInfo.currentFork}/${networkInfo.id}/proxy`, address) + _paq.push(['trackEvent', 'blockchain', 'Deploy With Proxy', 'Proxy deployment successful']) return this.call('udapp', 'resolveContractAndAddInstance', implementationContractObject, address) } this.runTx(args, confirmationCb, continueCb, promptCb, finalCb) } + async upgradeProxy(proxyAddress, newImplAddress, data, newImplementationContractObject) { + const upgradeModal = { + id: 'confirmProxyDeployment', + title: 'Confirm Update Proxy (ERC1967)', + message: `Confirm you want to update your proxy contract with the new implementation contract's address: ${newImplAddress}.`, + modalType: 'modal', + okLabel: 'OK', + cancelLabel: 'Cancel', + okFn: () => { + this.runUpgradeTx(proxyAddress, data, newImplementationContractObject) + _paq.push(['trackEvent', 'blockchain', 'Upgrade With Proxy', 'proxy upgrade confirmation click']) + }, + cancelFn: () => { + this.call('notification', 'toast', cancelUpgradeMsg()) + _paq.push(['trackEvent', 'blockchain', 'Upgrade With Proxy', 'proxy upgrade cancel click']) + }, + hideFn: () => null + } + this.call('notification', 'modal', upgradeModal) + } + + async runUpgradeTx (proxyAddress, data, newImplementationContractObject) { + const args = { useCall: false, data, to: proxyAddress } + 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) + + _paq.push(['trackEvent', 'blockchain', 'Upgrade With Proxy', 'Upgrade failed']) + return this.call('terminal', 'logHtml', log) + } + _paq.push(['trackEvent', 'blockchain', 'Upgrade With Proxy', 'Upgrade Successful']) + return this.call('udapp', 'resolveContractAndAddInstance', newImplementationContractObject, proxyAddress) + } + this.runTx(args, confirmationCb, continueCb, promptCb, finalCb) + } + async getEncodedFunctionHex (args, funABI) { return new Promise((resolve, reject) => { txFormat.encodeFunctionCall(args, funABI, (error, data) => { diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index b90f37a022..269f868dfb 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -8,7 +8,8 @@ const requiredModules = [ // services + layout views + system views 'manager', 'config', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'locale', 'fileManager', 'contentImport', 'blockchain', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons', 'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity', 'solidity-logic', 'gistHandler', 'layout', - 'notification', 'permissionhandler', 'walkthrough', 'storage', 'restorebackupzip', 'link-libraries', 'deploy-libraries', 'openzeppelin-proxy', 'hardhat-provider', 'compileAndRun', 'search'] + 'notification', 'permissionhandler', 'walkthrough', 'storage', 'restorebackupzip', 'link-libraries', 'deploy-libraries', 'openzeppelin-proxy', + 'hardhat-provider', 'compileAndRun', 'search', 'recorder'] const dependentModules = ['git', 'hardhat', 'truffle', 'slither'] // module which shouldn't be manually activated (e.g git is activated by remixd) diff --git a/apps/remix-ide/src/walkthroughService.js b/apps/remix-ide/src/walkthroughService.js index 8f088c443c..d0d466555f 100644 --- a/apps/remix-ide/src/walkthroughService.js +++ b/apps/remix-ide/src/walkthroughService.js @@ -5,7 +5,7 @@ const introJs = require('intro.js') const profile = { name: 'walkthrough', displayName: 'Walkthrough', - description: '', + description: 'Remix walkthrough for beginner', version: packageJson.version, methods: ['start'] } diff --git a/libs/remix-core-plugin/src/lib/constants/uups.ts b/libs/remix-core-plugin/src/lib/constants/uups.ts index 2fb521a999..977d3769a8 100644 --- a/libs/remix-core-plugin/src/lib/constants/uups.ts +++ b/libs/remix-core-plugin/src/lib/constants/uups.ts @@ -88,4 +88,18 @@ export const UUPSfunAbi = { type: "constructor", outputs: [], stateMutability: "payable" +} + +export const UUPSupgradeAbi = { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" } \ 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 2de757f4d2..bf3302f625 100644 --- a/libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts +++ b/libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts @@ -1,12 +1,12 @@ -import { Plugin } from '@remixproject/engine'; -import { ContractABI, ContractAST, DeployOption } from '../types/contract'; -import { UUPS, UUPSABI, UUPSBytecode, UUPSfunAbi } from './constants/uups'; +import { Plugin } from '@remixproject/engine' +import { ContractABI, ContractAST, ContractSources, DeployOptions } from '../types/contract' +import { UUPS, UUPSABI, UUPSBytecode, UUPSfunAbi, UUPSupgradeAbi } from './constants/uups' const proxyProfile = { name: 'openzeppelin-proxy', displayName: 'openzeppelin-proxy', description: 'openzeppelin-proxy', - methods: ['isConcerned', 'execute', 'getDeployOptions'] + methods: ['isConcerned', 'executeUUPSProxy', 'executeUUPSContractUpgrade', 'getProxyOptions', 'getUpgradeOptions'] }; export class OpenZeppelinProxy extends Plugin { blockchain: any @@ -28,26 +28,37 @@ export class OpenZeppelinProxy extends Plugin { return false } - async getDeployOptions (contracts: ContractABI): Promise<{ [name: string]: DeployOption }> { + async getProxyOptions (data: ContractSources, file: string): Promise<{ [name: string]: DeployOptions }> { + const contracts = data.contracts[file] + const ast = data.sources[file].ast 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 (ast) { + const UUPSSymbol = ast.exportedSymbols['UUPSUpgradeable'] ? ast.exportedSymbols['UUPSUpgradeable'][0] : null - if (initializeInput) { - inputs[name] = { - inputs: initializeInput, - initializeInputs: this.blockchain.getInputs(initializeInput) - } + ast.absolutePath === file && ast.nodes.map((node) => { + if (node.name === name && node.linearizedBaseContracts.includes(UUPSSymbol)) { + const abi = contracts[name].abi + const initializeInput = abi.find(node => node.name === 'initialize') + + inputs[name] = { + options: [{ title: 'Deploy with Proxy', active: false }, { title: 'Upgrade with Proxy', active: false }], + initializeOptions: { + inputs: initializeInput, + initializeInputs: initializeInput ? this.blockchain.getInputs(initializeInput) : null + } + } + } + }) } }) } return inputs } - async execute(implAddress: string, args: string | string [] = '', initializeABI, implementationContractObject): Promise { + async executeUUPSProxy(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 @@ -56,6 +67,13 @@ export class OpenZeppelinProxy extends Plugin { if (this.kind === 'UUPS') this.deployUUPSProxy(implAddress, _data, implementationContractObject) } + async executeUUPSContractUpgrade (proxyAddress: string, newImplAddress: string, newImplementationContractObject): Promise { + if (!newImplAddress) throw new Error('Cannot upgrade: Missing implementation address') + if (!proxyAddress) throw new Error('Cannot upgrade: Missing proxy address') + + if (this.kind === 'UUPS') this.upgradeUUPSProxy(proxyAddress, newImplAddress, newImplementationContractObject) + } + async deployUUPSProxy (implAddress: string, _data: string, implementationContractObject): Promise { const args = [implAddress, _data] const constructorData = await this.blockchain.getEncodedParams(args, UUPSfunAbi) @@ -74,4 +92,20 @@ export class OpenZeppelinProxy extends Plugin { implementationContractObject.name = proxyName this.blockchain.deployProxy(data, implementationContractObject) } + + async upgradeUUPSProxy (proxyAddress: string, newImplAddress: string, newImplementationContractObject): Promise { + const fnData = await this.blockchain.getEncodedFunctionHex([newImplAddress], UUPSupgradeAbi) + const proxyName = 'ERC1967Proxy' + const data = { + contractABI: UUPSABI, + contractName: proxyName, + funAbi: UUPSupgradeAbi, + funArgs: [newImplAddress], + linkReferences: {}, + dataHex: fnData.replace('0x', '') + } + // re-use implementation contract's ABI for UI display in udapp and change name to proxy name. + newImplementationContractObject.name = proxyName + this.blockchain.upgradeProxy(proxyAddress, newImplAddress, data, newImplementationContractObject) + } } diff --git a/libs/remix-core-plugin/src/types/contract.ts b/libs/remix-core-plugin/src/types/contract.ts index 92c32653b5..a327539a60 100644 --- a/libs/remix-core-plugin/src/types/contract.ts +++ b/libs/remix-core-plugin/src/types/contract.ts @@ -54,101 +54,132 @@ export interface ContractAST { }[] } -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 ContractABI = { + inputs: []; + stateMutability: string; + type: string; + anonymous?: undefined; + name?: string; + 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; } +export type DeployMode = 'Deploy with Proxy' | 'Upgrade with Proxy' + export type DeployOption = { - initializeInputs: string, + initializeInputs: string, + inputs: { inputs: { - inputs: { - internalType?: string, - name: string, - type: string - }[], - name: "initialize", - outputs?: any[], - stateMutability: string, - type: string, - payable?: boolean, - constant?: any + internalType?: string, + name: string, + type: string + }[], + name: "initialize", + outputs?: any[], + stateMutability: string, + type: string, + payable?: boolean, + constant?: any + } +} +export interface DeployOptions { + initializeOptions: DeployOption, + options: { title: DeployMode, active: boolean }[] +} + +export interface ContractSources { + contracts: { + [path: string]: { + [contractName: string]: { + abi: ContractABI[], + 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 + } + } + } + }, + error: { + component: string, + errorCode: string, + formattedMessage: string, + message: string, + severity: string, + sourceLocation: { + end: number, + file: string, + start: number + }, + type: string + }[], + sources: { + [path: string]: { + ast: ContractAST, + id: number + } } } diff --git a/libs/remix-ui/helper/src/lib/helper-components.tsx b/libs/remix-ui/helper/src/lib/helper-components.tsx index 206fbec926..fc1cf49e88 100644 --- a/libs/remix-ui/helper/src/lib/helper-components.tsx +++ b/libs/remix-ui/helper/src/lib/helper-components.tsx @@ -89,3 +89,29 @@ export const cancelProxyMsg = () => ( Proxy deployment cancelled. ) + +export const cancelUpgradeMsg = () => ( +
+ Upgrade with proxy cancelled. +
+) + +export const deployWithProxyMsg = () => ( +
+ Deploy with Proxy will initiate two (2) transactions: +
    +
  1. Deploying the implementation contract
  2. +
  3. Deploying an ERC1967 proxy contract
  4. +
+
+) + +export const upgradeWithProxyMsg = () => ( +
+ Upgrade with Proxy will initiate two (2) transactions: +
    +
  1. Deploying the new implementation contract
  2. +
  3. Updating the proxy contract with the address of the new implementation contract
  4. +
+
+) diff --git a/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx b/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx index 75851edbe6..a9514b8b97 100644 --- a/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx +++ b/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx @@ -5,10 +5,11 @@ import { PluginRecord } from '../types' import './panel.css' export interface RemixPanelProps { - plugins: Record; - } + plugins: Record; +} const RemixUIPanelHeader = (props: RemixPanelProps) => { const [plugin, setPlugin] = useState() + const [toggleExpander, setToggleExpander] = useState(false) useEffect(() => { if (props.plugins) { @@ -19,13 +20,51 @@ const RemixUIPanelHeader = (props: RemixPanelProps) => { } }, [props]) + const toggleClass = () => { + setToggleExpander(!toggleExpander) + } + return ( -
+
+
{/* @ts-ignore */}
- {plugin?.profile.documentation ? () : ''} +
+
+ {plugin?.profile?.maintainedBy?.toLowerCase() === "remix" && ()} + {plugin?.profile.documentation && ()} +
+
+ +
+
+
+
+ {plugin?.profile?.author && + + { plugin?.profile.author } + } + {plugin?.profile?.maintainedBy && + + { plugin?.profile.maintainedBy } + } + {plugin?.profile?.documentation && + + + + + } + {plugin?.profile?.description && + + { plugin?.profile.description } + } + {plugin?.profile?.repo && + + Make an issue + } +
) } diff --git a/libs/remix-ui/panel/src/lib/plugins/panel.css b/libs/remix-ui/panel/src/lib/plugins/panel.css index 8356d6ef15..b9988e19af 100644 --- a/libs/remix-ui/panel/src/lib/plugins/panel.css +++ b/libs/remix-ui/panel/src/lib/plugins/panel.css @@ -22,7 +22,6 @@ .swapitHeader { display: flex; align-items: center; - padding: 16px 24px 15px; justify-content: space-between; text-transform: uppercase; } diff --git a/libs/remix-ui/plugin-manager/src/lib/components/ActivePluginCard.tsx b/libs/remix-ui/plugin-manager/src/lib/components/ActivePluginCard.tsx index 593c6a2edd..47e35a55db 100644 --- a/libs/remix-ui/plugin-manager/src/lib/components/ActivePluginCard.tsx +++ b/libs/remix-ui/plugin-manager/src/lib/components/ActivePluginCard.tsx @@ -19,6 +19,9 @@ function ActivePluginCard ({
{ profile.displayName || profile.name } + { profile?.maintainedBy?.toLowerCase() == "remix" && + + } { profile.documentation &&