diff --git a/apps/remix-ide-e2e/src/commands/getModalBody.ts b/apps/remix-ide-e2e/src/commands/getModalBody.ts index 80e2169ff7..602b2c8d60 100644 --- a/apps/remix-ide-e2e/src/commands/getModalBody.ts +++ b/apps/remix-ide-e2e/src/commands/getModalBody.ts @@ -3,7 +3,7 @@ import EventEmitter from 'events' class GetModalBody extends EventEmitter { command (this: NightwatchBrowser, callback: (value: string, cb: VoidFunction) => void) { - this.api.waitForElementPresent('.modal-body') + this.api.waitForElementVisible('[data-id="modalDialogModalBody"]') .getText('#modal-dialog', (result) => { console.log(result) const value = typeof result.value === 'string' ? result.value : null diff --git a/apps/remix-ide-e2e/src/commands/verifyContracts.ts b/apps/remix-ide-e2e/src/commands/verifyContracts.ts index ae4ca93369..e7dbf4a591 100644 --- a/apps/remix-ide-e2e/src/commands/verifyContracts.ts +++ b/apps/remix-ide-e2e/src/commands/verifyContracts.ts @@ -22,12 +22,15 @@ function verifyContracts (browser: NightwatchBrowser, compiledContractNames: str if (opts.version) { browser .click('*[data-id="compilation-details"]') - .waitForElementVisible('*[data-id="treeViewDivcompiler"]') + .waitForElementVisible('*[data-id="remixui_treeviewitem_metadata"]') .pause(2000) - .click('*[data-id="treeViewDivcompiler"]') - .waitForElementVisible('*[data-id="treeViewLicompiler/version"]') - .assert.containsText('*[data-id="treeViewLicompiler/version"]', `version:\n ${opts.version}`) - .modalFooterCancelClick() + .click('*[data-id="remixui_treeviewitem_metadata"]') + .waitForElementVisible('*[data-id="treeViewDivtreeViewItemcompiler"]') + .pause(2000) + .click('*[data-id="treeViewDivtreeViewItemcompiler"]') + .waitForElementVisible('*[data-id="treeViewLiversion"]') + .assert.containsText('*[data-id="treeViewLiversion"]', `${opts.version}`) + .click('[data-id="workspacesModalDialog-modal-footer-ok-react"]') .perform(() => { done() callback() diff --git a/apps/remix-ide-e2e/src/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts index 484645b391..ba6266be54 100644 --- a/apps/remix-ide-e2e/src/helpers/init.ts +++ b/apps/remix-ide-e2e/src/helpers/init.ts @@ -7,6 +7,8 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url .url(url || 'http://127.0.0.1:8080') .pause(5000) .switchBrowserTab(0) + .waitForElementVisible('[id="remixTourSkipbtn"]') + .click('[id="remixTourSkipbtn"]') .fullscreenWindow(() => { if (preloadPlugins) { initModules(browser, () => { diff --git a/apps/remix-ide-e2e/src/tests/ballot.test.ts b/apps/remix-ide-e2e/src/tests/ballot.test.ts index aa6d507120..866ce3149b 100644 --- a/apps/remix-ide-e2e/src/tests/ballot.test.ts +++ b/apps/remix-ide-e2e/src/tests/ballot.test.ts @@ -49,7 +49,7 @@ module.exports = { 'Debug Ballot / delegate': function (browser: NightwatchBrowser) { browser.pause(500) - .click('*[data-id="txLoggerDebugButton0xf88bc0ac0761f78d8c883b32550c68dadcdb095595c30e1a1b7c583e5e958dcb"]') + .debugTransaction(1) .waitForElementVisible('*[data-id="buttonNavigatorJumpPreviousBreakpoint"]') .click('*[data-id="buttonNavigatorJumpPreviousBreakpoint"]') .pause(2000) diff --git a/apps/remix-ide-e2e/src/tests/ballot_0_4_11.spec.ts b/apps/remix-ide-e2e/src/tests/ballot_0_4_11.spec.ts index a3bf500ec0..5c768859f8 100644 --- a/apps/remix-ide-e2e/src/tests/ballot_0_4_11.spec.ts +++ b/apps/remix-ide-e2e/src/tests/ballot_0_4_11.spec.ts @@ -45,7 +45,7 @@ module.exports = { 'Debug Ballot / delegate': function (browser: NightwatchBrowser) { browser.pause(500) - .click('*[data-id="txLoggerDebugButton0xf88bc0ac0761f78d8c883b32550c68dadcdb095595c30e1a1b7c583e5e958dcb"]') + .debugTransaction(1) .pause(2000) .waitForElementVisible('*[data-id="buttonNavigatorJumpPreviousBreakpoint"]') .click('*[data-id="buttonNavigatorJumpPreviousBreakpoint"]') diff --git a/apps/remix-ide-e2e/src/tests/debugger.spec.ts b/apps/remix-ide-e2e/src/tests/debugger.spec.ts index 0baeee65b3..63bda87e9c 100644 --- a/apps/remix-ide-e2e/src/tests/debugger.spec.ts +++ b/apps/remix-ide-e2e/src/tests/debugger.spec.ts @@ -423,7 +423,7 @@ const localVariable_step717_ABIEncoder = { // eslint-disable-line const jsGetTrace = `(async () => { try { - const result = await remix.call('debugger', 'getTrace', '0xa38bff6f06e7c4fc91df1db6aa31a69ab5d5882faa953b1e7a88bfa523268ed7') + const result = await remix.call('debugger', 'getTrace', '0x9341be49e911afe99bf1abc67cbcf36739d2e6470a08a69511c205a0737d7332') console.log('result ', result) } catch (e) { console.log(e.message) @@ -432,7 +432,7 @@ const jsGetTrace = `(async () => { const jsDebug = `(async () => { try { - const result = await remix.call('debugger', 'debug', '0xa38bff6f06e7c4fc91df1db6aa31a69ab5d5882faa953b1e7a88bfa523268ed7') + const result = await remix.call('debugger', 'debug', '0x9341be49e911afe99bf1abc67cbcf36739d2e6470a08a69511c205a0737d7332') console.log('result ', result) } catch (e) { console.log(e.message) diff --git a/apps/remix-ide-e2e/src/tests/editor.spec.ts b/apps/remix-ide-e2e/src/tests/editor.spec.ts index c2fa0c0edd..83d4f23f8f 100644 --- a/apps/remix-ide-e2e/src/tests/editor.spec.ts +++ b/apps/remix-ide-e2e/src/tests/editor.spec.ts @@ -36,7 +36,7 @@ module.exports = { .click('*[class="ace_content"]') .sendKeys('*[class="ace_text-input"]', 'error') .pause(2000) - .waitForElementVisible('.ace_error', 60000) + .waitForElementVisible('.ace_error', 120000) .checkAnnotations('error', 28) .clickLaunchIcon('udapp') .checkAnnotationsNotPresent('error') diff --git a/apps/remix-ide-e2e/src/tests/gist.spec.ts b/apps/remix-ide-e2e/src/tests/gist.spec.ts index 1f1f0fec6c..8ed8e751a8 100644 --- a/apps/remix-ide-e2e/src/tests/gist.spec.ts +++ b/apps/remix-ide-e2e/src/tests/gist.spec.ts @@ -3,7 +3,7 @@ import { NightwatchBrowser } from 'nightwatch' import init from '../helpers/init' const testData = { - validGistId: '1859c97c6e1efc91047d725d5225888e', + validGistId: '02a847917a6a7ecaf4a7e0d4e68715bf', invalidGistId: '6368b389f9302v32902msk2402' } // 99266d6da54cc12f37f11586e8171546c7700d67 @@ -20,7 +20,7 @@ module.exports = { - switch to a file in the new gist */ console.log('token', process.env.gist_token) - const gistid = 'c15ed7c182a7991ea0a4dea1544fa254' + const gistid = '17ac9315bc065a3d95cf8dc1b28d71f8' browser .refresh() .pause(10000) @@ -125,9 +125,9 @@ module.exports = { .waitForElementVisible('*[data-id="modalDialogCustomPromptText"]') .setValue('*[data-id="modalDialogCustomPromptText"]', testData.validGistId) .modalFooterOKClick() - .openFile(`gist-${testData.validGistId}/ApplicationRegistry`) - .waitForElementVisible(`div[title='default_workspace/gist-${testData.validGistId}/ApplicationRegistry']`) - .assert.containsText(`div[title='default_workspace/gist-${testData.validGistId}/ApplicationRegistry'] > span`, 'ApplicationRegistry') + .openFile(`gist-${testData.validGistId}/README.txt`) + .waitForElementVisible(`div[title='default_workspace/gist-${testData.validGistId}/README.txt']`) + .assert.containsText(`div[title='default_workspace/gist-${testData.validGistId}/README.txt'] > span`, 'README.txt') .end() } } diff --git a/apps/remix-ide-e2e/src/tests/publishContract.test.ts b/apps/remix-ide-e2e/src/tests/publishContract.test.ts index f435321c0d..fb931a1c35 100644 --- a/apps/remix-ide-e2e/src/tests/publishContract.test.ts +++ b/apps/remix-ide-e2e/src/tests/publishContract.test.ts @@ -20,24 +20,32 @@ module.exports = { .verifyContracts(['Ballot']) .click('#publishOnIpfs') .pause(8000) - .getModalBody((value, done) => { - if (value.indexOf('Metadata of "ballot" was published successfully.') === -1) browser.assert.fail('ipfs deploy failed', '', '') - if (value.indexOf('ipfs://') === -1) browser.assert.fail('ipfs deploy failed', '', '') - done() + .waitForElementVisible('[data-id="publishToStorageModalDialogModalBody-react"]', 60000) + .getText('[data-id="publishToStorageModalDialogModalBody-react"]', (result) => { + const value = (result.value) + + browser.perform((done) => { + if (value.indexOf('Metadata of "ballot" was published successfully.') === -1) browser.assert.fail('ipfs deploy failed') + done() + }) }) - .modalFooterOKClick() + .click('[data-id="publishToStorage-modal-footer-ok-react"]') }, 'Publish on Swarm': '' + function (browser: NightwatchBrowser) { browser .click('#publishOnSwarm') .pause(8000) - .getModalBody((value, done) => { - if (value.indexOf('Metadata of "ballot" was successfully.') === -1) browser.assert.fail('swarm deploy failed', '', '') - if (value.indexOf('bzz') === -1) browser.assert.fail('swarm deploy failed', '', '') - done() + .getText('[data-id="publishToStorageModalDialogModalBody-react"]', (result) => { + const value = (result.value) + + browser.perform((done) => { + if (value.indexOf('Metadata of "ballot" was published successfully.') === -1) browser.assert.fail('swarm deploy failed') + if (value.indexOf('bzz') === -1) browser.assert.fail('swarm deploy failed') + done() + }) }) - .modalFooterOKClick() + .click('[data-id="publishToStorage-modal-footer-ok-react"]') }, 'Should publish contract metadata to ipfs on deploy': function (browser: NightwatchBrowser) { @@ -48,10 +56,11 @@ module.exports = { .clickLaunchIcon('udapp') .waitForElementPresent('*[data-id="contractDropdownIpfsCheckbox"]') .click('*[data-id="contractDropdownIpfsCheckbox"]') + .waitForElementVisible('*[data-id="Deploy - transact (not payable)"]') .click('*[data-id="Deploy - transact (not payable)"]') .pause(8000) .getModalBody((value, done) => { - if (value.indexOf('Metadata of "storage" was published successfully.') === -1) browser.assert.fail('ipfs deploy failed', '', '') + if (value.indexOf('Metadata of "storage" was published successfully.') === -1) browser.assert.fail('ipfs deploy failed') done() }) .modalFooterOKClick() diff --git a/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts b/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts index 9223ae1728..2c3a43ebc4 100644 --- a/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts +++ b/apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts @@ -84,8 +84,7 @@ module.exports = { .scrollAndClick('*[data-id="testTabRunTestsTabRunAction"]') .pause(2000) .click('*[data-id="testTabRunTestsTabStopAction"]') - .waitForElementContainsText('*[data-id="testTabRunTestsTabStopAction"]', 'Stopping', 60000) - .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', '/tests/ks2b_test.sol', 120000) + .waitForElementContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', '/tests/ks2b_test.sol', 200000) .notContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', '/tests/4_Ballot_test.sol') .notContainsText('*[data-id="testTabSolidityUnitTestsOutput"]', '/tests/simple_storage_test.sol') .waitForElementContainsText('*[data-id="testTabTestsExecutionStopped"]', 'The test execution has been stopped', 60000) diff --git a/apps/remix-ide-e2e/src/tests/url.spec.ts b/apps/remix-ide-e2e/src/tests/url.spec.ts index a2abb2cba2..bca3e11e68 100644 --- a/apps/remix-ide-e2e/src/tests/url.spec.ts +++ b/apps/remix-ide-e2e/src/tests/url.spec.ts @@ -17,7 +17,7 @@ module.exports = { return sources }, - 'Should load the code from URL params': function (browser: NightwatchBrowser) { + 'Should load the code from URL params (code param)': function (browser: NightwatchBrowser) { browser .pause(5000) .url('http://127.0.0.1:8080/#optimize=true&runs=300&evmVersion=istanbul&version=soljson-v0.7.4+commit.3f05b770.js&code=cHJhZ21hIHNvbGlkaXR5ID49MC42LjAgPDAuNy4wOwoKaW1wb3J0ICJodHRwczovL2dpdGh1Yi5jb20vT3BlblplcHBlbGluL29wZW56ZXBwZWxpbi1jb250cmFjdHMvYmxvYi9tYXN0ZXIvY29udHJhY3RzL2FjY2Vzcy9Pd25hYmxlLnNvbCI7Cgpjb250cmFjdCBHZXRQYWlkIGlzIE93bmFibGUgewogIGZ1bmN0aW9uIHdpdGhkcmF3KCkgZXh0ZXJuYWwgb25seU93bmVyIHsKICB9Cn0') @@ -31,6 +31,43 @@ module.exports = { }) }, + 'Should load the code from URL params (url param)': function (browser: NightwatchBrowser) { + browser + .pause(5000) + .url('http://127.0.0.1:8080/#optimize=true&runs=300&evmVersion=istanbul&version=soljson-v0.7.4+commit.3f05b770.js&url=https://github.com/ethereum/remix-project/blob/master/apps/remix-ide/contracts/app/solidity/mode.sol') + .refresh() // we do one reload for making sure we already have the default workspace + .pause(5000) + .currentWorkspaceIs('code-sample') + .getEditorValue((content) => { + browser.assert.ok(content.indexOf( + 'proposals.length = _numProposals;') !== -1, + 'url has not been loaded') + }) + }, + + 'Should load the code from URL & code params': function (browser: NightwatchBrowser) { + browser + .pause(5000) + .url('http://127.0.0.1:8080/#optimize=true&runs=300&evmVersion=istanbul&version=soljson-v0.7.4+commit.3f05b770.js&url=https://github.com/ethereum/remix-project/blob/master/apps/remix-ide/contracts/app/solidity/mode.sol&code=cHJhZ21hIHNvbGlkaXR5ID49MC42LjAgPDAuNy4wOwoKaW1wb3J0ICJodHRwczovL2dpdGh1Yi5jb20vT3BlblplcHBlbGluL29wZW56ZXBwZWxpbi1jb250cmFjdHMvYmxvYi9tYXN0ZXIvY29udHJhY3RzL2FjY2Vzcy9Pd25hYmxlLnNvbCI7Cgpjb250cmFjdCBHZXRQYWlkIGlzIE93bmFibGUgewogIGZ1bmN0aW9uIHdpdGhkcmF3KCkgZXh0ZXJuYWwgb25seU93bmVyIHsKICB9Cn0') + .refresh() // we do one reload for making sure we already have the default workspace + .pause(5000) + .currentWorkspaceIs('code-sample') + .getEditorValue((content) => { + browser.assert.ok(content.indexOf( + 'proposals.length = _numProposals;') !== -1, + 'code has not been loaded') + }) + .openFile('contract-76747f6e19.sol') + .openFile('ethereum') + .openFile('ethereum/remix-project') + .openFile('ethereum/remix-project/apps') + .openFile('ethereum/remix-project/apps/remix-ide') + .openFile('ethereum/remix-project/apps/remix-ide/contracts') + .openFile('ethereum/remix-project/apps/remix-ide/contracts/app') + .openFile('ethereum/remix-project/apps/remix-ide/contracts/app/solidity') + .openFile('ethereum/remix-project/apps/remix-ide/contracts/app/solidity/mode.sol') + }, + 'Should load using URL compiler params': function (browser: NightwatchBrowser) { browser .pause(5000) @@ -38,22 +75,22 @@ module.exports = { .refresh() .pause(5000) .clickLaunchIcon('solidity') - .assert.containsText('#versionSelector option[selected="selected"]', '0.7.4+commit.3f05b770') - .assert.containsText('#evmVersionSelector option[selected="selected"]', 'istanbul') + .assert.containsText('#versionSelector option[data-id="selected"]', '0.7.4+commit.3f05b770') + .assert.containsText('#evmVersionSelector option[data-id="selected"]', 'istanbul') .verify.elementPresent('#optimize:checked') .verify.attributeEquals('#runs', 'value', '300') }, 'Should load using compiler from link passed in remix URL': function (browser: NightwatchBrowser) { browser - .url('http://127.0.0.1:8080/#version=https://solidity-blog.s3.eu-central-1.amazonaws.com/data/08preview/soljson.js') + .url('http://127.0.0.1:8080/#version=https://solidity-blog.s3.eu-central-1.amazonaws.com/data/08preview/soljson.js&optimize=false') .refresh() .pause(5000) .clickLaunchIcon('solidity') .pause(5000) - .assert.containsText('#versionSelector option[selected="selected"]', 'custom') + .assert.containsText('#versionSelector option[data-id="selected"]', 'custom') // default values - .assert.containsText('#evmVersionSelector option[selected="selected"]', 'default') + .assert.containsText('#evmVersionSelector option[data-id="selected"]', 'default') .verify.elementPresent('#optimize') .assert.elementNotPresent('#optimize:checked') .verify.elementPresent('#runs:disabled') diff --git a/apps/remix-ide-e2e/src/tests/usingWebWorker.test.ts b/apps/remix-ide-e2e/src/tests/usingWebWorker.test.ts index 7db256035e..707cf13cfc 100644 --- a/apps/remix-ide-e2e/src/tests/usingWebWorker.test.ts +++ b/apps/remix-ide-e2e/src/tests/usingWebWorker.test.ts @@ -32,11 +32,8 @@ module.exports = { .clickLaunchIcon('filePanel') .addFile('basic.sol', sources[0]['basic.sol']) .clickLaunchIcon('solidity') - .execute(function () { - const elem = document.getElementById('nightlies') as HTMLInputElement - - elem.checked = true - }) + .waitForElementVisible('[data-id="compilerNightliesBuild"]') + .click('[data-id="compilerNightliesBuild"]') .noWorkerErrorFor('soljson-v0.3.4+commit.7dab8902.js') .noWorkerErrorFor('soljson-v0.6.5+commit.f956cc89.js') .noWorkerErrorFor('soljson-v0.6.8-nightly.2020.5.14+commit.a6d0067b.js') diff --git a/apps/remix-ide-e2e/src/tests/verticalIconsPanel.spec.ts b/apps/remix-ide-e2e/src/tests/verticalIconsPanel.spec.ts index 29eaf4a95b..d0593433c9 100644 --- a/apps/remix-ide-e2e/src/tests/verticalIconsPanel.spec.ts +++ b/apps/remix-ide-e2e/src/tests/verticalIconsPanel.spec.ts @@ -22,6 +22,7 @@ module.exports = { 'Checks vertical icons panel contex menu deactivate': function (browser: NightwatchBrowser) { browser.waitForElementVisible('div[data-id="remixIdeIconPanel"]', 10000) .waitForElementVisible('*[data-id="verticalIconsKinddebugger"]', 7000) + .pause(5000) .rightClick('[data-id="verticalIconsKinddebugger"]') .click('*[id="menuitemdeactivate"]') .click('*[data-id="verticalIconsKindsettings"]') diff --git a/apps/remix-ide/ci/publishIpfs b/apps/remix-ide/ci/publishIpfs index c56a5f37bf..98a5d56729 100755 --- a/apps/remix-ide/ci/publishIpfs +++ b/apps/remix-ide/ci/publishIpfs @@ -6,13 +6,13 @@ console.log('current folder', process.cwd()) const folder = process.cwd() + '/temp_publish_docker'; (async () => { - const host = 'ipfs.komputing.org' // ethdev berlin ipfs node + const host = 'ipfs.remixproject.org' const ipfs = IpfsHttpClient({ host, port: 443, protocol: 'https' }) try { let result = await ipfs.add(globSource(folder, { recursive: true}), { pin: false }) const hash = result.cid.toString() console.log('ipfs://' + hash) - console.log('https://ipfsgw.komputing.org/ipfs/' + hash) + console.log('https://ipfs.remixproject.org/ipfs/' + hash) console.log('https://gateway.ipfs.io/ipfs/' + hash) } catch (e) { console.log(e) diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index 8beeae8849..67ede9b1bd 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -7,6 +7,7 @@ import PanelsResize from './lib/panels-resize' import { RemixEngine } from './remixEngine' import { RemixAppManager } from './remixAppManager' import { FramingService } from './framingService' +import { WalkthroughService } from './walkthroughService' import { MainView } from './app/panels/main-view' import { ThemeModule } from './app/tabs/theme-module' import { NetworkModule } from './app/tabs/network-module' @@ -16,7 +17,8 @@ import { HiddenPanel } from './app/components/hidden-panel' import { VerticalIcons } from './app/components/vertical-icons' import { LandingPage } from './app/ui/landing-page/landing-page' import { MainPanel } from './app/components/main-panel' -import FetchAndCompile from './app/compiler/compiler-sourceVerifier-fetchAndCompile' + +import { OffsetToLineColumnConverter, CompilerMetadata, CompilerArtefacts, FetchAndCompile, CompilerImports } from '@remix-project/core-plugin' import migrateFileSystem from './migrateFileSystem' @@ -25,7 +27,7 @@ const csjs = require('csjs-inject') const yo = require('yo-yo') const remixLib = require('@remix-project/remix-lib') const registry = require('./global/registry') -const { OffsetToLineColumnConverter } = require('./lib/offsetToLineColumnConverter') + const QueryParams = require('./lib/query-params') const Storage = remixLib.Storage const RemixDProvider = require('./app/files/remixDProvider') @@ -38,13 +40,10 @@ const FileProvider = require('./app/files/fileProvider') const DGitProvider = require('./app/files/dgitProvider') const WorkspaceFileProvider = require('./app/files/workspaceFileProvider') const toolTip = require('./app/ui/tooltip') -const CompilerMetadata = require('./app/files/compiler-metadata') -const CompilerImport = require('./app/compiler/compiler-imports') const Blockchain = require('./blockchain/blockchain.js') const PluginManagerComponent = require('./app/components/plugin-manager-component') -const CompilersArtefacts = require('./app/compiler/compiler-artefacts') const CompileTab = require('./app/tabs/compile-tab') const SettingsTab = require('./app/tabs/settings-tab') @@ -114,7 +113,11 @@ const css = csjs` fill: var(--secondary); } .centered svg polygon { - fill: var(--secondary); + fill : var(--secondary); + } + .onboarding { + color : var(--text-info); + background-color : var(--info); } .matomoBtn { width : 100px; @@ -128,11 +131,11 @@ class App { self._components = {} self._view = {} self._view.splashScreen = yo` -
- ${basicLogo()} -
- REMIX IDE -
+
+ ${basicLogo()} +
+ REMIX IDE +
` document.body.appendChild(self._view.splashScreen) @@ -262,14 +265,14 @@ Please make a backup of your contracts and start using http://remix.ethereum.org const dGitProvider = new DGitProvider() // ----------------- import content service ------------------------ - const contentImport = new CompilerImport(fileManager) + const contentImport = new CompilerImports() const blockchain = new Blockchain(registry.get('config').api) // ----------------- compilation metadata generation service --------- - const compilerMetadataGenerator = new CompilerMetadata(blockchain, fileManager, registry.get('config').api) + const compilerMetadataGenerator = new CompilerMetadata() // ----------------- compilation result service (can keep track of compilation results) ---------------------------- - const compilersArtefacts = new CompilersArtefacts() // store all the compilation results (key represent a compiler name) + const compilersArtefacts = new CompilerArtefacts() // store all the compilation results (key represent a compiler name) registry.put({ api: compilersArtefacts, name: 'compilersartefacts' }) // service which fetch contract artifacts from sourve-verify, put artifacts in remix and compile it @@ -335,7 +338,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org const hiddenPanel = new HiddenPanel() const pluginManagerComponent = new PluginManagerComponent(appManager, engine) const filePanel = new FilePanel(appManager) - const landingPage = new LandingPage(appManager, menuicons, fileManager, filePanel) + const landingPage = new LandingPage(appManager, menuicons, fileManager, filePanel, contentImport) const settings = new SettingsTab( registry.get('config').api, editor, @@ -358,6 +361,9 @@ Please make a backup of your contracts and start using http://remix.ethereum.org settings ]) + const queryParams = new QueryParams() + const params = queryParams.get() + const onAcceptMatomo = () => { _paq.push(['forgetUserOptOut']) // @TODO remove next line when https://github.com/matomo-org/matomo/commit/9e10a150585522ca30ecdd275007a882a70c6df5 is used @@ -365,12 +371,21 @@ Please make a backup of your contracts and start using http://remix.ethereum.org settings.updateMatomoAnalyticsChoice(true) const el = document.getElementById('modal-dialog') el.parentElement.removeChild(el) + startWalkthroughService() } const onDeclineMatomo = () => { settings.updateMatomoAnalyticsChoice(false) _paq.push(['optUserOut']) const el = document.getElementById('modal-dialog') el.parentElement.removeChild(el) + startWalkthroughService() + } + + const startWalkthroughService = () => { + const walkthroughService = new WalkthroughService(localStorage) + if (!params.code && !params.url && !params.minimizeterminal && !params.gist && !params.minimizesidepanel) { + walkthroughService.start() + } } // Ask to opt in to Matomo for remix, remix-alpha and remix-beta @@ -404,6 +419,8 @@ Please make a backup of your contracts and start using http://remix.ethereum.org fn: null } ) + } else { + startWalkthroughService() } // CONTENT VIEWS & DEFAULT PLUGINS @@ -445,7 +462,8 @@ Please make a backup of your contracts and start using http://remix.ethereum.org test, filePanel.remixdHandle, filePanel.gitHandle, - filePanel.hardhatHandle + filePanel.hardhatHandle, + filePanel.slitherHandle ]) if (isElectron()) { @@ -458,14 +476,12 @@ Please make a backup of your contracts and start using http://remix.ethereum.org console.log('couldn\'t register iframe plugins', e.message) } - await appManager.activatePlugin(['contentImport', 'theme', 'editor', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'web3Provider', 'offsetToLineColumnConverter']) + await appManager.activatePlugin(['theme', 'editor', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'web3Provider', 'offsetToLineColumnConverter']) await appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs']) await appManager.activatePlugin(['sidePanel']) // activating host plugin separately await appManager.activatePlugin(['home']) - await appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'filePanel', 'settings', 'contextualListener', 'terminal', 'fetchAndCompile']) - - const queryParams = new QueryParams() - const params = queryParams.get() + await appManager.activatePlugin(['settings']) + await appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'filePanel', 'contextualListener', 'terminal', 'fetchAndCompile', 'contentImport']) // Set workspace after initial activation if (Array.isArray(workspace)) { @@ -497,7 +513,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org // Load and start the service who manager layout and frame const framingService = new FramingService(sidePanel, menuicons, mainview, this._components.resizeFeature) - framingService.start(params) if (params.embed) framingService.embed() + framingService.start(params) } diff --git a/apps/remix-ide/src/app/compiler/compiler-abstract.js b/apps/remix-ide/src/app/compiler/compiler-abstract.js deleted file mode 100644 index fcfb32a827..0000000000 --- a/apps/remix-ide/src/app/compiler/compiler-abstract.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict' -var remixLib = require('@remix-project/remix-lib') -var txHelper = remixLib.execution.txHelper - -module.exports = class CompilerAbstract { - constructor (languageversion, data, source) { - this.languageversion = languageversion - this.data = data - this.source = source // source code - } - - getContracts () { - return this.data.contracts - } - - getContract (name) { - return txHelper.getContract(name, this.data.contracts) - } - - visitContracts (calllback) { - return txHelper.visitContracts(this.data.contracts, calllback) - } - - getData () { - return this.data - } - - getAsts () { - return this.data.sources // ast - } - - getSourceName (fileIndex) { - if (this.data && this.data.sources) { - return Object.keys(this.data.sources)[fileIndex] - } else if (Object.keys(this.source.sources).length === 1) { - // if we don't have ast, we return the only one filename present. - const sourcesArray = Object.keys(this.source.sources) - return sourcesArray[0] - } - return null - } - - getSourceCode () { - return this.source - } -} diff --git a/apps/remix-ide/src/app/compiler/compiler-imports.js b/apps/remix-ide/src/app/compiler/compiler-imports.js deleted file mode 100644 index 0e72bb425d..0000000000 --- a/apps/remix-ide/src/app/compiler/compiler-imports.js +++ /dev/null @@ -1,169 +0,0 @@ -'use strict' -import { Plugin } from '@remixproject/engine' -import * as packageJson from '../../../../../package.json' -import { RemixURLResolver } from '@remix-project/remix-url-resolver' -const remixTests = require('@remix-project/remix-tests') -const globalRegistry = require('../../global/registry') -const addTooltip = require('../ui/tooltip') -const async = require('async') - -const profile = { - name: 'contentImport', - displayName: 'content import', - version: packageJson.version, - methods: ['resolve', 'resolveAndSave', 'isExternalUrl'] -} - -module.exports = class CompilerImports extends Plugin { - constructor (fileManager) { - super(profile) - this.fileManager = fileManager - // const token = await this.call('settings', 'getGithubAccessToken') - const token = globalRegistry.get('config').api.get('settings/gist-access-token') // TODO replace with the plugin call above https://github.com/ethereum/remix-ide/issues/2288 - const protocol = window.location.protocol - this.urlResolver = new RemixURLResolver(token, protocol) - this.previouslyHandled = {} // cache import so we don't make the request at each compilation. - } - - isRelativeImport (url) { - return /^([^/]+)/.exec(url) - } - - isExternalUrl (url) { - const handlers = this.urlResolver.getHandlers() - return handlers.some(handler => handler.match(url)) - } - - /** - * resolve the content of @arg url. This only resolves external URLs. - * - * @param {String} url - external URL of the content. can be basically anything like raw HTTP, ipfs URL, github address etc... - * @returns {Promise} - { content, cleanUrl, type, url } - */ - resolve (url) { - return new Promise((resolve, reject) => { - this.import(url, null, (error, content, cleanUrl, type, url) => { - if (error) return reject(error) - resolve({ content, cleanUrl, type, url }) - }) - }) - } - - async import (url, force, loadingCb, cb) { - if (typeof force !== 'boolean') { - const temp = loadingCb - loadingCb = force - cb = temp - force = false - } - if (!loadingCb) loadingCb = () => {} - if (!cb) cb = () => {} - - var self = this - if (force) delete this.previouslyHandled[url] - var imported = this.previouslyHandled[url] - if (imported) { - return cb(null, imported.content, imported.cleanUrl, imported.type, url) - } - - let resolved - try { - resolved = await this.urlResolver.resolve(url) - const { content, cleanUrl, type } = resolved - self.previouslyHandled[url] = { - content, - cleanUrl, - type - } - cb(null, content, cleanUrl, type, url) - } catch (e) { - return cb(new Error('not found ' + url)) - } - } - - importExternal (url, targetPath, cb) { - this.import(url, - // TODO: move to an event that is generated, the UI shouldn't be here - (loadingMsg) => { addTooltip(loadingMsg) }, - (error, content, cleanUrl, type, url) => { - if (error) return cb(error) - if (this.fileManager) { - const provider = this.fileManager.currentFileProvider() - const path = targetPath || type + '/' + cleanUrl - if (provider) provider.addExternal('.deps/' + path, content, url) - } - cb(null, content) - }) - } - - /** - * import the content of @arg url. - * first look in the browser localstorage (browser explorer) or locahost explorer. if the url start with `browser/*` or `localhost/*` - * then check if the @arg url is located in the localhost, in the node_modules or installed_contracts folder - * then check if the @arg url match any external url - * - * @param {String} url - URL of the content. can be basically anything like file located in the browser explorer, in the localhost explorer, raw HTTP, github address etc... - * @param {String} targetPath - (optional) internal path where the content should be saved to - * @returns {Promise} - string content - */ - resolveAndSave (url, targetPath) { - return new Promise((resolve, reject) => { - if (url.indexOf('remix_tests.sol') !== -1) resolve(remixTests.assertLibCode) - if (!this.fileManager) { - // fallback to just resolving the file, it won't be saved in file manager - return this.importExternal(url, targetPath, (error, content) => { - if (error) return reject(error) - resolve(content) - }) - } - var provider = this.fileManager.fileProviderOf(url) - if (provider) { - if (provider.type === 'localhost' && !provider.isConnected()) { - return reject(new Error(`file provider ${provider.type} not available while trying to resolve ${url}`)) - } - provider.exists(url).then(exist => { - /* - if the path is absolute and the file does not exist, we can stop here - Doesn't make sense to try to resolve "localhost/node_modules/localhost/node_modules/" and we'll end in an infinite loop. - */ - if (!exist && url.startsWith('browser/')) return reject(new Error(`not found ${url}`)) - if (!exist && url.startsWith('localhost/')) return reject(new Error(`not found ${url}`)) - - if (exist) { - return provider.get(url, (error, content) => { - if (error) return reject(error) - resolve(content) - }) - } - - // try to resolve localhost modules (aka truffle imports) - e.g from the node_modules folder - const localhostProvider = this.fileManager.getProvider('localhost') - if (localhostProvider.isConnected()) { - var splitted = /([^/]+)\/(.*)$/g.exec(url) - return async.tryEach([ - (cb) => { this.resolveAndSave('localhost/installed_contracts/' + url).then((result) => cb(null, result)).catch((error) => cb(error.message)) }, - (cb) => { if (!splitted) { cb('URL not parseable: ' + url) } else { this.resolveAndSave('localhost/installed_contracts/' + splitted[1] + '/contracts/' + splitted[2]).then((result) => cb(null, result)).catch((error) => cb(error.message)) } }, - (cb) => { this.resolveAndSave('localhost/node_modules/' + url).then((result) => cb(null, result)).catch((error) => cb(error.message)) }, - (cb) => { if (!splitted) { cb('URL not parseable: ' + url) } else { this.resolveAndSave('localhost/node_modules/' + splitted[1] + '/contracts/' + splitted[2]).then((result) => cb(null, result)).catch((error) => cb(error.message)) } }], - (error, result) => { - if (error) { - return this.importExternal(url, targetPath, (error, content) => { - if (error) return reject(error) - resolve(content) - }) - } - resolve(result) - }) - } - - this.importExternal(url, targetPath, (error, content) => { - if (error) return reject(error) - resolve(content) - }) - }).catch(error => { - return reject(error) - }) - } - }) - } -} diff --git a/apps/remix-ide/src/app/compiler/compiler-input.js b/apps/remix-ide/src/app/compiler/compiler-input.js deleted file mode 100644 index a0be3c499d..0000000000 --- a/apps/remix-ide/src/app/compiler/compiler-input.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict' - -module.exports = (sources, opts) => { - return JSON.stringify({ - language: 'Solidity', - sources: sources, - settings: { - optimizer: { - enabled: opts.optimize === true || opts.optimize === 1, - runs: 200 - }, - libraries: opts.libraries, - outputSelection: { - '*': { - '': ['ast'], - '*': ['abi', 'metadata', 'devdoc', 'userdoc', 'evm.legacyAssembly', 'evm.bytecode', 'evm.deployedBytecode', 'evm.methodIdentifiers', 'evm.gasEstimates'] - } - } - } - }) -} diff --git a/apps/remix-ide/src/app/components/vertical-icons.js b/apps/remix-ide/src/app/components/vertical-icons.js index 7a31682ed1..54b77f9720 100644 --- a/apps/remix-ide/src/app/components/vertical-icons.js +++ b/apps/remix-ide/src/app/components/vertical-icons.js @@ -69,12 +69,14 @@ export class VerticalIcons extends Plugin { title = title.replace(/^\w/, c => c.toUpperCase()) this.icons[name] = yo`
+ data-id="verticalIconsKind${name}" + id="verticalIconsKind${name}" + > ${name}
` this.iconKind[kind || 'none'].appendChild(this.icons[name]) @@ -249,13 +251,14 @@ export class VerticalIcons extends Plugin { render () { const home = yo`
${basicLogo()}
@@ -270,16 +273,18 @@ export class VerticalIcons extends Plugin { this.iconKind.settings = yo`
` this.view = yo` -
- ${home} - ${this.iconKind.fileexplorer} - ${this.iconKind.compiler} - ${this.iconKind.udapp} - ${this.iconKind.testing} - ${this.iconKind.analysis} - ${this.iconKind.debugging} - ${this.iconKind.none} - ${this.iconKind.settings} +
+
+ ${home} + ${this.iconKind.fileexplorer} + ${this.iconKind.compiler} + ${this.iconKind.udapp} + ${this.iconKind.testing} + ${this.iconKind.analysis} + ${this.iconKind.debugging} + ${this.iconKind.none} + ${this.iconKind.settings} +
` return this.view @@ -292,7 +297,6 @@ const css = csjs` width: 42px; height: 42px; margin-bottom: 20px; - margin-left: -5px; cursor: pointer; } .homeIcon svg path { @@ -302,8 +306,6 @@ const css = csjs` fill: var(--primary); } .icons { - margin-left: 10px; - margin-top: 15px; } .icon { cursor: pointer; diff --git a/apps/remix-ide/src/app/editor/sourceHighlighter.js b/apps/remix-ide/src/app/editor/sourceHighlighter.js index e25e2c948f..22f705001e 100644 --- a/apps/remix-ide/src/app/editor/sourceHighlighter.js +++ b/apps/remix-ide/src/app/editor/sourceHighlighter.js @@ -37,7 +37,7 @@ class SourceHighlighter { this.statementMarker = null this.fullLineMarker = null this.source = null - if (lineColumnPos) { + if (lineColumnPos && lineColumnPos.start && lineColumnPos.end) { this.source = filePath this.style = style || 'var(--info)' // if (!this.source) this.source = this._deps.fileManager.currentFile() diff --git a/apps/remix-ide/src/app/files/compiler-metadata.js b/apps/remix-ide/src/app/files/compiler-metadata.js deleted file mode 100644 index fe4dfc3c43..0000000000 --- a/apps/remix-ide/src/app/files/compiler-metadata.js +++ /dev/null @@ -1,148 +0,0 @@ -'use strict' -import { Plugin } from '@remixproject/engine' -import * as packageJson from '../../../../../package.json' -import { joinPath } from '../../lib/helper' -var CompilerAbstract = require('../compiler/compiler-abstract') - -const profile = { - name: 'compilerMetadata', - methods: ['deployMetadataOf'], - events: [], - version: packageJson.version -} - -class CompilerMetadata extends Plugin { - constructor (blockchain, fileManager, config) { - super(profile) - this.blockchain = blockchain - this.fileManager = fileManager - this.config = config - this.networks = ['VM:-', 'main:1', 'ropsten:3', 'rinkeby:4', 'kovan:42', 'görli:5', 'Custom'] - this.innerPath = 'artifacts' - } - - _JSONFileName (path, contractName) { - return joinPath(path, this.innerPath, contractName + '.json') - } - - _MetadataFileName (path, contractName) { - return joinPath(path, this.innerPath, contractName + '_metadata.json') - } - - onActivation () { - var self = this - this.on('solidity', 'compilationFinished', (file, source, languageVersion, data) => { - if (!self.config.get('settings/generate-contract-metadata')) return - const compiler = new CompilerAbstract(languageVersion, data, source) - var provider = self.fileManager.fileProviderOf(source.target) - var path = self.fileManager.extractPathOf(source.target) - if (provider) { - compiler.visitContracts((contract) => { - if (contract.file !== source.target) return - - var fileName = self._JSONFileName(path, contract.name) - var metadataFileName = self._MetadataFileName(path, contract.name) - provider.get(fileName, (error, content) => { - if (!error) { - content = content || '{}' - var metadata - try { - metadata = JSON.parse(content) - } catch (e) { - console.log(e) - } - - var deploy = metadata.deploy || {} - self.networks.forEach((network) => { - deploy[network] = self._syncContext(contract, deploy[network] || {}) - }) - - let parsedMetadata - try { - parsedMetadata = JSON.parse(contract.object.metadata) - } catch (e) { - console.log(e) - } - if (parsedMetadata) provider.set(metadataFileName, JSON.stringify(parsedMetadata, null, '\t')) - - var data = { - deploy, - data: { - bytecode: contract.object.evm.bytecode, - deployedBytecode: contract.object.evm.deployedBytecode, - gasEstimates: contract.object.evm.gasEstimates, - methodIdentifiers: contract.object.evm.methodIdentifiers - }, - abi: contract.object.abi - } - - provider.set(fileName, JSON.stringify(data, null, '\t')) - } - }) - }) - } - }) - } - - _syncContext (contract, metadata) { - var linkReferences = metadata.linkReferences - var autoDeployLib = metadata.autoDeployLib - if (!linkReferences) linkReferences = {} - if (autoDeployLib === undefined) autoDeployLib = true - - for (var libFile in contract.object.evm.bytecode.linkReferences) { - if (!linkReferences[libFile]) linkReferences[libFile] = {} - for (var lib in contract.object.evm.bytecode.linkReferences[libFile]) { - if (!linkReferences[libFile][lib]) { - linkReferences[libFile][lib] = '
' - } - } - } - metadata.linkReferences = linkReferences - metadata.autoDeployLib = autoDeployLib - return metadata - } - - // TODO: is only called by dropdownLogic and can be moved there - deployMetadataOf (contractName, fileLocation) { - return new Promise((resolve, reject) => { - var provider - let path - if (fileLocation) { - provider = this.fileManager.fileProviderOf(fileLocation) - path = fileLocation.split('/') - path.pop() - path = path.join('/') - } else { - provider = this.fileManager.currentFileProvider() - path = this.fileManager.currentPath() - } - - if (provider) { - this.blockchain.detectNetwork((err, { id, name } = {}) => { - if (err) { - console.log(err) - reject(err) - } else { - var fileName = this._JSONFileName(path, contractName) - provider.get(fileName, (error, content) => { - if (error) return reject(error) - if (!content) return resolve() - try { - var metadata = JSON.parse(content) - metadata = metadata.deploy || {} - return resolve(metadata[name + ':' + id] || metadata[name] || metadata[id] || metadata[name.toLowerCase() + ':' + id] || metadata[name.toLowerCase()]) - } catch (e) { - reject(e.message) - } - }) - } - }) - } else { - reject(new Error(`Please select the folder in the file explorer where the metadata of ${contractName} can be found`)) - } - }) - } -} - -module.exports = CompilerMetadata diff --git a/apps/remix-ide/src/app/files/dgitProvider.js b/apps/remix-ide/src/app/files/dgitProvider.js index ed7d4edb8e..e62c23bce3 100644 --- a/apps/remix-ide/src/app/files/dgitProvider.js +++ b/apps/remix-ide/src/app/files/dgitProvider.js @@ -27,10 +27,10 @@ class DGitProvider extends Plugin { constructor () { super(profile) this.ipfsconfig = { - host: 'ipfs.komputing.org', + host: 'ipfs.remixproject.org', port: 443, protocol: 'https', - ipfsurl: 'https://ipfsgw.komputing.org/ipfs/' + ipfsurl: 'https://ipfs.remixproject.org/ipfs/' } this.globalIPFSConfig = { host: 'ipfs.io', @@ -206,7 +206,20 @@ class DGitProvider extends Plugin { const commits = await this.log({ ref: 'HEAD' }) ob = { ref: commits[0].oid, - message: commits[0].commit.message + message: commits[0].commit.message, + commits: JSON.stringify(commits.map((commit) => { + return { + oid: commit.oid, + commit: { + parent: commit.commit?.parent, + tree: commit.commit?.tree, + message: commit.commit?.message, + committer: { + timestamp: commit.commit?.committer?.timestamp + } + } + } + })) } } catch (e) { ob = { diff --git a/apps/remix-ide/src/app/files/file-explorer.js b/apps/remix-ide/src/app/files/file-explorer.js deleted file mode 100644 index cef877b68b..0000000000 --- a/apps/remix-ide/src/app/files/file-explorer.js +++ /dev/null @@ -1,702 +0,0 @@ -/* global FileReader */ -/* global fetch */ -const async = require('async') -const Gists = require('gists') -const modalDialogCustom = require('../ui/modal-dialog-custom') -const tooltip = require('../ui/tooltip') -const QueryParams = require('../../lib/query-params') -const helper = require('../../lib/helper') -const yo = require('yo-yo') -const Treeview = require('../ui/TreeView') -const modalDialog = require('../ui/modaldialog') -const EventManager = require('events') -const contextMenu = require('../ui/contextMenu') -const css = require('./styles/file-explorer-styles') -const globalRegistry = require('../../global/registry') -const queryParams = new QueryParams() -let MENU_HANDLE - -function fileExplorer (localRegistry, files, menuItems, plugin) { - var self = this - this.events = new EventManager() - // file provider backend - this.files = files - // element currently focused on - this.focusElement = null - // path currently focused on - this.focusPath = null - const allItems = - [ - { - action: 'createNewFile', - title: 'Create New File', - icon: 'fas fa-plus-circle' - }, - { - action: 'publishToGist', - title: 'Publish all [browser] explorer files to a github gist', - icon: 'fab fa-github' - }, - { - action: 'uploadFile', - title: 'Add Local file to the Browser Storage Explorer', - icon: 'far fa-folder-open' - }, - { - action: 'updateGist', - title: 'Update the current [gist] explorer', - icon: 'fab fa-github' - } - ] - // menu items - this.menuItems = allItems.filter( - (item) => { - if (menuItems) return menuItems.find((name) => { return name === item.action }) - } - ) - - self._components = {} - self._components.registry = localRegistry || globalRegistry - self._deps = { - config: self._components.registry.get('config').api, - editor: self._components.registry.get('editor').api, - fileManager: self._components.registry.get('filemanager').api - } - - self.events.register('focus', function (path) { - self._deps.fileManager.open(path) - }) - - self._components.registry.put({ api: self, name: `fileexplorer/${self.files.type}` }) - - // warn if file changed outside of Remix - function remixdDialog () { - return yo`
This file has been changed outside of Remix IDE.
` - } - - this.files.event.register('fileExternallyChanged', (path, file) => { - if (self._deps.config.get('currentFile') === path && self._deps.editor.currentContent() && self._deps.editor.currentContent() !== file.content) { - if (this.files.isReadOnly(path)) return self._deps.editor.setText(file.content) - - modalDialog(path + ' changed', remixdDialog(), - { - label: 'Replace by the new content', - fn: () => { - self._deps.editor.setText(file.content) - } - }, - { - label: 'Keep the content displayed in Remix', - fn: () => {} - } - ) - } - }) - - // register to event of the file provider - files.event.on('fileRemoved', fileRemoved) - files.event.on('fileRenamed', fileRenamed) - files.event.on('fileRenamedError', fileRenamedError) - files.event.on('fileAdded', fileAdded) - files.event.on('folderAdded', folderAdded) - - function fileRenamedError (error) { - modalDialogCustom.alert(error) - } - - function fileAdded (filepath) { - self.ensureRoot(() => { - const folderpath = filepath.split('/').slice(0, -1).join('/') - const currentTree = self.treeView.nodeAt(folderpath) - if (!self.treeView.isExpanded(folderpath)) self.treeView.expand(folderpath) - if (currentTree) { - self.files.resolveDirectory(folderpath, (error, fileTree) => { - if (error) console.error(error) - if (!fileTree) return - fileTree = normalize(folderpath, fileTree) - self.treeView.updateNodeFromJSON(folderpath, fileTree, true) - self.focusElement = self.treeView.labelAt(self.focusPath) - // TODO: here we update the selected file (it applicable) - // cause we are refreshing the interface of the whole directory when there's a new file. - if (self.focusElement && !self.focusElement.classList.contains('bg-secondary')) { - self.focusElement.classList.add('bg-secondary') - } - }) - } - }) - } - - function extractNameFromKey (key) { - const keyPath = key.split('/') - - return keyPath[keyPath.length - 1] - } - - function folderAdded (folderpath) { - self.ensureRoot(() => { - folderpath = folderpath.split('/').slice(0, -1).join('/') - self.files.resolveDirectory(folderpath, (error, fileTree) => { - if (error) console.error(error) - if (!fileTree) return - fileTree = normalize(folderpath, fileTree) - self.treeView.updateNodeFromJSON(folderpath, fileTree, true) - if (!self.treeView.isExpanded(folderpath)) self.treeView.expand(folderpath) - }) - }) - } - - function fileRemoved (filepath) { - const label = self.treeView.labelAt(filepath) - filepath = filepath.split('/').slice(0, -1).join('/') - - if (label && label.parentElement) { - label.parentElement.removeChild(label) - } - - self.updatePath(filepath) - } - - function fileRenamed (oldName, newName, isFolder) { - fileRemoved(oldName) - fileAdded(newName) - } - - // make interface and register to nodeClick, leafClick - self.treeView = new Treeview({ - extractData: function extractData (value, tree, key) { - var newValue = {} - // var isReadOnly = false - var isFile = false - Object.keys(value).filter(function keep (x) { - if (x === '/content') isFile = true - if (x[0] !== '/') return true - }).forEach(function (x) { newValue[x] = value[x] }) - return { - path: (tree || {}).path ? tree.path + '/' + key : key, - children: isFile ? undefined - : value instanceof Array ? value.map((item, index) => ({ - key: index, value: item - })) : value instanceof Object ? Object.keys(value).map(subkey => ({ - key: subkey, value: value[subkey] - })) : undefined - } - }, - formatSelf: function formatSelf (key, data, li) { - const isRoot = data.path === self.files.type - const isFolder = !!data.children - return yo` -
- - ${key.split('/').pop()} - - ${isRoot ? self.renderMenuItems() : ''} -
- ` - } - }) - - /** - * Extracts first two folders as a subpath from the path. - **/ - function extractExternalFolder (path) { - const firstSlIndex = path.indexOf('/', 1) - if (firstSlIndex === -1) return '' - const secondSlIndex = path.indexOf('/', firstSlIndex + 1) - if (secondSlIndex === -1) return '' - return path.substring(0, secondSlIndex) - } - - self.treeView.event.register('nodeRightClick', function (key, data, label, event) { - if (self.files.readonly) return - if (key === self.files.type) return - MENU_HANDLE && MENU_HANDLE.hide(null, true) - const actions = {} - const provider = self._deps.fileManager.fileProviderOf(key) - actions['Create File'] = () => self.createNewFile(key) - actions['Create Folder'] = () => self.createNewFolder(key) - // @todo(#2386) not fully implemented. Readd later when fixed - if (provider.isExternalFolder(key)) { - /* actions['Discard changes'] = () => { - modalDialogCustom.confirm( - 'Discard changes', - 'Are you sure you want to discard all your changes?', - () => { self.files.discardChanges(key) }, - () => {} - ) - } */ - } else { - const folderPath = extractExternalFolder(key) - actions.Rename = () => { - if (self.files.isReadOnly(key)) { return tooltip('cannot rename folder. ' + self.files.type + ' is a read only explorer') } - var name = label.querySelector('span[data-path="' + key + '"]') - if (name) editModeOn(name) - } - actions.Delete = () => { - if (self.files.isReadOnly(key)) { return tooltip('cannot delete folder. ' + self.files.type + ' is a read only explorer') } - const currentFoldername = extractNameFromKey(key) - - modalDialogCustom.confirm('Confirm to delete folder', `Are you sure you want to delete ${currentFoldername} folder?`, - async () => { - const fileManager = self._deps.fileManager - const removeFolder = await fileManager.remove(key) - - if (!removeFolder) { - tooltip(`failed to remove ${key}. Make sure the directory is empty before removing it.`) - } - }, () => {}) - } - if (folderPath === 'browser/gists') { - actions['Push changes to gist'] = () => { - const id = key.substr(key.lastIndexOf('/') + 1, key.length - 1) - modalDialogCustom.confirm( - 'Push back to Gist', - 'Are you sure you want to push all your changes back to Gist?', - () => { self.toGist(id) }, - () => {} - ) - } - } - } - MENU_HANDLE = contextMenu(event, actions) - }) - - self.treeView.event.register('leafRightClick', function (key, data, label, event) { - if (key === self.files.type) return - MENU_HANDLE && MENU_HANDLE.hide(null, true) - const actions = {} - const provider = self._deps.fileManager.fileProviderOf(key) - if (!provider.isExternalFolder(key)) { - actions['Create Folder'] = () => self.createNewFolder(self._deps.fileManager.extractPathOf(key)) - actions.Rename = () => { - if (self.files.isReadOnly(key)) { return tooltip('cannot rename file. ' + self.files.type + ' is a read only explorer') } - var name = label.querySelector('span[data-path="' + key + '"]') - if (name) editModeOn(name) - } - actions.Delete = () => { - if (self.files.isReadOnly(key)) { return tooltip('cannot delete file. ' + self.files.type + ' is a read only explorer') } - const currentFilename = extractNameFromKey(key) - - modalDialogCustom.confirm( - 'Delete file', `Are you sure you want to delete ${currentFilename} file?`, - async () => { - const fileManager = self._deps.fileManager - const removeFile = await fileManager.remove(key) - - if (!removeFile) { - tooltip(`Failed to remove file ${key}.`) - } - }, - () => {} - ) - } - if (key.endsWith('.js')) { - actions.Run = async () => { - provider.get(key, (error, content) => { - if (error) return console.log(error) - plugin.call('scriptRunner', 'execute', content) - }) - } - } - } - MENU_HANDLE = contextMenu(event, actions) - }) - - self.treeView.event.register('leafClick', function (key, data, label) { - self.events.trigger('focus', [key]) - }) - - self.treeView.event.register('nodeClick', function (path, childrenContainer) { - if (!childrenContainer) return - if (childrenContainer.style.display === 'none') return - self.updatePath(path) - }) - - // register to main app, trigger when the current file in the editor changed - self._deps.fileManager.events.on('currentFileChanged', (newFile) => { - const provider = self._deps.fileManager.fileProviderOf(newFile) - if (self.focusElement && self.focusPath !== newFile) { - self.focusElement.classList.remove('bg-secondary') - self.focusElement = null - self.focusPath = null - } - if (provider && (provider.type === files.type)) { - self.focusElement = self.treeView.labelAt(newFile) - if (self.focusElement) { - self.focusElement.classList.add('bg-secondary') - self.focusPath = newFile - } - } - }) - - self._deps.fileManager.events.on('noFileSelected', () => { - if (self.focusElement) { - self.focusElement.classList.remove('bg-secondary') - self.focusElement = null - self.focusPath = null - } - }) - - var textUnderEdit = null - - function selectElementContents (el) { - var range = document.createRange() - range.selectNodeContents(el) - var sel = window.getSelection() - sel.removeAllRanges() - sel.addRange(range) - } - - function editModeOn (label) { - textUnderEdit = label.innerText - label.setAttribute('contenteditable', true) - label.classList.add('bg-light') - label.focus() - selectElementContents(label) - } - - function editModeOff (event) { - const label = this - - const isFolder = label.className.indexOf('folder') !== -1 - function rename () { - var newPath = label.dataset.path - newPath = newPath.split('/') - newPath[newPath.length - 1] = label.innerText - newPath = newPath.join('/') - if (label.innerText === '') { - modalDialogCustom.alert('File name cannot be empty') - label.innerText = textUnderEdit - } else if (helper.checkSpecialChars(label.innerText)) { - modalDialogCustom.alert('Special characters are not allowed') - label.innerText = textUnderEdit - } else { - files.exists(newPath, (error, exist) => { - if (error) return modalDialogCustom.alert('Unexpected error while renaming: ' + error) - if (!exist) { - files.rename(label.dataset.path, newPath, isFolder) - } else { - modalDialogCustom.alert('File already exists.') - label.innerText = textUnderEdit - } - }) - } - } - - if (event.which === 13) event.preventDefault() - if ((event.type === 'blur' || event.which === 13) && label.getAttribute('contenteditable')) { - var save = textUnderEdit !== label.innerText - if (save) { - modalDialogCustom.confirm( - 'Confirm to rename a ' + (isFolder ? 'folder' : 'file'), - 'Are you sure you want to rename ' + textUnderEdit + '?', - () => { rename() }, - () => { label.innerText = textUnderEdit } - ) - } - label.removeAttribute('contenteditable') - label.classList.remove('bg-light') - } - } -} - -fileExplorer.prototype.updatePath = function (path) { - this.files.resolveDirectory(path, (error, fileTree) => { - if (error) console.error(error) - if (!fileTree) return - var newTree = normalize(path, fileTree) - this.treeView.updateNodeFromJSON(path, newTree, true) - }) -} - -fileExplorer.prototype.hide = function () { - if (this.container) this.container.style.display = 'none' -} - -fileExplorer.prototype.show = function () { - if (this.container) this.container.style.display = 'block' -} - -fileExplorer.prototype.init = function () { - this.container = yo`
` - return this.container -} - -fileExplorer.prototype.publishToGist = function () { - modalDialogCustom.confirm( - 'Create a public gist', - 'Are you sure you want to publish all your files in browser directory anonymously as a public gist on github.com? Note: this will not include directories.', - () => { this.toGist() } - ) -} - -fileExplorer.prototype.uploadFile = function (event) { - // TODO The file explorer is merely a view on the current state of - // the files module. Please ask the user here if they want to overwrite - // a file and then just use `files.add`. The file explorer will - // pick that up via the 'fileAdded' event from the files module. - - const self = this - - ;[...event.target.files].forEach((file) => { - const files = this.files - function loadFile () { - var fileReader = new FileReader() - fileReader.onload = async function (event) { - if (helper.checkSpecialChars(file.name)) { - modalDialogCustom.alert('Special characters are not allowed') - return - } - var success = await files.set(name, event.target.result) - if (!success) { - modalDialogCustom.alert('Failed to create file ' + name) - } else { - self.events.trigger('focus', [name]) - } - } - fileReader.readAsText(file) - } - var name = files.type + '/' + file.name - files.exists(name, (error, exist) => { - if (error) console.log(error) - if (!exist) { - loadFile() - } else { - modalDialogCustom.confirm('Confirm overwrite', `The file ${name} already exists! Would you like to overwrite it?`, () => { loadFile() }) - } - }) - }) -} - -fileExplorer.prototype.toGist = function (id) { - const proccedResult = function (error, data) { - if (error) { - modalDialogCustom.alert('Failed to manage gist: ' + error) - console.log('Failed to manage gist: ' + error) - } else { - if (data.html_url) { - modalDialogCustom.confirm('Gist is ready', `The gist is at ${data.html_url}. Would you like to open it in a new window?`, () => { - window.open(data.html_url, '_blank') - }) - } else { - modalDialogCustom.alert(data.message + ' ' + data.documentation_url + ' ' + JSON.stringify(data.errors, null, '\t')) - } - } - } - - /** - * This function is to get the original content of given gist - * @params id is the gist id to fetch - */ - async function getOriginalFiles (id) { - if (!id) { - return [] - } - - const url = `https://api.github.com/gists/${id}` - const res = await fetch(url) - const data = await res.json() - return data.files || [] - } - - // If 'id' is not defined, it is not a gist update but a creation so we have to take the files from the browser explorer. - const folder = id ? '/gists/' + id : '/' - this.packageFiles(this.files, folder, (error, packaged) => { - if (error) { - console.log(error) - modalDialogCustom.alert('Failed to create gist: ' + error.message) - } else { - // check for token - var tokenAccess = this._deps.config.get('settings/gist-access-token') - if (!tokenAccess) { - modalDialogCustom.alert( - 'Remix requires an access token (which includes gists creation permission). Please go to the settings tab to create one.' - ) - } else { - const description = 'Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. \n Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=' + - queryParams.get().version + '&optimize=' + queryParams.get().optimize + '&runs=' + queryParams.get().runs + '&gist=' - const gists = new Gists({ token: tokenAccess }) - - if (id) { - const originalFileList = getOriginalFiles(id) - // Telling the GIST API to remove files - const updatedFileList = Object.keys(packaged) - const allItems = Object.keys(originalFileList) - .filter(fileName => updatedFileList.indexOf(fileName) === -1) - .reduce((acc, deleteFileName) => ({ - ...acc, - [deleteFileName]: null - }), originalFileList) - // adding new files - updatedFileList.forEach((file) => { - const _items = file.split('/') - const _fileName = _items[_items.length - 1] - allItems[_fileName] = packaged[file] - }) - - tooltip('Saving gist (' + id + ') ...') - gists.edit({ - description: description, - public: true, - files: allItems, - id: id - }, (error, result) => { - proccedResult(error, result) - if (!error) { - for (const key in allItems) { - if (allItems[key] === null) delete allItems[key] - } - } - }) - } else { - // id is not existing, need to create a new gist - tooltip('Creating a new gist ...') - gists.create({ - description: description, - public: true, - files: packaged - }, (error, result) => { - proccedResult(error, result) - }) - } - } - } - }) -} - -// return all the files, except the temporary/readonly ones.. -fileExplorer.prototype.packageFiles = function (filesProvider, directory, callback) { - const ret = {} - filesProvider.resolveDirectory(directory, (error, files) => { - if (error) callback(error) - else { - async.eachSeries(Object.keys(files), (path, cb) => { - if (filesProvider.isDirectory(path)) { - cb() - } else { - filesProvider.get(path, (error, content) => { - if (error) return cb(error) - if (/^\s+$/.test(content) || !content.length) { - content = '// this line is added to create a gist. Empty file is not allowed.' - } - ret[path] = { content } - cb() - }) - } - }, (error) => { - callback(error, ret) - }) - } - }) -} - -fileExplorer.prototype.createNewFile = function (parentFolder = '/') { - const self = this - modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => { - if (!input) input = 'New file' - helper.createNonClashingName(parentFolder + '/' + input, self.files, async (error, newName) => { - if (error) return tooltip('Failed to create file ' + newName + ' ' + error) - const fileManager = self._deps.fileManager - const createFile = await fileManager.writeFile(newName, '') - - if (!createFile) { - tooltip('Failed to create file ' + newName) - } else { - await fileManager.open(newName) - if (newName.includes('_test.sol')) { - self.events.trigger('newTestFileCreated', [newName]) - } - } - }) - }, null, true) -} - -fileExplorer.prototype.createNewFolder = function (parentFolder) { - const self = this - modalDialogCustom.prompt('Create new folder', '', 'New folder', (input) => { - if (!input) { - return tooltip('Failed to create folder. The name can not be empty') - } - - const currentPath = !parentFolder ? self._deps.fileManager.currentPath() : parentFolder - let newName = currentPath ? currentPath + '/' + input : self.files.type + '/' + input - - newName = newName + '/' - self.files.exists(newName, (error, exist) => { - if (error) return tooltip('Unexpected error while creating folder: ' + error) - if (!exist) { - self.files.set(newName, '') - } else { - tooltip('Folder already exists.', () => {}) - } - }) - }, null, true) -} - -fileExplorer.prototype.renderMenuItems = function () { - let items = '' - if (this.menuItems) { - items = this.menuItems.map(({ action, title, icon }) => { - if (action === 'uploadFile') { - return yo` - - ` - } else { - return yo` - { event.stopPropagation(); this[action]() }} - class="newFile ${icon} ${css.newFile}" - title=${title} - > - - ` - } - }) - } - return yo`${items}` -} - -fileExplorer.prototype.ensureRoot = function (cb) { - cb = cb || (() => {}) - var self = this - if (self.element) return cb() - const root = {} - root[this.files.type] = {} - var element = self.treeView.render(root, false) - element.classList.add(css.fileexplorer) - element.events = self.events - element.api = self.api - self.container.appendChild(element) - self.element = element - if (cb) cb() - self.treeView.expand(self.files.type) -} - -function normalize (path, filesList) { - var prefix = path.split('/')[0] - var newList = {} - Object.keys(filesList).forEach(key => { - newList[prefix + '/' + key] = filesList[key].isDirectory ? {} : { '/content': true } - }) - return newList -} - -module.exports = fileExplorer diff --git a/apps/remix-ide/src/app/files/fileManager.js b/apps/remix-ide/src/app/files/fileManager.js index c789991a9a..f2d83d3915 100644 --- a/apps/remix-ide/src/app/files/fileManager.js +++ b/apps/remix-ide/src/app/files/fileManager.js @@ -22,7 +22,7 @@ const profile = { icon: 'assets/img/fileManager.webp', permission: true, version: packageJson.version, - methods: ['file', 'exists', 'open', 'writeFile', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', 'readdir', 'remove', 'getCurrentFile', 'getFile', 'getFolder', 'setFile', 'switchFile', 'refresh'], + methods: ['file', 'exists', 'open', 'writeFile', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', 'readdir', 'remove', 'getCurrentFile', 'getFile', 'getFolder', 'setFile', 'switchFile', 'refresh', 'getProviderOf', 'getProviderByName'], kind: 'file-system' } const errorMsg = { @@ -155,9 +155,9 @@ class FileManager extends Plugin { * @param {string} path path of the directory * @returns {boolean} true if path is a directory. */ - isDirectory (path) { + async isDirectory (path) { const provider = this.fileProviderOf(path) - const result = provider.isDirectory(path) + const result = await provider.isDirectory(path) return result } @@ -362,7 +362,6 @@ class FileManager extends Plugin { path = this.limitPluginScope(path) await this._handleExists(path, `Cannot remove file or directory ${path}`) const provider = this.fileProviderOf(path) - return await provider.remove(path) } catch (e) { throw new Error(e) @@ -597,6 +596,32 @@ class FileManager extends Plugin { } } + /** + * Async API method getProviderOf + * @param {string} file + * + */ + + async getProviderOf (file) { + const cancall = await this.askUserPermission('getProviderByName') + if (cancall) { + return file ? this.fileProviderOf(file) : this.currentFileProvider() + } + } + + /** + * Async API method getProviderByName + * @param {string} name + * + */ + + async getProviderByName (name) { + const cancall = await this.askUserPermission('getProviderByName') + if (cancall) { + return this.getProvider(name) + } + } + getProvider (name) { return this._deps.filesProviders[name] } diff --git a/apps/remix-ide/src/app/files/fileProvider.js b/apps/remix-ide/src/app/files/fileProvider.js index 5d152ec74b..c789635160 100644 --- a/apps/remix-ide/src/app/files/fileProvider.js +++ b/apps/remix-ide/src/app/files/fileProvider.js @@ -1,6 +1,6 @@ 'use strict' -const CompilerImport = require('../compiler/compiler-imports') +import { CompilerImports } from '@remix-project/core-plugin' const EventManager = require('events') const modalDialogCustom = require('../ui/modal-dialog-custom') const tooltip = require('../ui/tooltip') @@ -44,7 +44,7 @@ class FileProvider { discardChanges (path) { this.remove(path) - const compilerImport = new CompilerImport() + const compilerImport = new CompilerImports() this.providerExternalsStorage.keys().map(value => { if (value.indexOf(path) === 0) { compilerImport.import( diff --git a/apps/remix-ide/src/app/files/remixDProvider.js b/apps/remix-ide/src/app/files/remixDProvider.js index bc59bfe90b..04b0217df1 100644 --- a/apps/remix-ide/src/app/files/remixDProvider.js +++ b/apps/remix-ide/src/app/files/remixDProvider.js @@ -38,7 +38,7 @@ module.exports = class RemixDProvider extends FileProvider { }) this._appManager.on('remixd', 'fileRenamed', (oldPath, newPath) => { - this.event.emit('fileRemoved', oldPath, newPath) + this.event.emit('fileRenamed', oldPath, newPath) }) this._appManager.on('remixd', 'rootFolderChanged', () => { @@ -141,7 +141,6 @@ module.exports = class RemixDProvider extends FileProvider { this._appManager.call('remixd', 'remove', { path: unprefixedpath }) .then(result => { const path = unprefixedpath - delete this.filesContent[path] resolve(true) this.init() diff --git a/apps/remix-ide/src/app/files/remixd-handle.js b/apps/remix-ide/src/app/files/remixd-handle.js index abea437b64..be6997574d 100644 --- a/apps/remix-ide/src/app/files/remixd-handle.js +++ b/apps/remix-ide/src/app/files/remixd-handle.js @@ -43,6 +43,7 @@ export class RemixdHandle extends WebsocketPlugin { if (super.socket) super.deactivate() // this.appManager.deactivatePlugin('git') // plugin call doesn't work.. see issue https://github.com/ethereum/remix-plugin/issues/342 if (this.appManager.actives.includes('hardhat')) this.appManager.deactivatePlugin('hardhat') + if (this.appManager.actives.includes('slither')) this.appManager.deactivatePlugin('slither') this.localhostProvider.close((error) => { if (error) console.log(error) }) @@ -88,6 +89,7 @@ export class RemixdHandle extends WebsocketPlugin { this.call('filePanel', 'setWorkspace', { name: LOCALHOST, isLocalhost: true }, true) }) this.call('manager', 'activatePlugin', 'hardhat') + this.call('manager', 'activatePlugin', 'slither') } } if (this.localhostProvider.isConnected()) { @@ -134,23 +136,25 @@ export class RemixdHandle extends WebsocketPlugin { } function remixdDialog () { - const commandText = 'remixd -s path-to-the-shared-folder --remix-ide remix-ide-instance-URL' + const commandText = 'remixd -s -u ' return yo`
Access your local file system from Remix IDE using Remixd NPM package.

Remixd needs to be running in the background to load the files in localhost workspace. For more info, please check the Remixd tutorial.
-
If you are just looking for the remixd command, here it is: +
+ If you are just looking for the remixd command, here it is:

${commandText} ${copyToClipboard(() => commandText)}
-
When connected, a session will be started between ${window.location.origin} and your local file system at ws://127.0.0.1:65520 - and the shared folder will be in the File Explorers workspace named "localhost". -
Note, if the shared folder is a Hardhat project, an additional Hardhat websocket plugin will be listening at ws://127.0.0.1:65522 +
+ When connected, a session will be started between ${window.location.origin} and your local file system at ws://127.0.0.1:65520. + The shared folder will be in the "File Explorers" workspace named "localhost". +
Read more about other Remixd ports usage
-
Please make sure your system is secured enough and ports 65520, 65522 are not opened nor forwarded. - This feature is still in Alpha, so we recommend to keep a copy of the shared folder. +
+ This feature is still in Alpha. We recommend to keep a backup of the shared folder.
diff --git a/apps/remix-ide/src/app/files/slither-handle.js b/apps/remix-ide/src/app/files/slither-handle.js new file mode 100644 index 0000000000..e8ff1e66c7 --- /dev/null +++ b/apps/remix-ide/src/app/files/slither-handle.js @@ -0,0 +1,18 @@ +import { WebsocketPlugin } from '@remixproject/engine-web' +import * as packageJson from '../../../../../package.json' + +const profile = { + name: 'slither', + displayName: 'Slither', + url: 'ws://127.0.0.1:65523', + methods: ['analyse'], + description: 'Using Remixd daemon, run slither static analysis', + kind: 'other', + version: packageJson.version +} + +export class SlitherHandle extends WebsocketPlugin { + constructor () { + super(profile) + } +} diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js index 82177860d3..4ed0e6c8c9 100644 --- a/apps/remix-ide/src/app/panels/file-panel.js +++ b/apps/remix-ide/src/app/panels/file-panel.js @@ -9,6 +9,7 @@ import { checkSpecialChars, checkSlash } from '../../lib/helper' const { RemixdHandle } = require('../files/remixd-handle.js') const { GitHandle } = require('../files/git-handle.js') const { HardhatHandle } = require('../files/hardhat-handle.js') +const { SlitherHandle } = require('../files/slither-handle.js') const globalRegistry = require('../../global/registry') const examples = require('../editor/examples') const GistHandler = require('../../lib/gist-handler') @@ -34,7 +35,7 @@ const modalDialogCustom = require('../ui/modal-dialog-custom') const profile = { name: 'filePanel', displayName: 'File explorers', - methods: ['createNewFile', 'uploadFile', 'getCurrentWorkspace', 'getWorkspaces', 'createWorkspace', 'setWorkspace'], + methods: ['createNewFile', 'uploadFile', 'getCurrentWorkspace', 'getWorkspaces', 'createWorkspace', 'setWorkspace', 'registerContextMenuItem'], events: ['setWorkspace', 'renameWorkspace', 'deleteWorkspace', 'createWorkspace'], icon: 'assets/img/fileManager.webp', description: ' - ', @@ -59,10 +60,13 @@ module.exports = class Filepanel extends ViewPlugin { this.remixdHandle = new RemixdHandle(this._deps.fileProviders.localhost, appManager) this.gitHandle = new GitHandle() this.hardhatHandle = new HardhatHandle() + this.slitherHandle = new SlitherHandle() this.registeredMenuItems = [] + this.removedMenuItems = [] this.request = {} this.workspaces = [] this.initialWorkspace = null + this.appManager = appManager } render () { @@ -88,6 +92,7 @@ module.exports = class Filepanel extends ViewPlugin { request={this.request} workspaces={this.workspaces} registeredMenuItems={this.registeredMenuItems} + removedMenuItems={this.removedMenuItems} initialWorkspace={this.initialWorkspace} /> , this.el) @@ -101,8 +106,22 @@ module.exports = class Filepanel extends ViewPlugin { if (!item) throw new Error('Invalid register context menu argument') if (!item.name || !item.id) throw new Error('Item name and id is mandatory') if (!item.type && !item.path && !item.extension && !item.pattern) throw new Error('Invalid file matching criteria provided') - + if (this.registeredMenuItems.filter((o) => { + return o.id === item.id && o.name === item.name + }).length) throw new Error(`Action ${item.name} already exists on ${item.id}`) this.registeredMenuItems = [...this.registeredMenuItems, item] + this.removedMenuItems = this.removedMenuItems.filter(menuItem => item.id !== menuItem.id) + this.renderComponent() + } + + removePluginActions (plugin) { + this.registeredMenuItems = this.registeredMenuItems.filter((item) => { + if (item.id !== plugin.name || item.sticky === true) return true + else { + this.removedMenuItems.push(item) + return false + } + }) this.renderComponent() } @@ -148,21 +167,34 @@ module.exports = class Filepanel extends ViewPlugin { } if (loadedFromGist) return - if (params.code) { + if (params.code || params.url) { try { await this.processCreateWorkspace('code-sample') this._deps.fileProviders.workspace.setWorkspace('code-sample') - var hash = bufferToHex(keccakFromString(params.code)) - const fileName = 'contract-' + hash.replace('0x', '').substring(0, 10) + '.sol' - const path = fileName - await this._deps.fileProviders.workspace.set(path, atob(params.code)) + let path = '' + let content = '' + if (params.code) { + var hash = bufferToHex(keccakFromString(params.code)) + path = 'contract-' + hash.replace('0x', '').substring(0, 10) + '.sol' + content = atob(params.code) + await this._deps.fileProviders.workspace.set(path, content) + } + if (params.url) { + const data = await this.call('contentImport', 'resolve', params.url) + path = data.cleanUrl + content = data.content + await this._deps.fileProviders.workspace.set(path, content) + } this.initialWorkspace = 'code-sample' - await this._deps.fileManager.openFile(fileName) + await this._deps.fileManager.openFile(path) } catch (e) { console.error(e) } return } + + const self = this + this.appManager.on('manager', 'pluginDeactivated', self.removePluginActions.bind(this)) // insert example contracts if there are no files to show return new Promise((resolve, reject) => { this._deps.fileProviders.browser.resolveDirectory('/', async (error, filesList) => { diff --git a/apps/remix-ide/src/app/panels/tab-proxy.js b/apps/remix-ide/src/app/panels/tab-proxy.js index 24edfa1da6..dba54aef61 100644 --- a/apps/remix-ide/src/app/panels/tab-proxy.js +++ b/apps/remix-ide/src/app/panels/tab-proxy.js @@ -44,7 +44,6 @@ export class TabProxy extends Plugin { fileManager.events.on('fileRemoved', (name) => { const workspace = this.fileManager.currentWorkspace() - workspace ? this.removeTab(workspace + '/' + name) : this.removeTab(this.fileManager.mode + '/' + name) }) diff --git a/apps/remix-ide/src/app/tabs/analysis-tab.js b/apps/remix-ide/src/app/tabs/analysis-tab.js index b3bba2705c..e9efe9f302 100644 --- a/apps/remix-ide/src/app/tabs/analysis-tab.js +++ b/apps/remix-ide/src/app/tabs/analysis-tab.js @@ -50,9 +50,7 @@ class AnalysisTab extends ViewPlugin { renderComponent () { ReactDOM.render( , diff --git a/apps/remix-ide/src/app/tabs/compile-tab.js b/apps/remix-ide/src/app/tabs/compile-tab.js index cb0773b2b0..6d84a9721f 100644 --- a/apps/remix-ide/src/app/tabs/compile-tab.js +++ b/apps/remix-ide/src/app/tabs/compile-tab.js @@ -1,28 +1,18 @@ /* global */ +import React from 'react' // eslint-disable-line +import ReactDOM from 'react-dom' +import { SolidityCompiler, CompileTab as CompileTabLogic, parseContracts } from '@remix-ui/solidity-compiler' // eslint-disable-line +import { compile } from '@remix-project/remix-solidity' import { ViewPlugin } from '@remixproject/engine-web' import * as packageJson from '../../../../../package.json' -import publishToStorage from '../../publishToStorage' -import { compile } from '../compiler/compiler-helpers' const EventEmitter = require('events') const $ = require('jquery') const yo = require('yo-yo') -const copy = require('copy-text-to-clipboard') var QueryParams = require('../../lib/query-params') -const TreeView = require('../ui/TreeView') -const modalDialog = require('../ui/modaldialog') -const copyToClipboard = require('../ui/copy-to-clipboard') -const modalDialogCustom = require('../ui/modal-dialog-custom') -const parseContracts = require('./compileTab/contractParser') const addTooltip = require('../ui/tooltip') -const Renderer = require('../ui/renderer') const globalRegistry = require('../../global/registry') -var css = require('./styles/compile-tab-styles') - -const CompileTabLogic = require('./compileTab/compileTab.js') -const CompilerContainer = require('./compileTab/compilerContainer.js') - const profile = { name: 'solidity', displayName: 'Solidity compiler', @@ -33,8 +23,7 @@ const profile = { location: 'sidePanel', documentation: 'https://remix-ide.readthedocs.io/en/latest/solidity_editor.html', version: packageJson.version, - methods: ['getCompilationResult', 'compile', 'compileWithParameters', 'setCompilerConfig'] - + methods: ['getCompilationResult', 'compile', 'compileWithParameters', 'setCompilerConfig', 'compileFile'] } // EditorApi: @@ -57,11 +46,9 @@ class CompileTab extends ViewPlugin { // dependencies this.editor = editor this.config = config - this.renderer = new Renderer(this) this.fileManager = fileManager - + this.contractsDetails = {} this.data = { - contractsDetails: {}, eventHandlers: {}, loading: false } @@ -71,30 +58,32 @@ class CompileTab extends ViewPlugin { this.editor, this.config, this.fileProvider, - this.contentImport + this.contentImport, + this.setCompileErrors.bind(this) ) - } - - onActivationInternal () { this.compiler = this.compileTabLogic.compiler this.compileTabLogic.init() - - this.compilerContainer = new CompilerContainer( - this.compileTabLogic, - this.editor, - this.config, - this.queryParams - ) + this.contractMap = {} + this.isHardHatProject = false + this.compileErrors = {} + this.compiledFileName = '' + this.selectedVersion = '' + this.configurationSettings = null + + this.el = document.createElement('div') + this.el.setAttribute('id', 'compileTabView') } resetResults () { - if (this._view.errorContainer) { - this._view.errorContainer.innerHTML = '' - } - this.compilerContainer.currentFile = '' - this.data.contractsDetails = {} - yo.update(this._view.contractSelection, this.contractSelection()) + this.currentFile = '' + this.contractsDetails = {} this.emit('statusChanged', { key: 'none' }) + this.renderComponent() + } + + setCompileErrors (data) { + this.compileErrors = data + this.renderComponent() } /************ @@ -102,13 +91,6 @@ class CompileTab extends ViewPlugin { */ listenToEvents () { - this.on('filePanel', 'setWorkspace', (workspace) => { - this.compileTabLogic.isHardhatProject().then((result) => { - if (result && workspace.isLocalhost) this.compilerContainer.hardhatCompilation.style.display = 'flex' - else this.compilerContainer.hardhatCompilation.style.display = 'none' - }) - }) - this.data.eventHandlers.onContentChanged = () => { this.emit('statusChanged', { key: 'edited', title: 'the content has changed, needs recompilation', type: 'info' }) } @@ -127,9 +109,6 @@ class CompileTab extends ViewPlugin { this.compiler.event.register('compilerLoaded', this.data.eventHandlers.onCompilerLoaded) this.data.eventHandlers.onStartingCompilation = () => { - if (this._view.errorContainer) { - this._view.errorContainer.innerHTML = '' - } this.emit('statusChanged', { key: 'loading', title: 'compiling...', type: 'info' }) } @@ -137,23 +116,32 @@ class CompileTab extends ViewPlugin { this.call('editor', 'clearAnnotations') } - this.on('filePanel', 'setWorkspace', () => this.resetResults()) + this.on('filePanel', 'setWorkspace', (workspace) => { + this.compileTabLogic.isHardhatProject().then((result) => { + if (result && workspace.isLocalhost) this.isHardHatProject = true + else this.isHardHatProject = false + this.renderComponent() + }) + this.resetResults() + }) this.compileTabLogic.event.on('startingCompilation', this.data.eventHandlers.onStartingCompilation) this.compileTabLogic.event.on('removeAnnotations', this.data.eventHandlers.onRemoveAnnotations) this.data.eventHandlers.onCurrentFileChanged = (name) => { - this.compilerContainer.currentFile = name + this.currentFile = name + this.renderComponent() } this.fileManager.events.on('currentFileChanged', this.data.eventHandlers.onCurrentFileChanged) this.data.eventHandlers.onNoFileSelected = () => { - this.compilerContainer.currentFile = '' + this.currentFile = '' + this.renderComponent() } this.fileManager.events.on('noFileSelected', this.data.eventHandlers.onNoFileSelected) this.data.eventHandlers.onCompilationFinished = (success, data, source) => { - this._view.errorContainer.appendChild(yo``) + this.setCompileErrors(data) if (success) { // forwarding the event to the appManager infra this.emit('compilationFinished', source.target, source, 'soljson', data) @@ -165,9 +153,9 @@ class CompileTab extends ViewPlugin { }) } else this.emit('statusChanged', { key: 'succeed', title: 'compilation successful', type: 'success' }) // Store the contracts - this.data.contractsDetails = {} + this.contractsDetails = {} this.compiler.visitContracts((contract) => { - this.data.contractsDetails[contract.name] = parseContracts( + this.contractsDetails[contract.name] = parseContracts( contract.name, contract.object, this.compiler.getSource(contract.file) @@ -178,37 +166,9 @@ class CompileTab extends ViewPlugin { this.emit('statusChanged', { key: count, title: `compilation failed with ${count} error${count.length > 1 ? 's' : ''}`, type: 'error' }) } // Update contract Selection - const contractMap = {} - if (success) this.compiler.visitContracts((contract) => { contractMap[contract.name] = contract }) - const contractSelection = this.contractSelection(contractMap) - yo.update(this._view.contractSelection, contractSelection) - - if (data.error) { - this.renderer.error( - data.error.formattedMessage || data.error, - this._view.errorContainer, - { type: data.error.severity || 'error', errorType: data.error.type } - ) - if (data.error.mode === 'panic') { - return modalDialogCustom.alert(yo` -
- The compiler returned with the following internal error:
${data.error.formattedMessage}.
- 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).

- Please join remix gitter channel for more information.
`) - } - } - if (data.errors && data.errors.length) { - data.errors.forEach((err) => { - if (this.config.get('hideWarnings')) { - if (err.severity !== 'warning') { - this.renderer.error(err.formattedMessage, this._view.errorContainer, { type: err.severity, errorType: err.type }) - } - } else { - this.renderer.error(err.formattedMessage, this._view.errorContainer, { type: err.severity, errorType: err.type }) - } - }) - } + this.contractMap = {} + if (success) this.compiler.visitContracts((contract) => { this.contractMap[contract.name] = contract }) + this.renderComponent() } this.compiler.event.register('compilationFinished', this.data.eventHandlers.onCompilationFinished) @@ -226,11 +186,19 @@ class CompileTab extends ViewPlugin { // ctrl+s or command+s if ((e.metaKey || e.ctrlKey) && e.keyCode === 83) { e.preventDefault() - this.compileTabLogic.runCompiler(this.compilerContainer.hhCompilation) + this.compileTabLogic.runCompiler(this.hhCompilation) } }) } + setHardHatCompilation (value) { + this.hhCompilation = value + } + + setSelectedVersion (version) { + this.selectedVersion = version + } + getCompilationResult () { return this.compileTabLogic.compiler.state.lastCompilationResult } @@ -254,20 +222,15 @@ class CompileTab extends ViewPlugin { * @param {object} settings {evmVersion, optimize, runs, version, language} */ async compileWithParameters (compilationTargets, settings) { - settings.version = settings.version || this.compilerContainer.data.selectedVersion + settings.version = settings.version || this.selectedVersion const res = await compile(compilationTargets, settings) return res } - // This function is used for passing the compiler remix-tests - getCurrentVersion () { - return this.compilerContainer.data.selectedVersion - } - // This function is used for passing the compiler configuration to 'remix-tests' getCurrentCompilerConfig () { return { - currentVersion: this.compilerContainer.data.selectedVersion, + currentVersion: this.selectedVersion, evmVersion: this.compileTabLogic.evmVersion, optimize: this.compileTabLogic.optimize, runs: this.compileTabLogic.runs @@ -280,96 +243,10 @@ class CompileTab extends ViewPlugin { * @param {object} settings {evmVersion, optimize, runs, version, language} */ setCompilerConfig (settings) { - return new Promise((resolve, reject) => { - addTooltip(yo`
${this.currentRequest.from} is updating the Solidity compiler configuration.
${JSON.stringify(settings, null, '\t')}
`) - this.compilerContainer.setConfiguration(settings) - // @todo(#2875) should use loading compiler return value to check whether the compiler is loaded instead of "setInterval" - let timeout = 0 - const id = setInterval(() => { - timeout++ - console.log(this.data.loading) - if (!this.data.loading || timeout > 10) { - resolve() - clearInterval(id) - } - }, 200) - }) - } - - /********* - * SUB-COMPONENTS - */ - - /** - * Section to select the compiled contract - * @param {string[]} contractList Names of the compiled contracts - */ - contractSelection (contractMap) { - // Return the file name of a path: ex "browser/ballot.sol" -> "ballot.sol" - const getFileName = (path) => { - const part = path.split('/') - return part[part.length - 1] - } - const contractList = contractMap ? Object.keys(contractMap).map((key) => ({ - name: key, - file: getFileName(contractMap[key].file) - })) : [] - const selectEl = yo` - - ` - // define swarm logo - - const result = contractList.length - ? yo`
- -
- - ${selectEl} -
-
- - - - -
-
-
- - -
-
-
-
- ` - : yo`
- No Contract Compiled Yet -
` - - if (contractList.length) { - this.selectedContract = selectEl.value - } else { - delete this.selectedContract - } - return result + this.configurationSettings = settings + this.renderComponent() + // @todo(#2875) should use loading compiler return value to check whether the compiler is loaded instead of "setInterval" + addTooltip(yo`
${this.currentRequest.from} is updating the Solidity compiler configuration.
${JSON.stringify(settings, null, '\t')}
`) } // TODO : Add success alert when compilation succeed @@ -390,128 +267,40 @@ class CompileTab extends ViewPlugin { this.selectedContract = contractName } - details () { - const help = { - Assembly: 'Assembly opcodes describing the contract including corresponding solidity source code', - Opcodes: 'Assembly opcodes describing the contract', - 'Runtime Bytecode': 'Bytecode storing the state and being executed during normal contract call', - bytecode: 'Bytecode being executed during contract creation', - functionHashes: 'List of declared function and their corresponding hash', - gasEstimates: 'Gas estimation for each function call', - metadata: 'Contains all informations related to the compilation', - metadataHash: 'Hash representing all metadata information', - abi: 'ABI: describing all the functions (input/output params, scope, ...)', - name: 'Name of the compiled contract', - swarmLocation: 'Swarm url where all metadata information can be found (contract needs to be published first)', - web3Deploy: 'Copy/paste this code to any JavaScript/Web3 console to deploy this contract' - } - if (!this.selectedContract) throw new Error('No contract compiled yet') - const contractProperties = this.data.contractsDetails[this.selectedContract] - const log = yo`
` - Object.keys(contractProperties).map(propertyName => { - const copyDetails = yo`${copyToClipboard(() => contractProperties[propertyName])}` - const questionMark = yo`` - log.appendChild(yo`
-
${propertyName} ${copyDetails} ${questionMark}
- ${this.insertValue(contractProperties, propertyName)} -
`) - }) - modalDialog(this.selectedContract, log, { label: '' }, { label: 'Close' }) - } - - insertValue (details, propertyName) { - var node - if (propertyName === 'web3Deploy' || propertyName === 'name' || propertyName === 'Assembly') { - node = yo`
${details[propertyName]}
` - } else if (propertyName === 'abi' || propertyName === 'metadata') { - const treeView = new TreeView({ - extractData: function (item, parent, key) { - var ret = {} - if (item instanceof Array) { - ret.children = item.map((item, index) => ({ key: index, value: item })) - ret.self = '' - } else if (item instanceof Object) { - ret.children = Object.keys(item).map((key) => ({ key: key, value: item[key] })) - ret.self = '' - } else { - ret.self = item - ret.children = [] - } - return ret - } - }) - if (details[propertyName] !== '') { - try { - node = yo` -
- ${treeView.render(typeof details[propertyName] === 'object' ? details[propertyName] : JSON.parse(details[propertyName]))} -
` // catch in case the parsing fails. - } catch (e) { - node = yo`
Unable to display "${propertyName}": ${e.message}
` - } - } else { - node = yo`
-
` - } - } else { - node = yo`
${JSON.stringify(details[propertyName], null, 4)}
` - } - return yo`
${node || ''}
` - } - - getContractProperty (property) { - if (!this.selectedContract) throw new Error('No contract compiled yet') - const contractProperties = this.data.contractsDetails[this.selectedContract] - return contractProperties[property] || null - } - - copyContractProperty (property) { - let content = this.getContractProperty(property) - if (!content) { - addTooltip('No content available for ' + property) - return - } - - try { - if (typeof content !== 'string') { - content = JSON.stringify(content, null, '\t') - } - } catch (e) {} - - copy(content) - addTooltip('Copied value to clipboard') - } - - copyABI () { - this.copyContractProperty('abi') - } - - copyBytecode () { - this.copyContractProperty('bytecode') + render () { + this.renderComponent() + return this.el } - render () { - if (this._view.el) return this._view.el - this.onActivationInternal() - this._view.errorContainer = yo`
` - this._view.contractSelection = this.contractSelection() - this._view.compilerContainer = this.compilerContainer.render() - this.compilerContainer.activate() - this._view.el = yo` -
- ${this._view.compilerContainer} - ${this._view.contractSelection} - ${this._view.errorContainer} -
` - return this._view.el + renderComponent () { + ReactDOM.render( + + , this.el) } onActivation () { this.call('manager', 'activatePlugin', 'solidity-logic') this.listenToEvents() + this.call('filePanel', 'registerContextMenuItem', { + id: 'solidity', + name: 'compileFile', + label: 'Compile', + type: [], + extension: ['.sol'], + path: [], + pattern: [] + }) + } + + compileFile (event) { + if (event.path.length > 0) { + this.compileTabLogic.compileFile(event.path[0]) + } } onDeactivation () { - this.compilerContainer.deactivate() + this.editor.event.unregister('contentChanged') + this.editor.event.unregister('sessionSwitched') this.editor.event.unregister('contentChanged', this.data.eventHandlers.onContentChanged) this.compiler.event.unregister('loadingCompiler', this.data.eventHandlers.onLoadingCompiler) this.compiler.event.unregister('compilerLoaded', this.data.eventHandlers.onCompilerLoaded) diff --git a/apps/remix-ide/src/app/tabs/compileTab/compilerContainer.js b/apps/remix-ide/src/app/tabs/compileTab/compilerContainer.js deleted file mode 100644 index dfb0cfc5a4..0000000000 --- a/apps/remix-ide/src/app/tabs/compileTab/compilerContainer.js +++ /dev/null @@ -1,578 +0,0 @@ - -import toaster from '../../ui/tooltip' -import { canUseWorker, baseURLBin, baseURLWasm, urlFromVersion, pathToURL, promisedMiniXhr } from '../../compiler/compiler-utils' -const yo = require('yo-yo') -const helper = require('../../../lib/helper') -const addTooltip = require('../../ui/tooltip') -const semver = require('semver') -const modalDialogCustom = require('../../ui/modal-dialog-custom') -const css = require('../styles/compile-tab-styles') - -class CompilerContainer { - constructor (compileTabLogic, editor, config, queryParams) { - this._view = {} - this.compileTabLogic = compileTabLogic - this.editor = editor - this.config = config - this.queryParams = queryParams - this.hhCompilation = false - - this.data = { - hideWarnings: config.get('hideWarnings') || false, - autoCompile: config.get('autoCompile'), - compileTimeout: null, - timeout: 300, - allversions: null, - selectedVersion: null, - defaultVersion: 'soljson-v0.8.4+commit.c7e474f2.js' // this default version is defined: in makeMockCompiler (for browser test) - } - } - - /** - * Update the compilation button with the name of the current file - */ - set currentFile (name = '') { - if (name && name !== '') { - this._setCompilerVersionFromPragma(name) - } - if (!this._view.compilationButton) return - const button = this.compilationButton(name.split('/').pop()) - this._disableCompileBtn(!name || (name && !this.isSolFileSelected(name))) - yo.update(this._view.compilationButton, button) - } - - isSolFileSelected (currentFile = '') { - if (!currentFile) currentFile = this.config.get('currentFile') - if (!currentFile) return false - const extention = currentFile.substr(currentFile.length - 3, currentFile.length) - return extention.toLowerCase() === 'sol' || extention.toLowerCase() === 'yul' - } - - deactivate () { - // deactivate editor listeners - this.editor.event.unregister('contentChanged') - this.editor.event.unregister('sessionSwitched') - } - - activate () { - this.currentFile = this.config.get('currentFile') - this.listenToEvents() - } - - listenToEvents () { - this.editor.event.register('sessionSwitched', () => { - if (!this._view.compileIcon) return - this.scheduleCompilation() - }) - - this.compileTabLogic.event.on('startingCompilation', () => { - if (!this._view.compileIcon) return - this._view.compileIcon.setAttribute('title', 'compiling...') - this._view.compileIcon.classList.remove(`${css.bouncingIcon}`) - this._view.compileIcon.classList.add(`${css.spinningIcon}`) - }) - - this.compileTabLogic.compiler.event.register('compilationDuration', (speed) => { - if (!this._view.warnCompilationSlow) return - if (speed > 1000) { - const msg = `Last compilation took ${speed}ms. We suggest to turn off autocompilation.` - this._view.warnCompilationSlow.setAttribute('title', msg) - this._view.warnCompilationSlow.style.visibility = 'visible' - } else { - this._view.warnCompilationSlow.style.visibility = 'hidden' - } - }) - - this.editor.event.register('contentChanged', () => { - if (!this._view.compileIcon) return - this.scheduleCompilation() - this._view.compileIcon.classList.add(`${css.bouncingIcon}`) // @TODO: compileView tab - }) - - this.compileTabLogic.compiler.event.register('loadingCompiler', () => { - if (!this._view.compileIcon) return - this._disableCompileBtn(true) - this._view.compileIcon.setAttribute('title', 'compiler is loading, please wait a few moments.') - this._view.compileIcon.classList.add(`${css.spinningIcon}`) - this._view.warnCompilationSlow.style.visibility = 'hidden' - this._updateLanguageSelector() - }) - - this.compileTabLogic.compiler.event.register('compilerLoaded', () => { - if (!this._view.compileIcon) return - this._disableCompileBtn(false) - this._view.compileIcon.setAttribute('title', '') - this._view.compileIcon.classList.remove(`${css.spinningIcon}`) - if (this.data.autoCompile) this.compileIfAutoCompileOn() - }) - - this.compileTabLogic.compiler.event.register('compilationFinished', (success, data, source) => { - if (!this._view.compileIcon) return - this._view.compileIcon.setAttribute('title', 'idle') - this._view.compileIcon.classList.remove(`${css.spinningIcon}`) - this._view.compileIcon.classList.remove(`${css.bouncingIcon}`) - }) - } - - /************** - * SUBCOMPONENT - */ - compilationButton (name = '') { - const displayed = name || '' - const disabled = name && this.isSolFileSelected() ? '' : 'disabled' - return yo` - - ` - } - - _disableCompileBtn (shouldDisable) { - const btn = document.getElementById('compileBtn') - if (!btn) return - if (shouldDisable) { - btn.classList.add('disabled') - } else if (this.isSolFileSelected()) { - btn.classList.remove('disabled') - } - } - - // Load solc compiler version according to pragma in contract file - _setCompilerVersionFromPragma (filename) { - if (!this.data.allversions) return - this.compileTabLogic.fileManager.readFile(filename).then(data => { - const pragmaArr = data.match(/(pragma solidity (.+?);)/g) - if (pragmaArr && pragmaArr.length === 1) { - const pragmaStr = pragmaArr[0].replace('pragma solidity', '').trim() - const pragma = pragmaStr.substring(0, pragmaStr.length - 1) - const releasedVersions = this.data.allversions.filter(obj => !obj.prerelease).map(obj => obj.version) - const allVersions = this.data.allversions.map(obj => this._retrieveVersion(obj.version)) - const currentCompilerName = this._retrieveVersion(this._view.versionSelector.selectedOptions[0].label) - // contains only numbers part, for example '0.4.22' - const pureVersion = this._retrieveVersion() - // is nightly build newer than the last release - const isNewestNightly = currentCompilerName.includes('nightly') && semver.gt(pureVersion, releasedVersions[0]) - // checking if the selected version is in the pragma range - const isInRange = semver.satisfies(pureVersion, pragma) - // checking if the selected version is from official compilers list(excluding custom versions) and in range or greater - const isOfficial = allVersions.includes(currentCompilerName) - if (isOfficial && (!isInRange && !isNewestNightly)) { - const compilerToLoad = semver.maxSatisfying(releasedVersions, pragma) - const compilerPath = this.data.allversions.filter(obj => !obj.prerelease && obj.version === compilerToLoad)[0].path - if (this.data.selectedVersion !== compilerPath) { - this.data.selectedVersion = compilerPath - this._updateVersionSelector() - } - } - } - }) - } - - _retrieveVersion (version) { - if (!version) version = this._view.versionSelector.value - if (version === 'builtin') version = this.data.defaultVersion - return semver.coerce(version) ? semver.coerce(version).version : '' - } - - render () { - this.compileTabLogic.compiler.event.register('compilerLoaded', (version) => this.setVersionText(version)) - this.fetchAllVersion((allversions, selectedVersion, isURL) => { - this.data.allversions = allversions - if (isURL) this._updateVersionSelector(selectedVersion) - else { - this.data.selectedVersion = selectedVersion - if (this._view.versionSelector) this._updateVersionSelector() - } - }) - - this.hardhatCompilation = yo`` - this._view.warnCompilationSlow = yo`` - this._view.compileIcon = yo`` - this._view.autoCompile = yo` this.updateAutoCompile()} data-id="compilerContainerAutoCompile" id="autoCompile" type="checkbox" title="Auto compile">` - this._view.hideWarningsBox = yo` this.hideWarnings()} id="hideWarningsBox" type="checkbox" title="Hide warnings">` - if (this.data.autoCompile) this._view.autoCompile.setAttribute('checked', '') - if (this.data.hideWarnings) this._view.hideWarningsBox.setAttribute('checked', '') - - this._view.optimize = yo` this.onchangeOptimize()} class="custom-control-input" id="optimize" type="checkbox">` - if (this.compileTabLogic.optimize) this._view.optimize.setAttribute('checked', '') - - this._view.runs = yo` this.onchangeRuns()} - >` - if (this.compileTabLogic.optimize) { - this._view.runs.removeAttribute('disabled') - this._view.runs.value = this.compileTabLogic.runs - } else { - this._view.runs.setAttribute('disabled', '') - } - - this._view.versionSelector = yo` - ` - this._view.languageSelector = yo` - ` - this._view.version = yo`` - - this._view.evmVersionSelector = yo` - ` - if (this.compileTabLogic.evmVersion) { - const s = this._view.evmVersionSelector - let i - for (i = 0; i < s.options.length; i++) { - if (s.options[i].value === this.compileTabLogic.evmVersion) { - break - } - } - if (i === s.options.length) { // invalid evmVersion from queryParams - s.selectedIndex = 0 // compiler default - this.onchangeEvmVersion() - } else { - s.selectedIndex = i - this.onchangeEvmVersion() - } - } - - this._view.compilationButton = this.compilationButton() - - this._view.includeNightlies = yo` - this._updateVersionSelector()}> - ` - this._view.compileContainer = yo` -
- -
-
-
- - ${this._view.versionSelector} -
-
- ${this._view.includeNightlies} - -
-
- - ${this._view.languageSelector} -
-
- - ${this._view.evmVersionSelector} -
-
-

Compiler Configuration

-
- ${this._view.autoCompile} - -
-
-
- ${this._view.optimize} - - ${this._view.runs} -
-
-
- ${this._view.hideWarningsBox} - -
-
- ${this.hardhatCompilation} - ${this._view.compilationButton} -
-
- -
` - - return this._view.compileContainer - } - - promtCompiler () { - modalDialogCustom.prompt( - 'Add a custom compiler', - 'URL', - '', - (url) => this.addCustomCompiler(url) - ) - } - - addCustomCompiler (url) { - this.data.selectedVersion = this._view.versionSelector.value - this._updateVersionSelector(url) - } - - updateAutoCompile (event) { - this.config.set('autoCompile', this._view.autoCompile.checked) - } - - updatehhCompilation (event) { - this.hhCompilation = event.target.checked - } - - compile (event) { - const currentFile = this.config.get('currentFile') - if (!this.isSolFileSelected()) return - - this._setCompilerVersionFromPragma(currentFile) - this.compileTabLogic.runCompiler(this.hhCompilation) - } - - compileIfAutoCompileOn () { - if (this.config.get('autoCompile')) { - this.compile() - } - } - - hideWarnings (event) { - this.config.set('hideWarnings', this._view.hideWarningsBox.checked) - this.compileIfAutoCompileOn() - } - - /* - The following functions are handlers for internal events. - */ - - onchangeOptimize () { - this.compileTabLogic.setOptimize(!!this._view.optimize.checked) - if (this.compileTabLogic.optimize) { - this._view.runs.removeAttribute('disabled') - this.compileTabLogic.setRuns(parseInt(this._view.runs.value)) - } else { - this.compileTabLogic.setRuns(200) - this._view.runs.setAttribute('disabled', '') - } - this.compileIfAutoCompileOn() - } - - onchangeRuns () { - this.compileTabLogic.setRuns(parseInt(this._view.runs.value)) - this.compileIfAutoCompileOn() - } - - onchangeLanguage () { - this.compileTabLogic.setLanguage(this._view.languageSelector.value) - this.compileIfAutoCompileOn() - } - - onchangeEvmVersion () { - const s = this._view.evmVersionSelector - let v = s.value - if (v === 'default') { - v = null - } - this.compileTabLogic.setEvmVersion(v) - for (let i = 0; i < s.options.length; i++) { - if (i === s.selectedIndex) { - s.options[s.selectedIndex].setAttribute('selected', 'selected') - } else { - s.options[i].removeAttribute('selected') - } - } - - this.compileIfAutoCompileOn() - } - - onchangeLoadVersion () { - this.data.selectedVersion = this._view.versionSelector.value - this._updateVersionSelector() - this._updateLanguageSelector() - } - - /* - The following functions map with the above event handlers. - They are an external API for modifying the compiler configuration. - */ - setConfiguration (settings) { - this.setLanguage(settings.language) - this.setEvmVersion(settings.evmVersion) - this.setOptimize(settings.optimize) - this.setRuns(settings.runs) - this.setVersion(settings.version) - } - - setOptimize (enabled) { - this._view.optimize.checked = enabled - this.onchangeOptimize() - } - - setRuns (value) { - if (value) { - this._view.runs.value = value - this.onchangeRuns() - } - } - - setLanguage (lang) { - this._view.languageSelector.value = lang - this.onchangeLanguage() - } - - setEvmVersion (version) { - this._view.evmVersionSelector.value = version || 'default' - this.onchangeEvmVersion() - } - - setVersion (version) { - this._view.versionSelector.value = `soljson-v${version}.js` - this.onchangeLoadVersion() - } - - _shouldBeAdded (version) { - return !version.includes('nightly') || - (version.includes('nightly') && this._view.includeNightlies.checked) - } - - _updateVersionSelector (customUrl = '') { - // update selectedversion if previous one got filtered out - if (!this.data.selectedVersion || !this._shouldBeAdded(this.data.selectedVersion)) { - this.data.selectedVersion = this.data.defaultVersion - } - this._view.versionSelector.innerHTML = '' - this._view.versionSelector.removeAttribute('disabled') - this.queryParams.update({ version: this.data.selectedVersion }) - let url - if (customUrl !== '') { - this.data.selectedVersion = customUrl - this._view.versionSelector.appendChild(yo``) - url = customUrl - this.queryParams.update({ version: this.data.selectedVersion }) - } else if (this.data.selectedVersion === 'builtin') { - let location = window.document.location - let path = location.pathname - if (!path.startsWith('/')) path = '/' + path - location = `${location.protocol}//${location.host}${path}assets/js` - if (location.endsWith('index.html')) location = location.substring(0, location.length - 10) - if (!location.endsWith('/')) location += '/' - url = location + 'soljson.js' - } else { - if (this.data.selectedVersion.indexOf('soljson') !== 0 || helper.checkSpecialChars(this.data.selectedVersion)) { - return console.log('loading ' + this.data.selectedVersion + ' not allowed') - } - url = `${urlFromVersion(this.data.selectedVersion)}` - } - - this.data.allversions.forEach(build => { - const option = build.path === this.data.selectedVersion - ? yo`` - : yo`` - - if (this._shouldBeAdded(option.innerText)) { - this._view.versionSelector.appendChild(option) - } - }) - if (this.data.selectedVersion !== 'builtin' && semver.lt(this._retrieveVersion(), 'v0.4.12+commit.194ff033.js')) { - toaster(yo` -
- Old compiler usage detected. -

You are using a compiler older than v0.4.12.

-

Some functionality may not work.

-
` - ) - } - - // Workers cannot load js on "file:"-URLs and we get a - // "Uncaught RangeError: Maximum call stack size exceeded" error on Chromium, - // resort to non-worker version in that case. - if (canUseWorker(this._retrieveVersion())) { - this.compileTabLogic.compiler.loadVersion(true, url) - this.setVersionText('(loading using worker)') - } else { - this.compileTabLogic.compiler.loadVersion(false, url) - this.setVersionText('(loading)') - } - } - - _updateLanguageSelector () { - // This is the first version when Yul is available - if (!semver.valid(this._retrieveVersion()) || semver.lt(this._retrieveVersion(), 'v0.5.7+commit.6da8b019.js')) { - this._view.languageSelector.setAttribute('disabled', '') - this._view.languageSelector.value = 'Solidity' - this.compileTabLogic.setLanguage('Solidity') - } else { - this._view.languageSelector.removeAttribute('disabled') - } - } - - setVersionText (text) { - if (this._view.version) this._view.version.innerText = text - } - - // fetching both normal and wasm builds and creating a [version, baseUrl] map - async fetchAllVersion (callback) { - let selectedVersion, allVersionsWasm, isURL - let allVersions = [{ path: 'builtin', longVersion: 'Stable local version - 0.8.4' }] - // fetch normal builds - const binRes = await promisedMiniXhr(`${baseURLBin}/list.json`) - // fetch wasm builds - const wasmRes = await promisedMiniXhr(`${baseURLWasm}/list.json`) - if (binRes.event.type === 'error' && wasmRes.event.type === 'error') { - selectedVersion = 'builtin' - return callback(allVersions, selectedVersion) - } - try { - const versions = JSON.parse(binRes.json).builds.slice().reverse() - allVersions = [...allVersions, ...versions] - selectedVersion = this.data.defaultVersion - if (this.queryParams.get().version) selectedVersion = this.queryParams.get().version - // Check if version is a URL and corresponding filename starts with 'soljson' - if (selectedVersion.startsWith('https://')) { - const urlArr = selectedVersion.split('/') - if (urlArr[urlArr.length - 1].startsWith('soljson')) isURL = true - } - if (wasmRes.event.type !== 'error') { - allVersionsWasm = JSON.parse(wasmRes.json).builds.slice().reverse() - } - } catch (e) { - addTooltip('Cannot load compiler version list. It might have been blocked by an advertisement blocker. Please try deactivating any of them from this page and reload. Error: ' + e) - } - // replace in allVersions those compiler builds which exist in allVersionsWasm with new once - if (allVersionsWasm && allVersions) { - allVersions.forEach((compiler, index) => { - const wasmIndex = allVersionsWasm.findIndex(wasmCompiler => { return wasmCompiler.longVersion === compiler.longVersion }) - if (wasmIndex !== -1) { - allVersions[index] = allVersionsWasm[wasmIndex] - pathToURL[compiler.path] = baseURLWasm - } else { - pathToURL[compiler.path] = baseURLBin - } - }) - } - callback(allVersions, selectedVersion, isURL) - } - - scheduleCompilation () { - if (!this.config.get('autoCompile')) return - if (this.data.compileTimeout) window.clearTimeout(this.data.compileTimeout) - this.data.compileTimeout = window.setTimeout(() => this.compileIfAutoCompileOn(), this.data.timeout) - } -} - -module.exports = CompilerContainer diff --git a/apps/remix-ide/src/app/tabs/hardhat-provider.js b/apps/remix-ide/src/app/tabs/hardhat-provider.js index 805bc37e08..75c20a90cd 100644 --- a/apps/remix-ide/src/app/tabs/hardhat-provider.js +++ b/apps/remix-ide/src/app/tabs/hardhat-provider.js @@ -65,7 +65,7 @@ export default class HardhatProvider extends Plugin { if (error) { this.blocked = true modalDialogCustom.alert('Hardhat Provider', `Error while connecting to the hardhat provider: ${error.message}`) - await this.call('udapp', 'setEnvironmentMode', 'vm') + await this.call('udapp', 'setEnvironmentMode', { context: 'vm', fork: 'london' }) this.provider = null setTimeout(_ => { this.blocked = false }, 1000) // we wait 1 second for letting remix to switch to vm return reject(error) diff --git a/apps/remix-ide/src/app/tabs/runTab/contractDropdown.js b/apps/remix-ide/src/app/tabs/runTab/contractDropdown.js index 0d3da9f1a2..8328e04bcb 100644 --- a/apps/remix-ide/src/app/tabs/runTab/contractDropdown.js +++ b/apps/remix-ide/src/app/tabs/runTab/contractDropdown.js @@ -361,7 +361,7 @@ class ContractDropdownUI { return continueTxExecution(null) } const amount = this.blockchain.fromWei(tx.value, true, 'ether') - const content = confirmDialog(tx, amount, gasEstimation, null, this.blockchain.determineGasFees(tx), this.blockchain.determineGasPrice.bind(this.blockchain)) + const content = confirmDialog(tx, network, amount, gasEstimation, this.blockchain.determineGasFees(tx), this.blockchain.determineGasPrice.bind(this.blockchain)) modalDialog('Confirm transaction', content, { @@ -370,10 +370,9 @@ class ContractDropdownUI { this.blockchain.config.setUnpersistedProperty('doNotShowTransactionConfirmationAgain', content.querySelector('input#confirmsetting').checked) // TODO: check if this is check is still valid given the refactor if (!content.gasPriceStatus) { - cancelCb('Given gas price is not correct') + cancelCb('Given transaction fee is not correct') } else { - var gasPrice = this.blockchain.toWei(content.querySelector('#gasprice').value, 'gwei') - continueTxExecution(gasPrice) + continueTxExecution(content.txFee) } } }, { diff --git a/apps/remix-ide/src/app/tabs/runTab/model/dropdownlogic.js b/apps/remix-ide/src/app/tabs/runTab/model/dropdownlogic.js index 2ee225fef3..386f654775 100644 --- a/apps/remix-ide/src/app/tabs/runTab/model/dropdownlogic.js +++ b/apps/remix-ide/src/app/tabs/runTab/model/dropdownlogic.js @@ -1,6 +1,6 @@ +import { CompilerAbstract } from '@remix-project/remix-solidity' const remixLib = require('@remix-project/remix-lib') const txHelper = remixLib.execution.txHelper -const CompilerAbstract = require('../../../compiler/compiler-abstract') const EventManager = remixLib.EventManager const _paq = window._paq = window._paq || [] diff --git a/apps/remix-ide/src/app/tabs/runTab/recorder.js b/apps/remix-ide/src/app/tabs/runTab/recorder.js index 47f6ff440b..52d5367464 100644 --- a/apps/remix-ide/src/app/tabs/runTab/recorder.js +++ b/apps/remix-ide/src/app/tabs/runTab/recorder.js @@ -104,7 +104,7 @@ class RecorderUI extends Plugin { return continueTxExecution(null) } const amount = this.blockchain.fromWei(tx.value, true, 'ether') - const content = confirmDialog(tx, amount, gasEstimation, null, this.blockchain.determineGasFees(tx), this.blockchain.determineGasPrice.bind(this.blockchain)) + const content = confirmDialog(tx, network, amount, gasEstimation, this.blockchain.determineGasFees(tx), this.blockchain.determineGasPrice.bind(this.blockchain)) modalDialog('Confirm transaction', content, { @@ -113,10 +113,9 @@ class RecorderUI extends Plugin { this.config.setUnpersistedProperty('doNotShowTransactionConfirmationAgain', content.querySelector('input#confirmsetting').checked) // TODO: check if this is check is still valid given the refactor if (!content.gasPriceStatus) { - cancelCb('Given gas price is not correct') + cancelCb('Given transaction fee is not correct') } else { - var gasPrice = this.blockchain.toWei(content.querySelector('#gasprice').value, 'gwei') - continueTxExecution(gasPrice) + continueTxExecution(content.txFee) } } }, { diff --git a/apps/remix-ide/src/app/tabs/runTab/settings.js b/apps/remix-ide/src/app/tabs/runTab/settings.js index f99a2bc461..d71ca500f7 100644 --- a/apps/remix-ide/src/app/tabs/runTab/settings.js +++ b/apps/remix-ide/src/app/tabs/runTab/settings.js @@ -98,14 +98,14 @@ class SettingsUI {
+ Gwei +
+
+
+
+ Max fee (Not less than base fee ${Web3.utils.fromWei(Web3.utils.toBN(parseInt(network.lastBlock.baseFeePerGas, 16)), 'Gwei')} Gwei): + + Gwei + +
+
` + : yo`
+ Gas price: + + Gwei (visit ethgasstation.info for current gas price info.) +
` + } +
Max transaction fee: - -
-
- Gas price: - - Gwei (visit ethgasstation.info for current gas price info.) -
-
- Data: -
${tx.data && tx.data.length > 50 ? tx.data.substring(0, 49) + '...' : tx.data} ${copyToClipboard(() => { return tx.data })}
+
@@ -74,10 +120,14 @@ function confirmDialog (tx, amount, gasEstimation, self, newGasPriceCb, initialP if (txFeeText) { el.querySelector('#txfee').innerHTML = txFeeText } - if (gasPriceValue) { + if (el.querySelector('#gasprice') && gasPriceValue) { el.querySelector('#gasprice').value = gasPriceValue onGasPriceChange() } + if (el.querySelector('#maxfee') && network && network.lastBlock && network.lastBlock.baseFeePerGas) { + el.querySelector('#maxfee').value = Web3.utils.fromWei(Web3.utils.toBN(parseInt(network.lastBlock.baseFeePerGas, 16)), 'Gwei') + onMaxFeeChange() + } if (gasPriceStatus !== undefined) { el.gasPriceStatus = gasPriceStatus } diff --git a/apps/remix-ide/src/app/ui/copy-to-clipboard.js b/apps/remix-ide/src/app/ui/copy-to-clipboard.js index 9974cc5782..26c96b0d2f 100644 --- a/apps/remix-ide/src/app/ui/copy-to-clipboard.js +++ b/apps/remix-ide/src/app/ui/copy-to-clipboard.js @@ -1,6 +1,6 @@ var yo = require('yo-yo') // -------------- copyToClipboard ---------------------- -const copy = require('copy-text-to-clipboard') +const copy = require('copy-to-clipboard') var addTooltip = require('./tooltip') // -------------- styling ---------------------- var csjs = require('csjs-inject') 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 1fa8b0dba2..60d762472f 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 @@ -6,7 +6,6 @@ import JSZip from 'jszip' const yo = require('yo-yo') const csjs = require('csjs-inject') const globalRegistry = require('../../../global/registry') -const CompilerImport = require('../../compiler/compiler-imports') const modalDialogCustom = require('../modal-dialog-custom') const modalDialog = require('../modaldialog') const tooltip = require('../tooltip') @@ -119,11 +118,12 @@ const profile = { } export class LandingPage extends ViewPlugin { - constructor (appManager, verticalIcons, fileManager, filePanel) { + constructor (appManager, verticalIcons, fileManager, filePanel, contentImport) { super(profile) this.profile = profile this.fileManager = fileManager this.filePanel = filePanel + this.contentImport = contentImport this.appManager = appManager this.verticalIcons = verticalIcons this.gistHandler = new GistHandler() @@ -216,7 +216,7 @@ export class LandingPage extends ViewPlugin { const invertNum = (themeQuality === 'dark') ? 1 : 0 if (this.solEnv.getElementsByTagName('img')[0]) this.solEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})` - if (this.debuggerEnv.getElementsByTagName('img')[0]) this.debuggerEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})` + if (this.optimismEnv.getElementsByTagName('img')[0]) this.optimismEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})` if (this.solhintEnv.getElementsByTagName('img')[0]) this.solhintEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})` if (this.learnEthEnv.getElementsByTagName('img')[0]) this.learnEthEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})` if (this.sourcifyEnv.getElementsByTagName('img')[0]) this.sourcifyEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})` @@ -240,7 +240,7 @@ export class LandingPage extends ViewPlugin { render () { const load = (service, item, examples, info) => { - const compilerImport = new CompilerImport() + const contentImport = this.contentImport const fileProviders = globalRegistry.get('fileproviders').api const msg = yo`
@@ -252,7 +252,7 @@ export class LandingPage extends ViewPlugin { const title = `Import from ${service}` modalDialogCustom.prompt(title, msg, null, (target) => { if (target !== '') { - compilerImport.import( + contentImport.import( target, (loadingMsg) => { tooltip(loadingMsg) }, (error, content, cleanUrl, type, url) => { @@ -277,10 +277,10 @@ export class LandingPage extends ViewPlugin { this.verticalIcons.select('solidity') _paq.push(['trackEvent', 'pluginManager', 'userActivate', 'solidity']) } - const startDebugger = async () => { - await this.appManager.activatePlugin('debugger') - this.verticalIcons.select('debugger') - _paq.push(['trackEvent', 'pluginManager', 'userActivate', 'debugger']) + const startOptimism = async () => { + await this.appManager.activatePlugin('optimism-compiler') + this.verticalIcons.select('optimism-compiler') + _paq.push(['trackEvent', 'pluginManager', 'userActivate', 'optimism-compiler']) } const startSolhint = async () => { await this.appManager.activatePlugin(['solidity', 'solhint']) @@ -385,8 +385,8 @@ export class LandingPage extends ViewPlugin { // main this.solEnv = createLargeButton('assets/img/solidityLogo.webp', 'solidityLogo', 'Solidity', startSolidity) // Featured - this.debuggerEnv = createLargeButton('assets/img/debuggerLogo.webp', 'debuggerLogo', 'Debugger', startDebugger) - this.solhintEnv = createLargeButton('assets/img/solhintLogo.png', 'solhintLogo', 'solhint linter', startSolhint) + this.optimismEnv = createLargeButton('assets/img/optimismLogo.webp', 'optimismLogo', 'Optimism', startOptimism) + this.solhintEnv = createLargeButton('assets/img/solhintLogo.png', 'solhintLogo', 'Solhint linter', startSolhint) this.learnEthEnv = createLargeButton('assets/img/learnEthLogo.webp', 'learnEthLogo', 'LearnEth', startLearnEth) this.sourcifyEnv = createLargeButton('assets/img/sourcifyLogo.webp', 'sourcifyLogo', 'Sourcify', startSourceVerify) this.moreEnv = createLargeButton('assets/img/moreLogo.webp', 'moreLogo', 'More', startPluginManager) @@ -395,7 +395,7 @@ export class LandingPage extends ViewPlugin { const themeQuality = globalRegistry.get('themeModule').api.currentTheme().quality const invertNum = (themeQuality === 'dark') ? 1 : 0 this.solEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})` - this.debuggerEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})` + this.optimismEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})` this.solhintEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})` this.learnEthEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})` this.sourcifyEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})` @@ -505,10 +505,10 @@ export class LandingPage extends ViewPlugin {

Featured Plugins

${this.solEnv} + ${this.optimismEnv} ${this.learnEthEnv} ${this.solhintEnv} - ${this.sourcifyEnv} - ${this.debuggerEnv} + ${this.sourcifyEnv} ${this.moreEnv}
diff --git a/apps/remix-ide/src/app/ui/sendTxCallbacks.js b/apps/remix-ide/src/app/ui/sendTxCallbacks.js index f2785482b2..3f5c7c7506 100644 --- a/apps/remix-ide/src/app/ui/sendTxCallbacks.js +++ b/apps/remix-ide/src/app/ui/sendTxCallbacks.js @@ -51,7 +51,7 @@ const confirmationCb = function (network, tx, gasEstimation, continueTxExecution return continueTxExecution(null) } var amount = Web3.utils.fromWei(typeConversion.toInt(tx.value), 'ether') - var content = confirmDialog(tx, amount, gasEstimation, self.udappUI, + var content = confirmDialog(tx, network, amount, gasEstimation, (gasPrice, cb) => { let txFeeText, priceStatus // TODO: this try catch feels like an anti pattern, can/should be @@ -93,10 +93,9 @@ const confirmationCb = function (network, tx, gasEstimation, continueTxExecution ) // TODO: check if this is check is still valid given the refactor if (!content.gasPriceStatus) { - cancelCb('Given gas price is not correct') + cancelCb('Given transaction fee is not correct') } else { - var gasPrice = Web3.utils.toWei(content.querySelector('#gasprice').value, 'gwei') - continueTxExecution(gasPrice) + continueTxExecution(content.txFee) } } }, diff --git a/apps/remix-ide/src/assets/img/optimismLogo.webp b/apps/remix-ide/src/assets/img/optimismLogo.webp new file mode 100644 index 0000000000..d7569da3f1 Binary files /dev/null and b/apps/remix-ide/src/assets/img/optimismLogo.webp differ diff --git a/apps/remix-ide/src/assets/js/editor/darkTheme.js b/apps/remix-ide/src/assets/js/editor/darkTheme.js index ace91156ed..f4059f60f7 100644 --- a/apps/remix-ide/src/assets/js/editor/darkTheme.js +++ b/apps/remix-ide/src/assets/js/editor/darkTheme.js @@ -30,7 +30,7 @@ ace.define("ace/theme/remixDark",["require","exports","module","ace/lib/dom"], f }\ .ace-remixDark {\ background-color: #222336;\ - color: #a2a3bd;\ + color: #d5d5e9;\ }\ .ace-remixDark .ace_cursor {\ border-left: 2px solid #FFFFFF;\ @@ -109,10 +109,10 @@ ace.define("ace/theme/remixDark",["require","exports","module","ace/lib/dom"], f }\ .ace-remixDark .ace_type {\ color:#75ceef;\ - }]\ - .ace-remixDark .ace_visibility (\ + }\ + .ace-remixDark .ace_visibility {\ color:#f7d777;\ - )\ + }\ .ace-remixDark .ace_identifier {\ color:#bec1dd;\ }\ diff --git a/apps/remix-ide/src/assets/js/intro.min.js b/apps/remix-ide/src/assets/js/intro.min.js new file mode 100644 index 0000000000..b3c2bfa36f --- /dev/null +++ b/apps/remix-ide/src/assets/js/intro.min.js @@ -0,0 +1,10 @@ +/*! + * Intro.js v4.1.0 + * https://introjs.com + * + * Copyright (C) 2012-2021 Afshin Mehrabani (@afshinmeh). + * https://raw.githubusercontent.com/usablica/intro.js/master/license.md + * + * Date: Fri, 18 Jun 2021 10:48:16 GMT + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).introJs=e()}(this,(function(){"use strict";function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}var e=function(){var t={};return function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"introjs-stamp";return t[n]=t[n]||0,void 0===e[n]&&(e[n]=t[n]++),e[n]}}();function n(t,e,n){if(t)for(var i=0,o=t.length;i0?ht:ut)(t)},pt=Math.min,dt=function(t){return t>0?pt(ft(t),9007199254740991):0},gt=Math.max,vt=Math.min,mt=function(t,e){var n=ft(t);return n<0?gt(n+e,0):vt(n,e)},bt=function(t){return function(e,n,i){var o,r=y(e),l=dt(r.length),a=mt(i,l);if(t&&n!=n){for(;l>a;)if((o=r[a++])!=o)return!0}else for(;l>a;a++)if((t||a in r)&&r[a]===n)return t||a||0;return!t&&-1}},yt={includes:bt(!0),indexOf:bt(!1)},wt=yt.indexOf,_t=function(t,e){var n,i=y(t),o=0,r=[];for(n in i)!j(J,n)&&j(i,n)&&r.push(n);for(;e.length>o;)j(i,n=e[o++])&&(~wt(r,n)||r.push(n));return r},St=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],xt=St.concat("length","prototype"),jt={f:Object.getOwnPropertyNames||function(t){return _t(t,xt)}},Ct={f:Object.getOwnPropertySymbols},Et=ct("Reflect","ownKeys")||function(t){var e=jt.f(I(t)),n=Ct.f;return n?e.concat(n(t)):e},At=function(t,e){for(var n=Et(e),i=O.f,o=N.f,r=0;r0&&(!r.multiline||r.multiline&&"\n"!==t[r.lastIndex-1])&&(s="(?: "+s+")",u=" "+u,c++),n=new RegExp("^(?:"+s+")",a)),Vt&&(n=new RegExp("^"+s+"$(?!\\s)",a)),Wt&&(e=r.lastIndex),i=Ut.call(l?n:r,u),l?i?(i.input=i.input.slice(c),i[0]=i[0].slice(c),i.index=r.lastIndex,r.lastIndex+=i[0].length):r.lastIndex=0:Wt&&i&&(r.lastIndex=r.global?i.index+i[0].length:e),Vt&&i&&i.length>1&&Ft.call(i[0],n,(function(){for(o=1;o=74)&&(Yt=Jt.match(/Chrome\/(\d+)/))&&(Xt=Yt[1]);var ee=Xt&&+Xt,ne=!!Object.getOwnPropertySymbols&&!s((function(){var t=Symbol();return!String(t)||!(Object(t)instanceof Symbol)||!Symbol.sham&&ee&&ee<41})),ie=ne&&!Symbol.sham&&"symbol"==typeof Symbol.iterator,oe=W("wks"),re=a.Symbol,le=ie?re:re&&re.withoutSetter||K,ae=function(t){return j(oe,t)&&(ne||"string"==typeof oe[t])||(ne&&j(re,t)?oe[t]=re[t]:oe[t]=le("Symbol."+t)),oe[t]},se=ae("species"),ce=RegExp.prototype,ue=!s((function(){var t=/./;return t.exec=function(){var t=[];return t.groups={a:"7"},t},"7"!=="".replace(t,"$")})),he="$0"==="a".replace(/./,"$0"),fe=ae("replace"),pe=!!/./[fe]&&""===/./[fe]("a","$0"),de=!s((function(){var t=/(?:)/,e=t.exec;t.exec=function(){return e.apply(this,arguments)};var n="ab".split(t);return 2!==n.length||"a"!==n[0]||"b"!==n[1]})),ge=function(t,e,n,i){var o=ae(t),r=!s((function(){var e={};return e[o]=function(){return 7},7!=""[t](e)})),l=r&&!s((function(){var e=!1,n=/a/;return"split"===t&&((n={}).constructor={},n.constructor[se]=function(){return n},n.flags="",n[o]=/./[o]),n.exec=function(){return e=!0,null},n[o](""),!e}));if(!r||!l||"replace"===t&&(!ue||!he||pe)||"split"===t&&!de){var a=/./[o],c=n(o,""[t],(function(t,e,n,i,o){var l=e.exec;return l===Kt||l===ce.exec?r&&!o?{done:!0,value:a.call(e,n,i)}:{done:!0,value:t.call(n,e,i)}:{done:!1}}),{REPLACE_KEEPS_$0:he,REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE:pe}),u=c[0],h=c[1];lt(String.prototype,t,u),lt(ce,o,2==e?function(t,e){return h.call(t,this,e)}:function(t){return h.call(t,this)})}i&&L(ce[o],"sham",!0)},ve=function(t){return function(e,n){var i,o,r=String(b(e)),l=ft(n),a=r.length;return l<0||l>=a?t?"":void 0:(i=r.charCodeAt(l))<55296||i>56319||l+1===a||(o=r.charCodeAt(l+1))<56320||o>57343?t?r.charAt(l):i:t?r.slice(l,l+2):o-56320+(i-55296<<10)+65536}},me={codeAt:ve(!1),charAt:ve(!0)}.charAt,be=function(t,e,n){return e+(n?me(t,e).length:1)},ye=function(t,e){var n=t.exec;if("function"==typeof n){var i=n.call(t,e);if("object"!=typeof i)throw TypeError("RegExp exec method returned something other than an Object or null");return i}if("RegExp"!==g(t))throw TypeError("RegExp#exec called on incompatible receiver");return Kt.call(t,e)};ge("match",1,(function(t,e,n){return[function(e){var n=b(this),i=null==e?void 0:e[t];return void 0!==i?i.call(e,n):new RegExp(e)[t](String(n))},function(t){var i=n(e,t,this);if(i.done)return i.value;var o=I(t),r=String(this);if(!o.global)return ye(o,r);var l=o.unicode;o.lastIndex=0;for(var a,s=[],c=0;null!==(a=ye(o,r));){var u=String(a[0]);s[c]=u,""===u&&(o.lastIndex=be(r,dt(o.lastIndex),l)),c++}return 0===c?null:s}]}));var we=Array.isArray||function(t){return"Array"==g(t)},_e=function(t,e,n){var i=_(e);i in t?O.f(t,i,p(0,n)):t[i]=n},Se=ae("species"),xe=function(t,e){var n;return we(t)&&("function"!=typeof(n=t.constructor)||n!==Array&&!we(n.prototype)?w(n)&&null===(n=n[Se])&&(n=void 0):n=void 0),new(void 0===n?Array:n)(0===e?0:e)},je=ae("species"),Ce=function(t){return ee>=51||!s((function(){var e=[];return(e.constructor={})[je]=function(){return{foo:1}},1!==e[t](Boolean).foo}))},Ee=ae("isConcatSpreadable"),Ae=9007199254740991,ke="Maximum allowed index exceeded",Te=ee>=51||!s((function(){var t=[];return t[Ee]=!1,t.concat()[0]!==t})),Ne=Ce("concat"),Ie=function(t){if(!w(t))return!1;var e=t[Ee];return void 0!==e?!!e:we(t)};qt({target:"Array",proto:!0,forced:!Te||!Ne},{concat:function(t){var e,n,i,o,r,l=S(this),a=xe(l,0),s=0;for(e=-1,i=arguments.length;eAe)throw TypeError(ke);for(n=0;n=Ae)throw TypeError(ke);_e(a,s++,r)}return a.length=s,a}});var Pe={};Pe[ae("toStringTag")]="z";var Oe="[object z]"===String(Pe),Le=ae("toStringTag"),Re="Arguments"==g(function(){return arguments}()),qe=Oe?g:function(t){var e,n,i;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=function(t,e){try{return t[e]}catch(t){}}(e=Object(t),Le))?n:Re?g(e):"Object"==(i=g(e))&&"function"==typeof e.callee?"Arguments":i},Be=Oe?{}.toString:function(){return"[object "+qe(this)+"]"};Oe||lt(Object.prototype,"toString",Be,{unsafe:!0});var Me="toString",He=RegExp.prototype,De=He.toString,$e=s((function(){return"/a/b"!=De.call({source:"a",flags:"b"})})),Ue=De.name!=Me;($e||Ue)&<(RegExp.prototype,Me,(function(){var t=I(this),e=String(t.source),n=t.flags;return"/"+e+"/"+String(void 0===n&&t instanceof RegExp&&!("flags"in He)?Bt.call(t):n)}),{unsafe:!0});var Fe=ae("match"),ze=function(t){var e;return w(t)&&(void 0!==(e=t[Fe])?!!e:"RegExp"==g(t))},We=function(t){if("function"!=typeof t)throw TypeError(String(t)+" is not a function");return t},Ge=ae("species"),Ve=$t.UNSUPPORTED_Y,Ke=[].push,Ye=Math.min,Xe=4294967295;function Je(t,e){if(t instanceof SVGElement){var i=t.getAttribute("class")||"";i.match(e)||t.setAttribute("class","".concat(i," ").concat(e))}else{if(void 0!==t.classList)n(e.split(" "),(function(e){t.classList.add(e)}));else t.className.match(e)||(t.className+=" ".concat(e))}}function Qe(t,e){var n="";return t.currentStyle?n=t.currentStyle[e]:document.defaultView&&document.defaultView.getComputedStyle&&(n=document.defaultView.getComputedStyle(t,null).getPropertyValue(e)),n&&n.toLowerCase?n.toLowerCase():n}function Ze(t){var e=t.element;if(this._options.scrollToElement){var n=function(t){var e=window.getComputedStyle(t),n="absolute"===e.position,i=/(auto|scroll)/;if("fixed"===e.position)return document.body;for(var o=t;o=o.parentElement;)if(e=window.getComputedStyle(o),(!n||"static"!==e.position)&&i.test(e.overflow+e.overflowY+e.overflowX))return o;return document.body}(e);n!==document.body&&(n.scrollTop=e.offsetTop-n.offsetTop)}}function tn(){if(void 0!==window.innerWidth)return{width:window.innerWidth,height:window.innerHeight};var t=document.documentElement;return{width:t.clientWidth,height:t.clientHeight}}function en(t,e,n){var i,o=e.element;if("off"!==t&&(this._options.scrollToElement&&(i="tooltip"===t?n.getBoundingClientRect():o.getBoundingClientRect(),!function(t){var e=t.getBoundingClientRect();return e.top>=0&&e.left>=0&&e.bottom+80<=window.innerHeight&&e.right<=window.innerWidth}(o)))){var r=tn().height;i.bottom-(i.bottom-i.top)<0||o.clientHeight>r?window.scrollBy(0,i.top-(r/2-i.height/2)-this._options.scrollPadding):window.scrollBy(0,i.top-(r/2-i.height/2)+this._options.scrollPadding)}}function nn(t){t.setAttribute("role","button"),t.tabIndex=0}ge("split",2,(function(t,e,n){var i;return i="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length?function(t,n){var i=String(b(this)),o=void 0===n?Xe:n>>>0;if(0===o)return[];if(void 0===t)return[i];if(!ze(t))return e.call(i,t,o);for(var r,l,a,s=[],c=(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.unicode?"u":"")+(t.sticky?"y":""),u=0,h=new RegExp(t.source,c+"g");(r=Kt.call(h,i))&&!((l=h.lastIndex)>u&&(s.push(i.slice(u,r.index)),r.length>1&&r.index=o));)h.lastIndex===r.index&&h.lastIndex++;return u===i.length?!a&&h.test("")||s.push(""):s.push(i.slice(u)),s.length>o?s.slice(0,o):s}:"0".split(void 0,0).length?function(t,n){return void 0===t&&0===n?[]:e.call(this,t,n)}:e,[function(e,n){var o=b(this),r=null==e?void 0:e[t];return void 0!==r?r.call(e,o,n):i.call(String(o),e,n)},function(t,o){var r=n(i,t,this,o,i!==e);if(r.done)return r.value;var l=I(t),a=String(this),s=function(t,e){var n,i=I(t).constructor;return void 0===i||null==(n=I(i)[Ge])?e:We(n)}(l,RegExp),c=l.unicode,u=(l.ignoreCase?"i":"")+(l.multiline?"m":"")+(l.unicode?"u":"")+(Ve?"g":"y"),h=new s(Ve?"^(?:"+l.source+")":l,u),f=void 0===o?Xe:o>>>0;if(0===f)return[];if(0===a.length)return null===ye(h,a)?[a]:[];for(var p=0,d=0,g=[];do;)for(var a,s=m(arguments[o++]),u=r?on(s).concat(r(s)):on(s),h=u.length,p=0;h>p;)a=u[p++],c&&!l.call(s,a)||(n[a]=s[a]);return n}:rn;function sn(t,e){var n=document.body,i=document.documentElement,o=window.pageYOffset||i.scrollTop||n.scrollTop,r=window.pageXOffset||i.scrollLeft||n.scrollLeft;e=e||n;var l=t.getBoundingClientRect(),a=e.getBoundingClientRect(),s=Qe(e,"position"),c={width:l.width,height:l.height};return"body"!==e.tagName.toLowerCase()&&"relative"===s||"sticky"===s?Object.assign(c,{top:l.top-a.top,left:l.left-a.left}):Object.assign(c,{top:l.top+o,left:l.left+r})}function cn(t){var e=t.parentNode;return!(!e||"HTML"===e.nodeName)&&("fixed"===Qe(t,"position")||cn(e))}qt({target:"Object",stat:!0,forced:Object.assign!==an},{assign:an});var un=Math.floor,hn="".replace,fn=/\$([$&'`]|\d{1,2}|<[^>]*>)/g,pn=/\$([$&'`]|\d{1,2})/g,dn=function(t,e,n,i,o,r){var l=n+t.length,a=i.length,s=pn;return void 0!==o&&(o=S(o),s=fn),hn.call(r,s,(function(r,s){var c;switch(s.charAt(0)){case"$":return"$";case"&":return t;case"`":return e.slice(0,n);case"'":return e.slice(l);case"<":c=o[s.slice(1,-1)];break;default:var u=+s;if(0===u)return r;if(u>a){var h=un(u/10);return 0===h?r:h<=a?void 0===i[h-1]?s.charAt(1):i[h-1]+s.charAt(1):r}c=i[u-1]}return void 0===c?"":c}))},gn=Math.max,vn=Math.min;function mn(t,e){if(t instanceof SVGElement){var n=t.getAttribute("class")||"";t.setAttribute("class",n.replace(e,"").replace(/^\s+|\s+$/g,""))}else t.className=t.className.replace(e,"").replace(/^\s+|\s+$/g,"")}function bn(t,e){var n="";if(t.style.cssText&&(n+=t.style.cssText),"string"==typeof e)n+=e;else for(var i in e)n+="".concat(i,":").concat(e[i],";");t.style.cssText=n}function yn(t){if(t){if(!this._introItems[this._currentStep])return;var e=this._introItems[this._currentStep],n=sn(e.element,this._targetElement),i=this._options.helperElementPadding;cn(e.element)?Je(t,"introjs-fixedTooltip"):mn(t,"introjs-fixedTooltip"),"floating"===e.position&&(i=0),bn(t,{width:"".concat(n.width+i,"px"),height:"".concat(n.height+i,"px"),top:"".concat(n.top-i/2,"px"),left:"".concat(n.left-i/2,"px")})}}ge("replace",2,(function(t,e,n,i){var o=i.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE,r=i.REPLACE_KEEPS_$0,l=o?"$":"$0";return[function(n,i){var o=b(this),r=null==n?void 0:n[t];return void 0!==r?r.call(n,o,i):e.call(String(o),n,i)},function(t,i){if(!o&&r||"string"==typeof i&&-1===i.indexOf(l)){var a=n(e,t,this,i);if(a.done)return a.value}var s=I(t),c=String(this),u="function"==typeof i;u||(i=String(i));var h=s.global;if(h){var f=s.unicode;s.lastIndex=0}for(var p=[];;){var d=ye(s,c);if(null===d)break;if(p.push(d),!h)break;""===String(d[0])&&(s.lastIndex=be(c,dt(s.lastIndex),f))}for(var g,v="",m=0,b=0;b=m&&(v+=c.slice(m,w)+C,m=w+y.length)}return v+c.slice(m)}]}));var wn,_n=c?Object.defineProperties:function(t,e){I(t);for(var n,i=on(e),o=i.length,r=0;o>r;)O.f(t,n=i[r++],e[n]);return t},Sn=ct("document","documentElement"),xn=X("IE_PROTO"),jn=function(){},Cn=function(t){return" @@ -56,6 +57,7 @@ } + - + + + + diff --git a/apps/remix-ide/src/lib/cmdInterpreterAPI.js b/apps/remix-ide/src/lib/cmdInterpreterAPI.js index d132f13107..9c79cae25b 100644 --- a/apps/remix-ide/src/lib/cmdInterpreterAPI.js +++ b/apps/remix-ide/src/lib/cmdInterpreterAPI.js @@ -1,9 +1,9 @@ 'use strict' +import { CompilerImports } from '@remix-project/core-plugin' var yo = require('yo-yo') var async = require('async') var EventManager = require('../lib/events') -var CompilerImport = require('../app/compiler/compiler-imports') var toolTip = require('../app/ui/tooltip') var globalRegistry = require('../global/registry') var SourceHighlighter = require('../app/editor/sourceHighlighter') @@ -18,7 +18,7 @@ class CmdInterpreterAPI { self._components.registry = localRegistry || globalRegistry self._components.terminal = terminal self._components.sourceHighlighter = new SourceHighlighter() - self._components.fileImport = new CompilerImport() + self._components.fileImport = new CompilerImports() self._components.gistHandler = new GistHandler() self._deps = { fileManager: self._components.registry.get('filemanager').api, diff --git a/apps/remix-ide/src/lib/publishOnIpfs.js b/apps/remix-ide/src/lib/publishOnIpfs.js index 52a55a02e7..07f8256540 100644 --- a/apps/remix-ide/src/lib/publishOnIpfs.js +++ b/apps/remix-ide/src/lib/publishOnIpfs.js @@ -4,7 +4,7 @@ const async = require('async') const IpfsClient = require('ipfs-mini') const ipfsNodes = [ - new IpfsClient({ host: 'ipfs.komputing.org', port: 443, protocol: 'https' }), + new IpfsClient({ host: 'ipfs.remixproject.org', port: 443, protocol: 'https' }), new IpfsClient({ host: 'ipfs.infura.io', port: 5001, protocol: 'https' }), new IpfsClient({ host: '127.0.0.1', port: 5001, protocol: 'http' }) ] diff --git a/apps/remix-ide/src/remixEngine.js b/apps/remix-ide/src/remixEngine.js index abf20340f6..2836d974b2 100644 --- a/apps/remix-ide/src/remixEngine.js +++ b/apps/remix-ide/src/remixEngine.js @@ -10,6 +10,7 @@ export class RemixEngine extends Engine { setPluginOption ({ name, kind }) { if (kind === 'provider') return { queueTimeout: 60000 * 2 } if (name === 'LearnEth') return { queueTimeout: 60000 } + if (name === 'slither') return { queueTimeout: 60000 * 4 } // Requires when a solc version is installed return { queueTimeout: 10000 } } diff --git a/apps/remix-ide/src/walkthroughService.js b/apps/remix-ide/src/walkthroughService.js new file mode 100644 index 0000000000..2969d1190f --- /dev/null +++ b/apps/remix-ide/src/walkthroughService.js @@ -0,0 +1,54 @@ +const introJs = require('intro.js') + +export class WalkthroughService { + constructor (params) { + this.params = params + } + + start (params) { + if (!localStorage.getItem('hadTour_initial')) { + introJs().setOptions({ + steps: [{ + title: 'Welcome to Remix IDE', + intro: 'Click to launch the Home tab that contains links, tips, and shortcuts..', + element: document.querySelector('#verticalIconsHomeIcon'), + tooltipClass: 'bg-light text-dark', + position: 'right' + }, + { + element: document.querySelector('#compileIcons'), + title: 'Solidity Compiler', + intro: 'Having selected a .sol file in the File Explorers (the icon above), compile it with the Solidity Compiler.', + tooltipClass: 'bg-light text-dark', + position: 'right' + }, + { + title: 'Deploy your contract', + element: document.querySelector('#runIcons'), + intro: 'Choose a chain, deploy a contract and play with your functions.', + tooltipClass: 'bg-light text-dark', + position: 'right' + } + ] + }).onafterchange((targetElement) => { + const header = document.getElementsByClassName('introjs-tooltip-header')[0] + if (header) { + header.classList.add('d-flex') + header.classList.add('justify-content-between') + header.classList.add('text-nowrap') + header.classList.add('pr-0') + } + const skipbutton = document.getElementsByClassName('introjs-skipbutton')[0] + if (skipbutton) { + skipbutton.classList.add('ml-3') + skipbutton.classList.add('text-decoration-none') + skipbutton.id = 'remixTourSkipbtn' + } + }).start() + localStorage.setItem('hadTour_initial', true) + } + } + + startFeatureTour () { + } +} diff --git a/libs/remix-analyzer/package.json b/libs/remix-analyzer/package.json index c9a0047c1d..c9b875ec1c 100644 --- a/libs/remix-analyzer/package.json +++ b/libs/remix-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/remix-analyzer", - "version": "0.5.11", + "version": "0.5.14", "description": "Tool to perform static analysis on Solidity smart contracts", "main": "index.js", "types": ".index.d.ts", @@ -19,14 +19,15 @@ } ], "dependencies": { - "@ethereumjs/block": "^3.3.0", - "@ethereumjs/tx": "^3.2.1", - "@ethereumjs/vm": "^5.4.1", + "@ethereumjs/block": "^3.4.0", + "@ethereumjs/tx": "^3.3.0", + "@ethereumjs/vm": "^5.5.0", "@remix-project/remix-astwalker": "^0.0.26", - "@remix-project/remix-lib": "^0.5.2", + "@remix-project/remix-lib": "^0.5.5", "async": "^2.6.2", "ethereumjs-util": "^7.0.10", - "ethers": "^5.1.4", + "ethers": "^5.4.2", + "string-similarity": "^4.0.4", "web3": "1.2.4" }, "publishConfig": { @@ -50,5 +51,5 @@ "typescript": "^3.7.5" }, "typings": "index.d.ts", - "gitHead": "50b32cc20d2d4dcc793bf7de955957e073e5b5b8" + "gitHead": "df7abe1c219e361a947031d620f4ae6e3786a4d7" } \ No newline at end of file diff --git a/libs/remix-astwalker/package.json b/libs/remix-astwalker/package.json index 68690d88d3..6054263f6f 100644 --- a/libs/remix-astwalker/package.json +++ b/libs/remix-astwalker/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/remix-astwalker", - "version": "0.0.32", + "version": "0.0.35", "description": "Tool to walk through Solidity AST", "main": "index.js", "scripts": { @@ -34,15 +34,16 @@ ] }, "dependencies": { - "@ethereumjs/block": "^3.3.0", - "@ethereumjs/tx": "^3.2.1", - "@ethereumjs/vm": "^5.4.1", - "@remix-project/remix-lib": "^0.5.2", + "@ethereumjs/block": "^3.4.0", + "@ethereumjs/tx": "^3.3.0", + "@ethereumjs/vm": "^5.5.0", + "@remix-project/remix-lib": "^0.5.5", "@types/tape": "^4.2.33", "async": "^2.6.2", "ethereumjs-util": "^7.0.10", - "ethers": "^5.1.4", + "ethers": "^5.4.2", "nyc": "^13.3.0", + "string-similarity": "^4.0.4", "tape": "^4.10.1", "ts-node": "^8.0.3", "typescript": "^3.4.3", @@ -52,5 +53,5 @@ "tap-spec": "^5.0.0" }, "typings": "index.d.ts", - "gitHead": "50b32cc20d2d4dcc793bf7de955957e073e5b5b8" + "gitHead": "df7abe1c219e361a947031d620f4ae6e3786a4d7" } \ No newline at end of file diff --git a/libs/remix-core-plugin/.eslintrc b/libs/remix-core-plugin/.eslintrc new file mode 100644 index 0000000000..ab8f38339c --- /dev/null +++ b/libs/remix-core-plugin/.eslintrc @@ -0,0 +1 @@ +{ "extends": "../../.eslintrc", "rules": {}, "ignorePatterns": ["!**/*"] } diff --git a/libs/remix-core-plugin/README.md b/libs/remix-core-plugin/README.md new file mode 100644 index 0000000000..fc60297f57 --- /dev/null +++ b/libs/remix-core-plugin/README.md @@ -0,0 +1,3 @@ +# remix-core-plugin-core-plugin + +This library was generated with [Nx](https://nx.dev). diff --git a/libs/remix-core-plugin/package.json b/libs/remix-core-plugin/package.json new file mode 100644 index 0000000000..dcdc862128 --- /dev/null +++ b/libs/remix-core-plugin/package.json @@ -0,0 +1,12 @@ +{ + "name": "@remix-project/core-plugin", + "version": "0.0.1", + "description": "This library was generated with [Nx](https://nx.dev).", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Remix Team", + "license": "ISC" + } + \ No newline at end of file diff --git a/libs/remix-core-plugin/src/index.ts b/libs/remix-core-plugin/src/index.ts new file mode 100644 index 0000000000..73c98a6181 --- /dev/null +++ b/libs/remix-core-plugin/src/index.ts @@ -0,0 +1,5 @@ +export { OffsetToLineColumnConverter } from './lib/offset-line-to-column-converter' +export { CompilerMetadata } from './lib/compiler-metadata' +export { FetchAndCompile } from './lib/compiler-fetch-and-compile' +export { CompilerImports } from './lib/compiler-content-imports' +export { CompilerArtefacts } from './lib/compiler-artefacts' diff --git a/apps/remix-ide/src/app/compiler/compiler-artefacts.js b/libs/remix-core-plugin/src/lib/compiler-artefacts.ts similarity index 92% rename from apps/remix-ide/src/app/compiler/compiler-artefacts.js rename to libs/remix-core-plugin/src/lib/compiler-artefacts.ts index 68b1cad9bd..47eb1d519b 100644 --- a/apps/remix-ide/src/app/compiler/compiler-artefacts.js +++ b/libs/remix-core-plugin/src/lib/compiler-artefacts.ts @@ -1,16 +1,17 @@ 'use strict' import { Plugin } from '@remixproject/engine' -import * as packageJson from '../../../../../package.json' -import CompilerAbstract from './compiler-abstract' +import { CompilerAbstract } from '@remix-project/remix-solidity' const profile = { name: 'compilerArtefacts', - methods: [], + methods: ['get', 'addResolvedContract'], events: [], - version: packageJson.version + version: '0.0.1' } -module.exports = class CompilerArtefacts extends Plugin { +export class CompilerArtefacts extends Plugin { + compilersArtefactsPerFile: any + compilersArtefacts: any constructor () { super(profile) this.compilersArtefacts = {} diff --git a/libs/remix-core-plugin/src/lib/compiler-content-imports.ts b/libs/remix-core-plugin/src/lib/compiler-content-imports.ts new file mode 100644 index 0000000000..edb512a7ed --- /dev/null +++ b/libs/remix-core-plugin/src/lib/compiler-content-imports.ts @@ -0,0 +1,180 @@ +'use strict' +import { Plugin } from '@remixproject/engine' +import { RemixURLResolver } from '@remix-project/remix-url-resolver' +const remixTests = require('@remix-project/remix-tests') +const async = require('async') + +const profile = { + name: 'contentImport', + displayName: 'content import', + version: '0.0.1', + methods: ['resolve', 'resolveAndSave', 'isExternalUrl'] +} + +export class CompilerImports extends Plugin { + previouslyHandled: {} + urlResolver: any + constructor () { + super(profile) + this.urlResolver = new RemixURLResolver() + this.previouslyHandled = {} // cache import so we don't make the request at each compilation. + } + + async setToken () { + try { + const protocol = typeof window !== 'undefined' && window.location.protocol + const token = await this.call('settings', 'get', 'settings/gist-access-token') + + this.urlResolver.setGistToken(token, protocol) + } catch (error) { + console.log(error) + } + } + + isRelativeImport (url) { + return /^([^/]+)/.exec(url) + } + + isExternalUrl (url) { + const handlers = this.urlResolver.getHandlers() + return handlers.some(handler => handler.match(url)) + } + + /** + * resolve the content of @arg url. This only resolves external URLs. + * + * @param {String} url - external URL of the content. can be basically anything like raw HTTP, ipfs URL, github address etc... + * @returns {Promise} - { content, cleanUrl, type, url } + */ + resolve (url) { + return new Promise((resolve, reject) => { + this.import(url, null, (error, content, cleanUrl, type, url) => { + if (error) return reject(error) + resolve({ content, cleanUrl, type, url }) + }, null) + }) + } + + async import (url, force, loadingCb, cb) { + if (typeof force !== 'boolean') { + const temp = loadingCb + loadingCb = force + cb = temp + force = false + } + if (!loadingCb) loadingCb = () => {} + if (!cb) cb = () => {} + + var self = this + if (force) delete this.previouslyHandled[url] + var imported = this.previouslyHandled[url] + if (imported) { + return cb(null, imported.content, imported.cleanUrl, imported.type, url) + } + + let resolved + try { + await this.setToken() + resolved = await this.urlResolver.resolve(url) + const { content, cleanUrl, type } = resolved + self.previouslyHandled[url] = { + content, + cleanUrl, + type + } + cb(null, content, cleanUrl, type, url) + } catch (e) { + return cb(new Error('not found ' + url)) + } + } + + importExternal (url, targetPath, cb) { + this.import(url, + // TODO: handle this event + (loadingMsg) => { this.emit('message', loadingMsg) }, + async (error, content, cleanUrl, type, url) => { + if (error) return cb(error) + try { + const provider = await this.call('fileManager', 'getProviderOf', null) + const path = targetPath || type + '/' + cleanUrl + if (provider) provider.addExternal('.deps/' + path, content, url) + } catch (err) { + + } + cb(null, content) + }, null) + } + + /** + * import the content of @arg url. + * first look in the browser localstorage (browser explorer) or locahost explorer. if the url start with `browser/*` or `localhost/*` + * then check if the @arg url is located in the localhost, in the node_modules or installed_contracts folder + * then check if the @arg url match any external url + * + * @param {String} url - URL of the content. can be basically anything like file located in the browser explorer, in the localhost explorer, raw HTTP, github address etc... + * @param {String} targetPath - (optional) internal path where the content should be saved to + * @returns {Promise} - string content + */ + resolveAndSave (url, targetPath) { + return new Promise((resolve, reject) => { + if (url.indexOf('remix_tests.sol') !== -1) resolve(remixTests.assertLibCode) + this.call('fileManager', 'getProviderOf', url).then((provider) => { + if (provider) { + if (provider.type === 'localhost' && !provider.isConnected()) { + return reject(new Error(`file provider ${provider.type} not available while trying to resolve ${url}`)) + } + provider.exists(url).then(exist => { + /* + if the path is absolute and the file does not exist, we can stop here + Doesn't make sense to try to resolve "localhost/node_modules/localhost/node_modules/" and we'll end in an infinite loop. + */ + if (!exist && url.startsWith('browser/')) return reject(new Error(`not found ${url}`)) + if (!exist && url.startsWith('localhost/')) return reject(new Error(`not found ${url}`)) + + if (exist) { + return provider.get(url, (error, content) => { + if (error) return reject(error) + resolve(content) + }) + } + + // try to resolve localhost modules (aka truffle imports) - e.g from the node_modules folder + this.call('fileManager', 'getProviderByName', 'localhost').then((localhostProvider) => { + if (localhostProvider.isConnected()) { + var splitted = /([^/]+)\/(.*)$/g.exec(url) + return async.tryEach([ + (cb) => { this.resolveAndSave('localhost/installed_contracts/' + url, null).then((result) => cb(null, result)).catch((error) => cb(error.message)) }, + // eslint-disable-next-line standard/no-callback-literal + (cb) => { if (!splitted) { cb('URL not parseable: ' + url) } else { this.resolveAndSave('localhost/installed_contracts/' + splitted[1] + '/contracts/' + splitted[2], null).then((result) => cb(null, result)).catch((error) => cb(error.message)) } }, + (cb) => { this.resolveAndSave('localhost/node_modules/' + url, null).then((result) => cb(null, result)).catch((error) => cb(error.message)) }, + // eslint-disable-next-line standard/no-callback-literal + (cb) => { if (!splitted) { cb('URL not parseable: ' + url) } else { this.resolveAndSave('localhost/node_modules/' + splitted[1] + '/contracts/' + splitted[2], null).then((result) => cb(null, result)).catch((error) => cb(error.message)) } }], + (error, result) => { + if (error) { + return this.importExternal(url, targetPath, (error, content) => { + if (error) return reject(error) + resolve(content) + }) + } + resolve(result) + }) + } + this.importExternal(url, targetPath, (error, content) => { + if (error) return reject(error) + resolve(content) + }) + }) + }).catch(error => { + return reject(error) + }) + } + }).catch(() => { + // fallback to just resolving the file, it won't be saved in file manager + return this.importExternal(url, targetPath, (error, content) => { + if (error) return reject(error) + resolve(content) + }) + }) + }) + } +} diff --git a/apps/remix-ide/src/app/compiler/compiler-sourceVerifier-fetchAndCompile.js b/libs/remix-core-plugin/src/lib/compiler-fetch-and-compile.ts similarity index 80% rename from apps/remix-ide/src/app/compiler/compiler-sourceVerifier-fetchAndCompile.js rename to libs/remix-core-plugin/src/lib/compiler-fetch-and-compile.ts index 4a513e2129..e7769b7b04 100644 --- a/apps/remix-ide/src/app/compiler/compiler-sourceVerifier-fetchAndCompile.js +++ b/libs/remix-core-plugin/src/lib/compiler-fetch-and-compile.ts @@ -1,18 +1,19 @@ -import * as packageJson from '../../../../../package.json' + import { Plugin } from '@remixproject/engine' -import { compile } from './compiler-helpers' -import globalRegistry from '../../global/registry' +import { compile } from '@remix-project/remix-solidity' +import { util } from '@remix-project/remix-lib' -import remixLib from '@remix-project/remix-lib' const ethutil = require('ethereumjs-util') const profile = { name: 'fetchAndCompile', methods: ['resolve'], - version: packageJson.version + version: '0.0.1' } -export default class FetchAndCompile extends Plugin { +export class FetchAndCompile extends Plugin { + unresolvedAddresses: any[] + sourceVerifierNetWork: string[] constructor () { super(profile) this.unresolvedAddresses = [] @@ -32,11 +33,10 @@ export default class FetchAndCompile extends Plugin { */ async resolve (contractAddress, codeAtAddress, targetPath) { contractAddress = ethutil.toChecksumAddress(contractAddress) - const compilersartefacts = globalRegistry.get('compilersartefacts').api - const localCompilation = () => compilersartefacts.get(contractAddress) ? compilersartefacts.get(contractAddress) : compilersartefacts.get('__last') ? compilersartefacts.get('__last') : null + const localCompilation = async () => await this.call('compilerArtefacts', 'get', contractAddress) ? await this.call('compilerArtefacts', 'get', contractAddress) : await this.call('compilerArtefacts', 'get', '__last') ? await this.call('compilerArtefacts', 'get', '__last') : null - const resolved = compilersartefacts.get(contractAddress) + const resolved = await this.call('compilerArtefacts', 'get', contractAddress) if (resolved) return resolved if (this.unresolvedAddresses.includes(contractAddress)) return localCompilation() @@ -53,15 +53,15 @@ export default class FetchAndCompile extends Plugin { if (!this.sourceVerifierNetWork.includes(network.name)) return localCompilation() // check if the contract if part of the local compilation result - const compilation = localCompilation() + const compilation = await localCompilation() if (compilation) { let found = false compilation.visitContracts((contract) => { - found = remixLib.util.compareByteCode('0x' + contract.object.evm.deployedBytecode.object, codeAtAddress) + found = util.compareByteCode('0x' + contract.object.evm.deployedBytecode.object, codeAtAddress) return found }) if (found) { - compilersartefacts.addResolvedContract(contractAddress, compilation) + await this.call('compilerArtefacts', 'addResolvedContract', contractAddress, compilation) setTimeout(_ => this.emit('usingLocalCompilation', contractAddress), 0) return compilation } @@ -118,8 +118,8 @@ export default class FetchAndCompile extends Plugin { const compData = await compile( compilationTargets, settings, - (url, cb) => this.call('contentImport', 'resolveAndSave', url).then((result) => cb(null, result)).catch((error) => cb(error.message))) - compilersartefacts.addResolvedContract(contractAddress, compData) + async (url, cb) => await this.call('contentImport', 'resolveAndSave', url).then((result) => cb(null, result)).catch((error) => cb(error.message))) + await this.call('compilerArtefacts', 'addResolvedContract', contractAddress, compData) return compData } catch (e) { this.unresolvedAddresses.push(contractAddress) diff --git a/libs/remix-core-plugin/src/lib/compiler-metadata.ts b/libs/remix-core-plugin/src/lib/compiler-metadata.ts new file mode 100644 index 0000000000..d194c0281d --- /dev/null +++ b/libs/remix-core-plugin/src/lib/compiler-metadata.ts @@ -0,0 +1,145 @@ +'use strict' +import { Plugin } from '@remixproject/engine' +import { CompilerAbstract } from '@remix-project/remix-solidity' + +const profile = { + name: 'compilerMetadata', + methods: ['deployMetadataOf'], + events: [], + version: '0.0.1' +} + +export class CompilerMetadata extends Plugin { + networks: string[] + innerPath: string + constructor () { + super(profile) + this.networks = ['VM:-', 'main:1', 'ropsten:3', 'rinkeby:4', 'kovan:42', 'görli:5', 'Custom'] + this.innerPath = 'artifacts' + } + + _JSONFileName (path, contractName) { + return this.joinPath(path, this.innerPath, contractName + '.json') + } + + _MetadataFileName (path, contractName) { + return this.joinPath(path, this.innerPath, contractName + '_metadata.json') + } + + onActivation () { + var self = this + this.on('solidity', 'compilationFinished', async (file, source, languageVersion, data) => { + if (!await this.call('settings', 'get', 'settings/generate-contract-metadata')) return + const compiler = new CompilerAbstract(languageVersion, data, source) + var path = self._extractPathOf(source.target) + compiler.visitContracts((contract) => { + if (contract.file !== source.target) return + (async () => { + const fileName = self._JSONFileName(path, contract.name) + const content = await this.call('fileManager', 'exists', fileName) ? await this.call('fileManager', 'readFile', fileName) : null + await this._setArtefacts(content, contract, path) + })() + }) + }) + } + + _extractPathOf (file) { + var reg = /(.*)(\/).*/ + var path = reg.exec(file) + return path ? path[1] : '/' + } + + async _setArtefacts (content, contract, path) { + content = content || '{}' + var metadata + try { + metadata = JSON.parse(content) + } catch (e) { + console.log(e) + } + var fileName = this._JSONFileName(path, contract.name) + var metadataFileName = this._MetadataFileName(path, contract.name) + + var deploy = metadata.deploy || {} + this.networks.forEach((network) => { + deploy[network] = this._syncContext(contract, deploy[network] || {}) + }) + + let parsedMetadata + try { + parsedMetadata = JSON.parse(contract.object.metadata) + } catch (e) { + console.log(e) + } + if (parsedMetadata) await this.call('fileManager', 'writeFile', metadataFileName, JSON.stringify(parsedMetadata, null, '\t')) + + var data = { + deploy, + data: { + bytecode: contract.object.evm.bytecode, + deployedBytecode: contract.object.evm.deployedBytecode, + gasEstimates: contract.object.evm.gasEstimates, + methodIdentifiers: contract.object.evm.methodIdentifiers + }, + abi: contract.object.abi + } + await this.call('fileManager', 'writeFile', fileName, JSON.stringify(data, null, '\t')) + } + + _syncContext (contract, metadata) { + var linkReferences = metadata.linkReferences + var autoDeployLib = metadata.autoDeployLib + if (!linkReferences) linkReferences = {} + if (autoDeployLib === undefined) autoDeployLib = true + + for (var libFile in contract.object.evm.bytecode.linkReferences) { + if (!linkReferences[libFile]) linkReferences[libFile] = {} + for (var lib in contract.object.evm.bytecode.linkReferences[libFile]) { + if (!linkReferences[libFile][lib]) { + linkReferences[libFile][lib] = '
' + } + } + } + metadata.linkReferences = linkReferences + metadata.autoDeployLib = autoDeployLib + return metadata + } + + async deployMetadataOf (contractName, fileLocation) { + let path + if (fileLocation) { + path = fileLocation.split('/') + path.pop() + path = path.join('/') + } else { + try { + path = this._extractPathOf(await this.call('fileManager', 'getCurrentFile')) + } catch (err) { + console.log(err) + throw new Error(err) + } + } + try { + const { id, name } = await this.call('network', 'detectNetwork') + const fileName = this._JSONFileName(path, contractName) + try { + const content = await this.call('fileManager', 'readFile', fileName) + if (!content) return null + let metadata = JSON.parse(content) + metadata = metadata.deploy || {} + return metadata[name + ':' + id] || metadata[name] || metadata[id] || metadata[name.toLowerCase() + ':' + id] || metadata[name.toLowerCase()] + } catch (err) { + return null + } + } catch (err) { + console.log(err) + throw new Error(err) + } + } + + joinPath (...paths) { + paths = paths.filter((value) => value !== '').map((path) => path.replace(/^\/|\/$/g, '')) // remove first and last slash) + if (paths.length === 1) return paths[0] + return paths.join('/') + } +} diff --git a/libs/remix-core-plugin/src/lib/offset-line-to-column-converter.ts b/libs/remix-core-plugin/src/lib/offset-line-to-column-converter.ts new file mode 100644 index 0000000000..57c3f3ed2e --- /dev/null +++ b/libs/remix-core-plugin/src/lib/offset-line-to-column-converter.ts @@ -0,0 +1,77 @@ +'use strict' +import { Plugin } from '@remixproject/engine' + +import { sourceMappingDecoder } from '@remix-project/remix-debug' + +const profile = { + name: 'offsetToLineColumnConverter', + methods: ['offsetToLineColumn'], + events: [], + version: '0.0.1' +} + +export class OffsetToLineColumnConverter extends Plugin { + lineBreakPositionsByContent: {} + sourceMappingDecoder: any + constructor () { + super(profile) + this.lineBreakPositionsByContent = {} + this.sourceMappingDecoder = sourceMappingDecoder + } + + /** + * Convert offset representation with line/column representation. + * This is also used to resolve the content: + * @arg file is the index of the file in the content sources array and content sources array does have filename as key and not index. + * So we use the asts (which references both index and filename) to look up the actual content targeted by the @arg file index. + * @param {{start, length}} rawLocation - offset location + * @param {number} file - The index where to find the source in the sources parameters + * @param {Object.} sources - Map of content sources + * @param {Object.} asts - Map of content sources + */ + offsetToLineColumn (rawLocation, file, sources, asts) { + if (!this.lineBreakPositionsByContent[file]) { + const sourcesArray = Object.keys(sources) + if (!asts || (file === 0 && sourcesArray.length === 1)) { + // if we don't have ast, we process the only one available content (applicable also for compiler older than 0.4.12) + this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(sources[sourcesArray[0]].content) + } else { + for (var filename in asts) { + const source = asts[filename] + if (source.id === file) { + this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(sources[filename].content) + break + } + } + } + } + return this.sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, this.lineBreakPositionsByContent[file]) + } + + /** + * Convert offset representation with line/column representation. + * @param {{start, length}} rawLocation - offset location + * @param {number} file - The index where to find the source in the sources parameters + * @param {string} content - source + */ + offsetToLineColumnWithContent (rawLocation, file, content) { + this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(content) + return this.sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, this.lineBreakPositionsByContent[file]) + } + + /** + * Clear the cache + */ + clear () { + this.lineBreakPositionsByContent = {} + } + + /** + * called by plugin API + */ + activate () { + this.on('solidity', 'compilationFinished', () => { + this.clear() + }) + } +} diff --git a/libs/remix-core-plugin/tsconfig.json b/libs/remix-core-plugin/tsconfig.json new file mode 100644 index 0000000000..f14da61cdf --- /dev/null +++ b/libs/remix-core-plugin/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/libs/remix-core-plugin/tsconfig.lib.json b/libs/remix-core-plugin/tsconfig.lib.json new file mode 100644 index 0000000000..7e93feb2f8 --- /dev/null +++ b/libs/remix-core-plugin/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "commonjs", + "outDir": "../../dist/out-tsc", + "declaration": true, + "rootDir": "./src", + "types": ["node"] + }, + "exclude": ["**/*.spec.ts"], + "include": ["**/*.ts"] +} diff --git a/libs/remix-debug/package.json b/libs/remix-debug/package.json index bc1225aef4..6691d37d1d 100644 --- a/libs/remix-debug/package.json +++ b/libs/remix-debug/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/remix-debug", - "version": "0.5.2", + "version": "0.5.5", "description": "Tool to debug Ethereum transactions", "contributors": [ { @@ -18,17 +18,18 @@ ], "main": "src/index.js", "dependencies": { - "@ethereumjs/block": "^3.3.0", + "@ethereumjs/block": "^3.4.0", "@ethereumjs/common": "^2.2.0", - "@ethereumjs/tx": "^3.2.1", - "@ethereumjs/vm": "^5.4.1", + "@ethereumjs/tx": "^3.3.0", + "@ethereumjs/vm": "^5.5.0", "@remix-project/remix-astwalker": "^0.0.26", - "@remix-project/remix-lib": "^0.5.2", + "@remix-project/remix-lib": "^0.5.5", "async": "^2.6.2", "commander": "^2.19.0", "deep-equal": "^1.0.1", "ethereumjs-util": "^7.0.10", - "ethers": "^5.1.4", + "ethers": "^5.4.2", + "string-similarity": "^4.0.4", "web3": "^1.2.4" }, "devDependencies": { @@ -60,5 +61,5 @@ }, "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme", "typings": "src/index.d.ts", - "gitHead": "50b32cc20d2d4dcc793bf7de955957e073e5b5b8" + "gitHead": "df7abe1c219e361a947031d620f4ae6e3786a4d7" } \ No newline at end of file diff --git a/libs/remix-debug/src/code/codeManager.ts b/libs/remix-debug/src/code/codeManager.ts index f0b38ea3d9..241698f0fb 100644 --- a/libs/remix-debug/src/code/codeManager.ts +++ b/libs/remix-debug/src/code/codeManager.ts @@ -147,13 +147,17 @@ export class CodeManager { private async retrieveIndexAndTrigger (codeMananger, address, step, code) { let result - let next + const next = [] const returnInstructionIndexes = [] const outOfGasInstructionIndexes = [] try { result = codeMananger.getInstructionIndex(address, step) - next = codeMananger.getInstructionIndex(address, step + 1) + for (let i = 1; i < 6; i++) { + if (this.traceManager.inRange(step + i)) { + next.push(codeMananger.getInstructionIndex(address, step + i)) + } + } let values = this.traceManager.getAllStopIndexes() if (values) { diff --git a/libs/remix-debug/src/code/codeUtils.ts b/libs/remix-debug/src/code/codeUtils.ts index b44dd2be61..da777d4b71 100644 --- a/libs/remix-debug/src/code/codeUtils.ts +++ b/libs/remix-debug/src/code/codeUtils.ts @@ -46,7 +46,7 @@ type Opcode = { * information about the opcode. */ export function parseCode (raw) { - const common = new Common({ chain: 'mainnet', hardfork: 'berlin' }) + const common = new Common({ chain: 'mainnet', hardfork: 'london' }) const opcodes = getOpcodesForHF(common) const code = [] diff --git a/libs/remix-debug/src/debugger/VmDebugger.ts b/libs/remix-debug/src/debugger/VmDebugger.ts index 72a131cfd6..4304d2e933 100644 --- a/libs/remix-debug/src/debugger/VmDebugger.ts +++ b/libs/remix-debug/src/debugger/VmDebugger.ts @@ -59,8 +59,8 @@ export class VmDebuggerLogic { } listenToCodeManagerEvents () { - this._codeManager.event.register('changed', (code, address, index, nextIndex, returnInstructionIndexes, outOfGasInstructionIndexes) => { - this.event.trigger('codeManagerChanged', [code, address, index, nextIndex, returnInstructionIndexes, outOfGasInstructionIndexes]) + this._codeManager.event.register('changed', (code, address, index, nextIndexes, returnInstructionIndexes, outOfGasInstructionIndexes) => { + this.event.trigger('codeManagerChanged', [code, address, index, nextIndexes, returnInstructionIndexes, outOfGasInstructionIndexes]) }) } diff --git a/libs/remix-debug/src/eventManager.ts b/libs/remix-debug/src/eventManager.ts index 60e83b0a78..f878395ed3 100644 --- a/libs/remix-debug/src/eventManager.ts +++ b/libs/remix-debug/src/eventManager.ts @@ -67,7 +67,7 @@ export class EventManager { } for (const listener in this.registered[eventName]) { const l = this.registered[eventName][listener] - l.func.apply(l.obj === this.anonymous ? {} : l.obj, args) + if (l.func) l.func.apply(l.obj === this.anonymous ? {} : l.obj, args) } } } diff --git a/libs/remix-debug/src/solidity-decoder/types/util.ts b/libs/remix-debug/src/solidity-decoder/types/util.ts index 30748c9aca..cd83d1cd32 100644 --- a/libs/remix-debug/src/solidity-decoder/types/util.ts +++ b/libs/remix-debug/src/solidity-decoder/types/util.ts @@ -48,7 +48,7 @@ export async function extractHexValue (location, storageResolver, byteLength) { try { slotvalue = await readFromStorage(location.slot, storageResolver) } catch (e) { - return '0x' + return '' } return extractHexByteSlice(slotvalue, byteLength, location.offset) } diff --git a/libs/remix-debug/src/trace/traceManager.ts b/libs/remix-debug/src/trace/traceManager.ts index 848b3c57aa..49ba500889 100644 --- a/libs/remix-debug/src/trace/traceManager.ts +++ b/libs/remix-debug/src/trace/traceManager.ts @@ -40,7 +40,7 @@ export class TraceManager { const networkId = await this.web3.eth.net.getId() this.fork = execution.forkAt(networkId, tx.blockNumber) } catch (e) { - this.fork = 'berlin' + this.fork = 'london' console.log(`unable to detect fork, defaulting to ${this.fork}..`) console.error(e) } @@ -151,7 +151,7 @@ export class TraceManager { if (this.trace[stepIndex] && this.trace[stepIndex].stack) { // there's always a stack const stack = this.trace[stepIndex].stack.slice(0) stack.reverse() - return stack + return stack.map(el => el.startsWith('0x') ? el : '0x' + el) } else { throw new Error('no stack found') } diff --git a/libs/remix-debug/test/decoder/vmCall.ts b/libs/remix-debug/test/decoder/vmCall.ts index 89417ac698..a0d2040e7c 100644 --- a/libs/remix-debug/test/decoder/vmCall.ts +++ b/libs/remix-debug/test/decoder/vmCall.ts @@ -11,7 +11,7 @@ export function sendTx (vm, from, to, value, data, cb?) { return new Promise ((resolve, reject) => { var tx = new Tx({ nonce: new BN(from.nonce++), - gasPrice: new BN(1), + // gasPrice: new BN(1), gasLimit: new BN(3000000, 10), to: to, value: new BN(value, 10), diff --git a/libs/remix-debug/test/vmCall.ts b/libs/remix-debug/test/vmCall.ts index b3cd6bccf1..a640c4d1b8 100644 --- a/libs/remix-debug/test/vmCall.ts +++ b/libs/remix-debug/test/vmCall.ts @@ -9,7 +9,7 @@ var remixLib = require('@remix-project/remix-lib') function sendTx (vm, from, to, value, data, cb) { var tx = new Tx({ nonce: new BN(from.nonce++), - gasPrice: new BN(1), + // gasPrice: new BN(1), gasLimit: new BN(3000000, 10), to: to, value: new BN(value, 10), diff --git a/libs/remix-lib/package.json b/libs/remix-lib/package.json index fa032c739c..59a6770087 100644 --- a/libs/remix-lib/package.json +++ b/libs/remix-lib/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/remix-lib", - "version": "0.5.2", + "version": "0.5.5", "description": "Library to various Remix tools", "contributors": [ { @@ -14,14 +14,15 @@ ], "main": "src/index.js", "dependencies": { - "@ethereumjs/block": "^3.3.0", - "@ethereumjs/tx": "^3.2.1", - "@ethereumjs/vm": "^5.4.1", + "@ethereumjs/block": "^3.4.0", + "@ethereumjs/tx": "^3.3.0", + "@ethereumjs/vm": "^5.5.0", "async": "^2.1.2", "ethereumjs-util": "^7.0.10", "ethers": "^4.0.40", "events": "^3.0.0", "solc": "^0.7.4", + "string-similarity": "^4.0.4", "web3": "^1.2.4" }, "devDependencies": { @@ -52,5 +53,5 @@ }, "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme", "typings": "src/index.d.ts", - "gitHead": "50b32cc20d2d4dcc793bf7de955957e073e5b5b8" + "gitHead": "df7abe1c219e361a947031d620f4ae6e3786a4d7" } \ No newline at end of file diff --git a/libs/remix-lib/src/eventManager.ts b/libs/remix-lib/src/eventManager.ts index 80280e8b27..a67548f899 100644 --- a/libs/remix-lib/src/eventManager.ts +++ b/libs/remix-lib/src/eventManager.ts @@ -64,7 +64,7 @@ export class EventManager { } for (const listener in this.registered[eventName]) { const l = this.registered[eventName][listener] - l.func.apply(l.obj === this.anonymous ? {} : l.obj, args) + if (l.func) l.func.apply(l.obj === this.anonymous ? {} : l.obj, args) } } } diff --git a/libs/remix-lib/src/execution/forkAt.ts b/libs/remix-lib/src/execution/forkAt.ts index 5c4316f868..c5f1a1e981 100644 --- a/libs/remix-lib/src/execution/forkAt.ts +++ b/libs/remix-lib/src/execution/forkAt.ts @@ -17,7 +17,7 @@ export function forkAt (networkId, blockNumber) { } return currentForkName } - return 'berlin' + return 'london' } // see https://github.com/ethereum/go-ethereum/blob/master/params/config.go @@ -46,6 +46,10 @@ const forks = { { number: 12244000, name: 'berlin' + }, + { + number: 12965000, + name: 'london' } ], 3: [ diff --git a/libs/remix-lib/src/execution/txExecution.ts b/libs/remix-lib/src/execution/txExecution.ts index 792175a48c..f7e34333ee 100644 --- a/libs/remix-lib/src/execution/txExecution.ts +++ b/libs/remix-lib/src/execution/txExecution.ts @@ -112,18 +112,32 @@ export function checkVMError (execResult, abi, contract) { // "contract" reprensents the compilation result containing the NATSPEC documentation if (contract && fn.functions && Object.keys(fn.functions).length) { const functionSignature = Object.keys(fn.functions)[0] - // we check in the 'devdoc' if there's a developer documentation for this error - devdoc = contract.object.devdoc.errors[functionSignature][0] || {} - // we check in the 'userdoc' if there's an user documentation for this error - const userdoc = contract.object.userdoc.errors[functionSignature][0] || {} - if (userdoc) customError += ' : ' + (userdoc as any).notice // we append the user doc if any + // we check in the 'devdoc' if there's a developer documentation for this error + try { + devdoc = (contract.object.devdoc.errors && contract.object.devdoc.errors[functionSignature][0]) || {} + } catch (e) { + console.error(e.message) + } + // we check in the 'userdoc' if there's an user documentation for this error + try { + const userdoc = (contract.object.userdoc.errors && contract.object.userdoc.errors[functionSignature][0]) || {} + if (userdoc && (userdoc as any).notice) customError += ' : ' + (userdoc as any).notice // we append the user doc if any + } catch (e) { + console.error(e.message) + } } + let inputIndex = 0 for (const input of functionDesc.inputs) { - const v = decodedCustomErrorInputs[input.name] - decodedCustomErrorInputsClean[input.name] = { - value: v.toString ? v.toString() : v, - documentation: (devdoc as any).params[input.name] // we add the developer documentation for this input parameter if any + const inputKey = input.name || inputIndex + const v = decodedCustomErrorInputs[inputKey] + + decodedCustomErrorInputsClean[inputKey] = { + value: v.toString ? v.toString() : v + } + if (devdoc && (devdoc as any).params) { + decodedCustomErrorInputsClean[input.name].documentation = (devdoc as any).params[inputKey] // we add the developer documentation for this input parameter if any } + inputIndex++ } break } diff --git a/libs/remix-lib/src/execution/txRunnerVM.ts b/libs/remix-lib/src/execution/txRunnerVM.ts index ce079856fc..ac6e629b89 100644 --- a/libs/remix-lib/src/execution/txRunnerVM.ts +++ b/libs/remix-lib/src/execution/txRunnerVM.ts @@ -72,7 +72,7 @@ export class TxRunnerVM { } } - const EIP1559 = this.commonContext.hardfork() !== 'berlin' + const EIP1559 = this.commonContext.hardfork() !== 'berlin' // berlin is the only pre eip1559 fork that we handle. let tx if (!EIP1559) { tx = Transaction.fromTxData({ diff --git a/libs/remix-lib/src/execution/txRunnerWeb3.ts b/libs/remix-lib/src/execution/txRunnerWeb3.ts index b36aaffdcc..64500d01a3 100644 --- a/libs/remix-lib/src/execution/txRunnerWeb3.ts +++ b/libs/remix-lib/src/execution/txRunnerWeb3.ts @@ -15,8 +15,18 @@ export class TxRunnerWeb3 { this._api = api } - _executeTx (tx, gasPrice, api, promptCb, callback) { - if (gasPrice) tx.gasPrice = this.getWeb3().utils.toHex(gasPrice) + _executeTx (tx, txFee, api, promptCb, callback) { + if (txFee) { + if (txFee.baseFeePerGas) { + tx.maxPriorityFee = this.getWeb3().utils.toHex(this.getWeb3().utils.toWei(txFee.maxPriorityFee, 'gwei')) + tx.maxFee = this.getWeb3().utils.toHex(this.getWeb3().utils.toWei(txFee.maxFee, 'gwei')) + tx.type = 2 + } else { + tx.gasPrice = this.getWeb3().utils.toHex(this.getWeb3().utils.toWei(txFee.gasPrice, 'gwei')) + tx.type = 1 + } + } + if (api.personalMode()) { promptCb( (value) => { @@ -100,8 +110,8 @@ export class TxRunnerWeb3 { return } - confirmCb(network, tx, tx['gas'], (gasPrice) => { - return this._executeTx(tx, gasPrice, this._api, promptCb, callback) + confirmCb(network, tx, tx['gas'], (txFee) => { + return this._executeTx(tx, txFee, this._api, promptCb, callback) }, (error) => { callback(error) }) diff --git a/libs/remix-lib/src/init.ts b/libs/remix-lib/src/init.ts index 7e3d371715..43c68ee58f 100644 --- a/libs/remix-lib/src/init.ts +++ b/libs/remix-lib/src/init.ts @@ -12,23 +12,6 @@ export function extendWeb3 (web3) { this.extend(web3) } -export function setProvider (web3, url) { - web3.setProvider(new web3.providers.HttpProvider(url)) -} - -export function web3DebugNode (network) { - const web3DebugNodes = { - Main: 'https://gethmainnet.komputing.org', - Rinkeby: 'https://remix-rinkeby.ethdevops.io', - Ropsten: 'https://remix-ropsten.ethdevops.io', - Goerli: 'https://remix-goerli.ethdevops.io' - } - if (web3DebugNodes[network]) { - return this.loadWeb3(web3DebugNodes[network]) - } - return null -} - export function extend (web3) { if (!web3.extend) { return diff --git a/libs/remix-simulator/package.json b/libs/remix-simulator/package.json index 45653e3e64..5a99b8dd63 100644 --- a/libs/remix-simulator/package.json +++ b/libs/remix-simulator/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/remix-simulator", - "version": "0.2.2", + "version": "0.2.5", "description": "Ethereum IDE and tools for the web", "contributors": [ { @@ -14,11 +14,11 @@ ], "main": "src/index.js", "dependencies": { - "@ethereumjs/block": "^3.3.0", + "@ethereumjs/block": "^3.4.0", "@ethereumjs/common": "^2.2.0", - "@ethereumjs/tx": "^3.2.1", - "@ethereumjs/vm": "^5.4.1", - "@remix-project/remix-lib": "^0.5.2", + "@ethereumjs/tx": "^3.3.0", + "@ethereumjs/vm": "^5.5.0", + "@remix-project/remix-lib": "^0.5.5", "ansi-gray": "^0.1.1", "async": "^3.1.0", "body-parser": "^1.18.2", @@ -26,10 +26,11 @@ "commander": "^2.19.0", "cors": "^2.8.5", "ethereumjs-util": "^7.0.10", - "ethers": "^5.1.4", + "ethers": "^5.4.2", "express": "^4.16.3", "express-ws": "^4.0.0", "merge": "^1.2.0", + "string-similarity": "^4.0.4", "time-stamp": "^2.0.0", "web3": "^1.2.4" }, @@ -65,5 +66,5 @@ }, "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-simulator#readme", "typings": "src/index.d.ts", - "gitHead": "50b32cc20d2d4dcc793bf7de955957e073e5b5b8" + "gitHead": "df7abe1c219e361a947031d620f4ae6e3786a4d7" } \ No newline at end of file diff --git a/libs/remix-simulator/src/vm-context.ts b/libs/remix-simulator/src/vm-context.ts index 363e9ab50e..b9cb6a4151 100644 --- a/libs/remix-simulator/src/vm-context.ts +++ b/libs/remix-simulator/src/vm-context.ts @@ -99,7 +99,7 @@ export class VMContext { constructor (fork?) { this.blockGasLimitDefault = 4300000 this.blockGasLimit = this.blockGasLimitDefault - this.currentFork = fork || 'berlin' + this.currentFork = fork || 'london' this.currentVm = this.createVm(this.currentFork) this.blocks = {} this.latestBlockNumber = 0 diff --git a/libs/remix-solidity/package.json b/libs/remix-solidity/package.json index f6aee88583..a3974fd364 100644 --- a/libs/remix-solidity/package.json +++ b/libs/remix-solidity/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/remix-solidity", - "version": "0.4.2", + "version": "0.4.5", "description": "Tool to load and run Solidity compiler", "main": "index.js", "types": "./index.d.ts", @@ -15,15 +15,16 @@ } ], "dependencies": { - "@ethereumjs/block": "^3.3.0", - "@ethereumjs/tx": "^3.2.1", - "@ethereumjs/vm": "^5.4.1", - "@remix-project/remix-lib": "^0.5.2", + "@ethereumjs/block": "^3.4.0", + "@ethereumjs/tx": "^3.3.0", + "@ethereumjs/vm": "^5.5.0", + "@remix-project/remix-lib": "^0.5.5", "async": "^2.6.2", "eslint-scope": "^5.0.0", "ethereumjs-util": "^7.0.10", - "ethers": "^5.1.4", + "ethers": "^5.4.2", "solc": "^0.7.4", + "string-similarity": "^4.0.4", "web3": "1.2.4", "webworkify-webpack": "^2.1.5" }, @@ -58,5 +59,5 @@ }, "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-solidity#readme", "typings": "index.d.ts", - "gitHead": "50b32cc20d2d4dcc793bf7de955957e073e5b5b8" + "gitHead": "df7abe1c219e361a947031d620f4ae6e3786a4d7" } \ No newline at end of file diff --git a/libs/remix-solidity/src/compiler/compiler-abstract.ts b/libs/remix-solidity/src/compiler/compiler-abstract.ts new file mode 100644 index 0000000000..81cd33db28 --- /dev/null +++ b/libs/remix-solidity/src/compiler/compiler-abstract.ts @@ -0,0 +1,48 @@ +'use strict' +import txHelper from './txHelper' + +export class CompilerAbstract { + languageversion: any + data: any + source: any + constructor (languageversion, data, source) { + this.languageversion = languageversion + this.data = data + this.source = source // source code + } + + getContracts () { + return this.data.contracts + } + + getContract (name) { + return txHelper.getContract(name, this.data.contracts) + } + + visitContracts (calllback) { + return txHelper.visitContracts(this.data.contracts, calllback) + } + + getData () { + return this.data + } + + getAsts () { + return this.data.sources // ast + } + + getSourceName (fileIndex) { + if (this.data && this.data.sources) { + return Object.keys(this.data.sources)[fileIndex] + } else if (Object.keys(this.source.sources).length === 1) { + // if we don't have ast, we return the only one filename present. + const sourcesArray = Object.keys(this.source.sources) + return sourcesArray[0] + } + return null + } + + getSourceCode () { + return this.source + } +} diff --git a/apps/remix-ide/src/app/compiler/compiler-helpers.js b/libs/remix-solidity/src/compiler/compiler-helpers.ts similarity index 89% rename from apps/remix-ide/src/app/compiler/compiler-helpers.js rename to libs/remix-solidity/src/compiler/compiler-helpers.ts index db7d5988f3..8a70e6be4f 100644 --- a/apps/remix-ide/src/app/compiler/compiler-helpers.js +++ b/libs/remix-solidity/src/compiler/compiler-helpers.ts @@ -1,7 +1,7 @@ 'use strict' import { canUseWorker, urlFromVersion } from './compiler-utils' -import { Compiler } from '@remix-project/remix-solidity' -import CompilerAbstract from './compiler-abstract' +import { CompilerAbstract } from './compiler-abstract' +import { Compiler } from './compiler' export const compile = async (compilationTargets, settings, contentResolverCallback) => { const res = await (() => { diff --git a/apps/remix-ide/src/app/compiler/compiler-utils.js b/libs/remix-solidity/src/compiler/compiler-utils.ts similarity index 100% rename from apps/remix-ide/src/app/compiler/compiler-utils.js rename to libs/remix-solidity/src/compiler/compiler-utils.ts diff --git a/libs/remix-solidity/src/index.ts b/libs/remix-solidity/src/index.ts index cb204a8af6..7de163dc97 100644 --- a/libs/remix-solidity/src/index.ts +++ b/libs/remix-solidity/src/index.ts @@ -1,3 +1,6 @@ export { Compiler } from './compiler/compiler' +export { compile } from './compiler/compiler-helpers' export { default as CompilerInput } from './compiler/compiler-input' +export { CompilerAbstract } from './compiler/compiler-abstract' export * from './compiler/types' +export { promisedMiniXhr, pathToURL, baseURLBin, baseURLWasm, canUseWorker, urlFromVersion } from './compiler/compiler-utils' diff --git a/libs/remix-solidity/src/lib/eventManager.ts b/libs/remix-solidity/src/lib/eventManager.ts index 289b2ec4eb..8282e09b6c 100644 --- a/libs/remix-solidity/src/lib/eventManager.ts +++ b/libs/remix-solidity/src/lib/eventManager.ts @@ -62,7 +62,7 @@ export default class EventManager { } for (const listener in this.registered[eventName]) { const l = this.registered[eventName][listener] - l.func.apply(l.obj === this.anonymous ? {} : l.obj, args) + if (l.func) l.func.apply(l.obj === this.anonymous ? {} : l.obj, args) } } } diff --git a/libs/remix-tests/package.json b/libs/remix-tests/package.json index 4b3559dfc9..b07486c5ad 100644 --- a/libs/remix-tests/package.json +++ b/libs/remix-tests/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/remix-tests", - "version": "0.2.2", + "version": "0.2.5", "description": "Tool to test Solidity smart contracts", "main": "src/index.js", "types": "./src/index.d.ts", @@ -35,13 +35,13 @@ }, "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-tests#readme", "dependencies": { - "@ethereumjs/block": "^3.3.0", + "@ethereumjs/block": "^3.4.0", "@ethereumjs/common": "^2.2.0", - "@ethereumjs/tx": "^3.2.1", - "@ethereumjs/vm": "^5.4.1", - "@remix-project/remix-lib": "^0.5.2", - "@remix-project/remix-simulator": "^0.2.2", - "@remix-project/remix-solidity": "^0.4.2", + "@ethereumjs/tx": "^3.3.0", + "@ethereumjs/vm": "^5.5.0", + "@remix-project/remix-lib": "^0.5.5", + "@remix-project/remix-simulator": "^0.2.5", + "@remix-project/remix-solidity": "^0.4.5", "ansi-gray": "^0.1.1", "async": "^2.6.0", "axios": ">=0.21.1", @@ -50,10 +50,11 @@ "colors": "^1.1.2", "commander": "^2.13.0", "ethereumjs-util": "^7.0.10", - "ethers": "^5.1.4", + "ethers": "^5.4.2", "express-ws": "^4.0.0", "merge": "^1.2.0", "signale": "^1.4.0", + "string-similarity": "^4.0.4", "time-stamp": "^2.2.0", "tslib": "^2.3.0", "web3": "^1.2.4", @@ -76,5 +77,5 @@ "typescript": "^3.3.1" }, "typings": "src/index.d.ts", - "gitHead": "50b32cc20d2d4dcc793bf7de955957e073e5b5b8" + "gitHead": "df7abe1c219e361a947031d620f4ae6e3786a4d7" } \ No newline at end of file diff --git a/libs/remix-ui/checkbox/src/lib/remix-ui-checkbox.tsx b/libs/remix-ui/checkbox/src/lib/remix-ui-checkbox.tsx index 5535a05971..95913e533b 100644 --- a/libs/remix-ui/checkbox/src/lib/remix-ui-checkbox.tsx +++ b/libs/remix-ui/checkbox/src/lib/remix-ui-checkbox.tsx @@ -1,4 +1,4 @@ -import React from 'react' //eslint-disable-line +import React, { CSSProperties } from 'react' //eslint-disable-line import './remix-ui-checkbox.css' /* eslint-disable-next-line */ @@ -12,6 +12,8 @@ export interface RemixUiCheckboxProps { id?: string itemName?: string categoryId?: string + visibility?: string + display?: string } export const RemixUiCheckbox = ({ @@ -23,10 +25,12 @@ export const RemixUiCheckbox = ({ checked, onChange, itemName, - categoryId + categoryId, + visibility, + display = 'flex' }: RemixUiCheckboxProps) => { return ( -
+
{ +interface ICopyToClipboard { + content: any, + tip?: string, + icon?: string, + direction?: Placement, + className?: string, + title?: string, + children?: JSX.Element +} +export const CopyToClipboard = (props: ICopyToClipboard) => { + let { content, tip = 'Copy', icon = 'fa-copy', direction = 'right', children, ...otherProps } = props const [message, setMessage] = useState(tip) - - const handleClick = (event) => { + const handleClick = (e) => { if (content && content !== '') { // module `copy` keeps last copied thing in the memory, so don't show tooltip if nothing is copied, because nothing was added to memory try { if (typeof content !== 'string') { content = JSON.stringify(content, null, '\t') } + copy(content) + setMessage('Copied') } catch (e) { console.error(e) } - copy(content) - setMessage('Copied') } else { setMessage('Cannot copy empty content!') } - event.preventDefault() + e.preventDefault() return false } @@ -30,15 +40,18 @@ export const CopyToClipboard = ({ content, tip='Copy', icon='fa-copy', ...otherP } return ( + // eslint-disable-next-line jsx-a11y/anchor-is-valid - { message } }> - + { + children || () + } ) diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/assembly-items.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/assembly-items.tsx index 1606ce8491..806f826917 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/assembly-items.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/assembly-items.tsx @@ -6,15 +6,15 @@ export const AssemblyItems = ({ registerEvent }) => { const [assemblyItems, dispatch] = useReducer(reducer, initialState) const [absoluteSelectedIndex, setAbsoluteSelectedIndex] = useState(0) const [selectedItem, setSelectedItem] = useState(0) - const [nextSelectedItem, setNextSelectedItem] = useState(1) + const [nextSelectedItems, setNextSelectedItems] = useState([1]) const [returnInstructionIndexes, setReturnInstructionIndexes] = useState([]) const [outOfGasInstructionIndexes, setOutOfGasInstructionIndexes] = useState([]) const refs = useRef({}) const asmItemsRef = useRef(null) useEffect(() => { - registerEvent && registerEvent('codeManagerChanged', (code, address, index, nextIndex, returnInstructionIndexes, outOfGasInstructionIndexes) => { - dispatch({ type: 'FETCH_OPCODES_SUCCESS', payload: { code, address, index, nextIndex, returnInstructionIndexes, outOfGasInstructionIndexes } }) + registerEvent && registerEvent('codeManagerChanged', (code, address, index, nextIndexes, returnInstructionIndexes, outOfGasInstructionIndexes) => { + dispatch({ type: 'FETCH_OPCODES_SUCCESS', payload: { code, address, index, nextIndexes, returnInstructionIndexes, outOfGasInstructionIndexes } }) }) }, []) @@ -22,7 +22,7 @@ export const AssemblyItems = ({ registerEvent }) => { if (absoluteSelectedIndex !== assemblyItems.index) { clearItems() indexChanged(assemblyItems.index) - nextIndexChanged(assemblyItems.nextIndex) + nextIndexesChanged(assemblyItems.nextIndexes) returnIndexes(assemblyItems.returnInstructionIndexes) outOfGasIndexes(assemblyItems.outOfGasInstructionIndexes) } @@ -40,7 +40,11 @@ export const AssemblyItems = ({ registerEvent }) => { const clearItems = () => { clearItem(refs.current[selectedItem] ? refs.current[selectedItem] : null) - clearItem(refs.current[nextSelectedItem] ? refs.current[nextSelectedItem] : null) + if (nextSelectedItems) { + nextSelectedItems.map((index) => { + clearItem(refs.current[index] ? refs.current[index] : null) + }) + } returnInstructionIndexes.map((index) => { if (index < 0) return @@ -70,18 +74,20 @@ export const AssemblyItems = ({ registerEvent }) => { setAbsoluteSelectedIndex(assemblyItems.opCodes.index) } - const nextIndexChanged = (index: number) => { - if (index < 0) return + const nextIndexesChanged = (indexes: Array) => { + indexes.map((index) => { + if (index < 0) return - const codeView = asmItemsRef.current + const codeView = asmItemsRef.current - const currentItem = codeView.children[index] - if (currentItem) { - currentItem.style.setProperty('border-color', 'var(--secondary)') - currentItem.style.setProperty('border-style', 'dotted') - currentItem.setAttribute('selected', 'selected') - } - setNextSelectedItem(index) + const currentItem = codeView.children[index] + if (currentItem) { + currentItem.style.setProperty('color', 'var(--primary)') + currentItem.style.setProperty('font-weight', 'bold') + currentItem.setAttribute('selected', 'selected') + } + }) + setNextSelectedItems(indexes) } const returnIndexes = (indexes) => { diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-state.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-state.tsx index 0bc60b9a3f..c30569b307 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-state.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-state.tsx @@ -5,32 +5,36 @@ import { ExtractData } from '../../types' // eslint-disable-line export const SolidityState = ({ calldata, message }) => { const formatSelf = (key: string, data: ExtractData) => { - let color = 'var(--primary)' - if (data.isArray || data.isStruct || data.isMapping) { - color = 'var(--info)' - } else if ( - data.type.indexOf('uint') === 0 || + try { + let color = 'var(--primary)' + if (data.isArray || data.isStruct || data.isMapping) { + color = 'var(--info)' + } else if ( + data.type.indexOf('uint') === 0 || data.type.indexOf('int') === 0 || data.type.indexOf('bool') === 0 || data.type.indexOf('enum') === 0 - ) { - color = 'var(--green)' - } else if (data.type === 'string') { - color = 'var(--teal)' + ) { + color = 'var(--green)' + } else if (data.type === 'string') { + color = 'var(--teal)' } else if (data.self == 0x0) { // eslint-disable-line - color = 'var(--gray)' - } - return ( -
{Object.keys(groupedModules).map((categoryId, i) => { @@ -318,7 +448,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { }
- last results for: + Last results for: { {state.file}
+
{Object.entries(warningState).length > 0 &&
@@ -333,9 +464,9 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { (Object.entries(warningState).map((element, index) => (
{element[0]} - {element[1].map((x, i) => ( - x.hasWarning ? ( -
+ {element[1]['map']((x, i) => ( // eslint-disable-line dot-notation + x.hasWarning ? ( // eslint-disable-next-line dot-notation +
diff --git a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.css b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.css index f190b84fac..534da8bca6 100644 --- a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.css +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.css @@ -11,6 +11,7 @@ position : relative; width : 100%; padding-left : 6px; + padding-right : 6px; padding-top : 6px; } .remixui_fileExplorerTree { diff --git a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx index 6a85a0febf..49676c2b08 100644 --- a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx @@ -3,6 +3,7 @@ import { FileExplorer } from '@remix-ui/file-explorer' // eslint-disable-line import './remix-ui-workspace.css' import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line import { Toaster } from '@remix-ui/toaster'// eslint-disable-line +import { MenuItems } from 'libs/remix-ui/file-explorer/src/lib/types' /* eslint-disable-next-line */ export interface WorkspaceProps { @@ -20,7 +21,8 @@ export interface WorkspaceProps { plugin: any // plugin call and resetFocus request: any // api request, workspaces: any, - registeredMenuItems: [] // menu items + registeredMenuItems: MenuItems // menu items + removedMenuItems: MenuItems initialWorkspace: string } @@ -409,6 +411,7 @@ export const Workspace = (props: WorkspaceProps) => { plugin={props.plugin} focusRoot={state.reset} contextMenuItems={props.registeredMenuItems} + removedContextMenuItems={props.removedMenuItems} displayInput={state.displayNewFile} externalUploads={state.uploadFileEvent} /> @@ -426,6 +429,7 @@ export const Workspace = (props: WorkspaceProps) => { plugin={props.plugin} focusRoot={state.reset} contextMenuItems={props.registeredMenuItems} + removedContextMenuItems={props.removedMenuItems} /> }
diff --git a/libs/remix-url-resolver/package.json b/libs/remix-url-resolver/package.json index e5d8376d62..a9b6770890 100644 --- a/libs/remix-url-resolver/package.json +++ b/libs/remix-url-resolver/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/remix-url-resolver", - "version": "0.0.23", + "version": "0.0.26", "description": "Solidity import url resolver engine", "main": "index.js", "types": "./index.d.ts", @@ -42,5 +42,5 @@ "typescript": "^3.1.6" }, "typings": "index.d.ts", - "gitHead": "50b32cc20d2d4dcc793bf7de955957e073e5b5b8" + "gitHead": "df7abe1c219e361a947031d620f4ae6e3786a4d7" } \ No newline at end of file diff --git a/libs/remix-url-resolver/src/resolve.ts b/libs/remix-url-resolver/src/resolve.ts index 13029cefbd..38076686a2 100644 --- a/libs/remix-url-resolver/src/resolve.ts +++ b/libs/remix-url-resolver/src/resolve.ts @@ -30,6 +30,10 @@ export class RemixURLResolver { constructor (gistToken?: string, protocol = 'http:') { this.previouslyHandled = {} + this.setGistToken(gistToken, protocol) + } + + async setGistToken (gistToken?: string, protocol = 'http:') { this.gistAccessToken = gistToken || '' this.protocol = protocol } @@ -109,7 +113,7 @@ export class RemixURLResolver { url = url.replace(/^ipfs:\/\/?/, 'ipfs/') // eslint-disable-next-line no-useless-catch try { - const req = 'https://ipfsgw.komputing.org/' + url + const req = 'https://ipfs.remixproject.org/' + url // If you don't find greeter.sol on ipfs gateway use local // const req = 'http://localhost:8080/' + url const response: AxiosResponse = await axios.get(req) diff --git a/libs/remixd/package.json b/libs/remixd/package.json index f65ed19606..6f9123c651 100644 --- a/libs/remixd/package.json +++ b/libs/remixd/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/remixd", - "version": "0.4.1", + "version": "0.5.0", "description": "remix server: allow accessing file system from remix.ethereum.org and start a dev environment (see help section)", "main": "index.js", "types": "./index.d.ts", diff --git a/libs/remixd/src/bin/remixd.ts b/libs/remixd/src/bin/remixd.ts index 2085735b8c..623fa5ef97 100644 --- a/libs/remixd/src/bin/remixd.ts +++ b/libs/remixd/src/bin/remixd.ts @@ -25,6 +25,7 @@ async function warnLatestVersion () { const services = { git: (readOnly: boolean) => new servicesList.GitClient(readOnly), hardhat: (readOnly: boolean) => new servicesList.HardhatClient(readOnly), + slither: (readOnly: boolean) => new servicesList.SlitherClient(readOnly), folder: (readOnly: boolean) => new servicesList.Sharedfolder(readOnly) } @@ -32,11 +33,12 @@ const services = { const ports = { git: 65521, hardhat: 65522, + slither: 65523, folder: 65520 } const killCallBack: Array = [] -function startService (service: S, callback: (ws: WS, sharedFolderClient: servicesList.Sharedfolder, error?:Error) => void) { +function startService (service: S, callback: (ws: WS, sharedFolderClient: servicesList.Sharedfolder, error?:Error) => void) { const socket = new WebSocket(ports[service], { remixIdeUrl: program.remixIde }, () => services[service](program.readOnly || false)) socket.start(callback) killCallBack.push(socket.close.bind(socket)) @@ -94,6 +96,10 @@ function errorHandler (error: any, service: string) { sharedFolderClient.setupNotifications(program.sharedFolder) sharedFolderClient.sharedFolder(program.sharedFolder) }) + startService('slither', (ws: WS, sharedFolderClient: servicesList.Sharedfolder) => { + sharedFolderClient.setWebSocket(ws) + sharedFolderClient.sharedFolder(program.sharedFolder) + }) // Run hardhat service if a hardhat project is shared as folder const hardhatConfigFilePath = absolutePath('./', program.sharedFolder) + '/hardhat.config.js' const isHardhatProject = fs.existsSync(hardhatConfigFilePath) diff --git a/libs/remixd/src/index.ts b/libs/remixd/src/index.ts index 849f35b6fa..8b35cea6dd 100644 --- a/libs/remixd/src/index.ts +++ b/libs/remixd/src/index.ts @@ -2,6 +2,7 @@ import { RemixdClient as sharedFolder } from './services/remixdClient' import { GitClient } from './services/gitClient' import { HardhatClient } from './services/hardhatClient' +import { SlitherClient } from './services/slitherClient' import Websocket from './websocket' import * as utils from './utils' @@ -11,6 +12,7 @@ module.exports = { services: { sharedFolder, GitClient, - HardhatClient + HardhatClient, + SlitherClient } } diff --git a/libs/remixd/src/origins.json b/libs/remixd/src/origins.json index d91e2f8a61..5a3331f3c7 100644 --- a/libs/remixd/src/origins.json +++ b/libs/remixd/src/origins.json @@ -6,6 +6,7 @@ "https://remix.ethereum.org", "package://a7df6d3c223593f3550b35e90d7b0b1f.mod", "package://6fd22d6fe5549ad4c4d8fd3ca0b7816b.mod", - "https://ipfsgw.komputing.org" + "https://ipfsgw.komputing.org", + "https://ipfs.remixproject.org" ] } \ No newline at end of file diff --git a/libs/remixd/src/serviceList.ts b/libs/remixd/src/serviceList.ts index 19d613b7c2..ec8c1f374d 100644 --- a/libs/remixd/src/serviceList.ts +++ b/libs/remixd/src/serviceList.ts @@ -1,3 +1,4 @@ export { RemixdClient as Sharedfolder } from './services/remixdClient' export { GitClient } from './services/gitClient' export { HardhatClient } from './services/hardhatClient' +export { SlitherClient } from './services/slitherClient' diff --git a/libs/remixd/src/services/remixdClient.ts b/libs/remixd/src/services/remixdClient.ts index 31588628ea..8645caf4ac 100644 --- a/libs/remixd/src/services/remixdClient.ts +++ b/libs/remixd/src/services/remixdClient.ts @@ -180,12 +180,34 @@ export class RemixdClient extends PluginClient { if (!fs.existsSync(path)) return reject(new Error('File not found ' + path)) if (!isRealPath(path)) return + // Saving the content of the item{folder} before removing it + const ls = [] + try { + const resolveList = (path) => { + if (!this._isFile(path)) { + const list = utils.resolveDirectory(path, this.currentSharedFolder) + Object.keys(list).forEach(itemPath => { + if (list[itemPath].isDirectory) { + resolveList(`${this.currentSharedFolder}/${itemPath}`) + } + ls.push(itemPath) + }) + } + } + resolveList(path) + ls.push(args.path) + } catch (e) { + throw new Error(e) + } return fs.remove(path, (error: Error) => { if (error) { console.log(error) return reject(new Error('Failed to remove file/directory: ' + error)) } - this.emit('fileRemoved', args.path) + for (const file in ls) { + this.emit('fileRemoved', ls[file]) + } + resolve(true) }) }) @@ -194,10 +216,17 @@ export class RemixdClient extends PluginClient { } } + _isFile (path: string): boolean { + try { + return fs.statSync(path).isFile() + } catch (error) { + throw new Error(error) + } + } + isDirectory (args: SharedFolderArgs): boolean { try { const path = utils.absolutePath(args.path, this.currentSharedFolder) - return fs.statSync(path).isDirectory() } catch (error) { throw new Error(error) @@ -207,7 +236,6 @@ export class RemixdClient extends PluginClient { isFile (args: SharedFolderArgs): boolean { try { const path = utils.absolutePath(args.path, this.currentSharedFolder) - return fs.statSync(path).isFile() } catch (error) { throw new Error(error) diff --git a/libs/remixd/src/services/slitherClient.ts b/libs/remixd/src/services/slitherClient.ts new file mode 100644 index 0000000000..a0808d281f --- /dev/null +++ b/libs/remixd/src/services/slitherClient.ts @@ -0,0 +1,162 @@ +/* eslint dot-notation: "off" */ + +import * as WS from 'ws' // eslint-disable-line +import { PluginClient } from '@remixproject/plugin' +import { existsSync, readFileSync, readdirSync } from 'fs' +import { OutputStandard } from '../types' // eslint-disable-line +const { spawn, execSync } = require('child_process') + +export class SlitherClient extends PluginClient { + methods: Array + websocket: WS + currentSharedFolder: string + + constructor (private readOnly = false) { + super() + this.methods = ['analyse'] + } + + setWebSocket (websocket: WS): void { + this.websocket = websocket + } + + sharedFolder (currentSharedFolder: string): void { + this.currentSharedFolder = currentSharedFolder + } + + mapNpmDepsDir (list) { + const remixNpmDepsPath = `${this.currentSharedFolder}/.deps/npm` + const localNpmDepsPath = `${this.currentSharedFolder}/node_modules` + const npmDepsExists = existsSync(remixNpmDepsPath) + const nodeModulesExists = existsSync(localNpmDepsPath) + let isLocalDep = false + let isRemixDep = false + let allowPathString = '' + let remapString = '' + + for (const e of list) { + const importPath = e.replace(/import ['"]/g, '').trim() + const packageName = importPath.split('/')[0] + if (nodeModulesExists && readdirSync(localNpmDepsPath).includes(packageName)) { + isLocalDep = true + remapString += `${packageName}=./node_modules/${packageName} ` + } else if (npmDepsExists && readdirSync(remixNpmDepsPath).includes(packageName)) { + isRemixDep = true + remapString += `${packageName}=./.deps/npm/${packageName} ` + } + } + if (isLocalDep) allowPathString += './node_modules,' + if (isRemixDep) allowPathString += './.deps/npm,' + + return { remapString, allowPathString } + } + + transform (detectors: Record[]): OutputStandard[] { + const standardReport: OutputStandard[] = [] + for (const e of detectors) { + const obj = {} as OutputStandard + obj.description = e.description + obj.title = e.check + obj.confidence = e.confidence + obj.severity = e.impact + obj.sourceMap = e.elements.map((element) => { + delete element.source_mapping.filename_used + delete element.source_mapping.filename_absolute + return element + }) + standardReport.push(obj) + } + return standardReport + } + + analyse (filePath: string, compilerConfig: Record) { + return new Promise((resolve, reject) => { + if (this.readOnly) { + const errMsg: string = '[Slither Analysis]: Cannot analyse in read-only mode' + return reject(new Error(errMsg)) + } + const options = { cwd: this.currentSharedFolder, shell: true } + const { currentVersion, optimize, evmVersion } = compilerConfig + if (currentVersion && currentVersion.includes('+commit')) { + // Get compiler version with commit id e.g: 0.8.2+commit.661d110 + const versionString: string = currentVersion.substring(0, currentVersion.indexOf('+commit') + 16) + console.log('\x1b[32m%s\x1b[0m', `[Slither Analysis]: Compiler version is ${versionString}`) + let solcOutput: Buffer + // Check solc current installed version + try { + solcOutput = execSync('solc --version', options) + } catch (err) { + console.log(err) + reject(new Error('Error in running solc command')) + } + if (!solcOutput.toString().includes(versionString)) { + console.log('\x1b[32m%s\x1b[0m', '[Slither Analysis]: Compiler version is different from installed solc version') + // Get compiler version without commit id e.g: 0.8.2 + const version: string = versionString.substring(0, versionString.indexOf('+commit')) + // List solc versions installed using solc-select + try { + const solcSelectInstalledVersions: Buffer = execSync('solc-select versions', options) + // Check if required version is already installed + if (!solcSelectInstalledVersions.toString().includes(version)) { + console.log('\x1b[32m%s\x1b[0m', `[Slither Analysis]: Installing ${version} using solc-select`) + // Install required version + execSync(`solc-select install ${version}`, options) + } + console.log('\x1b[32m%s\x1b[0m', `[Slither Analysis]: Setting ${version} as current solc version using solc-select`) + // Set solc current version as required version + execSync(`solc-select use ${version}`, options) + } catch (err) { + console.log(err) + reject(new Error('Error in running solc-select command')) + } + } else console.log('\x1b[32m%s\x1b[0m', '[Slither Analysis]: Compiler version is same as installed solc version') + } + // Allow paths and set solc remapping for import URLs + const fileContent = readFileSync(`${this.currentSharedFolder}/${filePath}`, 'utf8') + const importsArr = fileContent.match(/import ['"][^.|..](.+?)['"];/g) + let allowPaths = ''; let remaps = '' + if (importsArr?.length) { + const { remapString, allowPathString } = this.mapNpmDepsDir(importsArr) + allowPaths = allowPathString + remaps = remapString.trim() + } + const allowPathsOption: string = allowPaths ? `--allow-paths ${allowPaths} ` : '' + const optimizeOption: string = optimize ? '--optimize ' : '' + const evmOption: string = evmVersion ? `--evm-version ${evmVersion}` : '' + const solcArgs: string = optimizeOption || evmOption || allowPathsOption ? `--solc-args '${allowPathsOption}${optimizeOption}${evmOption}'` : '' + const solcRemaps = remaps ? `--solc-remaps "${remaps}"` : '' + + const outputFile: string = 'remix-slitherReport_' + Math.floor(Date.now() / 1000) + '.json' + const cmd: string = `slither ${filePath} ${solcArgs} ${solcRemaps} --json ${outputFile}` + console.log('\x1b[32m%s\x1b[0m', '[Slither Analysis]: Running Slither...') + // Added `stdio: 'ignore'` as for contract with NPM imports analysis which is exported in 'stderr' + // get too big and hangs the process. We process analysis from the report file only + const child = spawn(cmd, { cwd: this.currentSharedFolder, shell: true, stdio: 'ignore' }) + + const response = {} + child.on('close', () => { + const outputFileAbsPath: string = `${this.currentSharedFolder}/${outputFile}` + // Check if slither report file exists + if (existsSync(outputFileAbsPath)) { + let report = readFileSync(outputFileAbsPath, 'utf8') + report = JSON.parse(report) + if (report['success']) { + response['status'] = true + if (!report['results'] || !report['results'].detectors || !report['results'].detectors.length) { + response['count'] = 0 + } else { + const { detectors } = report['results'] + response['count'] = detectors.length + response['data'] = this.transform(detectors) + } + console.log('\x1b[32m%s\x1b[0m', `[Slither Analysis]: Analysis Completed!! ${response['count']} warnings found.`) + resolve(response) + } else { + console.log(report['error']) + reject(new Error('Error in running Slither Analysis.')) + } + } else reject(new Error('Error in generating Slither Analysis Report. Make sure Slither is properly installed.')) + }) + }) + } +} diff --git a/libs/remixd/src/types/index.ts b/libs/remixd/src/types/index.ts index cde06fcf07..66818dff48 100644 --- a/libs/remixd/src/types/index.ts +++ b/libs/remixd/src/types/index.ts @@ -1,6 +1,18 @@ import * as ServiceList from '../serviceList' import * as Websocket from 'ws' +export interface OutputStandard { + description: string + title: string + confidence: string + severity: string + sourceMap: any + category?: string + reference?: string + example?: any + [key: string]: any +} + type ServiceListKeys = keyof typeof ServiceList; export type Service = typeof ServiceList[ServiceListKeys] diff --git a/libs/remixd/src/websocket.ts b/libs/remixd/src/websocket.ts index 370dc48abb..324fa3332b 100644 --- a/libs/remixd/src/websocket.ts +++ b/libs/remixd/src/websocket.ts @@ -19,7 +19,8 @@ export default class WebSocket { const listeners = { 65520: 'remixd', 65521: 'git', - 65522: 'hardhat' + 65522: 'hardhat', + 65523: 'slither' } this.server.on('error', (error: Error) => { diff --git a/nx.json b/nx.json index 7243217040..2e74e811c4 100644 --- a/nx.json +++ b/nx.json @@ -106,6 +106,17 @@ "tags": [] }, "remix-ui-plugin-manager": { + + "remix-core-plugin": { + "tags": [] + }, + "remix-ui-solidity-compiler": { + "tags": [] + }, + "remix-ui-publish-to-storage": { + "tags": [] + }, + "remix-ui-renderer": { "tags": [] } } diff --git a/package-lock.json b/package-lock.json index db383a4010..e9014811b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "remix-project", - "version": "0.14.0-dev", + "version": "0.17.0-dev", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2559,32 +2559,73 @@ } }, "@ethereumjs/block": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/block/-/block-3.3.0.tgz", - "integrity": "sha512-WoefY9Rs4W8vZTxG9qwntAlV61xsSv0NPoXmHO7x3SH16dwJQtU15YvahPCz4HEEXbu7GgGgNgu0pv8JY7VauA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/block/-/block-3.4.0.tgz", + "integrity": "sha512-umKAoTX32yXzErpIksPHodFc/5y8bmZMnOl6hWy5Vd8xId4+HKFUOyEiN16Y97zMwFRysRpcrR6wBejfqc6Bmg==", "requires": { - "@ethereumjs/common": "^2.3.0", - "@ethereumjs/tx": "^3.2.0", - "ethereumjs-util": "^7.0.10", + "@ethereumjs/common": "^2.4.0", + "@ethereumjs/tx": "^3.3.0", + "ethereumjs-util": "^7.1.0", "merkle-patricia-tree": "^4.2.0" + }, + "dependencies": { + "@types/bn.js": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", + "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", + "requires": { + "@types/node": "*" + } + }, + "bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + }, + "ethereumjs-util": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.0.tgz", + "integrity": "sha512-kR+vhu++mUDARrsMMhsjjzPduRVAeundLGXucGRHF3B4oEltOUspfgCVco4kckucj3FMlLaZHUl9n7/kdmr6Tw==", + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.4" + } + } } }, "@ethereumjs/blockchain": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/blockchain/-/blockchain-5.3.0.tgz", - "integrity": "sha512-B0Y5QDZcRDQISPilv3m8nzk97QmC98DnSE9WxzGpCxfef22Mw7xhwGipci5Iy0dVC2Np2Cr5d3F6bHAR7+yVmQ==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/blockchain/-/blockchain-5.4.0.tgz", + "integrity": "sha512-wAuKLaew6PL52kH8YPXO7PbjjKV12jivRSyHQehkESw4slSLLfYA6Jv7n5YxyT2ajD7KNMPVh7oyF/MU6HcOvg==", "requires": { - "@ethereumjs/block": "^3.3.0", - "@ethereumjs/common": "^2.3.0", + "@ethereumjs/block": "^3.4.0", + "@ethereumjs/common": "^2.4.0", "@ethereumjs/ethash": "^1.0.0", "debug": "^2.2.0", - "ethereumjs-util": "^7.0.10", + "ethereumjs-util": "^7.1.0", "level-mem": "^5.0.1", "lru-cache": "^5.1.1", "rlp": "^2.2.4", "semaphore-async-await": "^1.5.1" }, "dependencies": { + "@types/bn.js": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", + "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", + "requires": { + "@types/node": "*" + } + }, + "bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -2593,6 +2634,19 @@ "ms": "2.0.0" } }, + "ethereumjs-util": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.0.tgz", + "integrity": "sha512-kR+vhu++mUDARrsMMhsjjzPduRVAeundLGXucGRHF3B4oEltOUspfgCVco4kckucj3FMlLaZHUl9n7/kdmr6Tw==", + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.4" + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -2601,12 +2655,40 @@ } }, "@ethereumjs/common": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.3.1.tgz", - "integrity": "sha512-V8hrULExoq0H4HFs3cCmdRGbgmipmlNzak6Xg34nHYfQyqkSdrCuflvYjyWmsNpI8GtrcZhzifAbgX/1C1Cjwg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.4.0.tgz", + "integrity": "sha512-UdkhFWzWcJCZVsj1O/H8/oqj/0RVYjLc1OhPjBrQdALAkQHpCp8xXI4WLnuGTADqTdJZww0NtgwG+TRPkXt27w==", "requires": { "crc-32": "^1.2.0", - "ethereumjs-util": "^7.0.10" + "ethereumjs-util": "^7.1.0" + }, + "dependencies": { + "@types/bn.js": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", + "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", + "requires": { + "@types/node": "*" + } + }, + "bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + }, + "ethereumjs-util": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.0.tgz", + "integrity": "sha512-kR+vhu++mUDARrsMMhsjjzPduRVAeundLGXucGRHF3B4oEltOUspfgCVco4kckucj3FMlLaZHUl9n7/kdmr6Tw==", + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.4" + } + } } }, "@ethereumjs/ethash": { @@ -2631,27 +2713,55 @@ } }, "@ethereumjs/tx": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.2.1.tgz", - "integrity": "sha512-i9V39OtKvwWos1uVNZxdVhd7zFOyzFLjgt69CoiOY0EmXugS0HjO3uxpLBSglDKFMRriuGqw6ddKEv+RP1UNEw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.3.0.tgz", + "integrity": "sha512-yTwEj2lVzSMgE6Hjw9Oa1DZks/nKTWM8Wn4ykDNapBPua2f4nXO3qKnni86O6lgDj5fVNRqbDsD0yy7/XNGDEA==", "requires": { - "@ethereumjs/common": "^2.3.1", - "ethereumjs-util": "^7.0.10" + "@ethereumjs/common": "^2.4.0", + "ethereumjs-util": "^7.1.0" + }, + "dependencies": { + "@types/bn.js": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", + "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", + "requires": { + "@types/node": "*" + } + }, + "bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + }, + "ethereumjs-util": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.0.tgz", + "integrity": "sha512-kR+vhu++mUDARrsMMhsjjzPduRVAeundLGXucGRHF3B4oEltOUspfgCVco4kckucj3FMlLaZHUl9n7/kdmr6Tw==", + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.4" + } + } } }, "@ethereumjs/vm": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/@ethereumjs/vm/-/vm-5.4.1.tgz", - "integrity": "sha512-cpQcg5CtjzXJBn8QNiobaiWckeN/ZQwsDHLYa9df2wBEUvzuEZgFWK48YEXSpx3CnUY9fNT/lgA9CzKdq8HTzQ==", - "requires": { - "@ethereumjs/block": "^3.3.0", - "@ethereumjs/blockchain": "^5.3.0", - "@ethereumjs/common": "^2.3.1", - "@ethereumjs/tx": "^3.2.1", + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/vm/-/vm-5.5.2.tgz", + "integrity": "sha512-AydZ4wfvZAsBuFzs3xVSA2iU0hxhL8anXco3UW3oh9maVC34kTEytOfjHf06LTEfN0MF9LDQ4ciLa7If6ZN/sg==", + "requires": { + "@ethereumjs/block": "^3.4.0", + "@ethereumjs/blockchain": "^5.4.0", + "@ethereumjs/common": "^2.4.0", + "@ethereumjs/tx": "^3.3.0", "async-eventemitter": "^0.2.4", "core-js-pure": "^3.0.1", "debug": "^2.2.0", - "ethereumjs-util": "^7.0.10", + "ethereumjs-util": "^7.1.0", "functional-red-black-tree": "^1.0.1", "mcl-wasm": "^0.7.1", "merkle-patricia-tree": "^4.2.0", @@ -2659,6 +2769,19 @@ "util.promisify": "^1.0.1" }, "dependencies": { + "@types/bn.js": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", + "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", + "requires": { + "@types/node": "*" + } + }, + "bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -2667,6 +2790,19 @@ "ms": "2.0.0" } }, + "ethereumjs-util": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.0.tgz", + "integrity": "sha512-kR+vhu++mUDARrsMMhsjjzPduRVAeundLGXucGRHF3B4oEltOUspfgCVco4kckucj3FMlLaZHUl9n7/kdmr6Tw==", + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.4" + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -2675,294 +2811,284 @@ } }, "@ethersproject/abi": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.1.2.tgz", - "integrity": "sha512-uMhoQVPX0UtfzTpekYQSEUcJGDgsJ25ifz+SV6PDETWaUFhcR8RNgb1QPTASP13inW8r6iy0/Xdq9D5hK2pNvA==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.4.0.tgz", + "integrity": "sha512-9gU2H+/yK1j2eVMdzm6xvHSnMxk8waIHQGYCZg5uvAyH0rsAzxkModzBSpbAkAuhKFEovC2S9hM4nPuLym8IZw==", "requires": { - "@ethersproject/address": "^5.1.0", - "@ethersproject/bignumber": "^5.1.0", - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/constants": "^5.1.0", - "@ethersproject/hash": "^5.1.0", - "@ethersproject/keccak256": "^5.1.0", - "@ethersproject/logger": "^5.1.0", - "@ethersproject/properties": "^5.1.0", - "@ethersproject/strings": "^5.1.0" + "@ethersproject/address": "^5.4.0", + "@ethersproject/bignumber": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/constants": "^5.4.0", + "@ethersproject/hash": "^5.4.0", + "@ethersproject/keccak256": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "@ethersproject/properties": "^5.4.0", + "@ethersproject/strings": "^5.4.0" } }, "@ethersproject/abstract-provider": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.1.0.tgz", - "integrity": "sha512-8dJUnT8VNvPwWhYIau4dwp7qe1g+KgdRm4XTWvjkI9gAT2zZa90WF5ApdZ3vl1r6NDmnn6vUVvyphClRZRteTQ==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.4.1.tgz", + "integrity": "sha512-3EedfKI3LVpjSKgAxoUaI+gB27frKsxzm+r21w9G60Ugk+3wVLQwhi1LsEJAKNV7WoZc8CIpNrATlL1QFABjtQ==", "requires": { - "@ethersproject/bignumber": "^5.1.0", - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/logger": "^5.1.0", - "@ethersproject/networks": "^5.1.0", - "@ethersproject/properties": "^5.1.0", - "@ethersproject/transactions": "^5.1.0", - "@ethersproject/web": "^5.1.0" + "@ethersproject/bignumber": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "@ethersproject/networks": "^5.4.0", + "@ethersproject/properties": "^5.4.0", + "@ethersproject/transactions": "^5.4.0", + "@ethersproject/web": "^5.4.0" } }, "@ethersproject/abstract-signer": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.1.0.tgz", - "integrity": "sha512-qQDMkjGZSSJSKl6AnfTgmz9FSnzq3iEoEbHTYwjDlEAv+LNP7zd4ixCcVWlWyk+2siud856M5CRhAmPdupeN9w==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.4.1.tgz", + "integrity": "sha512-SkkFL5HVq1k4/25dM+NWP9MILgohJCgGv5xT5AcRruGz4ILpfHeBtO/y6j+Z3UN/PAjDeb4P7E51Yh8wcGNLGA==", "requires": { - "@ethersproject/abstract-provider": "^5.1.0", - "@ethersproject/bignumber": "^5.1.0", - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/logger": "^5.1.0", - "@ethersproject/properties": "^5.1.0" + "@ethersproject/abstract-provider": "^5.4.0", + "@ethersproject/bignumber": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "@ethersproject/properties": "^5.4.0" } }, "@ethersproject/address": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.1.0.tgz", - "integrity": "sha512-rfWQR12eHn2cpstCFS4RF7oGjfbkZb0oqep+BfrT+gWEGWG2IowJvIsacPOvzyS1jhNF4MQ4BS59B04Mbovteg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.4.0.tgz", + "integrity": "sha512-SD0VgOEkcACEG/C6xavlU1Hy3m5DGSXW3CUHkaaEHbAPPsgi0coP5oNPsxau8eTlZOk/bpa/hKeCNoK5IzVI2Q==", "requires": { - "@ethersproject/bignumber": "^5.1.0", - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/keccak256": "^5.1.0", - "@ethersproject/logger": "^5.1.0", - "@ethersproject/rlp": "^5.1.0" + "@ethersproject/bignumber": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/keccak256": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "@ethersproject/rlp": "^5.4.0" } }, "@ethersproject/base64": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.1.0.tgz", - "integrity": "sha512-npD1bLvK4Bcxz+m4EMkx+F8Rd7CnqS9DYnhNu0/GlQBXhWjvfoAZzk5HJ0f1qeyp8d+A86PTuzLOGOXf4/CN8g==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.4.0.tgz", + "integrity": "sha512-CjQw6E17QDSSC5jiM9YpF7N1aSCHmYGMt9bWD8PWv6YPMxjsys2/Q8xLrROKI3IWJ7sFfZ8B3flKDTM5wlWuZQ==", "requires": { - "@ethersproject/bytes": "^5.1.0" + "@ethersproject/bytes": "^5.4.0" } }, "@ethersproject/basex": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.1.0.tgz", - "integrity": "sha512-vBKr39bum7DDbOvkr1Sj19bRMEPA4FnST6Utt6xhDzI7o7L6QNkDn2yrCfP+hnvJGhZFKtLygWwqlTBZoBXYLg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.4.0.tgz", + "integrity": "sha512-J07+QCVJ7np2bcpxydFVf/CuYo9mZ7T73Pe7KQY4c1lRlrixMeblauMxHXD0MPwFmUHZIILDNViVkykFBZylbg==", "requires": { - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/properties": "^5.1.0" + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/properties": "^5.4.0" } }, "@ethersproject/bignumber": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.1.1.tgz", - "integrity": "sha512-AVz5iqz7+70RIqoQTznsdJ6DOVBYciNlvO+AlQmPTB6ofCvoihI9bQdr6wljsX+d5W7Yc4nyvQvP4JMzg0Agig==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.4.1.tgz", + "integrity": "sha512-fJhdxqoQNuDOk6epfM7yD6J8Pol4NUCy1vkaGAkuujZm0+lNow//MKu1hLhRiYV4BsOHyBv5/lsTjF+7hWwhJg==", "requires": { - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/logger": "^5.1.0", - "bn.js": "^4.4.0" + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "bn.js": "^4.11.9" } }, "@ethersproject/bytes": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.1.0.tgz", - "integrity": "sha512-sGTxb+LVjFxJcJeUswAIK6ncgOrh3D8c192iEJd7mLr95V6du119rRfYT/b87WPkZ5I3gRBUYIYXtdgCWACe8g==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.4.0.tgz", + "integrity": "sha512-H60ceqgTHbhzOj4uRc/83SCN9d+BSUnOkrr2intevqdtEMO1JFVZ1XL84OEZV+QjV36OaZYxtnt4lGmxcGsPfA==", "requires": { - "@ethersproject/logger": "^5.1.0" + "@ethersproject/logger": "^5.4.0" } }, "@ethersproject/constants": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.1.0.tgz", - "integrity": "sha512-0/SuHrxc8R8k+JiLmJymxHJbojUDWBQqO+b+XFdwaP0jGzqC09YDy/CAlSZB6qHsBifY8X3I89HcK/oMqxRdBw==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.4.0.tgz", + "integrity": "sha512-tzjn6S7sj9+DIIeKTJLjK9WGN2Tj0P++Z8ONEIlZjyoTkBuODN+0VfhAyYksKi43l1Sx9tX2VlFfzjfmr5Wl3Q==", "requires": { - "@ethersproject/bignumber": "^5.1.0" + "@ethersproject/bignumber": "^5.4.0" } }, "@ethersproject/contracts": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.1.1.tgz", - "integrity": "sha512-6WwktLJ0DFWU8pDkgH4IGttQHhQN4SnwKFu9h+QYVe48VGWtbDu4W8/q/7QA1u/HWlWMrKxqawPiZUJj0UMvOw==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.4.1.tgz", + "integrity": "sha512-m+z2ZgPy4pyR15Je//dUaymRUZq5MtDajF6GwFbGAVmKz/RF+DNIPwF0k5qEcL3wPGVqUjFg2/krlCRVTU4T5w==", "requires": { - "@ethersproject/abi": "^5.1.0", - "@ethersproject/abstract-provider": "^5.1.0", - "@ethersproject/abstract-signer": "^5.1.0", - "@ethersproject/address": "^5.1.0", - "@ethersproject/bignumber": "^5.1.0", - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/constants": "^5.1.0", - "@ethersproject/logger": "^5.1.0", - "@ethersproject/properties": "^5.1.0", - "@ethersproject/transactions": "^5.1.0" + "@ethersproject/abi": "^5.4.0", + "@ethersproject/abstract-provider": "^5.4.0", + "@ethersproject/abstract-signer": "^5.4.0", + "@ethersproject/address": "^5.4.0", + "@ethersproject/bignumber": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/constants": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "@ethersproject/properties": "^5.4.0", + "@ethersproject/transactions": "^5.4.0" } }, "@ethersproject/hash": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.1.0.tgz", - "integrity": "sha512-fNwry20yLLPpnRRwm3fBL+2ksgO+KMadxM44WJmRIoTKzy4269+rbq9KFoe2LTqq2CXJM2CE70beGaNrpuqflQ==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.4.0.tgz", + "integrity": "sha512-xymAM9tmikKgbktOCjW60Z5sdouiIIurkZUr9oW5NOex5uwxrbsYG09kb5bMcNjlVeJD3yPivTNzViIs1GCbqA==", "requires": { - "@ethersproject/abstract-signer": "^5.1.0", - "@ethersproject/address": "^5.1.0", - "@ethersproject/bignumber": "^5.1.0", - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/keccak256": "^5.1.0", - "@ethersproject/logger": "^5.1.0", - "@ethersproject/properties": "^5.1.0", - "@ethersproject/strings": "^5.1.0" + "@ethersproject/abstract-signer": "^5.4.0", + "@ethersproject/address": "^5.4.0", + "@ethersproject/bignumber": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/keccak256": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "@ethersproject/properties": "^5.4.0", + "@ethersproject/strings": "^5.4.0" } }, "@ethersproject/hdnode": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.1.0.tgz", - "integrity": "sha512-obIWdlujloExPHWJGmhJO/sETOOo7SEb6qemV4f8kyFoXg+cJK+Ta9SvBrj7hsUK85n3LZeZJZRjjM7oez3Clg==", - "requires": { - "@ethersproject/abstract-signer": "^5.1.0", - "@ethersproject/basex": "^5.1.0", - "@ethersproject/bignumber": "^5.1.0", - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/logger": "^5.1.0", - "@ethersproject/pbkdf2": "^5.1.0", - "@ethersproject/properties": "^5.1.0", - "@ethersproject/sha2": "^5.1.0", - "@ethersproject/signing-key": "^5.1.0", - "@ethersproject/strings": "^5.1.0", - "@ethersproject/transactions": "^5.1.0", - "@ethersproject/wordlists": "^5.1.0" + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.4.0.tgz", + "integrity": "sha512-pKxdS0KAaeVGfZPp1KOiDLB0jba11tG6OP1u11QnYfb7pXn6IZx0xceqWRr6ygke8+Kw74IpOoSi7/DwANhy8Q==", + "requires": { + "@ethersproject/abstract-signer": "^5.4.0", + "@ethersproject/basex": "^5.4.0", + "@ethersproject/bignumber": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "@ethersproject/pbkdf2": "^5.4.0", + "@ethersproject/properties": "^5.4.0", + "@ethersproject/sha2": "^5.4.0", + "@ethersproject/signing-key": "^5.4.0", + "@ethersproject/strings": "^5.4.0", + "@ethersproject/transactions": "^5.4.0", + "@ethersproject/wordlists": "^5.4.0" } }, "@ethersproject/json-wallets": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.1.0.tgz", - "integrity": "sha512-00n2iBy27w8zrGZSiU762UOVuzCQZxUZxopsZC47++js6xUFuI74DHcJ5K/2pddlF1YBskvmMuboEu1geK8mnA==", - "requires": { - "@ethersproject/abstract-signer": "^5.1.0", - "@ethersproject/address": "^5.1.0", - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/hdnode": "^5.1.0", - "@ethersproject/keccak256": "^5.1.0", - "@ethersproject/logger": "^5.1.0", - "@ethersproject/pbkdf2": "^5.1.0", - "@ethersproject/properties": "^5.1.0", - "@ethersproject/random": "^5.1.0", - "@ethersproject/strings": "^5.1.0", - "@ethersproject/transactions": "^5.1.0", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.4.0.tgz", + "integrity": "sha512-igWcu3fx4aiczrzEHwG1xJZo9l1cFfQOWzTqwRw/xcvxTk58q4f9M7cjh51EKphMHvrJtcezJ1gf1q1AUOfEQQ==", + "requires": { + "@ethersproject/abstract-signer": "^5.4.0", + "@ethersproject/address": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/hdnode": "^5.4.0", + "@ethersproject/keccak256": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "@ethersproject/pbkdf2": "^5.4.0", + "@ethersproject/properties": "^5.4.0", + "@ethersproject/random": "^5.4.0", + "@ethersproject/strings": "^5.4.0", + "@ethersproject/transactions": "^5.4.0", "aes-js": "3.0.0", "scrypt-js": "3.0.1" } }, "@ethersproject/keccak256": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.1.0.tgz", - "integrity": "sha512-vrTB1W6AEYoadww5c9UyVJ2YcSiyIUTNDRccZIgwTmFFoSHwBtcvG1hqy9RzJ1T0bMdATbM9Hfx2mJ6H0i7Hig==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.4.0.tgz", + "integrity": "sha512-FBI1plWet+dPUvAzPAeHzRKiPpETQzqSUWR1wXJGHVWi4i8bOSrpC3NwpkPjgeXG7MnugVc1B42VbfnQikyC/A==", "requires": { - "@ethersproject/bytes": "^5.1.0", + "@ethersproject/bytes": "^5.4.0", "js-sha3": "0.5.7" } }, "@ethersproject/logger": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.1.0.tgz", - "integrity": "sha512-wtUaD1lBX10HBXjjKV9VHCBnTdUaKQnQ2XSET1ezglqLdPdllNOIlLfhyCRqXm5xwcjExVI5ETokOYfjPtaAlw==" + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.4.0.tgz", + "integrity": "sha512-xYdWGGQ9P2cxBayt64d8LC8aPFJk6yWCawQi/4eJ4+oJdMMjEBMrIcIMZ9AxhwpPVmnBPrsB10PcXGmGAqgUEQ==" }, "@ethersproject/networks": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.1.0.tgz", - "integrity": "sha512-A/NIrIED/G/IgU1XUukOA3WcFRxn2I4O5GxsYGA5nFlIi+UZWdGojs85I1VXkR1gX9eFnDXzjE6OtbgZHjFhIA==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.4.2.tgz", + "integrity": "sha512-eekOhvJyBnuibfJnhtK46b8HimBc5+4gqpvd1/H9LEl7Q7/qhsIhM81dI9Fcnjpk3jB1aTy6bj0hz3cifhNeYw==", "requires": { - "@ethersproject/logger": "^5.1.0" + "@ethersproject/logger": "^5.4.0" } }, "@ethersproject/pbkdf2": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.1.0.tgz", - "integrity": "sha512-B8cUbHHTgs8OtgJIafrRcz/YPDobVd5Ru8gTnShOiM9EBuFpYHQpq3+8iQJ6pyczDu6HP/oc/njAsIBhwFZYew==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.4.0.tgz", + "integrity": "sha512-x94aIv6tiA04g6BnazZSLoRXqyusawRyZWlUhKip2jvoLpzJuLb//KtMM6PEovE47pMbW+Qe1uw+68ameJjB7g==", "requires": { - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/sha2": "^5.1.0" + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/sha2": "^5.4.0" } }, "@ethersproject/properties": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.1.0.tgz", - "integrity": "sha512-519KKTwgmH42AQL3+GFV3SX6khYEfHsvI6v8HYejlkigSDuqttdgVygFTDsGlofNFchhDwuclrxQnD5B0YLNMg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.4.0.tgz", + "integrity": "sha512-7jczalGVRAJ+XSRvNA6D5sAwT4gavLq3OXPuV/74o3Rd2wuzSL035IMpIMgei4CYyBdialJMrTqkOnzccLHn4A==", "requires": { - "@ethersproject/logger": "^5.1.0" + "@ethersproject/logger": "^5.4.0" } }, "@ethersproject/providers": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.1.2.tgz", - "integrity": "sha512-GqsS8rd+eyd4eNkcNgzZ4l9IRULBPUZa7JPnv22k4MHflMobUseyhfbVnmoN5bVNNkOxjV1IPTw9i0sV1hwdpg==", - "requires": { - "@ethersproject/abstract-provider": "^5.1.0", - "@ethersproject/abstract-signer": "^5.1.0", - "@ethersproject/address": "^5.1.0", - "@ethersproject/basex": "^5.1.0", - "@ethersproject/bignumber": "^5.1.0", - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/constants": "^5.1.0", - "@ethersproject/hash": "^5.1.0", - "@ethersproject/logger": "^5.1.0", - "@ethersproject/networks": "^5.1.0", - "@ethersproject/properties": "^5.1.0", - "@ethersproject/random": "^5.1.0", - "@ethersproject/rlp": "^5.1.0", - "@ethersproject/sha2": "^5.1.0", - "@ethersproject/strings": "^5.1.0", - "@ethersproject/transactions": "^5.1.0", - "@ethersproject/web": "^5.1.0", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.4.3.tgz", + "integrity": "sha512-VURwkaWPoUj7jq9NheNDT5Iyy64Qcyf6BOFDwVdHsmLmX/5prNjFrgSX3GHPE4z1BRrVerDxe2yayvXKFm/NNg==", + "requires": { + "@ethersproject/abstract-provider": "^5.4.0", + "@ethersproject/abstract-signer": "^5.4.0", + "@ethersproject/address": "^5.4.0", + "@ethersproject/basex": "^5.4.0", + "@ethersproject/bignumber": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/constants": "^5.4.0", + "@ethersproject/hash": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "@ethersproject/networks": "^5.4.0", + "@ethersproject/properties": "^5.4.0", + "@ethersproject/random": "^5.4.0", + "@ethersproject/rlp": "^5.4.0", + "@ethersproject/sha2": "^5.4.0", + "@ethersproject/strings": "^5.4.0", + "@ethersproject/transactions": "^5.4.0", + "@ethersproject/web": "^5.4.0", "bech32": "1.1.4", - "ws": "7.2.3" + "ws": "7.4.6" }, "dependencies": { "ws": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz", - "integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==" + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" } } }, "@ethersproject/random": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.1.0.tgz", - "integrity": "sha512-+uuczLQZ4+no9cP6TCoCktXx0u2YbNaRT7lRkSt12d8263e702f0u+4JnnRO8Qmv5nylWJebnqCHzyxP+6mLqw==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.4.0.tgz", + "integrity": "sha512-pnpWNQlf0VAZDEOVp1rsYQosmv2o0ITS/PecNw+mS2/btF8eYdspkN0vIXrCMtkX09EAh9bdk8GoXmFXM1eAKw==", "requires": { - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/logger": "^5.1.0" + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/logger": "^5.4.0" } }, "@ethersproject/rlp": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.1.0.tgz", - "integrity": "sha512-vDTyHIwNPrecy55gKGZ47eJZhBm8LLBxihzi5ou+zrSvYTpkSTWRcKUlXFDFQVwfWB+P5PGyERAdiDEI76clxw==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.4.0.tgz", + "integrity": "sha512-0I7MZKfi+T5+G8atId9QaQKHRvvasM/kqLyAH4XxBCBchAooH2EX5rL9kYZWwcm3awYV+XC7VF6nLhfeQFKVPg==", "requires": { - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/logger": "^5.1.0" + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/logger": "^5.4.0" } }, "@ethersproject/sha2": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.1.0.tgz", - "integrity": "sha512-+fNSeZRstOpdRJpdGUkRONFCaiAqWkc91zXgg76Nlp5ndBQE25Kk5yK8gCPG1aGnCrbariiPr5j9DmrYH78JCA==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.4.0.tgz", + "integrity": "sha512-siheo36r1WD7Cy+bDdE1BJ8y0bDtqXCOxRMzPa4bV1TGt/eTUUt03BHoJNB6reWJD8A30E/pdJ8WFkq+/uz4Gg==", "requires": { - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/logger": "^5.1.0", - "hash.js": "1.1.3" - }, - "dependencies": { - "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - } - } + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "hash.js": "1.1.7" } }, "@ethersproject/signing-key": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.1.0.tgz", - "integrity": "sha512-tE5LFlbmdObG8bY04NpuwPWSRPgEswfxweAI1sH7TbP0ml1elNfqcq7ii/3AvIN05i5U0Pkm3Tf8bramt8MmLw==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.4.0.tgz", + "integrity": "sha512-q8POUeywx6AKg2/jX9qBYZIAmKSB4ubGXdQ88l40hmATj29JnG5pp331nAWwwxPn2Qao4JpWHNZsQN+bPiSW9A==", "requires": { - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/logger": "^5.1.0", - "@ethersproject/properties": "^5.1.0", - "bn.js": "^4.4.0", - "elliptic": "6.5.4" + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "@ethersproject/properties": "^5.4.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.7" }, "dependencies": { "elliptic": { @@ -2982,97 +3108,97 @@ } }, "@ethersproject/solidity": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.1.0.tgz", - "integrity": "sha512-kPodsGyo9zg1g9XSXp1lGhFaezBAUUsAUB1Vf6OkppE5Wksg4Et+x3kG4m7J/uShDMP2upkJtHNsIBK2XkVpKQ==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.4.0.tgz", + "integrity": "sha512-XFQTZ7wFSHOhHcV1DpcWj7VXECEiSrBuv7JErJvB9Uo+KfCdc3QtUZV+Vjh/AAaYgezUEKbCtE6Khjm44seevQ==", "requires": { - "@ethersproject/bignumber": "^5.1.0", - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/keccak256": "^5.1.0", - "@ethersproject/sha2": "^5.1.0", - "@ethersproject/strings": "^5.1.0" + "@ethersproject/bignumber": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/keccak256": "^5.4.0", + "@ethersproject/sha2": "^5.4.0", + "@ethersproject/strings": "^5.4.0" } }, "@ethersproject/strings": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.1.0.tgz", - "integrity": "sha512-perBZy0RrmmL0ejiFGUOlBVjMsUceqLut3OBP3zP96LhiJWWbS8u1NqQVgN4/Gyrbziuda66DxiQocXhsvx+Sw==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.4.0.tgz", + "integrity": "sha512-k/9DkH5UGDhv7aReXLluFG5ExurwtIpUfnDNhQA29w896Dw3i4uDTz01Quaptbks1Uj9kI8wo9tmW73wcIEaWA==", "requires": { - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/constants": "^5.1.0", - "@ethersproject/logger": "^5.1.0" + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/constants": "^5.4.0", + "@ethersproject/logger": "^5.4.0" } }, "@ethersproject/transactions": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.1.1.tgz", - "integrity": "sha512-Nwgbp09ttIVN0OoUBatCXaHxR7grWPHbozJN8v7AXDLrl6nnOIBEMDh+yJTnosSQlFhcyjfTGGN+Mx6R8HdvMw==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.4.0.tgz", + "integrity": "sha512-s3EjZZt7xa4BkLknJZ98QGoIza94rVjaEed0rzZ/jB9WrIuu/1+tjvYCWzVrystXtDswy7TPBeIepyXwSYa4WQ==", "requires": { - "@ethersproject/address": "^5.1.0", - "@ethersproject/bignumber": "^5.1.0", - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/constants": "^5.1.0", - "@ethersproject/keccak256": "^5.1.0", - "@ethersproject/logger": "^5.1.0", - "@ethersproject/properties": "^5.1.0", - "@ethersproject/rlp": "^5.1.0", - "@ethersproject/signing-key": "^5.1.0" + "@ethersproject/address": "^5.4.0", + "@ethersproject/bignumber": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/constants": "^5.4.0", + "@ethersproject/keccak256": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "@ethersproject/properties": "^5.4.0", + "@ethersproject/rlp": "^5.4.0", + "@ethersproject/signing-key": "^5.4.0" } }, "@ethersproject/units": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.1.0.tgz", - "integrity": "sha512-isvJrx6qG0nKWfxsGORNjmOq/nh175fStfvRTA2xEKrGqx8JNJY83fswu4GkILowfriEM/eYpretfJnfzi7YhA==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.4.0.tgz", + "integrity": "sha512-Z88krX40KCp+JqPCP5oPv5p750g+uU6gopDYRTBGcDvOASh6qhiEYCRatuM/suC4S2XW9Zz90QI35MfSrTIaFg==", "requires": { - "@ethersproject/bignumber": "^5.1.0", - "@ethersproject/constants": "^5.1.0", - "@ethersproject/logger": "^5.1.0" + "@ethersproject/bignumber": "^5.4.0", + "@ethersproject/constants": "^5.4.0", + "@ethersproject/logger": "^5.4.0" } }, "@ethersproject/wallet": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.1.0.tgz", - "integrity": "sha512-ULmUtiYQLTUS+y3DgkLzRhFEK10zMwmjOthnjiZxee3Q/MVwr3rnmuAnXIUZrPjna6hvUPnyRIdW5XuF0Ld0YQ==", - "requires": { - "@ethersproject/abstract-provider": "^5.1.0", - "@ethersproject/abstract-signer": "^5.1.0", - "@ethersproject/address": "^5.1.0", - "@ethersproject/bignumber": "^5.1.0", - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/hash": "^5.1.0", - "@ethersproject/hdnode": "^5.1.0", - "@ethersproject/json-wallets": "^5.1.0", - "@ethersproject/keccak256": "^5.1.0", - "@ethersproject/logger": "^5.1.0", - "@ethersproject/properties": "^5.1.0", - "@ethersproject/random": "^5.1.0", - "@ethersproject/signing-key": "^5.1.0", - "@ethersproject/transactions": "^5.1.0", - "@ethersproject/wordlists": "^5.1.0" + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.4.0.tgz", + "integrity": "sha512-wU29majLjM6AjCjpat21mPPviG+EpK7wY1+jzKD0fg3ui5fgedf2zEu1RDgpfIMsfn8fJHJuzM4zXZ2+hSHaSQ==", + "requires": { + "@ethersproject/abstract-provider": "^5.4.0", + "@ethersproject/abstract-signer": "^5.4.0", + "@ethersproject/address": "^5.4.0", + "@ethersproject/bignumber": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/hash": "^5.4.0", + "@ethersproject/hdnode": "^5.4.0", + "@ethersproject/json-wallets": "^5.4.0", + "@ethersproject/keccak256": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "@ethersproject/properties": "^5.4.0", + "@ethersproject/random": "^5.4.0", + "@ethersproject/signing-key": "^5.4.0", + "@ethersproject/transactions": "^5.4.0", + "@ethersproject/wordlists": "^5.4.0" } }, "@ethersproject/web": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.1.0.tgz", - "integrity": "sha512-LTeluWgTq04+RNqAkVhpydPcRZK/kKxD2Vy7PYGrAD27ABO9kTqTBKwiOuzTyAHKUQHfnvZbXmxBXJAGViSDcA==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.4.0.tgz", + "integrity": "sha512-1bUusGmcoRLYgMn6c1BLk1tOKUIFuTg8j+6N8lYlbMpDesnle+i3pGSagGNvwjaiLo4Y5gBibwctpPRmjrh4Og==", "requires": { - "@ethersproject/base64": "^5.1.0", - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/logger": "^5.1.0", - "@ethersproject/properties": "^5.1.0", - "@ethersproject/strings": "^5.1.0" + "@ethersproject/base64": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "@ethersproject/properties": "^5.4.0", + "@ethersproject/strings": "^5.4.0" } }, "@ethersproject/wordlists": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.1.0.tgz", - "integrity": "sha512-NsUCi/TpBb+oTFvMSccUkJGtp5o/84eOyqp5q5aBeiNBSLkYyw21znRn9mAmxZgySpxgruVgKbaapnYPgvctPQ==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.4.0.tgz", + "integrity": "sha512-FemEkf6a+EBKEPxlzeVgUaVSodU7G0Na89jqKjmWMlDB0tomoU8RlEMgUvXyqtrg8N4cwpLh8nyRnm1Nay1isA==", "requires": { - "@ethersproject/bytes": "^5.1.0", - "@ethersproject/hash": "^5.1.0", - "@ethersproject/logger": "^5.1.0", - "@ethersproject/properties": "^5.1.0", - "@ethersproject/strings": "^5.1.0" + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/hash": "^5.4.0", + "@ethersproject/logger": "^5.4.0", + "@ethersproject/properties": "^5.4.0", + "@ethersproject/strings": "^5.4.0" } }, "@evocateur/libnpmaccess": { @@ -7552,9 +7678,9 @@ "dev": true }, "@types/abstract-leveldown": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/abstract-leveldown/-/abstract-leveldown-5.0.1.tgz", - "integrity": "sha512-wYxU3kp5zItbxKmeRYCEplS2MW7DzyBnxPGj+GJVHZEUZiK/nn5Ei1sUFgURDh+X051+zsGe28iud3oHjrYWQQ==" + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/abstract-leveldown/-/abstract-leveldown-5.0.2.tgz", + "integrity": "sha512-+jA1XXF3jsz+Z7FcuiNqgK53hTa/luglT2TyTpKPqoYbxVY+mCPF22Rm+q3KPBrMHJwNXFrTViHszBOfU4vftQ==" }, "@types/aria-query": { "version": "4.2.0", @@ -7734,12 +7860,18 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "@types/level-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/level-errors/-/level-errors-3.0.0.tgz", + "integrity": "sha512-/lMtoq/Cf/2DVOm6zE6ORyOM+3ZVm/BvzEZVxUhf6bgh8ZHglXlBqxbxSlJeVp8FCbD3IVvk/VbsaNmDjrQvqQ==" + }, "@types/levelup": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@types/levelup/-/levelup-4.3.1.tgz", - "integrity": "sha512-n//PeTpbHLjMLTIgW5B/g06W/6iuTBHuvUka2nFL9APMSVMNe2r4enADfu3CIE9IyV9E+uquf9OEQQqrDeg24A==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@types/levelup/-/levelup-4.3.3.tgz", + "integrity": "sha512-K+OTIjJcZHVlZQN1HmU64VtrC0jC3dXWQozuEIR9zVvltIk90zaGPM2AgT+fIkChpzHhFE3YnvFLCbLtzAmexA==", "requires": { "@types/abstract-leveldown": "*", + "@types/level-errors": "*", "@types/node": "*" } }, @@ -13410,11 +13542,14 @@ "is-plain-object": "^2.0.1" } }, - "copy-text-to-clipboard": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-1.0.4.tgz", - "integrity": "sha512-4hDE+0bgqm4G/nXnt91CP3rc0vOptaePPU5WfVZuhv2AYNJogdLHR4pF1XPgXDAGY4QCzj9pD7zKATa+50sQPg==", - "dev": true + "copy-to-clipboard": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz", + "integrity": "sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==", + "dev": true, + "requires": { + "toggle-selection": "^1.0.6" + } }, "copy-webpack-plugin": { "version": "5.1.1", @@ -16363,40 +16498,40 @@ } }, "ethers": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.1.4.tgz", - "integrity": "sha512-EAPQ/fgGRu0PoR/VNFnHTMOtG/IZ0AItdW55C9T8ffmVu0rnyllZL404eBF66elJehOLz2kxnUrhXpE7TCpW7g==", - "requires": { - "@ethersproject/abi": "5.1.2", - "@ethersproject/abstract-provider": "5.1.0", - "@ethersproject/abstract-signer": "5.1.0", - "@ethersproject/address": "5.1.0", - "@ethersproject/base64": "5.1.0", - "@ethersproject/basex": "5.1.0", - "@ethersproject/bignumber": "5.1.1", - "@ethersproject/bytes": "5.1.0", - "@ethersproject/constants": "5.1.0", - "@ethersproject/contracts": "5.1.1", - "@ethersproject/hash": "5.1.0", - "@ethersproject/hdnode": "5.1.0", - "@ethersproject/json-wallets": "5.1.0", - "@ethersproject/keccak256": "5.1.0", - "@ethersproject/logger": "5.1.0", - "@ethersproject/networks": "5.1.0", - "@ethersproject/pbkdf2": "5.1.0", - "@ethersproject/properties": "5.1.0", - "@ethersproject/providers": "5.1.2", - "@ethersproject/random": "5.1.0", - "@ethersproject/rlp": "5.1.0", - "@ethersproject/sha2": "5.1.0", - "@ethersproject/signing-key": "5.1.0", - "@ethersproject/solidity": "5.1.0", - "@ethersproject/strings": "5.1.0", - "@ethersproject/transactions": "5.1.1", - "@ethersproject/units": "5.1.0", - "@ethersproject/wallet": "5.1.0", - "@ethersproject/web": "5.1.0", - "@ethersproject/wordlists": "5.1.0" + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.4.4.tgz", + "integrity": "sha512-zaTs8yaDjfb0Zyj8tT6a+/hEkC+kWAA350MWRp6yP5W7NdGcURRPMOpOU+6GtkfxV9wyJEShWesqhE/TjdqpMA==", + "requires": { + "@ethersproject/abi": "5.4.0", + "@ethersproject/abstract-provider": "5.4.1", + "@ethersproject/abstract-signer": "5.4.1", + "@ethersproject/address": "5.4.0", + "@ethersproject/base64": "5.4.0", + "@ethersproject/basex": "5.4.0", + "@ethersproject/bignumber": "5.4.1", + "@ethersproject/bytes": "5.4.0", + "@ethersproject/constants": "5.4.0", + "@ethersproject/contracts": "5.4.1", + "@ethersproject/hash": "5.4.0", + "@ethersproject/hdnode": "5.4.0", + "@ethersproject/json-wallets": "5.4.0", + "@ethersproject/keccak256": "5.4.0", + "@ethersproject/logger": "5.4.0", + "@ethersproject/networks": "5.4.2", + "@ethersproject/pbkdf2": "5.4.0", + "@ethersproject/properties": "5.4.0", + "@ethersproject/providers": "5.4.3", + "@ethersproject/random": "5.4.0", + "@ethersproject/rlp": "5.4.0", + "@ethersproject/sha2": "5.4.0", + "@ethersproject/signing-key": "5.4.0", + "@ethersproject/solidity": "5.4.0", + "@ethersproject/strings": "5.4.0", + "@ethersproject/transactions": "5.4.0", + "@ethersproject/units": "5.4.0", + "@ethersproject/wallet": "5.4.0", + "@ethersproject/web": "5.4.0", + "@ethersproject/wordlists": "5.4.0" } }, "ethjs-unit": { @@ -17722,12 +17857,6 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true - }, "fstream": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", @@ -20296,6 +20425,11 @@ "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" }, + "intro.js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/intro.js/-/intro.js-4.1.0.tgz", + "integrity": "sha512-+Y+UsP+yvqqlEOjFExMBXKopn3nzwc91PaUl0SrvqiVs6ztko1DzfkoXR2AnfirZVZZhr5Aej6wlXRlvIkuMcA==" + }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -22120,6 +22254,12 @@ "which": "^2.0.2" }, "dependencies": { + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -24985,9 +25125,19 @@ "dev": true }, "mcl-wasm": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.7.tgz", - "integrity": "sha512-jDGiCQA++5hX37gdH6RDZ3ZsA0raet7xyY/R5itj5cbcdf4Gvw+YyxWX/ZZ0Z2UPxJiw1ktRsCJZzpnqlQILdw==" + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.8.tgz", + "integrity": "sha512-qNHlYO6wuEtSoH5A8TcZfCEHtw8gGPqF6hLZpQn2SVd/Mck0ELIKOkmj072D98S9B9CI/jZybTUC96q1P2/ZDw==", + "requires": { + "typescript": "^4.3.4" + }, + "dependencies": { + "typescript": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==" + } + } }, "md5.js": { "version": "1.3.5", @@ -37389,6 +37539,12 @@ "through2": "^2.0.3" } }, + "toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI=", + "dev": true + }, "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", diff --git a/package.json b/package.json index a5e587c1e9..31b97135a1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "remix-project", - "version": "0.14.0-dev", + "version": "0.17.0-dev", "license": "MIT", "description": "Ethereum Remix Monorepo", "keywords": [ @@ -41,7 +41,11 @@ "workspace-schematic": "nx workspace-schematic", "dep-graph": "nx dep-graph", "help": "nx help", +<<<<<<< HEAD "lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-file-explorer,remix-ui-debugger-ui,remix-ui-workspace,remix-ui-static-analyser,remix-ui-checkbox,remix-ui-settings", +======= + "lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-file-explorer,remix-ui-debugger-ui,remix-ui-workspace,remix-ui-static-analyser,remix-ui-checkbox,remix-ui-settings,remix-core-plugin,remix-ui-renderer,remix-ui-publish-to-storage,remix-ui-solidity-compiler", +>>>>>>> 1f46c590a942e56f8e46ab4fa3b074d450d5ffc8 "build:libs": "nx run-many --target=build --parallel=false --with-deps=true --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd", "test:libs": "nx run-many --target=test --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd", "publish:libs": "npm run build:libs && lerna publish --skip-git && npm run bumpVersion:libs", @@ -130,10 +134,10 @@ }, "dependencies": { "@erebos/bzz-node": "^0.13.0", - "@ethereumjs/block": "^3.3.0", - "@ethereumjs/common": "^2.3.1", - "@ethereumjs/tx": "^3.2.1", - "@ethereumjs/vm": "^5.4.1", + "@ethereumjs/block": "^3.4.0", + "@ethereumjs/common": "^2.4.0", + "@ethereumjs/tx": "^3.3.0", + "@ethereumjs/vm": "^5.5.0", "@remixproject/engine": "^0.3.17", "@remixproject/engine-web": "^0.3.17", "@remixproject/plugin": "^0.3.17", @@ -152,18 +156,18 @@ "deep-equal": "^1.0.1", "document-register-element": "1.13.1", "ethereumjs-util": "^7.0.10", - "ethers": "^5.1.4", + "ethers": "^5.4.2", "express-ws": "^4.0.0", "file-saver": "^2.0.5", "form-data": "^4.0.0", "fs-extra": "^3.0.1", "http-server": "^0.11.1", + "intro.js": "^4.1.0", "isbinaryfile": "^3.0.2", "isomorphic-git": "^1.8.2", "jquery": "^3.3.1", "jszip": "^3.6.0", "latest-version": "^5.1.0", - "lodash": "^4.17.21", "merge": "^1.2.0", "npm-install-version": "^6.0.2", "react": "16.13.1", @@ -235,7 +239,7 @@ "browserify-reload": "^1.0.3", "chromedriver": "^92.0.1", "component-type": "^1.2.1", - "copy-text-to-clipboard": "^1.0.4", + "copy-to-clipboard": "^3.3.1", "csjs-inject": "^1.0.1", "csslint": "^1.0.2", "cypress": "^4.1.0", diff --git a/release-process.md b/release-process.md index ceb1caccbc..67e100a5f8 100644 --- a/release-process.md +++ b/release-process.md @@ -1,13 +1,22 @@ # Release process This document includes: + - how to release the remixd - how to publish remix libs to NPM - how to update remix.ethereum.org - how to update remix-alpha.ethereum.org - how to update remix-beta.ethereum.org - how to release remix IDE +## RemixD release + - update new version number in remixd libs/remixd/package.json + - nx build remixd + - cd into ./dist/libs/remixd + - npm publish + - create bump PR to master. + ## Remix libs release +(remove dist and login to npm) - git fetch origin master - git checkout origin/master - git checkout -b bumpLibsVersion @@ -76,4 +85,4 @@ This is not strictly speaking a release. Updating the remix site is done through ## remix-alpha.ethereum.org update -remix-alpha.ethereum.org is automaticaly updated every time commits are pushed to master \ No newline at end of file +remix-alpha.ethereum.org is automaticaly updated every time commits are pushed to master diff --git a/tsconfig.json b/tsconfig.json index 85c784b3a1..40052792c2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,14 +20,10 @@ "@remix-project/remix-astwalker": ["dist/libs/remix-astwalker/index.js"], "@remix-project/remix-debug": ["dist/libs/remix-debug/src/index.js"], "@remix-project/remix-lib": ["dist/libs/remix-lib/src/index.js"], - "@remix-project/remix-simulator": [ - "dist/libs/remix-simulator/src/index.js" - ], + "@remix-project/remix-simulator": ["dist/libs/remix-simulator/src/index.js"], "@remix-project/remix-solidity": ["dist/libs/remix-solidity/index.js"], "@remix-project/remix-tests": ["dist/libs/remix-tests/src/index.js"], - "@remix-project/remix-url-resolver": [ - "dist/libs/remix-url-resolver/index.js" - ], + "@remix-project/remix-url-resolver": ["dist/libs/remix-url-resolver/index.js"], "@remixproject/debugger-plugin": ["apps/debugger/src/index.ts"], "@remix-project/remixd": ["dist/libs/remixd/index.js"], "@remix-ui/tree-view": ["libs/remix-ui/tree-view/src/index.ts"], @@ -43,6 +39,13 @@ "@remix-ui/checkbox": ["libs/remix-ui/checkbox/src/index.ts"], "@remix-ui/settings": ["libs/remix-ui/settings/src/index.ts"], "@remix-ui/plugin-manager": ["libs/remix-ui/plugin-manager/src/index.ts"] +<<<<<<< HEAD +======= + "@remix-project/core-plugin": ["libs/remix-core-plugin/src/index.ts"], + "@remix-ui/solidity-compiler": ["libs/remix-ui/solidity-compiler/src/index.ts"], + "@remix-ui/publish-to-storage": ["libs/remix-ui/publish-to-storage/src/index.ts"], + "@remix-ui/renderer": ["libs/remix-ui/renderer/src/index.ts"] +>>>>>>> 1f46c590a942e56f8e46ab4fa3b074d450d5ffc8 } }, "exclude": ["node_modules", "tmp"] diff --git a/workspace.json b/workspace.json index 39dbe4333b..5dd74df1ed 100644 --- a/workspace.json +++ b/workspace.json @@ -780,6 +780,15 @@ "remix-ui-plugin-manager": { "root": "libs/remix-ui/plugin-manager", "sourceRoot": "libs/remix-ui/plugin-manager/src", + "tsConfig": ["libs/remix-ui/plugin-manager/tsconfig.lib.json"], + "exclude": [ + "**/node_modules/**", + "!libs/remix-ui/plugin-manager/**/*" + ] + } + "remix-core-plugin": { + "root": "libs/remix-core-plugin", + "sourceRoot": "libs/remix-core-plugin/src", "projectType": "library", "schematics": {}, "architect": { @@ -787,14 +796,80 @@ "builder": "@nrwl/linter:lint", "options": { "linter": "eslint", - "tsConfig": ["libs/remix-ui/plugin-manager/tsconfig.lib.json"], + "tsConfig": [ + "libs/remix-core-plugin/tsconfig.lib.json" + ], "exclude": [ "**/node_modules/**", - "!libs/remix-ui/plugin-manager/**/*" + "!libs/remix-core-plugin/**/*" + ] + } + }, + "build": { + "builder": "@nrwl/node:package", + "options": { + "outputPath": "dist/libs/core-plugin", + "tsConfig": "libs/remix-core-plugin/tsconfig.lib.json", + "packageJson": "libs/remix-core-plugin/package.json", + "main": "libs/remix-core-plugin/src/index.ts" + } + } + } + }, + "remix-ui-solidity-compiler": { + "root": "libs/remix-ui/solidity-compiler", + "sourceRoot": "libs/remix-ui/solidity-compiler/src", + "projectType": "library", + "schematics": {}, + "architect": { + "lint": { + "builder": "@nrwl/linter:lint", + "options": { + "linter": "eslint", + "tsConfig": ["libs/remix-ui/solidity-compiler/tsconfig.lib.json"], + "exclude": [ + "**/node_modules/**", + "!libs/remix-ui/solidity-compiler/**/*" ] } } } + }, + "remix-ui-publish-to-storage": { + "root": "libs/remix-ui/publish-to-storage", + "sourceRoot": "libs/remix-ui/publish-to-storage/src", + "projectType": "library", + "schematics": {}, + "architect": { + "lint": { + "builder": "@nrwl/linter:lint", + "options": { + "linter": "eslint", + "tsConfig": ["libs/remix-ui/publish-to-storage/tsconfig.lib.json"], + "exclude": [ + "**/node_modules/**", + "!libs/remix-ui/publish-to-storage/**/*" + ] + } + } + } + }, + "remix-ui-renderer": { + "root": "libs/remix-ui/renderer", + "sourceRoot": "libs/remix-ui/renderer/src", + "projectType": "library", + "schematics": {}, + "architect": { + "lint": { + "builder": "@nrwl/linter:lint", + "options": { + "linter": "eslint", + "tsConfig": ["libs/remix-ui/renderer/tsconfig.lib.json"], + "exclude": ["**/node_modules/**", "!libs/remix-ui/renderer/**/*"] + } + + } + } } }, "cli": {