git4refactor
filip mertens 7 months ago
commit f8a72e6043
  1. 2
      .github/workflows/pr-reminder.yml
  2. 4
      apps/etherscan/src/app/utils/networks.ts
  3. 74
      apps/remix-ide-e2e/src/commands/addFileSnekmate.ts
  4. 16
      apps/remix-ide-e2e/src/commands/openFile.ts
  5. 22
      apps/remix-ide-e2e/src/commands/selectFiles.ts
  6. 27
      apps/remix-ide-e2e/src/tests/file_explorer_multiselect.test.ts
  7. 60
      apps/remix-ide-e2e/src/tests/pinned_contracts.test.ts
  8. 4
      apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts
  9. 3
      apps/remix-ide-e2e/src/tests/transactionExecution.test.ts
  10. 54
      apps/remix-ide-e2e/src/tests/vyper_api.test.ts
  11. 11
      apps/remix-ide-e2e/src/tests/workspace.test.ts
  12. 2
      apps/remix-ide-e2e/src/types/index.d.ts
  13. 6
      apps/remix-ide/src/app.js
  14. 244
      apps/remix-ide/src/app/plugins/remixGuide.tsx
  15. 4
      apps/remix-ide/src/app/plugins/solcoderAI.tsx
  16. 2
      apps/remix-ide/src/app/providers/abstract-provider.tsx
  17. 41
      apps/remix-ide/src/app/providers/injected-custom-provider.tsx
  18. 2
      apps/remix-ide/src/app/providers/injected-provider-default.tsx
  19. 2
      apps/remix-ide/src/app/tabs/locale-module.js
  20. 2
      apps/remix-ide/src/app/tabs/locales/en/filePanel.json
  21. 4
      apps/remix-ide/src/app/tabs/locales/en/udapp.json
  22. 15
      apps/remix-ide/src/app/tabs/locales/ru/circuit.json
  23. 26
      apps/remix-ide/src/app/tabs/locales/ru/debugger.json
  24. 134
      apps/remix-ide/src/app/tabs/locales/ru/filePanel.json
  25. 69
      apps/remix-ide/src/app/tabs/locales/ru/home.json
  26. 17
      apps/remix-ide/src/app/tabs/locales/ru/index.js
  27. 10
      apps/remix-ide/src/app/tabs/locales/ru/panel.json
  28. 13
      apps/remix-ide/src/app/tabs/locales/ru/permissionHandler.json
  29. 43
      apps/remix-ide/src/app/tabs/locales/ru/pluginManager.json
  30. 3
      apps/remix-ide/src/app/tabs/locales/ru/remixApp.json
  31. 7
      apps/remix-ide/src/app/tabs/locales/ru/remixUiTabs.json
  32. 24
      apps/remix-ide/src/app/tabs/locales/ru/search.json
  33. 44
      apps/remix-ide/src/app/tabs/locales/ru/settings.json
  34. 81
      apps/remix-ide/src/app/tabs/locales/ru/solidity.json
  35. 41
      apps/remix-ide/src/app/tabs/locales/ru/solidityUnitTesting.json
  36. 43
      apps/remix-ide/src/app/tabs/locales/ru/terminal.json
  37. 139
      apps/remix-ide/src/app/tabs/locales/ru/udapp.json
  38. 86
      apps/remix-ide/src/app/udapp/run-tab.js
  39. 13
      apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css
  40. 15
      apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css
  41. 13
      apps/remix-ide/src/assets/css/themes/bootstrap-flatly.min.css
  42. 13
      apps/remix-ide/src/assets/css/themes/bootstrap-spacelab.min.css
  43. 3
      apps/remix-ide/src/assets/css/themes/remix-black_undtds.css
  44. 14
      apps/remix-ide/src/assets/css/themes/remix-candy_ikhg4m.css
  45. 3
      apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css
  46. 3
      apps/remix-ide/src/assets/css/themes/remix-hacker_owl.css
  47. 12
      apps/remix-ide/src/assets/css/themes/remix-light_powaqg.css
  48. 12
      apps/remix-ide/src/assets/css/themes/remix-midcentury_hrzph3.css
  49. 12
      apps/remix-ide/src/assets/css/themes/remix-unicorn.css
  50. 12
      apps/remix-ide/src/assets/css/themes/remix-violet.css
  51. 49
      apps/remix-ide/src/blockchain/blockchain.tsx
  52. 4
      apps/remix-ide/src/blockchain/providers/injected.ts
  53. 4
      apps/remix-ide/src/blockchain/providers/node.ts
  54. 6
      apps/remix-ide/src/blockchain/providers/vm.ts
  55. 32
      apps/remix-ide/src/remixAppManager.js
  56. 4
      apps/vyper/src/app/app.tsx
  57. 8
      apps/vyper/src/app/utils/compiler.tsx
  58. 8
      apps/vyper/src/app/utils/remix-client.tsx
  59. 8
      libs/ghaction-helper/package.json
  60. 8
      libs/remix-analyzer/package.json
  61. 6
      libs/remix-astwalker/package.json
  62. 12
      libs/remix-debug/package.json
  63. 4
      libs/remix-lib/package.json
  64. 2
      libs/remix-lib/src/execution/txExecution.ts
  65. 19
      libs/remix-lib/src/execution/txRunnerWeb3.ts
  66. 6
      libs/remix-simulator/package.json
  67. 6
      libs/remix-solidity/package.json
  68. 10
      libs/remix-tests/package.json
  69. 2
      libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx
  70. 7
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
  71. 4
      libs/remix-ui/grid-view/src/index.ts
  72. 42
      libs/remix-ui/grid-view/src/lib/components/customCheckbox.tsx
  73. 18
      libs/remix-ui/grid-view/src/lib/filtersContext.tsx
  74. 46
      libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.css
  75. 86
      libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.tsx
  76. 26
      libs/remix-ui/grid-view/src/lib/remix-ui-grid-section.css
  77. 38
      libs/remix-ui/grid-view/src/lib/remix-ui-grid-section.tsx
  78. 25
      libs/remix-ui/grid-view/src/lib/remix-ui-grid-view.css
  79. 147
      libs/remix-ui/grid-view/src/lib/remix-ui-grid-view.tsx
  80. 16
      libs/remix-ui/grid-view/src/lib/themeContext.tsx
  81. 2
      libs/remix-ui/home-tab/src/lib/components/homeTablangOptions.tsx
  82. 2
      libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx
  83. 2
      libs/remix-ui/run-tab/src/lib/actions/account.ts
  84. 5
      libs/remix-ui/run-tab/src/lib/actions/deploy.ts
  85. 71
      libs/remix-ui/run-tab/src/lib/actions/events.ts
  86. 104
      libs/remix-ui/run-tab/src/lib/components/account.tsx
  87. 32
      libs/remix-ui/run-tab/src/lib/components/environment.tsx
  88. 82
      libs/remix-ui/run-tab/src/lib/components/gasLimit.tsx
  89. 22
      libs/remix-ui/run-tab/src/lib/components/gasPrice.tsx
  90. 4
      libs/remix-ui/run-tab/src/lib/components/settingsUI.tsx
  91. 2
      libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx
  92. 1
      libs/remix-ui/run-tab/src/lib/css/run-tab.css
  93. 48
      libs/remix-ui/run-tab/src/lib/reducers/runTab.ts
  94. 2
      libs/remix-ui/run-tab/src/lib/types/blockchain.d.ts
  95. 44
      libs/remix-ui/run-tab/src/lib/types/index.ts
  96. 1
      libs/remix-ui/run-tab/src/lib/types/injected.d.ts
  97. 1
      libs/remix-ui/run-tab/src/lib/types/node.d.ts
  98. 1
      libs/remix-ui/run-tab/src/lib/types/vm.d.ts
  99. 2
      libs/remix-ui/static-analyser/src/staticanalyser.d.ts
  100. 10
      libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx
  101. Some files were not shown because too many files have changed in this diff Show More

@ -14,4 +14,4 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
freeze-date: '2024-04-22T18:00:00Z' freeze-date: '2024-05-06T18:00:00Z'

@ -17,9 +17,10 @@ export const scanAPIurls = {
1101: 'https://api-zkevm.polygonscan.com/api', 1101: 'https://api-zkevm.polygonscan.com/api',
59144: 'https://api.lineascan.build/api', 59144: 'https://api.lineascan.build/api',
8453: 'https://api.basescan.org/api', 8453: 'https://api.basescan.org/api',
534352: 'https://api.scrollscan.com/api',
// all testnet // all testnet
5: 'https://api-goerli.etherscan.io/api', 17000: 'https://api-holesky.etherscan.io/api',
11155111: 'https://api-sepolia.etherscan.io/api', 11155111: 'https://api-sepolia.etherscan.io/api',
97: 'https://api-testnet.bscscan.com/api', 97: 'https://api-testnet.bscscan.com/api',
80001: 'https://api-testnet.polygonscan.com/api', 80001: 'https://api-testnet.polygonscan.com/api',
@ -37,4 +38,5 @@ export const scanAPIurls = {
84532: "https://api-sepolia.basescan.org/api", 84532: "https://api-sepolia.basescan.org/api",
1442: 'https://api-testnet-zkevm.polygonscan.com/api', 1442: 'https://api-testnet-zkevm.polygonscan.com/api',
59140: 'https://api-testnet.lineascan.build/api', 59140: 'https://api-testnet.lineascan.build/api',
534351: 'https://api-sepolia.scrollscan.com/api',
} }

@ -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

@ -31,15 +31,15 @@ function openFile (browser: NightwatchBrowser, name: string, done: VoidFunction)
done() 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 module.exports = OpenFile

@ -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

@ -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()
}
}

@ -29,7 +29,7 @@ module.exports = {
.assert.textContains('*[data-id="deployAndRunNoInstanceText"]', 'Currently you have no unpinned contracts to interact with.') .assert.textContains('*[data-id="deployAndRunNoInstanceText"]', 'Currently you have no unpinned contracts to interact with.')
.assert.not.elementPresent('*[data-id="NoPinnedInstanceText"]') .assert.not.elementPresent('*[data-id="NoPinnedInstanceText"]')
.assert.elementPresent('*[data-id="pinnedInstance0xd9145CCE52D386f254917e481eB44e9943F39138"]') .assert.elementPresent('*[data-id="pinnedInstance0xd9145CCE52D386f254917e481eB44e9943F39138"]')
}, },
'Test pinned contract loading on environment change #group1': function (browser: NightwatchBrowser) { 'Test pinned contract loading on environment change #group1': function (browser: NightwatchBrowser) {
browser browser
.switchEnvironment('vm-shanghai') .switchEnvironment('vm-shanghai')
@ -41,7 +41,7 @@ module.exports = {
.assert.textContains('*[data-id="pinnedContractsSublabel"]', '(network: vm-cancun)') .assert.textContains('*[data-id="pinnedContractsSublabel"]', '(network: vm-cancun)')
.assert.not.elementPresent('*[data-id="NoPinnedInstanceText"]') .assert.not.elementPresent('*[data-id="NoPinnedInstanceText"]')
.assert.elementPresent('*[data-id="pinnedInstance0xd9145CCE52D386f254917e481eB44e9943F39138"]') .assert.elementPresent('*[data-id="pinnedInstance0xd9145CCE52D386f254917e481eB44e9943F39138"]')
}, },
'Interact with pinned contract #group1': function (browser: NightwatchBrowser) { 'Interact with pinned contract #group1': function (browser: NightwatchBrowser) {
browser browser
.click('*[data-id="universalDappUiTitleExpander0"]') .click('*[data-id="universalDappUiTitleExpander0"]')
@ -51,23 +51,23 @@ module.exports = {
.assert.textContains('*[data-id="instanceContractFilePath"]', 'default_workspace/contracts/1_Storage.sol') .assert.textContains('*[data-id="instanceContractFilePath"]', 'default_workspace/contracts/1_Storage.sol')
.clickFunction('retrieve - call') .clickFunction('retrieve - call')
.testFunction('last', .testFunction('last',
{ {
to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138', to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138',
'decoded output': { "0": "uint256: 0" } 'decoded output': { "0": "uint256: 0" }
}) })
.clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '35' }) .clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '35' })
.testFunction('last', .testFunction('last',
{ {
status: '0x1 Transaction mined and execution succeed', status: '0x1 Transaction mined and execution succeed',
'decoded input': { "uint256 num": "35" } 'decoded input': { "uint256 num": "35" }
}) })
.clickFunction('retrieve - call') .clickFunction('retrieve - call')
.testFunction('last', .testFunction('last',
{ {
to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138', to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138',
'decoded output': { "0": "uint256: 35" } 'decoded output': { "0": "uint256: 35" }
}) })
}, },
'Unpin & interact #group1': function (browser: NightwatchBrowser) { 'Unpin & interact #group1': function (browser: NightwatchBrowser) {
browser browser
.click('*[data-id="universalDappUiUdappUnpin"]') .click('*[data-id="universalDappUiUdappUnpin"]')
@ -78,23 +78,23 @@ module.exports = {
.assert.not.elementPresent('*[data-id="instanceContractFilePath"]') .assert.not.elementPresent('*[data-id="instanceContractFilePath"]')
.clickFunction('retrieve - call') .clickFunction('retrieve - call')
.testFunction('last', .testFunction('last',
{ {
to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138', to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138',
'decoded output': { "0": "uint256: 35" } 'decoded output': { "0": "uint256: 35" }
}) })
.clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '55' }) .clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '55' })
.testFunction('last', .testFunction('last',
{ {
status: '0x1 Transaction mined and execution succeed', status: '0x1 Transaction mined and execution succeed',
'decoded input': { "uint256 num": "55" } 'decoded input': { "uint256 num": "55" }
}) })
.clickFunction('retrieve - call') .clickFunction('retrieve - call')
.testFunction('last', .testFunction('last',
{ {
to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138', to: 'Storage.retrieve() 0xd9145CCE52D386f254917e481eB44e9943F39138',
'decoded output': { "0": "uint256: 55" } 'decoded output': { "0": "uint256: 55" }
}) })
}, },
'Re-pin & delete immediately #group1': function (browser: NightwatchBrowser) { 'Re-pin & delete immediately #group1': function (browser: NightwatchBrowser) {
browser browser
.click('*[data-id="universalDappUiUdappPin"]') .click('*[data-id="universalDappUiUdappPin"]')
@ -102,5 +102,5 @@ module.exports = {
.click('*[data-id="universalDappUiUdappDelete"]') .click('*[data-id="universalDappUiUdappDelete"]')
.assert.textContains('*[data-id="NoPinnedInstanceText"]', 'No pinned contracts found for selected workspace & network') .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.') .assert.textContains('*[data-id="deployAndRunNoInstanceText"]', 'Currently you have no unpinned contracts to interact with.')
}, },
} }

