diff --git a/.github/workflows/publish-action.yml b/.github/workflows/publish-action.yml index 3fb3a3031f..9cf0674850 100644 --- a/.github/workflows/publish-action.yml +++ b/.github/workflows/publish-action.yml @@ -9,18 +9,20 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 - - run: yarn install + - uses: actions/setup-node@v3 + with: + node-version: 14.17.6 + - run: yarn install - run: ls - run: pwd - run: yarn run downloadsolc_assets - run: yarn run build:production - - run: echo "action_state=$('./apps/remix-ide/ci/publishIpfs')" >> $GITHUB_ENV + - run: echo "action_state=$('./apps/remix-ide/ci/publishIpfs' ${{ secrets.IPFS_PROJET_ID }} ${{ secrets.IPFS_PROJECT_SECRET }})" >> $GITHUB_ENV - uses: mshick/add-pr-comment@v1 with: message: | ipfs://${{ env.action_state }} - https://ipfs.remixproject.org/ipfs/${{ env.action_state }} - https://gateway.ipfs.io/ipfs/${{ env.action_state }} + https://remix-project.infura-ipfs.io/ipfs/${{ env.action_state }} repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token-user-login: 'github-actions[bot]' # The user.login for temporary GitHub tokens allow-repeats: false # This is the default diff --git a/apps/remix-ide-e2e/src/commands/verifyContracts.ts b/apps/remix-ide-e2e/src/commands/verifyContracts.ts index aef1b06217..f29c3e42c6 100644 --- a/apps/remix-ide-e2e/src/commands/verifyContracts.ts +++ b/apps/remix-ide-e2e/src/commands/verifyContracts.ts @@ -2,7 +2,7 @@ import { NightwatchBrowser } from 'nightwatch' import EventEmitter from 'events' class VerifyContracts extends EventEmitter { - command (this: NightwatchBrowser, compiledContractNames: string[], opts = { wait: 1000, version: null }): NightwatchBrowser { + command (this: NightwatchBrowser, compiledContractNames: string[], opts = { wait: 1000, version: null, runs: '200' }): NightwatchBrowser { this.api.perform((done) => { verifyContracts(this.api, compiledContractNames, opts, () => { done() @@ -13,13 +13,13 @@ class VerifyContracts extends EventEmitter { } } -function verifyContracts (browser: NightwatchBrowser, compiledContractNames: string[], opts: { wait: number, version?: string }, callback: VoidFunction) { +function verifyContracts (browser: NightwatchBrowser, compiledContractNames: string[], opts: { wait: number, version?: string, runs?: string }, callback: VoidFunction) { browser .clickLaunchIcon('solidity') .pause(opts.wait) .pause(5000) .waitForElementPresent('*[data-id="compiledContracts"] option', 60000) - .perform((done) => { + .perform(async (done) => { if (opts.version) { browser .click('*[data-id="compilation-details"]') @@ -36,10 +36,28 @@ function verifyContracts (browser: NightwatchBrowser, compiledContractNames: str done() callback() }) - } else { - compiledContractNames.forEach((name) => { - browser.waitForElementContainsText('[data-id="compiledContracts"]', name, 60000) + } if (opts.runs) { + browser + .click('*[data-id="compilation-details"]') + .waitForElementVisible('*[data-id="remixui_treeviewitem_metadata"]') + .pause(2000) + .click('*[data-id="remixui_treeviewitem_metadata"]') + .waitForElementVisible('*[data-id="treeViewDivtreeViewItemsettings"]') + .pause(2000) + .click('*[data-id="treeViewDivtreeViewItemsettings"]') + .waitForElementVisible('*[data-id="treeViewDivtreeViewItemoptimizer"]') + .click('*[data-id="treeViewDivtreeViewItemoptimizer"]') + .waitForElementVisible('*[data-id="treeViewDivruns"]') + .assert.containsText('*[data-id="treeViewDivruns"]', `${opts.runs}`) + .click('[data-id="workspacesModalDialog-modal-footer-ok-react"]') + .perform(() => { + done() + callback() }) + } else { + for (const index in compiledContractNames) { + await browser.waitForElementContainsText('[data-id="compiledContracts"]', compiledContractNames[index], 60000) + } done() callback() } diff --git a/apps/remix-ide-e2e/src/tests/ballot.test.ts b/apps/remix-ide-e2e/src/tests/ballot.test.ts index 794dee9775..5244241e89 100644 --- a/apps/remix-ide-e2e/src/tests/ballot.test.ts +++ b/apps/remix-ide-e2e/src/tests/ballot.test.ts @@ -122,6 +122,24 @@ module.exports = { }) // Test in Udapp UI , treeViewDiv0 shows returned value on method click .assert.containsText('*[data-id="treeViewDiv0"]', 'bytes32: winnerName_ 0x48656c6c6f20576f726c64210000000000000000000000000000000000000000') + }, + + 'Compile Ballot using config file': function (browser: NightwatchBrowser) { + browser + .addFile('cf.json', {content: configFile}) + .clickLaunchIcon('solidity') + .waitForElementVisible('*[data-id="scConfigExpander"]') + .click('*[data-id="scConfigExpander"]') + .waitForElementVisible('*[data-id="scFileConfiguration"]', 10000) + .click('*[data-id="scFileConfiguration"]') + .waitForElementVisible('*[data-id="scConfigChangeFilePath"]', 10000) + .click('*[data-id="scConfigChangeFilePath"]') + .waitForElementVisible('*[data-id="scConfigFilePathInput"]', 10000) + .clearValue('*[data-id="scConfigFilePathInput"]') + .setValue('*[data-id="scConfigFilePathInput"]', 'cf.json') + .sendKeys('*[data-id$="scConfigFilePathInput"]', browser.Keys.ENTER) + .openFile('Untitled.sol') + .verifyContracts(['Ballot'], {wait: 2000, runs: '300'}) .end() } } @@ -190,6 +208,7 @@ const stateCheck = { immutable: false } } + const ballotABI = `[ { "inputs": [ @@ -356,3 +375,22 @@ const ballotABI = `[ "type": "function" } ]` + +const configFile = ` +{ + "language": "Solidity", + "settings": { + "optimizer": { + "enabled": true, + "runs": 300 + }, + "outputSelection": { + "*": { + "": ["ast"], + "*": ["abi", "metadata", "devdoc", "userdoc", "storageLayout", "evm.legacyAssembly", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "evm.gasEstimates", "evm.assembly"] + } + }, + "evmVersion": "byzantium" + } +} +` \ No newline at end of file diff --git a/apps/remix-ide-e2e/src/tests/compiler_api.test.ts b/apps/remix-ide-e2e/src/tests/compiler_api.test.ts index 2adc5a4c62..0646b83f80 100644 --- a/apps/remix-ide-e2e/src/tests/compiler_api.test.ts +++ b/apps/remix-ide-e2e/src/tests/compiler_api.test.ts @@ -168,3 +168,4 @@ contract DoesNotCompile { function fStackLimit(uint u1, uint u2, uint u3, uint u4, uint u5, uint u6, uint u7, uint u8, uint u9, uint u10, uint u11, uint u12) public { } }` + diff --git a/apps/remix-ide-e2e/src/tests/plugin_api.ts b/apps/remix-ide-e2e/src/tests/plugin_api.ts index cf696f2bec..faabf03247 100644 --- a/apps/remix-ide-e2e/src/tests/plugin_api.ts +++ b/apps/remix-ide-e2e/src/tests/plugin_api.ts @@ -231,7 +231,6 @@ module.exports = { 'Should get current files #group7': async function (browser: NightwatchBrowser) { await clickAndCheckLog(browser, 'fileManager:readdir', { - 'compiler_config.json': { isDirectory: false }, contracts: { isDirectory: true }, scripts: { isDirectory: true }, tests: { isDirectory: true }, @@ -286,15 +285,12 @@ module.exports = { 'Should create empty workspace #group2': async function (browser: NightwatchBrowser) { await clickAndCheckLog(browser, 'filePanel:createWorkspace', null, null, ['emptyworkspace', true]) await clickAndCheckLog(browser, 'filePanel:getCurrentWorkspace', { name: 'emptyworkspace', isLocalhost: false, absolutePath: '.workspaces/emptyworkspace' }, null, null) - await clickAndCheckLog(browser, 'fileManager:readdir', { - 'compiler_config.json': { isDirectory: false } - }, null, '/') + await clickAndCheckLog(browser, 'fileManager:readdir', {}, null, '/') }, 'Should create workspace #group2': async function (browser: NightwatchBrowser) { await clickAndCheckLog(browser, 'filePanel:createWorkspace', null, null, 'testspace') await clickAndCheckLog(browser, 'filePanel:getCurrentWorkspace', { name: 'testspace', isLocalhost: false, absolutePath: '.workspaces/testspace' }, null, null) await clickAndCheckLog(browser, 'fileManager:readdir', { - 'compiler_config.json': { isDirectory: false }, contracts: { isDirectory: true }, scripts: { isDirectory: true }, tests: { isDirectory: true }, diff --git a/apps/remix-ide-e2e/src/tests/publishContract.test.ts b/apps/remix-ide-e2e/src/tests/publishContract.test.ts index e1a19ccabb..38ee1c3e54 100644 --- a/apps/remix-ide-e2e/src/tests/publishContract.test.ts +++ b/apps/remix-ide-e2e/src/tests/publishContract.test.ts @@ -19,17 +19,22 @@ module.exports = { .openFile('contracts/3_Ballot.sol') .verifyContracts(['Ballot']) .click('#publishOnIpfs') + .pause(2000) + .waitForElementVisible('[data-id="publishToStorageModalDialogModalBody-react"]', 60000) + .click('[data-id="publishToStorage-modal-footer-ok-react"]') .pause(8000) .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') + if (value.indexOf('Metadata and sources of "ballot" were published successfully.') === -1) browser.assert.fail('ipfs deploy failed') done() }) }) .click('[data-id="publishToStorage-modal-footer-ok-react"]') + .openFile('ipfs/QmSUodhSvoorFL5m5CNqve8YvmuBpjCq17NbTf4GUX8ydw') + .openFile('ipfs/QmXYUS1ueS22EqNVRaKuZa31EgHLjKZ8uTM8vWhQLxa3pw') }, /* Disableing the test untill refactoring and the new swarm usage @@ -41,7 +46,7 @@ module.exports = { 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('Metadata and sources of "ballot" were published successfully.') === -1) browser.assert.fail('swarm deploy failed') if (value.indexOf('bzz') === -1) browser.assert.fail('swarm deploy failed') done() }) @@ -61,11 +66,13 @@ module.exports = { .waitForElementVisible('*[data-id="Deploy - transact (not payable)"]') .click('*[data-id="Deploy - transact (not payable)"]') .pause(5000) - .waitForElementVisible('[data-id="udappModalDialogModalBody-react"]') + .waitForElementVisible('[data-id="udappModalDialogModalBody-react"]', 60000) + .modalFooterOKClick('udapp') + .pause(8000) .getText('[data-id="udappModalDialogModalBody-react"]', (result) => { const value = typeof result.value === 'string' ? result.value : null - if (value.indexOf('Metadata of "storage" was published successfully.') === -1) browser.assert.fail('ipfs deploy failed') + if (value.indexOf('Metadata and sources of "storage" were published successfully.') === -1) browser.assert.fail('ipfs deploy failed') }) .modalFooterOKClick('udapp') }, diff --git a/apps/remix-ide-e2e/src/tests/search.test.ts b/apps/remix-ide-e2e/src/tests/search.test.ts index f7925fb9ea..b2cff57b7c 100644 --- a/apps/remix-ide-e2e/src/tests/search.test.ts +++ b/apps/remix-ide-e2e/src/tests/search.test.ts @@ -33,11 +33,11 @@ module.exports = { .clearValue('*[id="search_include"]').pause(2000) .setValue('*[id="search_include"]', '**').sendKeys('*[id="search_include"]', browser.Keys.ENTER).pause(4000) .elements('css selector', '.search_plugin_search_line', (res) => { - Array.isArray(res.value) && browser.assert.equal(res.value.length, 48) + Array.isArray(res.value) && browser.assert.equal(res.value.length, 61) }) .setValue('*[id="search_exclude"]', ',contracts/**').sendKeys('*[id="search_exclude"]', browser.Keys.ENTER).pause(4000) .elements('css selector', '.search_plugin_search_line', (res) => { - Array.isArray(res.value) && browser.assert.equal(res.value.length, 42) + Array.isArray(res.value) && browser.assert.equal(res.value.length, 55) }) .clearValue('*[id="search_include"]').setValue('*[id="search_include"]', '*.sol, *.js, *.txt') .clearValue('*[id="search_exclude"]').setValue('*[id="search_exclude"]', '.*/**/*') diff --git a/apps/remix-ide-e2e/src/tests/terminal.test.ts b/apps/remix-ide-e2e/src/tests/terminal.test.ts index fb828248fe..a824c7871f 100644 --- a/apps/remix-ide-e2e/src/tests/terminal.test.ts +++ b/apps/remix-ide-e2e/src/tests/terminal.test.ts @@ -291,7 +291,7 @@ const deployWithEthersJs = ` // 'web3Provider' is a remix global variable object const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner() - let factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer); + let factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer) let contract = await factory.deploy(...constructorArgs); @@ -320,7 +320,7 @@ describe("Storage with lib", function () { // Make sure contract is compiled and artifacts are generated const metadata = JSON.parse(await remix.call('fileManager', 'getFile', 'contracts/artifacts/Storage.json')) const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner() - let Storage = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer); + let Storage = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer) let storage = await Storage.deploy(); console.log('storage contract Address: ' + storage.address); await storage.deployed() @@ -330,7 +330,7 @@ describe("Storage with lib", function () { it("test updating and retrieving updated value", async function () { const metadata = JSON.parse(await remix.call('fileManager', 'getFile', 'contracts/artifacts/Storage.json')) const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner() - let Storage = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer); + let Storage = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer) let storage = await Storage.deploy(); await storage.deployed() const setValue = await storage.store(56); @@ -341,7 +341,7 @@ describe("Storage with lib", function () { it("fail test updating and retrieving updated value", async function () { const metadata = JSON.parse(await remix.call('fileManager', 'getFile', 'contracts/artifacts/Storage.json')) const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner() - let Storage = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer); + let Storage = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer) let storage = await Storage.deploy(); await storage.deployed() const setValue = await storage.store(56); diff --git a/apps/remix-ide-e2e/src/tests/workspace.test.ts b/apps/remix-ide-e2e/src/tests/workspace.test.ts index f5fea02e36..7e7cfbd55e 100644 --- a/apps/remix-ide-e2e/src/tests/workspace.test.ts +++ b/apps/remix-ide-e2e/src/tests/workspace.test.ts @@ -68,14 +68,14 @@ module.exports = { .click('*[data-id="treeViewLitreeViewItemscripts/web3-lib.ts"]') .pause(2000) .getEditorValue((content) => { - browser.assert.ok(content.indexOf(`export const deploy = async (contractName: string, args: Array, from?: string, gas?: number): Promise => {`) !== -1, + browser.assert.ok(content.indexOf(`export const deploy = async (contractName: string, args: Array, from?: string, gas?: number): Promise => {`) !== -1, 'Incorrect content') }) .assert.elementPresent('*[data-id="treeViewLitreeViewItemscripts/ethers-lib.ts"]') .click('*[data-id="treeViewLitreeViewItemscripts/ethers-lib.ts"]') .pause(100) .getEditorValue((content) => { - browser.assert.ok(content.indexOf(`export const deploy = async (contractName: string, args: Array, from?: string): Promise => { `) !== -1, + browser.assert.ok(content.indexOf(`export const deploy = async (contractName: string, args: Array, accountIndex?: number): Promise => {`) !== -1, 'Incorrect content') }) .assert.elementPresent('*[data-id="treeViewLitreeViewItemtests"]') @@ -107,8 +107,7 @@ module.exports = { const fileList = document.querySelector('*[data-id="treeViewUltreeViewMenu"]') return fileList.getElementsByTagName('li').length; }, [], function(result){ - // check there are no files in FE except config file - browser.assert.equal(result.value, 1, 'Incorrect number of files'); + browser.assert.equal(result.value, 0, 'Incorrect number of files'); }); }, @@ -146,14 +145,14 @@ module.exports = { .click('*[data-id="treeViewLitreeViewItemscripts/web3-lib.ts"]') .pause(100) .getEditorValue((content) => { - browser.assert.ok(content.indexOf(`export const deploy = async (contractName: string, args: Array, from?: string, gas?: number): Promise => {`) !== -1, + browser.assert.ok(content.indexOf(`export const deploy = async (contractName: string, args: Array, from?: string, gas?: number): Promise => {`) !== -1, 'Incorrect content') }) .assert.elementPresent('*[data-id="treeViewLitreeViewItemscripts/ethers-lib.ts"]') .click('*[data-id="treeViewLitreeViewItemscripts/ethers-lib.ts"]') .pause(100) .getEditorValue((content) => { - browser.assert.ok(content.indexOf(`export const deploy = async (contractName: string, args: Array, from?: string): Promise => { `) !== -1, + browser.assert.ok(content.indexOf(`export const deploy = async (contractName: string, args: Array, accountIndex?: number): Promise => {`) !== -1, 'Incorrect content') }) .assert.elementPresent('*[data-id="treeViewLitreeViewItemtests"]') @@ -194,14 +193,14 @@ module.exports = { .click('*[data-id="treeViewLitreeViewItemscripts/web3-lib.ts"]') .pause(100) .getEditorValue((content) => { - browser.assert.ok(content.indexOf(`export const deploy = async (contractName: string, args: Array, from?: string, gas?: number): Promise => {`) !== -1, + browser.assert.ok(content.indexOf(`export const deploy = async (contractName: string, args: Array, from?: string, gas?: number): Promise => {`) !== -1, 'Incorrect content') }) .assert.elementPresent('*[data-id="treeViewLitreeViewItemscripts/ethers-lib.ts"]') .click('*[data-id="treeViewLitreeViewItemscripts/ethers-lib.ts"]') .pause(100) .getEditorValue((content) => { - browser.assert.ok(content.indexOf(`export const deploy = async (contractName: string, args: Array, from?: string): Promise => { `) !== -1, + browser.assert.ok(content.indexOf(`export const deploy = async (contractName: string, args: Array, accountIndex?: number): Promise => {`) !== -1, 'Incorrect content') }) .assert.elementPresent('*[data-id="treeViewLitreeViewItemtests"]') diff --git a/apps/remix-ide-e2e/src/types/index.d.ts b/apps/remix-ide-e2e/src/types/index.d.ts index e8698d4407..7fbcb174d5 100644 --- a/apps/remix-ide-e2e/src/types/index.d.ts +++ b/apps/remix-ide-e2e/src/types/index.d.ts @@ -11,7 +11,7 @@ declare module 'nightwatch' { testContracts(fileName: string, contractCode: NightwatchContractContent, compiledContractNames: string[]): NightwatchBrowser, setEditorValue(value: string, callback?: () => void): NightwatchBrowser, addFile(name: string, content: NightwatchContractContent): NightwatchBrowser, - verifyContracts(compiledContractNames: string[], opts?: { wait: number, version?: string }): NightwatchBrowser, + verifyContracts(compiledContractNames: string[], opts?: { wait: number, version?: string, runs?: string }): NightwatchBrowser, selectAccount(account?: string): NightwatchBrowser, clickFunction(fnFullName: string, expectedInput?: NightwatchClickFunctionExpectedInput): NightwatchBrowser, testFunction(txHash: string, expectedInput: NightwatchTestFunctionExpectedInput): NightwatchBrowser, diff --git a/apps/remix-ide/ci/publishIpfs b/apps/remix-ide/ci/publishIpfs index 0f8fd96ca0..15d2dc9b66 100755 --- a/apps/remix-ide/ci/publishIpfs +++ b/apps/remix-ide/ci/publishIpfs @@ -5,8 +5,14 @@ const { globSource } = IpfsHttpClient const folder = process.cwd() + '/dist/apps/remix-ide'; (async () => { - const host = 'ipfs.remixproject.org' - const ipfs = IpfsHttpClient({ host, port: 443, protocol: 'https' }) + const host = 'ipfs.infura.io' + const projectId = process.argv[2] + const projectSecret = process.argv[3] + const auth = 'Basic ' + Buffer.from(projectId + ':' + projectSecret).toString('base64') + + const ipfs = IpfsHttpClient({ port: 5001, host, protocol: 'https', headers: { + authorization: auth + } }) try { let result = await ipfs.add(globSource(folder, { recursive: true}), { pin: false }) const hash = result.cid.toString() diff --git a/apps/remix-ide/src/app/editor/editor.js b/apps/remix-ide/src/app/editor/editor.js index 9bf7e3fec6..97dc63f988 100644 --- a/apps/remix-ide/src/app/editor/editor.js +++ b/apps/remix-ide/src/app/editor/editor.js @@ -1,5 +1,6 @@ 'use strict' import React from 'react' // eslint-disable-line +import { resolve } from 'path' import { EditorUI } from '@remix-ui/editor' // eslint-disable-line import { Plugin } from '@remixproject/engine' import * as packageJson from '../../../../../package.json' @@ -140,16 +141,62 @@ class Editor extends Plugin { this.on('sidePanel', 'pluginDisabled', (name) => { this.clearAllDecorationsFor(name) }) - this.on('fileManager', 'fileClosed', (name) => { - if (name === this.currentFile) { - this.currentFile = null - this.renderComponent() - } - }) this.on('theme', 'themeLoaded', (theme) => { this.currentThemeType = theme.quality this.renderComponent() }) + this.on('fileManager', 'currentFileChanged', async (name) => { + if (name.endsWith('.ts')) { + // extract the import, resolve their content + // and add the imported files to Monaco through the `addModel` + // so Monaco can provide auto completion + let content = await this.call('fileManager', 'readFile', name) + const paths = name.split('/') + paths.pop() + const fromPath = paths.join('/') // get current execution context path + for (const match of content.matchAll(/import\s+.*\s+from\s+(?:"(.*?)"|'(.*?)')/g)) { + let path = match[2] + if (path.startsWith('./') || path.startsWith('../')) path = resolve(fromPath, path) + if (path.startsWith('/')) path = path.substring(1) + if (!path.endsWith('.ts')) path = path + '.ts' + if (await this.call('fileManager', 'exists', path)) { + content = await this.call('fileManager', 'readFile', path) + this.emit('addModel', content, 'typescript', path, false) + } + } + } + }) + + this.on('fileManager', 'noFileSelected', async () => { + this.currentFile = null + this.renderComponent() + }) + this.on('fileManager', 'currentFileChanged', async (name) => { + if (name.endsWith('.ts')) { + // extract the import, resolve their content + // and add the imported files to Monaco through the `addModel` + // so Monaco can provide auto completion + let content = await this.call('fileManager', 'readFile', name) + const paths = name.split('/') + paths.pop() + const fromPath = paths.join('/') // get current execution context path + for (const match of content.matchAll(/import\s+.*\s+from\s+(?:"(.*?)"|'(.*?)')/g)) { + let path = match[2] + if (path.startsWith('./') || path.startsWith('../')) path = resolve(fromPath, path) + if (path.startsWith('/')) path = path.substring(1) + if (!path.endsWith('.ts')) path = path + '.ts' + if (await this.call('fileManager', 'exists', path)) { + content = await this.call('fileManager', 'readFile', path) + this.emit('addModel', content, 'typescript', path, false) + } + } + } + }) + + this.on('fileManager', 'noFileSelected', async () => { + this.currentFile = null + this.renderComponent() + }) try { this.currentThemeType = (await this.call('theme', 'currentTheme')).quality } catch (e) { diff --git a/apps/remix-ide/src/app/files/fileManager.ts b/apps/remix-ide/src/app/files/fileManager.ts index aa02851c3e..e7ae4763df 100644 --- a/apps/remix-ide/src/app/files/fileManager.ts +++ b/apps/remix-ide/src/app/files/fileManager.ts @@ -4,7 +4,7 @@ import * as packageJson from '../../../../../package.json' import Registry from '../state/registry' import { EventEmitter } from 'events' import { RemixAppManager } from '../../../../../libs/remix-ui/plugin-manager/src/types' -import { fileChangedToastMsg, storageFullMessage } from '@remix-ui/helper' +import { fileChangedToastMsg, recursivePasteToastMsg, storageFullMessage } from '@remix-ui/helper' import helper from '../../lib/helper.js' /* @@ -275,7 +275,7 @@ class FileManager extends Plugin { const provider = this.fileProviderOf(src) if (provider.isSubDirectory(src, dest)) { - this.call('notification', 'toast', 'File(s) to paste is an ancestor of the destination folder') + this.call('notification', 'toast', recursivePasteToastMsg()) } else { await this.inDepthCopy(src, dest) } diff --git a/apps/remix-ide/src/app/panels/layout.ts b/apps/remix-ide/src/app/panels/layout.ts index 33704eef35..37a0ee6fe4 100644 --- a/apps/remix-ide/src/app/panels/layout.ts +++ b/apps/remix-ide/src/app/panels/layout.ts @@ -57,9 +57,6 @@ export class Layout extends Plugin { this.panels.main.active = false this.event.emit('change', null) }) - this.on('tabs', 'tabCountChanged', async count => { - if (!count) await this.call('manager', 'activatePlugin', 'home') - }) this.on('manager', 'activate', (profile: Profile) => { switch (profile.name) { case 'filePanel': diff --git a/apps/remix-ide/src/app/panels/tab-proxy.js b/apps/remix-ide/src/app/panels/tab-proxy.js index 645b30ecce..82758c169f 100644 --- a/apps/remix-ide/src/app/panels/tab-proxy.js +++ b/apps/remix-ide/src/app/panels/tab-proxy.js @@ -283,7 +283,12 @@ export class TabProxy extends Plugin { delete this._handlers[name] let previous = currentFileTab this.loadedTabs = this.loadedTabs.filter((tab, index) => { - if (!previous && tab.name === name) previous = this.loadedTabs[index - 1] + if (!previous && tab.name === name) { + if(index - 1 >= 0 && this.loadedTabs[index - 1]) + previous = this.loadedTabs[index - 1] + else if (index + 1 && this.loadedTabs[index + 1]) + previous = this.loadedTabs[index + 1] + } return tab.name !== name }) this.renderComponent() diff --git a/apps/remix-ide/src/app/plugins/remixd-handle.tsx b/apps/remix-ide/src/app/plugins/remixd-handle.tsx index edaf7683d5..da3b2506b9 100644 --- a/apps/remix-ide/src/app/plugins/remixd-handle.tsx +++ b/apps/remix-ide/src/app/plugins/remixd-handle.tsx @@ -135,23 +135,28 @@ export class RemixdHandle extends WebsocketPlugin { function remixdDialog () { const commandText = 'remixd' + const fullCommandText = 'remixd -s -u ' return (<>
- 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 documentation. + Access your local file system from Remix IDE using Remixd NPM package.
- If you are just looking for the remixd command, here it is: -

