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

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

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

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

@ -174,7 +174,6 @@ module.exports = {
.journalLastChildIncludes('"documentation": "param1"')
.journalLastChildIncludes('"documentation": "param2"')
.journalLastChildIncludes('"documentation": "param3"')
.journalLastChildIncludes('Debug the transaction to get more information.')
.click('*[data-id="deployAndRunClearInstances"]')
},
@ -198,7 +197,6 @@ module.exports = {
.journalLastChildIncludes('"documentation": "param1"')
.journalLastChildIncludes('"documentation": "param2"')
.journalLastChildIncludes('"documentation": "param3"')
.journalLastChildIncludes('Debug the transaction to get more information.')
},
'Should Compile and Deploy a contract which define a custom error in a library, the error should be logged in the terminal #group3': function (browser: NightwatchBrowser) {
@ -216,7 +214,6 @@ module.exports = {
.journalLastChildIncludes('"documentation": "param1 from library"')
.journalLastChildIncludes('"documentation": "param2 from library"')
.journalLastChildIncludes('"documentation": "param3 from library"')
.journalLastChildIncludes('Debug the transaction to get more information.')
},
'Should compile and deploy 2 simple contracts, the contract creation component state should be correctly reset for the deployment of the second contract #group4': function (browser: NightwatchBrowser) {

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

@ -569,6 +569,17 @@ module.exports = {
.waitForElementVisible('*[data-id="treeViewLitreeViewItemsrc/MULTI_SIG/MultiSigSwapHook.sol"]')
},
'Should add Create2 solidity factory #group4': !function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('filePanel')
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspaceaddcreate2solidityfactory"]')
.getEditorValue((content) => {
browser.assert.ok(content.indexOf(`contract Create2FactoryAssembly {`) !== -1,
'current displayed content is not Create2FactoryAssembly')
})
},
tearDown: sauce
}

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