@ -44,7 +44,7 @@ module.exports = {
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.click('*[data-id="landingPageStartSolidity"]') .click('*[data-id="landingPageStartSolidity"]')
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.switchEnvironment('MetaMask') .switchEnvironment('injected-MetaMask')
.waitForElementPresent('*[data-id="settingsNetworkEnv"]') .waitForElementPresent('*[data-id="settingsNetworkEnv"]')
.assert.containsText('*[data-id="settingsNetworkEnv"]', 'Sepolia (11155111) network') .assert.containsText('*[data-id="settingsNetworkEnv"]', 'Sepolia (11155111) network')
.pause(5000) .pause(5000)
@ -123,7 +123,7 @@ module.exports = {
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.click('*[data-id="landingPageStartSolidity"]') .click('*[data-id="landingPageStartSolidity"]')
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.switchEnvironment('MetaMask') .switchEnvironment('injected-MetaMask')
.waitForElementPresent('*[data-id="settingsNetworkEnv"]') .waitForElementPresent('*[data-id="settingsNetworkEnv"]')
.assert.containsText('*[data-id="settingsNetworkEnv"]', 'Main (1) network') .assert.containsText('*[data-id="settingsNetworkEnv"]', 'Main (1) network')
}, },

@ -174,7 +174,6 @@ module.exports = {
.journalLastChildIncludes('"documentation": "param1"') .journalLastChildIncludes('"documentation": "param1"')
.journalLastChildIncludes('"documentation": "param2"') .journalLastChildIncludes('"documentation": "param2"')
.journalLastChildIncludes('"documentation": "param3"') .journalLastChildIncludes('"documentation": "param3"')
.journalLastChildIncludes('Debug the transaction to get more information.')
.click('*[data-id="deployAndRunClearInstances"]') .click('*[data-id="deployAndRunClearInstances"]')
}, },
@ -198,7 +197,6 @@ module.exports = {
.journalLastChildIncludes('"documentation": "param1"') .journalLastChildIncludes('"documentation": "param1"')
.journalLastChildIncludes('"documentation": "param2"') .journalLastChildIncludes('"documentation": "param2"')
.journalLastChildIncludes('"documentation": "param3"') .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) { '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": "param1 from library"')
.journalLastChildIncludes('"documentation": "param2 from library"') .journalLastChildIncludes('"documentation": "param2 from library"')
.journalLastChildIncludes('"documentation": "param3 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) { '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) {

@ -27,28 +27,30 @@ module.exports = {
.frameParent() .frameParent()
.clickLaunchIcon('filePanel') .clickLaunchIcon('filePanel')
.waitForElementVisible({ .waitForElementVisible({
selector: "//*[@data-id='workspacesSelect' and contains(.,'vyper-lang')]", selector: "//*[@data-id='workspacesSelect' and contains(.,'snekmate')]",
locateStrategy: 'xpath', locateStrategy: 'xpath',
timeout: 60000 timeout: 60000
}) })
.currentWorkspaceIs('vyper-lang') .currentWorkspaceIs('snekmate')
.waitForElementVisible({ .waitForElementVisible({
selector: "//*[@data-id='treeViewLitreeViewItemexamples' and contains(.,'examples')]", selector: "//*[@data-id='treeViewLitreeViewItemsrc' and contains(.,'src')]",
locateStrategy: 'xpath', locateStrategy: 'xpath',
timeout: 60000 timeout: 60000
}) })
.openFile('examples') .openFile('src')
.openFile('examples/auctions') .openFile('src/snekmate')
.openFile('examples/auctions/blind_auction.vy') .openFile('src/snekmate/tokens')
.openFile('src/snekmate/tokens/ERC721.vy')
}, },
// 'Add vyper file to run tests #group1': function (browser: NightwatchBrowser) { // 'Add vyper file to run tests #group1': function (browser: NightwatchBrowser) {
// browser.addFile('TestBallot.sol', sources[0]['TestBallot.sol']) // browser.addFile('TestBallot.sol', sources[0]['TestBallot.sol'])
// }, // },
'@sources': () => sources,
'Context menu click to compile blind_auction should succeed #group1': function (browser: NightwatchBrowser) { 'Context menu click to compile blind_auction should succeed #group1': function (browser: NightwatchBrowser) {
browser browser
.click('*[data-id="treeViewLitreeViewItemexamples/auctions/blind_auction.vy"]') .addFileSnekmate('blind_auction.vy', sources[0]['blindAuction'])
.rightClick('*[data-id="treeViewLitreeViewItemexamples/auctions/blind_auction.vy"]') .click('*[data-id="treeViewLitreeViewItemblind_auction.vy"]')
.rightClick('*[data-id="treeViewLitreeViewItemblind_auction.vy"]')
.waitForElementPresent('[data-id="contextMenuItemvyper"]') .waitForElementPresent('[data-id="contextMenuItemvyper"]')
.click('[data-id="contextMenuItemvyper"]') .click('[data-id="contextMenuItemvyper"]')
.clickLaunchIcon('vyper') .clickLaunchIcon('vyper')
@ -145,6 +147,33 @@ module.exports = {
browser.verifyCallReturnValue(contractAddress, ['0:uint256: 0']) browser.verifyCallReturnValue(contractAddress, ['0:uint256: 0'])
.perform(() => done()) .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()
} }
} }
@ -180,8 +209,9 @@ def _createPokemon(_name: String[32], _dna: uint256, _HP: uint256):
wins: 0 wins: 0
}) })
self.totalPokemonCount += 1` self.totalPokemonCount += 1`
const sources = [{
const blindAuction = ` '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) # 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 #pragma version ^0.3.10
@ -358,4 +388,6 @@ def auctionEnd():
# Transfer funds to beneficiary # Transfer funds to beneficiary
send(self.beneficiary, self.highestBid) send(self.beneficiary, self.highestBid)
` `}
}
]

@ -569,6 +569,17 @@ module.exports = {
.waitForElementVisible('*[data-id="treeViewLitreeViewItemsrc/MULTI_SIG/MultiSigSwapHook.sol"]') .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 tearDown: sauce
} }

@ -73,6 +73,8 @@ declare module 'nightwatch' {
waitForElementNotContainsText: (id: string, value: string, timeout: number = 10000) => NightwatchBrowser waitForElementNotContainsText: (id: string, value: string, timeout: number = 10000) => NightwatchBrowser
hideToolTips: (this: NightwatchBrowser) => NightwatchBrowser hideToolTips: (this: NightwatchBrowser) => NightwatchBrowser
enableClipBoard: () => NightwatchBrowser enableClipBoard: () => NightwatchBrowser
addFileSnekmate: (name: string, content: NightwatchContractContent) => NightwatchBrowser
selectFiles: (selelectedElements: any[]) => NightwatchBrowser
} }
export interface NightwatchBrowser { export interface NightwatchBrowser {

@ -42,6 +42,7 @@ import { CodeFormat } from './app/plugins/code-format'
import { SolidityUmlGen } from './app/plugins/solidity-umlgen' import { SolidityUmlGen } from './app/plugins/solidity-umlgen'
import { CompilationDetailsPlugin } from './app/plugins/compile-details' import { CompilationDetailsPlugin } from './app/plugins/compile-details'
import { VyperCompilationDetailsPlugin } from './app/plugins/vyper-compilation-details' import { VyperCompilationDetailsPlugin } from './app/plugins/vyper-compilation-details'
import { RemixGuidePlugin } from './app/plugins/remixGuide'
import { ContractFlattener } from './app/plugins/contractFlattener' import { ContractFlattener } from './app/plugins/contractFlattener'
import { TemplatesPlugin } from './app/plugins/remix-templates' import { TemplatesPlugin } from './app/plugins/remix-templates'
import { fsPlugin } from './app/plugins/electron/fsPlugin' import { fsPlugin } from './app/plugins/electron/fsPlugin'
@ -226,6 +227,10 @@ class AppComponent {
// ----------------- Compilation Details ---------------------------- // ----------------- Compilation Details ----------------------------
const compilationDetails = new CompilationDetailsPlugin(appManager) const compilationDetails = new CompilationDetailsPlugin(appManager)
const vyperCompilationDetails = new VyperCompilationDetailsPlugin(appManager) const vyperCompilationDetails = new VyperCompilationDetailsPlugin(appManager)
// ----------------- Remix Guide ----------------------------
const remixGuide = new RemixGuidePlugin(appManager)
// ----------------- ContractFlattener ---------------------------- // ----------------- ContractFlattener ----------------------------
const contractFlattener = new ContractFlattener() const contractFlattener = new ContractFlattener()
@ -344,6 +349,7 @@ class AppComponent {
solidityumlgen, solidityumlgen,
compilationDetails, compilationDetails,
vyperCompilationDetails, vyperCompilationDetails,
// remixGuide,
contractFlattener, contractFlattener,
solidityScript, solidityScript,
templates, templates,

@ -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<any> = () => { }
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<any>): void {
this.dispatch = dispatch
this.renderComponent()
}
render() {
return (
<div className="bg-dark" id="remixGuide">
<PluginViewWrapper plugin={this} />
</div>
)
}
renderComponent() {
this.dispatch({
...this,
...this.payload,
themeStyle: this.themeStyle,
theme: this.theme
})
}
updateComponent(state: any) {
return (
<RemixUIGridView
plugin={this}
styleList={""}
logo='/assets/img/YouTubeLogo.webp'
enableFilter={true}
showUntagged={true}
showPin={true}
tagList={[
['beginner', 'danger'],
['advanced', 'warning'],
['AI', 'success'],
['plugins', 'secondary'],
['solidity', 'primary'],
['vyper', 'info'],
['L2', 'danger']
]}
title='Remix Guide'
description="Streamlined access to categorized video tutorials for mastering Remix IDE. From fundamentals to advanced techniques, level up your development skills with ease."
//themeStyle={state.themeStyle}
>
<RemixUIGridSection
plugin={this}
title='Basics'
hScrollable= {true}
>
<RemixUIGridCell
plugin={this}
title="first item"
tagList={['L2', 'AI']}
logo='/assets/img/soliditySurvey2023.webp'
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell>
<RemixUIGridCell
plugin={this}
title="next"
pinned={true}
tagList={['L2', 'plugins']}
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell> <RemixUIGridCell
plugin={this}
title="something"
pinned={false}
tagList={['solidity', 'plugins']}
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell>
<RemixUIGridCell
plugin={this}
title="1"
tagList={['solidity']}
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell> <RemixUIGridCell
plugin={this}
title="1"
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell>
<RemixUIGridCell
plugin={this}
title="Something very very long"
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell> <RemixUIGridCell
plugin={this}
title="1"
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell>
<RemixUIGridCell
plugin={this}
title="1"
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell>
<RemixUIGridCell
plugin={this}
title="1"
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell>
<RemixUIGridCell
plugin={this}
title="1"
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell>
</RemixUIGridSection>
<RemixUIGridSection
plugin={this}
title='Basics not scrollable'
hScrollable= {false}
>
<RemixUIGridCell
plugin={this}
title="first item"
logo='/assets/img/soliditySurvey2023.webp'
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell>
<RemixUIGridCell
plugin={this}
title="next"
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell> <RemixUIGridCell
plugin={this}
title="something"
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell>
<RemixUIGridCell
plugin={this}
title="1"
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell> <RemixUIGridCell
plugin={this}
title="1"
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell>
<RemixUIGridCell
plugin={this}
title="1"
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell> <RemixUIGridCell
plugin={this}
title="1"
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell>
<RemixUIGridCell
plugin={this}
title="1"
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell>
<RemixUIGridCell
plugin={this}
title="1"
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell>
<RemixUIGridCell
plugin={this}
title="1"
>
<img src={'/assets/img/soliditySurvey2023.webp'} style={{height: '70px', width: '70px'}} alt=""></img>
</RemixUIGridCell>
</RemixUIGridSection>
</RemixUIGridView>
)
}
}

@ -86,7 +86,7 @@ export class SolCoder extends Plugin {
} }
async code_explaining(prompt): Promise<any> { async code_explaining(prompt, context:string=""): Promise<any> {
this.emit("aiInfering") this.emit("aiInfering")
this.call('layout', 'maximizeTerminal') this.call('layout', 'maximizeTerminal')
let result let result
@ -98,7 +98,7 @@ export class SolCoder extends Plugin {
Accept: 'application/json', Accept: 'application/json',
'Content-Type': '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() ).json()
if (result) { if (result) {

@ -119,7 +119,7 @@ export abstract class AbstractProvider extends Plugin implements IProvider {
} }
this.call('notification', 'alert', modalContent) this.call('notification', 'alert', modalContent)
} }
await this.call('udapp', 'setEnvironmentMode', {context: 'vm-paris'}) await this.call('udapp', 'setEnvironmentMode', {context: 'vm-cancun'})
return return
} }

@ -18,18 +18,17 @@ export class InjectedCustomProvider extends InjectedProviderDefault {
} }
async init() { async init() {
if (!this.chainId) { if (!this.chainId && this.rpcUrls.length > 0) {
const chainId = await new Web3(this.rpcUrls[0]).eth.getChainId() const chainId = await new Web3(this.rpcUrls[0]).eth.getChainId()
this.chainId = `0x${chainId.toString(16)}` this.chainId = `0x${chainId.toString(16)}`
} }
await super.init() await super.init()
if (this.chainName && this.rpcUrls && this.rpcUrls.length > 0) await addCustomNetwork(this.chainName, this.chainId, this.rpcUrls, this.nativeCurrency, this.blockExplorerUrls) await setCustomNetwork(this.chainName, this.chainId, this.rpcUrls, this.nativeCurrency, this.blockExplorerUrls)
else throw new Error('Cannot add the custom network to main injected provider')
return {} return {}
} }
} }
export const addCustomNetwork = async (chainName: string, chainId: string, rpcUrls: Array<string>, nativeCurrency?: Record<string, any>, blockExplorerUrls?: Array<string>) => { export const setCustomNetwork = async (chainName: string, chainId: string, rpcUrls: Array<string>, nativeCurrency?: Record<string, any>, blockExplorerUrls?: Array<string>) => {
try { try {
await (window as any).ethereum.request({ await (window as any).ethereum.request({
method: 'wallet_switchEthereumChain', method: 'wallet_switchEthereumChain',
@ -39,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. // This error code indicates that the chain has not been added to MetaMask.
if (switchError.code === 4902) { if (switchError.code === 4902) {
try { try {
const paramsObj: Record<string, any> = { if (chainName && rpcUrls && rpcUrls.length > 0) {
chainId: chainId, const paramsObj: Record<string, any> = {
chainName: chainName, chainId: chainId,
rpcUrls: rpcUrls, chainName: chainName,
} rpcUrls: rpcUrls,
if (nativeCurrency) paramsObj.nativeCurrency = nativeCurrency }
if (blockExplorerUrls) paramsObj.blockExplorerUrls = blockExplorerUrls if (nativeCurrency) paramsObj.nativeCurrency = nativeCurrency
await (window as any).ethereum.request({ if (blockExplorerUrls) paramsObj.blockExplorerUrls = blockExplorerUrls
method: 'wallet_addEthereumChain', await (window as any).ethereum.request({
params: [ paramsObj ] method: 'wallet_addEthereumChain',
}) params: [ paramsObj ]
})
await (window as any).ethereum.request({
method: 'wallet_switchEthereumChain', await (window as any).ethereum.request({
params: [{chainId: chainId}] method: 'wallet_switchEthereumChain',
}) params: [{chainId: chainId}]
})
}
} catch (addError) { } catch (addError) {
// handle "add" error // handle "add" error
} }

@ -25,7 +25,7 @@ export class InjectedProviderDefaultBase extends InjectedProvider {
} }
const profile = { const profile = {
name: 'injected', name: 'injected', // the name will be overwritten in the constructor.
displayName: 'Injected Provider', displayName: 'Injected Provider',
kind: 'provider', kind: 'provider',
description: 'injected Provider', description: 'injected Provider',

@ -8,6 +8,7 @@ import zhJson from './locales/zh'
import esJson from './locales/es' import esJson from './locales/es'
import frJson from './locales/fr' import frJson from './locales/fr'
import itJson from './locales/it' import itJson from './locales/it'
import ruJson from './locales/ru'
const _paq = window._paq = window._paq || [] const _paq = window._paq = window._paq || []
const locales = [ const locales = [
@ -15,6 +16,7 @@ const locales = [
{ code: 'en', name: 'English', localeName: 'English', messages: enJson }, { code: 'en', name: 'English', localeName: 'English', messages: enJson },
{ code: 'fr', name: 'French', localeName: 'Français', messages: frJson }, { code: 'fr', name: 'French', localeName: 'Français', messages: frJson },
{ code: 'it', name: 'Italian', localeName: 'Italiano', messages: itJson }, { code: 'it', name: 'Italian', localeName: 'Italiano', messages: itJson },
{ code: 'ru', name: 'Russian', localeName: 'Русский', messages: ruJson },
{ code: 'es', name: 'Spanish', localeName: 'Español', messages: esJson } { code: 'es', name: 'Spanish', localeName: 'Español', messages: esJson }
] ]

@ -36,6 +36,8 @@
"filePanel.addscriptetherscan": "Add Etherscan scripts", "filePanel.addscriptetherscan": "Add Etherscan scripts",
"filePanel.workspace.addscriptsindri": "Adds scripts for interacting with Sindri, a zk proof generation remote service", "filePanel.workspace.addscriptsindri": "Adds scripts for interacting with Sindri, a zk proof generation remote service",
"filePanel.addscriptsindri": "Add Sindri ZK scripts", "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.workspace.addscriptdeployer": "Adds scripts which can be used to deploy contracts",
"filePanel.addscriptdeployer": "Add contract deployer scripts", "filePanel.addscriptdeployer": "Add contract deployer scripts",
"filePanel.workspace.slitherghaction": "Adds a preset yml file to run slither analysis on github actions CI", "filePanel.workspace.slitherghaction": "Adds a preset yml file to run slither analysis on github actions CI",

@ -3,7 +3,9 @@
"udapp._comment_gasPrice.tsx": "libs/remix-ui/run-tab/src/lib/components/gasPrice.tsx", "udapp._comment_gasPrice.tsx": "libs/remix-ui/run-tab/src/lib/components/gasPrice.tsx",
"udapp.gasLimit": "Gas limit", "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._comment_value.tsx": "libs/remix-ui/run-tab/src/lib/components/value.tsx",
"udapp.value": "Value", "udapp.value": "Value",

@ -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": "Вычислить"
}

@ -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": "Перейти к предыдущей контрольной точке"
}

@ -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": "Эта рабочая область примера кода не будет сохранена. Нажмите здесь, чтобы сохранить."
}

@ -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"
}

@ -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())

@ -0,0 +1,10 @@
{
"panel.author": "Автор",
"panel.maintainedBy": "Поддерживается",
"panel.documentation": "Документация",
"panel.description": "Описание",
"panel.maintainedByRemix": "Поддерживается Remix",
"panel.pluginInfo": "Информация о плагине",
"panel.linkToDoc": "Ссылка на документацию",
"panel.makeAnissue": "Создать задачу"
}

@ -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": "Отклонить"
}

@ -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": "Управление разрешениями плагинов"
}

@ -0,0 +1,3 @@
{
"remixApp.scrollToSeeAllTabs": "Прокрутите, чтобы увидеть все вкладки"
}

@ -0,0 +1,7 @@
{
"remixUiTabs.tooltipText1": "Запуск скрипта (CTRL + SHIFT + S)",
"remixUiTabs.tooltipText2": "Компилировать CTRL + S",
"remixUiTabs.tooltipText3": "Выберите файл c расширением .sol или .yul для компиляции или файл .ts или .js для запуска",
"remixUiTabs.zoomOut": "Уменьшить",
"remixUiTabs.zoomIn": "Увеличить"
}

@ -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} Пожалуйста, сузьте поиск."
}

@ -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": "Температура"
}

@ -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 в котором можно найти всю информацию о метаданных (контракт должен быть опубликован первым)"
}

@ -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": "ПРОЙДЕН"
}

@ -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": "журналы"
}

@ -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:(см. <a>Geth Docs на сервере rpc</a>)",
"udapp.externalHttpProviderText2": "Для запуска Remix и локального тестового узла Geth используйте эту команду: (см. <a>Geth Docs в режиме Dev mode </a>)",
"udapp.externalHttpProviderText3": "<b>ВНИМАНИЕ:</b> Не безопасно использование флага --http.corsdomain с подстановочным символом: <b>--http.corsdomain *</b>",
"udapp.externalHttpProviderText4": "Для дополнительной информации: <a>Remix Docs на внешнем HTTP провайдере</a>",
"udapp.foundryProviderText1": "Примечание: Чтобы запустить Anvil в системе, запустите:",
"udapp.foundryProviderText2": "Для получения дополнительной информации, посетите <a>Документация по инструментарию разработки смарт-контрактов (Foundry) </a>",
"udapp.ganacheProviderText1": "Примечание: Чтобы запустить Ganache в системе, запустите:",
"udapp.ganacheProviderText2": "Для получения дополнительной информации, посетите: <a>Документация по Ganache</a>",
"udapp.hardhatProviderText1": "Примечание: Для запуска узла Hardhat в вашей системе, перейдите в папку hardhat проекта и запустите команду:",
"udapp.hardhatProviderText2": "Для получения дополнительной информации, посетите: <a>Документация по Hardhat</a>"
}

@ -1,6 +1,7 @@
import React from 'react' // eslint-disable-line import React from 'react' // eslint-disable-line
import {RunTabUI} from '@remix-ui/run-tab' import {RunTabUI} from '@remix-ui/run-tab'
import {ViewPlugin} from '@remixproject/engine-web' import {ViewPlugin} from '@remixproject/engine-web'
import isElectron from 'is-electron'
import {addressToString} from '@remix-ui/helper' import {addressToString} from '@remix-ui/helper'
import {InjectedProviderDefault} from '../providers/injected-provider-default' import {InjectedProviderDefault} from '../providers/injected-provider-default'
import {InjectedCustomProvider} from '../providers/injected-custom-provider' import {InjectedCustomProvider} from '../providers/injected-custom-provider'
@ -128,8 +129,9 @@ export class RunTab extends ViewPlugin {
async onInitDone() { async onInitDone() {
const udapp = this // eslint-disable-line 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', { await this.call('blockchain', 'addProvider', {
position,
options: {}, options: {},
dataId, dataId,
name, name,
@ -153,52 +155,63 @@ export class RunTab extends ViewPlugin {
}) })
} }
const addCustomInjectedProvider = async (event, name, networkId, urls, nativeCurrency) => { const addCustomInjectedProvider = async (position, event, name, displayName, networkId, urls, nativeCurrency) => {
name = `${name} through ${event.detail.info.name}` // name = `${name} through ${event.detail.info.name}`
await this.engine.register([new InjectedCustomProvider(event.detail.provider, name, networkId, urls, nativeCurrency)]) await this.engine.register([new InjectedCustomProvider(event.detail.provider, name, networkId, urls, nativeCurrency)])
await addProvider(name, name, true, false, false) await addProvider(position, name, displayName, true, false, false)
} }
const registerInjectedProvider = async (event) => { const registerInjectedProvider = async (event) => {
console.log('registerInjectedProvider', event) console.log('registerInjectedProvider', event)
await this.engine.register([new InjectedProviderDefault(event.detail.provider, event.detail.info.name)]) const name = 'injected-' + event.detail.info.name
await addProvider(event.detail.info.name, event.detail.info.name, true, false, false) const displayName = 'Injected Provider - ' + event.detail.info.name
await this.engine.register([new InjectedProviderDefault(event.detail.provider, name)])
await addCustomInjectedProvider(event, 'Optimism', '0xa', ['https://mainnet.optimism.io']) await addProvider(0, name, displayName, true, false, false)
await addCustomInjectedProvider(event, 'Arbitrum One', '0xa4b1', ['https://arb1.arbitrum.io/rpc'])
await addCustomInjectedProvider(event, 'SKALE Chaos Testnet', '0x50877ed6', ['https://staging-v3.skalenodes.com/v1/staging-fast-active-bellatrix'], { if (event.detail.info.name === 'MetaMask') {
"name": "sFUEL", await addCustomInjectedProvider(7, event, 'injected-metamask-optimism', 'L2 - Optimism', '0xa', ['https://mainnet.optimism.io'])
"symbol": "sFUEL", await addCustomInjectedProvider(8, event, 'injected-metamask-arbitrum', 'L2 - Arbitrum', '0xa4b1', ['https://arb1.arbitrum.io/rpc'])
"decimals": 18 await addCustomInjectedProvider(5, event, 'injected-metamask-sepolia', 'Testnet - Sepolia', '0xaa36a7', [],
}) {
await addCustomInjectedProvider(event, 'Ephemery Testnet', '', ['https://arb1.arbitrum.io/rpc']) "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 // VM
const titleVM = 'Execution environment is local to Remix. Data is only saved to browser memory and will vanish upon reload.' 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(1, 'vm-cancun', 'Remix VM (Cancun)', false, true, 'cancun', 'settingsVMCancunMode', titleVM)
await addProvider('vm-shanghai', 'Remix VM (Shanghai)', false, true, 'shanghai', 'settingsVMShanghaiMode', titleVM) await addProvider(50, 'vm-shanghai', 'Remix VM (Shanghai)', false, true, 'shanghai', 'settingsVMShanghaiMode', titleVM)
await addProvider('vm-paris', 'Remix VM (Paris)', false, true, 'paris', 'settingsVMParisMode', titleVM) await addProvider(51, 'vm-paris', 'Remix VM (Paris)', false, true, 'paris', 'settingsVMParisMode', titleVM)
await addProvider('vm-london', 'Remix VM (London)', false, true, 'london', 'settingsVMLondonMode', titleVM) await addProvider(52, 'vm-london', 'Remix VM (London)', false, true, 'london', 'settingsVMLondonMode', titleVM)
await addProvider('vm-berlin', 'Remix VM (Berlin)', false, true, 'berlin', 'settingsVMBerlinMode', titleVM) await addProvider(53, '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(2, '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(3, '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(4, 'vm-custom-fork', 'Remix VM - Custom fork', false, true, '', 'settingsVMCustomMode', titleVM)
await addProvider('vm-custom-fork', 'Remix VM - Custom fork', false, true, '', 'settingsVMCustomMode', titleVM)
// wallet connect // wallet connect
await addProvider('walletconnect', 'WalletConnect', false, false) await addProvider(6, '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)
*/
// external provider // external provider
await addProvider('basic-http-provider', 'Custom - External Http Provider', false, false) await addProvider(10, 'basic-http-provider', 'Custom - External Http Provider', false, false)
await addProvider('hardhat-provider', 'Dev - Hardhat Provider', false, false) await addProvider(20, 'hardhat-provider', 'Dev - Hardhat Provider', false, false)
await addProvider('ganache-provider', 'Dev - Ganache Provider', false, false) await addProvider(21, 'ganache-provider', 'Dev - Ganache Provider', false, false)
await addProvider('foundry-provider', 'Dev - Foundry Provider', false, false) await addProvider(22, 'foundry-provider', 'Dev - Foundry Provider', false, false)
// register injected providers // register injected providers
@ -208,8 +221,7 @@ export class RunTab extends ViewPlugin {
registerInjectedProvider(event) registerInjectedProvider(event)
} }
) )
if (!isElectron()) window.dispatchEvent(new Event("eip6963:requestProvider"))
window.dispatchEvent(new Event("eip6963:requestProvider"))
} }
writeFile(fileName, content) { writeFile(fileName, content) {

@ -66,6 +66,19 @@ body {
text-align:left; text-align:left;
background-color:#fff 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) { [tabindex="-1"]:focus:not(:focus-visible) {
outline:0!important outline:0!important
} }

@ -67,6 +67,19 @@ body {
text-align:left; text-align:left;
background-color:#060606 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) { [tabindex="-1"]:focus:not(:focus-visible) {
outline:0!important 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 background-color:#090909!important
} }
.bg-dark { .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 { a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
background-color:#939695!important background-color:#939695!important

@ -65,6 +65,19 @@ body {
text-align:left; text-align:left;
background-color:#fff 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) { [tabindex="-1"]:focus:not(:focus-visible) {
outline:0!important outline:0!important
} }

@ -69,6 +69,19 @@ body {
text-align:left; text-align:left;
background-color:#fff 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) { [tabindex="-1"]:focus:not(:focus-visible) {
outline:0!important outline:0!important
} }

@ -73,7 +73,8 @@ body {
background-color: var(--body-bg); background-color: var(--body-bg);
} }
*::-webkit-scrollbar { *::-webkit-scrollbar {
width: 8px; width: 8px;
height: 6px;
} }
*::-webkit-scrollbar-thumb { *::-webkit-scrollbar-thumb {
background-color: #37373b; background-color: #37373b;

@ -14,7 +14,7 @@
--gray: #6c757d; --gray: #6c757d;
--gray-dark: #343a40; --gray-dark: #343a40;
--primary: #fc58a3; --primary: #fc58a3;
--secondary: #e2f5f2; --secondary: #c7e3de;
--success: #24b882; --success: #24b882;
--info: #00bbff; --info: #00bbff;
--warning: #fabe33; --warning: #fabe33;
@ -76,6 +76,18 @@ body {
background-color: var(--body-bg); 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 { [tabindex="-1"]:focus {
outline: 0 !important; outline: 0 !important;
} }

@ -73,7 +73,8 @@ body {
background-color: var(--body-bg); background-color: var(--body-bg);
} }
*::-webkit-scrollbar { *::-webkit-scrollbar {
width: 8px; width: 8px;
height: 6px;
} }
*::-webkit-scrollbar-thumb { *::-webkit-scrollbar-thumb {
background-color: #41455b; background-color: #41455b;

@ -90,7 +90,8 @@ body {
background-color: var(--body-bg); background-color: var(--body-bg);
} }
*::-webkit-scrollbar { *::-webkit-scrollbar {
width: 8px; width: 8px;
height: 6px;
} }
*::-webkit-scrollbar-thumb { *::-webkit-scrollbar-thumb {
background-color: #41455b; background-color: #41455b;

@ -76,6 +76,18 @@ body {
background-color: var(--body-bg); 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 { [tabindex="-1"]:focus {
outline: 0 !important; outline: 0 !important;
} }

@ -76,6 +76,18 @@ body {
background-color: var(--body-bg); 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 { [tabindex="-1"]:focus {
outline: 0 !important; outline: 0 !important;
} }

@ -76,6 +76,18 @@ body {
background-color: var(--body-bg); 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 { [tabindex="-1"]:focus {
outline: 0 !important; outline: 0 !important;
} }

@ -76,6 +76,18 @@ body {
background-color: var(--body-bg); 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 { [tabindex="-1"]:focus {
outline: 0 !important; outline: 0 !important;
} }

@ -61,6 +61,7 @@ export class Blockchain extends Plugin {
} }
providers: {[key: string]: VMProvider | InjectedProvider | NodeProvider} providers: {[key: string]: VMProvider | InjectedProvider | NodeProvider}
transactionContextAPI: TransactionContextAPI transactionContextAPI: TransactionContextAPI
registeredPluginEvents: string[]
// NOTE: the config object will need to be refactored out in remix-lib // NOTE: the config object will need to be refactored out in remix-lib
constructor(config: Config) { constructor(config: Config) {
@ -91,6 +92,7 @@ export class Blockchain extends Plugin {
this.networkcallid = 0 this.networkcallid = 0
this.networkStatus = {network: {name: ' - ', id: ' - '}} this.networkStatus = {network: {name: ' - ', id: ' - '}}
this.registeredPluginEvents = []
this.setupEvents() this.setupEvents()
this.setupProviders() this.setupProviders()
} }
@ -103,34 +105,24 @@ export class Blockchain extends Plugin {
onActivation() { onActivation() {
this.active = true this.active = true
this.on('injected', 'chainChanged', () => { this.on('manager', 'pluginActivated', (plugin) => {
this.detectNetwork((error, network) => { if (plugin && plugin.name && (plugin.name.startsWith('injected') || plugin.name === 'walletconnect')) {
this.networkStatus = {network, error} this.registeredPluginEvents.push(plugin.name)
this._triggerEvent('networkStatus', [this.networkStatus]) this.on(plugin.name, '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])
})
}) })
} }
onDeactivation() { onDeactivation() {
this.active = false this.active = false
this.off('injected', 'chainChanged') for (const pluginName of this.registeredPluginEvents) {
this.off('injected-trustwallet', 'chainChanged') this.off(pluginName, 'chainChanged')
this.off('walletconnect', 'chainChanged') }
this.off('walletconnect', 'accountsChanged')
} }
setupEvents() { setupEvents() {
@ -175,6 +167,7 @@ export class Blockchain extends Plugin {
getCurrentProvider() { getCurrentProvider() {
const provider = this.getProvider() const provider = this.getProvider()
if (provider && provider.startsWith('vm')) return this.providers['vm'] 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] if (this.providers[provider]) return this.providers[provider]
return this.providers.web3 // default to the common type of 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() 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) { signMessage(message, account, passphrase, cb) {
this.getCurrentProvider().signMessage(message, account, passphrase, cb) this.getCurrentProvider().signMessage(message, account, passphrase, cb)
} }

@ -48,8 +48,4 @@ export class InjectedProvider {
cb(e.message) cb(e.message)
} }
} }
getProvider () {
return 'injected'
}
} }

@ -55,8 +55,4 @@ export class NodeProvider {
cb(e.message) cb(e.message)
} }
} }
getProvider () {
return this.executionContext.getProvider()
}
} }

@ -134,9 +134,5 @@ export class VMProvider {
this.web3.eth.sign(message, account) this.web3.eth.sign(message, account)
.then(signedData => cb(null, bytesToHex(messageHash), signedData)) .then(signedData => cb(null, bytesToHex(messageHash), signedData))
.catch(error => cb(error)) .catch(error => cb(error))
} }
getProvider () {
return this.executionContext.getProvider()
}
} }

@ -52,12 +52,6 @@ let requiredModules = [ // services + layout views + system views
'ganache-provider', 'ganache-provider',
'foundry-provider', 'foundry-provider',
'basic-http-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-custom-fork',
'vm-goerli-fork', 'vm-goerli-fork',
'vm-mainnet-fork', 'vm-mainnet-fork',
@ -98,7 +92,16 @@ const sensitiveCalls = {
web3Provider: ['sendAsync'] web3Provider: ['sendAsync']
} }
const isInjectedProvider = (name) => {
return name.startsWith('injected')
}
const isVM = (name) => {
return name.startsWith('vm')
}
export function isNative(name) { export function isNative(name) {
// nativePlugin allows to bypass the permission request // nativePlugin allows to bypass the permission request
const nativePlugins = [ const nativePlugins = [
'vyper', 'vyper',
@ -117,19 +120,16 @@ export function isNative(name) {
'ganache-provider', 'ganache-provider',
'foundry-provider', 'foundry-provider',
'basic-http-provider', 'basic-http-provider',
'injected-optimism-provider',
'tabs', 'tabs',
'injected-arbitrum-one-provider',
'injected-skale-chaos-testnet-provider',
'injected-ephemery-testnet-provider',
'injected',
'doc-gen', 'doc-gen',
'doc-viewer', 'doc-viewer',
'circuit-compiler', 'circuit-compiler',
'compilationDetails', '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) { async canDeactivatePlugin(from, to) {
if (requiredModules.includes(to.name)) return false if (this.isRequired(to.name)) return false
return isNative(from.name) return isNative(from.name)
} }
@ -208,7 +208,7 @@ export class RemixAppManager extends PluginManager {
) )
this.event.emit('activate', plugin) this.event.emit('activate', plugin)
this.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() { getAll() {
@ -236,7 +236,7 @@ export class RemixAppManager extends PluginManager {
isRequired(name) { isRequired(name) {
// excluding internal use plugins // excluding internal use plugins
return requiredModules.includes(name) return requiredModules.includes(name) || isInjectedProvider(name) || isVM(name)
} }
async registeredPlugins() { async registeredPlugins() {

@ -117,9 +117,9 @@ const App = () => {
<main id="vyper-plugin"> <main id="vyper-plugin">
<section> <section>
<div className="px-3 pt-3 mb-3 w-100"> <div className="px-3 pt-3 mb-3 w-100">
<CustomTooltip placement="bottom" tooltipText="Clone Vyper examples. Switch to the File Explorer to see the examples."> <CustomTooltip placement="bottom" tooltipText="Clone a repo of Vyper examples. Switch to the File Explorer to see the examples.">
<Button data-id="add-repository" className="w-100 btn btn-secondary" onClick={() => remixClient.cloneVyperRepo()}> <Button data-id="add-repository" className="w-100 btn btn-secondary" onClick={() => remixClient.cloneVyperRepo()}>
Clone Vyper examples repository Clone a repo of Vyper examples
</Button> </Button>
</CustomTooltip> </CustomTooltip>
</div> </div>

@ -144,14 +144,18 @@ const compileReturnType = (output, contract) => {
const fixContractContent = (content: string) => { const fixContractContent = (content: string) => {
if (content.length === 0) return if (content.length === 0) return
const pragmaFound = content.includes('#pragma version ^0.3.10') const pragmaFound = content.includes('#pragma version ^0.3.10')
const wrongpragmaFound = content.includes('# pragma version ^0.3.10')
const evmVerFound = content.includes('#pragma evm-version shanghai') const evmVerFound = content.includes('#pragma evm-version shanghai')
const pragma = '#pragma version ^0.3.10' const pragma = '#pragma version ^0.3.10'
const evmVer = '#pragma evm-version shanghai' const evmVer = '#pragma evm-version shanghai'
if (!evmVerFound) { if (evmVerFound === false) {
content = `${evmVer}\n${content}` content = `${evmVer}\n${content}`
} }
if (!pragmaFound) { if (wrongpragmaFound === true) {
content = content.replace('# pragma version ^0.3.10', '')
}
if (pragmaFound === false ) {
content = `${pragma}\n${content}` content = `${pragma}\n${content}`
} }
return content return content

@ -80,20 +80,20 @@ export class RemixClient extends PluginClient {
async cloneVyperRepo() { async cloneVyperRepo() {
try { try {
// @ts-ignore // @ts-ignore
this.call('notification', 'toast', 'cloning Vyper repository...') this.call('notification', 'toast', 'cloning Snekmate Vyper repository...')
await this.call('manager', 'activatePlugin', 'dGitProvider') await this.call('manager', 'activatePlugin', 'dGitProvider')
await this.call( await this.call(
'dGitProvider', 'dGitProvider',
'clone', 'clone',
{url: 'https://github.com/vyperlang/vyper', token: null, branch: 'v0.3.10'}, {url: 'https://github.com/pcaversaccio/snekmate', token: null, branch: 'v0.0.5'},
// @ts-ignore // @ts-ignore
'vyper-lang' 'snekmate'
) )
this.call( this.call(
// @ts-ignore // @ts-ignore
'notification', 'notification',
'toast', 'toast',
'Vyper repository cloned, the workspace Vyper has been created.' 'Snekmate Vyper repository cloned, the workspace snekmate has been created.'
) )
} catch (e) { } catch (e) {
// @ts-ignore // @ts-ignore

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/ghaction-helper", "name": "@remix-project/ghaction-helper",
"version": "0.1.27", "version": "0.1.28",
"description": "Solidity Tests GitHub Action Helper", "description": "Solidity Tests GitHub Action Helper",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {
@ -19,17 +19,17 @@
}, },
"homepage": "https://github.com/ethereum/remix-project#readme", "homepage": "https://github.com/ethereum/remix-project#readme",
"devDependencies": { "devDependencies": {
"@remix-project/remix-solidity": "^0.5.33", "@remix-project/remix-solidity": "^0.5.34",
"@types/chai": "^4.3.4", "@types/chai": "^4.3.4",
"typescript": "^4.9.3" "typescript": "^4.9.3"
}, },
"dependencies": { "dependencies": {
"@ethereum-waffle/chai": "^3.4.4", "@ethereum-waffle/chai": "^3.4.4",
"@remix-project/remix-simulator": "^0.2.47", "@remix-project/remix-simulator": "^0.2.48",
"chai": "^4.3.7", "chai": "^4.3.7",
"ethers": "^5.7.2", "ethers": "^5.7.2",
"web3": "^4.1.1" "web3": "^4.1.1"
}, },
"types": "./src/index.d.ts", "types": "./src/index.d.ts",
"gitHead": "65197fceebd45f013aefed3c4a90277cee7f2962" "gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-analyzer", "name": "@remix-project/remix-analyzer",
"version": "0.5.56", "version": "0.5.57",
"description": "Tool to perform static analysis on Solidity smart contracts", "description": "Tool to perform static analysis on Solidity smart contracts",
"scripts": { "scripts": {
"test": "./../../node_modules/.bin/ts-node --project ../../tsconfig.base.json --require tsconfig-paths/register ./../../node_modules/.bin/tape ./test/tests.ts" "test": "./../../node_modules/.bin/ts-node --project ../../tsconfig.base.json --require tsconfig-paths/register ./../../node_modules/.bin/tape ./test/tests.ts"
@ -25,8 +25,8 @@
"@ethereumjs/tx": "5.3.0", "@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "9.0.3", "@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0", "@ethereumjs/vm": "8.0.0",
"@remix-project/remix-astwalker": "^0.0.77", "@remix-project/remix-astwalker": "^0.0.78",
"@remix-project/remix-lib": "^0.5.54", "@remix-project/remix-lib": "^0.5.55",
"async": "^2.6.2", "async": "^2.6.2",
"ethers": "^5.4.2", "ethers": "^5.4.2",
"ethjs-util": "^0.1.6", "ethjs-util": "^0.1.6",
@ -50,6 +50,6 @@
"typescript": "^3.7.5" "typescript": "^3.7.5"
}, },
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "65197fceebd45f013aefed3c4a90277cee7f2962", "gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e",
"main": "./src/index.js" "main": "./src/index.js"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-astwalker", "name": "@remix-project/remix-astwalker",
"version": "0.0.77", "version": "0.0.78",
"description": "Tool to walk through Solidity AST", "description": "Tool to walk through Solidity AST",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {
@ -37,7 +37,7 @@
"@ethereumjs/tx": "5.3.0", "@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "9.0.3", "@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0", "@ethereumjs/vm": "8.0.0",
"@remix-project/remix-lib": "^0.5.54", "@remix-project/remix-lib": "^0.5.55",
"@types/tape": "^4.2.33", "@types/tape": "^4.2.33",
"async": "^2.6.2", "async": "^2.6.2",
"ethers": "^5.4.2", "ethers": "^5.4.2",
@ -53,6 +53,6 @@
"tap-spec": "^5.0.0" "tap-spec": "^5.0.0"
}, },
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "65197fceebd45f013aefed3c4a90277cee7f2962", "gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e",
"types": "./src/index.d.ts" "types": "./src/index.d.ts"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-debug", "name": "@remix-project/remix-debug",
"version": "0.5.47", "version": "0.5.48",
"description": "Tool to debug Ethereum transactions", "description": "Tool to debug Ethereum transactions",
"contributors": [ "contributors": [
{ {
@ -26,10 +26,10 @@
"@ethereumjs/tx": "5.3.0", "@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "9.0.3", "@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0", "@ethereumjs/vm": "8.0.0",
"@remix-project/remix-astwalker": "^0.0.77", "@remix-project/remix-astwalker": "^0.0.78",
"@remix-project/remix-lib": "^0.5.54", "@remix-project/remix-lib": "^0.5.55",
"@remix-project/remix-simulator": "^0.2.47", "@remix-project/remix-simulator": "^0.2.48",
"@remix-project/remix-solidity": "^0.5.33", "@remix-project/remix-solidity": "^0.5.34",
"ansi-gray": "^0.1.1", "ansi-gray": "^0.1.1",
"async": "^2.6.2", "async": "^2.6.2",
"color-support": "^1.1.3", "color-support": "^1.1.3",
@ -69,6 +69,6 @@
}, },
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme", "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme",
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "65197fceebd45f013aefed3c4a90277cee7f2962", "gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e",
"types": "./src/index.d.ts" "types": "./src/index.d.ts"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-lib", "name": "@remix-project/remix-lib",
"version": "0.5.54", "version": "0.5.55",
"description": "Library to various Remix tools", "description": "Library to various Remix tools",
"contributors": [ "contributors": [
{ {
@ -55,6 +55,6 @@
}, },
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme", "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme",
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "65197fceebd45f013aefed3c4a90277cee7f2962", "gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e",
"types": "./src/index.d.ts" "types": "./src/index.d.ts"
} }

@ -171,6 +171,6 @@ export function checkError (execResult, compiledContracts) {
msg = '\tState changes is not allowed in Static Call context\n' msg = '\tState changes is not allowed in Static Call context\n'
ret.error = true ret.error = true
} }
ret.message = `${error}\n${exceptionError}\n${msg}\nDebug the transaction to get more information.` ret.message = `${error}\n${exceptionError}\n${msg}\nYou may want to cautiously increase the gas limit if the transaction went out of gas.`
return ret return ret
} }

@ -106,7 +106,6 @@ export class TxRunnerWeb3 {
const tx = { from: from, to: to, data: data, value: value } const tx = { from: from, to: to, data: data, value: value }
if (!from) return callback('the value of "from" is not defined. Please make sure an account is selected.') if (!from) return callback('the value of "from" is not defined. Please make sure an account is selected.')
if (useCall) { if (useCall) {
tx['gas'] = gasLimit
if (this._api && this._api.isVM()) { if (this._api && this._api.isVM()) {
(this.getWeb3() as any).remix.registerCallId(timestamp) (this.getWeb3() as any).remix.registerCallId(timestamp)
} }
@ -137,8 +136,19 @@ export class TxRunnerWeb3 {
this.getWeb3().eth.estimateGas(txCopy) this.getWeb3().eth.estimateGas(txCopy)
.then(gasEstimation => { .then(gasEstimation => {
gasEstimationForceSend(null, () => { gasEstimationForceSend(null, () => {
// callback is called whenever no error /*
tx['gas'] = !gasEstimation ? gasLimit : gasEstimation * gasLimit is a value that can be set in the UI to hardcap value that can be put in a tx.
* e.g if the gasestimate
*/
if (gasLimit !== '0x0' && gasEstimation > gasLimit) {
return callback(`estimated gas for this transaction (${gasEstimation}) is higher than gasLimit set in the configuration (${gasLimit}). Please raise the gas limit.`)
}
if (gasLimit === '0x0') {
tx['gas'] = gasEstimation
} else {
tx['gas'] = gasLimit
}
if (this._api.config.getUnpersistedProperty('doNotShowTransactionConfirmationAgain')) { if (this._api.config.getUnpersistedProperty('doNotShowTransactionConfirmationAgain')) {
return this._executeTx(tx, network, null, this._api, promptCb, callback) return this._executeTx(tx, network, null, this._api, promptCb, callback)
@ -158,7 +168,8 @@ export class TxRunnerWeb3 {
} }
err = network.name === 'VM' ? null : err // just send the tx if "VM" err = network.name === 'VM' ? null : err // just send the tx if "VM"
gasEstimationForceSend(err, () => { gasEstimationForceSend(err, () => {
tx['gas'] = gasLimit const defaultGasLimit = 3000000
tx['gas'] = gasLimit === '0x0' ? '0x' + defaultGasLimit.toString(16) : gasLimit
if (this._api.config.getUnpersistedProperty('doNotShowTransactionConfirmationAgain')) { if (this._api.config.getUnpersistedProperty('doNotShowTransactionConfirmationAgain')) {
return this._executeTx(tx, network, null, this._api, promptCb, callback) return this._executeTx(tx, network, null, this._api, promptCb, callback)

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-simulator", "name": "@remix-project/remix-simulator",
"version": "0.2.47", "version": "0.2.48",
"description": "Ethereum IDE and tools for the web", "description": "Ethereum IDE and tools for the web",
"contributors": [ "contributors": [
{ {
@ -22,7 +22,7 @@
"@ethereumjs/tx": "5.3.0", "@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "9.0.3", "@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0", "@ethereumjs/vm": "8.0.0",
"@remix-project/remix-lib": "^0.5.54", "@remix-project/remix-lib": "^0.5.55",
"ansi-gray": "^0.1.1", "ansi-gray": "^0.1.1",
"async": "^3.1.0", "async": "^3.1.0",
"body-parser": "^1.18.2", "body-parser": "^1.18.2",
@ -70,6 +70,6 @@
}, },
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-simulator#readme", "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-simulator#readme",
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "65197fceebd45f013aefed3c4a90277cee7f2962", "gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e",
"types": "./src/index.d.ts" "types": "./src/index.d.ts"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-solidity", "name": "@remix-project/remix-solidity",
"version": "0.5.33", "version": "0.5.34",
"description": "Tool to load and run Solidity compiler", "description": "Tool to load and run Solidity compiler",
"main": "src/index.js", "main": "src/index.js",
"types": "src/index.d.ts", "types": "src/index.d.ts",
@ -19,7 +19,7 @@
"@ethereumjs/tx": "5.3.0", "@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "9.0.3", "@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0", "@ethereumjs/vm": "8.0.0",
"@remix-project/remix-lib": "^0.5.54", "@remix-project/remix-lib": "^0.5.55",
"async": "^2.6.2", "async": "^2.6.2",
"eslint-scope": "^5.0.0", "eslint-scope": "^5.0.0",
"ethers": "^5.4.2", "ethers": "^5.4.2",
@ -57,5 +57,5 @@
}, },
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-solidity#readme", "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-solidity#readme",
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "65197fceebd45f013aefed3c4a90277cee7f2962" "gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-tests", "name": "@remix-project/remix-tests",
"version": "0.2.47", "version": "0.2.48",
"description": "Tool to test Solidity smart contracts", "description": "Tool to test Solidity smart contracts",
"main": "src/index.js", "main": "src/index.js",
"types": "./src/index.d.ts", "types": "./src/index.d.ts",
@ -41,9 +41,9 @@
"@ethereumjs/tx": "5.3.0", "@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "9.0.3", "@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0", "@ethereumjs/vm": "8.0.0",
"@remix-project/remix-lib": "^0.5.54", "@remix-project/remix-lib": "^0.5.55",
"@remix-project/remix-simulator": "^0.2.47", "@remix-project/remix-simulator": "^0.2.48",
"@remix-project/remix-solidity": "^0.5.33", "@remix-project/remix-solidity": "^0.5.34",
"@remix-project/remix-url-resolver": "^0.0.42", "@remix-project/remix-url-resolver": "^0.0.42",
"ansi-gray": "^0.1.1", "ansi-gray": "^0.1.1",
"async": "^2.6.0", "async": "^2.6.0",
@ -89,5 +89,5 @@
"@ethereumjs/trie": "6.2.0" "@ethereumjs/trie": "6.2.0"
}, },
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "65197fceebd45f013aefed3c4a90277cee7f2962" "gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e"
} }

@ -106,7 +106,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
const providerChanged = () => { const providerChanged = () => {
debuggerModule.onEnvChanged((provider) => { debuggerModule.onEnvChanged((provider) => {
setState((prevState) => { setState((prevState) => {
const isLocalNodeUsed = !provider.startsWith('vm') && provider !== 'injected' const isLocalNodeUsed = !provider.startsWith('vm') && !provider.startsWith('injected')
return {...prevState, isLocalNodeUsed: isLocalNodeUsed} return {...prevState, isLocalNodeUsed: isLocalNodeUsed}
}) })
}) })

@ -753,7 +753,7 @@ export const EditorUI = (props: EditorUIProps) => {
const content = await props.plugin.call('fileManager', 'readFile', file) const content = await props.plugin.call('fileManager', 'readFile', file)
const selectedCode = editor.getModel().getValueInRange(editor.getSelection()) const selectedCode = editor.getModel().getValueInRange(editor.getSelection())
await props.plugin.call('solcoder', 'code_explaining', selectedCode) await props.plugin.call('solcoder', 'code_explaining', selectedCode, content)
_paq.push(['trackEvent', 'ai', 'solcoder', 'explainFunction']) _paq.push(['trackEvent', 'ai', 'solcoder', 'explainFunction'])
}, },
} }
@ -823,12 +823,15 @@ export const EditorUI = (props: EditorUIProps) => {
freeFunctionCondition.set(false) freeFunctionCondition.set(false)
return return
} }
const { nodesAtPosition } = await retrieveNodesAtPosition(props.editorAPI, props.plugin) const { nodesAtPosition } = await retrieveNodesAtPosition(props.editorAPI, props.plugin)
const freeFunctionNode = nodesAtPosition.find((node) => node.kind === 'freeFunction') const freeFunctionNode = nodesAtPosition.find((node) => node.kind === 'freeFunction')
if (freeFunctionNode) { if (freeFunctionNode) {
executeFreeFunctionAction.label = intl.formatMessage({id: 'editor.executeFreeFunction2'}, {name: freeFunctionNode.name}) executeFreeFunctionAction.label = intl.formatMessage({id: 'editor.executeFreeFunction2'}, {name: freeFunctionNode.name})
freeFunctionAction = editor.addAction(executeFreeFunctionAction) freeFunctionAction = editor.addAction(executeFreeFunctionAction)
} }
const functionImpl = nodesAtPosition.find((node) => node.kind === 'function') const functionImpl = nodesAtPosition.find((node) => node.kind === 'function')
if (functionImpl) { if (functionImpl) {
currentFunction.current = functionImpl.name currentFunction.current = functionImpl.name
@ -839,6 +842,8 @@ export const EditorUI = (props: EditorUIProps) => {
executeSolgptExplainFunctionAction.label = intl.formatMessage({id: 'editor.explainFunctionSol'}) executeSolgptExplainFunctionAction.label = intl.formatMessage({id: 'editor.explainFunctionSol'})
solgptExplainFunctionAction = editor.addAction(executeSolgptExplainFunctionAction) solgptExplainFunctionAction = editor.addAction(executeSolgptExplainFunctionAction)
}else{ }else{
// do not allow single character explaining
if (editor.getModel().getValueInRange(editor.getSelection()).length <=1){ return}
executeSolgptExplainFunctionAction.label = intl.formatMessage({id: 'editor.explainFunctionSol'}) executeSolgptExplainFunctionAction.label = intl.formatMessage({id: 'editor.explainFunctionSol'})
solgptExplainFunctionAction = editor.addAction(executeSolgptExplainFunctionAction) solgptExplainFunctionAction = editor.addAction(executeSolgptExplainFunctionAction)
} }

@ -0,0 +1,4 @@
export * from './lib/remix-ui-grid-view'
export * from './lib/remix-ui-grid-section'
export * from './lib/remix-ui-grid-cell'

@ -0,0 +1,42 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import React from 'react'
import { useContext } from 'react'
import FiltersContext from ".././filtersContext"
interface CustomCheckboxProps {
label: string
color?: string
}
export const CustomCheckbox = (props: CustomCheckboxProps) => {
const filterCon = useContext(FiltersContext)
let textColor = props.color
let defChecked = true
if (filterCon.keyValueMap[props.label]) defChecked = filterCon.keyValueMap[props.label].enabled
if (!textColor || textColor == '') textColor = filterCon.keyValueMap[props.label].color
return (
<div id={textColor + props.label} className="h-80 mx-1 align-items-center custom-control custom-checkbox" style={{minWidth: '4rem'}}>
<input
className="custom-control-input"
id={"GVCheckbox" + props.label}
defaultChecked={defChecked}
onChange={e => {
if (props.label == 'no tag')
filterCon.showUntagged = ! filterCon.showUntagged
else filterCon.updateValue(props.label, e.target.checked, textColor)}}
type="checkbox"
/>
<label
className={"form-check-label custom-control-label text-nowrap text-" + textColor}
style={{ paddingTop: '0.125rem' }}
htmlFor={"GVCheckbox" + props.label}
data-id={"GVCheckboxLabel" + props.label}
>
{ props.label }
</label>
</div>
)
}
export default CustomCheckbox

@ -0,0 +1,18 @@
import React, { createContext, useState, useContext } from 'react';
interface FilterContextType {
showUntagged: boolean
showPin: boolean
keyValueMap: Record<string, { enabled: boolean; color: string; }>;
updateValue: (key: string, enabled: boolean, color: string) => void
addValue: (key: string, enabled: boolean, color: string) => void
}
const FiltersContext = createContext<FilterContextType>({
showUntagged: false,
showPin: false,
keyValueMap: {},
updateValue: () => {},
addValue: () => {},
});
export default FiltersContext

@ -0,0 +1,46 @@
.remixui_grid_cell {
font-weight: normal;
}
.remixui_grid_cell_container {
width: fit-content;
}
.remixui_grid_cell_title{
font-size: 0.8rem;
font-style: italic;
}
.remixui_grid_cell_btn {
width: 32px;
}
.remixui_grid_cell_logo {
width: 3rem;
height: 3rem;
}
.remixui_grid_cell_pin:focus {
outline: none;
}
.remixui_grid_cell_pin {
width: 1rem;
height: 1rem;
position: relative;
right: 1rem;
top: -0.5rem;
background: transparent;
}
.remixui_grid_cell_tags {
position: relative;
right: 1rem;
top: 0.1rem;
}
.remixui_grid_cell_tag {
font-size: x-small;
font-weight: bolder;
width: 0.4rem;
height: 1.2rem;
}

@ -0,0 +1,86 @@
import React, {useState, useEffect, useContext, useRef, ReactNode} from 'react' // eslint-disable-line
import './remix-ui-grid-cell.css'
import FiltersContext from "./filtersContext"
import { CustomTooltip } from '@remix-ui/helper'
declare global {
interface Window {
_paq: any
}
}
const _paq = window._paq = window._paq || []
interface RemixUIGridCellProps {
plugin: any
pinned?: boolean
pinStateCallback?: any
logo?: string
title?: string
tagList?: string[] // max 8, others will be ignored
classList?: string
styleList?: any
children?: ReactNode
}
export const RemixUIGridCell = (props: RemixUIGridCellProps) => {
const filterCon = useContext(FiltersContext)
const [anyEnabled, setAnyEnabled] = useState(false)
const [pinned, setPinned] = useState<boolean>(props.pinned)
useEffect(() => {
if (props.tagList) setAnyEnabled(props.tagList.some((key) => filterCon.keyValueMap[key]?.enabled))
else setAnyEnabled(filterCon.showUntagged)
}, [filterCon, props.tagList])
return (
<div className='mr-2 mt-3'>
{ anyEnabled && <div className='d-flex flex-grid'>
<div className={"d-flex mx-0 p-2 bg-light border border-secondary remixui_grid_cell_container " + props.classList || ''} data-id={"remixUIGS" + props.title}>
<div className="d-flex remixui_grid_cell flex-column">
<div className='d-flex flex-row pb-1 align-items-end' style={{width: '8rem', height: '1rem'}}>
{ props.logo && <img className='remixui_grid_view_logo mr-1' src={props.logo} style={{width: '1rem', height: '1rem'}}/> }
{ props.title && <label
className='m-0 p-0 align-items-left'
style={{overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', fontSize: 'xx-small'}}
>
{ props.title }
</label> }
</div>
{ props.children }
</div>
</div>
{ filterCon.showPin && <button
className={`${pinned ? 'fa-duotone' : 'fa-light'}` + ` fa-map-pin text-info border-0 mb-0 remixui_grid_cell_pin`}
onClick={() => {
setPinned(!pinned)
props.pinStateCallback()
}}
></button>}
{ props.tagList && <div className='d-flex flex-column align-items-begin remixui_grid_cell_tags'>
{ Object.keys(props.tagList).map((key) => (
filterCon.keyValueMap[props.tagList[key]].enabled && (
<CustomTooltip
placement="right"
tooltipId="pluginManagerInactiveTitleLinkToDoc"
tooltipClasses="text-nowrap"
tooltipText={props.tagList[key]}
>
<span key={props.tagList[key]}
className={'remixui_grid_cell_tag bg-' + filterCon.keyValueMap[props.tagList[key]].color}
>
</span>
</CustomTooltip>
)
)) }
</div> }
{ !props.tagList && <span
className={'remixui_grid_cell_tags'}>
</span> }
</div> }
</div>
)
}
export default RemixUIGridCell

@ -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);
}

@ -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 (
<div
className={`d-flex px-4 py-2 flex-column w-100 remixui_grid_section_container ${props.classList}`}
data-id={"remixUIGS" + props.title}
style={{ overflowX: 'auto' }}
>
<div className="d-flex flex-column w-100 remixui_grid_section">
{ props.title && <h6 className='mt-1 mb-0 align-items-left '>{ props.title }</h6> }
<div className={(props.hScrollable) ? `d-flex flex-row pb-2 overflow-auto` : `d-flex flex-wrap`}>
{ props.children }
</div>
</div>
</div>
)
}
export default RemixUIGridSection

@ -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;
}

@ -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<Record<string, { enabled: boolean; color: string; }>>({});
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<string, { enabled: boolean; color: string; }> = {};
// 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 (
<FiltersContext.Provider value={{ showUntagged, showPin, keyValueMap, updateValue, addValue }}>
<div className={"d-flex flex-column bg-dark w-100 h-100 remixui_grid_view_container " + props.classList || ''} data-id="remixUIGV">
<ThemeContext.Provider value={state.themeQuality}>
<div className="d-flex flex-column w-100 remixui_grid_view">
<div className='d-flex p-4 bg-light flex-column remixui_grid_view_titlebar'>
<div className='d-flex flex-row align-items-center mb-2'>
{ props.logo && <img className='remixui_grid_view_logo mr-2' src={props.logo} /> }
{ props.title && <h3 className='mb-0'>{ props.title }</h3> }
</div>
{ props.description && <div className='pb-3 remixui_grid_view_title'>{ props.description }</div> }
{ props.enableFilter && <div className='d-flex flex-row'>
<div className="d-flex flex-row pr-2 pb-1 align-items-center justify-content-between">
<div className='d-flex' id="GVFilter">
<button
className="remixui_grid_view_btn text-secondary form-control bg-light border d-flex align-items-center p-2 justify-content-center fas fa-filter bg-light"
onClick={(e) => {
_paq.push(['trackEvent', 'GridView' + props.title ? props.title : '', 'filter', searchInputRef.current.value])
//setstate
}}
></button>
<input
ref={searchInputRef}
type="text"
style={{minWidth: '100px'}}
className="border form-control border-right-0 mr-4"
id="GVFilterInput"
placeholder={"Filter the list"}
data-id="RemixGVFilterInput"
/>
</div>
<div className='d-flex flex-row'>
{ Object.keys(keyValueMap).map((key) => (
<CustomCheckbox label={key} />
)) }
</div>
</div>
</div> }
</div>
{ props.children }
</div>
</ThemeContext.Provider>
</div>
</FiltersContext.Provider>
)
}
export default RemixUIGridView

@ -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
)

@ -32,7 +32,7 @@ export function LanguageOptions({ plugin }: { plugin: any }) {
{langOptions} {langOptions}
</Dropdown.Toggle> </Dropdown.Toggle>
<Dropdown.Menu className="dropdown-menu langSelector" style={{ paddingTop: "0px", paddingBottom: "0px", minWidth: 'fit-content', backgroundColor: 'var(--body-bg)'}}> <Dropdown.Menu className="dropdown-menu langSelector" style={{ paddingTop: "0px", paddingBottom: "0px", minWidth: 'fit-content', backgroundColor: 'var(--body-bg)'}}>
{['EN', 'ES', 'FR', 'IT', 'ZH'].map((lang, index) => ( {['EN', 'ES', 'FR', 'IT', 'RU', 'ZH'].map((lang, index) => (
<DropdownItem as={'span'} className={langOptions === lang ? "border border-primary px-2" : "px-2"} onClick={() => <DropdownItem as={'span'} className={langOptions === lang ? "border border-primary px-2" : "px-2"} onClick={() =>
{ {
changeLanguage(lang.toLowerCase()) changeLanguage(lang.toLowerCase())

@ -13,8 +13,6 @@ import { appPlatformTypes, platformContext } from '@remix-ui/app'
import { HomeTabFileElectron } from './components/homeTabFileElectron' import { HomeTabFileElectron } from './components/homeTabFileElectron'
import { LanguageOptions } from './components/homeTablangOptions' import { LanguageOptions } from './components/homeTablangOptions'
declare global { declare global {
interface Window { interface Window {
_paq: any _paq: any

@ -30,7 +30,7 @@ export const fillAccountsList = async (plugin: RunTab, dispatch: React.Dispatch<
} }
const provider = plugin.blockchain.getProvider() const provider = plugin.blockchain.getProvider()
if (provider === 'injected') { if (provider && provider.startsWith('injected')) {
const selectedAddress = plugin.blockchain.getInjectedWeb3Address() const selectedAddress = plugin.blockchain.getInjectedWeb3Address()
if (!(Object.keys(loadedAccounts).includes(toChecksumAddress(selectedAddress)))) setAccount(dispatch, null) if (!(Object.keys(loadedAccounts).includes(toChecksumAddress(selectedAddress)))) setAccount(dispatch, null)
} }

@ -120,8 +120,11 @@ const getConfirmationCb = (plugin: RunTab, dispatch: React.Dispatch<any>, confir
export const continueHandler = (dispatch: React.Dispatch<any>, gasEstimationPrompt: (msg: string) => JSX.Element, error, continueTxExecution, cancelCb) => { export const continueHandler = (dispatch: React.Dispatch<any>, gasEstimationPrompt: (msg: string) => JSX.Element, error, continueTxExecution, cancelCb) => {
if (error) { if (error) {
let msg = typeof error !== 'string' ? error.message : 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', () => { dispatch(displayNotification('Gas estimation failed', gasEstimationPrompt(msg), 'Send Transaction', 'Cancel Transaction', () => {
continueTxExecution() continueTxExecution()

@ -14,6 +14,13 @@ import { shortenAddress } from "@remix-ui/helper"
const _paq = window._paq = window._paq || [] const _paq = window._paq = window._paq || []
export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch<any>) => { export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch<any>) => {
// 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.blockchain.events.on('newTransaction', (tx, receipt) => {
plugin.emit('newTransaction', tx, receipt) plugin.emit('newTransaction', tx, receipt)
}) })
@ -33,7 +40,6 @@ export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch<any>) => {
} }
setFinalContext(plugin, dispatch) setFinalContext(plugin, dispatch)
fillAccountsList(plugin, dispatch) fillAccountsList(plugin, dispatch)
await loadPinnedContracts(plugin, dispatch)
}) })
plugin.blockchain.event.register('networkStatus', async ({ error, network }) => { plugin.blockchain.event.register('networkStatus', async ({ error, network }) => {
@ -44,10 +50,18 @@ export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch<any>) => {
return return
} }
const networkProvider = plugin.networkModule.getNetworkProvider.bind(plugin.networkModule) 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 pinnedChainId = !networkProvider().startsWith('vm') ? network.id : networkProvider() const netUI = !isVM ? `${network.name} (${network.id || '-'}) network` : 'VM'
const pinnedChainId = !isVM ? network.id : networkProvider()
setNetworkNameFromProvider(dispatch, netUI) setNetworkNameFromProvider(dispatch, netUI)
setPinnedChainId(dispatch, pinnedChainId) 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)) plugin.blockchain.event.register('addProvider', provider => addExternalProvider(dispatch, provider))
@ -102,9 +116,29 @@ export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch<any>) => {
}) })
}) })
plugin.on('manager', 'pluginActivated', (plugin: Plugin) => { plugin.on('manager', 'pluginActivated', (activatedPlugin: Plugin) => {
if (plugin.name === 'remixd') { if (activatedPlugin.name === 'remixd') {
dispatch(setRemixDActivated(true)) dispatch(setRemixDActivated(true))
} else {
if (activatedPlugin && activatedPlugin.name.startsWith('injected')) {
plugin.on(activatedPlugin.name, 'accountsChanged', (accounts: Array<string>) => {
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<string>) => {
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))
})
}
} }
}) })
@ -136,29 +170,6 @@ export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch<any>) => {
dispatch(clearRecorderCount()) dispatch(clearRecorderCount())
}) })
plugin.on('injected', 'accountsChanged', (accounts: Array<string>) => {
const accountsMap = {}
accounts.map(account => { accountsMap[account] = shortenAddress(account, '0')})
dispatch(fetchAccountsListSuccess(accountsMap))
})
plugin.on('injected-trustwallet', 'accountsChanged', (accounts: Array<string>) => {
const accountsMap = {}
accounts.map(account => { accountsMap[account] = shortenAddress(account, '0')})
dispatch(fetchAccountsListSuccess(accountsMap))
})
plugin.on('walletconnect', 'accountsChanged', async (accounts: Array<string>) => {
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(() => { setInterval(() => {
fillAccountsList(plugin, dispatch) fillAccountsList(plugin, dispatch)
@ -166,10 +177,8 @@ export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch<any>) => {
}, 30000) }, 30000)
} }
const loadPinnedContracts = async (plugin, dispatch) => { const loadPinnedContracts = async (plugin, dispatch, dirName) => {
await plugin.call('udapp', 'clearAllPinnedInstances') await plugin.call('udapp', 'clearAllPinnedInstances')
const { network } = await plugin.call('blockchain', 'getCurrentNetworkStatus')
const dirName = plugin.REACT_API.networkName === 'VM' ? plugin.REACT_API.selectExEnv : network.id
const isPinnedAvailable = await plugin.call('fileManager', 'exists', `.deploys/pinned-contracts/${dirName}`) const isPinnedAvailable = await plugin.call('fileManager', 'exists', `.deploys/pinned-contracts/${dirName}`)
if (isPinnedAvailable) { if (isPinnedAvailable) {
try { try {

@ -26,69 +26,69 @@ export function AccountUI(props: AccountProps) {
useEffect(() => { useEffect(() => {
props.setAccount('') props.setAccount('')
switch (selectExEnv) { if (selectExEnv && selectExEnv.startsWith('injected')) {
case 'injected':
setPlusOpt({ setPlusOpt({
classList: 'udapp_disableMouseEvents', classList: 'udapp_disableMouseEvents',
title: intl.formatMessage({id: 'udapp.injectedTitle'}) title: intl.formatMessage({id: 'udapp.injectedTitle'})
}) })
break } else {
switch (selectExEnv) {
case 'vm-cancun': case 'vm-cancun':
setPlusOpt({
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'})
})
break
case 'vm-shanghai':
setPlusOpt({
classList: '',
title: intl.formatMessage({id: 'udapp.createNewAccount'})
})
break
case 'web3':
if (!personalMode) {
setPlusOpt({ setPlusOpt({
classList: 'disableMouseEvents', classList: '',
title: intl.formatMessage({id: 'udapp.web3Title'}) title: intl.formatMessage({id: 'udapp.createNewAccount'})
}) })
} else { break
case 'vm-paris':
setPlusOpt({ setPlusOpt({
classList: '', classList: '',
title: intl.formatMessage({id: 'udapp.createNewAccount'}) 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) {
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]) }, [selectExEnv, personalMode])
const newAccount = () => { const newAccount = () => {

@ -1,24 +1,24 @@
// eslint-disable-next-line no-use-before-define // eslint-disable-next-line no-use-before-define
import React from 'react' import React from 'react'
import {FormattedMessage} from 'react-intl' import {FormattedMessage} from 'react-intl'
import {EnvironmentProps} from '../types' import {EnvironmentProps, Provider} from '../types'
import {Dropdown} from 'react-bootstrap' import {Dropdown} from 'react-bootstrap'
import {CustomMenu, CustomToggle, CustomTooltip} from '@remix-ui/helper' import {CustomMenu, CustomToggle, CustomTooltip} from '@remix-ui/helper'
export function EnvironmentUI(props: EnvironmentProps) { export function EnvironmentUI(props: EnvironmentProps) {
const handleChangeExEnv = (env: string) => { const handleChangeExEnv = (env: string) => {
const provider = props.providers.providerList.find((exEnv) => exEnv.value === env) const provider = props.providers.providerList.find((exEnv) => exEnv.name === env)
const context = provider.value const context = provider.name
props.setExecutionContext({context}) 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 = { const bridges = {
'injected-optimism-provider': 'https://app.optimism.io/bridge/deposit', 'L2 - Optimism': 'https://app.optimism.io/bridge/deposit',
'injected-arbitrum-one-provider': 'https://bridge.arbitrum.io/' '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 ( return (
<div className="udapp_crow"> <div className="udapp_crow">
<label id="selectExEnv" className="udapp_settingsLabel"> <label id="selectExEnv" className="udapp_settingsLabel">
@ -33,33 +33,33 @@ export function EnvironmentUI(props: EnvironmentProps) {
<div className="udapp_environment"> <div className="udapp_environment">
<Dropdown id="selectExEnvOptions" data-id="settingsSelectEnvOptions" className="udapp_selectExEnvOptions"> <Dropdown id="selectExEnvOptions" data-id="settingsSelectEnvOptions" className="udapp_selectExEnvOptions">
<Dropdown.Toggle as={CustomToggle} id="dropdown-custom-components" className="btn btn-light btn-block w-100 d-inline-block border border-dark form-control" icon={null}> <Dropdown.Toggle as={CustomToggle} id="dropdown-custom-components" className="btn btn-light btn-block w-100 d-inline-block border border-dark form-control" icon={null}>
{isL2(currentProvider) && 'L2 - '} {isL2(currentProvider && currentProvider.displayName) && 'L2 - '}
{currentProvider && currentProvider.content} {currentProvider && currentProvider.displayName}
{currentProvider && bridges[currentProvider.value] && ( {currentProvider && bridges[currentProvider.name] && (
<CustomTooltip placement={'right'} tooltipClasses="text-nowrap" tooltipId="info-recorder" tooltipText={<FormattedMessage id="udapp.tooltipText3" />}> <CustomTooltip placement={'right'} tooltipClasses="text-nowrap" tooltipId="info-recorder" tooltipText={<FormattedMessage id="udapp.tooltipText3" />}>
<i <i
style={{fontSize: 'medium'}} style={{fontSize: 'medium'}}
className={'ml-2 fa fa-rocket-launch'} className={'ml-2 fa fa-rocket-launch'}
aria-hidden="true" aria-hidden="true"
onClick={() => { onClick={() => {
window.open(bridges[currentProvider.value], '_blank') window.open(bridges[currentProvider.name], '_blank')
}} }}
></i> ></i>
</CustomTooltip> </CustomTooltip>
)} )}
</Dropdown.Toggle> </Dropdown.Toggle>
<Dropdown.Menu as={CustomMenu} className="w-100 custom-dropdown-items" data-id="custom-dropdown-items"> <Dropdown.Menu as={CustomMenu} className="w-100 custom-dropdown-items" data-id="custom-dropdown-items">
{props.providers.providerList.map(({content, value}, index) => ( {props.providers.providerList.map(({displayName, name}, index) => (
<Dropdown.Item <Dropdown.Item
key={index} key={index}
onClick={() => { onClick={() => {
handleChangeExEnv(value) handleChangeExEnv(name)
}} }}
data-id={`dropdown-item-${value}`} data-id={`dropdown-item-${name}`}
> >
<span className=""> <span className="">
{isL2({value}) && 'L2 - '} {isL2(displayName) && 'L2 - '}
{content} {displayName}
</span> </span>
</Dropdown.Item> </Dropdown.Item>
))} ))}

@ -0,0 +1,82 @@
// eslint-disable-next-line no-use-before-define
import {CustomTooltip} from '@remix-ui/helper'
import React, { useEffect, useRef, useState } from 'react'
import {FormattedMessage} from 'react-intl'
import {GasPriceProps} from '../types'
const defaultGasLimit = 3000000
export function GasLimitUI(props: GasPriceProps) {
const inputComponent = useRef<HTMLInputElement>(null)
const currentGasLimit = useRef(defaultGasLimit)
const [gasLimitAuto, setGasLimitAuto] = useState(true)
useEffect(() => {
handleGasLimitAuto()
}, [])
useEffect(() => {
handleGasLimitAuto()
}, [gasLimitAuto])
const handleGasLimit = (e) => {
props.setGasFee(e.target.value)
}
const handleGasLimitAuto = () => {
if (gasLimitAuto) {
currentGasLimit.current = parseInt(inputComponent.current.value)
props.setGasFee(0)
} else {
props.setGasFee(currentGasLimit.current)
}
}
return (
<div className="udapp_crow">
<label className="udapp_settingsLabel">
<FormattedMessage id="udapp.gasLimit" />
</label>
<div className='pl-0 custom-control custom-checkbox udapp_col2 udapp_gasNval'>
<div className="d-flex pb-1 custom-control custom-radio">
<input
className="custom-control-input"
type="radio"
name="gasLimitRadio"
value="auto"
onChange={() => setGasLimitAuto(!gasLimitAuto)}
checked={gasLimitAuto}
id="glAutoConfig"
/>
<label className="form-check-label custom-control-label" htmlFor="glAutoConfig" data-id="glAutoConfiguration">
<FormattedMessage id="udapp.gasLimitAuto" />
</label>
</div>
<div className="d-flex pb-1 custom-control custom-radio">
<input
className="custom-control-input"
type="radio"
name="gasLimitRadio"
value="manual"
onChange={() => setGasLimitAuto(!gasLimitAuto)}
checked={!gasLimitAuto}
id="glManualConfig"
/>
<label className="mb-1 w-100 form-check-label custom-control-label" htmlFor="glManualConfig" data-id="glManualConfiguration">
<FormattedMessage id="udapp.gasLimitManual" />
<CustomTooltip placement={'right'} tooltipClasses="text-nowrap" tooltipId="remixGasPriceTooltip" tooltipText={<FormattedMessage id="udapp.tooltipText4" />}>
<input
type="number"
ref={inputComponent}
disabled={gasLimitAuto}
className="mt-2 form-control"
id="gasLimit"
value={props.gasLimit === 0 ? currentGasLimit.current : props.gasLimit}
onChange={handleGasLimit}
/>
</CustomTooltip>
</label>
</div>
</div>
</div>
)
}

@ -1,22 +0,0 @@
// eslint-disable-next-line no-use-before-define
import {CustomTooltip} from '@remix-ui/helper'
import React from 'react'
import {FormattedMessage} from 'react-intl'
import {GasPriceProps} from '../types'
export function GasPriceUI(props: GasPriceProps) {
const handleGasLimit = (e) => {
props.setGasFee(e.target.value)
}
return (
<div className="udapp_crow">
<label className="udapp_settingsLabel">
<FormattedMessage id="udapp.gasLimit" />
</label>
<CustomTooltip placement={'right'} tooltipClasses="text-nowrap" tooltipId="remixGasPriceTooltip" tooltipText={<FormattedMessage id="udapp.tooltipText4" />}>
<input type="number" className="form-control udapp_gasNval udapp_col2" id="gasLimit" value={props.gasLimit} onChange={handleGasLimit} />
</CustomTooltip>
</div>
)
}

@ -4,7 +4,7 @@ import {SettingsProps} from '../types'
import {EnvironmentUI} from './environment' import {EnvironmentUI} from './environment'
import {NetworkUI} from './network' import {NetworkUI} from './network'
import {AccountUI} from './account' import {AccountUI} from './account'
import {GasPriceUI} from './gasPrice' import {GasLimitUI} from './gasLimit'
import {ValueUI} from './value' import {ValueUI} from './value'
export function SettingsUI(props: SettingsProps) { export function SettingsUI(props: SettingsProps) {
@ -27,7 +27,7 @@ export function SettingsUI(props: SettingsProps) {
signMessageWithAddress={props.signMessageWithAddress} signMessageWithAddress={props.signMessageWithAddress}
passphrase={props.passphrase} passphrase={props.passphrase}
/> />
<GasPriceUI gasLimit={props.gasLimit} setGasFee={props.setGasFee} /> <GasLimitUI gasLimit={props.gasLimit} setGasFee={props.setGasFee} />
<ValueUI setUnit={props.setUnit} sendValue={props.sendValue} sendUnit={props.sendUnit} setSendValue={props.setSendValue} /> <ValueUI setUnit={props.setUnit} sendValue={props.sendValue} sendUnit={props.sendUnit} setSendValue={props.setSendValue} />
</div> </div>
) )

@ -297,7 +297,7 @@ export function UniversalDappUI(props: UdappProps) {
<label> <label>
<b><FormattedMessage id="udapp.balance" />:</b> {instanceBalance} ETH <b><FormattedMessage id="udapp.balance" />:</b> {instanceBalance} ETH
</label> </label>
{props.exEnvironment === 'injected' && <i className="fas fa-edit btn btn-sm p-0" onClick={() => {props.editInstance(props.instance)}}></i>} {props.exEnvironment && props.exEnvironment.startsWith('injected') && <i className="fas fa-edit btn btn-sm p-0" onClick={() => {props.editInstance(props.instance)}}></i>}
</div> </div>
{ props.isPinnedContract && props.instance.pinnedAt ? ( { props.isPinnedContract && props.instance.pinnedAt ? (
<div className="d-flex" data-id="instanceContractPinnedAt"> <div className="d-flex" data-id="instanceContractPinnedAt">

@ -212,7 +212,6 @@
display: flex; display: flex;
} }
.udapp_gasNval { .udapp_gasNval {
width: 55%;
font-size: 0.8rem; font-size: 0.8rem;
} }
.udapp_gasNvalUnit { .udapp_gasNvalUnit {

@ -18,8 +18,8 @@ export const runTabInitialState: RunTabState = {
}, },
sendValue: '0', sendValue: '0',
sendUnit: 'wei', sendUnit: 'wei',
gasLimit: 3000000, gasLimit: 0,
selectExEnv: 'vm-paris', selectExEnv: 'vm-cancun',
personalMode: false, personalMode: false,
networkName: 'VM', networkName: 'VM',
chainId:'-', chainId:'-',
@ -78,14 +78,6 @@ export const runTabInitialState: RunTabState = {
} }
} }
type AddProvider = {
name: string,
displayName: string,
provider: any,
title?: string,
dataId?: string
}
export const runTabReducer = (state: RunTabState = runTabInitialState, action: Action) => { export const runTabReducer = (state: RunTabState = runTabInitialState, action: Action) => {
switch (action.type) { switch (action.type) {
case FETCH_ACCOUNTS_LIST_REQUEST: { case FETCH_ACCOUNTS_LIST_REQUEST: {
@ -174,7 +166,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A
return { return {
...state, ...state,
selectExEnv: payload, selectExEnv: payload,
networkName: state.selectExEnv === 'vm-paris' ? 'VM' : state.networkName, networkName: state.selectExEnv === 'vm-cancun' ? 'VM' : state.networkName,
accounts: { accounts: {
...state.accounts, ...state.accounts,
selectedAccount: '', selectedAccount: '',
@ -223,13 +215,11 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A
} }
case FETCH_PROVIDER_LIST_SUCCESS: { case FETCH_PROVIDER_LIST_SUCCESS: {
const payload: { id?: string, dataId?: string, title?: string, value: string, fork?: string, content: string }[] = action.payload
return { return {
...state, ...state,
providers: { providers: {
...state.providers, ...state.providers,
providerList: payload, providerList: action.payload,
isSuccessful: true, isSuccessful: true,
isRequesting: false, isRequesting: false,
error: null error: null
@ -252,15 +242,23 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A
} }
case ADD_PROVIDER: { case ADD_PROVIDER: {
const payload: AddProvider = action.payload const payload = action.payload
const id = action.payload.name const length = state.providers.providerList.length
state.providers.providerList.push({ if (state.providers.providerList.length === 0) {
content: payload.displayName, state.providers.providerList.push(payload)
dataId: payload.dataId, } else {
id, let index = 0
title: payload.title, for (const provider of state.providers.providerList) {
value: id if (provider.position >= payload.position) {
}) state.providers.providerList.splice(index, 0, payload)
break;
}
index++
}
if (length === state.providers.providerList.length) {
state.providers.providerList.push(payload)
}
}
return { return {
...state, ...state,
providers: { providers: {
@ -271,8 +269,8 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A
} }
case REMOVE_PROVIDER: { case REMOVE_PROVIDER: {
const id: string = action.payload const name: string = action.payload
const providers = state.providers.providerList.filter((el) => el.id !== id) const providers = state.providers.providerList.filter((el) => el.name !== name)
return { return {
...state, ...state,
providers: { providers: {

@ -47,8 +47,6 @@ export class Blockchain extends Plugin<any, any> {
* @return {String} - fork name * @return {String} - fork name
*/ */
getCurrentFork(): string; getCurrentFork(): string;
isWeb3Provider(): boolean;
isInjectedWeb3(): boolean;
signMessage(message: any, account: any, passphrase: any, cb: any): void; signMessage(message: any, account: any, passphrase: any, cb: any): void;
web3(): any; web3(): any;
getTxListener(opts: any): any; getTxListener(opts: any): any;

@ -19,6 +19,23 @@ export interface Contract {
export interface ContractList { export interface ContractList {
[file: string]: Contract[] [file: string]: Contract[]
} }
export type Provider = {
name: string
displayName: string
provider: {
sendAsync: () => void
},
init: () => void
title: string
dataId: string
options: { [key: string]: string}
fork: boolean
isVM: boolean
isInjected: boolean
position: number
}
export interface RunTabState { export interface RunTabState {
accounts: { accounts: {
loadedAccounts: Record<string, string>, loadedAccounts: Record<string, string>,
@ -35,14 +52,7 @@ export interface RunTabState {
networkName: string, networkName: string,
chainId: string chainId: string
providers: { providers: {
providerList: { providerList: Provider[],
id?: string,
dataId?: string,
title?: string,
value: string,
fork?: string
content: string
}[],
isRequesting: boolean, isRequesting: boolean,
isSuccessful: boolean, isSuccessful: boolean,
error: string error: string
@ -138,14 +148,7 @@ export interface SettingsProps {
personalMode: boolean, personalMode: boolean,
networkName: string, networkName: string,
providers: { providers: {
providerList: { providerList: Provider[],
id?: string,
dataId?: string,
title?: string,
value: string,
fork?: string
content: string
}[],
isRequesting: boolean, isRequesting: boolean,
isSuccessful: boolean, isSuccessful: boolean,
error: string error: string
@ -164,14 +167,7 @@ export interface SettingsProps {
export interface EnvironmentProps { export interface EnvironmentProps {
selectedEnv: string, selectedEnv: string,
providers: { providers: {
providerList: { providerList: Provider[],
id?: string,
dataId?: string,
title?: string,
value: string,
fork?: string
content: string
}[],
isRequesting: boolean, isRequesting: boolean,
isSuccessful: boolean, isSuccessful: boolean,
error: string error: string

@ -8,5 +8,4 @@ declare class InjectedProvider {
getBalanceInEther(address: any): Promise<string>; getBalanceInEther(address: any): Promise<string>;
getGasPrice(cb: any): void; getGasPrice(cb: any): void;
signMessage(message: any, account: any, _passphrase: any, cb: any): void; signMessage(message: any, account: any, _passphrase: any, cb: any): void;
getProvider(): string;
} }

@ -9,5 +9,4 @@ declare class NodeProvider {
getBalanceInEther(address: any): Promise<string>; getBalanceInEther(address: any): Promise<string>;
getGasPrice(cb: any): void; getGasPrice(cb: any): void;
signMessage(message: any, account: any, passphrase: any, cb: any): void; signMessage(message: any, account: any, passphrase: any, cb: any): void;
getProvider(): any;
} }

@ -12,5 +12,4 @@ declare class VMProvider {
getBalanceInEther(address: any): Promise<string>; getBalanceInEther(address: any): Promise<string>;
getGasPrice(cb: any): void; getGasPrice(cb: any): void;
signMessage(message: any, account: any, _passphrase: any, cb: any): void; signMessage(message: any, account: any, _passphrase: any, cb: any): void;
getProvider(): string;
} }

@ -2,7 +2,7 @@ import { CompilationResult, SourceWithTarget } from '@remixproject/plugin-api'
import { ViewPlugin } from '@remixproject/engine-web'; import { ViewPlugin } from '@remixproject/engine-web';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import {Registry} from '@remix-project/remix-lib'; import { Registry } from '@remix-project/remix-lib';
export declare class AnalysisTab extends ViewPlugin { export declare class AnalysisTab extends ViewPlugin {
event: EventManager; event: EventManager;
events: EventEmitter; events: EventEmitter;

@ -194,6 +194,16 @@ export function HamburgerMenu(props: HamburgerMenuProps) {
}} }}
platforms={[appPlatformTypes.web, appPlatformTypes.desktop]} platforms={[appPlatformTypes.web, appPlatformTypes.desktop]}
></HamburgerMenuItem> ></HamburgerMenuItem>
<HamburgerMenuItem
kind="addcreate2solidityfactory"
fa="fa-kit fa-ts-logo"
hideOption={hideWorkspaceOptions || hideFileOperations}
actionOnClick={() => {
props.addHelperScripts('contractCreate2Factory')
props.hideIconsMenu(!showIconsMenu)
}}
platforms={[appPlatformTypes.web, appPlatformTypes.desktop]}
></HamburgerMenuItem>
</> </>
) )
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save