- Go to your working directory and then run: -

{commandText} - + Remixd documentation.
- 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 + The remixd command is: +
{commandText} +
+
+ The remixd command without options uses the terminal's current directory as the shared directory and the shared Remix domain can only be https://remix.ethereum.org, https://remix-alpha.ethereum.org, or https://remix-beta.ethereum.org +
+
+ Example command with flags:
+ {fullCommandText} +
+
+ For info about ports, see Remixd ports usage
This feature is still in Alpha. We recommend to keep a backup of the shared folder. diff --git a/apps/remix-ide/src/app/tabs/compile-tab.js b/apps/remix-ide/src/app/tabs/compile-tab.js index 8e3d17e366..23a53846f7 100644 --- a/apps/remix-ide/src/app/tabs/compile-tab.js +++ b/apps/remix-ide/src/app/tabs/compile-tab.js @@ -56,6 +56,10 @@ class CompileTab extends CompilerApiMixin(ViewPlugin) { // implements ICompilerA this.renderComponent() } + onFileRemoved () { + this.renderComponent() + } + onNoFileSelected () { this.renderComponent() } diff --git a/apps/solidity-compiler/src/app/compiler-api.ts b/apps/solidity-compiler/src/app/compiler-api.ts index 8a5437359c..3065af630a 100644 --- a/apps/solidity-compiler/src/app/compiler-api.ts +++ b/apps/solidity-compiler/src/app/compiler-api.ts @@ -19,6 +19,7 @@ export const CompilerApiMixin = (Base) => class extends Base { onCurrentFileChanged: (fileName: string) => void // onResetResults: () => void onSetWorkspace: (isLocalhost: boolean, workspaceName: string) => void + onFileRemoved: (path: string) => void onNoFileSelected: () => void onCompilationFinished: (compilationDetails: { contractMap: { file: string } | Record, contractsDetails: Record }) => void onSessionSwitched: () => void @@ -240,6 +241,10 @@ export const CompilerApiMixin = (Base) => class extends Base { if (this.onSetWorkspace) this.onSetWorkspace(workspace.isLocalhost, workspace.name) }) + this.on('fileManager', 'fileRemoved', (path) => { + if (this.onFileRemoved) this.onFileRemoved(path) + }) + this.on('remixd', 'rootFolderChanged', () => { this.resetResults() if (this.onSetWorkspace) this.onSetWorkspace(true, 'localhost') @@ -282,36 +287,34 @@ export const CompilerApiMixin = (Base) => class extends Base { type: 'warning' }) } else this.statusChanged({ key: 'succeed', title: 'compilation successful', type: 'success' }) - // Store the contracts - this.compilationDetails.contractsDetails = {} - this.compiler.visitContracts((contract) => { - this.compilationDetails.contractsDetails[contract.name] = parseContracts( - contract.name, - contract.object, - this.compiler.getSource(contract.file) - ) - }) } else { const count = (data.errors ? data.errors.filter(error => error.severity === 'error').length : 0 + (data.error ? 1 : 0)) this.statusChanged({ key: count, title: `compilation failed with ${count} error${count > 1 ? 's' : ''}`, type: 'error' }) } - // Update contract Selection - this.compilationDetails.contractMap = {} - if (success) this.compiler.visitContracts((contract) => { this.compilationDetails.contractMap[contract.name] = contract }) - this.compilationDetails.target = source.target + // Store the contracts and Update contract Selection + if (success) { + this.compilationDetails = await this.visitsContractApi(source, data) + } else { + this.compilationDetails = { + contractMap: {}, + contractsDetails: {}, + target: source.target + } + } if (this.onCompilationFinished) this.onCompilationFinished(this.compilationDetails) // set annotations if (data.errors) { for (const error of data.errors) { let pos = helper.getPositionDetails(error.formattedMessage) - if (pos.errFile) { + const file = pos.errFile + if (file) { pos = { row: pos.errLine, column: pos.errCol, text: error.formattedMessage, type: error.severity } - await this.call('editor', 'addAnnotation', pos, pos.errFile) + await this.call('editor', 'addAnnotation', pos, file) } } } @@ -332,11 +335,40 @@ export const CompilerApiMixin = (Base) => class extends Base { // ctrl+s or command+s if ((e.metaKey || e.ctrlKey) && !e.shiftKey && e.keyCode === 83 && this.currentFile !== '') { e.preventDefault() - if(await this.getAppParameter('hardhat-compilation')) this.compileTabLogic.runCompiler('hardhat') - else if(await this.getAppParameter('truffle-compilation')) this.compileTabLogic.runCompiler('truffle') - else this.compileTabLogic.runCompiler(undefined) + if (this.currentFile && (this.currentFile.endsWith('.sol') || this.currentFile.endsWith('.yul'))) { + if(await this.getAppParameter('hardhat-compilation')) this.compileTabLogic.runCompiler('hardhat') + else if(await this.getAppParameter('truffle-compilation')) this.compileTabLogic.runCompiler('truffle') + else this.compileTabLogic.runCompiler(undefined) + } } } window.document.addEventListener('keydown', this.data.eventHandlers.onKeyDown) } + + async visitsContractApi (source, data): Promise<{ contractMap: { file: string } | Record, contractsDetails: Record, target?: string }> { + return new Promise((resolve) => { + if (!data.contracts || (data.contracts && Object.keys(data.contracts).length === 0)) { + return resolve({ + contractMap: {}, + contractsDetails: {}, + target: source.target + }) + } + const contractMap = {} + const contractsDetails = {} + this.compiler.visitContracts((contract) => { + contractMap[contract.name] = contract + contractsDetails[contract.name] = parseContracts( + contract.name, + contract.object, + this.compiler.getSource(contract.file) + ) + }) + return resolve({ + contractMap, + contractsDetails, + target: source.target + }) + }) + } } diff --git a/libs/remix-analyzer/package.json b/libs/remix-analyzer/package.json index 903e5f3c15..22d8646744 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.22", + "version": "0.5.23", "description": "Tool to perform static analysis on Solidity smart contracts", "main": "src/index.js", "types": "src/index.d.ts", @@ -22,8 +22,8 @@ "@ethereumjs/block": "^3.5.1", "@ethereumjs/tx": "^3.3.2", "@ethereumjs/vm": "^5.5.3", - "@remix-project/remix-astwalker": "^0.0.43", - "@remix-project/remix-lib": "^0.5.13", + "@remix-project/remix-astwalker": "^0.0.44", + "@remix-project/remix-lib": "^0.5.14", "async": "^2.6.2", "ethereumjs-util": "^7.0.10", "ethers": "^5.4.2", @@ -52,5 +52,5 @@ "typescript": "^3.7.5" }, "typings": "src/index.d.ts", - "gitHead": "2be5108c51f2ac9226e4598c512ec6d3c63f5c78" + "gitHead": "3f311aaf25f5796f70711006bb783ee4087ffc71" } \ No newline at end of file diff --git a/libs/remix-astwalker/package.json b/libs/remix-astwalker/package.json index 6a76dcf6dc..60e7f14374 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.43", + "version": "0.0.44", "description": "Tool to walk through Solidity AST", "main": "src/index.js", "scripts": { @@ -37,7 +37,7 @@ "@ethereumjs/block": "^3.5.1", "@ethereumjs/tx": "^3.3.2", "@ethereumjs/vm": "^5.5.3", - "@remix-project/remix-lib": "^0.5.13", + "@remix-project/remix-lib": "^0.5.14", "@types/tape": "^4.2.33", "async": "^2.6.2", "ethereumjs-util": "^7.0.10", @@ -54,5 +54,5 @@ "tap-spec": "^5.0.0" }, "typings": "src/index.d.ts", - "gitHead": "2be5108c51f2ac9226e4598c512ec6d3c63f5c78" + "gitHead": "3f311aaf25f5796f70711006bb783ee4087ffc71" } \ No newline at end of file diff --git a/libs/remix-debug/package.json b/libs/remix-debug/package.json index 8d26e36358..e70aba4523 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.13", + "version": "0.5.14", "description": "Tool to debug Ethereum transactions", "contributors": [ { @@ -22,9 +22,9 @@ "@ethereumjs/common": "^2.5.0", "@ethereumjs/tx": "^3.3.2", "@ethereumjs/vm": "^5.5.3", - "@remix-project/remix-astwalker": "^0.0.43", - "@remix-project/remix-lib": "^0.5.13", - "@remix-project/remix-simulator": "^0.2.13", + "@remix-project/remix-astwalker": "^0.0.44", + "@remix-project/remix-lib": "^0.5.14", + "@remix-project/remix-simulator": "^0.2.14", "ansi-gray": "^0.1.1", "async": "^2.6.2", "color-support": "^1.1.3", @@ -68,5 +68,5 @@ }, "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme", "typings": "src/index.d.ts", - "gitHead": "2be5108c51f2ac9226e4598c512ec6d3c63f5c78" + "gitHead": "3f311aaf25f5796f70711006bb783ee4087ffc71" } \ No newline at end of file diff --git a/libs/remix-lib/package.json b/libs/remix-lib/package.json index 9decef15f7..1a26aee068 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.13", + "version": "0.5.14", "description": "Library to various Remix tools", "contributors": [ { @@ -54,5 +54,5 @@ }, "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme", "typings": "src/index.d.ts", - "gitHead": "2be5108c51f2ac9226e4598c512ec6d3c63f5c78" + "gitHead": "3f311aaf25f5796f70711006bb783ee4087ffc71" } \ No newline at end of file diff --git a/libs/remix-lib/src/types/ICompilerApi.ts b/libs/remix-lib/src/types/ICompilerApi.ts index f34d20f420..259aa2547a 100644 --- a/libs/remix-lib/src/types/ICompilerApi.ts +++ b/libs/remix-lib/src/types/ICompilerApi.ts @@ -25,6 +25,7 @@ export interface ICompilerApi { onCurrentFileChanged: (fileName: string) => void // onResetResults: () => void, onSetWorkspace: (isLocalhost: boolean, workspaceName: string) => void + onFileRemoved: (path: string) => void onNoFileSelected: () => void onCompilationFinished: (contractsDetails: any, contractMap: any) => void onSessionSwitched: () => void diff --git a/libs/remix-simulator/package.json b/libs/remix-simulator/package.json index 95985105e7..edebf864e9 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.13", + "version": "0.2.14", "description": "Ethereum IDE and tools for the web", "contributors": [ { @@ -18,7 +18,7 @@ "@ethereumjs/common": "^2.5.0", "@ethereumjs/tx": "^3.3.2", "@ethereumjs/vm": "^5.5.3", - "@remix-project/remix-lib": "^0.5.13", + "@remix-project/remix-lib": "^0.5.14", "ansi-gray": "^0.1.1", "async": "^3.1.0", "body-parser": "^1.18.2", @@ -67,5 +67,5 @@ }, "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-simulator#readme", "typings": "src/index.d.ts", - "gitHead": "2be5108c51f2ac9226e4598c512ec6d3c63f5c78" + "gitHead": "3f311aaf25f5796f70711006bb783ee4087ffc71" } \ No newline at end of file diff --git a/libs/remix-simulator/src/methods/blocks.ts b/libs/remix-simulator/src/methods/blocks.ts index 1ecc7b30e4..e2594b05ac 100644 --- a/libs/remix-simulator/src/methods/blocks.ts +++ b/libs/remix-simulator/src/methods/blocks.ts @@ -40,7 +40,6 @@ export class Blocks { return cb(new Error('block not found')) } - console.log(block.transactions) const transactions = block.transactions.map((t) => { const hash = '0x' + t.hash().toString('hex') const tx = this.vmContext.txByHash[hash] @@ -95,7 +94,6 @@ export class Blocks { eth_getBlockByHash (payload, cb) { const block = this.vmContext.blocks[payload.params[0]] - console.log(block.transactions) const transactions = block.transactions.map((t) => { const hash = '0x' + t.hash().toString('hex') const tx = this.vmContext.txByHash[hash] diff --git a/libs/remix-solidity/package.json b/libs/remix-solidity/package.json index 351f9ab46f..bc1038ded4 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.13", + "version": "0.5.0", "description": "Tool to load and run Solidity compiler", "main": "src/index.js", "types": "src/index.d.ts", @@ -18,7 +18,7 @@ "@ethereumjs/block": "^3.5.1", "@ethereumjs/tx": "^3.3.2", "@ethereumjs/vm": "^5.5.3", - "@remix-project/remix-lib": "^0.5.13", + "@remix-project/remix-lib": "^0.5.14", "async": "^2.6.2", "eslint-scope": "^5.0.0", "ethereumjs-util": "^7.0.10", @@ -61,5 +61,5 @@ }, "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-solidity#readme", "typings": "src/index.d.ts", - "gitHead": "2be5108c51f2ac9226e4598c512ec6d3c63f5c78" + "gitHead": "3f311aaf25f5796f70711006bb783ee4087ffc71" } \ No newline at end of file diff --git a/libs/remix-tests/package.json b/libs/remix-tests/package.json index 35e805d91f..2029b0ed7e 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.13", + "version": "0.2.14", "description": "Tool to test Solidity smart contracts", "main": "src/index.js", "types": "./src/index.d.ts", @@ -39,9 +39,9 @@ "@ethereumjs/common": "^2.5.0", "@ethereumjs/tx": "^3.3.2", "@ethereumjs/vm": "^5.5.3", - "@remix-project/remix-lib": "^0.5.13", - "@remix-project/remix-simulator": "^0.2.13", - "@remix-project/remix-solidity": "^0.4.13", + "@remix-project/remix-lib": "^0.5.14", + "@remix-project/remix-simulator": "^0.2.14", + "@remix-project/remix-solidity": "^0.5.0", "ansi-gray": "^0.1.1", "async": "^2.6.0", "axios": ">=0.21.1", @@ -79,5 +79,5 @@ "typescript": "^3.3.1" }, "typings": "src/index.d.ts", - "gitHead": "2be5108c51f2ac9226e4598c512ec6d3c63f5c78" + "gitHead": "3f311aaf25f5796f70711006bb783ee4087ffc71" } \ No newline at end of file diff --git a/libs/remix-ui/editor/src/lib/remix-plugin-types.ts b/libs/remix-ui/editor/src/lib/remix-plugin-types.ts index ef781936c0..ceb49f5399 100644 --- a/libs/remix-ui/editor/src/lib/remix-plugin-types.ts +++ b/libs/remix-ui/editor/src/lib/remix-plugin-types.ts @@ -226,7 +226,7 @@ declare interface CondensedCompilationInput { optimize: boolean /** e.g: 0.6.8+commit.0bbfe453 */ version: string - evmVersion?: 'istanbul' | 'petersburg' | 'constantinople' | 'byzantium' | 'spuriousDragon' | 'tangerineWhistle' | 'homestead' + evmVersion?: 'berlin' | 'istanbul' | 'petersburg' | 'constantinople' | 'byzantium' | 'spuriousDragon' | 'tangerineWhistle' | 'homestead' } declare interface ContentImport { diff --git a/libs/remix-ui/editor/src/lib/web-types.ts b/libs/remix-ui/editor/src/lib/web-types.ts index 2ac05a5d26..065e4557bd 100644 --- a/libs/remix-ui/editor/src/lib/web-types.ts +++ b/libs/remix-ui/editor/src/lib/web-types.ts @@ -199,6 +199,10 @@ export const loadTypes = async (monaco) => { const indexWeb3Personal = await import('raw-loader!web3-eth-personal/types/index.d.ts') monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3Personal.default, `file:///node_modules/@types/web3-eth-personal/index.d.ts`) + // @ts-ignore + const indexWeb3Contract = await import('raw-loader!web3-eth-contract/types/index.d.ts') + monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3Contract.default, `file:///node_modules/@types/web3-eth-contract/index.d.ts`) + // @ts-ignore const indexWeb3Net = await import('raw-loader!web3-net/types/index.d.ts') monaco.languages.typescript.typescriptDefaults.addExtraLib(indexWeb3Net.default, `file:///node_modules/@types/web3-net/index.d.ts`) diff --git a/libs/remix-ui/helper/src/lib/helper-components.tsx b/libs/remix-ui/helper/src/lib/helper-components.tsx index e04e162ffc..c290f7bdf9 100644 --- a/libs/remix-ui/helper/src/lib/helper-components.tsx +++ b/libs/remix-ui/helper/src/lib/helper-components.tsx @@ -78,3 +78,9 @@ export const storageFullMessage = () => (
) + +export const recursivePasteToastMsg = () => ( +
+ File(s) to paste is an ancestor of the destination folder +
+) diff --git a/libs/remix-ui/home-tab/src/lib/components/rssFeed.css b/libs/remix-ui/home-tab/src/lib/components/rssFeed.css new file mode 100644 index 0000000000..22e231c0e0 --- /dev/null +++ b/libs/remix-ui/home-tab/src/lib/components/rssFeed.css @@ -0,0 +1,12 @@ +.RSSFeed-item img { + width: 100%; +} + +.RSSFeed-item .truncate { + max-height: 500px; + overflow: hidden; +} + +.RSSFeed-item .more-button { + +} \ No newline at end of file diff --git a/libs/remix-ui/home-tab/src/lib/components/rssFeed.tsx b/libs/remix-ui/home-tab/src/lib/components/rssFeed.tsx new file mode 100644 index 0000000000..71df031d2f --- /dev/null +++ b/libs/remix-ui/home-tab/src/lib/components/rssFeed.tsx @@ -0,0 +1,42 @@ +import React, { useState, useEffect } from "react"; +import Parser from "rss-parser"; +import './rssFeed.css'; + +interface RSSFeedProps { + feedUrl: string, + maxItems: number, +} + +export function RSSFeed({ feedUrl, maxItems }: RSSFeedProps) { + const [feed, setFeed] = useState(null); + + useEffect(() => { + const fetchData = async () => { + const parser = new Parser() + const feed = await parser.parseURL(feedUrl); + for (const item of feed.items) { + item.content = item['content:encoded'] + item.date = new Date(item.pubDate).toLocaleDateString('en-US', { + month: 'short', + day: 'numeric' + }) + } + setFeed(feed); + }; + fetchData(); + }, [feedUrl]); + + + return (<> + {feed && feed.items.slice(0, maxItems).map((item: any, index: any) => ( +
+

{item.title}

+

Author: {item.creator}

+

{item.date}

+
+ READ MORE +
+
+ ))} + ) +} \ No newline at end of file diff --git a/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx b/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx index cbb5f05179..05f7c32125 100644 --- a/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx +++ b/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx @@ -5,6 +5,7 @@ import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line import { Toaster } from '@remix-ui/toaster' // eslint-disable-line import PluginButton from './components/pluginButton' // eslint-disable-line import { ThemeContext, themes } from './themeContext' +import { RSSFeed } from './components/rssFeed' declare global { interface Window { _paq: any @@ -107,14 +108,8 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => { scriptTwitter.src = 'https://platform.twitter.com/widgets.js' scriptTwitter.async = true document.body.appendChild(scriptTwitter) - // to retrieve medium publications - const scriptMedium = document.createElement('script') - scriptMedium.src = 'https://www.twilik.com/assets/retainable/rss-embed/retainable-rss-embed.js' - scriptMedium.async = true - document.body.appendChild(scriptMedium) return () => { document.body.removeChild(scriptTwitter) - document.body.removeChild(scriptMedium) } }, []) @@ -340,17 +335,7 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => { >
- +
{ (!showFilePathInput && state.useFileConfiguration) && {state.configFilePath} } - { (!showFilePathInput&& !state.useFileConfiguration) && {state.configFilePath} } + onClick={configFilePath === '' ? () => {} : openFile} + className="py-2 remixui_compilerConfigPath" + >{configFilePath === '' ? 'No file selected.' : configFilePath} } + { (!showFilePathInput && !state.useFileConfiguration) && {configFilePath} } { if (event.key === 'Enter') { handleConfigPathChange() } }} /> - { !showFilePathInput && } + { !showFilePathInput && }
-
-
-
-
+
+
{ (global.fs.mode === 'browser') && (currentWorkspace !== NO_WORKSPACE) && , from?: string): Promise => { +/** + * Deploy the given contract + * @param {string} contractName name of the contract to deploy + * @param {Array} args list of constructor' parameters + * @param {Number} accountIndex account index from the exposed account + * @return {Contract} deployed contract + */ +export const deploy = async (contractName: string, args: Array, accountIndex?: number): Promise => { console.log(`deploying ${contractName}`) // Note that the script needs the ABI which is generated from the compilation artifact. // Make sure contract is compiled and artifacts are generated - const artifactsPath = `browser/contracts/artifacts/${contractName}.json` + const artifactsPath = `browser/contracts/artifacts/${contractName}.json` // Change this for different path const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath)) // 'web3Provider' is a remix global variable object - const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner() + + const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner(accountIndex) - const factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer); + const factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer) - let contract - if (from) { - contract = await factory.connect(from).deploy(...args); - } else { - contract = await factory.deploy(...args); - } + const contract = await factory.deploy(...args) // The contract is NOT deployed yet; we must wait until it is mined await contract.deployed() diff --git a/libs/remix-ws-templates/src/templates/ozerc20/scripts/web3-lib.ts b/libs/remix-ws-templates/src/templates/ozerc20/scripts/web3-lib.ts index 37ff2be99b..cbffde3aac 100644 --- a/libs/remix-ws-templates/src/templates/ozerc20/scripts/web3-lib.ts +++ b/libs/remix-ws-templates/src/templates/ozerc20/scripts/web3-lib.ts @@ -1,8 +1,17 @@ import Web3 from 'web3' +import { Contract, ContractSendMethod, Options } from 'web3-eth-contract' -export const deploy = async (contractName: string, args: Array, from?: string, gas?: number): Promise => { +/** + * Deploy the given contract + * @param {string} contractName name of the contract to deploy + * @param {Array} args list of constructor' parameters + * @param {string} from account used to send the transaction + * @param {number} gas gas limit + * @return {Options} deployed contract + */ +export const deploy = async (contractName: string, args: Array, from?: string, gas?: number): Promise => { - const web3 = new Web3(window.web3Provider) + const web3 = new Web3(web3Provider) console.log(`deploying ${contractName}`) // Note that the script needs the ABI which is generated from the compilation artifact. // Make sure contract is compiled and artifacts are generated @@ -12,14 +21,14 @@ export const deploy = async (contractName: string, args: Array, from?: stri const accounts = await web3.eth.getAccounts() - let contract = new web3.eth.Contract(metadata.abi) + const contract: Contract = new web3.eth.Contract(metadata.abi) - contract = contract.deploy({ + const contractSend: ContractSendMethod = contract.deploy({ data: metadata.data.bytecode.object, arguments: args }) - const newContractInstance = await contract.send({ + const newContractInstance = await contractSend.send({ from: from || accounts[0], gas: gas || 1500000 }) diff --git a/libs/remix-ws-templates/src/templates/ozerc721/scripts/ethers-lib.ts b/libs/remix-ws-templates/src/templates/ozerc721/scripts/ethers-lib.ts index 1c5f4c6548..e875db9a43 100644 --- a/libs/remix-ws-templates/src/templates/ozerc721/scripts/ethers-lib.ts +++ b/libs/remix-ws-templates/src/templates/ozerc721/scripts/ethers-lib.ts @@ -1,24 +1,27 @@ import { ethers } from 'ethers' -export const deploy = async (contractName: string, args: Array, from?: string): Promise => { +/** + * Deploy the given contract + * @param {string} contractName name of the contract to deploy + * @param {Array} args list of constructor' parameters + * @param {Number} accountIndex account index from the exposed account + * @return {Contract} deployed contract + */ +export const deploy = async (contractName: string, args: Array, accountIndex?: number): Promise => { console.log(`deploying ${contractName}`) // Note that the script needs the ABI which is generated from the compilation artifact. // Make sure contract is compiled and artifacts are generated - const artifactsPath = `browser/contracts/artifacts/${contractName}.json` + const artifactsPath = `browser/contracts/artifacts/${contractName}.json` // Change this for different path const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath)) // 'web3Provider' is a remix global variable object - const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner() + + const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner(accountIndex) - const factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer); + const factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer) - let contract - if (from) { - contract = await factory.connect(from).deploy(...args); - } else { - contract = await factory.deploy(...args); - } + const contract = await factory.deploy(...args) // The contract is NOT deployed yet; we must wait until it is mined await contract.deployed() diff --git a/libs/remix-ws-templates/src/templates/ozerc721/scripts/web3-lib.ts b/libs/remix-ws-templates/src/templates/ozerc721/scripts/web3-lib.ts index 37ff2be99b..cbffde3aac 100644 --- a/libs/remix-ws-templates/src/templates/ozerc721/scripts/web3-lib.ts +++ b/libs/remix-ws-templates/src/templates/ozerc721/scripts/web3-lib.ts @@ -1,8 +1,17 @@ import Web3 from 'web3' +import { Contract, ContractSendMethod, Options } from 'web3-eth-contract' -export const deploy = async (contractName: string, args: Array, from?: string, gas?: number): Promise => { +/** + * Deploy the given contract + * @param {string} contractName name of the contract to deploy + * @param {Array} args list of constructor' parameters + * @param {string} from account used to send the transaction + * @param {number} gas gas limit + * @return {Options} deployed contract + */ +export const deploy = async (contractName: string, args: Array, from?: string, gas?: number): Promise => { - const web3 = new Web3(window.web3Provider) + const web3 = new Web3(web3Provider) console.log(`deploying ${contractName}`) // Note that the script needs the ABI which is generated from the compilation artifact. // Make sure contract is compiled and artifacts are generated @@ -12,14 +21,14 @@ export const deploy = async (contractName: string, args: Array, from?: stri const accounts = await web3.eth.getAccounts() - let contract = new web3.eth.Contract(metadata.abi) + const contract: Contract = new web3.eth.Contract(metadata.abi) - contract = contract.deploy({ + const contractSend: ContractSendMethod = contract.deploy({ data: metadata.data.bytecode.object, arguments: args }) - const newContractInstance = await contract.send({ + const newContractInstance = await contractSend.send({ from: from || accounts[0], gas: gas || 1500000 }) diff --git a/libs/remix-ws-templates/src/templates/remixDefault/scripts/ethers-lib.ts b/libs/remix-ws-templates/src/templates/remixDefault/scripts/ethers-lib.ts index 40a478efbb..e875db9a43 100644 --- a/libs/remix-ws-templates/src/templates/remixDefault/scripts/ethers-lib.ts +++ b/libs/remix-ws-templates/src/templates/remixDefault/scripts/ethers-lib.ts @@ -1,6 +1,13 @@ import { ethers } from 'ethers' -export const deploy = async (contractName: string, args: Array, from?: string): Promise => { +/** + * Deploy the given contract + * @param {string} contractName name of the contract to deploy + * @param {Array} args list of constructor' parameters + * @param {Number} accountIndex account index from the exposed account + * @return {Contract} deployed contract + */ +export const deploy = async (contractName: string, args: Array, accountIndex?: number): Promise => { console.log(`deploying ${contractName}`) // Note that the script needs the ABI which is generated from the compilation artifact. @@ -9,16 +16,12 @@ export const deploy = async (contractName: string, args: Array, from?: stri const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath)) // 'web3Provider' is a remix global variable object - const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner() + + const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner(accountIndex) - const factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer); + const factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer) - let contract - if (from) { - contract = await factory.connect(from).deploy(...args); - } else { - contract = await factory.deploy(...args); - } + const contract = await factory.deploy(...args) // The contract is NOT deployed yet; we must wait until it is mined await contract.deployed() diff --git a/libs/remix-ws-templates/src/templates/remixDefault/scripts/web3-lib.ts b/libs/remix-ws-templates/src/templates/remixDefault/scripts/web3-lib.ts index 9ec1a2d864..cbffde3aac 100644 --- a/libs/remix-ws-templates/src/templates/remixDefault/scripts/web3-lib.ts +++ b/libs/remix-ws-templates/src/templates/remixDefault/scripts/web3-lib.ts @@ -1,25 +1,34 @@ import Web3 from 'web3' +import { Contract, ContractSendMethod, Options } from 'web3-eth-contract' -export const deploy = async (contractName: string, args: Array, from?: string, gas?: number): Promise => { +/** + * Deploy the given contract + * @param {string} contractName name of the contract to deploy + * @param {Array} args list of constructor' parameters + * @param {string} from account used to send the transaction + * @param {number} gas gas limit + * @return {Options} deployed contract + */ +export const deploy = async (contractName: string, args: Array, from?: string, gas?: number): Promise => { - const web3 = new Web3(window.web3Provider) + const web3 = new Web3(web3Provider) console.log(`deploying ${contractName}`) // Note that the script needs the ABI which is generated from the compilation artifact. // Make sure contract is compiled and artifacts are generated - const artifactsPath = `browser/contracts/artifacts/${contractName}.json` // Change this for different path + const artifactsPath = `browser/contracts/artifacts/${contractName}.json` const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath)) const accounts = await web3.eth.getAccounts() - let contract = new web3.eth.Contract(metadata.abi) + const contract: Contract = new web3.eth.Contract(metadata.abi) - contract = contract.deploy({ + const contractSend: ContractSendMethod = contract.deploy({ data: metadata.data.bytecode.object, arguments: args }) - const newContractInstance = await contract.send({ + const newContractInstance = await contractSend.send({ from: from || accounts[0], gas: gas || 1500000 }) diff --git a/libs/remix-ws-templates/src/templates/zeroxErc20/scripts/ethers-lib.ts b/libs/remix-ws-templates/src/templates/zeroxErc20/scripts/ethers-lib.ts index 1c5f4c6548..e875db9a43 100644 --- a/libs/remix-ws-templates/src/templates/zeroxErc20/scripts/ethers-lib.ts +++ b/libs/remix-ws-templates/src/templates/zeroxErc20/scripts/ethers-lib.ts @@ -1,24 +1,27 @@ import { ethers } from 'ethers' -export const deploy = async (contractName: string, args: Array, from?: string): Promise => { +/** + * Deploy the given contract + * @param {string} contractName name of the contract to deploy + * @param {Array} args list of constructor' parameters + * @param {Number} accountIndex account index from the exposed account + * @return {Contract} deployed contract + */ +export const deploy = async (contractName: string, args: Array, accountIndex?: number): Promise => { console.log(`deploying ${contractName}`) // Note that the script needs the ABI which is generated from the compilation artifact. // Make sure contract is compiled and artifacts are generated - const artifactsPath = `browser/contracts/artifacts/${contractName}.json` + const artifactsPath = `browser/contracts/artifacts/${contractName}.json` // Change this for different path const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath)) // 'web3Provider' is a remix global variable object - const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner() + + const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner(accountIndex) - const factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer); + const factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer) - let contract - if (from) { - contract = await factory.connect(from).deploy(...args); - } else { - contract = await factory.deploy(...args); - } + const contract = await factory.deploy(...args) // The contract is NOT deployed yet; we must wait until it is mined await contract.deployed() diff --git a/libs/remix-ws-templates/src/templates/zeroxErc20/scripts/web3-lib.ts b/libs/remix-ws-templates/src/templates/zeroxErc20/scripts/web3-lib.ts index 37ff2be99b..cbffde3aac 100644 --- a/libs/remix-ws-templates/src/templates/zeroxErc20/scripts/web3-lib.ts +++ b/libs/remix-ws-templates/src/templates/zeroxErc20/scripts/web3-lib.ts @@ -1,8 +1,17 @@ import Web3 from 'web3' +import { Contract, ContractSendMethod, Options } from 'web3-eth-contract' -export const deploy = async (contractName: string, args: Array, from?: string, gas?: number): Promise => { +/** + * Deploy the given contract + * @param {string} contractName name of the contract to deploy + * @param {Array} args list of constructor' parameters + * @param {string} from account used to send the transaction + * @param {number} gas gas limit + * @return {Options} deployed contract + */ +export const deploy = async (contractName: string, args: Array, from?: string, gas?: number): Promise => { - const web3 = new Web3(window.web3Provider) + const web3 = new Web3(web3Provider) console.log(`deploying ${contractName}`) // Note that the script needs the ABI which is generated from the compilation artifact. // Make sure contract is compiled and artifacts are generated @@ -12,14 +21,14 @@ export const deploy = async (contractName: string, args: Array, from?: stri const accounts = await web3.eth.getAccounts() - let contract = new web3.eth.Contract(metadata.abi) + const contract: Contract = new web3.eth.Contract(metadata.abi) - contract = contract.deploy({ + const contractSend: ContractSendMethod = contract.deploy({ data: metadata.data.bytecode.object, arguments: args }) - const newContractInstance = await contract.send({ + const newContractInstance = await contractSend.send({ from: from || accounts[0], gas: gas || 1500000 }) diff --git a/libs/remixd/package.json b/libs/remixd/package.json index 13e8c3a3f5..451cc8db16 100644 --- a/libs/remixd/package.json +++ b/libs/remixd/package.json @@ -1,6 +1,6 @@ { "name": "@remix-project/remixd", - "version": "0.6.1", + "version": "0.6.2", "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/package.json b/package.json index ec1788e7c2..478fe06031 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "remix-project", - "version": "0.24.0-dev", + "version": "0.25.0-dev", "license": "MIT", "description": "Ethereum Remix Monorepo", "keywords": [ @@ -60,7 +60,7 @@ "minify": "uglifyjs --in-source-map inline --source-map-inline -c warnings=false", "build:production": "NODE_ENV=production nx build remix-ide --skip-nx-cache", "serve:production": "npx http-server ./dist/apps/remix-ide", - "select_test": "sh apps/remix-ide-e2e/src/select_tests.sh", + "select_test": "bash apps/remix-ide-e2e/src/select_tests.sh", "group_test": "yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/${npm_config_test}_group${npm_config_group}.test.js --env=${npm_config_env}", "nightwatch_parallel": "yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js --env=chrome,firefox", "nightwatch_local_firefox": "yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js --env=firefox", @@ -198,6 +198,7 @@ "react-draggable": "^4.4.4", "react-tabs": "^3.2.2", "regenerator-runtime": "0.13.7", + "rss-parser": "^3.12.0", "selenium": "^2.20.0", "signale": "^1.4.0", "string-similarity": "^4.0.4",