@ -42,6 +42,7 @@ import { CodeFormat } from './app/plugins/code-format'
import { SolidityUmlGen } from './app/plugins/solidity-umlgen'
import { CompilationDetailsPlugin } from './app/plugins/compile-details'
import { VyperCompilationDetailsPlugin } from './app/plugins/vyper-compilation-details'
import { RemixGuidePlugin } from './app/plugins/remixGuide'
import { ContractFlattener } from './app/plugins/contractFlattener'
import { TemplatesPlugin } from './app/plugins/remix-templates'
import { fsPlugin } from './app/plugins/electron/fsPlugin'
@ -226,6 +227,10 @@ class AppComponent {
// ----------------- Compilation Details ----------------------------
const compilationDetails = new CompilationDetailsPlugin(appManager)
const vyperCompilationDetails = new VyperCompilationDetailsPlugin(appManager)
// ----------------- Remix Guide ----------------------------
const remixGuide = new RemixGuidePlugin(appManager)
// ----------------- ContractFlattener ----------------------------
const contractFlattener = new ContractFlattener()
@ -344,6 +349,7 @@ class AppComponent {
solidityumlgen,
compilationDetails,
vyperCompilationDetails,
// remixGuide,
contractFlattener,
solidityScript,
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.call('layout', 'maximizeTerminal')
let result
@ -98,7 +98,7 @@ export class SolCoder extends Plugin {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({"data":[prompt, "code_explaining", false,2000,0.9,0.8,50]}),
body: JSON.stringify({"data":[prompt, "code_explaining", false,2000,0.9,0.8,50, context]}),
})
).json()
if (result) {

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

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

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

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

@ -36,6 +36,8 @@
"filePanel.addscriptetherscan": "Add Etherscan scripts",
"filePanel.workspace.addscriptsindri": "Adds scripts for interacting with Sindri, a zk proof generation remote service",
"filePanel.addscriptsindri": "Add Sindri ZK scripts",
"filePanel.workspace.addcreate2solidityfactory": "A contract which allows you to deploy a contract using CREATE2.",
"filePanel.addcreate2solidityfactory": "Add Create2 Solidity factory",
"filePanel.workspace.addscriptdeployer": "Adds scripts which can be used to deploy contracts",
"filePanel.addscriptdeployer": "Add contract deployer scripts",
"filePanel.workspace.slitherghaction": "Adds a preset yml file to run slither analysis on github actions CI",

@ -3,7 +3,9 @@
"udapp._comment_gasPrice.tsx": "libs/remix-ui/run-tab/src/lib/components/gasPrice.tsx",
"udapp.gasLimit": "Gas limit",
"udapp.tooltipText4": "The default gas limit is 3M. Adjust as needed.",
"udapp.gasLimitAuto": "Estimated Gas",
"udapp.gasLimitManual": "Custom",
"udapp.tooltipText4": "Enter custom Gas Limit.",
"udapp._comment_value.tsx": "libs/remix-ui/run-tab/src/lib/components/value.tsx",
"udapp.value": "Value",

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

@ -66,6 +66,19 @@ body {
text-align:left;
background-color:#fff
}
*::-webkit-scrollbar {
width: 8px;
height: 6px;
background-color: var(--body-bg);
}
*::-webkit-scrollbar-thumb {
background-color: var(--secondary);
opacity: 0.3;
border-radius: 30px;
}
[tabindex="-1"]:focus:not(:focus-visible) {
outline:0!important
}

@ -67,6 +67,19 @@ body {
text-align:left;
background-color:#060606
}
*::-webkit-scrollbar {
width: 8px;
height: 6px;
background-color: var(--body-bg);
}
*::-webkit-scrollbar-thumb {
background-color: var(--secondary);
opacity: 0.3;
border-radius: 30px;
}
[tabindex="-1"]:focus:not(:focus-visible) {
outline:0!important
}
@ -5635,7 +5648,7 @@ a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover {
background-color:#090909!important
}
.bg-dark {
background-color:#adafae!important
background-color:#2f3130!important
}
a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover {
background-color:#939695!important

@ -65,6 +65,19 @@ body {
text-align:left;
background-color:#fff
}
*::-webkit-scrollbar {
width: 8px;
height: 6px;
background-color: var(--body-bg);
}
*::-webkit-scrollbar-thumb {
background-color: var(--secondary);
opacity: 0.3;
border-radius: 30px;
}
[tabindex="-1"]:focus:not(:focus-visible) {
outline:0!important
}

@ -69,6 +69,19 @@ body {
text-align:left;
background-color:#fff
}
*::-webkit-scrollbar {
width: 8px;
height: 6px;
background-color: var(--body-bg);
}
*::-webkit-scrollbar-thumb {
background-color: var(--secondary);
opacity: 0.3;
border-radius: 30px;
}
[tabindex="-1"]:focus:not(:focus-visible) {
outline:0!important
}

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

@ -14,7 +14,7 @@
--gray: #6c757d;
--gray-dark: #343a40;
--primary: #fc58a3;
--secondary: #e2f5f2;
--secondary: #c7e3de;
--success: #24b882;
--info: #00bbff;
--warning: #fabe33;
@ -76,6 +76,18 @@ body {
background-color: var(--body-bg);
}
*::-webkit-scrollbar {
width: 8px;
height: 6px;
background-color: var(--body-bg);
}
*::-webkit-scrollbar-thumb {
background-color: var(--secondary);
opacity: 0.3;
border-radius: 30px;
}
[tabindex="-1"]:focus {
outline: 0 !important;
}

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

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

@ -76,6 +76,18 @@ body {
background-color: var(--body-bg);
}
*::-webkit-scrollbar {
width: 8px;
height: 6px;
background-color: var(--body-bg);
}
*::-webkit-scrollbar-thumb {
background-color: var(--secondary);
opacity: 0.3;
border-radius: 30px;
}
[tabindex="-1"]:focus {
outline: 0 !important;
}

@ -76,6 +76,18 @@ body {
background-color: var(--body-bg);
}
*::-webkit-scrollbar {
width: 8px;
height: 6px;
background-color: var(--body-bg);
}
*::-webkit-scrollbar-thumb {
background-color: var(--secondary);
opacity: 0.3;
border-radius: 30px;
}
[tabindex="-1"]:focus {
outline: 0 !important;
}

@ -76,6 +76,18 @@ body {
background-color: var(--body-bg);
}
*::-webkit-scrollbar {
width: 8px;
height: 6px;
background-color: var(--body-bg);
}
*::-webkit-scrollbar-thumb {
background-color: var(--secondary);
opacity: 0.3;
border-radius: 30px;
}
[tabindex="-1"]:focus {
outline: 0 !important;
}

@ -76,6 +76,18 @@ body {
background-color: var(--body-bg);
}
*::-webkit-scrollbar {
width: 8px;
height: 6px;
background-color: var(--body-bg);
}
*::-webkit-scrollbar-thumb {
background-color: var(--secondary);
opacity: 0.3;
border-radius: 30px;
}
[tabindex="-1"]:focus {
outline: 0 !important;
}

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

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

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

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

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

@ -117,9 +117,9 @@ const App = () => {
<main id="vyper-plugin">
<section>
<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()}>
Clone Vyper examples repository
Clone a repo of Vyper examples
</Button>
</CustomTooltip>
</div>

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

@ -80,20 +80,20 @@ export class RemixClient extends PluginClient {
async cloneVyperRepo() {
try {
// @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(
'dGitProvider',
'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
'vyper-lang'
'snekmate'
)
this.call(
// @ts-ignore
'notification',
'toast',
'Vyper repository cloned, the workspace Vyper has been created.'
'Snekmate Vyper repository cloned, the workspace snekmate has been created.'
)
} catch (e) {
// @ts-ignore

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

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-analyzer",
"version": "0.5.56",
"version": "0.5.57",
"description": "Tool to perform static analysis on Solidity smart contracts",
"scripts": {
"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/util": "9.0.3",
"@ethereumjs/vm": "8.0.0",
"@remix-project/remix-astwalker": "^0.0.77",
"@remix-project/remix-lib": "^0.5.54",
"@remix-project/remix-astwalker": "^0.0.78",
"@remix-project/remix-lib": "^0.5.55",
"async": "^2.6.2",
"ethers": "^5.4.2",
"ethjs-util": "^0.1.6",
@ -50,6 +50,6 @@
"typescript": "^3.7.5"
},
"typings": "src/index.d.ts",
"gitHead": "65197fceebd45f013aefed3c4a90277cee7f2962",
"gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e",
"main": "./src/index.js"
}

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

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

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

@ -106,7 +106,6 @@ export class TxRunnerWeb3 {
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 (useCall) {
tx['gas'] = gasLimit
if (this._api && this._api.isVM()) {
(this.getWeb3() as any).remix.registerCallId(timestamp)
}
@ -137,8 +136,19 @@ export class TxRunnerWeb3 {
this.getWeb3().eth.estimateGas(txCopy)
.then(gasEstimation => {
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')) {
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"
gasEstimationForceSend(err, () => {
tx['gas'] = gasLimit
const defaultGasLimit = 3000000
tx['gas'] = gasLimit === '0x0' ? '0x' + defaultGasLimit.toString(16) : gasLimit
if (this._api.config.getUnpersistedProperty('doNotShowTransactionConfirmationAgain')) {
return this._executeTx(tx, network, null, this._api, promptCb, callback)

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

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

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

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

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

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

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

@ -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) => {
if (error) {
let msg = typeof error !== 'string' ? error.message : error
if (error && error.innerError) {
msg += '\n' + error.innerError
}
if (msg.includes('invalid opcode')) msg += '\n OR the EVM version used by the selected environment is not compatible with the compiler EVM version.'
if (msg.includes('invalid opcode')) msg += '\nThe EVM version used by the selected environment is not compatible with the compiler EVM version.'
dispatch(displayNotification('Gas estimation failed', gasEstimationPrompt(msg), 'Send Transaction', 'Cancel Transaction', () => {
continueTxExecution()

@ -14,6 +14,13 @@ import { shortenAddress } from "@remix-ui/helper"
const _paq = window._paq = window._paq || []
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.emit('newTransaction', tx, receipt)
})
@ -33,7 +40,6 @@ export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch<any>) => {
}
setFinalContext(plugin, dispatch)
fillAccountsList(plugin, dispatch)
await loadPinnedContracts(plugin, dispatch)
})
plugin.blockchain.event.register('networkStatus', async ({ error, network }) => {
@ -44,10 +50,18 @@ export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch<any>) => {
return
}
const networkProvider = plugin.networkModule.getNetworkProvider.bind(plugin.networkModule)
const netUI = !networkProvider().startsWith('vm') ? `${network.name} (${network.id || '-'}) network` : 'VM'
const pinnedChainId = !networkProvider().startsWith('vm') ? network.id : networkProvider()
const isVM = networkProvider().startsWith('vm') ? true : false
const netUI = !isVM ? `${network.name} (${network.id || '-'}) network` : 'VM'
const pinnedChainId = !isVM ? network.id : networkProvider()
setNetworkNameFromProvider(dispatch, netUI)
setPinnedChainId(dispatch, pinnedChainId)
// Check if provider is changed or network is changed for same provider e.g; Metamask
if (currentNetwork.provider !== networkProvider() || (!isVM && currentNetwork.chainId !== network.id)) {
currentNetwork.provider = networkProvider()
if (!isVM) currentNetwork.chainId = network.id
await loadPinnedContracts(plugin, dispatch, pinnedChainId)
}
})
plugin.blockchain.event.register('addProvider', provider => addExternalProvider(dispatch, provider))
@ -102,9 +116,29 @@ export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch<any>) => {
})
})
plugin.on('manager', 'pluginActivated', (plugin: Plugin) => {
if (plugin.name === 'remixd') {
plugin.on('manager', 'pluginActivated', (activatedPlugin: Plugin) => {
if (activatedPlugin.name === 'remixd') {
dispatch(setRemixDActivated(true))
} else {
if (activatedPlugin && activatedPlugin.name.startsWith('injected')) {
plugin.on(activatedPlugin.name, 'accountsChanged', (accounts: Array<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())
})
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(() => {
fillAccountsList(plugin, dispatch)
@ -166,10 +177,8 @@ export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch<any>) => {
}, 30000)
}
const loadPinnedContracts = async (plugin, dispatch) => {
const loadPinnedContracts = async (plugin, dispatch, dirName) => {
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}`)
if (isPinnedAvailable) {
try {

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

@ -1,24 +1,24 @@
// eslint-disable-next-line no-use-before-define
import React from 'react'
import {FormattedMessage} from 'react-intl'
import {EnvironmentProps} from '../types'
import {EnvironmentProps, Provider} from '../types'
import {Dropdown} from 'react-bootstrap'
import {CustomMenu, CustomToggle, CustomTooltip} from '@remix-ui/helper'
export function EnvironmentUI(props: EnvironmentProps) {
const handleChangeExEnv = (env: string) => {
const provider = props.providers.providerList.find((exEnv) => exEnv.value === env)
const context = provider.value
const provider = props.providers.providerList.find((exEnv) => exEnv.name === env)
const context = provider.name
props.setExecutionContext({context})
}
const currentProvider = props.providers.providerList.find((exEnv) => exEnv.value === props.selectedEnv)
const currentProvider = props.providers.providerList.find((exEnv) => exEnv.name === props.selectedEnv)
const bridges = {
'injected-optimism-provider': 'https://app.optimism.io/bridge/deposit',
'injected-arbitrum-one-provider': 'https://bridge.arbitrum.io/'
'L2 - Optimism': 'https://app.optimism.io/bridge/deposit',
'L2 - Arbitrum One': 'https://bridge.arbitrum.io/'
}
const isL2 = (provider) => provider && (provider.value === 'Optimism Provider' || provider.value === 'Arbitrum One Provider')
const isL2 = (providerDisplayName: string) => providerDisplayName === 'Optimism Provider' || providerDisplayName === 'Arbitrum One Provider'
return (
<div className="udapp_crow">
<label id="selectExEnv" className="udapp_settingsLabel">
@ -33,33 +33,33 @@ export function EnvironmentUI(props: EnvironmentProps) {
<div className="udapp_environment">
<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}>
{isL2(currentProvider) && 'L2 - '}
{currentProvider && currentProvider.content}
{currentProvider && bridges[currentProvider.value] && (
{isL2(currentProvider && currentProvider.displayName) && 'L2 - '}
{currentProvider && currentProvider.displayName}
{currentProvider && bridges[currentProvider.name] && (
<CustomTooltip placement={'right'} tooltipClasses="text-nowrap" tooltipId="info-recorder" tooltipText={<FormattedMessage id="udapp.tooltipText3" />}>
<i
style={{fontSize: 'medium'}}
className={'ml-2 fa fa-rocket-launch'}
aria-hidden="true"
onClick={() => {
window.open(bridges[currentProvider.value], '_blank')
window.open(bridges[currentProvider.name], '_blank')
}}
></i>
</CustomTooltip>
)}
</Dropdown.Toggle>
<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
key={index}
onClick={() => {
handleChangeExEnv(value)
handleChangeExEnv(name)
}}
data-id={`dropdown-item-${value}`}
data-id={`dropdown-item-${name}`}
>
<span className="">
{isL2({value}) && 'L2 - '}
{content}
{isL2(displayName) && 'L2 - '}
{displayName}
</span>
</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 {NetworkUI} from './network'
import {AccountUI} from './account'
import {GasPriceUI} from './gasPrice'
import {GasLimitUI} from './gasLimit'
import {ValueUI} from './value'
export function SettingsUI(props: SettingsProps) {
@ -27,7 +27,7 @@ export function SettingsUI(props: SettingsProps) {
signMessageWithAddress={props.signMessageWithAddress}
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} />
</div>
)

@ -297,7 +297,7 @@ export function UniversalDappUI(props: UdappProps) {
<label>
<b><FormattedMessage id="udapp.balance" />:</b> {instanceBalance} ETH
</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>
{ props.isPinnedContract && props.instance.pinnedAt ? (
<div className="d-flex" data-id="instanceContractPinnedAt">

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

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

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

@ -19,6 +19,23 @@ export interface Contract {
export interface ContractList {
[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 {
accounts: {
loadedAccounts: Record<string, string>,
@ -35,14 +52,7 @@ export interface RunTabState {
networkName: string,
chainId: string
providers: {
providerList: {
id?: string,
dataId?: string,
title?: string,
value: string,
fork?: string
content: string
}[],
providerList: Provider[],
isRequesting: boolean,
isSuccessful: boolean,
error: string
@ -138,14 +148,7 @@ export interface SettingsProps {
personalMode: boolean,
networkName: string,
providers: {
providerList: {
id?: string,
dataId?: string,
title?: string,
value: string,
fork?: string
content: string
}[],
providerList: Provider[],
isRequesting: boolean,
isSuccessful: boolean,
error: string
@ -164,14 +167,7 @@ export interface SettingsProps {
export interface EnvironmentProps {
selectedEnv: string,
providers: {
providerList: {
id?: string,
dataId?: string,
title?: string,
value: string,
fork?: string
content: string
}[],
providerList: Provider[],
isRequesting: boolean,
isSuccessful: boolean,
error: string

@ -8,5 +8,4 @@ declare class InjectedProvider {
getBalanceInEther(address: any): Promise<string>;
getGasPrice(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>;
getGasPrice(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>;
getGasPrice(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 { EventEmitter } from 'events';
import {Registry} from '@remix-project/remix-lib';
import { Registry } from '@remix-project/remix-lib';
export declare class AnalysisTab extends ViewPlugin {
event: EventManager;
events: EventEmitter;

@ -194,6 +194,16 @@ export function HamburgerMenu(props: HamburgerMenuProps) {
}}
platforms={[appPlatformTypes.web, appPlatformTypes.desktop]}
></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