diff --git a/.circleci/config.yml b/.circleci/config.yml index fbb696cec3..d2b2c89f79 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -598,6 +598,13 @@ jobs: type: string parallelism: 10 steps: + - checkout + - attach_workspace: + at: . + - run: unzip ./persist/dist.zip + - run: yarn install --cwd ./apps/remix-ide-e2e --modules-folder ../../node_modules || yarn install --cwd ./apps/remix-ide-e2e --modules-folder ../../node_modules + - run: mkdir node_modules/hardhat && wget https://unpkg.com/hardhat/console.sol -O node_modules/hardhat/console.sol + - run: ls -la ./dist/apps/remix-ide/assets/js - when: condition: equal: [ "chrome", << parameters.browser >> ] @@ -607,10 +614,8 @@ jobs: install-chrome: true install-chromedriver: false install-geckodriver: false - - install-chromedriver-custom-linux + - run: yarn install_webdriver - run: google-chrome --version - - run: chromedriver --version - - run: rm LICENSE.chromedriver 2> /dev/null || true - when: condition: equal: [ "firefox", << parameters.browser >> ] @@ -618,36 +623,10 @@ jobs: - browser-tools/install-browser-tools: install-firefox: true install-chrome: false - install-geckodriver: true + install-geckodriver: false install-chromedriver: false + - run: yarn install_webdriver - run: firefox --version - - run: geckodriver --version - - checkout - - attach_workspace: - at: . - - run: unzip ./persist/dist.zip - - run: yarn install --cwd ./apps/remix-ide-e2e --modules-folder ../../node_modules - - run: mkdir node_modules/hardhat && wget https://unpkg.com/hardhat/console.sol -O node_modules/hardhat/console.sol - - run: ls -la ./dist/apps/remix-ide/assets/js - - run: yarn run selenium-install --singleDriverInstall=firefox - - when: - condition: - equal: [ "chrome", << parameters.browser >> ] - steps: - - run: mkdir -p node_modules/selenium-standalone/.selenium/chromedriver/latest-x64/ - - run: cp ~/bin/chromedriver /home/circleci/remix-project/node_modules/selenium-standalone/.selenium/chromedriver/latest-x64/ - - run: - name: run selenium - command: yarn selenium-standalone start --singleDriverStart=chrome - background: true - - when: - condition: - equal: [ "firefox", << parameters.browser >> ] - steps: - - run: - name: run selenium - command: yarn selenium-standalone start --singleDriverStart=firefox - background: true - run: ./apps/remix-ide/ci/<< parameters.script >> << parameters.browser >> << parameters.jobsize >> << parameters.job >> - store_test_results: path: ./reports/tests @@ -674,28 +653,19 @@ jobs: default: 1 parallelism: << parameters.parallelism >> steps: + - checkout + - attach_workspace: + at: . + - run: unzip ./persist/dist.zip + - run: unzip ./persist/plugin-<< parameters.plugin >>.zip + - run: yarn install --cwd ./apps/remix-ide-e2e --modules-folder ../../node_modules || yarn install --cwd ./apps/remix-ide-e2e --modules-folder ../../node_modules - browser-tools/install-browser-tools: install-firefox: false install-chrome: true install-geckodriver: false install-chromedriver: false - - install-chromedriver-custom-linux + - run: yarn install_webdriver - run: google-chrome --version - - run: chromedriver --version - - run: rm LICENSE.chromedriver 2> /dev/null || true - - checkout - - attach_workspace: - at: . - - run: unzip ./persist/dist.zip - - run: unzip ./persist/plugin-<< parameters.plugin >>.zip - - run: yarn install --cwd ./apps/remix-ide-e2e --modules-folder ../../node_modules - - run: yarn run selenium-install --singleDriverInstall=firefox - - run: mkdir -p node_modules/selenium-standalone/.selenium/chromedriver/latest-x64/ - - run: cp ~/bin/chromedriver /home/circleci/remix-project/node_modules/selenium-standalone/.selenium/chromedriver/latest-x64/ - - run: - name: Start Selenium - command: yarn run selenium --singleDriverStart=chrome - background: true - run: ./apps/remix-ide/ci/browser_test_plugin.sh << parameters.plugin >> - store_test_results: path: ./reports/tests @@ -882,35 +852,3 @@ workflows: only: remix_beta # VS Code Extension Version: 1.5.1 -commands: - install-chromedriver-custom-linux: - description: Custom script to install chromedriver with better version support for linux - steps: - - run: - name: install-chromedriver-custom-linux - command: | - google-chrome --version > version.txt - VERSION=$(grep -Eo '[0-9]+\.' < version.txt | head -1) - # CHROMEDRIVER_URL=$(curl -s 'https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json' | jq '.channels.Stable.downloads.chromedriver[] | select(.platform == "linux64") | .url' | tr -d '"') - CHROMEDRIVER_URL=$(curl -s 'https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json' | jq --arg v "$VERSION" '.versions[] | select(.version | startswith($v)) | .downloads.chromedriver[] | select(.platform == "linux64") | .url' | tail -n1 | tr -d '"') - echo $CHROMEDRIVER_URL - ZIPFILEPATH="/tmp/chromedriver.zip" - echo "Downloading from $CHROMEDRIVER_URL" - curl -f --silent $CHROMEDRIVER_URL > "$ZIPFILEPATH" - - BINFILEPATH="$HOME/bin/chromedriver-linux" - echo "Extracting to $BINFILEPATH" - unzip -p "$ZIPFILEPATH" chromedriver-linux64/chromedriver > "$BINFILEPATH" - - echo Setting execute flag - chmod +x "$BINFILEPATH" - - echo Updating symlink - ln -nfs "$BINFILEPATH" ~/bin/chromedriver - - echo Removing ZIP file - rm "$ZIPFILEPATH" - rm version.txt - - echo Done - chromedriver -v diff --git a/.github/workflows/pr-reminder.yml b/.github/workflows/pr-reminder.yml index 567fd8e19b..37c60d323c 100644 --- a/.github/workflows/pr-reminder.yml +++ b/.github/workflows/pr-reminder.yml @@ -14,4 +14,4 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} - freeze-date: '2024-04-08T18:00:00Z' + freeze-date: '2024-04-22T18:00:00Z' diff --git a/.gitignore b/.gitignore index 082c09635c..9e40832324 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,4 @@ apps/remix-ide/src/assets/esbuild.wasm apps/remixdesktop/build* apps/remixdesktop/reports apps/remixdesktop/logs/ +logs diff --git a/README.md b/README.md index baec594045..6f79e6a0a5 100644 --- a/README.md +++ b/README.md @@ -146,21 +146,11 @@ For example, to run unit tests of `remix-analyzer`, use `nx test remix-analyzer` ## Browser Testing -To run the Selenium tests via Nightwatch: +To run the tests via Nightwatch: - - Install Selenium for the first time: `yarn run selenium-install` - - Run a selenium server: `yarn run selenium` + - Install webdrivers for the first time: `yarn install_webdriver` - Build & Serve Remix: `yarn serve` - - Run all the end-to-end tests: - for Firefox: `yarn run nightwatch_local_firefox`, or - - for Google Chrome: `yarn run nightwatch_local_chrome` - - Run a specific test case instead, use a command like this: - - - yarn run nightwatch_local_ballot - - The package.json file contains a list of all the tests you can run. **NOTE:** @@ -173,8 +163,6 @@ To run the Selenium tests via Nightwatch: gist_token = // token should have permission to create a gist ``` -### Using 'select_test' for locally running specific tests - There is a script to allow selecting the browser and a specific test to run: ``` @@ -246,12 +234,6 @@ This script will give you an options menu, just select the test you want ``` yarn run select_test ``` -#### method 2 - -``` -yarn run group_test --test=debugger --group=10 --env=chromeDesktop -``` -- specify chromeDesktop to see the browser action, use 'chrome' to run it headless ### Run the same (flaky) test across all instances in CircleCI diff --git a/apps/etherscan/src/app/utils/networks.ts b/apps/etherscan/src/app/utils/networks.ts index bcb8993499..fdb28e50a8 100644 --- a/apps/etherscan/src/app/utils/networks.ts +++ b/apps/etherscan/src/app/utils/networks.ts @@ -17,9 +17,10 @@ export const scanAPIurls = { 1101: 'https://api-zkevm.polygonscan.com/api', 59144: 'https://api.lineascan.build/api', 8453: 'https://api.basescan.org/api', + 534352: 'https://api.scrollscan.com/api', // all testnet - 5: 'https://api-goerli.etherscan.io/api', + 17000: 'https://api-holesky.etherscan.io/api', 11155111: 'https://api-sepolia.etherscan.io/api', 97: 'https://api-testnet.bscscan.com/api', 80001: 'https://api-testnet.polygonscan.com/api', @@ -37,4 +38,5 @@ export const scanAPIurls = { 84532: "https://api-sepolia.basescan.org/api", 1442: 'https://api-testnet-zkevm.polygonscan.com/api', 59140: 'https://api-testnet.lineascan.build/api', + 534351: 'https://api-sepolia.scrollscan.com/api', } diff --git a/apps/learneth/README.md b/apps/learneth/README.md index 9bf4030879..ff8a5ce950 100644 --- a/apps/learneth/README.md +++ b/apps/learneth/README.md @@ -42,11 +42,11 @@ Root directories are individual workshops, the name used will be the name of the ### README.md -The readme in each directry contains an explanation of what the workshop is about. If an additional summary property is provided in the config.yml that will be used in the overview section of the plugin. +The readme in each directory contains an explanation of what the workshop is about. If an additional summary property is provided in the config.yml that will be used in the overview section of the plugin. ### config.yml -This config file contains meta data describing some properties of your workshop, for example +This config file contains metadata describing some properties of your workshop, for example ``` --- diff --git a/apps/remix-ide-e2e/install-webdriver.sh b/apps/remix-ide-e2e/install-webdriver.sh new file mode 100644 index 0000000000..3dec4bf38e --- /dev/null +++ b/apps/remix-ide-e2e/install-webdriver.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# Determine the OS platform +OS="$(uname)" + +if [ "$OS" == "Darwin" ]; then + # macOS systems + if [ -e "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" ]; then + version=$("/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --version) + echo "Google Chrome version on macOS: $version" + else + echo "Google Chrome is not installed on your macOS." + fi +elif [ "$OS" == "Linux" ]; then + # Linux systems + if command -v google-chrome >/dev/null; then + version=$(google-chrome --version) + echo "Google Chrome version on Linux: $version" + else + echo "Google Chrome is not installed on your Linux." + fi +else + echo "Unsupported OS." +fi + +MAJORVERSION=$(echo "$version" | grep -Eo '[0-9]+\.' | head -1 | cut -d'.' -f1) +echo "CHROME DRIVER INSTALL $MAJORVERSION" + +# Specify the directory to check +directory="./tmp/webdrivers" + +# Check if the directory exists +if [ -d "$directory" ]; then + echo "Directory exists: $directory" +else + echo "Directory does not exist. Creating directory: $directory" + mkdir -p "$directory" +fi + + +yarn init -y --cwd "$directory" || exit 1 +yarn add -D chromedriver@$MAJORVERSION geckodriver --cwd "$directory" || yarn add -D chromedriver@$MAJORVERSION geckodriver --cwd "$directory" || yarn add -D chromedriver geckodriver --cwd "$directory" || exit 1 diff --git a/apps/remix-ide-e2e/nightwatch.ts b/apps/remix-ide-e2e/nightwatch-chrome.ts similarity index 71% rename from apps/remix-ide-e2e/nightwatch.ts rename to apps/remix-ide-e2e/nightwatch-chrome.ts index 7e05269897..8f1a02c923 100644 --- a/apps/remix-ide-e2e/nightwatch.ts +++ b/apps/remix-ide-e2e/nightwatch-chrome.ts @@ -1,3 +1,8 @@ +import * as fs from 'fs' + +const crxFile = fs.readFileSync('apps/remix-ide-e2e/src/extensions/chrome/11.13.1_0.crx') +const metamaskExtension = crxFile.toString('base64') + module.exports = { src_folders: ['dist/apps/remix-ide-e2e/src/tests'], output_folder: './reports/tests', @@ -6,10 +11,14 @@ module.exports = { page_objects_path: '', globals_path: '', + webdriver: { + start_process: true, + port: 9515, + server_path: './tmp/webdrivers/node_modules/chromedriver/bin/chromedriver', + }, + test_settings: { 'default': { - selenium_port: 4444, - selenium_host: 'localhost', globals: { waitForConditionTimeout: 10000, asyncHookTimeout: 100000 @@ -31,12 +40,12 @@ module.exports = { 'goog:chromeOptions': { args: [ 'window-size=2560,1440', - 'start-fullscreen', '--no-sandbox', - '--headless', + '--headless=new', '--verbose', '--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36' - ] + ], + extensions: [metamaskExtension] } } }, @@ -47,40 +56,31 @@ module.exports = { 'javascriptEnabled': true, 'acceptSslCerts': true, 'goog:chromeOptions': { - args: ['window-size=2560,1440', 'start-fullscreen', '--no-sandbox'] + args: ['window-size=2560,1440', 'start-fullscreen', '--no-sandbox', '--verbose'] } } }, - 'chrome-runAndDeploy': { + 'chromeDesktopMetamask': { desiredCapabilities: { 'browserName': 'chrome', 'javascriptEnabled': true, 'acceptSslCerts': true, 'goog:chromeOptions': { - args: ['window-size=2560,1440', 'start-fullscreen', '--no-sandbox', '--headless', '--verbose'] - } - } - }, - - 'firefoxDesktop': { - desiredCapabilities: { - 'browserName': 'firefox', - 'javascriptEnabled': true, - 'acceptSslCerts': true, - 'moz:firefoxOptions': { - args: ['-width=2560', '-height=1440'] + args: ['window-size=2560,1440', '--no-sandbox', '--verbose'] + ,extensions: [metamaskExtension] } } }, - 'firefox': { + 'chrome-runAndDeploy': { desiredCapabilities: { - 'browserName': 'firefox', + 'browserName': 'chrome', 'javascriptEnabled': true, 'acceptSslCerts': true, - 'moz:firefoxOptions': { - args: ['-headless', '-width=2560', '-height=1440'] + 'goog:chromeOptions': { + args: ['window-size=2560,1440', 'start-fullscreen', '--no-sandbox', '--headless', '--verbose'], + extensions: [metamaskExtension] } } } diff --git a/apps/remix-ide-e2e/nightwatch-firefox.ts b/apps/remix-ide-e2e/nightwatch-firefox.ts new file mode 100644 index 0000000000..f8b8d8a083 --- /dev/null +++ b/apps/remix-ide-e2e/nightwatch-firefox.ts @@ -0,0 +1,54 @@ +module.exports = { + src_folders: ['dist/apps/remix-ide-e2e/src/tests'], + output_folder: './reports/tests', + custom_commands_path: ['dist/apps/remix-ide-e2e/src/commands'], + custom_assertions_path: '', + page_objects_path: '', + globals_path: '', + + webdriver: { + start_process: true, + port: 4444, + server_path: './tmp/webdrivers/node_modules/geckodriver/bin/geckodriver.js', + }, + + test_settings: { + selenium_port: 4444, + selenium_host: 'localhost', + 'default': { + globals: { + waitForConditionTimeout: 10000, + asyncHookTimeout: 100000 + }, + screenshots: { + enabled: true, + path: './reports/screenshots', + on_failure: true, + on_error: true + }, + exclude: ['dist/apps/remix-ide-e2e/src/tests/runAndDeploy.test.js', 'dist/apps/remix-ide-e2e/src/tests/pluginManager.test.ts'] + }, + + 'firefoxDesktop': { + desiredCapabilities: { + 'browserName': 'firefox', + 'javascriptEnabled': true, + 'acceptSslCerts': true, + 'moz:firefoxOptions': { + args: ['-width=2560', '-height=1440'] + } + } + }, + + 'firefox': { + desiredCapabilities: { + 'browserName': 'firefox', + 'javascriptEnabled': true, + 'acceptSslCerts': true, + 'moz:firefoxOptions': { + args: ['-headless', '-width=2560', '-height=1440'] + } + } + } + } +} diff --git a/apps/remix-ide-e2e/package.json b/apps/remix-ide-e2e/package.json index 4153017b27..7beb0e5f87 100644 --- a/apps/remix-ide-e2e/package.json +++ b/apps/remix-ide-e2e/package.json @@ -12,7 +12,6 @@ "@openzeppelin/wizard": "^0.4.0", "@remix-project/remixd": "../../dist/libs/remixd", "deep-equal": "^1.0.1", - "selenium-standalone": "^9.0.3", "tree-kill": "^1.2.2" }, "devDependencies": { diff --git a/apps/remix-ide-e2e/src/commands/addFileSnekmate.ts b/apps/remix-ide-e2e/src/commands/addFileSnekmate.ts new file mode 100644 index 0000000000..a41cff8d06 --- /dev/null +++ b/apps/remix-ide-e2e/src/commands/addFileSnekmate.ts @@ -0,0 +1,74 @@ +import EventEmitter from 'events' +import { NightwatchBrowser, NightwatchContractContent } from 'nightwatch' + +class AddFileSnekmate extends EventEmitter { + command(this: NightwatchBrowser, name: string, content: NightwatchContractContent): NightwatchBrowser { + this.api.perform((done) => { + addFileSnekmate(this.api, name, content, () => { + done() + this.emit('complete') + }) + }) + return this + } +} + +function addFileSnekmate(browser: NightwatchBrowser, name: string, content: NightwatchContractContent, done: VoidFunction) { + browser + .isVisible({ + selector: "//*[@data-id='sidePanelSwapitTitle' and contains(.,'File explorer')]", + locateStrategy: 'xpath', + suppressNotFoundErrors: true, + timeout: 1000 + }, (okVisible) => { + if (!okVisible.value) { + browser.clickLaunchIcon('filePanel') + } + }) + .scrollInto('li[data-id="treeViewLitreeViewItemREADME.txt"]') + .waitForElementVisible('li[data-id="treeViewLitreeViewItemLICENSE"]') + .click('li[data-id="treeViewLitreeViewItemLICENSE"]').pause(1000) // focus on root directory + .isVisible({ + selector: `//*[@data-id="treeViewLitreeViewItem${name}"]`, + locateStrategy: 'xpath', + abortOnFailure: false, + suppressNotFoundErrors: true, + timeout: 2000 + }, (okVisible) => { + // @ts-ignore + // status === -1 means the element is not visible, 0 means it is visible. + if (okVisible.status === 0) { + browser.openFile(name) + .perform(function () { + done() + }) + } else { + browser.click('[data-id="fileExplorerNewFilecreateNewFile"]') + .waitForElementContainsText('*[data-id$="fileExplorerTreeItemInput"]', '', 60000) + .sendKeys('*[data-id$="fileExplorerTreeItemInput"]', name) + .sendKeys('*[data-id$="fileExplorerTreeItemInput"]', browser.Keys.ENTER) + // isvisible is protocol action called isDisplayed https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/WebElement.html#isDisplayed-- + .isVisible({ + selector: `li[data-id="treeViewLitreeViewItem${name}"]`, + abortOnFailure: false, + suppressNotFoundErrors: true, + timeout: 60000 + }) + .waitForElementVisible({ + selector: `//*[@data-id='tab-active' and contains(@data-path, "${name}")]`, + locateStrategy: 'xpath' + }) + .setEditorValue(content.content) + .getEditorValue((result) => { + if(result != content.content) { + browser.setEditorValue(content.content) + } + }) + .perform(function () { + done() + }) + } + }) +} + +module.exports = AddFileSnekmate diff --git a/apps/remix-ide-e2e/src/commands/openFile.ts b/apps/remix-ide-e2e/src/commands/openFile.ts index f214100eee..a049b125e9 100644 --- a/apps/remix-ide-e2e/src/commands/openFile.ts +++ b/apps/remix-ide-e2e/src/commands/openFile.ts @@ -31,15 +31,15 @@ function openFile (browser: NightwatchBrowser, name: string, done: VoidFunction) done() }) } - - }) - }) - .waitForElementVisible('li[data-id="treeViewLitreeViewItem' + name + '"', 60000) - .click('li[data-id="treeViewLitreeViewItem' + name + '"') - .pause(2000) - .perform(() => { - done() + + }) }) + .waitForElementVisible('li[data-id="treeViewLitreeViewItem' + name + '"', 60000) + .click('li[data-id="treeViewLitreeViewItem' + name + '"') + .pause(2000) + .perform(() => { + done() + }) } module.exports = OpenFile diff --git a/apps/remix-ide-e2e/src/commands/selectFiles.ts b/apps/remix-ide-e2e/src/commands/selectFiles.ts new file mode 100644 index 0000000000..d24ec1e42b --- /dev/null +++ b/apps/remix-ide-e2e/src/commands/selectFiles.ts @@ -0,0 +1,22 @@ +import EventEmitter from "events" +import { NightwatchBrowser } from "nightwatch" + +class SelectFiles extends EventEmitter { + command (this: NightwatchBrowser, selectedElements: any[]): NightwatchBrowser { + const browser = this.api + + browser.perform(function () { + const actions = this.actions({ async: true }) + actions.keyDown(this.Keys.SHIFT) + for(let i = 0; i < selectedElements.length; i++) { + actions.click(selectedElements[i].value) + } + return actions.contextClick(selectedElements[0].value) + }) + this.emit('complete') + return this + } +} + + +module.exports = SelectFiles diff --git a/apps/remix-ide-e2e/src/commands/setupMetamask.ts b/apps/remix-ide-e2e/src/commands/setupMetamask.ts index a113611237..768b9631bb 100644 --- a/apps/remix-ide-e2e/src/commands/setupMetamask.ts +++ b/apps/remix-ide-e2e/src/commands/setupMetamask.ts @@ -3,7 +3,7 @@ import { NightwatchBrowser } from 'nightwatch' const EventEmitter = require('events') class MetaMask extends EventEmitter { - command (this: NightwatchBrowser, passphrase: string, password: string): NightwatchBrowser { + command(this: NightwatchBrowser, passphrase: string, password: string): NightwatchBrowser { this.api.perform((done) => { setupMetaMask(this.api, passphrase, password, () => { done() @@ -14,26 +14,59 @@ class MetaMask extends EventEmitter { } } -function setupMetaMask (browser: NightwatchBrowser, passphrase: string, password: string, done: VoidFunction) { +function setupMetaMask(browser: NightwatchBrowser, passphrase: string, password: string, done: VoidFunction) { + const words = passphrase.split(' ') browser - .switchBrowserWindow('chrome-extension://poemojpkcjbpmcccohjnomjffeinlafe/home.html#initialize/welcome', 'MetaMask', (browser) => { - browser.waitForElementPresent('.first-time-flow__button') - .click('.first-time-flow__button') - .waitForElementPresent('.select-action__select-button:nth-of-type(1) > .first-time-flow__button') - .click('.select-action__select-button:nth-of-type(1) > .first-time-flow__button') - .waitForElementPresent('.page-container__footer-button:nth-of-type(2)') - .click('.page-container__footer-button:nth-of-type(2)') - .waitForElementPresent('.first-time-flow__textarea') - .setValue('.first-time-flow__textarea', passphrase) - .setValue('*[autocomplete="new-password"]', password) - .setValue('*[autocomplete="confirm-password"]', password) - .click('.first-time-flow__checkbox') - .click('.first-time-flow__button') - .pause(5000) - .click('.first-time-flow__button') - .perform(() => { - done() - }) + .switchBrowserTab(1) + .waitForElementVisible('input[data-testid="onboarding-terms-checkbox"]') + .click('input[data-testid="onboarding-terms-checkbox"]') + .waitForElementVisible('button[data-testid="onboarding-import-wallet"]') + .click('button[data-testid="onboarding-import-wallet"]') + .waitForElementVisible('button[data-testid="metametrics-i-agree"]') + .click('button[data-testid="metametrics-i-agree"]') + .waitForElementVisible('input[data-testid="import-srp__srp-word-0"]') + .setValue('input[data-testid="import-srp__srp-word-0"]', words[0]) // import account + .setValue('input[data-testid="import-srp__srp-word-1"]', words[1]) // import account + .setValue('input[data-testid="import-srp__srp-word-2"]', words[2]) // import account + .setValue('input[data-testid="import-srp__srp-word-3"]', words[3]) // import account + .setValue('input[data-testid="import-srp__srp-word-4"]', words[4]) // import account + .setValue('input[data-testid="import-srp__srp-word-5"]', words[5]) // import account + .setValue('input[data-testid="import-srp__srp-word-6"]', words[6]) // import account + .setValue('input[data-testid="import-srp__srp-word-7"]', words[7]) // import account + .setValue('input[data-testid="import-srp__srp-word-8"]', words[8]) // import account + .setValue('input[data-testid="import-srp__srp-word-9"]', words[9]) // import account + .setValue('input[data-testid="import-srp__srp-word-10"]', words[10]) // import account + .setValue('input[data-testid="import-srp__srp-word-11"]', words[11]) // import account + .click('button[data-testid="import-srp-confirm"]') + .waitForElementVisible('input[data-testid="create-password-new"]') + .setValue('input[data-testid="create-password-new"]', password) + .setValue('input[data-testid="create-password-confirm"]', password) + .click('input[data-testid="create-password-terms"]') + .click('button[data-testid="create-password-import"]') + .waitForElementVisible('button[data-testid="onboarding-complete-done"]') + .click('button[data-testid="onboarding-complete-done"]') + .waitForElementVisible('button[data-testid="pin-extension-next"]') + .click('button[data-testid="pin-extension-next"]') + .waitForElementVisible('button[data-testid="pin-extension-done"]') + .click('button[data-testid="pin-extension-done"]') + .isVisible({ + selector: 'button[data-testid="popover-close"]', + locateStrategy: 'css selector', + suppressNotFoundErrors: true, + timeout: 3000 + }, (okVisible) => { + console.log('okVisible', okVisible) + if (!okVisible.value) { + console.log('popover not found') + }else{ + browser.click('button[data-testid="popover-close"]') + } + }) + .click('[data-testid="network-display"]') + .click('.mm-modal-content label.toggle-button--off') // show test networks + .click('div[data-testid="Sepolia"]') // switch to sepolia + .perform(() => { + done() }) } diff --git a/apps/remix-ide-e2e/src/commands/switchBrowserTab.ts b/apps/remix-ide-e2e/src/commands/switchBrowserTab.ts index c37abe39a7..76db38f0aa 100644 --- a/apps/remix-ide-e2e/src/commands/switchBrowserTab.ts +++ b/apps/remix-ide-e2e/src/commands/switchBrowserTab.ts @@ -9,6 +9,7 @@ class SwitchBrowserTab extends EventEmitter { command (this: NightwatchBrowser, index: number): NightwatchBrowser { this.api.perform((browser: NightwatchAPI, done) => { browser.windowHandles((result) => { + console.log('switching to window', result) browser.switchWindow(result.value[index]) done() }) diff --git a/apps/remix-ide-e2e/src/extensions/chrome/11.13.1_0.crx b/apps/remix-ide-e2e/src/extensions/chrome/11.13.1_0.crx new file mode 100644 index 0000000000..219a0e1d03 Binary files /dev/null and b/apps/remix-ide-e2e/src/extensions/chrome/11.13.1_0.crx differ diff --git a/apps/remix-ide-e2e/src/extensions/chrome/metamask.crx b/apps/remix-ide-e2e/src/extensions/chrome/metamask.crx deleted file mode 100644 index 6cde846884..0000000000 Binary files a/apps/remix-ide-e2e/src/extensions/chrome/metamask.crx and /dev/null differ diff --git a/apps/remix-ide-e2e/src/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts index aa364da42a..e1aed5c6e4 100644 --- a/apps/remix-ide-e2e/src/helpers/init.ts +++ b/apps/remix-ide-e2e/src/helpers/init.ts @@ -10,6 +10,8 @@ type LoadPlugin = { export default function (browser: NightwatchBrowser, callback: VoidFunction, url?: string, preloadPlugins = true, loadPlugin?: LoadPlugin, hideToolTips: boolean = true): void { browser .url(url || 'http://127.0.0.1:8080') + .pause(5000) + .switchBrowserTab(0) .perform((done) => { if (!loadPlugin) return done() browser diff --git a/apps/remix-ide-e2e/src/select_tests.sh b/apps/remix-ide-e2e/src/select_tests.sh index 6216b824dd..3c6440def7 100644 --- a/apps/remix-ide-e2e/src/select_tests.sh +++ b/apps/remix-ide-e2e/src/select_tests.sh @@ -3,7 +3,7 @@ # Bash Menu Script Example PS3='Select a browser: ' -BROWSERS=( "chrome" "chrome headless" "firefox" "exit" ) +BROWSERS=( "chrome" "chrome with metamask" "firefox" "exit" ) select opt in "${BROWSERS[@]}" do case $opt in @@ -12,9 +12,9 @@ do BROWSER="chromeDesktop" break ;; - "chrome headless") - echo "Chrome headless selected" - BROWSER="chrome" + "chrome with metamask") + echo "Chrome metamask selected" + BROWSER="chromeDesktopMetamask" break ;; "firefox") @@ -47,6 +47,15 @@ do done else # run the selected test - yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js $opt --env=$BROWSER + if [ "$BROWSER" = "firefoxDesktop" ]; then + yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch-firefox.js $opt --env=$BROWSER + elif [ "$BROWSER" = "chrome" ]; then + yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch-chrome.js $opt --env=$BROWSER + elif [ "$BROWSER" = "chromeDesktop" ]; then + yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch-chrome.js $opt --env=$BROWSER + elif [ "$BROWSER" = "chromeDesktopMetamask" ]; then + yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch-chrome.js $opt --env=$BROWSER + fi + fi done diff --git a/apps/remix-ide-e2e/src/tests/circom.test.ts b/apps/remix-ide-e2e/src/tests/circom.test.ts index 0f7d9e87ec..2f64844faa 100644 --- a/apps/remix-ide-e2e/src/tests/circom.test.ts +++ b/apps/remix-ide-e2e/src/tests/circom.test.ts @@ -23,9 +23,15 @@ module.exports = { .waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits"]') .waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits/semaphore.circom"]') .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts"]') - .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/run_setup.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16/groth16_trusted_setup.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16/groth16_zkproof.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk/plonk_trusted_setup.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk/plonk_zkproof.ts"]') .waitForElementVisible('*[data-id="treeViewLitreeViewItemtemplates"]') .waitForElementVisible('*[data-id="treeViewLitreeViewItemtemplates/groth16_verifier.sol.ejs"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtemplates/plonk_verifier.sol.ejs"]') }, 'Should compile a simple circuit using editor play button #group1': function (browser: NightwatchBrowser) { browser @@ -143,6 +149,105 @@ module.exports = { .frameParent() .clickLaunchIcon('filePanel') .waitForElementPresent('[data-id="treeViewLitreeViewItemcircuits/.bin/simple.wasm"]') + }, + 'Should create a new workspace using hash checker template #group5 #group6': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('filePanel') + .click('*[data-id="workspacesMenuDropdown"]') + .click('*[data-id="workspacecreate"]') + .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') + .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button') + .click('select[id="wstemplate"]') + .click('select[id="wstemplate"] option[value=hashchecker]') + .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') + .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() }) + .pause(100) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits/calculate_hash.circom"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16/groth16_trusted_setup.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16/groth16_zkproof.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk/plonk_trusted_setup.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk/plonk_zkproof.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtemplates"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtemplates/groth16_verifier.sol.ejs"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtemplates/plonk_verifier.sol.ejs"]') + }, + 'Should run groth16 trusted setup script for hash checker #group5': function (browser: NightwatchBrowser) { + browser + .click('[data-id="treeViewLitreeViewItemscripts/groth16/groth16_trusted_setup.ts"]') + .waitForElementPresent('[data-path="Hash Checker - 1/scripts/groth16/groth16_trusted_setup.ts"]') + .waitForElementVisible('[data-path="Hash Checker - 1/scripts/groth16/groth16_trusted_setup.ts"]') + .waitForElementPresent('[data-id="verticalIconsKindcircuit-compiler"]') + .waitForElementVisible('[data-id="verticalIconsKindcircuit-compiler"]') + .click('[data-id="play-editor"]') + .pause(2000) + .journalLastChildIncludes('Generating R1CS for circuits/calculate_hash.circom') + .pause(5000) + .journalLastChildIncludes('Everything went okay') + .journalLastChildIncludes('newZkey') + .pause(25000) + .journalLastChildIncludes('setup done.') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemzk/keys/groth16/verification_key.json"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemzk/keys/groth16/zkey_final.txt"]') + }, + 'Should run groth16 zkproof script for hash checker #group5': function (browser: NightwatchBrowser) { + browser + .click('[data-id="treeViewLitreeViewItemscripts/groth16/groth16_zkproof.ts"]') + .waitForElementPresent('[data-path="Hash Checker - 1/scripts/groth16/groth16_zkproof.ts"]') + .waitForElementVisible('[data-path="Hash Checker - 1/scripts/groth16/groth16_zkproof.ts"]') + .waitForElementPresent('[data-id="verticalIconsKindcircuit-compiler"]') + .waitForElementVisible('[data-id="verticalIconsKindcircuit-compiler"]') + .click('[data-id="play-editor"]') + .pause(2000) + .journalLastChildIncludes('Compiling circuits/calculate_hash.circom') + .pause(5000) + .journalLastChildIncludes('Everything went okay') + .journalLastChildIncludes('WITNESS CHECKING STARTED') + .pause(5000) + .journalLastChildIncludes('WITNESS CHECKING FINISHED SUCCESSFULLY') + .pause(2000) + .journalLastChildIncludes('zk proof validity') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemzk/build/groth16/zk_verifier.sol"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemzk/build/groth16/input.json"]') + }, + 'Should run plonk trusted setup script for hash checker #group6': function (browser: NightwatchBrowser) { + browser + .click('[data-id="treeViewLitreeViewItemscripts/plonk/plonk_trusted_setup.ts"]') + .waitForElementPresent('[data-path="Hash Checker - 1/scripts/plonk/plonk_trusted_setup.ts"]') + .waitForElementVisible('[data-path="Hash Checker - 1/scripts/plonk/plonk_trusted_setup.ts"]') + .waitForElementPresent('[data-id="verticalIconsKindcircuit-compiler"]') + .waitForElementVisible('[data-id="verticalIconsKindcircuit-compiler"]') + .click('[data-id="play-editor"]') + .pause(2000) + .journalLastChildIncludes('Generating R1CS for circuits/calculate_hash.circom') + .pause(5000) + .journalLastChildIncludes('Everything went okay') + .journalLastChildIncludes('plonk setup') + .pause(10000) + .journalLastChildIncludes('setup done') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemzk/keys/plonk/verification_key.json"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemzk/keys/plonk/zkey_final.txt"]') + }, + 'Should run plonk zkproof script for hash checker #group6': function (browser: NightwatchBrowser) { + browser + .click('[data-id="treeViewLitreeViewItemscripts/plonk/plonk_zkproof.ts"]') + .waitForElementPresent('[data-path="Hash Checker - 1/scripts/plonk/plonk_zkproof.ts"]') + .waitForElementVisible('[data-path="Hash Checker - 1/scripts/plonk/plonk_zkproof.ts"]') + .waitForElementPresent('[data-id="verticalIconsKindcircuit-compiler"]') + .waitForElementVisible('[data-id="verticalIconsKindcircuit-compiler"]') + .click('[data-id="play-editor"]') + .pause(2000) + .journalLastChildIncludes('Compiling circuits/calculate_hash.circom') + .pause(5000) + .journalLastChildIncludes('Everything went okay') + .pause(5000) + .journalLastChildIncludes('zk proof validity') + .journalLastChildIncludes('proof done.') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemzk/build/plonk/zk_verifier.sol"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemzk/build/plonk/input.json"]') } } diff --git a/apps/remix-ide-e2e/src/tests/file_explorer_multiselect.test.ts b/apps/remix-ide-e2e/src/tests/file_explorer_multiselect.test.ts new file mode 100644 index 0000000000..1d31d6a9b5 --- /dev/null +++ b/apps/remix-ide-e2e/src/tests/file_explorer_multiselect.test.ts @@ -0,0 +1,27 @@ +import { NightwatchBrowser } from 'nightwatch' +import init from '../helpers/init' + +module.exports = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + init(browser, done) + }, + + 'Should select multiple items in file explorer #group1': function (browser: NightwatchBrowser) { + const selectedElements = [] + browser + .openFile('contracts') + .click({ selector: '//*[@data-id="treeViewLitreeViewItemcontracts/1_Storage.sol"]', locateStrategy: 'xpath' }) + .findElement({ selector: '//*[@data-id="treeViewLitreeViewItemcontracts/2_Owner.sol"]', locateStrategy: 'xpath' }, (el) => { + selectedElements.push(el) + }) + browser.findElement({ selector: '//*[@data-id="treeViewLitreeViewItemtests"]', locateStrategy: 'xpath' }, + (el: any) => { + selectedElements.push(el) + }) + browser.selectFiles(selectedElements) + .assert.visible('.bg-secondary[data-id="treeViewLitreeViewItemcontracts/1_Storage.sol"]') + .assert.visible('.bg-secondary[data-id="treeViewLitreeViewItemcontracts/2_Owner.sol"]') + .assert.visible('.bg-secondary[data-id="treeViewLitreeViewItemtests"]') + .end() + } +} diff --git a/apps/remix-ide-e2e/src/tests/pinned_contracts.test.ts b/apps/remix-ide-e2e/src/tests/pinned_contracts.test.ts new file mode 100644 index 0000000000..8c57a89947 --- /dev/null +++ b/apps/remix-ide-e2e/src/tests/pinned_contracts.test.ts @@ -0,0 +1,106 @@ +'use strict' +import { NightwatchBrowser } from 'nightwatch' +import init from '../helpers/init' + +module.exports = { + '@disabled': true, + before: function (browser: NightwatchBrowser, done: VoidFunction) { + init(browser, done) + }, + 'Should show text in pinned contracts section #group1': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('udapp') + .assert.elementPresent('*[data-id="pinnedContracts"]') + .assert.textContains('*[data-id="pinnedContractsSublabel"]', '(network: vm-cancun)') + .assert.elementPresent('*[data-id="NoPinnedInstanceText"]') + .assert.textContains('*[data-id="NoPinnedInstanceText"]', 'No pinned contracts found for selected workspace & network') + }, + 'Deploy & pin contract #group1': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('filePanel') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]') + .click('*[data-id="treeViewLitreeViewItemcontracts"]') + .click('*[data-id="treeViewLitreeViewItemcontracts/1_Storage.sol"]') + .clickLaunchIcon('udapp') + .click('*[data-id="Deploy - transact (not payable)"]') + .assert.elementPresent('*[data-id="unpinnedInstance0xd9145CCE52D386f254917e481eB44e9943F39138"]') + .click('*[data-id="universalDappUiUdappPin"]') + .assert.elementPresent('*[data-id="deployAndRunNoInstanceText"]') + .assert.textContains('*[data-id="deployAndRunNoInstanceText"]', 'Currently you have no unpinned contracts to interact with.') + .assert.not.elementPresent('*[data-id="NoPinnedInstanceText"]') + .assert.elementPresent('*[data-id="pinnedInstance0xd9145CCE52D386f254917e481eB44e9943F39138"]') + }, + 'Test pinned contract loading on environment change #group1': function (browser: NightwatchBrowser) { + browser + .switchEnvironment('vm-shanghai') + .assert.elementPresent('*[data-id="pinnedContracts"]') + .assert.textContains('*[data-id="pinnedContractsSublabel"]', '(network: vm-shanghai)') + .assert.elementPresent('*[data-id="NoPinnedInstanceText"]') + .assert.textContains('*[data-id="NoPinnedInstanceText"]', 'No pinned contracts found for selected workspace & network') + .switchEnvironment('vm-cancun') + .assert.textContains('*[data-id="pinnedContractsSublabel"]', '(network: vm-cancun)') + .assert.not.elementPresent('*[data-id="NoPinnedInstanceText"]') + .assert.elementPresent('*[data-id="pinnedInstance0xd9145CCE52D386f254917e481eB44e9943F39138"]') + }, + 'Interact with pinned contract #group1': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="universalDappUiTitleExpander0"]') + .assert.elementPresent('*[data-id="instanceContractBal"]') + .assert.elementPresent('*[data-id="instanceContractPinnedAt"]') + .assert.elementPresent('*[data-id="instanceContractFilePath"]') + .assert.textContains('*[data-id="instanceContractFilePath"]', 'default_workspace/contracts/1_Storage.sol') + .clickFunction('retrieve - call') + .testFunction('last', + { + to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138', + 'decoded output': { "0": "uint256: 0" } + }) + .clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '35' }) + .testFunction('last', + { + status: '0x1 Transaction mined and execution succeed', + 'decoded input': { "uint256 num": "35" } + }) + .clickFunction('retrieve - call') + .testFunction('last', + { + to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138', + 'decoded output': { "0": "uint256: 35" } + }) + }, + 'Unpin & interact #group1': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="universalDappUiUdappUnpin"]') + .assert.textContains('*[data-id="NoPinnedInstanceText"]', 'No pinned contracts found for selected workspace & network') + .assert.not.elementPresent('*[data-id="deployAndRunNoInstanceText"]') + .click('*[data-id="universalDappUiTitleExpander0"]') + .assert.not.elementPresent('*[data-id="instanceContractPinnedAt"]') + .assert.not.elementPresent('*[data-id="instanceContractFilePath"]') + .clickFunction('retrieve - call') + .testFunction('last', + { + to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138', + 'decoded output': { "0": "uint256: 35" } + }) + .clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '55' }) + .testFunction('last', + { + status: '0x1 Transaction mined and execution succeed', + 'decoded input': { "uint256 num": "55" } + }) + .clickFunction('retrieve - call') + .testFunction('last', + { + to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138', + 'decoded output': { "0": "uint256: 55" } + }) + }, + 'Re-pin & delete immediately #group1': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="universalDappUiUdappPin"]') + .assert.elementPresent('*[data-id="deployAndRunNoInstanceText"]') + .click('*[data-id="universalDappUiUdappDelete"]') + .assert.textContains('*[data-id="NoPinnedInstanceText"]', 'No pinned contracts found for selected workspace & network') + .assert.textContains('*[data-id="deployAndRunNoInstanceText"]', 'Currently you have no unpinned contracts to interact with.') + }, +} diff --git a/apps/remix-ide-e2e/src/tests/runAndDeploy.test.ts b/apps/remix-ide-e2e/src/tests/runAndDeploy.test.ts index 24388def61..8af5c611d9 100644 --- a/apps/remix-ide-e2e/src/tests/runAndDeploy.test.ts +++ b/apps/remix-ide-e2e/src/tests/runAndDeploy.test.ts @@ -2,9 +2,6 @@ import { NightwatchBrowser } from 'nightwatch' import init from '../helpers/init' -const passphrase = process.env.account_passphrase -const password = process.env.account_password - module.exports = { '@disabled': true, before: function (browser: NightwatchBrowser, done: VoidFunction) { @@ -113,132 +110,7 @@ module.exports = { // Consider adding tests to check return value of contract call // See: https://github.com/ethereum/remix-project/pull/1229 .end() - }, - - 'Should connect to Goerli Test Network using MetaMask': !function (browser: NightwatchBrowser) { - browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]') - .setupMetamask(passphrase, password) - .click('.network-indicator__down-arrow') - .useXpath().click("//span[text()='Goerli Test Network']") - .useCss().switchBrowserTab(0) - .refreshPage() - .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) - .click('*[data-id="landingPageStartSolidity"]') - .pause(5000) - .clickLaunchIcon('udapp') - .waitForElementPresent('*[data-id="settingsSelectEnvOptions"]') - .click('*[data-id="settingsSelectEnvOptions"] option[id="injected-mode"]') - .waitForElementPresent('*[data-id="settingsNetworkEnv"]') - .assert.containsText('*[data-id="settingsNetworkEnv"]', 'Goerli (5) network') - .switchBrowserTab(2) - .waitForElementPresent('.page-container__footer-button:nth-of-type(2)') - .click('.page-container__footer-button:nth-of-type(2)') - .switchBrowserTab(0) - }, - - 'Should deploy contract on Goerli Test Network using MetaMask': !function (browser: NightwatchBrowser) { - browser.waitForElementPresent('*[data-id="runTabSelectAccount"] option') - .clickLaunchIcon('filePanel') - .openFile('Greet.sol') - .clickLaunchIcon('udapp') - .waitForElementPresent('*[data-id="Deploy - transact (not payable)"]') - .click('*[data-id="Deploy - transact (not payable)"]') - .switchBrowserTab(2) - .waitForElementPresent('.transaction-status--unapproved') - .click('.transaction-status--unapproved') - .waitForElementPresent('.page-container__footer-button:nth-of-type(2)') - .click('.page-container__footer-button:nth-of-type(2)') - .waitForElementPresent('.transaction-status--submitted') - .pause(25000) - .switchBrowserTab(0) - }, - - 'Should run low level interaction (fallback function) on Goerli Test Network using MetaMask': !function (browser: NightwatchBrowser) { - browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]') - .waitForElementPresent('*[data-id="universalDappUiTitleExpander"]') - .click('*[data-id="universalDappUiTitleExpander"]') - .waitForElementPresent('*[data-id="pluginManagerSettingsDeployAndRunLLTxSendTransaction"]') - .click('*[data-id="pluginManagerSettingsDeployAndRunLLTxSendTransaction"]') - .switchBrowserTab(2) - .waitForElementPresent('.transaction-status--unapproved') - .click('.transaction-status--unapproved') - .waitForElementPresent('.page-container__footer-button:nth-of-type(2)') - .click('.page-container__footer-button:nth-of-type(2)') - .waitForElementPresent('.transaction-status--submitted') - .pause(25000) - .switchBrowserTab(0) - .end() - }, - - 'Should connect to Ethereum Main Network using MetaMask': !function (browser: NightwatchBrowser) { - browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]') - .switchBrowserTab(2) - .waitForElementPresent('.network-indicator__down-arrow') - .click('.network-indicator__down-arrow') - .useXpath().click("//span[text()='Main Ethereum Network']") - .useCss().switchBrowserTab(0) - .refreshPage() - .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) - .click('*[data-id="landingPageStartSolidity"]') - .pause(5000) - .clickLaunchIcon('udapp') - .waitForElementPresent('*[data-id="settingsSelectEnvOptions"]') - .click('*[data-id="settingsSelectEnvOptions"] option[id="injected-mode"]') - .waitForElementPresent('*[data-id="settingsNetworkEnv"]') - .assert.containsText('*[data-id="settingsNetworkEnv"]', 'Main (1) network') - }, - - 'Should deploy contract on Ethereum Main Network using MetaMask': !function (browser: NightwatchBrowser) { - browser.waitForElementPresent('*[data-id="runTabSelectAccount"] option') - .clickLaunchIcon('filePanel') - .openFile('Greet.sol') - .clickLaunchIcon('udapp') - .waitForElementPresent('*[data-id="Deploy - transact (not payable)"]') - .click('*[data-id="Deploy - transact (not payable)"]') - .waitForElementPresent('*[data-id="modalDialogContainer"]', 15000) - .pause(10000) - .assert.containsText('*[data-id="modalDialogModalBody"]', 'You are creating a transaction on the main network. Click confirm if you are sure to continue.') - .modalFooterCancelClick() - }, - - /* - * This test is using 3 different services: - * - Metamask for getting the transaction - * - Source Verifier service for fetching the contract code - * - Ropsten node for retrieving the trace and storage - * - */ - 'Should debug Ropsten transaction with source highlighting using the source verifier service and MetaMask': !function (browser: NightwatchBrowser) { - browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]') - .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) - .switchBrowserTab(2) - .waitForElementPresent('.network-indicator__down-arrow') - .click('.network-indicator__down-arrow') - .useXpath().click("//span[text()='Ropsten Test Network']") // switch to Ropsten - .useCss().switchBrowserTab(0) - .refreshPage() - .clickLaunchIcon('pluginManager') // load debugger and source verification - // .scrollAndClick('#pluginManager article[id="remixPluginManagerListItem_sourcify"] button') - // debugger already activated .scrollAndClick('#pluginManager article[id="remixPluginManagerListItem_debugger"] button') - .clickLaunchIcon('udapp') - .waitForElementPresent('*[data-id="settingsSelectEnvOptions"]') - .click('*[data-id="settingsSelectEnvOptions"] option[id="injected-mode"]') // switch to Ropsten in udapp - .waitForElementPresent('*[data-id="settingsNetworkEnv"]') - .assert.containsText('*[data-id="settingsNetworkEnv"]', 'Ropsten (3) network') - .clickLaunchIcon('debugger') - .setValue('*[data-id="debuggerTransactionInput"]', '0x959371506b8f6223d71c709ac2eb2d0158104dca2d76ca949f1662712cf0e6db') // debug tx - .click('*[data-id="debuggerTransactionStartButton"]') - .waitForElementVisible('*[data-id="treeViewDivto"]', 30000) - .assert.containsText('*[data-id="stepdetail"]', 'loaded address:\n0x3c943Fb816694d7D1f4C738e3e7823818a88DD6C') - .assert.containsText('*[data-id="solidityLocals"]', 'to: 0x6C3CCC7FBA111707D5A1AAF2758E9D4F4AC5E7B1') - }, - - 'Call web3.eth.getAccounts() using Injected Provider (Metamask)': !function (browser: NightwatchBrowser) { - browser - .executeScriptInTerminal('web3.eth.getAccounts()') - .journalLastChildIncludes('[ "0x76a3ABb5a12dcd603B52Ed22195dED17ee82708f" ]') - .end() - }, + }, 'Should ensure that save environment state is checked by default #group4 #group5': function (browser: NightwatchBrowser) { browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]') diff --git a/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts b/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts new file mode 100644 index 0000000000..8f29fbd5ca --- /dev/null +++ b/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts @@ -0,0 +1,272 @@ +'use strict' +import { NightwatchBrowser } from 'nightwatch' +import init from '../helpers/init' + +const passphrase = process.env.account_passphrase +const password = process.env.account_password +const extension_id = 'nkbihfbeogaeaoehlefnkodbefgpgknn' +const extension_url = `chrome-extension://${extension_id}/home.html` + +const checkBrowserIsChrome = function (browser: NightwatchBrowser) { + return browser.browserName.indexOf('chrome') > -1 +} + +const checkAlerts = function (browser: NightwatchBrowser){ + browser.isVisible({ + selector: '//*[contains(.,"not have enough")]', + locateStrategy: 'xpath', + suppressNotFoundErrors: true, + timeout: 3000 + }, (okVisible) => { + if (okVisible.value) { + browser.assert.fail('Not enough ETH in test account!!') + browser.end() + } + }) +} + +module.exports = { + '@disabled': true, + before: function (browser: NightwatchBrowser, done: VoidFunction) { + init(browser, done) + }, + + '@sources': function () { + return sources + }, + + 'Should connect to Sepolia Test Network using MetaMask #group1': function (browser: NightwatchBrowser) { + if (!checkBrowserIsChrome(browser)) return + browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]') + .setupMetamask(passphrase, password) + .useCss().switchBrowserTab(0) + .refreshPage() + .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) + .click('*[data-id="landingPageStartSolidity"]') + .clickLaunchIcon('udapp') + .switchEnvironment('injected-MetaMask') + .waitForElementPresent('*[data-id="settingsNetworkEnv"]') + .assert.containsText('*[data-id="settingsNetworkEnv"]', 'Sepolia (11155111) network') + .pause(5000) + .switchBrowserWindow(extension_url, 'MetaMask', (browser) => { + browser + .waitForElementVisible('*[data-testid="page-container-footer-next"]') + .click('*[data-testid="page-container-footer-next"]') // this connects the metamask account to remix + .pause(2000) + .waitForElementVisible('*[data-testid="page-container-footer-next"]') + .click('*[data-testid="page-container-footer-next"]') + // .waitForElementVisible('*[data-testid="popover-close"]') + // .click('*[data-testid="popover-close"]') + }) + .switchBrowserTab(0) // back to remix + }, + + 'Should add a contract file #group1': function (browser: NightwatchBrowser) { + if (!checkBrowserIsChrome(browser)) return + browser.waitForElementVisible('*[data-id="remixIdeSidePanel"]') + .clickLaunchIcon('filePanel') + .addFile('Greet.sol', sources[0]['Greet.sol']) + .clickLaunchIcon('udapp') + .waitForElementVisible('*[data-id="Deploy - transact (not payable)"]', 45000) // wait for the contract to compile + }, + + 'Should deploy contract on Sepolia Test Network using MetaMask #group1': function (browser: NightwatchBrowser) { + if (!checkBrowserIsChrome(browser)) return + browser.clearConsole().waitForElementPresent('*[data-id="runTabSelectAccount"] option', 45000) + .clickLaunchIcon('filePanel') + .openFile('Greet.sol') + .clickLaunchIcon('udapp') + .waitForElementPresent('*[data-id="Deploy - transact (not payable)"]') + .click('*[data-id="Deploy - transact (not payable)"]') + .pause(5000) + .perform((done) => { + browser.switchBrowserWindow(extension_url, 'MetaMask', (browser) => { + checkAlerts(browser) + browser + .waitForElementPresent('[data-testid="page-container-footer-next"]') + .click('[data-testid="page-container-footer-next"]') // approve the tx + .switchBrowserTab(0) // back to remix + .waitForElementContainsText('*[data-id="terminalJournal"]', 'view on etherscan', 60000) + .waitForElementContainsText('*[data-id="terminalJournal"]', 'from: 0x76a...2708f', 60000) + .perform(() => done()) + }) + }) + }, + + 'Should run low level interaction (fallback function) on Sepolia Test Network using MetaMask #group1': function (browser: NightwatchBrowser) { + if (!checkBrowserIsChrome(browser)) return + browser.clearConsole().waitForElementPresent('*[data-id="remixIdeSidePanel"]') + .clickInstance(0) + .waitForElementPresent('*[data-id="pluginManagerSettingsDeployAndRunLLTxSendTransaction"]') + .click('*[data-id="pluginManagerSettingsDeployAndRunLLTxSendTransaction"]') + .perform((done) => { + browser.switchBrowserWindow(extension_url, 'MetaMask', (browser) => { + browser + .waitForElementPresent('[data-testid="page-container-footer-next"]') + .click('[data-testid="page-container-footer-next"]') // approve the tx + .switchBrowserTab(0) // back to remix + .waitForElementContainsText('*[data-id="terminalJournal"]', 'view on etherscan', 60000) + .waitForElementContainsText('*[data-id="terminalJournal"]', 'from: 0x76a...2708f', 60000) + .perform(() => done()) + }) + }) + }, + + 'Should connect to Ethereum Main Network using MetaMask #group1': function (browser: NightwatchBrowser) { + if (!checkBrowserIsChrome(browser)) return + browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]') + .switchBrowserTab(1) + .click('[data-testid="network-display"]') + .click('div[data-testid="Ethereum Mainnet"]') // switch to mainnet + .useCss().switchBrowserTab(0) + .refreshPage() + .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) + .click('*[data-id="landingPageStartSolidity"]') + .clickLaunchIcon('udapp') + .switchEnvironment('injected-MetaMask') + .waitForElementPresent('*[data-id="settingsNetworkEnv"]') + .assert.containsText('*[data-id="settingsNetworkEnv"]', 'Main (1) network') + }, + + 'Should deploy contract on Ethereum Main Network using MetaMask #group1': function (browser: NightwatchBrowser) { + if (!checkBrowserIsChrome(browser)) return + browser.waitForElementPresent('*[data-id="runTabSelectAccount"] option') + .clickLaunchIcon('filePanel') + .openFile('Greet.sol') + .clickLaunchIcon('udapp') + .waitForElementPresent('*[data-id="Deploy - transact (not payable)"]') + .click('*[data-id="Deploy - transact (not payable)"]') + .waitForElementVisible('*[data-id="udappNotifyModalDialogModalBody-react"]', 65000) + .modalFooterOKClick('udappNotify') + .pause(10000) + .assert.containsText('*[data-id="udappNotifyModalDialogModalBody-react"]', 'You are about to create a transaction on Main Network. Confirm the details to send the info to your provider.') + .modalFooterCancelClick('udappNotify') + }, + + 'Should deploy Ballot to Sepolia using metamask': function (browser: NightwatchBrowser) { + if (!checkBrowserIsChrome(browser)) return + browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]') + .switchBrowserTab(1) + .click('[data-testid="network-display"]') + .click('div[data-testid="Sepolia"]') // switch to sepolia + .useCss().switchBrowserTab(0) + .openFile('contracts') + .openFile('contracts/3_Ballot.sol') + .clickLaunchIcon('udapp') + .clearConsole() + .clearTransactions() + .clickLaunchIcon('udapp') + .waitForElementVisible('input[placeholder="bytes32[] proposalNames"]') + .setValue('input[placeholder="bytes32[] proposalNames"]', '["0x48656c6c6f20576f726c64210000000000000000000000000000000000000000"]') + .click('*[data-id="Deploy - transact (not payable)"]') // deploy ballot + .perform((done) => { + browser.switchBrowserWindow(extension_url, 'MetaMask', (browser) => { + browser + .waitForElementPresent('[data-testid="page-container-footer-next"]') + .click('[data-testid="page-container-footer-next"]') // approve the tx + .switchBrowserTab(0) // back to remix + .waitForElementContainsText('*[data-id="terminalJournal"]', 'view on etherscan', 60000) + .waitForElementContainsText('*[data-id="terminalJournal"]', 'from: 0x76a...2708f', 60000) + .perform(() => done()) + }) + }) + .waitForElementPresent('*[data-id="universalDappUiContractActionWrapper"]', 60000) + .clearConsole() + .clickInstance(0) + .clickFunction('delegate - transact (not payable)', { types: 'address to', values: '"0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db"' }) + .perform((done) => { // call delegate + browser.switchBrowserWindow(extension_url, 'MetaMask', (browser) => { + browser + .waitForElementPresent('[data-testid="page-container-footer-next"]') + .click('[data-testid="page-container-footer-next"]') // approve the tx + .switchBrowserTab(0) // back to remix + .waitForElementContainsText('*[data-id="terminalJournal"]', 'view on etherscan', 60000) + .waitForElementContainsText('*[data-id="terminalJournal"]', 'from: 0x76a...2708f', 60000) + .perform(() => done()) + }) + }) + .testFunction('last', + { + status: '0x1 Transaction mined and execution succeed', + 'decoded input': { 'address to': '0x4B0897b0513fdC7C541B6d9D7E929C4e5364D2dB' } + }) + }, + + /* + * This test is using 2 different services: + * - Metamask for getting the transaction + * - Sepolia node for retrieving the trace and storage + */ + 'Should debug Sepolia transaction with source highlighting MetaMask #group1': function (browser: NightwatchBrowser) { + if (!checkBrowserIsChrome(browser)) return + let txhash + browser.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) + .clickLaunchIcon('pluginManager') // load debugger and source verification + // .scrollAndClick('#pluginManager article[id="remixPluginManagerListItem_sourcify"] button') + // debugger already activated .scrollAndClick('#pluginManager article[id="remixPluginManagerListItem_debugger"] button') + .clickLaunchIcon('udapp') + .perform((done) => { + browser.getLastTransactionHash((hash) => { + txhash = hash + done() + }) + }) + .perform((done) => { + browser + .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) + .clickLaunchIcon('debugger') + .setValue('*[data-id="debuggerTransactionInput"]', txhash) // debug tx + .click('*[data-id="debuggerTransactionStartButton"]') + .waitForElementVisible('*[data-id="treeViewDivto"]', 30000) + .checkVariableDebug('soliditylocals', localsCheck) + .perform(() => done()) + }) + + }, + + 'Call web3.eth.getAccounts() using Injected Provider (Metamask) #group1': function (browser: NightwatchBrowser) { + if (!checkBrowserIsChrome(browser)) return + browser + .executeScriptInTerminal('web3.eth.getAccounts()') + .journalLastChildIncludes('["0x76a3ABb5a12dcd603B52Ed22195dED17ee82708f"]') + } +} + +const localsCheck = { + to: { + value: '0x4B0897B0513FDC7C541B6D9D7E929C4E5364D2DB', + type: 'address' + } +} + +const sources = [ + { + 'Greet.sol': { + content: + ` + pragma solidity ^0.8.0; + contract HelloWorld { + string public message; + + fallback () external { + message = 'Hello World!'; + } + + function greet(string memory _message) public { + message = _message; + } + }` + }, + 'checkBalance.sol': { + content: `pragma solidity ^0.8.0; + contract CheckBalance { + constructor () payable {} + + function sendSomeEther(uint256 num) public { + payable(msg.sender).transfer(num); + } + + }` + } + } +] diff --git a/apps/remix-ide-e2e/src/tests/sol2uml.test.ts b/apps/remix-ide-e2e/src/tests/sol2uml.test.ts index fc33a0df3a..8ef79eb69b 100644 --- a/apps/remix-ide-e2e/src/tests/sol2uml.test.ts +++ b/apps/remix-ide-e2e/src/tests/sol2uml.test.ts @@ -4,30 +4,30 @@ import init from '../helpers/init' module.exports = { '@disabled': true, - before: function (browser: NightwatchBrowser, done: VoidFunction) { + before: function (browser: NightwatchBrowser, done: VoidFunction) { init(browser, done) }, '@sources': () => sources, - 'Generate uml diagram from contract #group1': function (browser: NightwatchBrowser) { + 'Generate uml diagram from contract #group1': function (browser: NightwatchBrowser) { browser.addFile('TestBallot.sol', sources[0]['TestBallot.sol']) .waitForElementVisible('*[data-id="treeViewLitreeViewItemTestBallot.sol"') .rightClick('*[data-id="treeViewLitreeViewItemTestBallot.sol"]') .click('*[id="menuitemgeneratecustomaction"') .waitForElementVisible('*[id="sol-uml-gen"]') - }, - 'Generate uml for contracts with imports #group1': function (browser: NightwatchBrowser) { - browser.addFile('secondContract.sol', sources[1]['secondContract.sol']) - .waitForElementVisible('*[data-id="treeViewLitreeViewItemsecondContract.sol"') - .pause(3000) - .rightClick('*[data-id="treeViewLitreeViewItemsecondContract.sol"]') - .click('*[id="menuitemgeneratecustomaction"') - .waitForElementVisible('*[id="sol-uml-gen"]') - .waitForElementVisible('*[data-id="treeViewLitreeViewItemsecondContract_flattened.sol"]') - }, - 'Zoom into uml diagram #group1': function (browser: NightwatchBrowser) { - browser - .click('*[data-id="umlZoominbtn"]') - } + }, + 'Generate uml for contracts with imports #group1': function (browser: NightwatchBrowser) { + browser.addFile('secondContract.sol', sources[1]['secondContract.sol']) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemsecondContract.sol"') + .pause(3000) + .rightClick('*[data-id="treeViewLitreeViewItemsecondContract.sol"]') + .click('*[id="menuitemgeneratecustomaction"') + .waitForElementVisible('*[id="sol-uml-gen"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemsecondContract_flattened.sol"]') + }, + 'Zoom into uml diagram #group1': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="umlZoominbtn"]') + } } const sources = [ @@ -38,7 +38,7 @@ const sources = [ pragma solidity >=0.7.0 <0.9.0; -/** +/** * @title Ballot * @dev Implements voting process along with vote delegation */ @@ -52,7 +52,7 @@ contract Ballot { } struct Proposal { - // If you can limit the length to a certain number of bytes, + // If you can limit the length to a certain number of bytes, // always use one of bytes1 to bytes32 because they are much cheaper bytes32 name; // short name (up to 32 bytes) uint voteCount; // number of accumulated votes @@ -64,7 +64,7 @@ contract Ballot { Proposal[] public proposals; - /** + /** * @dev Create a new ballot to choose one of 'proposalNames'. * @param proposalNames names of proposals */ @@ -83,7 +83,7 @@ contract Ballot { } } - /** + /** * @dev Give 'voter' the right to vote on this ballot. May only be called by 'chairperson'. * @param voter address of voter */ @@ -146,7 +146,7 @@ contract Ballot { proposals[proposal].voteCount += sender.weight; } - /** + /** * @dev Computes the winning proposal taking all previous votes into account. * @return winningProposal_ index of winning proposal in the proposals array */ @@ -162,7 +162,7 @@ contract Ballot { } } - /** + /** * @dev Calls winningProposal() function to get the index of the winner contained in the proposals array and then * @return winnerName_ the name of the winner */ @@ -208,7 +208,7 @@ contract SampleERC20 is ERC20Token { balances[msg.sender] = _totalSupply; } } - + `} -} + } ] diff --git a/apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts b/apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts index f8f2d3467e..2814a653e1 100644 --- a/apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts +++ b/apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts @@ -46,7 +46,6 @@ module.exports = { .waitForElementPresent('//*[@id="staticanalysisresult"]', 5000) .useCss() // Check warning count - .pause() .waitForElementVisible('span#ssaRemixtab') .click('span#ssaRemixtab') .assert.containsText('span#ssaRemixtab > *[data-id="RemixStaticAnalysisErrorCount"]', '1') diff --git a/apps/remix-ide-e2e/src/tests/transactionExecution.test.ts b/apps/remix-ide-e2e/src/tests/transactionExecution.test.ts index a3019ee444..5cbdd41f5b 100644 --- a/apps/remix-ide-e2e/src/tests/transactionExecution.test.ts +++ b/apps/remix-ide-e2e/src/tests/transactionExecution.test.ts @@ -174,7 +174,6 @@ module.exports = { .journalLastChildIncludes('"documentation": "param1"') .journalLastChildIncludes('"documentation": "param2"') .journalLastChildIncludes('"documentation": "param3"') - .journalLastChildIncludes('Debug the transaction to get more information.') .click('*[data-id="deployAndRunClearInstances"]') }, @@ -198,7 +197,6 @@ module.exports = { .journalLastChildIncludes('"documentation": "param1"') .journalLastChildIncludes('"documentation": "param2"') .journalLastChildIncludes('"documentation": "param3"') - .journalLastChildIncludes('Debug the transaction to get more information.') }, 'Should Compile and Deploy a contract which define a custom error in a library, the error should be logged in the terminal #group3': function (browser: NightwatchBrowser) { @@ -216,7 +214,6 @@ module.exports = { .journalLastChildIncludes('"documentation": "param1 from library"') .journalLastChildIncludes('"documentation": "param2 from library"') .journalLastChildIncludes('"documentation": "param3 from library"') - .journalLastChildIncludes('Debug the transaction to get more information.') }, 'Should compile and deploy 2 simple contracts, the contract creation component state should be correctly reset for the deployment of the second contract #group4': function (browser: NightwatchBrowser) { diff --git a/apps/remix-ide-e2e/src/tests/vyper_api.test.ts b/apps/remix-ide-e2e/src/tests/vyper_api.test.ts index ba77570263..356752a56a 100644 --- a/apps/remix-ide-e2e/src/tests/vyper_api.test.ts +++ b/apps/remix-ide-e2e/src/tests/vyper_api.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ 'use strict' import { NightwatchBrowser } from 'nightwatch' import init from '../helpers/init' @@ -26,25 +27,30 @@ module.exports = { .frameParent() .clickLaunchIcon('filePanel') .waitForElementVisible({ - selector: "//*[@data-id='workspacesSelect' and contains(.,'vyper-lang')]", + selector: "//*[@data-id='workspacesSelect' and contains(.,'snekmate')]", locateStrategy: 'xpath', timeout: 60000 }) - .currentWorkspaceIs('vyper-lang') + .currentWorkspaceIs('snekmate') .waitForElementVisible({ - selector: "//*[@data-id='treeViewLitreeViewItemexamples' and contains(.,'examples')]", + selector: "//*[@data-id='treeViewLitreeViewItemsrc' and contains(.,'src')]", locateStrategy: 'xpath', timeout: 60000 }) - .openFile('examples') - .openFile('examples/auctions') - .openFile('examples/auctions/blind_auction.vy') + .openFile('src') + .openFile('src/snekmate') + .openFile('src/snekmate/tokens') + .openFile('src/snekmate/tokens/ERC721.vy') }, - + // 'Add vyper file to run tests #group1': function (browser: NightwatchBrowser) { + // browser.addFile('TestBallot.sol', sources[0]['TestBallot.sol']) + // }, + '@sources': () => sources, 'Context menu click to compile blind_auction should succeed #group1': function (browser: NightwatchBrowser) { browser - .click('*[data-id="treeViewLitreeViewItemexamples/auctions/blind_auction.vy"]') - .rightClick('*[data-id="treeViewLitreeViewItemexamples/auctions/blind_auction.vy"]') + .addFileSnekmate('blind_auction.vy', sources[0]['blindAuction']) + .click('*[data-id="treeViewLitreeViewItemblind_auction.vy"]') + .rightClick('*[data-id="treeViewLitreeViewItemblind_auction.vy"]') .waitForElementPresent('[data-id="contextMenuItemvyper"]') .click('[data-id="contextMenuItemvyper"]') .clickLaunchIcon('vyper') @@ -141,6 +147,33 @@ module.exports = { browser.verifyCallReturnValue(contractAddress, ['0:uint256: 0']) .perform(() => done()) }) + }, + + 'Compile Ownable contract from snekmate #group1': function (browser: NightwatchBrowser) { + let contractAddress + browser + .frameParent() + .clickLaunchIcon('filePanel') + .switchWorkspace('snekmate') + .openFile('src') + .openFile('src/snekmate') + .openFile('src/snekmate/auth') + .openFile('src/snekmate/auth/Ownable.vy') + .rightClick('*[data-id="treeViewLitreeViewItemsrc/snekmate/auth/Ownable.vy"]') + .waitForElementVisible('*[data-id="contextMenuItemvyper"]') + .click('*[data-id="contextMenuItemvyper"]') + .clickLaunchIcon('vyper') + // @ts-ignore + .frame(0) + .click('[data-id="compile"]') + .waitForElementVisible({ + selector:'[data-id="compilation-details"]', + timeout: 60000 + }) + .click('[data-id="compilation-details"]') + .frameParent() + .waitForElementVisible('[data-id="copy-abi"]') + .end() } } @@ -176,3 +209,185 @@ def _createPokemon(_name: String[32], _dna: uint256, _HP: uint256): wins: 0 }) self.totalPokemonCount += 1` +const sources = [{ + + 'blindAuction' : { content: ` +# Blind Auction. Adapted to Vyper from [Solidity by Example](https://github.com/ethereum/solidity/blob/develop/docs/solidity-by-example.rst#blind-auction-1) +#pragma version ^0.3.10 + +struct Bid: + blindedBid: bytes32 + deposit: uint256 + +# Note: because Vyper does not allow for dynamic arrays, we have limited the +# number of bids that can be placed by one address to 128 in this example +MAX_BIDS: constant(int128) = 128 + +# Event for logging that auction has ended +event AuctionEnded: + highestBidder: address + highestBid: uint256 + +# Auction parameters +beneficiary: public(address) +biddingEnd: public(uint256) +revealEnd: public(uint256) + +# Set to true at the end of auction, disallowing any new bids +ended: public(bool) + +# Final auction state +highestBid: public(uint256) +highestBidder: public(address) + +# State of the bids +bids: HashMap[address, Bid[128]] +bidCounts: HashMap[address, int128] + +# Allowed withdrawals of previous bids +pendingReturns: HashMap[address, uint256] + + + +@external +def __init__(_beneficiary: address, _biddingTime: uint256, _revealTime: uint256): + self.beneficiary = _beneficiary + self.biddingEnd = block.timestamp + _biddingTime + self.revealEnd = self.biddingEnd + _revealTime + + +# Place a blinded bid with: +# +# _blindedBid = keccak256(concat( +# convert(value, bytes32), +# convert(fake, bytes32), +# secret) +# ) +# +# The sent ether is only refunded if the bid is correctly revealed in the +# revealing phase. The bid is valid if the ether sent together with the bid is +# at least "value" and "fake" is not true. Setting "fake" to true and sending +# not the exact amount are ways to hide the real bid but still make the +# required deposit. The same address can place multiple bids. +@external +@payable +def bid(_blindedBid: bytes32): + # Check if bidding period is still open + assert block.timestamp < self.biddingEnd + + # Check that payer hasn't already placed maximum number of bids + numBids: int128 = self.bidCounts[msg.sender] + assert numBids < MAX_BIDS + + # Add bid to mapping of all bids + self.bids[msg.sender][numBids] = Bid({ + blindedBid: _blindedBid, + deposit: msg.value + }) + self.bidCounts[msg.sender] += 1 + + +# Returns a boolean value, 'True' if bid placed successfully, 'False' otherwise. +@internal +def placeBid(bidder: address, _value: uint256) -> bool: + # If bid is less than highest bid, bid fails + if (_value <= self.highestBid): + return False + + # Refund the previously highest bidder + if (self.highestBidder != empty(address)): + self.pendingReturns[self.highestBidder] += self.highestBid + + # Place bid successfully and update auction state + self.highestBid = _value + self.highestBidder = bidder + + return True + + +# Reveal your blinded bids. You will get a refund for all correctly blinded +# invalid bids and for all bids except for the totally highest. +@external +def reveal(_numBids: int128, _values: uint256[128], _fakes: bool[128], _secrets: bytes32[128]): + # Check that bidding period is over + assert block.timestamp > self.biddingEnd + + # Check that reveal end has not passed + assert block.timestamp < self.revealEnd + + # Check that number of bids being revealed matches log for sender + assert _numBids == self.bidCounts[msg.sender] + + # Calculate refund for sender + refund: uint256 = 0 + for i in range(MAX_BIDS): + # Note that loop may break sooner than 128 iterations if i >= _numBids + if (i >= _numBids): + break + + # Get bid to check + bidToCheck: Bid = (self.bids[msg.sender])[i] + + # Check against encoded packet + value: uint256 = _values[i] + fake: bool = _fakes[i] + secret: bytes32 = _secrets[i] + blindedBid: bytes32 = keccak256(concat( + convert(value, bytes32), + convert(fake, bytes32), + secret + )) + + # Bid was not actually revealed + # Do not refund deposit + assert blindedBid == bidToCheck.blindedBid + + # Add deposit to refund if bid was indeed revealed + refund += bidToCheck.deposit + if (not fake and bidToCheck.deposit >= value): + if (self.placeBid(msg.sender, value)): + refund -= value + + # Make it impossible for the sender to re-claim the same deposit + zeroBytes32: bytes32 = empty(bytes32) + bidToCheck.blindedBid = zeroBytes32 + + # Send refund if non-zero + if (refund != 0): + send(msg.sender, refund) + + +# Withdraw a bid that was overbid. +@external +def withdraw(): + # Check that there is an allowed pending return. + pendingAmount: uint256 = self.pendingReturns[msg.sender] + if (pendingAmount > 0): + # If so, set pending returns to zero to prevent recipient from calling + # this function again as part of the receiving call before 'transfer' + # returns (see the remark above about conditions -> effects -> + # interaction). + self.pendingReturns[msg.sender] = 0 + + # Then send return + send(msg.sender, pendingAmount) + + +# End the auction and send the highest bid to the beneficiary. +@external +def auctionEnd(): + # Check that reveal end has passed + assert block.timestamp > self.revealEnd + + # Check that auction has not already been marked as ended + assert not self.ended + + # Log auction ending and set flag + log AuctionEnded(self.highestBidder, self.highestBid) + self.ended = True + + # Transfer funds to beneficiary + send(self.beneficiary, self.highestBid) +`} +} +] diff --git a/apps/remix-ide-e2e/src/tests/workspace.test.ts b/apps/remix-ide-e2e/src/tests/workspace.test.ts index 6dedfef7af..b0e261f554 100644 --- a/apps/remix-ide-e2e/src/tests/workspace.test.ts +++ b/apps/remix-ide-e2e/src/tests/workspace.test.ts @@ -402,9 +402,15 @@ module.exports = { 'Incorrect content') }) .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts"]') - .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/run_setup.ts"]') - .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/run_verification.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16/groth16_trusted_setup.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16/groth16_zkproof.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk/plonk_trusted_setup.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk/plonk_zkproof.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtemplates"]') .waitForElementVisible('*[data-id="treeViewLitreeViewItemtemplates/groth16_verifier.sol.ejs"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtemplates/plonk_verifier.sol.ejs"]') .click('*[data-id="treeViewLitreeViewItemtemplates/groth16_verifier.sol.ejs"]') .getEditorValue((content) => { browser.assert.ok(content.indexOf(`contract Groth16Verifier {`) !== -1, @@ -539,8 +545,8 @@ module.exports = { .currentWorkspaceIs('default_workspace') }, - - 'Should create a cookbook workspace #group3': function (browser: NightwatchBrowser) { + // This test is disable as it was failing for chrome on CI + 'Should create a cookbook workspace #group3': !function (browser: NightwatchBrowser) { browser .clickLaunchIcon('filePanel') .click('*[data-id="workspacesMenuDropdown"]') @@ -563,6 +569,17 @@ module.exports = { .waitForElementVisible('*[data-id="treeViewLitreeViewItemsrc/MULTI_SIG/MultiSigSwapHook.sol"]') }, + 'Should add Create2 solidity factory #group4': !function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('filePanel') + .click('*[data-id="workspacesMenuDropdown"]') + .click('*[data-id="workspaceaddcreate2solidityfactory"]') + .getEditorValue((content) => { + browser.assert.ok(content.indexOf(`contract Create2FactoryAssembly {`) !== -1, + 'current displayed content is not Create2FactoryAssembly') + }) + }, + tearDown: sauce } diff --git a/apps/remix-ide-e2e/src/types/index.d.ts b/apps/remix-ide-e2e/src/types/index.d.ts index 74f9e518fe..b97d053f79 100644 --- a/apps/remix-ide-e2e/src/types/index.d.ts +++ b/apps/remix-ide-e2e/src/types/index.d.ts @@ -73,6 +73,8 @@ declare module 'nightwatch' { waitForElementNotContainsText: (id: string, value: string, timeout: number = 10000) => NightwatchBrowser hideToolTips: (this: NightwatchBrowser) => NightwatchBrowser enableClipBoard: () => NightwatchBrowser + addFileSnekmate: (name: string, content: NightwatchContractContent) => NightwatchBrowser + selectFiles: (selelectedElements: any[]) => NightwatchBrowser } export interface NightwatchBrowser { diff --git a/apps/remix-ide-e2e/yarn.lock b/apps/remix-ide-e2e/yarn.lock index fe1b407d64..ec987d4405 100644 --- a/apps/remix-ide-e2e/yarn.lock +++ b/apps/remix-ide-e2e/yarn.lock @@ -45,27 +45,14 @@ dependencies: array.prototype.flatmap "^1.2.4" -"@puppeteer/browsers@^1.5.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-1.6.0.tgz#d52413a7039e40a5ef72fb13fb6505fd87ce842e" - integrity sha512-R2ib8j329427jtKB/qlz0MJbwfJE/6I8ocJLiajsRqJ2PPI8DbjiNzC3lQZeISXEcjOBVhbG2RafN8SlHdcT+A== - dependencies: - debug "4.3.4" - extract-zip "2.0.1" - progress "2.0.3" - proxy-agent "6.3.0" - tar-fs "3.0.4" - unbzip2-stream "1.4.3" - yargs "17.7.1" - "@remix-project/remixd@../../dist/libs/remixd": - version "0.6.18" + version "0.6.30" dependencies: "@remixproject/plugin" "0.3.33" "@remixproject/plugin-api" "0.3.33" "@remixproject/plugin-utils" "0.3.33" "@remixproject/plugin-ws" "0.3.33" - axios "1.1.2" + axios "1.6.0" chokidar "^2.1.8" commander "^9.4.1" fs-extra "^3.0.1" @@ -111,11 +98,6 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== -"@sindresorhus/is@^4.0.0": - version "4.6.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" - integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== - "@szmarczak/http-timer@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" @@ -123,18 +105,6 @@ dependencies: defer-to-connect "^1.0.1" -"@szmarczak/http-timer@^4.0.5": - version "4.0.6" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" - integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== - dependencies: - defer-to-connect "^2.0.0" - -"@tootallnate/quickjs-emscripten@^0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c" - integrity sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA== - "@types/bn.js@^5.1.0": version "5.1.1" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.1.tgz#b51e1b55920a4ca26e9285ff79936bbdec910682" @@ -142,28 +112,6 @@ dependencies: "@types/node" "*" -"@types/cacheable-request@^6.0.1": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" - integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== - dependencies: - "@types/http-cache-semantics" "*" - "@types/keyv" "^3.1.4" - "@types/node" "*" - "@types/responselike" "^1.0.0" - -"@types/http-cache-semantics@*": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812" - integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ== - -"@types/keyv@^3.1.4": - version "3.1.4" - resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" - integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== - dependencies: - "@types/node" "*" - "@types/node@*": version "20.5.0" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.0.tgz#7fc8636d5f1aaa3b21e6245e97d56b7f56702313" @@ -176,13 +124,6 @@ dependencies: "@types/node" "*" -"@types/responselike@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" - integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== - dependencies: - "@types/node" "*" - "@types/secp256k1@^4.0.1": version "4.0.3" resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.3.tgz#1b8e55d8e00f08ee7220b4d59a6abe89c37a901c" @@ -190,25 +131,11 @@ dependencies: "@types/node" "*" -"@types/yauzl@^2.9.1": - version "2.10.0" - resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.0.tgz#b3248295276cf8c6f153ebe6a9aba0c988cb2599" - integrity sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw== - dependencies: - "@types/node" "*" - "@ungap/promise-all-settled@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== -agent-base@^7.0.1, agent-base@^7.0.2, agent-base@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.0.tgz#536802b76bc0b34aa50195eb2442276d613e3434" - integrity sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg== - dependencies: - debug "^4.3.4" - ansi-align@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" @@ -345,13 +272,6 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== -ast-types@^0.13.4: - version "0.13.4" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" - integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w== - dependencies: - tslib "^2.0.1" - async-each@^1.0.1: version "1.0.6" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.6.tgz#52f1d9403818c179b7561e11a5d1b77eb2160e77" @@ -389,29 +309,15 @@ axe-core@^4.4.3: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.2.tgz#040a7342b20765cb18bb50b628394c21bccc17a0" integrity sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g== -axios@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.1.2.tgz#8b6f6c540abf44ab98d9904e8daf55351ca4a331" - integrity sha512-bznQyETwElsXl2RK7HLLwb5GPpOLlycxHCtrpDR/4RqqBzjARaOTo3jz4IgtntWUYee7Ne4S8UHd92VCuzPaWA== - dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - -axios@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f" - integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA== +axios@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102" + integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg== dependencies: follow-redirects "^1.15.0" form-data "^4.0.0" proxy-from-env "^1.1.0" -b4a@^1.6.4: - version "1.6.4" - resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.4.tgz#ef1c1422cae5ce6535ec191baeed7567443f36c9" - integrity sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw== - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -449,11 +355,6 @@ basic-auth@^2.0.1: dependencies: safe-buffer "5.1.2" -basic-ftp@^5.0.2: - version "5.0.3" - resolved "https://registry.yarnpkg.com/basic-ftp/-/basic-ftp-5.0.3.tgz#b14c0fe8111ce001ec913686434fe0c2fb461228" - integrity sha512-QHX8HLlncOLpy54mh+k/sWIFd0ThmRqwe9ZjELybGZK+tZ8rUb9VO0saKJUROTbE+KhzDUT7xziGpGrW8Kmd+g== - binary-extensions@^1.0.0: version "1.13.1" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" @@ -598,11 +499,6 @@ buffer-alloc@^1.2.0: buffer-alloc-unsafe "^1.1.0" buffer-fill "^1.0.0" -buffer-crc32@~0.2.3: - version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== - buffer-fill@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" @@ -613,7 +509,7 @@ buffer-xor@^1.0.3: resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== -buffer@^5.2.1, buffer@^5.5.0: +buffer@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -636,11 +532,6 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -cacheable-lookup@^5.0.3: - version "5.0.4" - resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" - integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== - cacheable-request@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" @@ -654,19 +545,6 @@ cacheable-request@^6.0.0: normalize-url "^4.1.0" responselike "^1.0.2" -cacheable-request@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817" - integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^4.0.0" - lowercase-keys "^2.0.0" - normalize-url "^6.0.1" - responselike "^2.0.0" - call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" @@ -790,15 +668,6 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" -cliui@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" - integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.1" - wrap-ansi "^7.0.0" - clone-response@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" @@ -838,11 +707,6 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -commander@^10.0.0: - version "10.0.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" - integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== - commander@^9.4.1: version "9.5.0" resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" @@ -901,27 +765,6 @@ create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" -cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -data-uri-to-buffer@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-5.0.1.tgz#db89a9e279c2ffe74f50637a59a32fb23b3e4d7c" - integrity sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg== - -debug@4, debug@4.3.4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - debug@4.3.3: version "4.3.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" @@ -943,6 +786,13 @@ debug@^3.2.7: dependencies: ms "^2.1.1" +debug@^4.1.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + decamelize@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" @@ -960,13 +810,6 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" -decompress-response@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" - integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== - dependencies: - mimic-response "^3.1.0" - deep-eql@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.0.1.tgz#2b65bc89491d193780c452edee2144a91bb0a445" @@ -1003,11 +846,6 @@ defer-to-connect@^1.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== -defer-to-connect@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" - integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== - define-data-property@^1.0.1: version "1.1.1" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" @@ -1052,15 +890,6 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" -degenerator@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-5.0.1.tgz#9403bf297c6dad9a1ece409b37db27954f91f2f5" - integrity sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ== - dependencies: - ast-types "^0.13.4" - escodegen "^2.1.0" - esprima "^4.0.1" - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -1253,32 +1082,6 @@ escape-string-regexp@4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -escodegen@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17" - integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w== - dependencies: - esprima "^4.0.1" - estraverse "^5.2.0" - esutils "^2.0.2" - optionalDependencies: - source-map "~0.6.1" - -esprima@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - ethereum-cryptography@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" @@ -1371,29 +1174,6 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extract-zip@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" - integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== - dependencies: - debug "^4.1.1" - get-stream "^5.1.0" - yauzl "^2.10.0" - optionalDependencies: - "@types/yauzl" "^2.9.1" - -fast-fifo@^1.1.0, fast-fifo@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.0.tgz#03e381bcbfb29932d7c3afde6e15e83e05ab4d8b" - integrity sha512-IgfweLvEpwyA4WgiQe9Nx6VV2QkML2NkvZnk1oKnIzXgXdWxuhF7zw4DvLTPZJn6PIUneiAXPF24QmoEqHTjyw== - -fd-slicer@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" - integrity sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g== - dependencies: - pend "~1.2.0" - file-uri-to-path@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" @@ -1469,7 +1249,7 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" -fs-extra@^10.0.0, fs-extra@^10.1.0: +fs-extra@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== @@ -1487,15 +1267,6 @@ fs-extra@^3.0.1: jsonfile "^3.0.0" universalify "^0.1.0" -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -1586,16 +1357,6 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" -get-uri@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-6.0.1.tgz#cff2ba8d456c3513a04b70c45de4dbcca5b1527c" - integrity sha512-7ZqONUVqaabogsYNWlYj0t3YZaL6dhuEueZXGF+/YVmf6dHmaFg8/6psJKqhx9QykIDKzpGcy2cn4oV4YC7V/Q== - dependencies: - basic-ftp "^5.0.2" - data-uri-to-buffer "^5.0.1" - debug "^4.3.4" - fs-extra "^8.1.0" - get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -1654,23 +1415,6 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -got@^11.8.2: - version "11.8.6" - resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" - integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== - dependencies: - "@sindresorhus/is" "^4.0.0" - "@szmarczak/http-timer" "^4.0.5" - "@types/cacheable-request" "^6.0.1" - "@types/responselike" "^1.0.0" - cacheable-lookup "^5.0.3" - cacheable-request "^7.0.2" - decompress-response "^6.0.0" - http2-wrapper "^1.0.0-beta.5.2" - lowercase-keys "^2.0.0" - p-cancelable "^2.0.0" - responselike "^2.0.0" - got@^9.6.0: version "9.6.0" resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" @@ -1813,14 +1557,6 @@ http-cache-semantics@^4.0.0: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== -http-proxy-agent@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz#e9096c5afd071a3fce56e6252bb321583c124673" - integrity sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ== - dependencies: - agent-base "^7.1.0" - debug "^4.3.4" - http-proxy@^1.18.1: version "1.18.1" resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" @@ -1849,22 +1585,6 @@ http-server@^14.1.1: union "~0.5.0" url-join "^4.0.1" -http2-wrapper@^1.0.0-beta.5.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" - integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== - dependencies: - quick-lru "^5.1.1" - resolve-alpn "^1.0.0" - -https-proxy-agent@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz#0277e28f13a07d45c663633841e20a40aaafe0ab" - integrity sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ== - dependencies: - agent-base "^7.0.2" - debug "4" - iconv-lite@0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -1909,16 +1629,6 @@ internal-slot@^1.0.5: has "^1.0.3" side-channel "^1.0.4" -ip@^1.1.8: - version "1.1.9" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.9.tgz#8dfbcc99a754d07f425310b86a99546b1151e396" - integrity sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ== - -ip@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105" - integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ== - is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -2110,11 +1820,6 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-port-reachable@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-port-reachable/-/is-port-reachable-3.1.0.tgz#f6668d3bca9c36b07f737c48a8f875ab0653cd2b" - integrity sha512-vjc0SSRNZ32s9SbZBzGaiP6YVB+xglLShhgZD/FHMZUXBvQWaV9CtzgeVhjccFJrI6RAMV+LX7NYxueW/A8W5A== - is-regex@^1.0.4, is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -2231,11 +1936,6 @@ json-buffer@3.0.0: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" integrity sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ== -json-buffer@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" - integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== - jsonfile@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66" @@ -2243,13 +1943,6 @@ jsonfile@^3.0.0: optionalDependencies: graceful-fs "^4.1.6" -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== - optionalDependencies: - graceful-fs "^4.1.6" - jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" @@ -2285,13 +1978,6 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" -keyv@^4.0.0: - version "4.5.3" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.3.tgz#00873d2b046df737963157bd04f294ca818c9c25" - integrity sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug== - dependencies: - json-buffer "3.0.1" - kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -2430,12 +2116,7 @@ lodash.keys@^3.0.0: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" -lodash.mapvalues@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c" - integrity sha512-JPFqXFeZQ7BfS00H58kClY7SPVeHertPE0lNuCyZ26/XlN8TvakYD7b9bGyNmXbT/D3BbtPAAmq90gPWqLkxlQ== - -lodash.merge@4.6.2, lodash.merge@^4.6.2: +lodash.merge@4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== @@ -2477,11 +2158,6 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -lru-cache@^7.14.1: - version "7.18.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" - integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== - map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -2549,11 +2225,6 @@ mimic-response@^1.0.0, mimic-response@^1.0.1: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== -mimic-response@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" - integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== - minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -2590,7 +2261,7 @@ minimist@1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== -minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.7: +minimist@^1.2.0, minimist@^1.2.6, minimist@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -2603,11 +2274,6 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp-classic@^0.5.2: - version "0.5.3" - resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" - integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== - mkdirp@^0.5.6: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" @@ -2615,11 +2281,6 @@ mkdirp@^0.5.6: dependencies: minimist "^1.2.6" -mkdirp@^2.1.3: - version "2.1.6" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" - integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A== - mkpath@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mkpath/-/mkpath-1.0.0.tgz#ebb3a977e7af1c683ae6fda12b545a6ba6c5853d" @@ -2697,11 +2358,6 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" -netmask@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" - integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== - nightwatch-axe-verbose@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/nightwatch-axe-verbose/-/nightwatch-axe-verbose-2.0.3.tgz#719f0a1b53d611fa2b4872ee5730f5c0ad2c0cec" @@ -2775,11 +2431,6 @@ normalize-url@^4.1.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== -normalize-url@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" - integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== - object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" @@ -2879,11 +2530,6 @@ p-cancelable@^1.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== -p-cancelable@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" - integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== - p-limit@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" @@ -2898,29 +2544,6 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" -pac-proxy-agent@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.0.0.tgz#db42120c64292685dafaf2bd921e223c56bfb13b" - integrity sha512-t4tRAMx0uphnZrio0S0Jw9zg3oDbz1zVhQ/Vy18FjLfP1XOLNUEjaVxYCYRI6NS+BsMBXKIzV6cTLOkO9AtywA== - dependencies: - "@tootallnate/quickjs-emscripten" "^0.23.0" - agent-base "^7.0.2" - debug "^4.3.4" - get-uri "^6.0.1" - http-proxy-agent "^7.0.0" - https-proxy-agent "^7.0.0" - pac-resolver "^7.0.0" - socks-proxy-agent "^8.0.1" - -pac-resolver@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-7.0.0.tgz#79376f1ca26baf245b96b34c339d79bff25e900c" - integrity sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg== - dependencies: - degenerator "^5.0.0" - ip "^1.1.8" - netmask "^2.0.2" - package-json@^6.3.0: version "6.5.0" resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" @@ -2956,11 +2579,6 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - pathval@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" @@ -2977,11 +2595,6 @@ pbkdf2@^3.0.17: safe-buffer "^5.0.1" sha.js "^2.4.8" -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== - picomatch@^2.0.4, picomatch@^2.2.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -3011,11 +2624,6 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -progress@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - proper-lockfile@^4.1.1: version "4.1.2" resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" @@ -3025,20 +2633,6 @@ proper-lockfile@^4.1.1: retry "^0.12.0" signal-exit "^3.0.2" -proxy-agent@6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.3.0.tgz#72f7bb20eb06049db79f7f86c49342c34f9ba08d" - integrity sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og== - dependencies: - agent-base "^7.0.2" - debug "^4.3.4" - http-proxy-agent "^7.0.0" - https-proxy-agent "^7.0.0" - lru-cache "^7.14.1" - pac-proxy-agent "^7.0.0" - proxy-from-env "^1.1.0" - socks-proxy-agent "^8.0.1" - proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -3059,16 +2653,6 @@ qs@^6.4.0: dependencies: side-channel "^1.0.4" -queue-tick@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142" - integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag== - -quick-lru@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" - integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== - randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -3189,11 +2773,6 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== -resolve-alpn@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" - integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== - resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -3206,13 +2785,6 @@ responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" -responselike@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" - integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw== - dependencies: - lowercase-keys "^2.0.0" - restore-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" @@ -3323,28 +2895,6 @@ secure-compare@3.0.1: resolved "https://registry.yarnpkg.com/secure-compare/-/secure-compare-3.0.1.tgz#f1a0329b308b221fae37b9974f3d578d0ca999e3" integrity sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw== -selenium-standalone@^9.0.3: - version "9.0.3" - resolved "https://registry.yarnpkg.com/selenium-standalone/-/selenium-standalone-9.0.3.tgz#2e484c5412d28e60f4b8837305b2f573f28e8147" - integrity sha512-uv2Cx+VVwVSxBoUdA+fjiyXPNyP9fFZf3sl8hokz+KetNNMXZw6s+fxkUNvmZKL0jdvAI/fnHf+xjMCo/0NiKQ== - dependencies: - "@puppeteer/browsers" "^1.5.0" - axios "^1.4.0" - commander "^10.0.0" - cross-spawn "^7.0.3" - debug "^4.3.1" - fs-extra "^10.0.0" - got "^11.8.2" - is-port-reachable "^3.0.0" - lodash.mapvalues "^4.6.0" - lodash.merge "^4.6.2" - minimist "^1.2.5" - mkdirp "^2.1.3" - progress "2.0.3" - tar-stream "3.1.6" - which "^2.0.2" - yauzl "^2.10.0" - selenium-webdriver@4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.3.1.tgz#5e9c6c4adee65e57776b5bd4c07c59b65b8f056d" @@ -3405,18 +2955,6 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -3431,11 +2969,6 @@ signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -smart-buffer@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" - integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== - snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -3466,23 +2999,6 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -socks-proxy-agent@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.1.tgz#ffc5859a66dac89b0c4dab90253b96705f3e7120" - integrity sha512-59EjPbbgg8U3x62hhKOFVAmySQUcfRQ4C7Q/D5sEHnZTQRrQlNKINks44DMR1gwXp0p4LaVIeccX2KHTTcHVqQ== - dependencies: - agent-base "^7.0.1" - debug "^4.3.4" - socks "^2.7.1" - -socks@^2.7.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55" - integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ== - dependencies: - ip "^2.0.0" - smart-buffer "^4.2.0" - solidity-ast@^0.4.51: version "0.4.52" resolved "https://registry.yarnpkg.com/solidity-ast/-/solidity-ast-0.4.52.tgz#9f1a9abc7e5ba28bbf91146ecd07aec7e70f3c85" @@ -3511,11 +3027,6 @@ source-map@^0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== -source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" @@ -3538,15 +3049,7 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -streamx@^2.15.0: - version "2.15.1" - resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.1.tgz#396ad286d8bc3eeef8f5cea3f029e81237c024c6" - integrity sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA== - dependencies: - fast-fifo "^1.1.0" - queue-tick "^1.0.1" - -string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -3654,29 +3157,6 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -tar-fs@3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.4.tgz#a21dc60a2d5d9f55e0089ccd78124f1d3771dbbf" - integrity sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w== - dependencies: - mkdirp-classic "^0.5.2" - pump "^3.0.0" - tar-stream "^3.1.5" - -tar-stream@3.1.6, tar-stream@^3.1.5: - version "3.1.6" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.6.tgz#6520607b55a06f4a2e2e04db360ba7d338cc5bab" - integrity sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg== - dependencies: - b4a "^1.6.4" - fast-fifo "^1.2.0" - streamx "^2.15.0" - -through@^2.3.8: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== - tmp@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" @@ -3731,11 +3211,6 @@ tslib@2.0.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.1.tgz#410eb0d113e5b6356490eec749603725b021b43e" integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ== -tslib@^2.0.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" - integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== - type-detect@4.0.8, type-detect@^4.0.0: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" @@ -3800,14 +3275,6 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -unbzip2-stream@1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" - integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== - dependencies: - buffer "^5.2.1" - through "^2.3.8" - union-value@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" @@ -3916,7 +3383,7 @@ which-typed-array@^1.1.10, which-typed-array@^1.1.11: gopd "^1.0.1" has-tostringtag "^1.0.0" -which@2.0.2, which@^2.0.1, which@^2.0.2: +which@2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== @@ -3979,11 +3446,6 @@ yargs-parser@^20.2.2: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-parser@^21.1.1: - version "21.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== - yargs-unparser@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" @@ -4007,27 +3469,6 @@ yargs@16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@17.7.1: - version "17.7.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.1.tgz#34a77645201d1a8fc5213ace787c220eabbd0967" - integrity sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw== - dependencies: - cliui "^8.0.1" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.1.1" - -yauzl@^2.10.0: - version "2.10.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" - integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.1.0" - yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" diff --git a/apps/remix-ide/ci/browser_test.sh b/apps/remix-ide/ci/browser_test.sh index 7bc595e1e7..8af369b567 100755 --- a/apps/remix-ide/ci/browser_test.sh +++ b/apps/remix-ide/ci/browser_test.sh @@ -17,7 +17,7 @@ sleep 5 node apps/remix-ide/ci/splice_tests.js $2 $3 TESTFILES=$(node apps/remix-ide/ci/splice_tests.js $2 $3 | circleci tests split --split-by=timings) for TESTFILE in $TESTFILES; do - npx nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/${TESTFILE}.js --env=$1 || npx nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/${TESTFILE}.js --env=$1 || TEST_EXITCODE=1 + npx nightwatch --config dist/apps/remix-ide-e2e/nightwatch-${1}.js dist/apps/remix-ide-e2e/src/tests/${TESTFILE}.js --env=$1 || npx nightwatch --config dist/apps/remix-ide-e2e/nightwatch-${1}.js dist/apps/remix-ide-e2e/src/tests/${TESTFILE}.js --env=$1 || TEST_EXITCODE=1 done echo "$TEST_EXITCODE" diff --git a/apps/remix-ide/ci/browser_test_plugin.sh b/apps/remix-ide/ci/browser_test_plugin.sh index b0f02995a0..1f5afbd28c 100755 --- a/apps/remix-ide/ci/browser_test_plugin.sh +++ b/apps/remix-ide/ci/browser_test_plugin.sh @@ -15,7 +15,7 @@ sleep 5 TESTFILES=$(grep -IRiL "\'@disabled\': \?true" "dist/apps/remix-ide-e2e/src/tests" | grep $1 | sort | circleci tests split ) for TESTFILE in $TESTFILES; do - npx nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js $TESTFILE --env=chrome || TEST_EXITCODE=1 + npx nightwatch --config dist/apps/remix-ide-e2e/nightwatch-chrome.js $TESTFILE --env=chrome || TEST_EXITCODE=1 done echo "$TEST_EXITCODE" diff --git a/apps/remix-ide/ci/flaky.sh b/apps/remix-ide/ci/flaky.sh index 6cc1adb557..5373daec0b 100755 --- a/apps/remix-ide/ci/flaky.sh +++ b/apps/remix-ide/ci/flaky.sh @@ -23,7 +23,7 @@ yarn run serve:production & sleep 5 for TESTFILE in $TESTFILES; do - npx nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js $TESTFILE --env=$1 || TEST_EXITCODE=1 + npx nightwatch --config dist/apps/remix-ide-e2e/nightwatch-${1}.js $TESTFILE --env=$1 || TEST_EXITCODE=1 done echo "$TEST_EXITCODE" diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index 3679e9201e..28da59dc35 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -37,17 +37,12 @@ import {HardhatProvider} from './app/providers/hardhat-provider' import {GanacheProvider} from './app/providers/ganache-provider' import {FoundryProvider} from './app/providers/foundry-provider' import {ExternalHttpProvider} from './app/providers/external-http-provider' -import {InjectedProviderDefault} from './app/providers/injected-provider-default' -import {InjectedProviderTrustWallet} from './app/providers/injected-provider-trustwallet' -import {Injected0ptimismProvider} from './app/providers/injected-optimism-provider' -import {InjectedArbitrumOneProvider} from './app/providers/injected-arbitrum-one-provider' -import {InjectedEphemeryTestnetProvider} from './app/providers/injected-ephemery-testnet-provider' -import {InjectedSKALEChaosTestnetProvider} from './app/providers/injected-skale-chaos-testnet-provider' import { FileDecorator } from './app/plugins/file-decorator' import { CodeFormat } from './app/plugins/code-format' import { SolidityUmlGen } from './app/plugins/solidity-umlgen' import { CompilationDetailsPlugin } from './app/plugins/compile-details' import { VyperCompilationDetailsPlugin } from './app/plugins/vyper-compilation-details' +import { RemixGuidePlugin } from './app/plugins/remixGuide' import { ContractFlattener } from './app/plugins/contractFlattener' import { TemplatesPlugin } from './app/plugins/remix-templates' import { fsPlugin } from './app/plugins/electron/fsPlugin' @@ -229,6 +224,10 @@ class AppComponent { // ----------------- Compilation Details ---------------------------- const compilationDetails = new CompilationDetailsPlugin(appManager) const vyperCompilationDetails = new VyperCompilationDetailsPlugin(appManager) + + // ----------------- Remix Guide ---------------------------- + const remixGuide = new RemixGuidePlugin(appManager) + // ----------------- ContractFlattener ---------------------------- const contractFlattener = new ContractFlattener() @@ -269,12 +268,6 @@ class AppComponent { const ganacheProvider = new GanacheProvider(blockchain) const foundryProvider = new FoundryProvider(blockchain) const externalHttpProvider = new ExternalHttpProvider(blockchain) - const trustWalletInjectedProvider = new InjectedProviderTrustWallet() - const defaultInjectedProvider = new InjectedProviderDefault() - const injected0ptimismProvider = new Injected0ptimismProvider() - const injectedArbitrumOneProvider = new InjectedArbitrumOneProvider() - const injectedEphemeryTestnetProvider = new InjectedEphemeryTestnetProvider() - const injectedSKALEChaosTestnetProvider = new InjectedSKALEChaosTestnetProvider() // ----------------- convert offset to line/column service ----------- const offsetToLineColumnConverter = new OffsetToLineColumnConverter() Registry.getInstance().put({ @@ -347,18 +340,13 @@ class AppComponent { hardhatProvider, ganacheProvider, foundryProvider, - externalHttpProvider, - defaultInjectedProvider, - trustWalletInjectedProvider, - injected0ptimismProvider, - injectedArbitrumOneProvider, - injectedEphemeryTestnetProvider, - injectedSKALEChaosTestnetProvider, + externalHttpProvider, this.walkthroughService, search, solidityumlgen, compilationDetails, vyperCompilationDetails, + // remixGuide, contractFlattener, solidityScript, templates, @@ -418,7 +406,8 @@ class AppComponent { filePanel, Registry.getInstance().get('compilersartefacts').api, networkModule, - Registry.getInstance().get('fileproviders/browser').api + Registry.getInstance().get('fileproviders/browser').api, + this.engine ) const analysis = new AnalysisTab() const debug = new DebuggerTab() @@ -524,7 +513,8 @@ class AppComponent { - await this.appManager.activatePlugin(['filePanel']) + await this.appManager.activatePlugin(['filePanel']) + // Set workspace after initial activation this.appManager.on('editor', 'editorMounted', () => { if (Array.isArray(this.workspace)) { diff --git a/apps/remix-ide/src/app/plugins/remixGuide.tsx b/apps/remix-ide/src/app/plugins/remixGuide.tsx new file mode 100644 index 0000000000..d782e11ff3 --- /dev/null +++ b/apps/remix-ide/src/app/plugins/remixGuide.tsx @@ -0,0 +1,244 @@ + +import React from 'react' +import { ViewPlugin } from '@remixproject/engine-web' +import { PluginViewWrapper } from '@remix-ui/helper' +import { RemixAppManager } from '../../remixAppManager' +import { RemixUIGridView } from '@remix-ui/remix-ui-grid-view' +import { RemixUIGridSection } from '@remix-ui/remix-ui-grid-section' +import { RemixUIGridCell } from '@remix-ui/remix-ui-grid-cell' +import { ThemeKeys, ThemeObject } from '@microlink/react-json-view' +//@ts-ignore +const _paq = (window._paq = window._paq || []) + +const profile = { + name: 'remixGuide', + displayName: 'Remix Guide', + description: 'Learn remix with videos', + location: 'mainPanel', + methods: ['showDetails'], + events: [] +} + +export class RemixGuidePlugin extends ViewPlugin { + dispatch: React.Dispatch = () => { } + appManager: RemixAppManager + element: HTMLDivElement + payload: any + themeStyle: any + theme: ThemeKeys | ThemeObject + constructor(appManager: RemixAppManager) { + super(profile) + this.appManager = appManager + this.element = document.createElement('div') + this.element.setAttribute('id', 'remixGuideEl') + } + + async onActivation() { + this.handleThemeChange() + await this.call('tabs', 'focus', 'remixGuide') + this.renderComponent() + _paq.push(['trackEvent', 'plugin', 'activated', 'remixGuide']) + } + + onDeactivation(): void { + } + + async showDetails(sentPayload: any) { + const contractName = Object.entries(sentPayload).find(([key, value]) => key) + await this.call('tabs', 'focus', 'remixGuide') + this.profile.displayName = `${contractName[0]}` + this.payload = sentPayload + const active = await this.call('theme', 'currentTheme') + + this.renderComponent() + } + + private handleThemeChange() { + this.on('theme', 'themeChanged', (theme: any) => { + + this.renderComponent() + }) + } + + setDispatch(dispatch: React.Dispatch): void { + this.dispatch = dispatch + this.renderComponent() + } + render() { + return ( +
+ +
+ ) + } + + renderComponent() { + this.dispatch({ + ...this, + ...this.payload, + themeStyle: this.themeStyle, + theme: this.theme + }) + } + + updateComponent(state: any) { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) + } + +} diff --git a/apps/remix-ide/src/app/plugins/solcoderAI.tsx b/apps/remix-ide/src/app/plugins/solcoderAI.tsx index f4da44af3f..9e52dd0d11 100644 --- a/apps/remix-ide/src/app/plugins/solcoderAI.tsx +++ b/apps/remix-ide/src/app/plugins/solcoderAI.tsx @@ -15,7 +15,7 @@ const profile = { name: 'solcoder', displayName: 'solcoder', description: 'solcoder', - methods: ['code_generation', 'code_completion', "solidity_answer", "code_explaining"], + methods: ['code_generation', 'code_completion', "solidity_answer", "code_explaining", "code_insertion"], events: [], maintainedBy: 'Remix', } @@ -32,7 +32,6 @@ export class SolCoder extends Plugin { async code_generation(prompt): Promise { this.emit("aiInfering") this.call('layout', 'maximizeTerminal') - this.call('terminal', 'log', { type: 'aitypewriterwarning', value: 'Code Generation: Waiting for Solcoder answer...'}) let result try { result = await( @@ -45,7 +44,6 @@ export class SolCoder extends Plugin { body: JSON.stringify({"data":[prompt, "code_completion", "", false,1000,0.9,0.92,50]}), }) ).json() - console.log(result) if ("error" in result){ this.call('terminal', 'log', { type: 'aitypewriterwarning', value: result.error }) return result @@ -62,7 +60,6 @@ export class SolCoder extends Plugin { async solidity_answer(prompt): Promise { this.emit("aiInfering") this.call('layout', 'maximizeTerminal') - this.call('terminal', 'log', { type: 'aitypewriterwarning', value: 'Waiting for Solcoder answer...'}) let result try { result = await( @@ -89,10 +86,9 @@ export class SolCoder extends Plugin { } - async code_explaining(prompt): Promise { + async code_explaining(prompt, context:string=""): Promise { this.emit("aiInfering") this.call('layout', 'maximizeTerminal') - this.call('terminal', 'log', { type: 'aitypewriterwarning', value: 'Explain Code: Waiting for Solcoder answer...'}) let result try { result = await( @@ -102,7 +98,7 @@ export class SolCoder extends Plugin { Accept: 'application/json', 'Content-Type': 'application/json', }, - body: JSON.stringify({"data":[prompt, "code_explaining", false,2000,0.9,0.8,50]}), + body: JSON.stringify({"data":[prompt, "code_explaining", false,2000,0.9,0.8,50, context]}), }) ).json() if (result) { @@ -151,7 +147,6 @@ export class SolCoder extends Plugin { ).json() if ("error" in result){ - this.call('terminal', 'log', { type: 'aitypewriterwarning', value: result.error }) return result } return result.data @@ -164,5 +159,42 @@ export class SolCoder extends Plugin { } } + async code_insertion(msg_pfx, msg_sfx): Promise { + this.emit("aiInfering") + let result + try { + result = await( + await fetch(this.completion_url, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({"data":[ + msg_pfx, // Text before current cursor line + "code_insertion", + msg_sfx, // Text after current cursor line + 1024, + 0.5, + 0.92, + 50 + ] }), + }) + ).json() + + if ("error" in result){ + return result + } + return result.data + + } catch (e) { + this.call('terminal', 'log', { type: 'aitypewriterwarning', value: `Unable to get a response ${e.message}` }) + return + } finally { + this.emit("aiInferingDone") + } + } + + } diff --git a/apps/remix-ide/src/app/providers/abstract-provider.tsx b/apps/remix-ide/src/app/providers/abstract-provider.tsx index e169e048d6..60c6032cc9 100644 --- a/apps/remix-ide/src/app/providers/abstract-provider.tsx +++ b/apps/remix-ide/src/app/providers/abstract-provider.tsx @@ -119,7 +119,7 @@ export abstract class AbstractProvider extends Plugin implements IProvider { } this.call('notification', 'alert', modalContent) } - await this.call('udapp', 'setEnvironmentMode', {context: 'vm-paris'}) + await this.call('udapp', 'setEnvironmentMode', {context: 'vm-cancun'}) return } diff --git a/apps/remix-ide/src/app/providers/injected-custom-provider.tsx b/apps/remix-ide/src/app/providers/injected-custom-provider.tsx index 90b81c7263..153efcd1bb 100644 --- a/apps/remix-ide/src/app/providers/injected-custom-provider.tsx +++ b/apps/remix-ide/src/app/providers/injected-custom-provider.tsx @@ -1,14 +1,15 @@ -import {InjectedProviderDefaultBase} from './injected-provider-default' +import Web3 from 'web3' +import {InjectedProviderDefault} from './injected-provider-default' -export class InjectedCustomProvider extends InjectedProviderDefaultBase { +export class InjectedCustomProvider extends InjectedProviderDefault { chainName: string chainId: string rpcUrls: Array nativeCurrency: Record blockExplorerUrls: Array - constructor(profile: any, chainName: string, chainId: string, rpcUrls: Array, nativeCurrency?: Record, blockExplorerUrls?: Array) { - super(profile) + constructor(provider: any, chainName: string, chainId: string, rpcUrls: Array, nativeCurrency?: Record, blockExplorerUrls?: Array) { + super(provider, chainName) this.chainName = chainName this.chainId = chainId this.rpcUrls = rpcUrls @@ -17,14 +18,17 @@ export class InjectedCustomProvider extends InjectedProviderDefaultBase { } async init() { + if (!this.chainId && this.rpcUrls.length > 0) { + const chainId = await new Web3(this.rpcUrls[0]).eth.getChainId() + this.chainId = `0x${chainId.toString(16)}` + } await super.init() - if (this.chainName && this.rpcUrls && this.rpcUrls.length > 0) await addCustomNetwork(this.chainName, this.chainId, this.rpcUrls, this.nativeCurrency, this.blockExplorerUrls) - else throw new Error('Cannot add the custom network to main injected provider') + await setCustomNetwork(this.chainName, this.chainId, this.rpcUrls, this.nativeCurrency, this.blockExplorerUrls) return {} } } -export const addCustomNetwork = async (chainName: string, chainId: string, rpcUrls: Array, nativeCurrency?: Record, blockExplorerUrls?: Array) => { +export const setCustomNetwork = async (chainName: string, chainId: string, rpcUrls: Array, nativeCurrency?: Record, blockExplorerUrls?: Array) => { try { await (window as any).ethereum.request({ method: 'wallet_switchEthereumChain', @@ -34,22 +38,24 @@ export const addCustomNetwork = async (chainName: string, chainId: string, rpcUr // This error code indicates that the chain has not been added to MetaMask. if (switchError.code === 4902) { try { - const paramsObj: Record = { - chainId: chainId, - chainName: chainName, - rpcUrls: rpcUrls, - } - if (nativeCurrency) paramsObj.nativeCurrency = nativeCurrency - if (blockExplorerUrls) paramsObj.blockExplorerUrls = blockExplorerUrls - await (window as any).ethereum.request({ - method: 'wallet_addEthereumChain', - params: [ paramsObj ] - }) - - await (window as any).ethereum.request({ - method: 'wallet_switchEthereumChain', - params: [{chainId: chainId}] - }) + if (chainName && rpcUrls && rpcUrls.length > 0) { + const paramsObj: Record = { + chainId: chainId, + chainName: chainName, + rpcUrls: rpcUrls, + } + if (nativeCurrency) paramsObj.nativeCurrency = nativeCurrency + if (blockExplorerUrls) paramsObj.blockExplorerUrls = blockExplorerUrls + await (window as any).ethereum.request({ + method: 'wallet_addEthereumChain', + params: [ paramsObj ] + }) + + await (window as any).ethereum.request({ + method: 'wallet_switchEthereumChain', + params: [{chainId: chainId}] + }) + } } catch (addError) { // handle "add" error } diff --git a/apps/remix-ide/src/app/providers/injected-provider-default.tsx b/apps/remix-ide/src/app/providers/injected-provider-default.tsx index 7223d945f2..c2a0f0a440 100644 --- a/apps/remix-ide/src/app/providers/injected-provider-default.tsx +++ b/apps/remix-ide/src/app/providers/injected-provider-default.tsx @@ -25,7 +25,7 @@ export class InjectedProviderDefaultBase extends InjectedProvider { } const profile = { - name: 'injected', + name: 'injected', // the name will be overwritten in the constructor. displayName: 'Injected Provider', kind: 'provider', description: 'injected Provider', @@ -34,7 +34,13 @@ const profile = { } export class InjectedProviderDefault extends InjectedProviderDefaultBase { - constructor() { - super(profile) + provider: any + constructor(provider: any, name: string) { + super({ ...profile, ...{ name, displayName: name } }) + this.provider = provider + } + + getInjectedProvider() { + return this.provider } } diff --git a/apps/remix-ide/src/app/tabs/locale-module.js b/apps/remix-ide/src/app/tabs/locale-module.js index 89febee68d..465a34fbed 100644 --- a/apps/remix-ide/src/app/tabs/locale-module.js +++ b/apps/remix-ide/src/app/tabs/locale-module.js @@ -8,6 +8,7 @@ import zhJson from './locales/zh' import esJson from './locales/es' import frJson from './locales/fr' import itJson from './locales/it' +import ruJson from './locales/ru' const _paq = window._paq = window._paq || [] const locales = [ @@ -15,6 +16,7 @@ const locales = [ { code: 'en', name: 'English', localeName: 'English', messages: enJson }, { code: 'fr', name: 'French', localeName: 'Français', messages: frJson }, { code: 'it', name: 'Italian', localeName: 'Italiano', messages: itJson }, + { code: 'ru', name: 'Russian', localeName: 'Русский', messages: ruJson }, { code: 'es', name: 'Spanish', localeName: 'Español', messages: esJson } ] diff --git a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json index fd217f921f..5f033c3aad 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json +++ b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json @@ -36,6 +36,8 @@ "filePanel.addscriptetherscan": "Add Etherscan scripts", "filePanel.workspace.addscriptsindri": "Adds scripts for interacting with Sindri, a zk proof generation remote service", "filePanel.addscriptsindri": "Add Sindri ZK scripts", + "filePanel.workspace.addcreate2solidityfactory": "A contract which allows you to deploy a contract using CREATE2.", + "filePanel.addcreate2solidityfactory": "Add Create2 Solidity factory", "filePanel.workspace.addscriptdeployer": "Adds scripts which can be used to deploy contracts", "filePanel.addscriptdeployer": "Add contract deployer scripts", "filePanel.workspace.slitherghaction": "Adds a preset yml file to run slither analysis on github actions CI", diff --git a/apps/remix-ide/src/app/tabs/locales/en/remixUiTabs.json b/apps/remix-ide/src/app/tabs/locales/en/remixUiTabs.json index 46c5181a84..a7cc252c1a 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/remixUiTabs.json +++ b/apps/remix-ide/src/app/tabs/locales/en/remixUiTabs.json @@ -4,9 +4,9 @@ "remixUiTabs.tooltipText3": "Select .sol or .yul file to compile or a .ts or .js file and run it", "remixUiTabs.tooltipText4": "Select .sol file to use AI tools [BETA]", "remixUiTabs.tooltipText5": "Explain the contract(s) in current file [BETA]", - "remixUiTabs.tooltipText6": "Enable AI Copilot [BETA]", - "remixUiTabs.tooltipText7": "Disable AI Copilot [BETA]", - "remixUiTabs.tooltipText8": "AI Documentation [BETA]", + "remixUiTabs.tooltipText6": "Enable Remix AI Copilot [BETA]", + "remixUiTabs.tooltipText7": "Disable Remix AI Copilot [BETA]", + "remixUiTabs.tooltipText8": "Remix AI Tools Documentation [BETA]", "remixUiTabs.zoomOut": "Zoom out", "remixUiTabs.zoomIn": "Zoom in" } diff --git a/apps/remix-ide/src/app/tabs/locales/en/udapp.json b/apps/remix-ide/src/app/tabs/locales/en/udapp.json index 1db24ca378..a7ee39b3e5 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/udapp.json +++ b/apps/remix-ide/src/app/tabs/locales/en/udapp.json @@ -3,7 +3,9 @@ "udapp._comment_gasPrice.tsx": "libs/remix-ui/run-tab/src/lib/components/gasPrice.tsx", "udapp.gasLimit": "Gas limit", - "udapp.tooltipText4": "The default gas limit is 3M. Adjust as needed.", + "udapp.gasLimitAuto": "Estimated Gas", + "udapp.gasLimitManual": "Custom", + "udapp.tooltipText4": "Enter custom Gas Limit.", "udapp._comment_value.tsx": "libs/remix-ui/run-tab/src/lib/components/value.tsx", "udapp.value": "Value", @@ -70,12 +72,12 @@ "udapp.deployAndRunNoInstanceText": "Currently you have no unpinned contracts to interact with.", "udapp.tooltipText6": "Autogenerated generic user interfaces for interaction with deployed/unpinned contracts", - "udapp.savedContracts": "Pinned Contracts", + "udapp.pinnedContracts": "Pinned Contracts", "udapp.tooltipTextPinnedContracts": "List of pinned contracts for selected workspace & network", - "udapp.NoSavedInstanceText": "No pinned contracts found for selected workspace & network", - "udapp.tooltipTextDelete": "Delete pinned contract", + "udapp.NoPinnedInstanceText": "No pinned contracts found for selected workspace & network", + "udapp.tooltipTextDelete": "Delete immediately", "udapp.tooltipTextUnpin": "Unpin contract", - "udapp.savedOn": "Pinned at", + "udapp.pinnedAt": "Pinned at", "udapp.filePath": "File path", "udapp._comment_recorderCardUI.tsx": "libs/remix-ui/run-tab/src/lib/components/recorderCardUI.tsx", diff --git a/apps/remix-ide/src/app/tabs/locales/ru/circuit.json b/apps/remix-ide/src/app/tabs/locales/ru/circuit.json new file mode 100644 index 0000000000..bab6795a2a --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/ru/circuit.json @@ -0,0 +1,15 @@ +{ + "circuit.compiler": "Компилятор", + "circuit.autoCompile": "Автокомпиляция", + "circuit.hideWarnings": "Скрыть предупреждения", + "circuit.advancedConfigurations": "Расширенные настройки", + "circuit.compilerConfiguration": "Настройки компилятора", + "circuit.prime": "Изначально", + "circuit.useConfigurationFile": "Использовать файл настроек", + "circuit.compile": "Скомпилировать", + "circuit.noFileSelected": "нет выбранных файлов", + "circuit.generateR1cs": "Сгенерировать R1CS", + "circuit.computeWitness": "Вычислить Witness", + "circuit.signalInput": "Сигнал ввода", + "circuit.compute": "Вычислить" +} diff --git a/apps/remix-ide/src/app/tabs/locales/ru/debugger.json b/apps/remix-ide/src/app/tabs/locales/ru/debugger.json new file mode 100644 index 0000000000..c0a3222660 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/ru/debugger.json @@ -0,0 +1,26 @@ +{ + "debugger.displayName": "Отладчик", + "debugger.debuggerConfiguration": "Настройки отладчика", + "debugger.stopDebugging": "Завершить отладку", + "debugger.provideTxNumber": "Пожалуйста, укажите действительный хэш транзакции", + "debugger.startDebugging": "Начать отладку", + "debugger.placeholder": "Хэш транзакции, должен начинаться с 0x", + "debugger.debugLocaNodeLabel": "Принудительное использование локального узла", + "debugger.useGeneratedSources": "Использовать сгенерированные источники", + "debugger.debugWithGeneratedSources": "Когда флажок установлен, то отладчик проверит скомпилированный файл .yul, если он существует.", + "debugger.introduction": "При отладке с хэшем транзакции, если контракт проверен, Remix попытается получить исходный код из Sourcify или Etherscan. Укажите API ключ Etherscan в настройках Remix. Поддерживаемые сети смотрите в", + "debugger.forceToUseCurrentLocalNode": "Заставить отладчик использовать текущий локальный узел", + "debugger.sourceLocationStatus1": "Поиск контрольной точки. Это может занять некоторое время...", + "debugger.sourceLocationStatus2": "Местоположение источника недоступно ни в Sourcify ни в Etherscan. Пожалуйста, убедитесь, что ключ api Etherscan указан в настройках.", + "debugger.sourcifyDocs": "Документации Sourcify", + "debugger.noDataAvailable": "Данные отсутствуют", + "debugger.loadMore": "Загрузить еще", + "debugger.copy": "Копировать", + "debugger.stepOverBack": "Шаг назад", + "debugger.stepBack": "Назад", + "debugger.stepInto": "Шаг в", + "debugger.stepOverForward": "Шаг вперед", + "debugger.jumpPreviousBreakpoint": "Перейти к предыдущей контрольной точке", + "debugger.jumpOut": "Выпрыгнуть", + "debugger.jumpNextBreakpoint": "Перейти к предыдущей контрольной точке" +} diff --git a/apps/remix-ide/src/app/tabs/locales/ru/filePanel.json b/apps/remix-ide/src/app/tabs/locales/ru/filePanel.json new file mode 100644 index 0000000000..db98791057 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/ru/filePanel.json @@ -0,0 +1,134 @@ +{ + "filePanel.displayName": "Файловый менеджер", + "filePanel.workspace": "ПРОЕКТЫ", + "filePanel.create": "Создать", + "filePanel.clone": "Клонировать", + "filePanel.download": "Скачать", + "filePanel.backup": "Резервная копия", + "filePanel.restore": "Восстановить", + "filePanel.workspace.create": "Создать проект", + "filePanel.workspace.rename": "Переименовать проект", + "filePanel.workspace.save_workspace": "Сохранить проект", + "filePanel.workspace.delete": "Удалить проект", + "filePanel.workspace.deleteConfirm": "Вы уверены, что хотите удалить текущий проект?", + "filePanel.workspace.download": "Скачать проект", + "filePanel.workspace.downloadConfirm": "Текущий проект будет загружен в виде zip-файла. Вы хотите продолжить?", + "filePanel.workspace.deleteAll": "Удалить все проекты", + "filePanel.workspace.deleteAllConfirm1": "Вы уверены, что хотите удалить все ваши проекты?", + "filePanel.workspace.deleteAllConfirm2": "Удаленные проекты не могут быть восстановлены каким-либо образом.", + "filePanel.workspace.name": "Название проекта", + "filePanel.workspace.chooseTemplate": "Выбрать шаблон", + "filePanel.workspace.backup": "Резервное копирование всех проектов", + "filePanel.workspace.restore": "Восстановить проекты из резервной копии", + "filePanel.workspace.clone": "Клонировать репозиторий", + "filePanel.workspace.cloneMessage": "Пожалуйста, укажите действительный url git репозитория.", + "filePanel.workspace.enterGitUrl": "Введите url git репозитория", + "filePanel.workspace.switch": "Переключиться на проект", + "filePanel.workspace.solghaction": "Добавляет предустановленный yml файл для запуска модульных тестов Solidity в действиях github CI.", + "filePanel.solghaction": "Рабочий процесс тестирования Solidity", + "filePanel.workspace.tssoltestghaction": "Добавляет предустановленный yml файл для запуска mocha и chai тестов на прочность CI действий на github", + "filePanel.tssoltestghaction": "Рабочий процесс Mocha Chai Test", + "filePanel.workspace.addscriptetherscan": "Добавляет скрипты, которые могут использоваться для взаимодействия с Etherscan API", + "filePanel.addscriptetherscan": "Добавить скрипты Etherscan", + "filePanel.workspace.addscriptdeployer": "Добавляет скрипты, которые могут использоваться для развертывания контрактов", + "filePanel.addscriptdeployer": "Добавить скрипты развертывания контракта", + "filePanel.workspace.slitherghaction": "Добавляет предустановленный yml файл для запуска модульных тестов Solidity в действиях github CI", + "filePanel.slitherghaction": "Рабочий процесс Slither", + "filePanel.workspace.helperscripts": "Добавляет удобные скрипты в директорию 'scripts'", + "filePanel.helperscripts": "Web3 скрипты", + "filePanel.newFile": "Новый файл", + "filePanel.newFolder": "Новая папка", + "filePanel.rename": "Переименовать", + "filePanel.delete": "Удалить", + "filePanel.deleteAll": "Удалить всё", + "filePanel.run": "Запустить", + "filePanel.pushChangesToGist": "Отправить изменения в Gist", + "filePanel.publishFolderToGist": "Опубликовать папку в Gist", + "filePanel.publishFileToGist": "Опубликовать файл в Gist", + "filePanel.copy": "Копировать", + "filePanel.copyFileName": "Копировать название", + "filePanel.copyFilePath": "Копировать путь", + "filePanel.contractflattener": "Сведение", + "filePanel.nahmii-compiler": "Компиляция Nahmii", + "filePanel.solidityumlgen": "Сгенерировать UML", + "filePanel.doc-gen": "Генерировать документы", + "filePanel.solidity": "Скомпилировать", + "filePanel.paste": "Вставить", + "filePanel.compile": "Скомпилировать", + "filePanel.compileForNahmii": "Компиляция для Nahmii", + "filePanel.createNewFile": "Создать новый файл", + "filePanel.createNewFolder": "Создать новую папку", + "filePanel.publishToGist": "Опубликовать все файлы в GitHub Gist", + "filePanel.uploadFile": "Загрузить файлы", + "filePanel.uploadFolder": "Загрузка папки", + "filePanel.updateGist": "Обновить текущий обозреватель [gist]", + "filePanel.viewAllBranches": "Просмотреть все ветки", + "filePanel.createBranch": "Создать ветку", + "filePanel.switchBranches": "Переключить ветку", + "filePanel.checkoutGitBranch": "Проверьте Git ветку", + "filePanel.findOrCreateABranch": "Найти или создать ветку.", + "filePanel.initGitRepositoryLabel": "Инициализировать рабочую область как новый git репозиторий", + "filePanel.initGitRepositoryWarning": "Чтобы использовать функции Git, добавьте имя пользователя и адрес электронной почты в раздел Github на Панели настроек.", + "filePanel.workspaceName": "Название рабочей области", + "filePanel.customizeTemplate": "Настроить шаблон", + "filePanel.features": "Особенности", + "filePanel.upgradeability": "Улучшение", + "filePanel.ok": "OK", + "filePanel.yes": "Да", + "filePanel.cancel": "Отменить", + "filePanel.createNewWorkspace": "создать новую рабочую область", + "filePanel.connectToLocalhost": "подключиться к локальному хосту", + "filePanel.copiedToClipboard": "Скопировано в буфер обмена {path}", + "filePanel.downloadFailed": "Ошибка загрузки", + "filePanel.downloadFailedMsg": "Непредвиденная ошибка при загрузке: {error}", + "filePanel.close": "Закрыть", + "filePanel.copyFileFailed": "Ошибка копирования файла", + "filePanel.copyFileFailedMsg": "Непредвиденная ошибка при копировании файла: {src}", + "filePanel.copyFolderFailed": "Ошибка копирования папки", + "filePanel.copyFolderFailedMsg": "Непредвиденная ошибка при копировании папки: {src}", + "filePanel.runScriptFailed": "Не удалось запустить скрипт", + "filePanel.createPublicGist": "Создать публичный Gist", + "filePanel.createPublicGistMsg1": "Вы уверены, что хотите отправить изменения в удалённый файл gist на github.com?", + "filePanel.createPublicGistMsg2": "Вы уверены, что хотите анонимно опубликовать все ваши файлы в папке {path} как публичный файл на github.com?", + "filePanel.createPublicGistMsg3": "Вы уверены, что хотите анонимно опубликовать все ваши файлы в папке {path} как публичный файл на github.com?", + "filePanel.createPublicGistMsg4": "Вы уверены, что хотите анонимно опубликовать все ваши файлы в папке {name} как публичный файл на github.com?", + "filePanel.deleteMsg": "Вы уверены, что хотите удалить?", + "filePanel.theseItems": "эти элементы", + "filePanel.thisItem": "этот элемент", + "filePanel.deleteItems": "Удалить элементы", + "filePanel.deleteItem": "Удалить элемент", + "filePanel.globalToast": "Невозможно записать/изменить файловую систему в режиме только для чтения.", + "filePanel.basic": "Основной", + "filePanel.blank": "Пустой", + "filePanel.multiSigWallet": "Кошелек с мультиподписью", + "filePanel.mintable": "Чеканный", + "filePanel.burnable": "Ожигаемый", + "filePanel.pausable": "Пауза", + "filePanel.semaphore": "Семафор", + "filePanel.hashchecker": "Хэш-чекер", + "filePanel.rln": "Обнулитель ограничения частоты запросов", + "filePanel.breakthroughLabsUniswapv4Hooks": "Breakthrough-Labs Hooks", + "filePanel.uniswapV4Periphery": "V4 периферия", + "filePanel.uniswapV4HookBookMultiSigSwapHook": "HookBook MultiSigSwapHook", + "filePanel.transparent": "Прозрачный", + "filePanel.initGitRepoTitle": "Установите флажок для активизации рабочей области как нового git репозитория", + "filePanel.switchToBranchTitle1": "Проверить новую ветку из удалённой ветки", + "filePanel.switchToBranchTitle2": "Выдать в локальную ветку", + "filePanel.readOnly": "только для чтения", + "filePanel.renameFileFailed": "Не удалось переименовать файл", + "filePanel.renameFileFailedMsg": "Непредвиденная ошибка при переименовании: {error}", + "filePanel.fileCreationFailed": "Ошибка создания файла", + "filePanel.folderCreationFailed": "Ошибка создания папки", + "filePanel.validationError": "Ошибка проверки", + "filePanel.validationErrorMsg": "Нельзя использовать специальные символы", + "filePanel.reservedKeyword": "Зарезервированное ключевое слово", + "filePanel.reservedKeywordMsg": "Имя файла содержит зарезервированные ключевые слова Remix \".{content}\"", + "filePanel.moveFile": "Перемещение файлов", + "filePanel.moveFileMsg1": "Вы уверены, что хотите переместить {src} в {dest}?", + "filePanel.movingFileFailed": "Не удалось переместить файл", + "filePanel.movingFileFailedMsg": "Непредвиденная ошибка при перемещении файла: {src}", + "filePanel.movingFolderFailed": "Не удалось переместить папку", + "filePanel.movingFolderFailedMsg": "Непредвиденная ошибка при перемещении папки: {src}", + "filePanel.workspaceActions": "Действия в рабочей области", + "filePanel.saveCodeSample": "Эта рабочая область примера кода не будет сохранена. Нажмите здесь, чтобы сохранить." +} diff --git a/apps/remix-ide/src/app/tabs/locales/ru/home.json b/apps/remix-ide/src/app/tabs/locales/ru/home.json new file mode 100644 index 0000000000..6de3fd10e8 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/ru/home.json @@ -0,0 +1,69 @@ +{ + "home.scamAlert": "Предупреждение о мошенничестве", + "home.scamAlertText": "Единственный URL, который использует Remix, - это remix.ethereum.org", + "home.scamAlertText2": "Остерегайтесь видеороликов, рекламирующих \"ботов-передовиков ликвидности\"", + "home.scamAlertText3": "Дополнительные советы по технике безопасности", + "home.learnMore": "Узнать больше", + "home.here": "здесь", + "home.featured": "Рекомендуемые", + "home.jumpIntoWeb3": "Перейти в WEB3", + "home.jumpIntoWeb3More": "Подробнее", + "home.jumpIntoWeb3Text": "Remix IDE является частью проекта Remix, широкий выбор инструментов которого, может быть использован для всего путешествия по разработке контракта пользователями любого уровня знаний. Узнайте больше на сайте проекта Remix.", + "home.remixYouTube": "СМОТРИМ И УЧИМСЯ", + "home.remixYouTubeText1": "Видео советы от команды Remix", + "home.remixYouTubeMore": "Смотреть", + "home.remixYouTubeText2": "У Remix растущая библиотека видео, содержащая множество советов по использованию инструмента. Проверьте их и подпишитесь, чтобы получить наши последние обновления.", + "home.betaTesting": "БЕТА-ТЕСТИРОВАНИЕ", + "home.betaTestingText1": "Наше сообщество поддерживает нас.", + "home.betaTestingText2": "Помогите нам запустить бета-тестирование прямо сейчас и ознакомьтесь с новыми функциями", + "home.betaTestingMore": "Зарегистрироваться", + "home.featuredPlugins": "Рекомендуемые плагины", + "home.solidityPluginDesc": "Компиляция, тестирование и анализ смарт-контрактов.", + "home.cookbookDesc": "Найти смарт-контракты, solidity библиотеки и обнаружить протоколы.", + "home.codeAnalyizerPluginDesc": "Анализируйте ваш код с помощью Remix, Solhint и Slither.", + "home.starkNetPluginDesc": "Компиляция и развертывание контрактов с Cairo, родным языком StarkNet.", + "home.solhintPluginDesc": "Solhint — проект с открытым исходным кодом для линейки кода Solidity.", + "home.sourcifyPluginDesc": "Контракт Solidity и сервис проверки метаданных.", + "home.unitTestPluginDesc": "Напишите и запустите модульные тесты для ваших контрактов в Solidity.", + "home.dgitPluginDesc": "Добавить контроль за исходным кодом в ваши проекты.", + "home.oneClickDappDesc": "Быстрое создание смарт-контрактных интерфейсов", + "home.getStarted": "Приступить к работе", + "home.projectTemplates": "Шаблоны проектов", + "home.blankTemplateDesc": "Создать пустую рабочую область.", + "home.remixDefaultTemplateDesc": "Создать рабочую область с файлами примеров.", + "home.ozerc20TemplateDesc": "Создайте ERC20 токен, импортируя библиотеку OpenZeppelin.", + "home.ozerc721TemplateDesc": "Создайте NFT токен, импортируя библиотеку OpenZeppelin.", + "home.ozerc1155TemplateDesc": "Создайте ERC1155 токен, импортируя библиотеку OpenZeppelin.", + "home.gnosisSafeMultisigTemplateDesc": "Создайте кошельки с мульти-подписью с использованием этого шаблона.", + "home.zeroxErc20TemplateDesc": "Создайте токен ERC20, импортируя контракт с 0xProject.", + "home.learn": "Обучение", + "home.learnEth1": "Основы Remix", + "home.learnEth1Desc": "Введение в интерфейс Remix-а и основные операции.", + "home.learnEth2": "Введение в Solidity", + "home.learnEth2Desc": "Интерактивное изучение концепции Solidity для начинающих.", + "home.remixAdvanced": "Развертывание с Библиотеками", + "home.remixAdvancedDesc": "Научитесь развертывать с библиотеками в Remix", + "home.remixYoutubePlaylist": "Плейлист Remix на Youtube", + "home.remixTwitterProfile": "Remix Twitter Профиль", + "home.remixLinkedinProfile": "Remix Linkedin профиль", + "home.remixMediumPosts": "Remix Medium публикации", + "home.joinUsOnDiscord": "Присоединяйтесь к нам в Discord", + "home.nativeIDE": "Родная IDE для разработки WEB3.", + "home.website": "Веб-сайт", + "home.documentation": "Документация", + "home.remixPlugin": "Remix плагин", + "home.remixDesktop": "Remix Desktop", + "home.searchDocumentation": "Поиск документации", + "home.files": "Файлы", + "home.newFile": "Новый файл", + "home.startCoding": "Начать кодирование", + "home.startCodingPlayground": "Откройте площадку для прототипирования и простого обучения", + "home.openFile": "Открыть файл", + "home.openFileTooltip": "Откройте файл из вашей файловой системы", + "home.accessFileSystem": "Доступ к файловой системе", + "home.loadFrom": "Загрузить из", + "home.resources": "Источники", + "home.connectToLocalhost": "Подключиться к локальному хосту", + "home.seeAllTutorials": "Посмотреть все уроки", + "home.maintainedByRemix": "Поддерживается Remix" +} diff --git a/apps/remix-ide/src/app/tabs/locales/ru/index.js b/apps/remix-ide/src/app/tabs/locales/ru/index.js new file mode 100644 index 0000000000..d1dbf937cd --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/ru/index.js @@ -0,0 +1,17 @@ +import enJson from '../en' + +function readAndCombineJsonFiles() { + const dataContext = require.context('./', true, /\.json$/) + + let combinedData = {} + dataContext.keys().forEach((key) => { + const jsonData = dataContext(key) + combinedData = {...combinedData, ...jsonData} + }) + + return combinedData +} + +// There may have some un-translated content. Always fill in the gaps with EN JSON. +// No need for a defaultMessage prop when render a FormattedMessage component. +export default Object.assign({}, enJson, readAndCombineJsonFiles()) diff --git a/apps/remix-ide/src/app/tabs/locales/ru/panel.json b/apps/remix-ide/src/app/tabs/locales/ru/panel.json new file mode 100644 index 0000000000..066069d5bd --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/ru/panel.json @@ -0,0 +1,10 @@ +{ + "panel.author": "Автор", + "panel.maintainedBy": "Поддерживается", + "panel.documentation": "Документация", + "panel.description": "Описание", + "panel.maintainedByRemix": "Поддерживается Remix", + "panel.pluginInfo": "Информация о плагине", + "panel.linkToDoc": "Ссылка на документацию", + "panel.makeAnissue": "Создать задачу" +} diff --git a/apps/remix-ide/src/app/tabs/locales/ru/permissionHandler.json b/apps/remix-ide/src/app/tabs/locales/ru/permissionHandler.json new file mode 100644 index 0000000000..6fcd314eae --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/ru/permissionHandler.json @@ -0,0 +1,13 @@ +{ + "permissionHandler.allPermissionsReset": "Все разрешения были сброшены.", + "permissionHandler.rememberText": "изменено и", + "permissionHandler.permissionHandlerMessage": "\"{from}\" {rememberText} хочет получить доступ к \"{method}\" из \"{to}\"`", + "permissionHandler.description": "Описание", + "permissionHandler.noDescriptionProvided": "Описание отсутствует", + "permissionHandler.makeSureYouTrustThisPlugin": "Убедитесь, что Вы доверяете этому плагину перед обработкой этого вызова. Если Вы запомните выбор для этого вызова, то значение будет сохранено только для текущей сессии.", + "permissionHandler.rememberThisChoice": "Запомнить этот выбор", + "permissionHandler.resetAllPermissions": "Сбросить все разрешения", + "permissionHandler.permissionNeededFor": "Для {to} необходимо разрешение", + "permissionHandler.accept": "Принять", + "permissionHandler.decline": "Отклонить" +} diff --git a/apps/remix-ide/src/app/tabs/locales/ru/pluginManager.json b/apps/remix-ide/src/app/tabs/locales/ru/pluginManager.json new file mode 100644 index 0000000000..4632f26e44 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/ru/pluginManager.json @@ -0,0 +1,43 @@ +{ + "pluginManager.displayName": "Менеджер плагинов", + "pluginManager.activate": "Активировать", + "pluginManager.deactivate": "Деактивировать", + "pluginManager.activeModules": "Активные модули", + "pluginManager.inactiveModules": "Неактивные модули", + "pluginManager.connectLocal": "Подключиться к локальному плагину", + "pluginManager.localForm.title": "Локальный плагин", + "pluginManager.localForm.pluginName": "Название плагина", + "pluginManager.localForm.shouldBeCamelCase": "Должно быть в camelCase", + "pluginManager.localForm.displayName": "Отображаемое название", + "pluginManager.localForm.nameInTheHeader": "Название в заголовке", + "pluginManager.localForm.required": "требуется", + "pluginManager.localForm.commaSeparatedMethod": "список методов через запятую", + "pluginManager.localForm.commaSeparatedPlugin": "список названий плагинов через запятую", + "pluginManager.localForm.pluginsItCanActivate": "Плагины, которые могут быть активированы", + "pluginManager.localForm.typeOfConnection": "Тип соединения", + "pluginManager.localForm.locationInRemix": "Расположение в Remix", + "pluginManager.localForm.sidePanel": "Боковая панель", + "pluginManager.localForm.mainPanel": "Главная панель", + "pluginManager.localForm.none": "Пусто", + "pluginManager.localForm.methods": "Методы", + "pluginManager.localForm.pluginNames": "Имя плагина", + "pluginManager.localForm.ok": "OK", + "pluginManager.localForm.cancel": "Отменить", + "pluginManager.Permissions": "Разрешения", + "pluginManager.permissions": "разрешения", + "pluginManager.pluginManagerPermissions": "Разрешения менеджера плагинов", + "pluginManager.currentPermissionSettings": "Текущие настройки разрешений", + "pluginManager.noPermissionRequestedYet": "Пока нет запрошенных разрешений.", + "pluginManager.allow": "Разрешить", + "pluginManager.toCall": "чтобы вызвать", + "pluginManager.ok": "OK", + "pluginManager.cancel": "Отменить", + "pluginManager.maintainedByRemix": "Поддерживается Remix", + "pluginManager.linkToDoc": "Ссылка на документацию", + "pluginManager.versionAlpha": "Альфа-версия", + "pluginManager.versionBeta": "Бета-версия", + "pluginManager.deactivatePlugin": "Отключить {pluginName}", + "pluginManager.activatePlugin": "Включить {pluginName}", + "pluginManager.search": "Поиск", + "pluginManager.managePluginsPermissions": "Управление разрешениями плагинов" +} diff --git a/apps/remix-ide/src/app/tabs/locales/ru/remixApp.json b/apps/remix-ide/src/app/tabs/locales/ru/remixApp.json new file mode 100644 index 0000000000..96d5afdd05 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/ru/remixApp.json @@ -0,0 +1,3 @@ +{ + "remixApp.scrollToSeeAllTabs": "Прокрутите, чтобы увидеть все вкладки" +} diff --git a/apps/remix-ide/src/app/tabs/locales/ru/remixUiTabs.json b/apps/remix-ide/src/app/tabs/locales/ru/remixUiTabs.json new file mode 100644 index 0000000000..811616873e --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/ru/remixUiTabs.json @@ -0,0 +1,7 @@ +{ + "remixUiTabs.tooltipText1": "Запуск скрипта (CTRL + SHIFT + S)", + "remixUiTabs.tooltipText2": "Компилировать CTRL + S", + "remixUiTabs.tooltipText3": "Выберите файл c расширением .sol или .yul для компиляции или файл .ts или .js для запуска", + "remixUiTabs.zoomOut": "Уменьшить", + "remixUiTabs.zoomIn": "Увеличить" +} diff --git a/apps/remix-ide/src/app/tabs/locales/ru/search.json b/apps/remix-ide/src/app/tabs/locales/ru/search.json new file mode 100644 index 0000000000..5b62a4cebe --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/ru/search.json @@ -0,0 +1,24 @@ +{ + "search.displayName": "Поиск в файлах", + "search.replace": "Заменить", + "search.replaceAll": "Заменить все", + "search.placeholder1": "Искать ( Введите для поиска )", + "search.placeholder2": "Включить ie *.sol ( Введите для включения)", + "search.placeholder3": "Исключить ie .git/**/* ( Введите для исключения )", + "search.matchCase": "Учитывать регистр", + "search.matchWholeWord": "Только слово целиком", + "search.useRegularExpression": "Использовать регулярные выражения", + "search.replaceWithoutConfirmation": "заменить без подтверждения", + "search.filesToInclude": "Файлы для включения", + "search.filesToExclude": "Файлы для исключения", + "search.toggleReplace": "Переключить замену", + "search.replaceInFiles": "заменить в файлах", + "search.stop": "Стоп", + "search.undoChanges": "Отменить изменения {path}", + "search.confirmreplaceMsg": "Вы уверены, что вы хотите заменить \"{find}\" на \"{replace}\" в {filename}?", + "search.yes": "Да", + "search.no": "Нет", + "search.loading": "Загрузка", + "search.text1": "Показать {count} результаты в {fileCount} файлах", + "search.text2": "Слишком много результатов для отображения...{br} Пожалуйста, сузьте поиск." +} diff --git a/apps/remix-ide/src/app/tabs/locales/ru/settings.json b/apps/remix-ide/src/app/tabs/locales/ru/settings.json new file mode 100644 index 0000000000..87887396ff --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/ru/settings.json @@ -0,0 +1,44 @@ +{ + "settings.displayName": "Настройки", + "settings.reset": "Сбросить до настроек по умолчанию", + "settings.general": "Общие настройки", + "settings.generateContractMetadataText": "Генерирует метаданные договора. Генерирует JSON-файл в папке с договором. Позволяет указать адреса библиотек, от которых зависит контракт. Если ничего не указано, то Remix развертывает библиотеки автоматически.", + "settings.ethereunVMText": "Всегда использовать виртуальную машину Remix при загрузке", + "settings.wordWrapText": "Обводка слов в редакторе", + "settings.useAutoCompleteText": "Включение завершения кода в редакторе.", + "settings.useShowGasInEditorText": "Отобразить в редакторе расчеты газа.", + "settings.displayErrorsText": "Отображать ошибки в редакторе при вводе текста.", + "settings.matomoAnalytics": "Включение Matomo Analytics. Мы не собираем личную информацию (ПД). Эта информация используется для улучшения UX и пользовательского интерфейса сайта. Узнайте больше ", + "settings.enablePersonalModeText": " Включение персонального режима для провайдера web3. Транзакция, отправленная через Web 3, будет использовать web 3.personal API.", + "settings.warnText": "Убедитесь, что конечная точка открыта перед включением. Этот режим позволяет пользователю предоставить парольную фразу в интерфейсе Remix без необходимости разблокировать аккаунт. Несмотря на то, что это очень удобно, вы должны полностью доверять бэкэнду, к которому вы подключены (Geth, Parity, ...). Remix никогда не будет сохраняться парольная фраза", + "settings.gitAccessTokenTitle": "Учетные данные Github", + "settings.gitAccessTokenText": "Токен доступа используется для публикации Gist и получения содержимого GitHub. Возможно, вам потребуется ввести имя пользователя/электронную почту.", + "settings.gitAccessTokenText2": "Перейдите на страницу токенов github (ссылка ниже), создайте новый токен и сохраните его в Remix. Убедитесь, что этот токен имеет только право 'create gist'", + "settings.etherscanTokenTitle": "Токен доступа EtherScan", + "settings.etherscanAccessTokenText": "Управляйте ключом api, используемым для взаимодействия с Etherscan.", + "settings.etherscanAccessTokenText2": "Перейдите на страницу api ключей Etherscan (ссылка ниже), чтобы создать новый api ключ и сохраните его в Remix.", + "settings.save": "Сохранить", + "settings.remove": "Удалить", + "settings.themes": "Темы", + "settings.locales": "Язык", + "settings.swarm": "Настройки Swarm", + "settings.ipfs": "Настройки IPFS", + "settings.token": "ТОКЕН", + "settings.copy": "Копировать", + "settings.deleteEtherscanToken": "Удалить Etherscan токен", + "settings.username": "ИМЯ ПОЛЬЗОВАТЕЛЯ", + "settings.email": "Электронная почта", + "settings.deleteGithubCredentials": "Удалить учетные данные Github", + "settings.privateBeeAddress": "ПРИВАТНЫЙ BEE АДРЕС", + "settings.postageStampID": "ID почтового штампа", + "settings.host": "Хост", + "settings.protocol": "Протокол", + "settings.port": "ПОРТ", + "settings.projectID": "ID ПРОЕКТА", + "settings.projectSecret": "СЕКРЕТ ПРОЕКТА", + "settings.analyticsInRemix": "Аналитика в Remix IDE", + "settings.copilot": "Solidity второй пилот - Альфа", + "settings.copilot.activate": "Загрузка и активация копилота", + "settings.copilot.max_new_tokens": "Максимальное количество слов для генерации", + "settings.copilot.temperature": "Температура" +} diff --git a/apps/remix-ide/src/app/tabs/locales/ru/solidity.json b/apps/remix-ide/src/app/tabs/locales/ru/solidity.json new file mode 100644 index 0000000000..2ffe1e3873 --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/ru/solidity.json @@ -0,0 +1,81 @@ +{ + "solidity.displayName": "Компилятор Solidity", + "solidity._comment_compiler-container.tsx": "libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx", + "solidity.compiler": "Компилятор", + "solidity.addACustomCompiler": "Добавить пользовательский компилятор", + "solidity.addACustomCompilerWithURL": "Добавить пользовательский компилятор со ссылкой URL", + "solidity.includeNightlyBuilds": "Включить ночные сборки", + "solidity.autoCompile": "Автокомпиляция", + "solidity.hideWarnings": "Скрыть предупреждения", + "solidity.enableHardhat": "Включить Hardhat компиляцию", + "solidity.learnHardhat": "Узнайте, как использовать аппаратную компиляцию", + "solidity.enableTruffle": "Включить компиляцию Truffle", + "solidity.learnTruffle": "Узнайте, как использовать Truffle компиляцию", + "solidity.advancedConfigurations": "Расширенные конфигурации", + "solidity.compilerConfiguration": "Конфигурация Компилятора", + "solidity.compilationDetails": "Подробности компиляции", + "solidity.language": "Язык", + "solidity.evmVersion": "Версия EVM", + "solidity.enableOptimization": "Включить оптимизацию", + "solidity.useConfigurationFile": "Использовать файл настроек", + "solidity.change": "Изменить", + "solidity.compile": "Скомпилировать", + "solidity.noFileSelected": "файл не выбран", + "solidity.compileAndRunScript": "Компиляция и запуск скрипта", + "solidity.newConfigFileTitle": "Новый файл конфигурации", + "solidity.newConfigFileMessage": "Файл \"{configFilePathInput}\" который вы ввели не существует. Хотите создать новый?", + "solidity.create": "Создать", + "solidity.ok": "OK", + "solidity.cancel": "Отменить", + "solidity.noFileSelected1": "Нет выбранных файлов.", + "solidity.toCompile": "скомпилировать", + "solidity.noConfigFileSelected": "Не выбран файл конфигурации", + "solidity.copyNatSpecTag": "Нажмите, чтобы скопировать пользовательский тег NatSpec", + "solidity.inputTitle1": "Если файл, который вы ввели, не существует, вы сможете создать его на следующем шаге.", + "solidity.inputTitle2": "Расчетное количество раз, когда каждый опцион развернутого кода будет выполняться в течение всего срока действия контракта.", + "solidity.tooltipText1": "Выберите сценарий для выполнения сразу после компиляции, добавив тег `dev-run-script` natspec как в:", + "solidity.tooltipText2": "Нажмите на значок \"i\", чтобы узнать больше", + "solidity.tooltipText3": "для компиляции и выполнения скрипта", + "solidity.tooltipText4": "Нажмите, чтобы открыть файл конфигурации", + "solidity.tooltipText5": "Не удается загрузить список версий компилятора. Возможно, он заблокирован блокировщиком рекламы. Пожалуйста, попробуйте отключить любой из них с этой страницы и перезагрузить. Ошибка: ", + "solidity.tooltipText6": "Спецификация языка доступна от Компилятора >= v0.5.7", + "solidity.toastMessage": "Обновление версии компилятора, чтобы соответствовать текущему файлу контракта pragma т.е. {version}", + "solidity.compileIconAttribute": "компилятор загружается, пожалуйста, подождите несколько минут.", + "solidity.compilerLicense": "Лицензия Компилятора", + "solidity.compilerLicenseMsg1": "Загрузка компилятора. Лицензия будет отображаться после загрузки компилятора", + "solidity.compilerLicenseMsg2": "Не удалось получить лицензию для выбранной версии компилятора", + "solidity.compilerLicenseMsg3": "Лицензия недоступна", + "solidity.seeCompilerLicense": "Посмотреть лицензию компилятора", + "solidity._comment_contract-selection.tsx": "libs/remix-ui/solidity-compiler/src/lib/contract-selection.tsx", + "solidity.publishOn": "Опубликовано на", + "solidity.flatten": "Сглаживание контракта до генерации UML.", + "solidity.generateUML": "Создать UML диаграмму вашего контракта.", + "solidity.flattenLabel": "Сведение", + "solidity.generateUMLLabel": "Генерировать UML диаграмму", + "solidity.copy": "Копировать", + "solidity.copyABI": "Копировать ABI в буфер обмена", + "solidity.copyBytecode": "Копировать Bytecode в буфер обмена", + "solidity.unableToDisplay": "Не удается отобразить", + "solidity.download": "Скачать", + "solidity.compileDetails": "Скачать информацию о компиляции (формат JSON)", + "solidity.close": "Закрыть", + "solidity.contract": "Контракт", + "solidity.displayContractDetails": "Показать детали контракта", + "solidity.noContractCompiled": "Контракт еще не компилирован", + "solidity.Assembly": "Коды сборки, описывающие контракт, включая соответствующий исходный код Solidity", + "solidity.Opcodes": "Коды сборки с описанием контракта", + "solidity.name": "Название скомпилированного контракта", + "solidity.metadata": "Содержит всю информацию, относящуюся к компиляции", + "solidity.bytecode": "Байт-код, выполняемый при создании контракта", + "solidity.abi": "ABI: описание всех функций (входные и выходные параметры, область применения, ...)", + "solidity.web3Deploy": "Скопируйте или вставьте этот код в любую консоль JavaScript/Web3 для развертывания этого контракта", + "solidity.metadataHash": "Хэш представляющий всю метаинформацию", + "solidity.functionHashes": "Список объявленных функций и их соответствующий хэш", + "solidity.gasEstimates": "Оценка газа для каждого вызова функции", + "solidity.Runtime Bytecode": "Байт-код хранит состояние и выполняется во время обычного вызова контракта", + "solidity.storageLayout": "См. документацию по схеме хранилища.", + "solidity.devdoc": "Документация для разработчиков (natspec)", + "solidity.userdoc": "Документация пользователя (natspec)", + "solidity.compilerInput": "Ввод в компилятор Solidity", + "solidity.swarmLocation": "Url - адрес Swarm в котором можно найти всю информацию о метаданных (контракт должен быть опубликован первым)" +} diff --git a/apps/remix-ide/src/app/tabs/locales/ru/solidityUnitTesting.json b/apps/remix-ide/src/app/tabs/locales/ru/solidityUnitTesting.json new file mode 100644 index 0000000000..c6adc570fe --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/ru/solidityUnitTesting.json @@ -0,0 +1,41 @@ +{ + "solidityUnitTesting.displayName": "Модульное тестирование Solidity", + "solidityUnitTesting.testDirectory": "Тестовая директория", + "solidityUnitTesting.testYourSmartContract": "Проверьте ваш смарт - контракт в Solidity.", + "solidityUnitTesting.selectDirectory": "Выберите директорию для загрузки и создания тестовых файлов.", + "solidityUnitTesting.uiPathInputTooltip": "Нажмите 'Enter', чтобы изменить путь к тестовым файлами.", + "solidityUnitTesting.uiPathInputButtonTooltip": "Создать тестовую папку", + "solidityUnitTesting.create": "Создать", + "solidityUnitTesting.generateTestsButtonTooltip": "Создать пример тестового файла", + "solidityUnitTesting.generate": "Генерировать", + "solidityUnitTesting.generateTestsLinkTooltip": "Ознакомьтесь с документацией.", + "solidityUnitTesting.howToUse": "Как использовать...", + "solidityUnitTesting.runButtonTitle1": "Начать тесты", + "solidityUnitTesting.runButtonTitle2": "Пожалуйста, выберите версию компилятора Solidity выше чем 0.4.12.", + "solidityUnitTesting.runButtonTitle3": "Не выбран Solidity файл", + "solidityUnitTesting.runButtonTitle4": "Solidity плагин должен быть активирован", + "solidityUnitTesting.runButtonTitle5": "Тестовый файл не выбран", + "solidityUnitTesting.stopButtonLabel1": "Стоп", + "solidityUnitTesting.stopButtonLabel2": "Останавливается", + "solidityUnitTesting.run": "Запустить", + "solidityUnitTesting.runTestsTabStopActionTooltip": "Остановить запуск тестов", + "solidityUnitTesting.selectAll": "Выбрать все", + "solidityUnitTesting.testTabTestsExecutionStopped": "Выполнение теста остановлено", + "solidityUnitTesting.testTabTestsExecutionStoppedError": "Выполнение теста остановлено из-за ошибки(ошибок) в вашем тестовом файле", + "solidityUnitTesting.progress": "Прогресс: {readyTestsNumber} завершён (из {runningTestsNumber})", + "solidityUnitTesting.resultFor": "Результат для", + "solidityUnitTesting.passed": "Успешно", + "solidityUnitTesting.failed": "Сбой", + "solidityUnitTesting.timeTaken": "Затраченное время", + "solidityUnitTesting.errorMessage": "Сообщение об ошибке", + "solidityUnitTesting.assertion": "Утверждение", + "solidityUnitTesting.expectedValueShouldBe": "Ожидаемое значение должно быть", + "solidityUnitTesting.receivedValue": "Полученные значения", + "solidityUnitTesting.skippingTheRemainingTests": "Пропуск оставшихся тестов функции.", + "solidityUnitTesting.toasterMsg": "Папка успешно создана", + "solidityUnitTesting.tooltipText1": "Не удалось выполнить тест по крайней мере одного контракта", + "solidityUnitTesting.tooltipText2": "Все контрактные тесты пройдены", + "solidityUnitTesting.tooltipText3": "Начать отладку", + "solidityUnitTesting.fail": "НЕПРОЙДЕН", + "solidityUnitTesting.pass": "ПРОЙДЕН" +} diff --git a/apps/remix-ide/src/app/tabs/locales/ru/terminal.json b/apps/remix-ide/src/app/tabs/locales/ru/terminal.json new file mode 100644 index 0000000000..2778fb35de --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/ru/terminal.json @@ -0,0 +1,43 @@ +{ + "terminal.listen": "прослушивание всех транзакций", + "terminal.listenTitle": "Если флажок установлен, то Remix будет прослушивать все транзакции, добытые в текущей среде, а не только транзакции, созданные вами", + "terminal.search": "Поиск по хэшу или адресу транзакции", + "terminal.used": "используется", + "terminal.debug": "Отладка", + "terminal.welcomeText1": "Добро пожаловать в", + "terminal.welcomeText2": "Ваши файлы хранятся в", + "terminal.welcomeText3": "Вы можете использовать этот терминал для", + "terminal.welcomeText4": "Проверьте детали транзакций и начните отладку", + "terminal.welcomeText5": "Выполнение скриптов JavaScript", + "terminal.welcomeText6": "Введите сценарий непосредственно в интерфейсе командной строки", + "terminal.welcomeText7": "Выберите файл Javascript в проводнике файлов, а затем запустите \"remix.execute()\" или \"remix.exeCurrent()\" в интерфейсе командной строки", + "terminal.welcomeText8": "Щелкните правой кнопкой мыши на файл JavaScript в проводнике и затем нажмите `Выполнить`", + "terminal.welcomeText9": "Доступны следующие библиотеки", + "terminal.welcomeText10": "Введите имя библиотеки, чтобы увидеть доступные команды", + "terminal.text1": "Этот тип команды устарел и больше не функционирует. Пожалуйста, запустите remix.help(), чтобы получить список доступных команд.", + "terminal.hideTerminal": "Скрыть терминал", + "terminal.showTerminal": "Показать терминал", + "terminal.clearConsole": "Очистить консоль", + "terminal.pendingTransactions": "Ожидающие транзакции", + "terminal.toasterMsg1": "нет контента для выполнения", + "terminal.toasterMsg2": "не найден поставщик пути {fileName}", + "terminal.vmMode": "Режим VM", + "terminal.vmModeMsg": "Не удается отладить этот вызов. Отладка вызовов возможна только в режиме Remix VM.", + "terminal.ok": "Ok", + "terminal.cancel": "Отменить", + "terminal.callWarning": "(Применяется только в случае вызова контракта)", + "terminal.msg1": "Транзакция добыта, но выполнение не удалось", + "terminal.msg2": "Успешное выполнение транзакций", + "terminal.msg3": "Статус недоступен в данный момент", + "terminal.status": "статус", + "terminal.transactionHash": "хеш транзакции", + "terminal.blockHash": "хеш блока", + "terminal.blockNumber": "номер блока", + "terminal.contractAddress": "адрес контракта", + "terminal.transactionCost": "стоимость транзакции", + "terminal.executionCost": "стоимость исполнения", + "terminal.input": "ввод", + "terminal.decodedInput": "декодированный ввод", + "terminal.decodedOutput": "декодированный вывод", + "terminal.logs": "журналы" +} diff --git a/apps/remix-ide/src/app/tabs/locales/ru/udapp.json b/apps/remix-ide/src/app/tabs/locales/ru/udapp.json new file mode 100644 index 0000000000..4e69c9e02a --- /dev/null +++ b/apps/remix-ide/src/app/tabs/locales/ru/udapp.json @@ -0,0 +1,139 @@ +{ + "udapp.displayName": "Развертывание и запуск транзакций", + "udapp._comment_gasPrice.tsx": "libs/remix-ui/run-tab/src/lib/components/gasPrice.tsx", + "udapp.gasLimit": "Лимит газа", + "udapp.tooltipText4": "Стандартный газовой лимит составляет 3М. Регулировка по мере необходимости.", + "udapp._comment_value.tsx": "libs/remix-ui/run-tab/src/lib/components/value.tsx", + "udapp.value": "Значение", + "udapp.tooltipText5": "Введите сумму и выберите ее единицу", + "udapp._comment_contractDropdownUI.tsx": "libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx", + "udapp.contract": "Контракт", + "udapp.compiledBy": "скомпилировано {compilerName}", + "udapp.warningEvmVersion": "Пожалуйста, убедитесь, что выбранная сеть совместима с данной Evm версией: {evmVersion}. В противном случае развёртывание закончится неудачно.", + "udapp.infoSyncCompiledContractTooltip": "Нажмите здесь, чтобы импортировать контакты, скомпилированные из внешней платформы.\nЭто действие включается, когда Remix подключён к внешнему фреймворку (hardhat, truffle, foundry) через remixd", + "udapp.remixIpfsUdappTooltip": "Публикация исходного кода и метаданных IPFS облегчает верификацию исходного кода с помощью Sourcify и значительно ускоряет принятие контракта (аудит, отладка, вызов и т.д...)", + "udapp.deploy": "Развернуть", + "udapp.publishTo": "Опубликовать в", + "udapp.atAddress": "At Address", + "udapp.atAddressOptionsTitle1": "адрес контракта", + "udapp.atAddressOptionsTitle2": "Для взаимодействия с развёрнутым контрактом, необходимо выбрать в редакторе файл .abi или скомпилированный файл .sol (с той же конфигурацией компилятора)", + "udapp.atAddressOptionsTitle3": "Компилируйте *.sol файл или выберите файл *.abi.", + "udapp.atAddressOptionsTitle4": "Для взаимодействия с развёрнутым контрактом, либо введите его адрес и скомпилируйте исходный файл *.sol (с такими же настройками компилятора) или выберите его .abi файл в редакторе.", + "udapp.contractOptionsTitle1": "Пожалуйста, скомпилируйте *.sol файл для развертывания или доступа к контракту", + "udapp.contractOptionsTitle2": "Выберите скомпилированный контракт для развертывания или используйте по адресу.", + "udapp.contractOptionsTitle3": "Выберите и скомпилируйте *.sol файл для развертывания или доступа к контракту.", + "udapp.contractOptionsTitle4": "При наличии скомпилированного файла .sol, выберите контракт для развертывания или использования с параметром \"At Address\".", + "udapp.checkSumWarning": "Похоже вы не используете адрес с контрольной суммой. Адрес с контрольной суммой это адрес который состоит из заглавных букв, как указано в {a}. Контрольные адреса предназначены для предотвращения отправки пользователями транзакций по ошибочному адресу.", + "udapp.isOverSizePromptEip170": "Инициализация создания контракта возвращает данные длиной более 24576 байт. Развёртывание скорее всего завершится неудачей, если текущая сеть активировала eip 170. Дополнительная информация: {a}", + "udapp.isOverSizePromptEip3860": "Код инициализации контракта превышает допустимый максимальный размер кода 49152 байта. Развёртывание скорее всего не будет выполнено, если текущая сеть активировала eip 3860. Дополнительная информация: {a}", + "udapp.thisContractMayBeAbstract": "Этот контракт может быть абстрактным, он может не полностью применять методы абстрактного родительского объекта или он может неправильно вызывать унаследованный конструктор контракта.", + "udapp.noCompiledContracts": "Компилированных контрактов нет", + "udapp.addressOfContract": "Адрес контракта", + "udapp.loadContractFromAddress": "Загрузить контракт из адреса", + "udapp.ok": "OK", + "udapp.alert": "Предупреждение", + "udapp.proceed": "Продолжить", + "udapp.cancel": "Отменить", + "udapp.abiFileSelected": "Выбран файл ABI", + "udapp.evmVersion": "версия EVM", + "udapp.addressNotValid": "Адрес не действителен", + "udapp._comment_account.tsx": "libs/remix-ui/run-tab/src/lib/components/account.tsx", + "udapp.account": "Аккаунт", + "udapp.signAMessage": "Подписать сообщение", + "udapp.enterAMessageToSign": "Введите сообщение для подписания", + "udapp.hash": "хэш", + "udapp.signature": "подпись", + "udapp.injectedTitle": "К сожалению, невозможно создать учетную запись с помощью внедрённого провайдера. Пожалуйста, создайте аккаунт непосредственно у вашего провайдера (т.е. Metamask или другого такого же типа).", + "udapp.createNewAccount": "Создать новый аккаунт", + "udapp.web3Title": "Создание учетной записи возможно только в Личном режиме. Пожалуйста, перейдите в Настройки, чтобы включить ее.", + "udapp.defaultTitle": "К сожалению, невозможно создать учетную запись с помощью внешнего кошелька ({selectExEnv}).", + "udapp.text1": "Пожалуйста, укажите пароль для создания учетной записи", + "udapp.tooltipText1": "Список учётных записей пуст, пожалуйста, убедитесь, что текущий провайдер правильно подключен к remix", + "udapp.modalTitle1": "Парольная фраза для подписания сообщения", + "udapp.modalMessage1": "Введите ваш пароль для этой учётной записи чтобы подписания сообщения", + "udapp.copyAccount": "Копировать аккаунт в буфер обмена", + "udapp.signMsgUsingAccount": "Подписать сообщение, используя эту учетную запись", + "udapp._comment_environment.tsx": "libs/remix-ui/run-tab/src/lib/components/environment.tsx", + "udapp.environment": "Среда", + "udapp.environmentDocs": "Нажмите для получения документации о Среде", + "udapp.tooltipText2": "Откройте chainlist.org и получите данные подключения к цепочке, с которой вы хотите взаимодействовать.", + "udapp.tooltipText3": "Нажмите, чтобы открыть мост для преобразования L1 mainnet ETH в выбранную сетевую валюту.", + "udapp._comment_instanceContainerUI.tsx": "libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx", + "udapp.deployedContracts": "Развернутые контракты", + "udapp.deployAndRunClearInstances": "Очистить список экземпляров и сбросить рекордер", + "udapp.deployAndRunNoInstanceText": "В настоящее время у вас нет экземпляров контракта для взаимодействия.", + "udapp.tooltipText6": "Автоматически создаваемые пользовательские интерфейсы для взаимодействия с развернутыми контрактами", + "udapp._comment_recorderCardUI.tsx": "libs/remix-ui/run-tab/src/lib/components/recorderCardUI.tsx", + "udapp.transactionsRecorded": "Транзакции записаны", + "udapp.transactionsCountTooltip": "Количество записанных транзакций", + "udapp.transactionSaveTooltip1": "Нет транзакций для сохранения", + "udapp.transactionSaveTooltip2": "Сохранить транзакцию {count} как файл сценария", + "udapp.transactionSaveTooltip3": "Сохранить транзакции {count} как файл сценария", + "udapp.transactionsWalkthroughTooltip": "Начать пошаговое описание для записи.", + "udapp.infoRecorderTooltip": "Сохранить транзакции (развернутые контракты и выполнение функций) и повторить их в другой среде. Например, транзакции, созданные в Remix VM, могут воспроизводиться во внутреннем провайдере (Injected Provider).", + "udapp.livemodeRecorderTooltip": "Если контракты обновляются после записи транзакций, то установка этого флажка приведёт к запуску записанных транзакций с последней копией скомпилированных контрактов", + "udapp.livemodeRecorderLabel": "Выполнить транзакции с использованием последнего результата компиляции", + "udapp.runRecorderTooltip": "Выполнить транзакцию(и) из текущего файла сценария", + "udapp.save": "Сохранить", + "udapp.run": "Запустить", + "udapp._comment_contractGUI.tsx": "libs/remix-ui/run-tab/src/lib/components/contractGUI.tsx", + "udapp.parameters": "Параметры", + "udapp.copyParameters": "Копировать параметры ввода в буфер обмена", + "udapp.copyCalldata": "Копировать данные вызова в буфер обмена", + "udapp.deployWithProxy": "Развернуть с прокси", + "udapp.upgradeWithProxy": "Обновить с прокси", + "udapp.getEncodedCallError": "невозможно кодировать пустые аргументы", + "udapp.proxyAddressError1": "прокси адрес не может быть пустым", + "udapp.proxyAddressError2": "недействительный адрес контракта", + "udapp.tooltipText11": "Прокси адрес не может быть пустым", + "udapp.tooltipText12": "Требуется ввод", + "udapp.tooltipText13": "Развернуто {date}", + "udapp._comment_universalDappUI.tsx": "libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx", + "udapp.tooltipText7": "Удалить из списка", + "udapp.tooltipText8": "Нажмите для просмотра документации об использовании функций 'receive'/'fallback'", + "udapp.tooltipText9": "Данные вызова для отправки в резервную функцию контракта.", + "udapp.tooltipText10": "Отправить данные контракту.", + "udapp.balance": "Баланс", + "udapp.lowLevelInteractions": "Взаимодействия низкого уровня", + "udapp.llIError1": "Отправляемое значение должно быть числом", + "udapp.llIError2": "Для получения перевода Ether контракт должен иметь функцию 'receive' или оплачиваемую функцию 'fallback'", + "udapp.llIError3": "Вызываемые данные должны быть допустимым шестнадцатеричным значением с размером не менее одного байта.", + "udapp.llIError4": "Вызываемые данные должны быть допустимым шестнадцатеричным значением.", + "udapp.llIError5": "Функция 'Fallback' не определена", + "udapp.llIError6": "Обе функции 'receive' и 'fallback' не определены", + "udapp.llIError7": "Пожалуйста, определите функцию 'Fallback' для отправки вызываемых данных или 'Receive' или оплачиваемую функцию 'Fallback' для отправки эфира", + "udapp.copy": "Копировать", + "udapp._comment_mainnet.tsx": "libs/remix-ui/run-tab/src/lib/components/mainnet.tsx", + "udapp.mainnetText1": "Вы собираетесь создать транзакцию в сети {name}. Подтвердите данные для отправки информации вашему провайдеру.", + "udapp.mainnetText2": "Провайдером для многих пользователей является MetaMask. Провайдер попросит вас подписать транзакцию перед отправкой ее в сеть {name}.", + "udapp.amount": "Количество", + "udapp.gasEstimation": "Оценка газа", + "udapp.maxPriorityFee": "Максимальная плата за приоритет", + "udapp.maxFee": "Максимальная комиссия (не меньше базовой комиссии {baseFeePerGas} Gwei)", + "udapp.contractCreation": "Создание контракта", + "udapp.transactionFee": "Недопустимая операция. Максимальная комиссия не должна быть меньше базовой комиссии", + "udapp.title1": "Представляет собой часть комиссии, которая направляется майнеру", + "udapp.title2": "Представляет максимальную сумму комиссии, которую вы платите за эту транзакцию. Минимальная сумма должна быть равной базовой комиссии.", + "udapp.gasPrice": "Цена газа", + "udapp.gweiText": "посетите {a} для информации о текущей цене газа.", + "udapp.maxTransactionFee": "Максимальная комиссия за транзакцию", + "udapp.mainnetText3": "Больше не показывать это предупреждение.", + "udapp._comment_run-tab.tsx": "libs/remix-ui/run-tab/src/lib/run-tab.tsx", + "udapp.gasEstimationPromptText": "При оценке газа произошла ошибка со следующим сообщением (см. ниже). Выполнение транзакции скорее всего закончится неудачно. Хотите принудительно отправить?", + "udapp._comment_custom-dropdown.tsx": "libs/remix-ui/helper/src/lib/components/custom-dropdown.tsx", + "udapp.enterProxyAddress": "Введите адрес прокси", + "udapp._comment_provider": "apps/remix-ide/src/app/providers", + "udapp.customVmForkProviderText": "Пожалуйста, предоставьте информацию о пользовательском форке. Если URL-адрес узла не указан, Виртуальная Машина запустится с пустого состояния.", + "udapp.nodeUrl": "URL узла", + "udapp.blockNumber": "Номер блока (или \"последний\")", + "udapp.externalHttpProviderText1": "Примечание: Для использования Geth и https://remix.ethereum.org, настройте его так, чтобы он разрешал запросы от Remix:(см. Geth Docs на сервере rpc)", + "udapp.externalHttpProviderText2": "Для запуска Remix и локального тестового узла Geth используйте эту команду: (см. Geth Docs в режиме Dev mode )", + "udapp.externalHttpProviderText3": "ВНИМАНИЕ: Не безопасно использование флага --http.corsdomain с подстановочным символом: --http.corsdomain *", + "udapp.externalHttpProviderText4": "Для дополнительной информации: Remix Docs на внешнем HTTP провайдере", + "udapp.foundryProviderText1": "Примечание: Чтобы запустить Anvil в системе, запустите:", + "udapp.foundryProviderText2": "Для получения дополнительной информации, посетите Документация по инструментарию разработки смарт-контрактов (Foundry) ", + "udapp.ganacheProviderText1": "Примечание: Чтобы запустить Ganache в системе, запустите:", + "udapp.ganacheProviderText2": "Для получения дополнительной информации, посетите: Документация по Ganache", + "udapp.hardhatProviderText1": "Примечание: Для запуска узла Hardhat в вашей системе, перейдите в папку hardhat проекта и запустите команду:", + "udapp.hardhatProviderText2": "Для получения дополнительной информации, посетите: Документация по Hardhat" +} diff --git a/apps/remix-ide/src/app/udapp/run-tab.js b/apps/remix-ide/src/app/udapp/run-tab.js index 7d65cae8de..515e0093b9 100644 --- a/apps/remix-ide/src/app/udapp/run-tab.js +++ b/apps/remix-ide/src/app/udapp/run-tab.js @@ -1,7 +1,10 @@ import React from 'react' // eslint-disable-line import {RunTabUI} from '@remix-ui/run-tab' import {ViewPlugin} from '@remixproject/engine-web' +import isElectron from 'is-electron' import {addressToString} from '@remix-ui/helper' +import {InjectedProviderDefault} from '../providers/injected-provider-default' +import {InjectedCustomProvider} from '../providers/injected-custom-provider' import * as packageJson from '../../../../../package.json' const EventManager = require('../../lib/events') @@ -28,17 +31,18 @@ const profile = { 'getSettings', 'setEnvironmentMode', 'clearAllInstances', - 'clearAllSavedInstances', + 'clearAllPinnedInstances', 'addInstance', - 'addSavedInstance', + 'addPinnedInstance', 'resolveContractAndAddInstance' ] } export class RunTab extends ViewPlugin { - constructor(blockchain, config, fileManager, editor, filePanel, compilersArtefacts, networkModule, fileProvider) { + constructor(blockchain, config, fileManager, editor, filePanel, compilersArtefacts, networkModule, fileProvider, engine) { super(profile) this.event = new EventManager() + this.engine = engine this.config = config this.blockchain = blockchain this.fileManager = fileManager @@ -81,16 +85,16 @@ export class RunTab extends ViewPlugin { this.emit('clearAllInstancesReducer') } - clearAllSavedInstances() { - this.emit('clearAllSavedInstancesReducer') + clearAllPinnedInstances() { + this.emit('clearAllPinnedInstancesReducer') } addInstance(address, abi, name, contractData) { this.emit('addInstanceReducer', address, abi, name, contractData) } - addSavedInstance(address, abi, name, savedOn, filePath) { - this.emit('addSavedInstanceReducer', address, abi, name, savedOn, filePath) + addPinnedInstance(address, abi, name, pinnedAt, filePath) { + this.emit('addPinnedInstanceReducer', address, abi, name, pinnedAt, filePath) } createVMAccount(newAccount) { @@ -125,8 +129,9 @@ export class RunTab extends ViewPlugin { async onInitDone() { const udapp = this // eslint-disable-line - const addProvider = async (name, displayName, isInjected, isVM, fork = '', dataId = '', title = '') => { + const addProvider = async (position, name, displayName, isInjected, isVM, fork = '', dataId = '', title = '') => { await this.call('blockchain', 'addProvider', { + position, options: {}, dataId, name, @@ -150,59 +155,73 @@ export class RunTab extends ViewPlugin { }) } - // basic injected - // if it's the trust wallet provider, we have a specific provider for that, see below - if (window && window.ethereum && !(window.ethereum.isTrustWallet || window.ethereum.selectedProvider?.isTrustWallet)) { - const displayNameInjected = `Injected Provider${ - window && window.ethereum && !(window.ethereum.providers && !window.ethereum.selectedProvider) - ? window.ethereum.isCoinbaseWallet || window.ethereum.selectedProvider?.isCoinbaseWallet - ? ' - Coinbase' - : window.ethereum.isBraveWallet || window.ethereum.selectedProvider?.isBraveWallet - ? ' - Brave' - : window.ethereum.isMetaMask || window.ethereum.selectedProvider?.isMetaMask - ? ' - MetaMask' - : '' - : '' - }` - await addProvider('injected', displayNameInjected, true, false) - } else if (window && !window.ethereum) { - // we still add "injected" if there's no provider (just so it's visible to the user). - await addProvider('injected', 'Injected Provider', true, false) + const addCustomInjectedProvider = async (position, event, name, displayName, networkId, urls, nativeCurrency) => { + // name = `${name} through ${event.detail.info.name}` + await this.engine.register([new InjectedCustomProvider(event.detail.provider, name, networkId, urls, nativeCurrency)]) + await addProvider(position, name, displayName, true, false, false) } - - if (window && window.trustwallet) { - const displayNameInjected = `Injected Provider - TrustWallet` - await addProvider('injected-trustwallet', displayNameInjected, true, false) + const registerInjectedProvider = async (event) => { + console.log('registerInjectedProvider', event) + const name = 'injected-' + event.detail.info.name + const displayName = 'Injected Provider - ' + event.detail.info.name + await this.engine.register([new InjectedProviderDefault(event.detail.provider, name)]) + await addProvider(0, name, displayName, true, false, false) + + if (event.detail.info.name === 'MetaMask') { + await addCustomInjectedProvider(7, event, 'injected-metamask-optimism', 'L2 - Optimism', '0xa', ['https://mainnet.optimism.io']) + await addCustomInjectedProvider(8, event, 'injected-metamask-arbitrum', 'L2 - Arbitrum', '0xa4b1', ['https://arb1.arbitrum.io/rpc']) + await addCustomInjectedProvider(5, event, 'injected-metamask-sepolia', 'Testnet - Sepolia', '0xaa36a7', [], + { + "name": "Sepolia ETH", + "symbol": "ETH", + "decimals": 18 + }) + await addCustomInjectedProvider(9, event, 'injected-metamask-ephemery', 'Ephemery Testnet', '', ['https://otter.bordel.wtf/erigon', 'https://eth.ephemeral.zeus.fyi'], + { + "name": "Ephemery ETH", + "symbol": "ETH", + "decimals": 18 + }) + /* + await addCustomInjectedProvider(9, event, 'SKALE Chaos Testnet', '0x50877ed6', ['https://staging-v3.skalenodes.com/v1/staging-fast-active-bellatrix'], + { + "name": "sFUEL", + "symbol": "sFUEL", + "decimals": 18 + }) + */ + } } // VM const titleVM = 'Execution environment is local to Remix. Data is only saved to browser memory and will vanish upon reload.' - await addProvider('vm-cancun', 'Remix VM (Cancun)', false, true, 'cancun', 'settingsVMCancunMode', titleVM) - await addProvider('vm-shanghai', 'Remix VM (Shanghai)', false, true, 'shanghai', 'settingsVMShanghaiMode', titleVM) - await addProvider('vm-paris', 'Remix VM (Paris)', false, true, 'paris', 'settingsVMParisMode', titleVM) - await addProvider('vm-london', 'Remix VM (London)', false, true, 'london', 'settingsVMLondonMode', titleVM) - await addProvider('vm-berlin', 'Remix VM (Berlin)', false, true, 'berlin', 'settingsVMBerlinMode', titleVM) - await addProvider('vm-mainnet-fork', 'Remix VM - Mainnet fork', false, true, 'cancun', 'settingsVMMainnetMode', titleVM) - await addProvider('vm-sepolia-fork', 'Remix VM - Sepolia fork', false, true, 'cancun', 'settingsVMSepoliaMode', titleVM) - await addProvider('vm-goerli-fork', 'Remix VM - Goerli fork', false, true, 'paris', 'settingsVMGoerliMode', titleVM) - await addProvider('vm-custom-fork', 'Remix VM - Custom fork', false, true, '', 'settingsVMCustomMode', titleVM) + await addProvider(1, 'vm-cancun', 'Remix VM (Cancun)', false, true, 'cancun', 'settingsVMCancunMode', titleVM) + await addProvider(50, 'vm-shanghai', 'Remix VM (Shanghai)', false, true, 'shanghai', 'settingsVMShanghaiMode', titleVM) + await addProvider(51, 'vm-paris', 'Remix VM (Paris)', false, true, 'paris', 'settingsVMParisMode', titleVM) + await addProvider(52, 'vm-london', 'Remix VM (London)', false, true, 'london', 'settingsVMLondonMode', titleVM) + await addProvider(53, 'vm-berlin', 'Remix VM (Berlin)', false, true, 'berlin', 'settingsVMBerlinMode', titleVM) + await addProvider(2, 'vm-mainnet-fork', 'Remix VM - Mainnet fork', false, true, 'cancun', 'settingsVMMainnetMode', titleVM) + await addProvider(3, 'vm-sepolia-fork', 'Remix VM - Sepolia fork', false, true, 'cancun', 'settingsVMSepoliaMode', titleVM) + await addProvider(4, 'vm-custom-fork', 'Remix VM - Custom fork', false, true, '', 'settingsVMCustomMode', titleVM) // wallet connect - await addProvider('walletconnect', 'WalletConnect', false, false) - - // testnet - await addProvider('injected-ephemery-testnet-provider', 'Ephemery Testnet', true, false) - await addProvider('injected-skale-chaos-testnet-provider', 'SKALE Chaos Testnet', true, false) + await addProvider(6, 'walletconnect', 'WalletConnect', false, false) // external provider - await addProvider('basic-http-provider', 'Custom - External Http Provider', false, false) - await addProvider('hardhat-provider', 'Dev - Hardhat Provider', false, false) - await addProvider('ganache-provider', 'Dev - Ganache Provider', false, false) - await addProvider('foundry-provider', 'Dev - Foundry Provider', false, false) - - // injected provider - await addProvider('injected-optimism-provider', 'L2 - Optimism Provider', true, false) - await addProvider('injected-arbitrum-one-provider', 'L2 - Arbitrum One Provider', true, false) + await addProvider(10, 'basic-http-provider', 'Custom - External Http Provider', false, false) + await addProvider(20, 'hardhat-provider', 'Dev - Hardhat Provider', false, false) + await addProvider(21, 'ganache-provider', 'Dev - Ganache Provider', false, false) + await addProvider(22, 'foundry-provider', 'Dev - Foundry Provider', false, false) + + // register injected providers + + window.addEventListener( + "eip6963:announceProvider", + (event) => { + registerInjectedProvider(event) + } + ) + if (!isElectron()) window.dispatchEvent(new Event("eip6963:requestProvider")) } writeFile(fileName, content) { diff --git a/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css b/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css index eac0b0f94f..ad040ceabb 100644 --- a/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css +++ b/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css @@ -66,6 +66,19 @@ body { text-align:left; background-color:#fff } + +*::-webkit-scrollbar { + width: 8px; + height: 6px; + background-color: var(--body-bg); +} + +*::-webkit-scrollbar-thumb { + background-color: var(--secondary); + opacity: 0.3; + border-radius: 30px; +} + [tabindex="-1"]:focus:not(:focus-visible) { outline:0!important } diff --git a/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css b/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css index 0c74e7f730..4af9940e57 100644 --- a/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css +++ b/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css @@ -67,6 +67,19 @@ body { text-align:left; background-color:#060606 } + +*::-webkit-scrollbar { + width: 8px; + height: 6px; + background-color: var(--body-bg); +} + +*::-webkit-scrollbar-thumb { + background-color: var(--secondary); + opacity: 0.3; + border-radius: 30px; +} + [tabindex="-1"]:focus:not(:focus-visible) { outline:0!important } @@ -5635,7 +5648,7 @@ a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover { background-color:#090909!important } .bg-dark { - background-color:#adafae!important + background-color:#2f3130!important } a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { background-color:#939695!important diff --git a/apps/remix-ide/src/assets/css/themes/bootstrap-flatly.min.css b/apps/remix-ide/src/assets/css/themes/bootstrap-flatly.min.css index 45d3dfe8eb..ab8737b811 100644 --- a/apps/remix-ide/src/assets/css/themes/bootstrap-flatly.min.css +++ b/apps/remix-ide/src/assets/css/themes/bootstrap-flatly.min.css @@ -65,6 +65,19 @@ body { text-align:left; background-color:#fff } + +*::-webkit-scrollbar { + width: 8px; + height: 6px; + background-color: var(--body-bg); +} + +*::-webkit-scrollbar-thumb { + background-color: var(--secondary); + opacity: 0.3; + border-radius: 30px; +} + [tabindex="-1"]:focus:not(:focus-visible) { outline:0!important } diff --git a/apps/remix-ide/src/assets/css/themes/bootstrap-spacelab.min.css b/apps/remix-ide/src/assets/css/themes/bootstrap-spacelab.min.css index dc4d761c61..79bc661135 100644 --- a/apps/remix-ide/src/assets/css/themes/bootstrap-spacelab.min.css +++ b/apps/remix-ide/src/assets/css/themes/bootstrap-spacelab.min.css @@ -69,6 +69,19 @@ body { text-align:left; background-color:#fff } + +*::-webkit-scrollbar { + width: 8px; + height: 6px; + background-color: var(--body-bg); +} + +*::-webkit-scrollbar-thumb { + background-color: var(--secondary); + opacity: 0.3; + border-radius: 30px; +} + [tabindex="-1"]:focus:not(:focus-visible) { outline:0!important } diff --git a/apps/remix-ide/src/assets/css/themes/remix-black_undtds.css b/apps/remix-ide/src/assets/css/themes/remix-black_undtds.css index 8af0836f0b..75d64e2ed1 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-black_undtds.css +++ b/apps/remix-ide/src/assets/css/themes/remix-black_undtds.css @@ -73,7 +73,8 @@ body { background-color: var(--body-bg); } *::-webkit-scrollbar { - width: 8px; + width: 8px; + height: 6px; } *::-webkit-scrollbar-thumb { background-color: #37373b; diff --git a/apps/remix-ide/src/assets/css/themes/remix-candy_ikhg4m.css b/apps/remix-ide/src/assets/css/themes/remix-candy_ikhg4m.css index aba42e3ac6..5ca0945900 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-candy_ikhg4m.css +++ b/apps/remix-ide/src/assets/css/themes/remix-candy_ikhg4m.css @@ -14,7 +14,7 @@ --gray: #6c757d; --gray-dark: #343a40; --primary: #fc58a3; - --secondary: #e2f5f2; + --secondary: #c7e3de; --success: #24b882; --info: #00bbff; --warning: #fabe33; @@ -76,6 +76,18 @@ body { background-color: var(--body-bg); } +*::-webkit-scrollbar { + width: 8px; + height: 6px; + background-color: var(--body-bg); +} + +*::-webkit-scrollbar-thumb { + background-color: var(--secondary); + opacity: 0.3; + border-radius: 30px; +} + [tabindex="-1"]:focus { outline: 0 !important; } diff --git a/apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css b/apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css index 1708371250..249a430f6c 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css +++ b/apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css @@ -73,7 +73,8 @@ body { background-color: var(--body-bg); } *::-webkit-scrollbar { - width: 8px; + width: 8px; + height: 6px; } *::-webkit-scrollbar-thumb { background-color: #41455b; diff --git a/apps/remix-ide/src/assets/css/themes/remix-hacker_owl.css b/apps/remix-ide/src/assets/css/themes/remix-hacker_owl.css index 6c9ecb9534..4230f2c6a0 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-hacker_owl.css +++ b/apps/remix-ide/src/assets/css/themes/remix-hacker_owl.css @@ -90,7 +90,8 @@ body { background-color: var(--body-bg); } *::-webkit-scrollbar { - width: 8px; + width: 8px; + height: 6px; } *::-webkit-scrollbar-thumb { background-color: #41455b; diff --git a/apps/remix-ide/src/assets/css/themes/remix-light_powaqg.css b/apps/remix-ide/src/assets/css/themes/remix-light_powaqg.css index 3d47c2031c..7b520a88ee 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-light_powaqg.css +++ b/apps/remix-ide/src/assets/css/themes/remix-light_powaqg.css @@ -76,6 +76,18 @@ body { background-color: var(--body-bg); } +*::-webkit-scrollbar { + width: 8px; + height: 6px; + background-color: var(--body-bg); +} + +*::-webkit-scrollbar-thumb { + background-color: var(--secondary); + opacity: 0.3; + border-radius: 30px; +} + [tabindex="-1"]:focus { outline: 0 !important; } diff --git a/apps/remix-ide/src/assets/css/themes/remix-midcentury_hrzph3.css b/apps/remix-ide/src/assets/css/themes/remix-midcentury_hrzph3.css index 0b6cb171f4..739f79ca95 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-midcentury_hrzph3.css +++ b/apps/remix-ide/src/assets/css/themes/remix-midcentury_hrzph3.css @@ -76,6 +76,18 @@ body { background-color: var(--body-bg); } +*::-webkit-scrollbar { + width: 8px; + height: 6px; + background-color: var(--body-bg); +} + +*::-webkit-scrollbar-thumb { + background-color: var(--secondary); + opacity: 0.3; + border-radius: 30px; +} + [tabindex="-1"]:focus { outline: 0 !important; } diff --git a/apps/remix-ide/src/assets/css/themes/remix-unicorn.css b/apps/remix-ide/src/assets/css/themes/remix-unicorn.css index a7f4196f71..3ac67df8cd 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-unicorn.css +++ b/apps/remix-ide/src/assets/css/themes/remix-unicorn.css @@ -76,6 +76,18 @@ body { background-color: var(--body-bg); } +*::-webkit-scrollbar { + width: 8px; + height: 6px; + background-color: var(--body-bg); +} + +*::-webkit-scrollbar-thumb { + background-color: var(--secondary); + opacity: 0.3; + border-radius: 30px; +} + [tabindex="-1"]:focus { outline: 0 !important; } diff --git a/apps/remix-ide/src/assets/css/themes/remix-violet.css b/apps/remix-ide/src/assets/css/themes/remix-violet.css index 85b855c862..3782cb7518 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-violet.css +++ b/apps/remix-ide/src/assets/css/themes/remix-violet.css @@ -76,6 +76,18 @@ body { background-color: var(--body-bg); } +*::-webkit-scrollbar { + width: 8px; + height: 6px; + background-color: var(--body-bg); +} + +*::-webkit-scrollbar-thumb { + background-color: var(--secondary); + opacity: 0.3; + border-radius: 30px; +} + [tabindex="-1"]:focus { outline: 0 !important; } diff --git a/apps/remix-ide/src/blockchain/blockchain.tsx b/apps/remix-ide/src/blockchain/blockchain.tsx index fa57a1d58b..b30a88c0ad 100644 --- a/apps/remix-ide/src/blockchain/blockchain.tsx +++ b/apps/remix-ide/src/blockchain/blockchain.tsx @@ -61,6 +61,7 @@ export class Blockchain extends Plugin { } providers: {[key: string]: VMProvider | InjectedProvider | NodeProvider} transactionContextAPI: TransactionContextAPI + registeredPluginEvents: string[] // NOTE: the config object will need to be refactored out in remix-lib constructor(config: Config) { @@ -91,6 +92,7 @@ export class Blockchain extends Plugin { this.networkcallid = 0 this.networkStatus = {network: {name: ' - ', id: ' - '}} + this.registeredPluginEvents = [] this.setupEvents() this.setupProviders() } @@ -103,34 +105,24 @@ export class Blockchain extends Plugin { onActivation() { this.active = true - this.on('injected', 'chainChanged', () => { - this.detectNetwork((error, network) => { - this.networkStatus = {network, error} - this._triggerEvent('networkStatus', [this.networkStatus]) - }) - }) - - this.on('injected-trustwallet', 'chainChanged', () => { - this.detectNetwork((error, network) => { - this.networkStatus = {network, error} - this._triggerEvent('networkStatus', [this.networkStatus]) - }) - }) - - this.on('walletconnect', 'chainChanged', () => { - this.detectNetwork((error, network) => { - this.networkStatus = {network, error} - this._triggerEvent('networkStatus', [this.networkStatus]) - }) + this.on('manager', 'pluginActivated', (plugin) => { + if (plugin && plugin.name && (plugin.name.startsWith('injected') || plugin.name === 'walletconnect')) { + this.registeredPluginEvents.push(plugin.name) + this.on(plugin.name, 'chainChanged', () => { + this.detectNetwork((error, network) => { + this.networkStatus = {network, error} + this._triggerEvent('networkStatus', [this.networkStatus]) + }) + }) + } }) } onDeactivation() { this.active = false - this.off('injected', 'chainChanged') - this.off('injected-trustwallet', 'chainChanged') - this.off('walletconnect', 'chainChanged') - this.off('walletconnect', 'accountsChanged') + for (const pluginName of this.registeredPluginEvents) { + this.off(pluginName, 'chainChanged') + } } setupEvents() { @@ -175,6 +167,7 @@ export class Blockchain extends Plugin { getCurrentProvider() { const provider = this.getProvider() if (provider && provider.startsWith('vm')) return this.providers['vm'] + if (provider && provider.startsWith('injected')) return this.providers['injected'] if (this.providers[provider]) return this.providers[provider] return this.providers.web3 // default to the common type of provider } @@ -534,16 +527,6 @@ export class Blockchain extends Plugin { return this.executionContext.getCurrentFork() } - isWeb3Provider() { - const isVM = this.executionContext.isVM() - const isInjected = this.getProvider() === 'injected' - return !isVM && !isInjected - } - - isInjectedWeb3() { - return this.getProvider() === 'injected' - } - signMessage(message, account, passphrase, cb) { this.getCurrentProvider().signMessage(message, account, passphrase, cb) } diff --git a/apps/remix-ide/src/blockchain/providers/injected.ts b/apps/remix-ide/src/blockchain/providers/injected.ts index 905e77559a..8ef55f8093 100644 --- a/apps/remix-ide/src/blockchain/providers/injected.ts +++ b/apps/remix-ide/src/blockchain/providers/injected.ts @@ -48,8 +48,4 @@ export class InjectedProvider { cb(e.message) } } - - getProvider () { - return 'injected' - } } diff --git a/apps/remix-ide/src/blockchain/providers/node.ts b/apps/remix-ide/src/blockchain/providers/node.ts index fec159f11f..9c7c538307 100644 --- a/apps/remix-ide/src/blockchain/providers/node.ts +++ b/apps/remix-ide/src/blockchain/providers/node.ts @@ -55,8 +55,4 @@ export class NodeProvider { cb(e.message) } } - - getProvider () { - return this.executionContext.getProvider() - } } diff --git a/apps/remix-ide/src/blockchain/providers/vm.ts b/apps/remix-ide/src/blockchain/providers/vm.ts index e44b67946a..8c210260fa 100644 --- a/apps/remix-ide/src/blockchain/providers/vm.ts +++ b/apps/remix-ide/src/blockchain/providers/vm.ts @@ -134,9 +134,5 @@ export class VMProvider { this.web3.eth.sign(message, account) .then(signedData => cb(null, bytesToHex(messageHash), signedData)) .catch(error => cb(error)) - } - - getProvider () { - return this.executionContext.getProvider() - } + } } diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index 0e1d78fdce..919b04a132 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -52,12 +52,6 @@ let requiredModules = [ // services + layout views + system views 'ganache-provider', 'foundry-provider', 'basic-http-provider', - 'injected', - 'injected-trustwallet', - 'injected-optimism-provider', - 'injected-arbitrum-one-provider', - 'injected-ephemery-testnet-provider', - 'injected-skale-chaos-testnet-provider', 'vm-custom-fork', 'vm-goerli-fork', 'vm-mainnet-fork', @@ -98,7 +92,16 @@ const sensitiveCalls = { web3Provider: ['sendAsync'] } +const isInjectedProvider = (name) => { + return name.startsWith('injected') +} + +const isVM = (name) => { + return name.startsWith('vm') +} + export function isNative(name) { + // nativePlugin allows to bypass the permission request const nativePlugins = [ 'vyper', @@ -117,19 +120,16 @@ export function isNative(name) { 'ganache-provider', 'foundry-provider', 'basic-http-provider', - 'injected-optimism-provider', 'tabs', - 'injected-arbitrum-one-provider', - 'injected-skale-chaos-testnet-provider', - 'injected-ephemery-testnet-provider', - 'injected', 'doc-gen', 'doc-viewer', 'circuit-compiler', 'compilationDetails', - 'vyperCompilationDetails' + 'vyperCompilationDetails', + 'remixGuide', + 'walletconnect' ] - return nativePlugins.includes(name) || requiredModules.includes(name) + return nativePlugins.includes(name) || requiredModules.includes(name) || isInjectedProvider(name) || isVM(name) } /** @@ -163,7 +163,7 @@ export class RemixAppManager extends PluginManager { } async canDeactivatePlugin(from, to) { - if (requiredModules.includes(to.name)) return false + if (this.isRequired(to.name)) return false return isNative(from.name) } @@ -208,7 +208,7 @@ export class RemixAppManager extends PluginManager { ) this.event.emit('activate', plugin) this.emit('activate', plugin) - if (!requiredModules.includes(plugin.name)) _paq.push(['trackEvent', 'pluginManager', 'activate', plugin.name]) + if (!this.isRequired(plugin.name)) _paq.push(['trackEvent', 'pluginManager', 'activate', plugin.name]) } getAll() { @@ -236,7 +236,7 @@ export class RemixAppManager extends PluginManager { isRequired(name) { // excluding internal use plugins - return requiredModules.includes(name) + return requiredModules.includes(name) || isInjectedProvider(name) || isVM(name) } async registeredPlugins() { diff --git a/apps/vyper/src/app/app.tsx b/apps/vyper/src/app/app.tsx index f6f0ef2279..58a5d92a04 100644 --- a/apps/vyper/src/app/app.tsx +++ b/apps/vyper/src/app/app.tsx @@ -47,6 +47,7 @@ const App = () => { try { await remixClient.loaded() remixClient.onFileChange((name) => { + !name.endsWith('.vy') && remixClient.changeStatus({ key: 'none' }) setOutput({}) setContract(name) }) @@ -116,9 +117,9 @@ const App = () => {
- +
@@ -155,13 +156,13 @@ const App = () => { compiler version {' '} &{' '} - + EVM version {' '} in the .vy file.
- setOutput({...output, [name]: update})} resetCompilerState={resetCompilerResultState} /> + setOutput({...output, [name]: update})} resetCompilerState={resetCompilerResultState} output={output} remixClient={remixClient}/>
diff --git a/apps/vyper/src/app/components/CompileErrorCard.tsx b/apps/vyper/src/app/components/CompileErrorCard.tsx index dce0afe26b..10774ea01e 100644 --- a/apps/vyper/src/app/components/CompileErrorCard.tsx +++ b/apps/vyper/src/app/components/CompileErrorCard.tsx @@ -7,7 +7,6 @@ export function CompileErrorCard(props: { output: any, plugin: RemixClient }) {
- await props.plugin.askGpt(props.output.message)}> + await props.plugin.askGpt(props.output.message)}> Ask GPT diff --git a/apps/vyper/src/app/components/CompilerButton.tsx b/apps/vyper/src/app/components/CompilerButton.tsx index 54597171e9..cf06790c4e 100644 --- a/apps/vyper/src/app/components/CompilerButton.tsx +++ b/apps/vyper/src/app/components/CompilerButton.tsx @@ -1,16 +1,19 @@ -import React, { Fragment, useState } from 'react' -import {isVyper, compile, toStandardOutput, isCompilationError, remixClient, normalizeContractPath, compileContract} from '../utils' +import React, { Fragment, useEffect, useState } from 'react' +import {isVyper, compile, toStandardOutput, isCompilationError, remixClient, normalizeContractPath, compileContract, RemixClient} from '../utils' import Button from 'react-bootstrap/Button' interface Props { compilerUrl: string contract?: string + output?: any setOutput: (name: string, output: any) => void resetCompilerState: () => void + remixClient: RemixClient } -function CompilerButton({contract, setOutput, compilerUrl, resetCompilerState}: Props) { +function CompilerButton({contract, setOutput, compilerUrl, resetCompilerState, output, remixClient}: Props) { const [loadingSpinner, setLoadingSpinnerState] = useState(false) + if (!contract || !contract) { return } @@ -24,12 +27,14 @@ function CompilerButton({contract, setOutput, compilerUrl, resetCompilerState}: return ( } + { props.tagList &&
+ { Object.keys(props.tagList).map((key) => ( + filterCon.keyValueMap[props.tagList[key]].enabled && ( + + + + + ) + )) } +
} + { !props.tagList && + } +
} +
+ ) +} + +export default RemixUIGridCell diff --git a/libs/remix-ui/grid-view/src/lib/remix-ui-grid-section.css b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-section.css new file mode 100644 index 0000000000..5c79533a71 --- /dev/null +++ b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-section.css @@ -0,0 +1,26 @@ +.remixui_grid_section { + font-weight: normal; +} + +.remixui_grid_section_container { + width: fit-content; +} + +.remixui_grid_section_title{ + font-size: 0.8rem; + font-style: italic; +} + +.remixui_grid_section_btn { + width: 32px; +} + +.remixui_grid_section_logo { + width: 3rem; + height: 3rem; +} + +* { + scrollbar-width: thin; + scrollbar-color: var(--bg-dark) var(--bg-light); +} \ No newline at end of file diff --git a/libs/remix-ui/grid-view/src/lib/remix-ui-grid-section.tsx b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-section.tsx new file mode 100644 index 0000000000..c1b332bc01 --- /dev/null +++ b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-section.tsx @@ -0,0 +1,38 @@ +import React, {useState, useEffect, useContext, useRef, ReactNode} from 'react' // eslint-disable-line + +import './remix-ui-grid-section.css' + +declare global { + interface Window { + _paq: any + } +} +const _paq = window._paq = window._paq || [] + +interface RemixUIGridSectionProps { + plugin: any + title?: string + hScrollable: boolean + classList?: string + styleList?: any + children?: ReactNode +} + +export const RemixUIGridSection = (props: RemixUIGridSectionProps) => { + return ( +
+
+ { props.title &&
{ props.title }
} +
+ { props.children } +
+
+
+ ) +} + +export default RemixUIGridSection diff --git a/libs/remix-ui/grid-view/src/lib/remix-ui-grid-view.css b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-view.css new file mode 100644 index 0000000000..89e41d0cdf --- /dev/null +++ b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-view.css @@ -0,0 +1,25 @@ +.remixui_grid_view { + font-weight: normal; +} + +.remixui_grid_view_container { + overflow: auto; +} + +.remixui_grid_view_title{ + font-size: 0.8rem; + font-style: italic; +} + +.remixui_grid_view_btn { + width: 32px; +} + +.remixui_grid_view_logo { + width: 3rem; + height: 3rem; +} + +.remixui_grid_view_titlebar { + min-width: max-content; +} \ No newline at end of file diff --git a/libs/remix-ui/grid-view/src/lib/remix-ui-grid-view.tsx b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-view.tsx new file mode 100644 index 0000000000..19fdfe452c --- /dev/null +++ b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-view.tsx @@ -0,0 +1,147 @@ +import React, {useState, useEffect, useContext, useRef, ReactNode} from 'react' // eslint-disable-line + +import './remix-ui-grid-view.css' +import {ThemeContext, themes} from './themeContext' +import CustomCheckbox from './components/customCheckbox' +import FiltersContext from "./filtersContext" + +declare global { + interface Window { + _paq: any + } +} +const _paq = window._paq = window._paq || [] + +interface RemixUIGridViewProps { + plugin: any + logo?: string + title?: string + enableFilter?: boolean + tagList?: [string, string][] // max 8, others will be ignored + showUntagged?: boolean + showPin?: boolean + classList?: string + styleList?: any + description?: string + children?: ReactNode +} + +export const RemixUIGridView = (props: RemixUIGridViewProps) => { + const [keyValueMap, setKeyValueMap] = useState>({}); + + const showUntagged = props.showUntagged || false + const showPin = props.showPin || false + const updateValue = (key: string, enabled: boolean, color?: string) => { + if (!color || color === '') color = setKeyValueMap[key].color + setKeyValueMap((prevMap) => ({ + ...prevMap, + [key]: {color, enabled}, + })) + } + + const addValue = (key: string, enabled: boolean, color: string) => { + // Check if the key already exists, if so, do not add + if (key in keyValueMap) { + return + } + + // Add the new key-value pair + setKeyValueMap((prevMap) => ({ + ...prevMap, + [key]: { enabled, color }, + })) + } + + const {plugin} = props.plugin + const searchInputRef = useRef(null) + + const [state, setState] = useState<{ + themeQuality: {filter: string; name: string} + }>({ + themeQuality: themes.light + }) + + // Initialize filters context with data from props + useEffect(() => { + if (props.tagList && Array.isArray(props.tagList)) { + const initialKeyValueMap: Record = {}; + + // Limit to first 8 elements, ignoring the rest + for (let i = 0; i < props.tagList.length; i++) { + const [key, color] = props.tagList[i] + initialKeyValueMap[key] = { enabled: true, color } + } + if (showUntagged) initialKeyValueMap['no tag'] = { enabled: true, color: 'primary' } + setKeyValueMap(initialKeyValueMap) + } + }, []) + + useEffect(() => { + plugin?.call('theme', 'currentTheme').then((theme) => { + // update theme quality. To be used for for images + setState((prevState) => { + return { + ...prevState, + themeQuality: theme.quality === 'dark' ? themes.dark : themes.light + } + }) + }) + plugin?.on('theme', 'themeChanged', (theme) => { + // update theme quality. To be used for for images + setState((prevState) => { + return { + ...prevState, + themeQuality: theme.quality === 'dark' ? themes.dark : themes.light + } + }) + }) + }, [plugin]) + + return ( + +
+ +
+
+
+ { props.logo && } + { props.title &&

{ props.title }

} +
+ { props.description &&
{ props.description }
} + { props.enableFilter &&
+
+
+ + +
+
+ { Object.keys(keyValueMap).map((key) => ( + + )) } +
+
+
} +
+ { props.children } +
+
+
+
+ ) +} + +export default RemixUIGridView diff --git a/libs/remix-ui/grid-view/src/lib/themeContext.tsx b/libs/remix-ui/grid-view/src/lib/themeContext.tsx new file mode 100644 index 0000000000..fc67007dac --- /dev/null +++ b/libs/remix-ui/grid-view/src/lib/themeContext.tsx @@ -0,0 +1,16 @@ +import React from 'react' // eslint-disable-line + +export const themes = { + light: { + filter: 'invert(0)', + name: 'light' + }, + dark: { + filter: 'invert(1)', + name: 'dark' + } +} + +export const ThemeContext = React.createContext( + themes.dark // default value +) diff --git a/libs/remix-ui/home-tab/src/lib/components/homeTablangOptions.tsx b/libs/remix-ui/home-tab/src/lib/components/homeTablangOptions.tsx index 0b47e649b8..be69466d77 100644 --- a/libs/remix-ui/home-tab/src/lib/components/homeTablangOptions.tsx +++ b/libs/remix-ui/home-tab/src/lib/components/homeTablangOptions.tsx @@ -32,7 +32,7 @@ export function LanguageOptions({ plugin }: { plugin: any }) { {langOptions} - {['EN', 'ES', 'FR', 'IT', 'ZH'].map((lang, index) => ( + {['EN', 'ES', 'FR', 'IT', 'RU', 'ZH'].map((lang, index) => ( { changeLanguage(lang.toLowerCase()) 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 0198779612..3de9cdbc65 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 @@ -13,8 +13,6 @@ import { appPlatformTypes, platformContext } from '@remix-ui/app' import { HomeTabFileElectron } from './components/homeTabFileElectron' import { LanguageOptions } from './components/homeTablangOptions' - - declare global { interface Window { _paq: any diff --git a/libs/remix-ui/run-tab/src/lib/actions/account.ts b/libs/remix-ui/run-tab/src/lib/actions/account.ts index e210cfe48c..e1b121faf1 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/account.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/account.ts @@ -30,7 +30,7 @@ export const fillAccountsList = async (plugin: RunTab, dispatch: React.Dispatch< } const provider = plugin.blockchain.getProvider() - if (provider === 'injected') { + if (provider && provider.startsWith('injected')) { const selectedAddress = plugin.blockchain.getInjectedWeb3Address() if (!(Object.keys(loadedAccounts).includes(toChecksumAddress(selectedAddress)))) setAccount(dispatch, null) } diff --git a/libs/remix-ui/run-tab/src/lib/actions/actions.ts b/libs/remix-ui/run-tab/src/lib/actions/actions.ts index 127993af20..66d6cf496e 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/actions.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/actions.ts @@ -1,5 +1,5 @@ import { ContractData } from "@remix-project/core-plugin" -import { addNewInstance, addNewSavedInstance, addProvider, clearAllInstances, clearAllSavedInstances, clearRecorderCount, hidePopUp, newProxyDeployment, removeExistingInstance, removeProvider, setBaseFeePerGas, setConfirmSettings, setCurrentContract, setExecutionEnvironment, setExternalEndpoint, setGasLimit, setGasPrice, setGasPriceStatus, setMatchPassphrase, setMaxFee, setMaxPriorityFee, setNetworkName, setPassphrase, setPathToScenario, setSelectedAccount, setSendUnit, setSendValue } from "./payload" +import { addNewInstance, addNewPinnedInstance, addProvider, clearAllInstances, clearAllPinnedInstances, clearRecorderCount, hidePopUp, newProxyDeployment, removeExistingInstance, removeProvider, setBaseFeePerGas, setConfirmSettings, setCurrentContract, setExecutionEnvironment, setExternalEndpoint, setGasLimit, setGasPrice, setGasPriceStatus, setMatchPassphrase, setMaxFee, setMaxPriorityFee, setNetworkName, setChainId, setPassphrase, setPathToScenario, setSelectedAccount, setSendUnit, setSendValue } from "./payload" export const setAccount = (dispatch: React.Dispatch, account: string) => { dispatch(setSelectedAccount(account)) @@ -21,6 +21,10 @@ export const setNetworkNameFromProvider = (dispatch: React.Dispatch, networ dispatch(setNetworkName(networkName)) } +export const setPinnedChainId = (dispatch: React.Dispatch, chainId: string) => { + dispatch(setChainId(chainId)) +} + export const addExternalProvider = (dispatch: React.Dispatch, network) => { dispatch(addProvider(network)) } @@ -70,13 +74,13 @@ export const addInstance = (dispatch: React.Dispatch, instance: { contractD dispatch(addNewInstance(instance)) } -export const addSavedInstance = (dispatch: React.Dispatch, instance: { contractData?: ContractData, address: string, name: string, abi?: any, decodedResponse?: Record, savedOn?: number, filePath?: string }) => { +export const addPinnedInstance = (dispatch: React.Dispatch, instance: { contractData?: ContractData, address: string, name: string, abi?: any, decodedResponse?: Record, pinnedAt?: number, filePath?: string }) => { instance.decodedResponse = {} - dispatch(addNewSavedInstance(instance)) + dispatch(addNewPinnedInstance(instance)) } -export const removeInstance = (dispatch: React.Dispatch, index: number, isSavedContract: boolean, shouldDelete: boolean) => { - dispatch(removeExistingInstance(index, isSavedContract, shouldDelete)) +export const removeInstance = (dispatch: React.Dispatch, index: number, isPinnedContract: boolean, shouldDelete: boolean) => { + dispatch(removeExistingInstance(index, isPinnedContract, shouldDelete)) } export const clearInstances = (dispatch: React.Dispatch) => { @@ -84,8 +88,8 @@ export const clearInstances = (dispatch: React.Dispatch) => { dispatch(clearRecorderCount()) } -export const clearSavedInstances = (dispatch: React.Dispatch) => { - dispatch(clearAllSavedInstances()) +export const clearPinnedInstances = (dispatch: React.Dispatch) => { + dispatch(clearAllPinnedInstances()) dispatch(clearRecorderCount()) } diff --git a/libs/remix-ui/run-tab/src/lib/actions/deploy.ts b/libs/remix-ui/run-tab/src/lib/actions/deploy.ts index c6b3418a00..46a2183510 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/deploy.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/deploy.ts @@ -120,8 +120,11 @@ const getConfirmationCb = (plugin: RunTab, dispatch: React.Dispatch, confir export const continueHandler = (dispatch: React.Dispatch, gasEstimationPrompt: (msg: string) => JSX.Element, error, continueTxExecution, cancelCb) => { if (error) { let msg = typeof error !== 'string' ? error.message : error + if (error && error.innerError) { + msg += '\n' + error.innerError + } - if (msg.includes('invalid opcode')) msg += '\n OR the EVM version used by the selected environment is not compatible with the compiler EVM version.' + if (msg.includes('invalid opcode')) msg += '\nThe EVM version used by the selected environment is not compatible with the compiler EVM version.' dispatch(displayNotification('Gas estimation failed', gasEstimationPrompt(msg), 'Send Transaction', 'Cancel Transaction', () => { continueTxExecution() @@ -283,7 +286,7 @@ export const runTransactions = ( plugin: RunTab, dispatch: React.Dispatch, instanceIndex: number, - isSavedContract: boolean, + isPinnedContract: boolean, lookupOnly: boolean, funcABI: FuncABI, inputsValues: string, @@ -320,7 +323,7 @@ export const runTransactions = ( (returnValue) => { const response = txFormat.decodeResponse(returnValue, funcABI) - dispatch(setDecodedResponse(instanceIndex, response, funcIndex, isSavedContract)) + dispatch(setDecodedResponse(instanceIndex, response, funcIndex, isPinnedContract)) }, (network, tx, gasEstimation, continueTxExecution, cancelCb) => { confirmationHandler(plugin, dispatch, mainnetPrompt, network, tx, gasEstimation, continueTxExecution, cancelCb) @@ -339,8 +342,9 @@ export const getFuncABIInputs = (plugin: RunTab, funcABI: FuncABI) => { } export const updateInstanceBalance = async (plugin: RunTab, dispatch: React.Dispatch) => { - if (plugin.REACT_API?.instances?.instanceList?.length) { - const instances = plugin.REACT_API?.instances?.instanceList + if (plugin.REACT_API?.instances?.instanceList?.length || plugin.REACT_API?.pinnedInstances?.instanceList?.length) { + let instances = plugin.REACT_API?.instances?.instanceList?.length ? plugin.REACT_API?.instances?.instanceList : [] + instances = plugin.REACT_API?.pinnedInstances?.instanceList.length ? instances.concat(plugin.REACT_API.pinnedInstances.instanceList) : instances for (const instance of instances) { const balInEth = await plugin.blockchain.getBalanceInEther(instance.address) instance.balance = balInEth diff --git a/libs/remix-ui/run-tab/src/lib/actions/events.ts b/libs/remix-ui/run-tab/src/lib/actions/events.ts index ab2188847b..31120b4f5c 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/events.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/events.ts @@ -1,8 +1,8 @@ import { envChangeNotification } from "@remix-ui/helper" import { RunTab } from "../types/run-tab" import { setExecutionContext, setFinalContext, updateAccountBalances, fillAccountsList } from "./account" -import { addExternalProvider, addInstance, addSavedInstance, addNewProxyDeployment, removeExternalProvider, setNetworkNameFromProvider } from "./actions" -import { addDeployOption, clearAllInstances, clearAllSavedInstances, clearRecorderCount, fetchContractListSuccess, resetProxyDeployments, resetUdapp, setCurrentContract, setCurrentFile, setLoadType, setRecorderCount, setRemixDActivated, setSendValue, fetchAccountsListSuccess } from "./payload" +import { addExternalProvider, addInstance, addPinnedInstance, addNewProxyDeployment, removeExternalProvider, setNetworkNameFromProvider, setPinnedChainId } from "./actions" +import { addDeployOption, clearAllInstances, clearAllPinnedInstances, clearRecorderCount, fetchContractListSuccess, resetProxyDeployments, resetUdapp, setCurrentContract, setCurrentFile, setLoadType, setRecorderCount, setRemixDActivated, setSendValue, fetchAccountsListSuccess } from "./payload" import { updateInstanceBalance } from './deploy' import { CompilerAbstract } from '@remix-project/remix-solidity' import BN from 'bn.js' @@ -14,6 +14,13 @@ import { shortenAddress } from "@remix-ui/helper" const _paq = window._paq = window._paq || [] export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch) => { + // This maintains current network state and update the pinned contracts list, + // only when there is a change in provider or in chain id for same provider + // as 'networkStatus' is triggered in each 10 seconds + const currentNetwork = { + provider: null, + chainId: null + } plugin.blockchain.events.on('newTransaction', (tx, receipt) => { plugin.emit('newTransaction', tx, receipt) }) @@ -35,7 +42,7 @@ export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch) => { fillAccountsList(plugin, dispatch) }) - plugin.blockchain.event.register('networkStatus', ({ error, network }) => { + plugin.blockchain.event.register('networkStatus', async ({ error, network }) => { if (error) { const netUI = 'can\'t detect network' setNetworkNameFromProvider(dispatch, netUI) @@ -43,9 +50,18 @@ export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch) => { return } const networkProvider = plugin.networkModule.getNetworkProvider.bind(plugin.networkModule) - const netUI = !networkProvider().startsWith('vm') ? `${network.name} (${network.id || '-'}) network` : 'VM' - + const isVM = networkProvider().startsWith('vm') ? true : false + const netUI = !isVM ? `${network.name} (${network.id || '-'}) network` : 'VM' + const pinnedChainId = !isVM ? network.id : networkProvider() setNetworkNameFromProvider(dispatch, netUI) + setPinnedChainId(dispatch, pinnedChainId) + + // Check if provider is changed or network is changed for same provider e.g; Metamask + if (currentNetwork.provider !== networkProvider() || (!isVM && currentNetwork.chainId !== network.id)) { + currentNetwork.provider = networkProvider() + if (!isVM) currentNetwork.chainId = network.id + await loadPinnedContracts(plugin, dispatch, pinnedChainId) + } }) plugin.blockchain.event.register('addProvider', provider => addExternalProvider(dispatch, provider)) @@ -79,29 +95,50 @@ export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch) => { dispatch(clearAllInstances()) }) - plugin.on('udapp', 'clearAllSavedInstancesReducer', () => { - dispatch(clearAllSavedInstances()) + plugin.on('udapp', 'clearAllPinnedInstancesReducer', () => { + dispatch(clearAllPinnedInstances()) }) plugin.on('udapp', 'addInstanceReducer', (address, abi, name, contractData?) => { addInstance(dispatch, { contractData, abi, address, name }) }) - plugin.on('udapp', 'addSavedInstanceReducer', (address, abi, name, savedOn, filePath) => { - addSavedInstance(dispatch, { abi, address, name, savedOn, filePath}) + plugin.on('udapp', 'addPinnedInstanceReducer', (address, abi, name, pinnedAt, filePath) => { + addPinnedInstance(dispatch, { abi, address, name, pinnedAt, filePath}) }) - plugin.on('filePanel', 'setWorkspace', () => { + plugin.on('filePanel', 'setWorkspace', async () => { dispatch(resetUdapp()) resetAndInit(plugin) + await migrateSavedContracts(plugin) plugin.call('manager', 'isActive', 'remixd').then((activated) => { dispatch(setRemixDActivated(activated)) }) }) - plugin.on('manager', 'pluginActivated', (plugin: Plugin) => { - if (plugin.name === 'remixd') { + plugin.on('manager', 'pluginActivated', (activatedPlugin: Plugin) => { + if (activatedPlugin.name === 'remixd') { dispatch(setRemixDActivated(true)) + } else { + if (activatedPlugin && activatedPlugin.name.startsWith('injected')) { + plugin.on(activatedPlugin.name, 'accountsChanged', (accounts: Array) => { + const accountsMap = {} + accounts.map(account => { accountsMap[account] = shortenAddress(account, '0')}) + dispatch(fetchAccountsListSuccess(accountsMap)) + }) + } else if (activatedPlugin && activatedPlugin.name === 'walletconnect') { + plugin.on('walletconnect', 'accountsChanged', async (accounts: Array) => { + const accountsMap = {} + + await Promise.all(accounts.map(async (account) => { + const balance = await plugin.blockchain.getBalanceInEther(account) + const updated = shortenAddress(account, balance) + + accountsMap[account] = updated + })) + dispatch(fetchAccountsListSuccess(accountsMap)) + }) + } } }) @@ -133,29 +170,6 @@ export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch) => { dispatch(clearRecorderCount()) }) - plugin.on('injected', 'accountsChanged', (accounts: Array) => { - const accountsMap = {} - accounts.map(account => { accountsMap[account] = shortenAddress(account, '0')}) - dispatch(fetchAccountsListSuccess(accountsMap)) - }) - - plugin.on('injected-trustwallet', 'accountsChanged', (accounts: Array) => { - const accountsMap = {} - accounts.map(account => { accountsMap[account] = shortenAddress(account, '0')}) - dispatch(fetchAccountsListSuccess(accountsMap)) - }) - - plugin.on('walletconnect', 'accountsChanged', async (accounts: Array) => { - const accountsMap = {} - - await Promise.all(accounts.map(async (account) => { - const balance = await plugin.blockchain.getBalanceInEther(account) - const updated = shortenAddress(account, balance) - - accountsMap[account] = updated - })) - dispatch(fetchAccountsListSuccess(accountsMap)) - }) setInterval(() => { fillAccountsList(plugin, dispatch) @@ -163,6 +177,47 @@ export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch) => { }, 30000) } +const loadPinnedContracts = async (plugin, dispatch, dirName) => { + await plugin.call('udapp', 'clearAllPinnedInstances') + const isPinnedAvailable = await plugin.call('fileManager', 'exists', `.deploys/pinned-contracts/${dirName}`) + if (isPinnedAvailable) { + try { + const list = await plugin.call('fileManager', 'readdir', `.deploys/pinned-contracts/${dirName}`) + const filePaths = Object.keys(list) + for (const file of filePaths) { + const pinnedContract = await plugin.call('fileManager', 'readFile', file) + const pinnedContractObj = JSON.parse(pinnedContract) + if (pinnedContractObj) addPinnedInstance(dispatch, pinnedContractObj) + } + } catch(err) { + console.log(err) + } + } +} + +const migrateSavedContracts = async (plugin) => { + // Move contract saved in localstorage to Remix FE + const allSavedContracts = localStorage.getItem('savedContracts') + if (allSavedContracts) { + const savedContracts = JSON.parse(allSavedContracts) + for (const networkId in savedContracts) { + if (savedContracts[networkId].length > 0) { + for (const contractDetails of savedContracts[networkId]) { + const objToSave = { + name: contractDetails.name, + address: contractDetails.address, + abi: contractDetails.abi || contractDetails.contractData.abi, + filePath: contractDetails.filePath, + pinnedAt: contractDetails.savedOn + } + await plugin.call('fileManager', 'writeFile', `.deploys/pinned-contracts/${networkId}/${contractDetails.address}.json`, JSON.stringify(objToSave, null, 2)) + } + } + } + localStorage.removeItem('savedContracts') + } +} + const broadcastCompilationResult = async (compilerName: string, plugin: RunTab, dispatch: React.Dispatch, file, source, languageVersion, data, input?) => { _paq.push(['trackEvent', 'udapp', 'broadcastCompilationResult', compilerName]) // TODO check whether the tab is configured diff --git a/libs/remix-ui/run-tab/src/lib/actions/index.ts b/libs/remix-ui/run-tab/src/lib/actions/index.ts index 7c40c0f65a..41ac1012d0 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/index.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/index.ts @@ -48,9 +48,9 @@ export const setGasPriceStatus = (status: boolean) => updateGasPriceStatus(dispa export const setMaxFee = (fee: string) => updateMaxFee(dispatch, fee) export const setMaxPriorityFee = (fee: string) => updateMaxPriorityFee(dispatch, fee) export const removeInstances = () => clearInstances(dispatch) -export const removeSingleInstance = (index: number, isSavedContract: boolean, shouldDelete: boolean) => removeInstance(dispatch, index, isSavedContract, shouldDelete) +export const removeSingleInstance = (index: number, isPinnedContract: boolean, shouldDelete: boolean) => removeInstance(dispatch, index, isPinnedContract, shouldDelete) export const getExecutionContext = () => getContext(plugin) -export const executeTransactions = (instanceIndex: number, isSavedContract: boolean, lookupOnly: boolean, funcABI: FuncABI, inputsValues: string, contractName: string, contractABI, contract, address, logMsg:string, mainnetPrompt: MainnetPrompt, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, funcIndex?: number) => runTransactions(plugin, dispatch, instanceIndex, isSavedContract, lookupOnly, funcABI, inputsValues, contractName, contractABI, contract, address, logMsg, mainnetPrompt, gasEstimationPrompt, passphrasePrompt, funcIndex) +export const executeTransactions = (instanceIndex: number, isPinnedContract: boolean, lookupOnly: boolean, funcABI: FuncABI, inputsValues: string, contractName: string, contractABI, contract, address, logMsg:string, mainnetPrompt: MainnetPrompt, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, funcIndex?: number) => runTransactions(plugin, dispatch, instanceIndex, isPinnedContract, lookupOnly, funcABI, inputsValues, contractName, contractABI, contract, address, logMsg, mainnetPrompt, gasEstimationPrompt, passphrasePrompt, funcIndex) export const loadFromAddress = (contract: ContractData, address: string) => loadAddress(plugin, dispatch, contract, address) export const storeNewScenario = async (prompt: (msg: string, defaultValue: string) => JSX.Element) => storeScenario(plugin, dispatch, prompt) export const runScenario = (liveMode: boolean, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, confirmDialogContent: MainnetPrompt) => runCurrentScenario(liveMode, plugin, dispatch, gasEstimationPrompt, passphrasePrompt, confirmDialogContent) diff --git a/libs/remix-ui/run-tab/src/lib/actions/payload.ts b/libs/remix-ui/run-tab/src/lib/actions/payload.ts index 8d2e9a8366..fdd794e857 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/payload.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/payload.ts @@ -1,5 +1,5 @@ import { ContractData } from '@remix-project/core-plugin' -import { ADD_DEPLOY_OPTION, ADD_INSTANCE, ADD_SAVED_INSTANCE, UPDATE_INSTANCES_BALANCE, ADD_PROVIDER, CLEAR_INSTANCES, CLEAR_SAVED_INSTANCES, CLEAR_RECORDER_COUNT, DISPLAY_NOTIFICATION, DISPLAY_POPUP_MESSAGE, FETCH_ACCOUNTS_LIST_FAILED, FETCH_ACCOUNTS_LIST_REQUEST, FETCH_ACCOUNTS_LIST_SUCCESS, FETCH_CONTRACT_LIST_FAILED, FETCH_CONTRACT_LIST_REQUEST, FETCH_CONTRACT_LIST_SUCCESS, HIDE_NOTIFICATION, HIDE_POPUP_MESSAGE, REMOVE_DEPLOY_OPTION, REMOVE_INSTANCE, REMOVE_PROVIDER, RESET_STATE, SET_BASE_FEE_PER_GAS, SET_CONFIRM_SETTINGS, SET_CURRENT_CONTRACT, SET_CURRENT_FILE, SET_DECODED_RESPONSE, SET_DEPLOY_OPTIONS, SET_EXECUTION_ENVIRONMENT, SET_EXTERNAL_WEB3_ENDPOINT, SET_GAS_LIMIT, SET_GAS_PRICE, SET_GAS_PRICE_STATUS, SET_IPFS_CHECKED_STATE, SET_LOAD_TYPE, SET_MATCH_PASSPHRASE, SET_MAX_FEE, SET_MAX_PRIORITY_FEE, SET_NETWORK_NAME, SET_PASSPHRASE, SET_PATH_TO_SCENARIO, SET_PERSONAL_MODE, SET_RECORDER_COUNT, SET_SELECTED_ACCOUNT, SET_SEND_UNIT, SET_SEND_VALUE, SET_REMIXD_ACTIVATED, FETCH_PROXY_DEPLOYMENTS, NEW_PROXY_DEPLOYMENT, RESET_PROXY_DEPLOYMENTS, EXTRACT_COMPILER_VERSION } from '../constants' +import { ADD_DEPLOY_OPTION, ADD_INSTANCE, ADD_PINNED_INSTANCE, UPDATE_INSTANCES_BALANCE, ADD_PROVIDER, CLEAR_INSTANCES, CLEAR_PINNED_INSTANCES, CLEAR_RECORDER_COUNT, DISPLAY_NOTIFICATION, DISPLAY_POPUP_MESSAGE, FETCH_ACCOUNTS_LIST_FAILED, FETCH_ACCOUNTS_LIST_REQUEST, FETCH_ACCOUNTS_LIST_SUCCESS, FETCH_CONTRACT_LIST_FAILED, FETCH_CONTRACT_LIST_REQUEST, FETCH_CONTRACT_LIST_SUCCESS, HIDE_NOTIFICATION, HIDE_POPUP_MESSAGE, REMOVE_DEPLOY_OPTION, REMOVE_INSTANCE, REMOVE_PROVIDER, RESET_STATE, SET_BASE_FEE_PER_GAS, SET_CONFIRM_SETTINGS, SET_CURRENT_CONTRACT, SET_CURRENT_FILE, SET_DECODED_RESPONSE, SET_DEPLOY_OPTIONS, SET_EXECUTION_ENVIRONMENT, SET_CHAIN_ID, SET_EXTERNAL_WEB3_ENDPOINT, SET_GAS_LIMIT, SET_GAS_PRICE, SET_GAS_PRICE_STATUS, SET_IPFS_CHECKED_STATE, SET_LOAD_TYPE, SET_MATCH_PASSPHRASE, SET_MAX_FEE, SET_MAX_PRIORITY_FEE, SET_NETWORK_NAME, SET_PASSPHRASE, SET_PATH_TO_SCENARIO, SET_PERSONAL_MODE, SET_RECORDER_COUNT, SET_SELECTED_ACCOUNT, SET_SEND_UNIT, SET_SEND_VALUE, SET_REMIXD_ACTIVATED, FETCH_PROXY_DEPLOYMENTS, NEW_PROXY_DEPLOYMENT, RESET_PROXY_DEPLOYMENTS, EXTRACT_COMPILER_VERSION } from '../constants' import { ContractList, DeployOptions } from '../types' export const fetchAccountsListRequest = () => { @@ -72,6 +72,13 @@ export const setNetworkName = (networkName: string) => { } } +export const setChainId = (chainId: string) => { + return { + type: SET_CHAIN_ID, + payload: chainId + } +} + export const addProvider = (provider: string) => { return { type: ADD_PROVIDER, @@ -230,19 +237,19 @@ export const addNewInstance = (instance: { contractData?: ContractData, address: } } -export const addNewSavedInstance = (instance: { contractData?: ContractData, address: string, name: string, abi?: any, savedOn?: number }) => { +export const addNewPinnedInstance = (instance: { contractData?: ContractData, address: string, name: string, abi?: any, pinnedAt?: number }) => { return { - type: ADD_SAVED_INSTANCE, + type: ADD_PINNED_INSTANCE, payload: instance } } -export const removeExistingInstance = (index: number, isSavedContract: boolean, shouldDelete: boolean) => { +export const removeExistingInstance = (index: number, isPinnedContract: boolean, shouldDelete: boolean) => { return { type: REMOVE_INSTANCE, payload: { index, - isSavedContract, + isPinnedContract, shouldDelete } } @@ -254,20 +261,20 @@ export const clearAllInstances = () => { } } -export const clearAllSavedInstances = () => { +export const clearAllPinnedInstances = () => { return { - type: CLEAR_SAVED_INSTANCES + type: CLEAR_PINNED_INSTANCES } } -export const setDecodedResponse = (instanceIndex: number, response, funcIndex?: number, isSavedContract?: boolean) => { +export const setDecodedResponse = (instanceIndex: number, response, funcIndex?: number, isPinnedContract?: boolean) => { return { type: SET_DECODED_RESPONSE, payload: { instanceIndex, funcIndex, response, - isSavedContract + isPinnedContract } } } diff --git a/libs/remix-ui/run-tab/src/lib/components/account.tsx b/libs/remix-ui/run-tab/src/lib/components/account.tsx index d1ab6b5552..21b0d67db4 100644 --- a/libs/remix-ui/run-tab/src/lib/components/account.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/account.tsx @@ -26,62 +26,69 @@ export function AccountUI(props: AccountProps) { useEffect(() => { props.setAccount('') - switch (selectExEnv) { - case 'injected': + if (selectExEnv && selectExEnv.startsWith('injected')) { setPlusOpt({ classList: 'udapp_disableMouseEvents', title: intl.formatMessage({id: 'udapp.injectedTitle'}) }) - break - - case 'vm-paris': - setPlusOpt({ - classList: '', - title: intl.formatMessage({id: 'udapp.createNewAccount'}) - }) - break - - case 'vm-london': - setPlusOpt({ - classList: '', - title: intl.formatMessage({id: 'udapp.createNewAccount'}) - }) - break - - case 'vm-berlin': - setPlusOpt({ - classList: '', - title: intl.formatMessage({id: 'udapp.createNewAccount'}) - }) - break - - case 'vm-shanghai': - setPlusOpt({ - classList: '', - title: intl.formatMessage({id: 'udapp.createNewAccount'}) - }) - break - - case 'web3': - if (!personalMode) { + } else { + switch (selectExEnv) { + case 'vm-cancun': setPlusOpt({ - classList: 'disableMouseEvents', - title: intl.formatMessage({id: 'udapp.web3Title'}) + classList: '', + title: intl.formatMessage({id: 'udapp.createNewAccount'}) + }) + break + + case 'vm-paris': + setPlusOpt({ + classList: '', + title: intl.formatMessage({id: 'udapp.createNewAccount'}) + }) + break + + case 'vm-london': + setPlusOpt({ + classList: '', + title: intl.formatMessage({id: 'udapp.createNewAccount'}) + }) + break + + case 'vm-berlin': + setPlusOpt({ + classList: '', + title: intl.formatMessage({id: 'udapp.createNewAccount'}) }) - } else { + break + + case 'vm-shanghai': setPlusOpt({ classList: '', title: intl.formatMessage({id: 'udapp.createNewAccount'}) }) + break + + case 'web3': + if (!personalMode) { + setPlusOpt({ + classList: 'disableMouseEvents', + title: intl.formatMessage({id: 'udapp.web3Title'}) + }) + } else { + setPlusOpt({ + classList: '', + title: intl.formatMessage({id: 'udapp.createNewAccount'}) + }) + } + break + + default: + setPlusOpt({ + classList: 'disableMouseEvents', + title: intl.formatMessage({id: 'udapp.defaultTitle'}, {selectExEnv}) + }) } - break - - default: - setPlusOpt({ - classList: 'disableMouseEvents', - title: intl.formatMessage({id: 'udapp.defaultTitle'}, {selectExEnv}) - }) - } + } }, [selectExEnv, personalMode]) const newAccount = () => { diff --git a/libs/remix-ui/run-tab/src/lib/components/environment.tsx b/libs/remix-ui/run-tab/src/lib/components/environment.tsx index 04ba57383d..5f72f4bfeb 100644 --- a/libs/remix-ui/run-tab/src/lib/components/environment.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/environment.tsx @@ -1,24 +1,24 @@ // eslint-disable-next-line no-use-before-define import React from 'react' import {FormattedMessage} from 'react-intl' -import {EnvironmentProps} from '../types' +import {EnvironmentProps, Provider} from '../types' import {Dropdown} from 'react-bootstrap' import {CustomMenu, CustomToggle, CustomTooltip} from '@remix-ui/helper' export function EnvironmentUI(props: EnvironmentProps) { const handleChangeExEnv = (env: string) => { - const provider = props.providers.providerList.find((exEnv) => exEnv.value === env) - const context = provider.value + const provider = props.providers.providerList.find((exEnv) => exEnv.name === env) + const context = provider.name props.setExecutionContext({context}) } - const currentProvider = props.providers.providerList.find((exEnv) => exEnv.value === props.selectedEnv) + const currentProvider = props.providers.providerList.find((exEnv) => exEnv.name === props.selectedEnv) const bridges = { - 'injected-optimism-provider': 'https://app.optimism.io/bridge/deposit', - 'injected-arbitrum-one-provider': 'https://bridge.arbitrum.io/' + 'L2 - Optimism': 'https://app.optimism.io/bridge/deposit', + 'L2 - Arbitrum One': 'https://bridge.arbitrum.io/' } - const isL2 = (provider) => provider && (provider.value === 'Optimism Provider' || provider.value === 'Arbitrum One Provider') + const isL2 = (providerDisplayName: string) => providerDisplayName === 'Optimism Provider' || providerDisplayName === 'Arbitrum One Provider' return (