git4refactor
filip mertens 8 months ago
commit 019ed19fc9
  1. 4
      .github/workflows/pr-reminder.yml
  2. 6
      apps/circuit-compiler/src/app/actions/index.ts
  3. 16
      apps/circuit-compiler/src/app/components/witness.tsx
  4. 4
      apps/learneth/README.md
  5. 1
      apps/learneth/src/redux/models/workshop.ts
  6. 4
      apps/remix-ide-e2e/package.json
  7. 2
      apps/remix-ide-e2e/src/commands/openFile.ts
  8. 1
      apps/remix-ide-e2e/src/local-plugin/src/app/app.tsx
  9. 34
      apps/remix-ide-e2e/src/tests/debugger.test.ts
  10. 51
      apps/remix-ide-e2e/src/tests/eip1153.test.ts
  11. 4
      apps/remix-ide-e2e/src/tests/etherscan_api.test.ts
  12. 2
      apps/remix-ide-e2e/src/tests/generalSettings.test.ts
  13. 42
      apps/remix-ide-e2e/src/tests/gist.test.ts
  14. 353
      apps/remix-ide-e2e/src/tests/proxy_oz_v5_non_shanghai_runtime.test.ts
  15. 117
      apps/remix-ide-e2e/src/tests/runAndDeploy.test.ts
  16. 4
      apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts
  17. 2
      apps/remix-ide-e2e/src/tests/specialFunctions.test.ts
  18. 2
      apps/remix-ide-e2e/src/tests/terminal.test.ts
  19. 40
      apps/remix-ide-e2e/src/tests/url.test.ts
  20. 2
      apps/remix-ide-e2e/src/tests/vyper_api.test.ts
  21. 22
      apps/remix-ide-e2e/yarn.lock
  22. 53
      apps/remix-ide/ci/downloadsoljson.sh
  23. 4
      apps/remix-ide/src/app.js
  24. 3
      apps/remix-ide/src/app/editor/editor.js
  25. 10
      apps/remix-ide/src/app/files/fileManager.ts
  26. 16
      apps/remix-ide/src/app/panels/tab-proxy.js
  27. 41
      apps/remix-ide/src/app/panels/terminal.tsx
  28. 2
      apps/remix-ide/src/app/providers/abstract-provider.tsx
  29. 6
      apps/remix-ide/src/app/providers/mainnet-vm-fork-provider.tsx
  30. 4
      apps/remix-ide/src/app/providers/sepolia-vm-fork-provider.tsx
  31. 26
      apps/remix-ide/src/app/providers/vm-provider.tsx
  32. 4
      apps/remix-ide/src/app/tabs/locales/en/filePanel.json
  33. 6
      apps/remix-ide/src/app/tabs/locales/en/settings.json
  34. 4
      apps/remix-ide/src/app/tabs/locales/en/terminal.json
  35. 17
      apps/remix-ide/src/app/tabs/locales/en/udapp.json
  36. 2
      apps/remix-ide/src/app/tabs/locales/es/filePanel.json
  37. 3
      apps/remix-ide/src/app/tabs/locales/es/settings.json
  38. 2
      apps/remix-ide/src/app/tabs/locales/es/udapp.json
  39. 2
      apps/remix-ide/src/app/tabs/locales/fr/filePanel.json
  40. 3
      apps/remix-ide/src/app/tabs/locales/fr/settings.json
  41. 2
      apps/remix-ide/src/app/tabs/locales/fr/udapp.json
  42. 2
      apps/remix-ide/src/app/tabs/locales/it/filePanel.json
  43. 3
      apps/remix-ide/src/app/tabs/locales/it/settings.json
  44. 2
      apps/remix-ide/src/app/tabs/locales/it/udapp.json
  45. 2
      apps/remix-ide/src/app/tabs/locales/zh/filePanel.json
  46. 3
      apps/remix-ide/src/app/tabs/locales/zh/settings.json
  47. 2
      apps/remix-ide/src/app/tabs/locales/zh/udapp.json
  48. 6
      apps/remix-ide/src/app/tabs/runTab/model/recorder.js
  49. 18
      apps/remix-ide/src/app/tabs/web3-provider.js
  50. 23
      apps/remix-ide/src/app/udapp/run-tab.js
  51. BIN
      apps/remix-ide/src/assets/img/vyperLogo2.webp
  52. 15
      apps/remix-ide/src/assets/list.json
  53. 46
      apps/remix-ide/src/blockchain/blockchain.tsx
  54. 102
      apps/remix-ide/src/blockchain/execution-context.js
  55. 4
      apps/remix-ide/src/blockchain/providers/injected.ts
  56. 6
      apps/remix-ide/src/blockchain/providers/node.ts
  57. 37
      apps/remix-ide/src/blockchain/providers/vm.ts
  58. 2
      apps/remix-ide/src/blockchain/providers/worker-vm.ts
  59. 4
      apps/remix-ide/src/lib/helper.js
  60. 4
      apps/remix-ide/src/remixAppManager.js
  61. 2
      apps/remix-ide/src/remixEngine.js
  62. 2
      apps/remix-ide/team-best-practices.md
  63. 20
      apps/remix-ide/webpack.config.js
  64. 2
      apps/remixdesktop/package.json
  65. 89
      apps/remixdesktop/yarn.lock
  66. 2
      apps/solhint/src/profile.json
  67. 6
      apps/solhint/yarn.lock
  68. 44
      apps/vyper/src/app/app.css
  69. 81
      apps/vyper/src/app/app.tsx
  70. 23
      apps/vyper/src/app/components/CompileErrorCard.tsx
  71. 2
      apps/vyper/src/app/components/CompilerButton.tsx
  72. 26
      apps/vyper/src/app/components/CustomAccordionToggle.tsx
  73. 17
      apps/vyper/src/app/components/VyperResult.tsx
  74. 192
      apps/vyper/src/app/utils/compiler.tsx
  75. 18
      apps/vyper/src/app/utils/remix-client.tsx
  76. 4
      apps/vyper/src/index.html
  77. 6
      apps/vyper/src/profile.json
  78. 8
      libs/ghaction-helper/package.json
  79. 16
      libs/remix-analyzer/package.json
  80. 14
      libs/remix-astwalker/package.json
  81. 1
      libs/remix-core-plugin/src/index.ts
  82. 6
      libs/remix-core-plugin/src/lib/compiler-fetch-and-compile.ts
  83. 6
      libs/remix-core-plugin/src/lib/constants/uups.ts
  84. 7
      libs/remix-core-plugin/src/lib/gist-handler.ts
  85. 66
      libs/remix-core-plugin/src/lib/helpers/fetch-blockscout.ts
  86. 22
      libs/remix-debug/package.json
  87. 9
      libs/remix-debug/src/code/codeUtils.ts
  88. 4
      libs/remix-debug/src/code/disassembler.ts
  89. 10
      libs/remix-debug/src/solidity-decoder/types/Mapping.ts
  90. 6
      libs/remix-debug/src/solidity-decoder/types/util.ts
  91. 2
      libs/remix-debug/src/trace/traceHelper.ts
  92. 2
      libs/remix-debug/src/trace/traceManager.ts
  93. 2
      libs/remix-debug/test/decoder/stateTests/mapping.ts
  94. 6
      libs/remix-lib/package.json
  95. 10
      libs/remix-lib/src/execution/forkAt.ts
  96. 21
      libs/remix-lib/src/execution/logsManager.ts
  97. 2
      libs/remix-lib/src/execution/txFormat.ts
  98. 8
      libs/remix-lib/src/execution/txListener.ts
  99. 90
      libs/remix-lib/src/execution/txRunnerVM.ts
  100. 4
      libs/remix-lib/src/execution/typeConversion.ts
  101. Some files were not shown because too many files have changed in this diff Show More

@ -2,7 +2,7 @@ name: PRs reviews reminder
on: on:
schedule: schedule:
- cron: "0 8-17/8 * * 1-5" - cron: "0 8 * * 1-5"
workflow_dispatch: workflow_dispatch:
jobs: jobs:
@ -14,4 +14,4 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
freeze-date: '2024-02-26T18:00:00Z' freeze-date: '2024-04-08T18:00:00Z'

@ -6,7 +6,7 @@ export const compileCircuit = async (plugin: CircomPluginClient, appState: AppSt
if (appState.status !== "compiling") { if (appState.status !== "compiling") {
await plugin.compile(appState.filePath, { version: appState.version, prime: appState.primeValue }) await plugin.compile(appState.filePath, { version: appState.version, prime: appState.primeValue })
} else { } else {
console.log('Exisiting circuit compilation in progress') console.log('Existing circuit compilation in progress')
} }
} catch (e) { } catch (e) {
plugin.internalEvents.emit('circuit_compiling_errored', e) plugin.internalEvents.emit('circuit_compiling_errored', e)
@ -19,7 +19,7 @@ export const generateR1cs = async (plugin: CircomPluginClient, appState: AppStat
if (appState.status !== "generating") { if (appState.status !== "generating") {
await plugin.generateR1cs(appState.filePath, { version: appState.version, prime: appState.primeValue }) await plugin.generateR1cs(appState.filePath, { version: appState.version, prime: appState.primeValue })
} else { } else {
console.log('Exisiting r1cs generation in progress') console.log('Existing r1cs generation in progress')
} }
} catch (e) { } catch (e) {
plugin.internalEvents.emit('circuit_generating_r1cs_errored', e) plugin.internalEvents.emit('circuit_generating_r1cs_errored', e)
@ -34,7 +34,7 @@ export const computeWitness = async (plugin: CircomPluginClient, status: string,
await plugin.computeWitness(input) await plugin.computeWitness(input)
} else { } else {
console.log('Exisiting witness computation in progress') console.log('Existing witness computation in progress')
} }
} catch (e) { } catch (e) {
plugin.internalEvents.emit('circuit_computing_witness_errored', e) plugin.internalEvents.emit('circuit_computing_witness_errored', e)

@ -12,10 +12,20 @@ export function WitnessSection ({ plugin, signalInputs, status }: {plugin: Circo
const handleSignalInput = (e: any) => { const handleSignalInput = (e: any) => {
let value = e.target.value let value = e.target.value
try { if (value.startsWith('[') && value.endsWith(']')) {
value = remixLib.execution.txFormat.parseFunctionParams(value) try {
} catch (e) { value = remixLib.execution.txFormat.parseFunctionParams(value)
} catch (e) {
// do nothing // do nothing
}
} else if (value.startsWith('[') && !value.endsWith(']')) {
// do nothing
} else {
try {
value = remixLib.execution.txFormat.parseFunctionParams(value)
} catch (e) {
// do nothing
}
} }
setWitnessValues({ setWitnessValues({
...witnessValues, ...witnessValues,

@ -92,7 +92,7 @@ addRepository(repoName, branch)
startTutorial(repoName,branch,id) startTutorial(repoName,branch,id)
``` ```
You don't need to add a seperate addRepository before calling startTutorial, this call will also add the repo. You don't need to add a separate addRepository before calling startTutorial, this call will also add the repo.
_Parameters_ _Parameters_
@ -117,7 +117,7 @@ tags:
``` ```
(function () { (function () {
try { try {
// You don't need to add a seperate addRepository before calling startTutorial, this is just an example // You don't need to add a separate addRepository before calling startTutorial, this is just an example
remix.call('LearnEth', 'addRepository', "ethereum/remix-workshops", "master") remix.call('LearnEth', 'addRepository', "ethereum/remix-workshops", "master")
remix.call('LearnEth', 'startTutorial', "ethereum/remix-workshops", "master", "basics") remix.call('LearnEth', 'startTutorial', "ethereum/remix-workshops", "master", "basics")
remix.call('LearnEth', 'startTutorial', "ethereum/remix-workshops", "master", 2) remix.call('LearnEth', 'startTutorial', "ethereum/remix-workshops", "master", 2)

@ -56,7 +56,6 @@ const Model: ModelType = {
const url = `${apiUrl}/clone/${encodeURIComponent(payload.name)}/${payload.branch}?${Math.random()}` const url = `${apiUrl}/clone/${encodeURIComponent(payload.name)}/${payload.branch}?${Math.random()}`
console.log('loading ', url) console.log('loading ', url)
const {data} = yield axios.get(url) const {data} = yield axios.get(url)
console.log(data)
const repoId = `${payload.name}-${payload.branch}` const repoId = `${payload.name}-${payload.branch}`
for (let i = 0; i < data.ids.length; i++) { for (let i = 0; i < data.ids.length; i++) {

@ -6,8 +6,8 @@
"npm": "^6.14.15" "npm": "^6.14.15"
}, },
"dependencies": { "dependencies": {
"@openzeppelin/contracts": "^5.0.0", "@openzeppelin/contracts": "^5.0.2",
"@openzeppelin/contracts-upgradeable": "^5.0.0", "@openzeppelin/contracts-upgradeable": "^5.0.2",
"@openzeppelin/upgrades-core": "^1.30.0", "@openzeppelin/upgrades-core": "^1.30.0",
"@openzeppelin/wizard": "^0.4.0", "@openzeppelin/wizard": "^0.4.0",
"@remix-project/remixd": "../../dist/libs/remixd", "@remix-project/remixd": "../../dist/libs/remixd",

@ -21,7 +21,7 @@ function openFile (browser: NightwatchBrowser, name: string, done: VoidFunction)
// if side panel is shown, check this is the file panel // if side panel is shown, check this is the file panel
browser.element('css selector', '[data-id="verticalIconsKindfilePanel"] img[data-id="selected"]', (result) => { browser.element('css selector', '[data-id="verticalIconsKindfilePanel"] img[data-id="selected"]', (result) => {
if (result.status === 0) { if (result.status === 0) {
done() done()
} else browser.clickLaunchIcon('filePanel').perform(() => { } else browser.clickLaunchIcon('filePanel').perform(() => {
done() done()
}) })

@ -46,7 +46,6 @@ function App() {
const customProfiles = ['menuicons', 'tabs', 'solidityUnitTesting', 'hardhat-provider', 'notification'] const customProfiles = ['menuicons', 'tabs', 'solidityUnitTesting', 'hardhat-provider', 'notification']
client.testCommand = async (data: any) => { client.testCommand = async (data: any) => {
console.log(data)
methodLog(data) methodLog(data)
} }

@ -95,7 +95,7 @@ module.exports = {
.waitForElementVisible('#stepdetail') .waitForElementVisible('#stepdetail')
.waitForElementVisible({ .waitForElementVisible({
locateStrategy: 'xpath', locateStrategy: 'xpath',
selector: '//*[@data-id="treeViewLivm trace step" and contains(.,"531")]', selector: '//*[@data-id="treeViewLivm trace step" and contains(.,"475")]',
}) })
.getEditorValue((content) => { .getEditorValue((content) => {
browser.assert.ok(content.indexOf(`constructor (string memory name_, string memory symbol_) { browser.assert.ok(content.indexOf(`constructor (string memory name_, string memory symbol_) {
@ -206,16 +206,40 @@ module.exports = {
}, },
// depends on Should debug using generated sources // depends on Should debug using generated sources
'Should call the debugger api: getTrace #group4': function (browser: NightwatchBrowser) { 'Should call the debugger api: getTrace #group4': function (browser: NightwatchBrowser) {
let txhash
browser browser
.addFile('test_jsGetTrace.js', { content: jsGetTrace }) .clickLaunchIcon('udapp')
.perform((done) => {
browser.getLastTransactionHash((hash) => {
txhash = hash
done()
})
})
.perform((done) => {
browser.addFile('test_jsGetTrace.js', { content: jsGetTrace.replace('<txhash>', txhash) }).perform(() => {
done()
})
})
.executeScriptInTerminal('remix.exeCurrent()') .executeScriptInTerminal('remix.exeCurrent()')
.pause(3000) .pause(3000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '{"gas":"0x5752","return":"0x0000000000000000000000000000000000000000000000000000000000000000","structLogs":', 60000) .waitForElementContainsText('*[data-id="terminalJournal"]', '{"gas":"0x5752","return":"0x0000000000000000000000000000000000000000000000000000000000000000","structLogs":', 60000)
}, },
// depends on Should debug using generated sources // depends on Should debug using generated sources
'Should call the debugger api: debug #group4': function (browser: NightwatchBrowser) { 'Should call the debugger api: debug #group4': function (browser: NightwatchBrowser) {
let txhash
browser browser
.addFile('test_jsDebug.js', { content: jsDebug }) .clickLaunchIcon('udapp')
.perform((done) => {
browser.getLastTransactionHash((hash) => {
txhash = hash
done()
})
})
.perform((done) => {
browser.addFile('test_jsDebug.js', { content: jsDebug.replace('<txhash>', txhash) }).perform(() => {
done()
})
})
.executeScriptInTerminal('remix.exeCurrent()') .executeScriptInTerminal('remix.exeCurrent()')
.pause(3000) .pause(3000)
.clickLaunchIcon('debugger') .clickLaunchIcon('debugger')
@ -495,7 +519,7 @@ const localVariable_step717_ABIEncoder = { // eslint-disable-line
const jsGetTrace = `(async () => { const jsGetTrace = `(async () => {
try { try {
const result = await remix.call('debugger', 'getTrace', '0x00a9f5b1ac2c9cb93e5890ea86c81efbd36b619ef2378136ef74d8c6171ddda6') const result = await remix.call('debugger', 'getTrace', '<txhash>')
console.log('result ', result) console.log('result ', result)
} catch (e) { } catch (e) {
console.log(e.message) console.log(e.message)
@ -504,7 +528,7 @@ const jsGetTrace = `(async () => {
const jsDebug = `(async () => { const jsDebug = `(async () => {
try { try {
const result = await remix.call('debugger', 'debug', '0x00a9f5b1ac2c9cb93e5890ea86c81efbd36b619ef2378136ef74d8c6171ddda6') const result = await remix.call('debugger', 'debug', '<txhash>')
console.log('result ', result) console.log('result ', result)
} catch (e) { } catch (e) {
console.log(e.message) console.log(e.message)

@ -0,0 +1,51 @@
'use strict'
import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
'Should execute a contract that uses transient storage #group1': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('udapp')
.switchEnvironment('vm-cancun') // switch to a vm that know this eip.
.addFile('transient_storage.sol', { content: contractTransientStorage })
.clickLaunchIcon('solidity')
.setSolidityCompilerVersion('soljson-v0.8.24+commit.e11b9ed9.js')
.click('*[data-id="scConfigExpander"]')
.setValue('#evmVersionSelector', 'cancun') // set target compilation to cancun
.clickLaunchIcon('solidity')
.verifyContracts(['TestTransientStorage'])
.clickLaunchIcon('udapp')
.createContract('')
.clickInstance(0)
.clickFunction('useTransientStorage - transact (not payable)')
.testFunction('last',
{
status: '0x1 Transaction mined and execution succeed',
'decoded output': {
0: 'uint256: out1 14',
1: 'uint256: out2 15'
}
})
.end()
}
}
const contractTransientStorage = `// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.2 <0.9.0;
contract TestTransientStorage {
function useTransientStorage() public returns (uint out1, uint out2) {
assembly {
tstore(0, 14)
tstore(1, 15)
out1 := tload(0)
out2 := tload(1)
}
}
}`

@ -33,7 +33,7 @@ module.exports = {
.execute(() => { .execute(() => {
(document.querySelector('*[data-id="basic-http-providerModalDialogContainer-react"] input[data-id="modalDialogCustomPromp"]') as any).focus() (document.querySelector('*[data-id="basic-http-providerModalDialogContainer-react"] input[data-id="modalDialogCustomPromp"]') as any).focus()
}, [], () => {}) }, [], () => {})
.setValue('[data-id="modalDialogCustomPromp"]', 'https://remix-goerli.ethdevops.io') .setValue('[data-id="modalDialogCustomPromp"]', 'https://go.getblock.io/ee42d0a88f314707be11dd799b122cb9') // sepolia
.modalFooterOKClick('basic-http-provider') .modalFooterOKClick('basic-http-provider')
.clickLaunchIcon('solidity') // compile .clickLaunchIcon('solidity') // compile
.testContracts('Owner_1.sol', { content: verifiedContract }, ['Owner']) .testContracts('Owner_1.sol', { content: verifiedContract }, ['Owner'])
@ -42,7 +42,7 @@ module.exports = {
.frame(0) .frame(0)
.click('[data-id="home"]') .click('[data-id="home"]')
.setValue('select[name="contractName"]', 'Owner') .setValue('select[name="contractName"]', 'Owner')
.setValue('*[name="contractAddress"]', ['0x9981c9d00103da481c3c65b22a79582a3e3ff50b', browser.Keys.TAB]) .setValue('*[name="contractAddress"]', ['0xfF6A41815582cFD18855c5B90efD1d45784fd4f5', browser.Keys.TAB])
.click('[data-id="verify-contract"]') .click('[data-id="verify-contract"]')
.waitForElementVisible('[data-id="verify-result"]') .waitForElementVisible('[data-id="verify-result"]')
.waitForElementContainsText('[data-id="verify-result"]', 'Contract source code already verified', 15000) .waitForElementContainsText('[data-id="verify-result"]', 'Contract source code already verified', 15000)

@ -152,7 +152,7 @@ module.exports = {
.scrollAndClick('*[data-id="settingsTabLocaleLabelen"]') .scrollAndClick('*[data-id="settingsTabLocaleLabelen"]')
.pause(2000) .pause(2000)
.assert.containsText('*[data-id="sidePanelSwapitTitle"]', 'SETTINGS') .assert.containsText('*[data-id="sidePanelSwapitTitle"]', 'SETTINGS')
.assert.containsText('*[data-id="listenNetworkCheckInput"]', 'listen on all transactions') .assert.containsText('*[data-id="listenNetworkCheckInput"]', 'Listen on all transactions')
.assert.containsText('*[data-id="settingsTabGenerateContractMetadataLabel"]', 'Generate contract metadata') .assert.containsText('*[data-id="settingsTabGenerateContractMetadataLabel"]', 'Generate contract metadata')
.assert.containsText('*[data-id="settingsAutoCompleteLabel"]', 'Enable code completion in editor') .assert.containsText('*[data-id="settingsAutoCompleteLabel"]', 'Enable code completion in editor')
.assert.containsText('*[data-id="settingsShowGasLabel"]', 'Display gas estimates in editor') .assert.containsText('*[data-id="settingsShowGasLabel"]', 'Display gas estimates in editor')

@ -38,7 +38,7 @@ module.exports = {
.executeScriptInTerminal(`remix.loadgist('${gistid}')`) .executeScriptInTerminal(`remix.loadgist('${gistid}')`)
// .perform((done) => { if (runtimeBrowser === 'chrome') { browser.openFile('gists') } done() }) // .perform((done) => { if (runtimeBrowser === 'chrome') { browser.openFile('gists') } done() })
.waitForElementVisible(`[data-id="treeViewLitreeViewItemREADME.txt"]`) .waitForElementVisible(`[data-id="treeViewLitreeViewItemREADME.txt"]`)
.openFile(`README.txt`) .openFile(`README.txt`)
// Remix publish to gist // Remix publish to gist
/* .click('*[data-id="fileExplorerNewFilepublishToGist"]') /* .click('*[data-id="fileExplorerNewFilepublishToGist"]')
@ -111,7 +111,7 @@ module.exports = {
.click('[data-id="settingsTabRemoveGistToken"]') .click('[data-id="settingsTabRemoveGistToken"]')
.clickLaunchIcon('filePanel') .clickLaunchIcon('filePanel')
.click('*[data-id="workspacesMenuDropdown"]') .click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacepublishToGist"]') .click('*[data-id="workspacepublishToGist"]')
.waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
.execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() }) .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
.pause(10000) .pause(10000)
@ -145,24 +145,24 @@ module.exports = {
.openFile(`README.txt`) .openFile(`README.txt`)
.waitForElementVisible(`div[data-path='gist ${testData.validGistId}/README.txt']`) .waitForElementVisible(`div[data-path='gist ${testData.validGistId}/README.txt']`)
.assert.containsText(`div[data-path='gist ${testData.validGistId}/README.txt'] > span`, 'README.txt') .assert.containsText(`div[data-path='gist ${testData.validGistId}/README.txt'] > span`, 'README.txt')
}, },
'Load Gist from URL and verify truncated files are loaded #group3': function (browser: NightwatchBrowser) { 'Load Gist from URL and verify truncated files are loaded #group3': function (browser: NightwatchBrowser) {
const gistId = '1b179bf1b92c8b0664b4cbe61774e15d' const gistId = '1b179bf1b92c8b0664b4cbe61774e15d'
browser browser
.url('http://127.0.0.1:8080/#gist=' + gistId) // loading the gist .url('http://127.0.0.1:8080/#gist=' + gistId) // loading the gist
.refreshPage() .refreshPage()
.currentWorkspaceIs('gist ' + gistId) .currentWorkspaceIs('gist ' + gistId)
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 15000) .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 15000)
.waitForElementVisible(`#fileExplorerView li[data-path='contracts']`, 30000) .waitForElementVisible(`#fileExplorerView li[data-path='contracts']`, 30000)
.openFile(`contracts/2_Owner.sol`) .openFile(`contracts/2_Owner.sol`)
.getEditorValue((content) => { .getEditorValue((content) => {
browser.assert.ok(content.indexOf('contract Owner {') !== -1) browser.assert.ok(content.indexOf('contract Owner {') !== -1)
}) })
.click('*[data-id="workspacesMenuDropdown"]') .click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacepublishToGist"]') .click('*[data-id="workspacepublishToGist"]')
.modalFooterOKClick('fileSystem') .modalFooterOKClick('fileSystem')
.waitForElementVisible('*[data-shared="tooltipPopup"]', 5000) .waitForElementVisible('*[data-shared="tooltipPopup"]', 5000)
.assert.containsText('*[data-shared="tooltipPopup"]', 'Saving gist (' + gistId + ') ...') .assert.containsText('*[data-shared="tooltipPopup"]', 'Saving gist (' + gistId + ') ...')
} }
} }

@ -0,0 +1,353 @@
'use strict'
import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
let firstProxyAddress: string
let lastProxyAddress: string
let shortenedFirstAddress: string
let shortenedLastAddress: string
module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
'@sources': function () {
return sources
},
'Should show deploy proxy option for UUPS upgradeable contract #group1': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('udapp')
.switchEnvironment('vm-paris') // this runtime doesn't have the PUSH0 opcode.
.clickLaunchIcon('solidity')
.click('.remixui_compilerConfigSection')
.setValue('#evmVersionSelector', 'paris') // set an evm version which doesn't have PUSH0 opcode.
.clickLaunchIcon('filePanel')
.addFile('myTokenV1.sol', sources[0]['myTokenV1.sol'])
.clickLaunchIcon('solidity')
.pause(2000)
// because the compilatiom imports are slow and sometimes stop loading (not sure why, it's bug) we need to recompile and check to see if the files are really in de FS
.click('[data-id="compilerContainerCompileBtn"]')
.clickLaunchIcon('filePanel')
.isVisible({
selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"]',
timeout: 120000,
suppressNotFoundErrors: true
})
.clickLaunchIcon('solidity')
.click('[data-id="compilerContainerCompileBtn"]')
.clickLaunchIcon('filePanel')
.isVisible({
selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"]',
timeout: 120000,
suppressNotFoundErrors: true
})
.clickLaunchIcon('solidity')
.click('[data-id="compilerContainerCompileBtn"]')
.clickLaunchIcon('filePanel')
.waitForElementVisible({
selector: '*[data-id="treeViewDivtreeViewItem.deps/npm/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"]',
timeout: 120000,
})
.clickLaunchIcon('solidity')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyToken]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyToken]')
.waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]')
.waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]')
},
'Should show upgrade proxy option for child contract inheriting UUPS parent contract #group1': function (browser: NightwatchBrowser) {
browser
.addFile('myTokenV2.sol', sources[1]['myTokenV2.sol'])
.clickLaunchIcon('solidity')
.assert.visible('[data-id="compilerContainerCompileBtn"]')
.click('[data-id="compilerContainerCompileBtn"]')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyTokenV2]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyTokenV2]')
.waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]')
.waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]')
},
'Should deploy proxy without initialize parameters #group1': function (browser: NightwatchBrowser) {
browser
.openFile('myTokenV1.sol')
.clickLaunchIcon('solidity')
.assert.visible('[data-id="compilerContainerCompileBtn"]')
.click('[data-id="compilerContainerCompileBtn"]')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyToken]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyToken]')
.verify.visible('[data-id="contractGUIDeployWithProxyLabel"]')
.waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]')
.click('[data-id="contractGUIDeployWithProxyLabel"]')
.setValue('[data-id="initializeInputs-initialOwner"]', '0x5B38Da6a701c568545dCfcB03FcB875f56beddC4')
.createContract('')
.waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Proxy (ERC1967)')
.waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]')
.click('[data-id="udappNotify-modal-footer-ok-react"]')
.waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Deploy Proxy (ERC1967)')
.waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Deploying ERC1967 >= 5.0.0 as proxy...')
},
'Should interact with deployed contract via ERC1967 (proxy) #group1': function (browser: NightwatchBrowser) {
browser
.getAddressAtPosition(1, (address) => {
firstProxyAddress = address
shortenedFirstAddress = address.slice(0, 5) + '...' + address.slice(address.length - 5, address.length)
})
.clickInstance(1)
.perform((done) => {
browser.testConstantFunction(firstProxyAddress, 'name - call', null, '0:\nstring: MyToken').perform(() => {
done()
})
})
.perform((done) => {
browser.testConstantFunction(firstProxyAddress, 'symbol - call', null, '0:\nstring: MTK').perform(() => {
done()
})
})
},
'Should deploy proxy with initialize parameters #group1': function (browser: NightwatchBrowser) {
browser
.waitForElementPresent('[data-id="deployAndRunClearInstances"]')
.click('[data-id="deployAndRunClearInstances"]')
.addFile('initializeProxy.sol', sources[2]['initializeProxy.sol'])
.clickLaunchIcon('solidity')
.assert.visible('[data-id="compilerContainerCompileBtn"]')
.click('[data-id="compilerContainerCompileBtn"]')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyInitializedToken]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyInitializedToken]')
.waitForElementPresent('[data-id="contractGUIDeployWithProxyLabel"]')
.click('[data-id="contractGUIDeployWithProxyLabel"]')
.useXpath()
.waitForElementPresent('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[1]/input')
.waitForElementPresent('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[2]/input')
.setValue('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[1]/input', 'Remix')
.setValue('//*[@id="runTabView"]/div/div[2]/div[3]/div[1]/div/div[1]/div[4]/div/div[2]/input', "R")
.useCss()
.setValue('[data-id="initializeInputs-initialOwner"]', '0x5B38Da6a701c568545dCfcB03FcB875f56beddC4')
.createContract('')
.waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Proxy (ERC1967)')
.waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]')
.click('[data-id="udappNotify-modal-footer-ok-react"]')
.waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Deploy Proxy (ERC1967)')
.waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Deploying ERC1967 >= 5.0.0 as proxy...')
},
'Should interact with initialized contract to verify parameters #group1': function (browser: NightwatchBrowser) {
browser
.getAddressAtPosition(1, (address) => {
lastProxyAddress = address
shortenedLastAddress = address.slice(0, 5) + '...' + address.slice(address.length - 5, address.length)
})
.clickInstance(1)
.perform((done) => {
browser.testConstantFunction(lastProxyAddress, 'name - call', null, '0:\nstring: Remix').perform(() => {
done()
})
})
.perform((done) => {
browser.testConstantFunction(lastProxyAddress, 'symbol - call', null, '0:\nstring: R').perform(() => {
done()
})
})
},
'Should upgrade contract by selecting a previously deployed proxy address from dropdown (MyTokenV1 to MyTokenV2) #group1': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="terminalClearConsole"]')
.waitForElementPresent('[data-id="deployAndRunClearInstances"]')
.click('[data-id="deployAndRunClearInstances"]')
.openFile('myTokenV2.sol')
.clickLaunchIcon('solidity')
.assert.visible('[data-id="compilerContainerCompileBtn"]')
.click('[data-id="compilerContainerCompileBtn"]')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyTokenV2]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyTokenV2]')
.waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]')
.click('[data-id="contractGUIUpgradeImplementationLabel"]')
.waitForElementPresent('[data-id="toggleProxyAddressDropdown"]')
.click('[data-id="toggleProxyAddressDropdown"]')
.waitForElementVisible('[data-id="proxy-dropdown-items"]')
.assert.textContains('[data-id="proxy-dropdown-items"]', shortenedFirstAddress)
.assert.textContains('[data-id="proxy-dropdown-items"]', shortenedLastAddress)
.click('[data-id="proxyAddress1"]')
.createContract('')
.waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Update Proxy')
.waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]')
.click('[data-id="udappNotify-modal-footer-ok-react"]')
.waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Update Proxy (ERC1967)')
.waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.click(
{
selector: '[data-id="confirmProxyDeployment-modal-footer-ok-react"]',
})
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Using ERC1967 >= 5.0.0 for the proxy upgrade...')
},
'Should interact with upgraded function in contract MyTokenV2 #group1': function (browser: NightwatchBrowser) {
browser
.clickInstance(1)
.perform((done) => {
browser.testConstantFunction(lastProxyAddress, 'version - call', null, '0:\nstring: MyTokenV2!').perform(() => {
done()
})
})
},
'Should upgrade contract by providing proxy address in input field (MyTokenV1 to MyTokenV2) #group1': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="terminalClearConsole"]')
.waitForElementPresent('[data-id="deployAndRunClearInstances"]')
.click('[data-id="deployAndRunClearInstances"]')
.openFile('myTokenV2.sol')
.clickLaunchIcon('solidity')
.assert.visible('[data-id="compilerContainerCompileBtn"]')
.click('[data-id="compilerContainerCompileBtn"]')
.waitForElementPresent('select[id="compiledContracts"] option[value=MyTokenV2]', 60000)
.clickLaunchIcon('udapp')
.click('select.udapp_contractNames')
.click('select.udapp_contractNames option[value=MyTokenV2]')
.waitForElementPresent('[data-id="contractGUIUpgradeImplementationLabel"]')
.waitForElementPresent('[data-id="toggleProxyAddressDropdown"]')
.clearValue('[data-id="ERC1967AddressInput"]')
.setValue('[data-id="ERC1967AddressInput"]', firstProxyAddress)
.createContract('')
.waitForElementContainsText('[data-id="udappNotifyModalDialogModalTitle-react"]', 'Deploy Implementation & Update Proxy')
.waitForElementVisible('[data-id="udappNotify-modal-footer-ok-react"]')
.click('[data-id="udappNotify-modal-footer-ok-react"]')
.waitForElementContainsText('[data-id="confirmProxyDeploymentModalDialogModalTitle-react"]', 'Confirm Update Proxy (ERC1967)')
.waitForElementVisible('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.click('[data-id="confirmProxyDeployment-modal-footer-ok-react"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander0"]')
.waitForElementPresent('[data-id="universalDappUiTitleExpander1"]')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Using ERC1967 >= 5.0.0 for the proxy upgrade...')
},
'Should interact with upgraded contract through provided proxy address #group1': function (browser: NightwatchBrowser) {
browser
.clearConsole()
.clickInstance(1)
.perform((done) => {
browser.testConstantFunction(firstProxyAddress, 'version - call', null, '0:\nstring: MyTokenV2!').perform(() => {
done()
})
})
},
'Should debug the call': function(browser: NightwatchBrowser) {
browser
.debugTransaction(0)
.waitForElementVisible({
locateStrategy: 'xpath',
selector: '//*[@data-id="treeViewLivm trace step" and contains(.,"7")]',
timeout: 60000
})
.goToVMTraceStep(129)
.waitForElementContainsText('*[data-id="functionPanel"]', 'version()', 60000)
.end()
}
}
const sources = [
{
'myTokenV1.sol': {
content: `
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
contract MyToken is Initializable, ERC721Upgradeable, OwnableUpgradeable, UUPSUpgradeable {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(address initialOwner) initializer public {
__ERC721_init("MyToken", "MTK");
__Ownable_init(initialOwner);
__UUPSUpgradeable_init();
}
function _authorizeUpgrade(address newImplementation)
internal
onlyOwner
override
{}
}
`
}
}, {
'myTokenV2.sol': {
content: `
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./myTokenV1.sol";
contract MyTokenV2 is MyToken {
function version () public view returns (string memory) {
return "MyTokenV2!";
}
}
`
}
}, {
'initializeProxy.sol': {
content: `
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
contract MyInitializedToken is Initializable, ERC721Upgradeable, OwnableUpgradeable, UUPSUpgradeable {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(string memory tokenName, string memory tokenSymbol, address initialOwner) initializer public {
__ERC721_init(tokenName, tokenSymbol);
__Ownable_init(initialOwner);
__UUPSUpgradeable_init();
}
function _authorizeUpgrade(address newImplementation)
internal
onlyOwner
override
{}
}
`
}
}
]

@ -33,7 +33,7 @@ module.exports = {
'Should sign message using account key #group2': function (browser: NightwatchBrowser) { 'Should sign message using account key #group2': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('*[data-id="settingsRemixRunSignMsg"]') browser.waitForElementVisible('*[data-id="settingsRemixRunSignMsg"]')
.switchEnvironment('vm-merge') .switchEnvironment('vm-paris')
.pause(2000) .pause(2000)
.click('*[data-id="settingsRemixRunSignMsg"]') .click('*[data-id="settingsRemixRunSignMsg"]')
.pause(2000) .pause(2000)
@ -82,21 +82,21 @@ module.exports = {
instanceAddress = address instanceAddress = address
console.log('instanceAddress', instanceAddress) console.log('instanceAddress', instanceAddress)
browser browser
.waitForElementVisible(`#instance${instanceAddress} [data-id="instanceContractBal"]`) .waitForElementVisible(`#instance${instanceAddress} [data-id="instanceContractBal"]`)
//*[@id="instance0xbBF289D846208c16EDc8474705C748aff07732dB" and contains(.,"Balance") and contains(.,'0.000000000000000111')] //*[@id="instance0xbBF289D846208c16EDc8474705C748aff07732dB" and contains(.,"Balance") and contains(.,'0.000000000000000111')]
.waitForElementVisible({ .waitForElementVisible({
locateStrategy: 'xpath', locateStrategy: 'xpath',
selector: `//*[@id="instance${instanceAddress}" and contains(.,"Balance") and contains(.,'0.000000000000000111')]`, selector: `//*[@id="instance${instanceAddress}" and contains(.,"Balance") and contains(.,'0.000000000000000111')]`,
timeout: 60000 timeout: 60000
}) })
//.waitForElementContainsText(`#instance${instanceAddress} [data-id="instanceContractBal"]`, 'Balance: 0.000000000000000111 ETH', 60000) //.waitForElementContainsText(`#instance${instanceAddress} [data-id="instanceContractBal"]`, 'Balance: 0.000000000000000111 ETH', 60000)
.clickFunction('sendSomeEther - transact (not payable)', { types: 'uint256 num', values: '2' }) .clickFunction('sendSomeEther - transact (not payable)', { types: 'uint256 num', values: '2' })
.pause(1000) .pause(1000)
.waitForElementVisible({ .waitForElementVisible({
locateStrategy: 'xpath', locateStrategy: 'xpath',
selector: `//*[@id="instance${instanceAddress}" and contains(.,"Balance") and contains(.,'0.000000000000000109')]`, selector: `//*[@id="instance${instanceAddress}" and contains(.,"Balance") and contains(.,'0.000000000000000109')]`,
timeout: 60000 timeout: 60000
}) })
}) })
}, },
@ -238,6 +238,95 @@ module.exports = {
.executeScriptInTerminal('web3.eth.getAccounts()') .executeScriptInTerminal('web3.eth.getAccounts()')
.journalLastChildIncludes('[ "0x76a3ABb5a12dcd603B52Ed22195dED17ee82708f" ]') .journalLastChildIncludes('[ "0x76a3ABb5a12dcd603B52Ed22195dED17ee82708f" ]')
.end() .end()
},
'Should ensure that save environment state is checked by default #group4 #group5': function (browser: NightwatchBrowser) {
browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]')
.clickLaunchIcon('settings')
.waitForElementPresent('[data-id="settingsEnableSaveEnvStateLabel"]')
.scrollInto('[data-id="settingsEnableSaveEnvStateLabel"]')
.verify.elementPresent('[data-id="settingsEnableSaveEnvState"]:checked')
},
'Should deploy default storage contract; store value and ensure that state is saved. #group4 #group5': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('filePanel')
.click('*[data-id="treeViewLitreeViewItemcontracts"]')
.openFile('contracts/1_Storage.sol')
.pause(5000)
.clickLaunchIcon('udapp')
.waitForElementPresent('*[data-id="Deploy - transact (not payable)"]')
.click('*[data-id="Deploy - transact (not payable)"]')
.waitForElementPresent('#instance0xd9145CCE52D386f254917e481eB44e9943F39138')
.clickInstance(0)
.clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '10' })
.clickFunction('retrieve - call')
.waitForElementContainsText('[data-id="treeViewLi0"]', 'uint256: 10')
.clickLaunchIcon('filePanel')
.openFile('.states/vm-cancun/state.json')
.getEditorValue((content) => {
browser
.assert.ok(content.includes('"latestBlockNumber": "0x2"'), 'State is saved')
})
},
'Should load state after page refresh #group4': function (browser: NightwatchBrowser) {
browser.refreshPage()
.waitForElementVisible('*[data-id="remixIdeSidePanel"]')
.click('*[data-id="treeViewLitreeViewItemcontracts"]')
.openFile('contracts/1_Storage.sol')
.addAtAddressInstance('0xd9145CCE52D386f254917e481eB44e9943F39138', true, true, false)
.clickInstance(0)
.clickFunction('retrieve - call')
.waitForElementContainsText('[data-id="treeViewLi0"]', 'uint256: 10')
},
'Should save state after running web3 script #group4': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('settings')
.waitForElementPresent('[data-id="settingsTabGenerateContractMetadataLabel"]')
.click('[data-id="settingsTabGenerateContractMetadataLabel"]')
.verify.elementPresent('[data-id="settingsTabGenerateContractMetadata"]:checked')
.clickLaunchIcon('solidity')
.click('.remixui_compilerConfigSection')
.setValue('#evmVersionSelector', 'london')
.click('*[data-id="compilerContainerCompileBtn"]')
.pause(5000)
.clickLaunchIcon('udapp')
.switchEnvironment('vm-london')
.clickLaunchIcon('filePanel')
.click('*[data-id="treeViewLitreeViewItemscripts"]')
.openFile('scripts/deploy_with_web3.ts')
.click('[data-id="play-editor"]')
.waitForElementPresent('[data-id="treeViewDivDraggableItem.states/vm-london/state.json"]')
.click('[data-id="treeViewDivDraggableItem.states/vm-london/state.json"]')
.pause(100000)
.getEditorValue((content) => {
browser
.assert.ok(content.includes('"latestBlockNumber": "0x1"'), 'State is saved')
})
},
'Should ensure that .states is not updated when save env option is unchecked #group5': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('settings')
.waitForElementPresent('[data-id="settingsEnableSaveEnvStateLabel"]')
.click('[data-id="settingsEnableSaveEnvStateLabel"]')
.verify.elementNotPresent('[data-id="settingsEnableSaveEnvState"]:checked')
.clickLaunchIcon('filePanel')
.openFile('contracts/1_Storage.sol')
.pause(5000)
.clickLaunchIcon('udapp')
.waitForElementPresent('*[data-id="Deploy - transact (not payable)"]')
.click('*[data-id="Deploy - transact (not payable)"]')
.pause(5000)
.clickLaunchIcon('filePanel')
.openFile('.states/vm-cancun/state.json')
.getEditorValue((content) => {
browser
.assert.ok(content.includes('"latestBlockNumber": "0x2"'), 'State is unchanged')
})
.end()
} }
} }

@ -339,8 +339,12 @@ module.exports = {
'Basic Solidity Unit tests with local compiler #group6': function (browser: NightwatchBrowser) { 'Basic Solidity Unit tests with local compiler #group6': function (browser: NightwatchBrowser) {
browser browser
.clickLaunchIcon('udapp')
.switchEnvironment('vm-cancun')
.clickLaunchIcon('solidity') .clickLaunchIcon('solidity')
.setSolidityCompilerVersion('builtin') .setSolidityCompilerVersion('builtin')
.click('.remixui_compilerConfigSection')
.setValue('#evmVersionSelector', 'cancun') // Temporary fix
.clickLaunchIcon('filePanel') .clickLaunchIcon('filePanel')
.click('*[data-id="treeViewLitreeViewItemcontracts"]') .click('*[data-id="treeViewLitreeViewItemcontracts"]')
.openFile('contracts/3_Ballot.sol') .openFile('contracts/3_Ballot.sol')

@ -129,7 +129,7 @@ module.exports = {
}) })
}) })
}, },
'Use special functions receive/fallback - only fallback is diclared and is payable, sending data and wei #group3': function (browser: NightwatchBrowser) { 'Use special functions receive/fallback - only fallback is declared and is payable, sending data and wei #group3': function (browser: NightwatchBrowser) {
// don't need to redeploy it, same contract // don't need to redeploy it, same contract
browser.perform((done) => { browser.perform((done) => {
browser.getAddressAtPosition(0, (address) => { browser.getAddressAtPosition(0, (address) => {

@ -319,7 +319,7 @@ module.exports = {
.execute(() => { .execute(() => {
(document.querySelector('*[data-id="vm-custom-forkModalDialogContainer-react"] input[data-id="CustomForkEvmType"]') as any).focus() (document.querySelector('*[data-id="vm-custom-forkModalDialogContainer-react"] input[data-id="CustomForkEvmType"]') as any).focus()
}, [], () => { }) }, [], () => { })
.click('*[data-id="CustomForkEvmType"] [value="merge"]') .click('*[data-id="CustomForkEvmType"] [value="cancun"]')
.pause(5000) .pause(5000)
.modalFooterOKClick('vm-custom-fork') .modalFooterOKClick('vm-custom-fork')
.waitForElementPresent({ .waitForElementPresent({

@ -107,6 +107,46 @@ module.exports = {
}) })
}, },
'Should load Blockscout verified contracts from URL "address" and "blockscout" params (single source)': function (browser: NightwatchBrowser) {
browser
.url('http://127.0.0.1:8080/#address=0xdAC17F958D2ee523a2206206994597C13D831ec7&blockscout=eth.blockscout.com')
.refreshPage()
.pause(7000)
.currentWorkspaceIs('code-sample')
.assert.elementPresent('*[data-id="treeViewLitreeViewItemeth.blockscout.com"]')
.assert.elementPresent('*[data-id="treeViewLitreeViewItemeth.blockscout.com/0xdAC17F958D2ee523a2206206994597C13D831ec7"]')
.getEditorValue((content) => {
browser.assert.ok(content && content.indexOf(
'contract TetherToken is Pausable, StandardToken, BlackList {') !== -1)
})
},
'Should load Blockscout verified contracts from URL "address" and "blockscout" params (multiple sources)': function (browser: NightwatchBrowser) {
browser
.url('http://127.0.0.1:8080/#address=0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9&blockscout=eth.blockscout.com')
.refreshPage()
.pause(7000)
.currentWorkspaceIs('code-sample')
.assert.elementPresent('*[data-id="treeViewLitreeViewItemeth.blockscout.com"]')
.assert.elementPresent('*[data-id="treeViewLitreeViewItemeth.blockscout.com/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9"]')
.assert.elementPresent('*[data-id="treeViewLitreeViewItemeth.blockscout.com/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9/contracts"]')
.assert.elementPresent('*[data-id="treeViewLitreeViewItemeth.blockscout.com/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9/contracts/open-zeppelin"]')
.assert.elementPresent('*[data-id="treeViewLitreeViewItemeth.blockscout.com/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9/contracts/open-zeppelin/Address.sol"]')
.assert.elementPresent('*[data-id="treeViewLitreeViewItemeth.blockscout.com/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9/contracts/open-zeppelin/BaseAdminUpgradeabilityProxy.sol"]')
.assert.elementPresent('*[data-id="treeViewLitreeViewItemeth.blockscout.com/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9/contracts/open-zeppelin/BaseUpgradeabilityProxy.sol"]')
.assert.elementPresent('*[data-id="treeViewLitreeViewItemeth.blockscout.com/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9/contracts/open-zeppelin/InitializableAdminUpgradeabilityProxy.sol"]')
.assert.elementPresent('*[data-id="treeViewLitreeViewItemeth.blockscout.com/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9/contracts/open-zeppelin/InitializableUpgradeabilityProxy.sol"]')
.assert.elementPresent('*[data-id="treeViewLitreeViewItemeth.blockscout.com/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9/contracts/open-zeppelin/Proxy.sol"]')
.assert.elementPresent('*[data-id="treeViewLitreeViewItemeth.blockscout.com/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9/contracts/open-zeppelin/UpgradeabilityProxy.sol"]')
.openFile('eth.blockscout.com/0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9/contracts/open-zeppelin/InitializableAdminUpgradeabilityProxy.sol')
.getEditorValue((content) => {
browser.assert.ok(content && content.indexOf(
'contract InitializableAdminUpgradeabilityProxy is BaseAdminUpgradeabilityProxy, InitializableUpgradeabilityProxy {') !== -1)
})
},
'Should load the code from URL & code params #group1': function (browser: NightwatchBrowser) { 'Should load the code from URL & code params #group1': function (browser: NightwatchBrowser) {
browser browser
.url('http://127.0.0.1:8080/#optimize=true&runs=300&url=https://github.com/ethereum/remix-project/blob/master/apps/remix-ide/contracts/app/solidity/mode.sol&code=cHJhZ21hIHNvbGlkaXR5ID49MC42LjAgPDAuNy4wOwoKaW1wb3J0ICJodHRwczovL2dpdGh1Yi5jb20vT3BlblplcHBlbGluL29wZW56ZXBwZWxpbi1jb250cmFjdHMvYmxvYi9tYXN0ZXIvY29udHJhY3RzL2FjY2Vzcy9Pd25hYmxlLnNvbCI7Cgpjb250cmFjdCBHZXRQYWlkIGlzIE93bmFibGUgewogIGZ1bmN0aW9uIHdpdGhkcmF3KCkgZXh0ZXJuYWwgb25seU93bmVyIHsKICB9Cn0') .url('http://127.0.0.1:8080/#optimize=true&runs=300&url=https://github.com/ethereum/remix-project/blob/master/apps/remix-ide/contracts/app/solidity/mode.sol&code=cHJhZ21hIHNvbGlkaXR5ID49MC42LjAgPDAuNy4wOwoKaW1wb3J0ICJodHRwczovL2dpdGh1Yi5jb20vT3BlblplcHBlbGluL29wZW56ZXBwZWxpbi1jb250cmFjdHMvYmxvYi9tYXN0ZXIvY29udHJhY3RzL2FjY2Vzcy9Pd25hYmxlLnNvbCI7Cgpjb250cmFjdCBHZXRQYWlkIGlzIE93bmFibGUgewogIGZ1bmN0aW9uIHdpdGhkcmF3KCkgZXh0ZXJuYWwgb25seU93bmVyIHsKICB9Cn0')

@ -67,7 +67,6 @@ module.exports = {
browser browser
// @ts-ignore // @ts-ignore
.frame(0) .frame(0)
.click('[data-id="remote-compiler"]')
.click('[data-id="compile"]') .click('[data-id="compile"]')
.waitForElementVisible({ .waitForElementVisible({
selector:'[data-id="compilation-details"]', selector:'[data-id="compilation-details"]',
@ -89,7 +88,6 @@ module.exports = {
chromeBrowser.setPermission('clipboard-write', 'granted') chromeBrowser.setPermission('clipboard-write', 'granted')
browser browser
.frame(0) .frame(0)
.click('[data-id="remote-compiler"]')
.click('[data-id="compile"]') .click('[data-id="compile"]')
.waitForElementVisible({ .waitForElementVisible({
selector:'[data-id="compilation-details"]', selector:'[data-id="compilation-details"]',

@ -14,15 +14,15 @@
pathval "1.1.1" pathval "1.1.1"
type-detect "4.0.8" type-detect "4.0.8"
"@openzeppelin/contracts-upgradeable@^5.0.0": "@openzeppelin/contracts-upgradeable@^5.0.2":
version "5.0.0" version "5.0.2"
resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-5.0.0.tgz#859c00c55f04b6dda85b3c88bce507d65019888f" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-5.0.2.tgz#3e5321a2ecdd0b206064356798c21225b6ec7105"
integrity sha512-D54RHzkOKHQ8xUssPgQe2d/U92mwaiBDY7qCCVGq6VqwQjsT3KekEQ3bonev+BLP30oZ0R1U6YC8/oLpizgC5Q== integrity sha512-0MmkHSHiW2NRFiT9/r5Lu4eJq5UJ4/tzlOgYXNAIj/ONkQTVnz22pLxDvp4C4uZ9he7ZFvGn3Driptn1/iU7tQ==
"@openzeppelin/contracts@^5.0.0": "@openzeppelin/contracts@^5.0.2":
version "5.0.0" version "5.0.2"
resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.0.0.tgz#ee0e4b4564f101a5c4ee398cd4d73c0bd92b289c" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.0.2.tgz#b1d03075e49290d06570b2fd42154d76c2a5d210"
integrity sha512-bv2sdS6LKqVVMLI5+zqnNrNU/CA+6z6CmwFXm/MzmOPBRSO5reEJN7z0Gbzvs0/bv/MZZXNklubpwy3v2+azsw== integrity sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA==
"@openzeppelin/upgrades-core@^1.30.0": "@openzeppelin/upgrades-core@^1.30.0":
version "1.30.1" version "1.30.1"
@ -1437,9 +1437,9 @@ flat@^5.0.2:
integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
follow-redirects@^1.0.0, follow-redirects@^1.15.0: follow-redirects@^1.0.0, follow-redirects@^1.15.0:
version "1.15.4" version "1.15.6"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw== integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
for-each@^0.3.3: for-each@^0.3.3:
version "0.3.3" version "0.3.3"

@ -1,34 +1,45 @@
#!/usr/bin/env bash #!/usr/bin/env bash
echo "Downloading latest soljson.js from https://binaries.soliditylang.org/wasm/list.json" echo "Downloading specified soljson.js version based on defaultVersion in package.json"
set -e set -e
# check if curl is installed
if ! command -v curl &> /dev/null # Check if curl and jq are installed
then if ! command -v curl &> /dev/null; then
echo "curl could not be found" echo "curl could not be found"
exit exit 1
fi fi
# Read the defaultVersion from package.json
defaultVersion=$(grep '"defaultVersion"' package.json | awk -F '"' '{print $4}')
echo "Specified version from package.json: $defaultVersion"
# download https://binaries.soliditylang.org/wasm/list.json as json # Download the list.json file containing available versions
curl -s https://binaries.soliditylang.org/wasm/list.json > list.json curl -s https://binaries.soliditylang.org/wasm/list.json > list.json
# get the latest version without jq
latest=$(grep 'latestRelease' list.json | cut -d '"' -f 4) # Use jq to extract the path for the specified version from the builds array
echo "latest version: $latest" check=$(grep "\"$defaultVersion\"" list.json)
# get url if [ -z "$check" ]; then
url=$(grep "\"$latest\":" list.json | cut -d '"' -f 4) echo "The specified version $defaultVersion could not be found in the list"
echo "url: $url" exit 1
path="https://binaries.soliditylang.org/bin/$url" fi
echo "path: $path"
# download the file to ./apps/remix-ide/src/assets/js/soljson.js echo "Path for the specified version: $defaultVersion"
curl -s $path > ./apps/remix-ide/src/assets/js/soljson.js fullPath="https://binaries.soliditylang.org/bin/$defaultVersion"
# if directory ./apps/remix-ide/src/assets/js/soljson does not exist, create it echo "Download fullPath: $fullPath"
# Ensure the target directory exists
if [ ! -d "./apps/remix-ide/src/assets/js/soljson" ]; then if [ ! -d "./apps/remix-ide/src/assets/js/soljson" ]; then
mkdir ./apps/remix-ide/src/assets/js/soljson mkdir -p ./apps/remix-ide/src/assets/js/soljson
fi fi
cp ./apps/remix-ide/src/assets/js/soljson.js ./apps/remix-ide/src/assets/js/soljson/$url
# Download the file to ./apps/remix-ide/src/assets/js/soljson.js
echo "Downloading soljson.js from "$fullPath" to ./apps/remix-ide/src/assets/js/soljson.js"
curl -s "$fullPath" > ./apps/remix-ide/src/assets/js/soljson.js
# Copy the downloaded soljson.js to the specific version directory
cp ./apps/remix-ide/src/assets/js/soljson.js "./apps/remix-ide/src/assets/js/soljson/$path"
cp list.json ./apps/remix-ide/src/assets/list.json cp list.json ./apps/remix-ide/src/assets/list.json
# remove list.json # Clean up by removing the list.json
rm list.json rm list.json

@ -28,7 +28,7 @@ import {StoragePlugin} from './app/plugins/storage'
import {Layout} from './app/panels/layout' import {Layout} from './app/panels/layout'
import {NotificationPlugin} from './app/plugins/notification' import {NotificationPlugin} from './app/plugins/notification'
import {Blockchain} from './blockchain/blockchain' import {Blockchain} from './blockchain/blockchain'
import {MergeVMProvider, LondonVMProvider, BerlinVMProvider, ShanghaiVMProvider} from './app/providers/vm-provider' import {MergeVMProvider, LondonVMProvider, BerlinVMProvider, ShanghaiVMProvider, CancunVMProvider} from './app/providers/vm-provider'
import {MainnetForkVMProvider} from './app/providers/mainnet-vm-fork-provider' import {MainnetForkVMProvider} from './app/providers/mainnet-vm-fork-provider'
import {SepoliaForkVMProvider} from './app/providers/sepolia-vm-fork-provider' import {SepoliaForkVMProvider} from './app/providers/sepolia-vm-fork-provider'
import {GoerliForkVMProvider} from './app/providers/goerli-vm-fork-provider' import {GoerliForkVMProvider} from './app/providers/goerli-vm-fork-provider'
@ -264,6 +264,7 @@ class AppComponent {
const vmProviderSepoliaFork = new SepoliaForkVMProvider(blockchain) const vmProviderSepoliaFork = new SepoliaForkVMProvider(blockchain)
const vmProviderGoerliFork = new GoerliForkVMProvider(blockchain) const vmProviderGoerliFork = new GoerliForkVMProvider(blockchain)
const vmProviderShanghai = new ShanghaiVMProvider(blockchain) const vmProviderShanghai = new ShanghaiVMProvider(blockchain)
const vmProviderCancun = new CancunVMProvider(blockchain)
const vmProviderMerge = new MergeVMProvider(blockchain) const vmProviderMerge = new MergeVMProvider(blockchain)
const vmProviderBerlin = new BerlinVMProvider(blockchain) const vmProviderBerlin = new BerlinVMProvider(blockchain)
const vmProviderLondon = new LondonVMProvider(blockchain) const vmProviderLondon = new LondonVMProvider(blockchain)
@ -338,6 +339,7 @@ class AppComponent {
dGitProvider, dGitProvider,
storagePlugin, storagePlugin,
vmProviderShanghai, vmProviderShanghai,
vmProviderCancun,
vmProviderMerge, vmProviderMerge,
vmProviderBerlin, vmProviderBerlin,
vmProviderLondon, vmProviderLondon,

@ -52,7 +52,8 @@ class Editor extends Plugin {
cairo: 'cairo', cairo: 'cairo',
ts: 'typescript', ts: 'typescript',
move: 'move', move: 'move',
circom: 'circom' circom: 'circom',
nr: 'rust'
} }
this.activated = false this.activated = false

@ -24,7 +24,7 @@ const profile = {
methods: ['closeAllFiles', 'closeFile', 'file', 'exists', 'open', 'writeFile', 'writeMultipleFiles', 'writeFileNoRewrite', methods: ['closeAllFiles', 'closeFile', 'file', 'exists', 'open', 'writeFile', 'writeMultipleFiles', 'writeFileNoRewrite',
'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', 'readdir', 'dirList', 'fileList', 'remove', 'getCurrentFile', 'getFile', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', 'readdir', 'dirList', 'fileList', 'remove', 'getCurrentFile', 'getFile',
'getFolder', 'setFile', 'switchFile', 'refresh', 'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath', 'getFolder', 'setFile', 'switchFile', 'refresh', 'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath',
'saveCurrentFile', 'setBatchFiles', 'isGitRepo', 'isFile', 'isDirectory', 'hasGitSubmodule' 'saveCurrentFile', 'setBatchFiles', 'isGitRepo', 'isFile', 'isDirectory', 'hasGitSubmodule', 'copyFolderToJson'
], ],
kind: 'file-system' kind: 'file-system'
} }
@ -1041,6 +1041,14 @@ class FileManager extends Plugin {
throw new Error(e) throw new Error(e)
} }
} }
async copyFolderToJson(folder: string) {
const provider = this.currentFileProvider()
if (provider && provider.copyFolderToJson) {
return await provider.copyFolderToJson(folder)
}
throw new Error('copyFolderToJson not available')
}
} }
module.exports = FileManager module.exports = FileManager

@ -224,9 +224,23 @@ export class TabProxy extends Plugin {
this.removeTab(oldName) this.removeTab(oldName)
} }
/**
*
* @param {string} name
* @param {string} title
* @param {Function} switchTo
* @param {Function} close
* @param {string} icon
* @param {string} description
* @returns
*/
addTab (name, title, switchTo, close, icon, description = '') { addTab (name, title, switchTo, close, icon, description = '') {
if (this._handlers[name]) return this.renderComponent() if (this._handlers[name]) return this.renderComponent()
if ((name.endsWith('.vy') && icon === undefined) || title.includes('Vyper')) {
icon = 'assets/img/vyperLogo2.webp'
}
var slash = name.split('/') var slash = name.split('/')
const tabPath = slash.reverse() const tabPath = slash.reverse()
const tempTitle = [] const tempTitle = []
@ -292,7 +306,7 @@ export class TabProxy extends Plugin {
if (!previous && tab.name === name) { if (!previous && tab.name === name) {
if(index - 1 >= 0 && this.loadedTabs[index - 1]) if(index - 1 >= 0 && this.loadedTabs[index - 1])
previous = this.loadedTabs[index - 1] previous = this.loadedTabs[index - 1]
else if (index + 1 && this.loadedTabs[index + 1]) else if (index + 1 && this.loadedTabs[index + 1])
previous = this.loadedTabs[index + 1] previous = this.loadedTabs[index + 1]
} }
return tab.name !== name return tab.name !== name

@ -1,12 +1,12 @@
/* global Node, requestAnimationFrame */ // eslint-disable-line /* global Node, requestAnimationFrame */ // eslint-disable-line
import React from 'react' // eslint-disable-line import React from 'react' // eslint-disable-line
import { RemixUiTerminal } from '@remix-ui/terminal' // eslint-disable-line import { RemixUiTerminal, RemixUITerminalWrapper } from '@remix-ui/terminal' // eslint-disable-line
import { Plugin } from '@remixproject/engine' import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../../../package.json' import * as packageJson from '../../../../../package.json'
import {Registry} from '@remix-project/remix-lib' import {Registry} from '@remix-project/remix-lib'
import { PluginViewWrapper } from '@remix-ui/helper' import { PluginViewWrapper } from '@remix-ui/helper'
import vm from 'vm' import vm from 'vm'
const EventManager = require('../../lib/events') import EventManager from '../../lib/events'
import { CompilerImports } from '@remix-project/core-plugin' // eslint-disable-line import { CompilerImports } from '@remix-project/core-plugin' // eslint-disable-line
import { RemixUiXterminals } from '@remix-ui/xterm' import { RemixUiXterminals } from '@remix-ui/xterm'
@ -26,6 +26,34 @@ const profile = {
} }
class Terminal extends Plugin { class Terminal extends Plugin {
fileImport: CompilerImports
event: any
globalRegistry: Registry
element: HTMLDivElement
eventsDecoder: any
txListener: any
_deps: { fileManager: any; editor: any; compilersArtefacts: any; offsetToLineColumnConverter: any }
commandHelp: { 'remix.loadgist(id)': string; 'remix.loadurl(url)': string; 'remix.execute(filepath)': string; 'remix.exeCurrent()': string; 'remix.help()': string }
blockchain: any
vm: typeof vm
_api: any
_opts: any
config: any
version: string
data: {
lineLength: any // ????
session: any[]; activeFilters: { commands: any; input: string }; filterFns: any
}
_view: { el: any; bar: any; input: any; term: any; journal: any; cli: any }
_components: any
_commands: any
commands: any
_JOURNAL: any[]
_jobs: any[]
_INDEX: any
_shell: any
dispatch: any
terminalApi: any
constructor(opts, api) { constructor(opts, api) {
super(profile) super(profile)
this.fileImport = new CompilerImports() this.fileImport = new CompilerImports()
@ -75,7 +103,7 @@ class Terminal extends Plugin {
this._INDEX.commandsMain = {} this._INDEX.commandsMain = {}
if (opts.shell) this._shell = opts.shell // ??? if (opts.shell) this._shell = opts.shell // ???
register(this) register(this)
this.event.register('debuggingRequested', async (hash) => { this.event.register('debuggingRequested', async (hash: any) => {
// TODO should probably be in the run module // TODO should probably be in the run module
if (!await this._opts.appManager.isActive('debugger')) await this._opts.appManager.activatePlugin('debugger') if (!await this._opts.appManager.isActive('debugger')) await this._opts.appManager.activatePlugin('debugger')
this.call('menuicons', 'select', 'debugger') this.call('menuicons', 'select', 'debugger')
@ -114,13 +142,12 @@ class Terminal extends Plugin {
} }
updateComponent(state) { updateComponent(state) {
return (Registry.getInstance().get('platform').api.isDesktop()) ? <RemixUiXterminals onReady={state.onReady} plugin={state.plugin}> return(
</RemixUiXterminals> <RemixUITerminalWrapper
: <RemixUiTerminal
plugin={state.plugin} plugin={state.plugin}
onReady={state.onReady} onReady={state.onReady}
visible={true} visible={true}
/> />)
} }
renderComponent() { renderComponent() {

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

@ -8,16 +8,16 @@ export class MainnetForkVMProvider extends BasicVMProvider {
super( super(
{ {
name: 'vm-mainnet-fork', name: 'vm-mainnet-fork',
displayName: 'Mainet fork -Remix VM (London)', displayName: 'Mainnet fork - Remix VM (Cancun)',
kind: 'provider', kind: 'provider',
description: 'Remix VM (London)', description: 'Remix VM (Cancun)',
methods: ['sendAsync', 'init'], methods: ['sendAsync', 'init'],
version: packageJson.version version: packageJson.version
}, },
blockchain blockchain
) )
this.blockchain = blockchain this.blockchain = blockchain
this.fork = 'shanghai' this.fork = 'cancun'
this.nodeUrl = 'https://go.getblock.io/56f8bc5187aa4ac696348f67545acf38' this.nodeUrl = 'https://go.getblock.io/56f8bc5187aa4ac696348f67545acf38'
this.blockNumber = 'latest' this.blockNumber = 'latest'
} }

@ -8,7 +8,7 @@ export class SepoliaForkVMProvider extends BasicVMProvider {
super( super(
{ {
name: 'vm-sepolia-fork', name: 'vm-sepolia-fork',
displayName: 'Sepolia fork - Remix VM (London)', displayName: 'Sepolia fork - Remix VM (Cancun)',
kind: 'provider', kind: 'provider',
description: 'Remix VM (London)', description: 'Remix VM (London)',
methods: ['sendAsync', 'init'], methods: ['sendAsync', 'init'],
@ -17,7 +17,7 @@ export class SepoliaForkVMProvider extends BasicVMProvider {
blockchain blockchain
) )
this.blockchain = blockchain this.blockchain = blockchain
this.fork = 'shanghai' this.fork = 'cancun'
this.nodeUrl = 'https://go.getblock.io/ee42d0a88f314707be11dd799b122cb9' this.nodeUrl = 'https://go.getblock.io/ee42d0a88f314707be11dd799b122cb9'
this.blockNumber = 'latest' this.blockNumber = 'latest'
} }

@ -46,17 +46,17 @@ export class MergeVMProvider extends BasicVMProvider {
constructor(blockchain) { constructor(blockchain) {
super( super(
{ {
name: 'vm-merge', name: 'vm-paris',
displayName: 'Remix VM (Merge)', displayName: 'Remix VM (Paris)',
kind: 'provider', kind: 'provider',
description: 'Remix VM (Merge)', description: 'Remix VM (Paris)',
methods: ['sendAsync', 'init'], methods: ['sendAsync', 'init'],
version: packageJson.version version: packageJson.version
}, },
blockchain blockchain
) )
this.blockchain = blockchain this.blockchain = blockchain
this.fork = 'merge' this.fork = 'paris'
} }
} }
@ -113,3 +113,21 @@ export class ShanghaiVMProvider extends BasicVMProvider {
this.fork = 'shanghai' this.fork = 'shanghai'
} }
} }
export class CancunVMProvider extends BasicVMProvider {
constructor(blockchain) {
super(
{
name: 'vm-cancun',
displayName: 'Remix VM (Cancun)',
kind: 'provider',
description: 'Remix VM (Cancun)',
methods: ['sendAsync', 'init'],
version: packageJson.version
},
blockchain
)
this.blockchain = blockchain
this.fork = 'cancun'
}
}

@ -34,6 +34,8 @@
"filePanel.tssoltestghaction": "Mocha Chai Test Workflow", "filePanel.tssoltestghaction": "Mocha Chai Test Workflow",
"filePanel.workspace.addscriptetherscan": "Adds scripts which can be used to interact with the Etherscan API", "filePanel.workspace.addscriptetherscan": "Adds scripts which can be used to interact with the Etherscan API",
"filePanel.addscriptetherscan": "Add Etherscan scripts", "filePanel.addscriptetherscan": "Add Etherscan scripts",
"filePanel.workspace.addscriptsindri": "Adds scripts for interacting with Sindri, a zk proof generation remote service",
"filePanel.addscriptsindri": "Add Sindri ZK scripts",
"filePanel.workspace.addscriptdeployer": "Adds scripts which can be used to deploy contracts", "filePanel.workspace.addscriptdeployer": "Adds scripts which can be used to deploy contracts",
"filePanel.addscriptdeployer": "Add contract deployer scripts", "filePanel.addscriptdeployer": "Add contract deployer scripts",
"filePanel.workspace.slitherghaction": "Adds a preset yml file to run slither analysis on github actions CI", "filePanel.workspace.slitherghaction": "Adds a preset yml file to run slither analysis on github actions CI",
@ -94,7 +96,7 @@
"filePanel.copyFolderFailed": "Copy Folder Failed", "filePanel.copyFolderFailed": "Copy Folder Failed",
"filePanel.copyFolderFailedMsg": "Unexpected error while copying folder: {src}", "filePanel.copyFolderFailedMsg": "Unexpected error while copying folder: {src}",
"filePanel.runScriptFailed": "Run script failed", "filePanel.runScriptFailed": "Run script failed",
"filePanel.createPublicGist": "Create a public gist", "filePanel.createPublicGist": "Publish to a public gist",
"filePanel.createPublicGistMsg1": "Are you sure you want to push changes to remote gist file on github.com?", "filePanel.createPublicGistMsg1": "Are you sure you want to push changes to remote gist file on github.com?",
"filePanel.createPublicGistMsg2": "Are you sure you want to anonymously publish all your files in the {path} folder as a public gist on github.com?", "filePanel.createPublicGistMsg2": "Are you sure you want to anonymously publish all your files in the {path} folder as a public gist on github.com?",
"filePanel.createPublicGistMsg3": "Are you sure you want to anonymously publish {path} file as a public gist on github.com?", "filePanel.createPublicGistMsg3": "Are you sure you want to anonymously publish {path} file as a public gist on github.com?",

@ -17,6 +17,9 @@
"settings.etherscanTokenTitle": "EtherScan Access Token", "settings.etherscanTokenTitle": "EtherScan Access Token",
"settings.etherscanAccessTokenText": "Manage the api key used to interact with Etherscan.", "settings.etherscanAccessTokenText": "Manage the api key used to interact with Etherscan.",
"settings.etherscanAccessTokenText2": "Go to Etherscan api key page (link below) to create a new api key and save it in Remix.", "settings.etherscanAccessTokenText2": "Go to Etherscan api key page (link below) to create a new api key and save it in Remix.",
"settings.sindriAccessTokenTitle": "Sindri Credentials",
"settings.sindriAccessTokenText": "The access token is used to compile ZKP circuits and generate proofs with Sindri.",
"settings.sindriAccessTokenText2":"Go to the Sindri account creation page (link below) to create a new token and save it in Remix.",
"settings.save": "Save", "settings.save": "Save",
"settings.remove": "Remove", "settings.remove": "Remove",
"settings.themes": "Themes", "settings.themes": "Themes",
@ -40,5 +43,6 @@
"settings.copilot": "Solidity copilot - Alpha", "settings.copilot": "Solidity copilot - Alpha",
"settings.copilot.activate": "Load & Activate copilot", "settings.copilot.activate": "Load & Activate copilot",
"settings.copilot.max_new_tokens": "Maximum number of words to generate", "settings.copilot.max_new_tokens": "Maximum number of words to generate",
"settings.copilot.temperature": "Temperature" "settings.copilot.temperature": "Temperature",
"settings.enableSaveEnvState": "Save environment state"
} }

@ -1,8 +1,8 @@
{ {
"terminal.listen": "listen on all transactions", "terminal.listen": "Listen on all transactions",
"terminal.listenVM": "Listen on all transactions is disabled for VM environment", "terminal.listenVM": "Listen on all transactions is disabled for VM environment",
"terminal.listenTitle": "If checked Remix will listen on all transactions mined in the current environment and not only transactions created by you", "terminal.listenTitle": "If checked Remix will listen on all transactions mined in the current environment and not only transactions created by you",
"terminal.search": "Search with transaction hash or address", "terminal.search": "Filter with transaction hash or address",
"terminal.used": "used", "terminal.used": "used",
"terminal.debug": "Debug", "terminal.debug": "Debug",
"terminal.welcomeText1": "Welcome to", "terminal.welcomeText1": "Welcome to",

@ -65,10 +65,18 @@
"udapp.tooltipText3": "Click to open a bridge for converting L1 mainnet ETH to the selected network currency.", "udapp.tooltipText3": "Click to open a bridge for converting L1 mainnet ETH to the selected network currency.",
"udapp._comment_instanceContainerUI.tsx": "libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx", "udapp._comment_instanceContainerUI.tsx": "libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx",
"udapp.deployedContracts": "Deployed Contracts", "udapp.deployedContracts": "Deployed/Unpinned Contracts",
"udapp.deployAndRunClearInstances": "Clear instances list and reset recorder", "udapp.deployAndRunClearInstances": "Clear instances list and reset recorder",
"udapp.deployAndRunNoInstanceText": "Currently you have no contract instances to interact with.", "udapp.deployAndRunNoInstanceText": "Currently you have no unpinned contracts to interact with.",
"udapp.tooltipText6": "Autogenerated generic user interfaces for interaction with deployed contracts", "udapp.tooltipText6": "Autogenerated generic user interfaces for interaction with deployed/unpinned contracts",
"udapp.savedContracts": "Pinned Contracts",
"udapp.tooltipTextPinnedContracts": "List of pinned contracts for selected workspace & network",
"udapp.NoSavedInstanceText": "No pinned contracts found for selected workspace & network",
"udapp.tooltipTextDelete": "Delete pinned contract",
"udapp.tooltipTextUnpin": "Unpin contract",
"udapp.savedOn": "Pinned at",
"udapp.filePath": "File path",
"udapp._comment_recorderCardUI.tsx": "libs/remix-ui/run-tab/src/lib/components/recorderCardUI.tsx", "udapp._comment_recorderCardUI.tsx": "libs/remix-ui/run-tab/src/lib/components/recorderCardUI.tsx",
"udapp.transactionsRecorded": "Transactions recorded", "udapp.transactionsRecorded": "Transactions recorded",
@ -98,7 +106,8 @@
"udapp.tooltipText13": "Deployed {date}", "udapp.tooltipText13": "Deployed {date}",
"udapp._comment_universalDappUI.tsx": "libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx", "udapp._comment_universalDappUI.tsx": "libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx",
"udapp.tooltipText7": "Remove from the list", "udapp.tooltipTextRemove": "Remove from the list",
"udapp.tooltipTextPin": "Pin contract",
"udapp.tooltipText8": "Click for docs about using 'receive'/'fallback'", "udapp.tooltipText8": "Click for docs about using 'receive'/'fallback'",
"udapp.tooltipText9": "The Calldata to send to fallback function of the contract.", "udapp.tooltipText9": "The Calldata to send to fallback function of the contract.",
"udapp.tooltipText10": "Send data to contract.", "udapp.tooltipText10": "Send data to contract.",

@ -86,7 +86,7 @@
"filePanel.copyFolderFailed": "Copia de Carpeta Fallida", "filePanel.copyFolderFailed": "Copia de Carpeta Fallida",
"filePanel.copyFolderFailedMsg": "Error inesperado al copiar la carpeta: {src}", "filePanel.copyFolderFailedMsg": "Error inesperado al copiar la carpeta: {src}",
"filePanel.runScriptFailed": "Error al ejecutar el script", "filePanel.runScriptFailed": "Error al ejecutar el script",
"filePanel.createPublicGist": "Crear una lista pública", "filePanel.createPublicGist": "Publicar una lista pública",
"filePanel.createPublicGistMsg1": "¿Está seguro que desea empujar cambios al archivo gist remoto en github.com?", "filePanel.createPublicGistMsg1": "¿Está seguro que desea empujar cambios al archivo gist remoto en github.com?",
"filePanel.createPublicGistMsg2": "¿Estás seguro que quieres publicar todos tus archivos de forma anónima en la carpeta {path} como un gist público en github.com?", "filePanel.createPublicGistMsg2": "¿Estás seguro que quieres publicar todos tus archivos de forma anónima en la carpeta {path} como un gist público en github.com?",
"filePanel.createPublicGistMsg3": "¿Estás seguro de que quieres publicar de forma anónima el archivo {path} como una gist público en github.com?", "filePanel.createPublicGistMsg3": "¿Estás seguro de que quieres publicar de forma anónima el archivo {path} como una gist público en github.com?",

@ -36,5 +36,6 @@
"settings.port": "PUERTO", "settings.port": "PUERTO",
"settings.projectID": "ID DEL PROYECTO", "settings.projectID": "ID DEL PROYECTO",
"settings.projectSecret": "SECRETO DE PROYECTO", "settings.projectSecret": "SECRETO DE PROYECTO",
"settings.analyticsInRemix": "Analíticas en IDE Remix" "settings.analyticsInRemix": "Analíticas en IDE Remix",
"settings.enableSaveEnvState": "Save environment state"
} }

@ -88,7 +88,7 @@
"udapp.tooltipText12": "Entrada requerida", "udapp.tooltipText12": "Entrada requerida",
"udapp.tooltipText13": "Publicado en {date}", "udapp.tooltipText13": "Publicado en {date}",
"udapp._comment_universalDappUI.tsx": "libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx", "udapp._comment_universalDappUI.tsx": "libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx",
"udapp.tooltipText7": "Eliminar de la lista", "udapp.tooltipTextRemove": "Eliminar de la lista",
"udapp.tooltipText8": "Haga clic para ver los documentos sobre el uso de 'receive'/'fallback'", "udapp.tooltipText8": "Haga clic para ver los documentos sobre el uso de 'receive'/'fallback'",
"udapp.tooltipText9": "El datos de llamada a enviar a la función fallback del contrato.", "udapp.tooltipText9": "El datos de llamada a enviar a la función fallback del contrato.",
"udapp.tooltipText10": "Enviar datos al contrato.", "udapp.tooltipText10": "Enviar datos al contrato.",

@ -86,7 +86,7 @@
"filePanel.copyFolderFailed": "Échec de la copie du dossier", "filePanel.copyFolderFailed": "Échec de la copie du dossier",
"filePanel.copyFolderFailedMsg": "Erreur inattendue lors de la copie du fichier : {src}", "filePanel.copyFolderFailedMsg": "Erreur inattendue lors de la copie du fichier : {src}",
"filePanel.runScriptFailed": "Échec de l'exécution du script", "filePanel.runScriptFailed": "Échec de l'exécution du script",
"filePanel.createPublicGist": "Créer un gist public", "filePanel.createPublicGist": "Publier un gist public",
"filePanel.createPublicGistMsg1": "Êtes-vous sûr de vouloir envoyer les changements dans le fichier gist distant sur github.com?", "filePanel.createPublicGistMsg1": "Êtes-vous sûr de vouloir envoyer les changements dans le fichier gist distant sur github.com?",
"filePanel.createPublicGistMsg2": "Êtes-vous sûr de vouloir publier anonymement tous vos fichiers dans le dossier {path} en tant que gist public sur github.com?", "filePanel.createPublicGistMsg2": "Êtes-vous sûr de vouloir publier anonymement tous vos fichiers dans le dossier {path} en tant que gist public sur github.com?",
"filePanel.createPublicGistMsg3": "Êtes-vous sûr de vouloir publier anonymement tous vos fichiers dans le dossier {path} en tant que gist public sur github.com?", "filePanel.createPublicGistMsg3": "Êtes-vous sûr de vouloir publier anonymement tous vos fichiers dans le dossier {path} en tant que gist public sur github.com?",

@ -36,5 +36,6 @@
"settings.port": "PORT", "settings.port": "PORT",
"settings.projectID": "ID du projet", "settings.projectID": "ID du projet",
"settings.projectSecret": "SECRET DU PROJET", "settings.projectSecret": "SECRET DU PROJET",
"settings.analyticsInRemix": "Analytics dans l'IDE de Remix" "settings.analyticsInRemix": "Analytics dans l'IDE de Remix",
"settings.enableSaveEnvState": "Save environment state"
} }

@ -88,7 +88,7 @@
"udapp.tooltipText12": "Entrée nécessaire", "udapp.tooltipText12": "Entrée nécessaire",
"udapp.tooltipText13": "Déployé {date}", "udapp.tooltipText13": "Déployé {date}",
"udapp._comment_universalDappUI.tsx": "libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx", "udapp._comment_universalDappUI.tsx": "libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx",
"udapp.tooltipText7": "Supprimer de la liste", "udapp.tooltipTextRemove": "Supprimer de la liste",
"udapp.tooltipText8": "Cliquez sur la documentation à propos de l'utilisation de 'receive'/'fallback'", "udapp.tooltipText8": "Cliquez sur la documentation à propos de l'utilisation de 'receive'/'fallback'",
"udapp.tooltipText9": "Les Calldata à envoyer à la fonction fallback du contrat.", "udapp.tooltipText9": "Les Calldata à envoyer à la fonction fallback du contrat.",
"udapp.tooltipText10": "Envoyer des données au contrat.", "udapp.tooltipText10": "Envoyer des données au contrat.",

@ -86,7 +86,7 @@
"filePanel.copyFolderFailed": "Copia Cartella Non Riuscita", "filePanel.copyFolderFailed": "Copia Cartella Non Riuscita",
"filePanel.copyFolderFailedMsg": "Errore inatteso durante la copia della cartella: {src}", "filePanel.copyFolderFailedMsg": "Errore inatteso durante la copia della cartella: {src}",
"filePanel.runScriptFailed": "Esecuzione dello script non riuscita", "filePanel.runScriptFailed": "Esecuzione dello script non riuscita",
"filePanel.createPublicGist": "Crea Gist Pubblico", "filePanel.createPublicGist": "Pubblicare Gist Pubblico",
"filePanel.createPublicGistMsg1": "Sei sicuro di voler inviare le modifiche al file gist remoto su github.com?", "filePanel.createPublicGistMsg1": "Sei sicuro di voler inviare le modifiche al file gist remoto su github.com?",
"filePanel.createPublicGistMsg2": "Sei sicuro di voler pubblicare in modo anonimo tutti i tuoi file nella cartella {path} come gist pubblico su github.com?", "filePanel.createPublicGistMsg2": "Sei sicuro di voler pubblicare in modo anonimo tutti i tuoi file nella cartella {path} come gist pubblico su github.com?",
"filePanel.createPublicGistMsg3": "Sei sicuro di voler pubblicare in modo anonimo tutti i tuoi file nella cartella {path} come gist pubblico su github.com?", "filePanel.createPublicGistMsg3": "Sei sicuro di voler pubblicare in modo anonimo tutti i tuoi file nella cartella {path} come gist pubblico su github.com?",

@ -36,5 +36,6 @@
"settings.port": "PORTA", "settings.port": "PORTA",
"settings.projectID": "ID PROGETTO", "settings.projectID": "ID PROGETTO",
"settings.projectSecret": "SEGRETO DEL PROGETTO", "settings.projectSecret": "SEGRETO DEL PROGETTO",
"settings.analyticsInRemix": "Analytics nella Remix IDE" "settings.analyticsInRemix": "Analytics nella Remix IDE",
"settings.enableSaveEnvState": "Save environment state"
} }

@ -88,7 +88,7 @@
"udapp.tooltipText12": "Input richiesto", "udapp.tooltipText12": "Input richiesto",
"udapp.tooltipText13": "Deploiato", "udapp.tooltipText13": "Deploiato",
"udapp._comment_universalDappUI.tsx": "libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx", "udapp._comment_universalDappUI.tsx": "libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx",
"udapp.tooltipText7": "Rimuovi dalla lista", "udapp.tooltipTextRemove": "Rimuovi dalla lista",
"udapp.tooltipText8": "Fare clic per i documenti sull'uso di 'receive'/'fallback'", "udapp.tooltipText8": "Fare clic per i documenti sull'uso di 'receive'/'fallback'",
"udapp.tooltipText9": "Il Calldata per inviare alla funzione di fallback del contratto.", "udapp.tooltipText9": "Il Calldata per inviare alla funzione di fallback del contratto.",
"udapp.tooltipText10": "Invia dati al contratto.", "udapp.tooltipText10": "Invia dati al contratto.",

@ -86,7 +86,7 @@
"filePanel.copyFolderFailed": "复制文件夹失败", "filePanel.copyFolderFailed": "复制文件夹失败",
"filePanel.copyFolderFailedMsg": "复制文件夹时出现意外错误:{src}", "filePanel.copyFolderFailedMsg": "复制文件夹时出现意外错误:{src}",
"filePanel.runScriptFailed": "执行脚本失败", "filePanel.runScriptFailed": "执行脚本失败",
"filePanel.createPublicGist": "创建一个公开的 gist", "filePanel.createPublicGist": "发布到公共 gist",
"filePanel.createPublicGistMsg1": "您确定要将更改推送到 github.com 上的远程 gist 文件吗?", "filePanel.createPublicGistMsg1": "您确定要将更改推送到 github.com 上的远程 gist 文件吗?",
"filePanel.createPublicGistMsg2": "您确定要在 github.com 上以匿名方式将 {path} 文件夹中的所有文件发布为公开的 gist?", "filePanel.createPublicGistMsg2": "您确定要在 github.com 上以匿名方式将 {path} 文件夹中的所有文件发布为公开的 gist?",
"filePanel.createPublicGistMsg3": "您确定要将 {path} 文件匿名发布为 github.com 上的公开 gist?", "filePanel.createPublicGistMsg3": "您确定要将 {path} 文件匿名发布为 github.com 上的公开 gist?",

@ -36,5 +36,6 @@
"settings.port": "端口", "settings.port": "端口",
"settings.projectID": "项目 ID", "settings.projectID": "项目 ID",
"settings.projectSecret": "项目密钥", "settings.projectSecret": "项目密钥",
"settings.analyticsInRemix": "Remix IDE 中的分析功能" "settings.analyticsInRemix": "Remix IDE 中的分析功能",
"settings.enableSaveEnvState": "Save environment state"
} }

@ -88,7 +88,7 @@
"udapp.tooltipText12": "必填", "udapp.tooltipText12": "必填",
"udapp.tooltipText13": "已部署 {date}", "udapp.tooltipText13": "已部署 {date}",
"udapp._comment_universalDappUI.tsx": "libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx", "udapp._comment_universalDappUI.tsx": "libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx",
"udapp.tooltipText7": "从列表中删除", "udapp.tooltipTextRemove": "从列表中删除",
"udapp.tooltipText8": "点击查看有关使用 'receive'/'fallback' 的文档", "udapp.tooltipText8": "点击查看有关使用 'receive'/'fallback' 的文档",
"udapp.tooltipText9": "发送到合约 fallback 函数的 Calldata。", "udapp.tooltipText9": "发送到合约 fallback 函数的 Calldata。",
"udapp.tooltipText10": "将数据发送到合约。", "udapp.tooltipText10": "将数据发送到合约。",

@ -1,6 +1,6 @@
var async = require('async') var async = require('async')
var remixLib = require('@remix-project/remix-lib') var remixLib = require('@remix-project/remix-lib')
import { bufferToHex } from '@ethereumjs/util' import { bytesToHex } from '@ethereumjs/util'
import { hash } from '@remix-project/remix-lib' import { hash } from '@remix-project/remix-lib'
import { Plugin } from '@remixproject/engine' import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../../.././../../package.json' import * as packageJson from '../../../../.././../../package.json'
@ -43,7 +43,7 @@ class Recorder extends Plugin {
} }
if (!to) { if (!to) {
var abi = payLoad.contractABI var abi = payLoad.contractABI
var keccak = bufferToHex(hash.keccakFromString(JSON.stringify(abi))) var keccak = bytesToHex(hash.keccakFromString(JSON.stringify(abi)))
record.abi = keccak record.abi = keccak
record.contractName = payLoad.contractName record.contractName = payLoad.contractName
record.bytecode = payLoad.contractBytecode record.bytecode = payLoad.contractBytecode
@ -208,7 +208,7 @@ class Recorder extends Plugin {
// resolve the bytecode and ABI using the contract name, this ensure getting the last compiled one. // resolve the bytecode and ABI using the contract name, this ensure getting the last compiled one.
const data = await this.call('compilerArtefacts', 'getArtefactsByContractName', tx.record.contractName) const data = await this.call('compilerArtefacts', 'getArtefactsByContractName', tx.record.contractName)
tx.record.bytecode = data.artefact.evm.bytecode.object tx.record.bytecode = data.artefact.evm.bytecode.object
const updatedABIKeccak = bufferToHex(hash.keccakFromString(JSON.stringify(data.artefact.abi))) const updatedABIKeccak = bytesToHex(hash.keccakFromString(JSON.stringify(data.artefact.abi)))
abis[updatedABIKeccak] = data.artefact.abi abis[updatedABIKeccak] = data.artefact.abi
tx.record.abi = updatedABIKeccak tx.record.abi = updatedABIKeccak
} }

@ -58,11 +58,27 @@ export class Web3ProviderModule extends Plugin {
const contractAddressStr = addressToString(receipt.contractAddress) const contractAddressStr = addressToString(receipt.contractAddress)
const contractData = await this.call('compilerArtefacts', 'getContractDataFromAddress', contractAddressStr) const contractData = await this.call('compilerArtefacts', 'getContractDataFromAddress', contractAddressStr)
if (contractData) { if (contractData) {
this.call('udapp', 'addInstance', contractAddressStr, contractData.contract.abi, contractData.name)
const data = await this.call('compilerArtefacts', 'getCompilerAbstract', contractData.file) const data = await this.call('compilerArtefacts', 'getCompilerAbstract', contractData.file)
const contractObject = {
name: contractData.name,
abi: contractData.contract.abi,
compiler: data,
contract: {
file : contractData.file,
object: contractData.contract
}
}
this.call('udapp', 'addInstance', contractAddressStr, contractData.contract.abi, contractData.name, contractObject)
await this.call('compilerArtefacts', 'addResolvedContract', contractAddressStr, data) await this.call('compilerArtefacts', 'addResolvedContract', contractAddressStr, data)
} }
}, 50) }, 50)
const isVM = this.blockchain.executionContext.isVM()
if (isVM && this.blockchain.config.get('settings/save-evm-state')) {
await this.blockchain.executionContext.getStateDetails().then((state) => {
this.call('fileManager', 'writeFile', `.states/${this.blockchain.executionContext.getProvider()}/state.json`, state)
})
}
} }
} }
resolve(message) resolve(message)

@ -28,7 +28,9 @@ const profile = {
'getSettings', 'getSettings',
'setEnvironmentMode', 'setEnvironmentMode',
'clearAllInstances', 'clearAllInstances',
'clearAllSavedInstances',
'addInstance', 'addInstance',
'addSavedInstance',
'resolveContractAndAddInstance' 'resolveContractAndAddInstance'
] ]
} }
@ -79,8 +81,16 @@ export class RunTab extends ViewPlugin {
this.emit('clearAllInstancesReducer') this.emit('clearAllInstancesReducer')
} }
addInstance(address, abi, name) { clearAllSavedInstances() {
this.emit('addInstanceReducer', address, abi, name) this.emit('clearAllSavedInstancesReducer')
}
addInstance(address, abi, name, contractData) {
this.emit('addInstanceReducer', address, abi, name, contractData)
}
addSavedInstance(address, abi, name, savedOn, filePath) {
this.emit('addSavedInstanceReducer', address, abi, name, savedOn, filePath)
} }
createVMAccount(newAccount) { createVMAccount(newAccount) {
@ -167,13 +177,14 @@ export class RunTab extends ViewPlugin {
// VM // VM
const titleVM = 'Execution environment is local to Remix. Data is only saved to browser memory and will vanish upon reload.' const titleVM = 'Execution environment is local to Remix. Data is only saved to browser memory and will vanish upon reload.'
await addProvider('vm-cancun', 'Remix VM (Cancun)', false, true, 'cancun', 'settingsVMCancunMode', titleVM)
await addProvider('vm-shanghai', 'Remix VM (Shanghai)', false, true, 'shanghai', 'settingsVMShanghaiMode', titleVM) await addProvider('vm-shanghai', 'Remix VM (Shanghai)', false, true, 'shanghai', 'settingsVMShanghaiMode', titleVM)
await addProvider('vm-merge', 'Remix VM (Merge)', false, true, 'merge', 'settingsVMMergeMode', 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-london', 'Remix VM (London)', false, true, 'london', 'settingsVMLondonMode', titleVM)
await addProvider('vm-berlin', 'Remix VM (Berlin)', false, true, 'berlin', 'settingsVMBerlinMode', titleVM) await addProvider('vm-berlin', 'Remix VM (Berlin)', false, true, 'berlin', 'settingsVMBerlinMode', titleVM)
await addProvider('vm-mainnet-fork', 'Remix VM - Mainnet fork', false, true, 'merge', 'settingsVMMainnetMode', 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, 'merge', 'settingsVMSepoliaMode', 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, 'merge', 'settingsVMGoerliMode', 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('vm-custom-fork', 'Remix VM - Custom fork', false, true, '', 'settingsVMCustomMode', titleVM)
// wallet connect // wallet connect

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

@ -1091,9 +1091,22 @@
"bzzr://c604bdd6384bf73594cd0e5cfbe979048191549ebc88e70996346f3b744c0680", "bzzr://c604bdd6384bf73594cd0e5cfbe979048191549ebc88e70996346f3b744c0680",
"dweb:/ipfs/QmW2SQbEhiz3n2qV5iL8WBgzapv6cXjkLStvTMpCZhvr2x" "dweb:/ipfs/QmW2SQbEhiz3n2qV5iL8WBgzapv6cXjkLStvTMpCZhvr2x"
] ]
},
{
"path": "soljson-v0.8.25+commit.b61c2a91.js",
"version": "0.8.25",
"build": "commit.b61c2a91",
"longVersion": "0.8.25+commit.b61c2a91",
"keccak256": "0x4639103a26b2f669bd3ecc22b1a1665819f2a2956f917ab91380bd9565dbcd01",
"sha256": "0xf8c9554471ff2db3843167dffb7a503293b5dc728c8305b044ef9fd37d626ca7",
"urls": [
"bzzr://d201e60bd46193b11382988a854132b9e7fb0e1574cc766cb7f9efe8e44a680c",
"dweb:/ipfs/QmdduJxmPXungjJk2FBDw1bdDQ6ucHxYGLXRMBJqMFW7h9"
]
} }
], ],
"releases": { "releases": {
"0.8.25": "soljson-v0.8.25+commit.b61c2a91.js",
"0.8.24": "soljson-v0.8.24+commit.e11b9ed9.js", "0.8.24": "soljson-v0.8.24+commit.e11b9ed9.js",
"0.8.23": "soljson-v0.8.23+commit.f704f362.js", "0.8.23": "soljson-v0.8.23+commit.f704f362.js",
"0.8.22": "soljson-v0.8.22+commit.4fc1097e.js", "0.8.22": "soljson-v0.8.22+commit.4fc1097e.js",
@ -1186,5 +1199,5 @@
"0.4.0": "soljson-v0.4.0+commit.acd334c9.js", "0.4.0": "soljson-v0.4.0+commit.acd334c9.js",
"0.3.6": "soljson-v0.3.6+commit.3fc68da5.js" "0.3.6": "soljson-v0.3.6+commit.3fc68da5.js"
}, },
"latestRelease": "0.8.24" "latestRelease": "0.8.25"
} }

@ -1,7 +1,7 @@
import React from 'react' // eslint-disable-line import React from 'react' // eslint-disable-line
import {fromWei, toBigInt, toWei} from 'web3-utils' import {fromWei, toBigInt, toWei} from 'web3-utils'
import {Plugin} from '@remixproject/engine' import {Plugin} from '@remixproject/engine'
import {toBuffer, addHexPrefix} from '@ethereumjs/util' import {toBytes, addHexPrefix} from '@ethereumjs/util'
import {EventEmitter} from 'events' import {EventEmitter} from 'events'
import {format} from 'util' import {format} from 'util'
import {ExecutionContext} from './execution-context' import {ExecutionContext} from './execution-context'
@ -135,7 +135,8 @@ export class Blockchain extends Plugin {
setupEvents() { setupEvents() {
this.executionContext.event.register('contextChanged', async (context) => { this.executionContext.event.register('contextChanged', async (context) => {
await this.resetEnvironment() // reset environment to last known state of the context
await this.loadContext(context)
this._triggerEvent('contextChanged', [context]) this._triggerEvent('contextChanged', [context])
this.detectNetwork((error, network) => { this.detectNetwork((error, network) => {
this.networkStatus = {network, error} this.networkStatus = {network, error}
@ -286,7 +287,7 @@ export class Blockchain extends Plugin {
await this.saveDeployedContractStorageLayout(implementationContractObject, address, networkInfo) await this.saveDeployedContractStorageLayout(implementationContractObject, address, networkInfo)
this.events.emit('newProxyDeployment', address, new Date().toISOString(), implementationContractObject.contractName) this.events.emit('newProxyDeployment', address, new Date().toISOString(), implementationContractObject.contractName)
_paq.push(['trackEvent', 'blockchain', 'Deploy With Proxy', 'Proxy deployment successful']) _paq.push(['trackEvent', 'blockchain', 'Deploy With Proxy', 'Proxy deployment successful'])
this.call('udapp', 'addInstance', addressToString(address), implementationContractObject.abi, implementationContractObject.name) this.call('udapp', 'addInstance', addressToString(address), implementationContractObject.abi, implementationContractObject.name, implementationContractObject)
} }
this.runTx(args, confirmationCb, continueCb, promptCb, finalCb) this.runTx(args, confirmationCb, continueCb, promptCb, finalCb)
@ -336,7 +337,7 @@ export class Blockchain extends Plugin {
} }
await this.saveDeployedContractStorageLayout(newImplementationContractObject, proxyAddress, networkInfo) await this.saveDeployedContractStorageLayout(newImplementationContractObject, proxyAddress, networkInfo)
_paq.push(['trackEvent', 'blockchain', 'Upgrade With Proxy', 'Upgrade Successful']) _paq.push(['trackEvent', 'blockchain', 'Upgrade With Proxy', 'Upgrade Successful'])
this.call('udapp', 'addInstance', addressToString(proxyAddress), newImplementationContractObject.abi, newImplementationContractObject.name) this.call('udapp', 'addInstance', addressToString(proxyAddress), newImplementationContractObject.abi, newImplementationContractObject.name, newImplementationContractObject)
} }
this.runTx(args, confirmationCb, continueCb, promptCb, finalCb) this.runTx(args, confirmationCb, continueCb, promptCb, finalCb)
} }
@ -643,8 +644,23 @@ export class Blockchain extends Plugin {
}) })
} }
async resetEnvironment() { async loadContext(context: string) {
await this.getCurrentProvider().resetEnvironment() const saveEvmState = this.config.get('settings/save-evm-state')
if (saveEvmState) {
const contextExists = await this.call('fileManager', 'exists', `.states/${context}/state.json`)
if (contextExists) {
const stateDb = await this.call('fileManager', 'readFile', `.states/${context}/state.json`)
await this.getCurrentProvider().resetEnvironment(stateDb)
} else {
await this.getCurrentProvider().resetEnvironment()
}
} else {
await this.getCurrentProvider().resetEnvironment()
}
// TODO: most params here can be refactored away in txRunner // TODO: most params here can be refactored away in txRunner
const web3Runner = new TxRunnerWeb3( const web3Runner = new TxRunnerWeb3(
{ {
@ -677,7 +693,7 @@ export class Blockchain extends Plugin {
view on etherscan view on etherscan
</a> </a>
) )
} }
}) })
}) })
this.txRunner = new TxRunner(web3Runner, {}) this.txRunner = new TxRunner(web3Runner, {})
@ -889,8 +905,16 @@ export class Blockchain extends Plugin {
let execResult let execResult
let returnValue = null let returnValue = null
if (isVM) { if (isVM) {
const hhlogs = await this.web3().remix.getHHLogsForTx(txResult.transactionHash) if (!tx.useCall && this.config.get('settings/save-evm-state')) {
try {
const state = await this.executionContext.getStateDetails()
this.call('fileManager', 'writeFile', `.states/${this.executionContext.getProvider()}/state.json`, state)
} catch (e) {
console.error(e)
}
}
const hhlogs = await this.web3().remix.getHHLogsForTx(txResult.transactionHash)
if (hhlogs && hhlogs.length) { if (hhlogs && hhlogs.length) {
const finalLogs = ( const finalLogs = (
<div> <div>
@ -920,8 +944,8 @@ export class Blockchain extends Plugin {
if (execResult) { if (execResult) {
// if it's not the VM, we don't have return value. We only have the transaction, and it does not contain the return value. // if it's not the VM, we don't have return value. We only have the transaction, and it does not contain the return value.
returnValue = execResult returnValue = execResult
? toBuffer(execResult.returnValue) ? toBytes(execResult.returnValue)
: toBuffer(addHexPrefix(txResult.result) || '0x0000000000000000000000000000000000000000000000000000000000000000') : toBytes(addHexPrefix(txResult.result) || '0x0000000000000000000000000000000000000000000000000000000000000000')
const compiledContracts = await this.call('compilerArtefacts', 'getAllContractDatas') const compiledContracts = await this.call('compilerArtefacts', 'getAllContractDatas')
const vmError = txExecution.checkError({ errorMessage: execResult.exceptionError ? execResult.exceptionError.error : '', errorData: execResult.returnValue }, compiledContracts) const vmError = txExecution.checkError({ errorMessage: execResult.exceptionError ? execResult.exceptionError.error : '', errorData: execResult.returnValue }, compiledContracts)
if (vmError.error) { if (vmError.error) {
@ -930,7 +954,7 @@ export class Blockchain extends Plugin {
} }
} }
if (!isVM && tx && tx.useCall) { if (!isVM && tx && tx.useCall) {
returnValue = toBuffer(addHexPrefix(txResult.result)) returnValue = toBytes(addHexPrefix(txResult.result))
} }
let address = null let address = null

@ -3,6 +3,7 @@
import Web3 from 'web3' import Web3 from 'web3'
import { execution } from '@remix-project/remix-lib' import { execution } from '@remix-project/remix-lib'
import EventManager from '../lib/events' import EventManager from '../lib/events'
import { bytesToHex } from '@ethereumjs/util'
const _paq = window._paq = window._paq || [] const _paq = window._paq = window._paq || []
let web3 let web3
@ -22,11 +23,11 @@ web3.eth.setConfig(config)
export class ExecutionContext { export class ExecutionContext {
constructor () { constructor () {
this.event = new EventManager() this.event = new EventManager()
this.executionContext = 'vm-shanghai' this.executionContext = 'vm-cancun'
this.lastBlock = null this.lastBlock = null
this.blockGasLimitDefault = 4300000 this.blockGasLimitDefault = 4300000
this.blockGasLimit = this.blockGasLimitDefault this.blockGasLimit = this.blockGasLimitDefault
this.currentFork = 'shanghai' this.currentFork = 'cancun'
this.mainNetGenesisHash = '0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3' this.mainNetGenesisHash = '0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3'
this.customNetWorks = {} this.customNetWorks = {}
this.blocks = {} this.blocks = {}
@ -36,7 +37,7 @@ export class ExecutionContext {
} }
init (config) { init (config) {
this.executionContext = 'vm-shanghai' this.executionContext = 'vm-cancun'
this.event.trigger('contextChanged', [this.executionContext]) this.event.trigger('contextChanged', [this.executionContext])
} }
@ -71,40 +72,49 @@ export class ExecutionContext {
} }
detectNetwork (callback) { detectNetwork (callback) {
if (this.isVM()) { return new Promise((resolve, reject) => {
callback(null, { id: '-', name: 'VM' }) if (this.isVM()) {
} else { callback && callback(null, { id: '-', name: 'VM' })
if (!web3.currentProvider) { return resolve({ id: '-', name: 'VM' })
return callback('No provider set') } else {
} if (!web3.currentProvider) {
const cb = (err, id) => { callback && callback('No provider set')
let name = null return reject('No provider set')
if (err) name = 'Unknown' }
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md const cb = (err, id) => {
else if (id === 1) name = 'Main' let name = null
else if (id === 3) name = 'Ropsten' if (err) name = 'Unknown'
else if (id === 4) name = 'Rinkeby' // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
else if (id === 5) name = 'Goerli' else if (id === 1) name = 'Main'
else if (id === 42) name = 'Kovan' else if (id === 3) name = 'Ropsten'
else if (id === 11155111) name = 'Sepolia' else if (id === 4) name = 'Rinkeby'
else name = 'Custom' else if (id === 5) name = 'Goerli'
else if (id === 42) name = 'Kovan'
if (id === 1) { else if (id === 11155111) name = 'Sepolia'
web3.eth.getBlock(0).then((block) => { else name = 'Custom'
if (block && block.hash !== this.mainNetGenesisHash) name = 'Custom'
callback(err, { id, name, lastBlock: this.lastBlock, currentFork: this.currentFork }) if (id === 1) {
}).catch((error) => callback(error)) web3.eth.getBlock(0).then((block) => {
} else { if (block && block.hash !== this.mainNetGenesisHash) name = 'Custom'
callback(err, { id, name, lastBlock: this.lastBlock, currentFork: this.currentFork }) callback && callback(err, { id, name, lastBlock: this.lastBlock, currentFork: this.currentFork })
return resolve({ id, name, lastBlock: this.lastBlock, currentFork: this.currentFork })
}).catch((error) => {
callback && callback(error)
return reject(error)
})
} else {
callback && callback(err, { id, name, lastBlock: this.lastBlock, currentFork: this.currentFork })
return resolve({ id, name, lastBlock: this.lastBlock, currentFork: this.currentFork })
}
} }
web3.eth.net.getId().then(id=>cb(null,parseInt(id))).catch(err=>cb(err))
} }
web3.eth.net.getId().then(id=>cb(null,parseInt(id))).catch(err=>cb(err)) })
}
} }
removeProvider (name) { removeProvider (name) {
if (name && this.customNetWorks[name]) { if (name && this.customNetWorks[name]) {
if (this.executionContext === name) this.setContext('vm-merge', null, null, null) if (this.executionContext === name) this.setContext('vm-cancun', null, null, null)
delete this.customNetWorks[name] delete this.customNetWorks[name]
this.event.trigger('removeProvider', [name]) this.event.trigger('removeProvider', [name])
} }
@ -164,7 +174,7 @@ export class ExecutionContext {
try { try {
this.currentFork = execution.forkAt(await web3.eth.net.getId(), block.number) this.currentFork = execution.forkAt(await web3.eth.net.getId(), block.number)
} catch (e) { } catch (e) {
this.currentFork = 'merge' this.currentFork = 'cancun'
console.log(`unable to detect fork, defaulting to ${this.currentFork}..`) console.log(`unable to detect fork, defaulting to ${this.currentFork}..`)
console.error(e) console.error(e)
} }
@ -195,4 +205,32 @@ export class ExecutionContext {
return transactionDetailsLinks[network] + hash return transactionDetailsLinks[network] + hash
} }
} }
async getStateDetails() {
const stateDb = await this.web3().remix.getStateDb()
const blocksData = await this.web3().remix.getBlocksData()
const state = {
db: Object.fromEntries(stateDb.db._database),
blocks: blocksData.blocks,
latestBlockNumber: blocksData.latestBlockNumber
}
const stringifyed = JSON.stringify(state, (key, value) => {
if (key === 'db') {
return value
} else if (key === 'blocks') {
return value.map(block => bytesToHex(block))
} else if (key === '') {
return value
}
if (typeof value === 'string') {
return value.startsWith('0x') ? value : '0x' + value
} else if (typeof value === 'number') {
return '0x' + value.toString(16)
} else {
return bytesToHex(value)
}
}, '\t')
return stringifyed
}
} }

@ -1,5 +1,5 @@
import Web3 from 'web3' import Web3 from 'web3'
import { hashPersonalMessage, isHexString } from '@ethereumjs/util' import { hashPersonalMessage, isHexString, bytesToHex } from '@ethereumjs/util'
import { ExecutionContext } from '../execution-context' import { ExecutionContext } from '../execution-context'
export class InjectedProvider { export class InjectedProvider {
@ -42,7 +42,7 @@ export class InjectedProvider {
try { try {
message = isHexString(message) ? message : Web3.utils.utf8ToHex(message) message = isHexString(message) ? message : Web3.utils.utf8ToHex(message)
this.executionContext.web3().eth.personal.sign(message, account).then((error, signedData) => { this.executionContext.web3().eth.personal.sign(message, account).then((error, signedData) => {
cb(error, '0x' + messageHash.toString('hex'), signedData) cb(error, bytesToHex(messageHash), signedData)
}).catch((error => cb(error))) }).catch((error => cb(error)))
} catch (e) { } catch (e) {
cb(e.message) cb(e.message)

@ -1,5 +1,5 @@
import Web3 from 'web3' import Web3 from 'web3'
import { hashPersonalMessage, isHexString } from '@ethereumjs/util' import { hashPersonalMessage, isHexString, bytesToHex } from '@ethereumjs/util'
import { Personal } from 'web3-eth-personal' import { Personal } from 'web3-eth-personal'
import { ExecutionContext } from '../execution-context' import { ExecutionContext } from '../execution-context'
import Config from '../../config' import Config from '../../config'
@ -49,8 +49,8 @@ export class NodeProvider {
const personal = new Personal(this.executionContext.web3().currentProvider) const personal = new Personal(this.executionContext.web3().currentProvider)
message = isHexString(message) ? message : Web3.utils.utf8ToHex(message) message = isHexString(message) ? message : Web3.utils.utf8ToHex(message)
personal.sign(message, account, passphrase) personal.sign(message, account, passphrase)
.then(signedData => cb(undefined, '0x' + messageHash.toString('hex'), signedData)) .then(signedData => cb(undefined, bytesToHex(messageHash), signedData))
.catch(error => cb(error, '0x' + messageHash.toString('hex'), undefined)) .catch(error => cb(error, bytesToHex(messageHash), undefined))
} catch (e) { } catch (e) {
cb(e.message) cb(e.message)
} }

@ -1,6 +1,6 @@
import Web3, { FMT_BYTES, FMT_NUMBER, LegacySendAsyncProvider } from 'web3' import Web3, { FMT_BYTES, FMT_NUMBER, LegacySendAsyncProvider } from 'web3'
import { fromWei, toBigInt } from 'web3-utils' import { fromWei, toBigInt } from 'web3-utils'
import { privateToAddress, hashPersonalMessage, isHexString } from '@ethereumjs/util' import { privateToAddress, hashPersonalMessage, isHexString, bytesToHex } from '@ethereumjs/util'
import { extend, JSONRPCRequestPayload, JSONRPCResponseCallback } from '@remix-project/remix-simulator' import { extend, JSONRPCRequestPayload, JSONRPCResponseCallback } from '@remix-project/remix-simulator'
import { ExecutionContext } from '../execution-context' import { ExecutionContext } from '../execution-context'
@ -12,9 +12,7 @@ export class VMProvider {
sendAsync: (query: JSONRPCRequestPayload, callback: JSONRPCResponseCallback) => void sendAsync: (query: JSONRPCRequestPayload, callback: JSONRPCResponseCallback) => void
} }
newAccountCallback: {[stamp: number]: (error: Error, address: string) => void} newAccountCallback: {[stamp: number]: (error: Error, address: string) => void}
constructor (executionContext: ExecutionContext) { constructor (executionContext: ExecutionContext) {
this.executionContext = executionContext this.executionContext = executionContext
this.worker = null this.worker = null
this.provider = null this.provider = null
@ -29,7 +27,7 @@ export class VMProvider {
}) })
} }
async resetEnvironment () { async resetEnvironment (stringifiedState?: string) {
if (this.worker) this.worker.terminate() if (this.worker) this.worker.terminate()
this.worker = new Worker(new URL('./worker-vm', import.meta.url)) this.worker = new Worker(new URL('./worker-vm', import.meta.url))
const provider = this.executionContext.getProviderObject() const provider = this.executionContext.getProviderObject()
@ -76,17 +74,42 @@ export class VMProvider {
} }
} }
}) })
this.worker.postMessage({ cmd: 'init', fork: this.executionContext.getCurrentFork(), nodeUrl: provider?.options['nodeUrl'], blockNumber: provider?.options['blockNumber']}) if (stringifiedState) {
try {
const blockchainState = JSON.parse(stringifiedState)
const blockNumber = parseInt(blockchainState.latestBlockNumber, 16)
const stateDb = blockchainState.db
this.worker.postMessage({
cmd: 'init',
fork: this.executionContext.getCurrentFork(),
nodeUrl: provider?.options['nodeUrl'],
blockNumber,
stateDb,
blocks: blockchainState.blocks
})
} catch (e) {
console.error(e)
}
} else {
this.worker.postMessage({
cmd: 'init',
fork: this.executionContext.getCurrentFork(),
nodeUrl: provider?.options['nodeUrl'],
blockNumber: provider?.options['blockNumber']
})
}
}) })
} }
// TODO: is still here because of the plugin API // TODO: is still here because of the plugin API
// can be removed later when we update the API // can be removed later when we update the API
createVMAccount (newAccount) { createVMAccount (newAccount) {
const { privateKey, balance } = newAccount const { privateKey, balance } = newAccount
this.worker.postMessage({ cmd: 'addAccount', privateKey: privateKey, balance }) this.worker.postMessage({ cmd: 'addAccount', privateKey: privateKey, balance })
const privKey = Buffer.from(privateKey, 'hex') const privKey = Buffer.from(privateKey, 'hex')
return '0x' + privateToAddress(privKey).toString('hex') return bytesToHex(privateToAddress(privKey))
} }
newAccount (_passwordPromptCb, cb) { newAccount (_passwordPromptCb, cb) {
@ -109,7 +132,7 @@ export class VMProvider {
const messageHash = hashPersonalMessage(Buffer.from(message)) const messageHash = hashPersonalMessage(Buffer.from(message))
message = isHexString(message) ? message : Web3.utils.utf8ToHex(message) message = isHexString(message) ? message : Web3.utils.utf8ToHex(message)
this.web3.eth.sign(message, account) this.web3.eth.sign(message, account)
.then(signedData => cb(null, '0x' + messageHash.toString('hex'), signedData)) .then(signedData => cb(null, bytesToHex(messageHash), signedData))
.catch(error => cb(error)) .catch(error => cb(error))
} }

@ -6,7 +6,7 @@ self.onmessage = (e: MessageEvent) => {
switch (data.cmd) { switch (data.cmd) {
case 'init': case 'init':
{ {
provider = new Provider({ fork: data.fork, nodeUrl: data.nodeUrl, blockNumber: data.blockNumber }) provider = new Provider({ fork: data.fork, nodeUrl: data.nodeUrl, blockNumber: data.blockNumber, stateDb: data.stateDb, blocks: data.blocks})
provider.init().then(() => { provider.init().then(() => {
self.postMessage({ self.postMessage({
cmd: 'initiateResult', cmd: 'initiateResult',

@ -1,5 +1,5 @@
var async = require('async') var async = require('async')
import { toChecksumAddress } from '@ethereumjs/util' import { toChecksumAddress, bytesToHex } from '@ethereumjs/util'
export default { export default {
shortenAddress: function (address, etherBalance) { shortenAddress: function (address, etherBalance) {
@ -9,7 +9,7 @@ export default {
addressToString: function (address) { addressToString: function (address) {
if (!address) return null if (!address) return null
if (typeof address !== 'string') { if (typeof address !== 'string') {
address = address.toString('hex') address = bytesToHex(address)
} }
if (address.indexOf('0x') === -1) { if (address.indexOf('0x') === -1) {
address = '0x' + address address = '0x' + address

@ -12,6 +12,7 @@ let requiredModules = [ // services + layout views + system views
'config', 'config',
'compilerArtefacts', 'compilerArtefacts',
'compilerMetadata', 'compilerMetadata',
'compilerloader',
'contextualListener', 'contextualListener',
'editor', 'editor',
'offsetToLineColumnConverter', 'offsetToLineColumnConverter',
@ -61,7 +62,7 @@ let requiredModules = [ // services + layout views + system views
'vm-goerli-fork', 'vm-goerli-fork',
'vm-mainnet-fork', 'vm-mainnet-fork',
'vm-sepolia-fork', 'vm-sepolia-fork',
'vm-merge', 'vm-paris',
'vm-london', 'vm-london',
'vm-berlin', 'vm-berlin',
'vm-shanghai', 'vm-shanghai',
@ -108,6 +109,7 @@ export function isNative(name) {
'solidity', 'solidity',
'solidity-logic', 'solidity-logic',
'solidityStaticAnalysis', 'solidityStaticAnalysis',
'solhint',
'solidityUnitTesting', 'solidityUnitTesting',
'layout', 'layout',
'notification', 'notification',

@ -27,7 +27,7 @@ export class RemixEngine extends Engine {
if (name === 'filePanel') return { queueTimeout: 60000 * 20 } if (name === 'filePanel') return { queueTimeout: 60000 * 20 }
if (name === 'fileManager') return { queueTimeout: 60000 * 20 } if (name === 'fileManager') return { queueTimeout: 60000 * 20 }
if (name === 'openaigpt') return { queueTimeout: 60000 * 2 } if (name === 'openaigpt') return { queueTimeout: 60000 * 2 }
if (name === 'cookbookdev') return { queueTimeout: 60000 * 2 } if (name === 'cookbookdev') return { queueTimeout: 60000 * 3 }
return { queueTimeout: 10000 } return { queueTimeout: 10000 }
} }

@ -168,7 +168,7 @@ Before starting coding, we should ensure all devs / contributors are aware of:
### 3) Documentation: ### 3) Documentation:
- The documentation is done / updated just after the feature / release in a team effort. - The documentation is done / updated just after the feature / release in a team effort.
- Documentation work is filable as a github issue. - Documentation work is fileable as a github issue.
- It is encouraged to find and link associated doc produced by the community (blog posts, videos, tutorials, ...) - It is encouraged to find and link associated doc produced by the community (blog posts, videos, tutorials, ...)
--- ---

@ -6,7 +6,7 @@ const version = require('../../package.json').version
const fs = require('fs') const fs = require('fs')
const TerserPlugin = require('terser-webpack-plugin') const TerserPlugin = require('terser-webpack-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const axios = require('axios') const path = require('path')
const versionData = { const versionData = {
version: version, version: version,
@ -16,9 +16,10 @@ const versionData = {
const loadLocalSolJson = async () => { const loadLocalSolJson = async () => {
//execute apps/remix-ide/ci/downloadsoljson.sh //execute apps/remix-ide/ci/downloadsoljson.sh
console.log('loading local soljson')
const child = require('child_process').execSync('bash ' + __dirname + '/ci/downloadsoljson.sh', { encoding: 'utf8', cwd: process.cwd(), shell: true }) const child = require('child_process').execSync('bash ' + __dirname + '/ci/downloadsoljson.sh', { encoding: 'utf8', cwd: process.cwd(), shell: true })
// show output // show output
//console.log(child) console.log(child)
} }
fs.writeFileSync(__dirname + '/src/assets/version.json', JSON.stringify(versionData)) fs.writeFileSync(__dirname + '/src/assets/version.json', JSON.stringify(versionData))
@ -74,7 +75,7 @@ module.exports = composePlugins(withNx(), withReact(), (config) => {
// add externals // add externals
config.externals = { config.externals = {
...config.externals, ...config.externals,
solc: 'solc' solc: 'solc',
} }
// uncomment this to enable react profiling // uncomment this to enable react profiling
@ -85,6 +86,17 @@ module.exports = composePlugins(withNx(), withReact(), (config) => {
} }
*/ */
// use the web build instead of the node.js build
// we do like that because using "config.resolve.alias" doesn't work
let pkgVerkle = fs.readFileSync(path.resolve(__dirname, '../../node_modules/rust-verkle-wasm/package.json'), 'utf8')
pkgVerkle = pkgVerkle.replace('"main": "./nodejs/rust_verkle_wasm.js",', '"main": "./web/rust_verkle_wasm.js",')
fs.writeFileSync(path.resolve(__dirname, '../../node_modules/rust-verkle-wasm/package.json'), pkgVerkle)
config.resolve.alias = {
...config.resolve.alias,
// 'rust-verkle-wasm$': path.resolve(__dirname, '../../node_modules/rust-verkle-wasm/web/run_verkle_wasm.js')
}
// add public path // add public path
if(process.env.NX_DESKTOP_FROM_DIST){ if(process.env.NX_DESKTOP_FROM_DIST){
@ -112,7 +124,7 @@ module.exports = composePlugins(withNx(), withReact(), (config) => {
new webpack.ProvidePlugin({ new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'], Buffer: ['buffer', 'Buffer'],
url: ['url', 'URL'], url: ['url', 'URL'],
process: 'process/browser', process: 'process/browser'
}) })
) )

@ -52,7 +52,7 @@
"axios": "^1.6.1", "axios": "^1.6.1",
"byline": "^5.0.0", "byline": "^5.0.0",
"chokidar": "^3.5.3", "chokidar": "^3.5.3",
"express": "^4.18.2", "express": "^4.19.2",
"isomorphic-git": "^1.24.2", "isomorphic-git": "^1.24.2",
"node-pty": "^0.10.1", "node-pty": "^0.10.1",
"semver": "^7.5.4" "semver": "^7.5.4"

@ -520,9 +520,9 @@
semver "^7.3.5" semver "^7.3.5"
"@openzeppelin/contracts@^4.7.3": "@openzeppelin/contracts@^4.7.3":
version "4.9.3" version "4.9.6"
resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.3.tgz#00d7a8cf35a475b160b3f0293a6403c511099364" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.6.tgz#2a880a24eb19b4f8b25adc2a5095f2aa27f39677"
integrity sha512-He3LieZ1pP2TNt5JbkPA4PNT9WC3gOTOlDcFGJW4Le4QKqwmiNJCRt44APfxMxvq7OugU/cqYuPcSBzOw38DAg== integrity sha512-xSmezSupL+y9VkHZJGDoCBpmnB2ogM13ccaYDWqJTfS3dbuHkgjuwDFUmaFauBCboQMGB/S5UqUl2y54X99BmA==
"@openzeppelin/wizard@^0.1.1": "@openzeppelin/wizard@^0.1.1":
version "0.1.1" version "0.1.1"
@ -1259,25 +1259,7 @@ bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1:
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70"
integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==
body-parser@1.20.1: body-parser@1.20.2, body-parser@^1.16.0:
version "1.20.1"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668"
integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==
dependencies:
bytes "3.1.2"
content-type "~1.0.4"
debug "2.6.9"
depd "2.0.0"
destroy "1.2.0"
http-errors "2.0.0"
iconv-lite "0.4.24"
on-finished "2.4.1"
qs "6.11.0"
raw-body "2.5.1"
type-is "~1.6.18"
unpipe "1.0.0"
body-parser@^1.16.0:
version "1.20.2" version "1.20.2"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd"
integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==
@ -1709,10 +1691,10 @@ cookie-signature@1.0.6:
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
cookie@0.5.0: cookie@0.6.0:
version "0.5.0" version "0.6.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
core-util-is@1.0.2: core-util-is@1.0.2:
version "1.0.2" version "1.0.2"
@ -2173,13 +2155,14 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1" is-date-object "^1.0.1"
is-symbol "^1.0.2" is-symbol "^1.0.2"
es5-ext@^0.10.35, es5-ext@^0.10.50: es5-ext@^0.10.35, es5-ext@^0.10.50, es5-ext@^0.10.62, es5-ext@~0.10.14:
version "0.10.62" version "0.10.63"
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.63.tgz#9c222a63b6a332ac80b1e373b426af723b895bd6"
integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA== integrity sha512-hUCZd2Byj/mNKjfP9jXrdVZ62B8KuA/VoK7X8nUh5qT+AxDmcbvZz041oDVZdbIN1qW6XY9VDNwzkvKnZvK2TQ==
dependencies: dependencies:
es6-iterator "^2.0.3" es6-iterator "^2.0.3"
es6-symbol "^3.1.3" es6-symbol "^3.1.3"
esniff "^2.0.1"
next-tick "^1.1.0" next-tick "^1.1.0"
es6-error@^4.1.1: es6-error@^4.1.1:
@ -2224,6 +2207,16 @@ escape-string-regexp@^4.0.0:
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
esniff@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308"
integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==
dependencies:
d "^1.0.1"
es5-ext "^0.10.62"
event-emitter "^0.3.5"
type "^2.7.2"
etag@~1.8.1: etag@~1.8.1:
version "1.8.1" version "1.8.1"
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
@ -2351,6 +2344,14 @@ ethjs-unit@0.1.6:
bn.js "4.11.6" bn.js "4.11.6"
number-to-bn "1.7.0" number-to-bn "1.7.0"
event-emitter@^0.3.5:
version "0.3.5"
resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==
dependencies:
d "1"
es5-ext "~0.10.14"
eventemitter3@4.0.4: eventemitter3@4.0.4:
version "4.0.4" version "4.0.4"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384"
@ -2374,17 +2375,17 @@ exponential-backoff@^3.1.1:
resolved "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz" resolved "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz"
integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==
express@^4.14.0, express@^4.18.2: express@^4.14.0, express@^4.19.2:
version "4.18.2" version "4.19.2"
resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465"
integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==
dependencies: dependencies:
accepts "~1.3.8" accepts "~1.3.8"
array-flatten "1.1.1" array-flatten "1.1.1"
body-parser "1.20.1" body-parser "1.20.2"
content-disposition "0.5.4" content-disposition "0.5.4"
content-type "~1.0.4" content-type "~1.0.4"
cookie "0.5.0" cookie "0.6.0"
cookie-signature "1.0.6" cookie-signature "1.0.6"
debug "2.6.9" debug "2.6.9"
depd "2.0.0" depd "2.0.0"
@ -2489,9 +2490,9 @@ finalhandler@1.2.0:
unpipe "~1.0.0" unpipe "~1.0.0"
follow-redirects@^1.15.0: follow-redirects@^1.15.0:
version "1.15.3" version "1.15.6"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
for-each@^0.3.3: for-each@^0.3.3:
version "0.3.3" version "0.3.3"
@ -4197,16 +4198,6 @@ range-parser@~1.2.1:
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
raw-body@2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857"
integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==
dependencies:
bytes "3.1.2"
http-errors "2.0.0"
iconv-lite "0.4.24"
unpipe "1.0.0"
raw-body@2.5.2: raw-body@2.5.2:
version "2.5.2" version "2.5.2"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"

@ -13,7 +13,7 @@
"icon": "https://raw.githubusercontent.com/protofire/solhint/master/solhint-icon.png", "icon": "https://raw.githubusercontent.com/protofire/solhint/master/solhint-icon.png",
"location": "hiddenPanel", "location": "hiddenPanel",
"url": "", "url": "",
"documentation": "https://remix-plugins.readthedocs.io/en/latest/", "documentation": "https://remix-ide.readthedocs.io/en/latest/static_analysis.html",
"repo": "https://github.com/ethereum/remix-project", "repo": "https://github.com/ethereum/remix-project",
"maintainedBy": "Remix", "maintainedBy": "Remix",
"authorContact": "remix@ethereum.org" "authorContact": "remix@ethereum.org"

@ -245,9 +245,9 @@ fast-json-stable-stringify@^2.0.0:
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
follow-redirects@^1.14.0: follow-redirects@^1.14.0:
version "1.15.4" version "1.15.6"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw== integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
fs.realpath@^1.0.0: fs.realpath@^1.0.0:
version "1.0.0" version "1.0.0"

@ -222,3 +222,47 @@ html, body, #root, main {
margin: 15px; margin: 15px;
padding: 15px; padding: 15px;
} }
.cursor-status {
}
.cursor-status :hover {
cursor: pointer;
}
.accordion-background {
background-color: var(--body-bg);
}
.accordion-background:hover {
cursor: pointer;
}
.vyper-compile-warning,
.vyper-compile-error {
white-space: pre-line;
word-wrap: break-word;
cursor: pointer;
position: relative;
margin: 0.5em 0 1em 0;
border-radius: 5px;
line-height: 20px;
padding: 8px 15px;
}
.vyper-compile-warning pre,
.vyper-compile-error pre {
white-space: pre-line;
overflow-y: hidden;
background-color: transparent;
margin: 0;
font-size: 12px;
border: 0 none;
padding: 0;
border-radius: 0;
}
.vyper-panel-width {
width: 94%;
}

@ -1,4 +1,4 @@
import React, {useState, useEffect} from 'react' import React, {useState, useEffect, useRef} from 'react'
import {remixClient} from './utils' import {remixClient} from './utils'
import {CompilationResult} from '@remixproject/plugin-api' import {CompilationResult} from '@remixproject/plugin-api'
@ -11,11 +11,14 @@ import LocalUrlInput from './components/LocalUrl'
import ToggleButtonGroup from 'react-bootstrap/ToggleButtonGroup' import ToggleButtonGroup from 'react-bootstrap/ToggleButtonGroup'
import ToggleButton from 'react-bootstrap/ToggleButton' import ToggleButton from 'react-bootstrap/ToggleButton'
import Button from 'react-bootstrap/Button' import Button from 'react-bootstrap/Button'
import Accordion from 'react-bootstrap/Accordion'
import Card from 'react-bootstrap/Card'
import './app.css' import './app.css'
import {CustomTooltip} from '@remix-ui/helper' import {CustomTooltip} from '@remix-ui/helper'
import {Form} from 'react-bootstrap' import {Form} from 'react-bootstrap'
import {CompileErrorCard} from './components/CompileErrorCard' import {CompileErrorCard} from './components/CompileErrorCard'
import CustomAccordionToggle from './components/CustomAccordionToggle'
interface AppState { interface AppState {
status: 'idle' | 'inProgress' status: 'idle' | 'inProgress'
@ -37,11 +40,16 @@ const App = () => {
localUrl: 'http://localhost:8000/', localUrl: 'http://localhost:8000/',
}) })
const spinnerIcon = useRef(null)
useEffect(() => { useEffect(() => {
async function start() { async function start() {
try { try {
await remixClient.loaded() await remixClient.loaded()
remixClient.onFileChange((name) => setContract(name)) remixClient.onFileChange((name) => {
setOutput({})
setContract(name)
})
remixClient.onNoFileSelected(() => setContract('')) remixClient.onNoFileSelected(() => setContract(''))
} catch (err) { } catch (err) {
console.log(err) console.log(err)
@ -68,9 +76,6 @@ const App = () => {
useEffect(() => { useEffect(() => {
remixClient.eventEmitter.on('setOutput', (payload) => { remixClient.eventEmitter.on('setOutput', (payload) => {
if (payload.status === 'failed') {
console.error('Error in the compiler', payload)
}
setOutput(payload) setOutput(payload)
}) })
@ -98,17 +103,17 @@ const App = () => {
setOutput(remixClient.compilerOutput) setOutput(remixClient.compilerOutput)
} }
const startingCompilation = () => {
if (!spinnerIcon.current) return
spinnerIcon.current.setAttribute('title', 'compiling...')
spinnerIcon.current.classList.remove('remixui_bouncingIcon')
spinnerIcon.current.classList.add('remixui_spinningIcon')
}
const [toggleAccordion, setToggleAccordion] = useState(false)
return ( return (
<main id="vyper-plugin"> <main id="vyper-plugin">
<header>
<div className="title">
<img src={'assets/vyperLogo_v2.webp'} alt="Vyper logo" />
<h4 className="pl-1">yper Compiler</h4>
</div>
<a rel="noopener noreferrer" href="https://github.com/ethereum/remix-project/tree/master/apps/vyper" target="_blank">
<i className="fab fa-github"></i>
</a>
</header>
<section> <section>
<div className="px-3 pt-3 mb-3 w-100"> <div className="px-3 pt-3 mb-3 w-100">
<CustomTooltip placement="bottom" tooltipText="Clone Vyper examples. Switch to the File Explorer to see the examples."> <CustomTooltip placement="bottom" tooltipText="Clone Vyper examples. Switch to the File Explorer to see the examples.">
@ -117,25 +122,55 @@ const App = () => {
</Button> </Button>
</CustomTooltip> </CustomTooltip>
</div> </div>
<Form>
<div className="d-flex flex-row gap-5 mb-3 mt-2"> <Accordion className="border-0 w-100 mb-3 accordion-background">
<Form.Check inline data-id="remote-compiler" type="radio" value={state.environment} checked={state.environment === 'remote'} onChange={() => setEnvironment('remote')} label="Remote Compiler" style={{cursor: state.environment === 'remote' ? 'default' : 'pointer'}} className="d-flex mr-4" /> <div className="border-0">
<Form.Check inline id="local-compiler" data-id="local-compiler" checked={state.environment === 'local'} type="radio" name="local" value={state.environment} onChange={() => setEnvironment('local')} label="Local Compiler" style={{cursor: state.environment === 'local' ? 'default' : 'pointer'}} /> <div className="">
<CustomAccordionToggle eventKey="0">
<span className="">Advanced Compiler Settings</span>
</CustomAccordionToggle>
</div>
<Accordion.Collapse eventKey="0">
<div className="pt-2">
<Form>
<div className="d-flex flex-row justify-content-around mb-1 mt-2">
<div className={`custom-control custom-radio ${state.environment === 'remote' ? 'd-flex' : 'd-flex cursor-status'}`}>
<input type="radio" id="remote-compiler" data-id="remote-compiler" name="remote" value={state.environment} checked={state.environment === 'remote'} onChange={() => setEnvironment('remote')} className={`custom-control-input ${state.environment === 'remote' ? 'd-flex mr-1' : 'd-flex mr-1 cursor-status'}`} />
<label htmlFor="remote-compiler" className="form-check-label custom-control-label">Remote Compiler</label>
</div>
<div className={`custom-control custom-radio ${state.environment === 'local' ? 'mr-2' : `cursor-status`}`}>
<input id="local-compiler" data-id="local-compiler" checked={state.environment === 'local'} type="radio" name="local" value={state.environment} onChange={() => setEnvironment('local')} className={`custom-control-input ${state.environment === 'local' ? '' : `cursor-status`}`} />
<label htmlFor="local-compiler" className="form-check-label custom-control-label">Local Compiler</label>
</div>
</div>
</Form>
<LocalUrlInput url={state.localUrl} setUrl={setLocalUrl} environment={state.environment} />
</div>
</Accordion.Collapse>
</div> </div>
</Form> </Accordion>
<span className="px-3 mt-1 mb-1 small text-warning">Specify the compiler version & EVM version in the .vy file</span> <span className="px-3 mt-3 mb-3 small text-warning">
<LocalUrlInput url={state.localUrl} setUrl={setLocalUrl} environment={state.environment} /> Specify the{' '}
<a className="text-warning" target="_blank" href="https://remix-ide.readthedocs.io/en/latest/vyper.html#specify-vyper-version">
compiler version
</a>{' '}
&{' '}
<a className="text-warning" href="http://docs.vyperlang.org/en/stable/compiling-a-contract.html#setting-the-target-evm-version" target="_blank" rel="noopener noreferrer">
EVM version
</a>{' '}
in the .vy file.
</span>
<div className="px-3 w-100 mb-3 mt-1" id="compile-btn"> <div className="px-3 w-100 mb-3 mt-1" id="compile-btn">
<CompilerButton compilerUrl={compilerUrl()} contract={contract} setOutput={(name, update) => setOutput({...output, [name]: update})} resetCompilerState={resetCompilerResultState} /> <CompilerButton compilerUrl={compilerUrl()} contract={contract} setOutput={(name, update) => setOutput({...output, [name]: update})} resetCompilerState={resetCompilerResultState} />
</div> </div>
<article id="result" className="px-2 mx-2 border-top mt-3"> <article id="result" className="p-2 mx-3 border-top mt-2">
{output && Object.keys(output).length > 0 && output.status !== 'failed' ? ( {output && Object.keys(output).length > 0 && output.status !== 'failed' ? (
<> <>
<VyperResult output={output} plugin={remixClient} /> <VyperResult output={output} plugin={remixClient} />
</> </>
) : output.status === 'failed' ? ( ) : output.status === 'failed' ? (
<CompileErrorCard output={output} /> <CompileErrorCard output={output} plugin={remixClient} />
) : null} ) : null}
</article> </article>
</section> </section>

@ -1,12 +1,17 @@
import {CopyToClipboard} from '@remix-ui/clipboard'
import Reaact from 'react' import Reaact from 'react'
import { RemixClient } from '../utils'
export function CompileErrorCard(props: any) { export function CompileErrorCard(props: { output: any, plugin: RemixClient }) {
return ( return (
<div id="vyperErrorResult" className="px-2 mx-3 alert alert-danger error" title={props.output.message}> <div
<i className="fas fa-exclamation-circle text-danger"></i> id="vyperErrorResult"
className=" d-flex flex-column p-2 alert alert-danger error vyper-compile-error vyper-panel-width"
title={props.output?.title}
>
<span <span
data-id="error-message" data-id="error-message"
className="text-center" className="text-left"
style={{ style={{
overflowX: 'hidden', overflowX: 'hidden',
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
@ -14,6 +19,16 @@ export function CompileErrorCard(props: any) {
> >
{props.output.message.trim()} {props.output.message.trim()}
</span> </span>
<div className="d-flex flex-column pt-3 align-items-end mb-2">
<div>
<span className="border border-success text-success btn-sm" onClick={async () => await props.plugin.askGpt(props.output.message)}>
Ask GPT
</span>
<span className="ml-3 pt-1 py-1">
<CopyToClipboard content={props.output.message} className={`p-0 m-0 far fa-copy alert alert-danger`} direction={'top'} />
</span>
</div>
</div>
</div> </div>
) )
} }

@ -29,7 +29,7 @@ function CompilerButton({contract, setOutput, compilerUrl, resetCompilerState}:
className="btn btn-primary w-100 d-block btn-block text-break remixui_disabled mb-1 mt-3" className="btn btn-primary w-100 d-block btn-block text-break remixui_disabled mb-1 mt-3"
> >
<div className="d-flex align-items-center justify-content-center fa-1x"> <div className="d-flex align-items-center justify-content-center fa-1x">
<span className="fas fa-sync fa-pulse mr-1" /> {/* <span className="fas fa-sync fa-pulse mr-1" /> */}
<div className="text-truncate overflow-hidden text-nowrap"> <div className="text-truncate overflow-hidden text-nowrap">
<span>Compile</span> <span>Compile</span>
<span className="ml-1 text-nowrap">{contract}</span> <span className="ml-1 text-nowrap">{contract}</span>

@ -0,0 +1,26 @@
import React, { useState } from 'react'
import { useAccordionToggle } from 'react-bootstrap/AccordionToggle'
export type CustomAccordionToggleProps = {
children: React.ReactNode
eventKey: string
callback?: any
}
export default function CustomAccordionToggle({ children, eventKey }: CustomAccordionToggleProps) {
const [toggleAccordion, setToggleAccordion] = useState(false)
const decoratedOnClick = useAccordionToggle(eventKey, () =>
setToggleAccordion(!toggleAccordion)
)
return (
<div
onClick={decoratedOnClick}
className="d-flex flex-row justify-content-between align-items-center mx-3"
>
{children}
<i className={toggleAccordion ? 'far fa-angle-down' : 'far fa-angle-right'}></i>
</div>
)
}

@ -58,9 +58,8 @@ function VyperResult({ output, plugin }: VyperResultProps) {
return ( return (
<> <>
<div className="border border-top"></div> <div className="d-flex justify-content-center mx-3 mb-3 mt-1 vyper-panel-width flex-column">
<div className="d-flex justify-content-center px-2 w-100 flex-column border border-bottom"> <button data-id="compilation-details" className="btn btn-secondary d-block btn-block" onClick={async () => {
<button data-id="compilation-details" className="btn btn-secondary w-100" onClick={async () => {
await plugin?.call('vyperCompilationDetails', 'showDetails', output) await plugin?.call('vyperCompilationDetails', 'showDetails', output)
}}> }}>
<span>Compilation Details</span> <span>Compilation Details</span>
@ -68,17 +67,17 @@ function VyperResult({ output, plugin }: VyperResultProps) {
<div className="mt-1"> <div className="mt-1">
<div className="input-group input-group mt-3 d-flex flex-row-reverse"> <div className="input-group input-group mt-3 d-flex flex-row-reverse">
<div className="btn-group align-self-start" role="group" aria-label="Copy to Clipboard"> <div className="btn-group align-self-start" role="group" aria-label="Copy to Clipboard">
<CopyToClipboard tip={'Copy ABI to clipboard'} getContent={() => (Object.values(output)[0] as OutputType).abi} direction="bottom" icon="far fa-copy"> <CopyToClipboard tip={'Copy ABI to clipboard'} getContent={() => (Object.values(output)[1] as OutputType)?.abi} direction="bottom" icon="far fa-copy">
<button className="btn remixui_copyButton"> <span className="btn remixui_copyButton">
<i className="remixui_copyIcon far fa-copy" aria-hidden="true"></i> <i className="remixui_copyIcon far fa-copy" aria-hidden="true"></i>
<span>ABI</span> <span>ABI</span>
</button> </span>
</CopyToClipboard> </CopyToClipboard>
<CopyToClipboard tip={'Copy Bytecode to clipboard'} getContent={() => (Object.values(output)[0] as OutputType).bytecode.object} direction="bottom" icon="far fa-copy"> <CopyToClipboard tip={'Copy Bytecode to clipboard'} getContent={() => (Object.values(output)[1] as OutputType)?.bytecode.object} direction="bottom" icon="far fa-copy">
<button className="btn remixui_copyButton"> <span className="btn remixui_copyButton">
<i className="remixui_copyIcon far fa-copy" aria-hidden="true"></i> <i className="remixui_copyIcon far fa-copy" aria-hidden="true"></i>
<span>Bytecode</span> <span>Bytecode</span>
</button> </span>
</CopyToClipboard> </CopyToClipboard>
</div> </div>
</div> </div>

@ -31,9 +31,7 @@ export interface VyperCompilationError {
export type VyperCompilationOutput = VyperCompilationResult | VyperCompilationError export type VyperCompilationOutput = VyperCompilationResult | VyperCompilationError
/** Check if the output is an error */ /** Check if the output is an error */
export function isCompilationError(output: VyperCompilationOutput): output is VyperCompilationError { export const isCompilationError = (output: VyperCompilationOutput): output is VyperCompilationError => output.status === 'failed'
return output.status === 'failed'
}
export function normalizeContractPath(contractPath: string): string[] { export function normalizeContractPath(contractPath: string): string[] {
const paths = contractPath.split('/') const paths = contractPath.split('/')
@ -52,22 +50,113 @@ function parseErrorString(errorString) {
// Split the string into lines // Split the string into lines
let lines = errorString.trim().split('\n') let lines = errorString.trim().split('\n')
// Extract the line number and message // Extract the line number and message
let message = lines[1].trim() let message = errorString.trim()
let targetLine = lines[2].split(',') let targetLine = lines[2].split(',')
let lineColumn = targetLine[targetLine.length - 1].split(' ')[2].split(':') let tline = lines[2].trim().split(' ')[1].split(':')
const errorObject = { const errorObject = {
status: 'failed', status: 'failed',
message: message, message: message,
column: parseInt(lineColumn[1]), column: tline[1],
line: parseInt(lineColumn[0]) line: tline[0]
} }
message = null message = null
targetLine = null targetLine = null
lineColumn = null
lines = null lines = null
tline = null
return errorObject return errorObject
} }
const buildError = (output) => {
if (isCompilationError(output)) {
const line = output.line
if (line) {
const lineColumnPos = {
start: {line: line - 1, column: 10},
end: {line: line - 1, column: 10}
}
// remixClient.highlight(lineColumnPos as any, _contract.name, '#e0b4b4')
} else {
const regex = output?.message?.match(/line ((\d+):(\d+))+/g)
const errors = output?.message?.split(/line ((\d+):(\d+))+/g) // extract error message
if (regex) {
let errorIndex = 0
regex.map((errorLocation) => {
const location = errorLocation?.replace('line ', '').split(':')
let message = errors[errorIndex]
errorIndex = errorIndex + 4
if (message && message?.split('\n\n').length > 0) {
try {
message = message?.split('\n\n')[message.split('\n\n').length - 1]
} catch (e) {}
}
if (location?.length > 0) {
const lineColumnPos = {
start: {line: parseInt(location[0]) - 1, column: 10},
end: {line: parseInt(location[0]) - 1, column: 10}
}
// remixClient.highlight(lineColumnPos as any, _contract.name, message)
}
})
}
}
throw new Error(output.message)
}
}
const compileReturnType = (output, contract) => {
const t: any = toStandardOutput(contract, output)
const temp = _.merge(t['contracts'][contract])
const normal = normalizeContractPath(contract)[2]
const abi = temp[normal]['abi']
const evm = _.merge(temp[normal]['evm'])
const dpb = evm.deployedBytecode
const runtimeBytecode = evm.bytecode
const methodIdentifiers = evm.methodIdentifiers
const version = output?.compilers[0]?.version ?? '0.3.10'
const optimized = output?.compilers[0]?.settings?.optimize ?? true
const evmVersion = ''
const result: {
contractName: any,
abi: any,
bytecode: any,
runtimeBytecode: any,
ir: '',
methodIdentifiers: any,
version?: '',
evmVersion?: ''
optimized?: boolean
} = {
contractName: normal,
abi,
bytecode: dpb,
runtimeBytecode,
ir: '',
methodIdentifiers,
version,
evmVersion,
optimized
}
return result
}
const fixContractContent = (content: string) => {
if (content.length === 0) return
const pragmaFound = 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) {
content = `${evmVer}\n${content}`
}
if (!pragmaFound) {
content = `${pragma}\n${content}`
}
return content
}
/** /**
* Compile the a contract * Compile the a contract
* @param url The url of the compiler * @param url The url of the compiler
@ -82,11 +171,13 @@ export async function compile(url: string, contract: Contract): Promise<any> {
throw new Error('Use extension .vy for Vyper.') throw new Error('Use extension .vy for Vyper.')
} }
let contractName = contract['name'] let contractName = contract['name']
const compilePackage = { const compilePackage = {
manifest: 'ethpm/3', manifest: 'ethpm/3',
sources: { sources: {
[contractName] : {content : contract.content} [contractName] : {content : fixContractContent(contract.content)}
} }
} }
let response = await axios.post(`${url}compile`, compilePackage ) let response = await axios.post(`${url}compile`, compilePackage )
@ -181,15 +272,11 @@ export async function compileContract(contract: string, compilerUrl: string, set
try { try {
_contract = await remixClient.getContract() _contract = await remixClient.getContract()
} catch (e: any) { } catch (e: any) {
// if (setOutput === null || setOutput === undefined) { const errorGettingContract = {
const compileResult = {
status: 'failed', status: 'failed',
message: e.message message: e.message
} }
remixClient.eventEmitter.emit('setOutput', compileResult) remixClient.eventEmitter.emit('setOutput', errorGettingContract)
// } else {
// setOutput('', {status: 'failed', message: e.message})
// }
return return
} }
remixClient.changeStatus({ remixClient.changeStatus({
@ -198,76 +285,19 @@ export async function compileContract(contract: string, compilerUrl: string, set
title: 'Compiling' title: 'Compiling'
}) })
let output let output
try { // try {
output = await compile(compilerUrl, _contract) output = await compile(compilerUrl, _contract)
console.log('checking compile result', output) if (output.status === 'failed') {
remixClient.eventEmitter.emit('setOutput', output)
} catch (e: any) {
remixClient.changeStatus({ remixClient.changeStatus({
key: 'failed', key: 'failed',
type: 'error', type: 'error',
title: `${e.message} debugging` title: 'Compilation failed...'
}) })
// setOutput !== null || setOutput !== undefined && setOutput('', {status: 'failed', message: e.message}) remixClient.eventEmitter.emit('setOutput', {status: 'failed', message: output.message, title: 'Error compiling...', line: output.line, column: output.column})
remixClient.eventEmitter.emit('setOutput', {status: 'failed', message: e.message}) output = null
return return
} }
const compileReturnType = () => {
const t: any = toStandardOutput(contract, output)
const temp = _.merge(t['contracts'][contract])
const normal = normalizeContractPath(contract)[2]
const abi = temp[normal]['abi']
const evm = _.merge(temp[normal]['evm'])
const dpb = evm.deployedBytecode
const runtimeBytecode = evm.bytecode
const methodIdentifiers = evm.methodIdentifiers
const result = {
contractName: normal,
abi: abi,
bytecode: dpb,
runtimeBytecode: runtimeBytecode,
ir: '',
methodIdentifiers: methodIdentifiers
}
return result
}
// ERROR
if (isCompilationError(output)) {
const line = output.line
if (line) {
const lineColumnPos = {
start: {line: line - 1, column: 10},
end: {line: line - 1, column: 10}
}
// remixClient.highlight(lineColumnPos as any, _contract.name, '#e0b4b4')
} else {
const regex = output?.message?.match(/line ((\d+):(\d+))+/g)
const errors = output?.message?.split(/line ((\d+):(\d+))+/g) // extract error message
if (regex) {
let errorIndex = 0
regex.map((errorLocation) => {
const location = errorLocation?.replace('line ', '').split(':')
let message = errors[errorIndex]
errorIndex = errorIndex + 4
if (message && message?.split('\n\n').length > 0) {
try {
message = message?.split('\n\n')[message.split('\n\n').length - 1]
} catch (e) {}
}
if (location?.length > 0) {
const lineColumnPos = {
start: {line: parseInt(location[0]) - 1, column: 10},
end: {line: parseInt(location[0]) - 1, column: 10}
}
// remixClient.highlight(lineColumnPos as any, _contract.name, message)
}
})
}
}
throw new Error(output.message)
}
// SUCCESS // SUCCESS
// remixClient.discardHighlight() // remixClient.discardHighlight()
remixClient.changeStatus({ remixClient.changeStatus({
@ -278,12 +308,12 @@ export async function compileContract(contract: string, compilerUrl: string, set
const data = toStandardOutput(_contract.name, output) const data = toStandardOutput(_contract.name, output)
remixClient.compilationFinish(_contract.name, _contract.content, data) remixClient.compilationFinish(_contract.name, _contract.content, data)
const contractName = _contract['name']
const compileResult = compileReturnType(output, contractName)
if (setOutput === null || setOutput === undefined) { if (setOutput === null || setOutput === undefined) {
const contractName = _contract['name']
const compileResult = compileReturnType()
remixClient.eventEmitter.emit('setOutput', { contractName, compileResult }) remixClient.eventEmitter.emit('setOutput', { contractName, compileResult })
} else { } else {
setOutput(_contract.name, compileReturnType()) remixClient.eventEmitter.emit('setOutput', { contractName, compileResult })
} }
} catch (err: any) { } catch (err: any) {
remixClient.changeStatus({ remixClient.changeStatus({

@ -60,6 +60,23 @@ export class RemixClient extends PluginClient {
} }
} }
async askGpt(message: string) {
if (message.length === 0) {
this.client.call('terminal', 'log', { type: 'log', value: 'kindly send a proper message so I can respond please' })
return
}
try {
const formattedMessage = `
${message}
can you explain why this error occurred and how to fix it?
`
await this.client.call('openaigpt' as any, 'message', formattedMessage)
} catch (err) {
console.error('unable to askGpt')
console.error(err)
}
}
async cloneVyperRepo() { async cloneVyperRepo() {
try { try {
// @ts-ignore // @ts-ignore
@ -144,4 +161,3 @@ export class RemixClient extends PluginClient {
} }
export const remixClient = new RemixClient() export const remixClient = new RemixClient()
// export const RemixClientContext = React.createContext(new RemixClient())

@ -7,8 +7,12 @@
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" /> <link rel="icon" type="image/x-icon" href="favicon.ico" />
<link rel="stylesheet" integrity="ha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf"
crossorigin="anonymous" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css">
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>
<script src="https://kit.fontawesome.com/41dd021e94.js" crossorigin="anonymous"></script>
</body> </body>
</html> </html>

@ -1,12 +1,12 @@
{ {
"name": "vyper", "name": "vyper",
"displayName": "Vyper", "displayName": "Vyper Compiler",
"methods": ["getCompilationResult", "compile", "vyperCompileCustomAction"], "methods": ["getCompilationResult", "compile", "vyperCompileCustomAction"],
"url": "https://ipfs-cluster.ethdevops.io/ipfs/QmbmPzUg7ghTKcF2eo64zm1k1LKdibYfqYmiqXkHKXks8r", "url": "https://ipfs-cluster.ethdevops.io/ipfs/QmbmPzUg7ghTKcF2eo64zm1k1LKdibYfqYmiqXkHKXks8r",
"documentation": "https://remix-ide.readthedocs.io/en/latest/plugin_list.html", "documentation": "https://remix-ide.readthedocs.io/en/latest/vyper.html",
"description": "Compile vyper contracts", "description": "Compile vyper contracts",
"kind": "compiler", "kind": "compiler",
"icon": "data:image/svg+xml;base64,PHN2ZyBpZD0iRmxhdF9Mb2dvIiBkYXRhLW5hbWU9IkZsYXQgTG9nbyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMjA0OCAxNzczLjYyIj4gIDx0aXRsZT52eXBlci1sb2dvLWZsYXQ8L3RpdGxlPiAgPHBvbHlsaW5lIHBvaW50cz0iMTAyNCA4ODYuODEgNzY4IDEzMzAuMjIgMTAyNCAxNzczLjYyIDEyODAgMTMzMC4yMiAxMDI0IDg4Ni44MSIgc3R5bGU9ImZpbGw6IzMzMyIvPiAgPHBvbHlsaW5lIHBvaW50cz0iMTI4MCA0NDMuNDEgMTAyNCA4ODYuODEgMTI4MCAxMzMwLjIyIDE1MzYgODg2LjgxIDEyODAgNDQzLjQxIiBzdHlsZT0iZmlsbDojNjY2Ii8+ICA8cG9seWxpbmUgcG9pbnRzPSI3NjggNDQzLjQxIDUxMiA4ODYuODEgNzY4IDEzMzAuMjIgMTAyNCA4ODYuODEgNzY4IDQ0My40MSIgc3R5bGU9ImZpbGw6IzY2NiIvPiAgPHBvbHlsaW5lIHBvaW50cz0iMTUzNiAwIDEyODAgNDQzLjQxIDE1MzYgODg2LjgxIDE3OTIgNDQzLjQxIDE1MzYgMCIgc3R5bGU9ImZpbGw6IzhjOGM4YyIvPiAgPHBvbHlsaW5lIHBvaW50cz0iMTE1MiAyMjEuNyA4OTYgMjIxLjcgNzY4IDQ0My40MSAxMDI0IDg4Ni44MSAxMjgwIDQ0My40MSAxMTUyIDIyMS43IiBzdHlsZT0iZmlsbDojOGM4YzhjIi8+ICA8cG9seWxpbmUgcG9pbnRzPSI1MTIgMCAyNTYgNDQzLjQxIDUxMiA4ODYuODEgNzY4IDQ0My40MSA1MTIgMCIgc3R5bGU9ImZpbGw6IzhjOGM4YyIvPiAgPHBvbHlsaW5lIHBvaW50cz0iMjA0OCAwIDE1MzYgMCAxNzkyIDQ0My40IDIwNDggMCIgc3R5bGU9ImZpbGw6I2IyYjJiMiIvPiAgPHBvbHlsaW5lIHBvaW50cz0iNTEyIDAgMCAwIDI1NiA0NDMuNCA1MTIgMCIgc3R5bGU9ImZpbGw6I2IyYjJiMiIvPjwvc3ZnPg==", "icon": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzM4IiBoZWlnaHQ9IjM3NiIgdmlld0JveD0iMCAwIDMzOCAzNzYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0xOTUuMzA0IDMxMS44MzdMODIuNTE4IDE5OS4wODRDNzcuOTI0MSAxOTQuMzA0IDc1LjM5MjcgMTg3LjgzNyA3NS4zOTI3IDE4MC42MlYxOS42OTE0Qzc1LjM5MjcgMTAuMzE4OCA2Ni4wMTc0IDAuOTQ2MTI3IDU2LjY0MiAwLjk0NjEyN0gxOS4wNDY3QzkuNjcxMjggMC45NDYxMjcgMC4yOTU4OTggMTAuMzE4OCAwLjI5NTg5OCAxOS42OTE0VjIwNy4xNDVDMC4yOTU4OTggMjE3LjA4IDMuOTUyMyAyMjYuNjQgMTAuOTgzOCAyMzMuNjY5TDE0Mi4yMzkgMzY0Ljg4NkMxNDkuNTUyIDM3Mi4xOTcgMTU5LjExNSAzNzUuODUyIDE2OC43NzIgMzc1Ljg1MkgxODcuNTIyQzE5Ny45MjkgMzc1Ljg1MiAyMDYuMjczIDM2Ny40MTcgMjA2LjI3MyAzNTcuMTA3VjMzOC40NTZDMjA2LjI3MyAzMjguODAyIDIwMi42MTcgMzE5LjI0MiAxOTUuMzA0IDMxMS45MzFWMzExLjgzN1oiIGZpbGw9IiMxODBDMjUiLz4KPHBhdGggZD0iTTMzNy44MSAxOS41OTc3QzMzNy44MSAxMC4xMzEzIDMyOC41MjkgMC44NTI0MTcgMzE5LjA1OSAwLjg1MjQxN0gyODEuNDY0QzI3Mi4wODkgMC44NTI0MTcgMjYyLjcxMyAxMC4yMjUxIDI2Mi43MTMgMTkuNTk3N1YxODAuNDMzQzI2Mi43MTMgMTg3LjY1IDI1OS45MDEgMTk0LjExNyAyNTUuMjEzIDE5OC45OUwyMTcuNDMgMjM2Ljc2MkMyMTAuMTE4IDI0NC4wNzMgMjA2LjQ2MSAyNTMuNjMzIDIwNi40NjEgMjYzLjI4N1YyODIuMDMyQzIwNi40NjEgMjkyLjQzNiAyMTQuODk5IDMwMC43NzggMjI1LjIxMiAzMDAuNzc4SDI0My45NjNDMjUzLjUyNiAzMDAuNzc4IDI2My4xODIgMjk3LjEyMiAyNzAuNDk1IDI4OS44MTFMMzI2Ljc0NyAyMzMuNTc2QzMzMy43NzkgMjI2LjU0NiAzMzcuNzE2IDIxNi45ODYgMzM3LjcxNiAyMDcuMDUxVjE5LjU5NzdIMzM3LjgxWiIgZmlsbD0iIzE4MEMyNSIvPgo8L3N2Zz4K",
"location": "sidePanel", "location": "sidePanel",
"repo": "https://github.com/ethereum/remix-project/tree/master/apps/vyper", "repo": "https://github.com/ethereum/remix-project/tree/master/apps/vyper",
"maintainedBy": "Remix", "maintainedBy": "Remix",

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/ghaction-helper", "name": "@remix-project/ghaction-helper",
"version": "0.1.22", "version": "0.1.25",
"description": "Solidity Tests GitHub Action Helper", "description": "Solidity Tests GitHub Action Helper",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {
@ -19,17 +19,17 @@
}, },
"homepage": "https://github.com/ethereum/remix-project#readme", "homepage": "https://github.com/ethereum/remix-project#readme",
"devDependencies": { "devDependencies": {
"@remix-project/remix-solidity": "^0.5.28", "@remix-project/remix-solidity": "^0.5.31",
"@types/chai": "^4.3.4", "@types/chai": "^4.3.4",
"typescript": "^4.9.3" "typescript": "^4.9.3"
}, },
"dependencies": { "dependencies": {
"@ethereum-waffle/chai": "^3.4.4", "@ethereum-waffle/chai": "^3.4.4",
"@remix-project/remix-simulator": "^0.2.42", "@remix-project/remix-simulator": "^0.2.45",
"chai": "^4.3.7", "chai": "^4.3.7",
"ethers": "^5.7.2", "ethers": "^5.7.2",
"web3": "^4.1.1" "web3": "^4.1.1"
}, },
"types": "./src/index.d.ts", "types": "./src/index.d.ts",
"gitHead": "817089ab1f206f5e195756a4051afb812ec26901" "gitHead": "aebbd10b67952c3aa0cbf7e82944cd91fcd6f48c"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-analyzer", "name": "@remix-project/remix-analyzer",
"version": "0.5.51", "version": "0.5.54",
"description": "Tool to perform static analysis on Solidity smart contracts", "description": "Tool to perform static analysis on Solidity smart contracts",
"scripts": { "scripts": {
"test": "./../../node_modules/.bin/ts-node --project ../../tsconfig.base.json --require tsconfig-paths/register ./../../node_modules/.bin/tape ./test/tests.ts" "test": "./../../node_modules/.bin/ts-node --project ../../tsconfig.base.json --require tsconfig-paths/register ./../../node_modules/.bin/tape ./test/tests.ts"
@ -21,12 +21,12 @@
} }
], ],
"dependencies": { "dependencies": {
"@ethereumjs/block": "^4.2.0", "@ethereumjs/block": "5.2.0",
"@ethereumjs/tx": "^4.1.1", "@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "^8.0.5", "@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "^6.4.1", "@ethereumjs/vm": "8.0.0",
"@remix-project/remix-astwalker": "^0.0.72", "@remix-project/remix-astwalker": "^0.0.75",
"@remix-project/remix-lib": "^0.5.49", "@remix-project/remix-lib": "^0.5.52",
"async": "^2.6.2", "async": "^2.6.2",
"ethers": "^5.4.2", "ethers": "^5.4.2",
"ethjs-util": "^0.1.6", "ethjs-util": "^0.1.6",
@ -50,6 +50,6 @@
"typescript": "^3.7.5" "typescript": "^3.7.5"
}, },
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "817089ab1f206f5e195756a4051afb812ec26901", "gitHead": "aebbd10b67952c3aa0cbf7e82944cd91fcd6f48c",
"main": "./src/index.js" "main": "./src/index.js"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-astwalker", "name": "@remix-project/remix-astwalker",
"version": "0.0.72", "version": "0.0.75",
"description": "Tool to walk through Solidity AST", "description": "Tool to walk through Solidity AST",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {
@ -33,11 +33,11 @@
] ]
}, },
"dependencies": { "dependencies": {
"@ethereumjs/block": "^4.2.0", "@ethereumjs/block": "5.2.0",
"@ethereumjs/tx": "^4.1.1", "@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "^8.0.5", "@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "^6.4.1", "@ethereumjs/vm": "8.0.0",
"@remix-project/remix-lib": "^0.5.49", "@remix-project/remix-lib": "^0.5.52",
"@types/tape": "^4.2.33", "@types/tape": "^4.2.33",
"async": "^2.6.2", "async": "^2.6.2",
"ethers": "^5.4.2", "ethers": "^5.4.2",
@ -53,6 +53,6 @@
"tap-spec": "^5.0.0" "tap-spec": "^5.0.0"
}, },
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "817089ab1f206f5e195756a4051afb812ec26901", "gitHead": "aebbd10b67952c3aa0cbf7e82944cd91fcd6f48c",
"types": "./src/index.d.ts" "types": "./src/index.d.ts"
} }

@ -8,3 +8,4 @@ export * from './types/contract'
export { LinkLibraries, DeployLibraries } from './lib/link-libraries' export { LinkLibraries, DeployLibraries } from './lib/link-libraries'
export { OpenZeppelinProxy } from './lib/openzeppelin-proxy' export { OpenZeppelinProxy } from './lib/openzeppelin-proxy'
export { fetchContractFromEtherscan } from './lib/helpers/fetch-etherscan' export { fetchContractFromEtherscan } from './lib/helpers/fetch-etherscan'
export { fetchContractFromBlockscout } from './lib/helpers/fetch-blockscout'

@ -4,7 +4,7 @@ import { util } from '@remix-project/remix-lib'
import { toChecksumAddress } from '@ethereumjs/util' import { toChecksumAddress } from '@ethereumjs/util'
import { fetchContractFromEtherscan } from './helpers/fetch-etherscan' import { fetchContractFromEtherscan } from './helpers/fetch-etherscan'
import { fetchContractFromSourcify } from './helpers/fetch-sourcify' import { fetchContractFromSourcify } from './helpers/fetch-sourcify'
import { UUPSDeployedByteCode, UUPSCompilerVersion, UUPSOptimize, UUPSRuns, UUPSEvmVersion, UUPSLanguage, UUPSDeployedByteCodeV5, UUPSCompilerVersionV5 } from './constants/uups' import { UUPSDeployedByteCode, UUPSCompilerVersion, UUPSOptimize, UUPSRuns, UUPSEvmVersion, UUPSLanguage, UUPSDeployedByteCodeV5, UUPSCompilerVersionV5, UUPSEvmVersionv5, UUPSOptimizev5 } from './constants/uups'
const profile = { const profile = {
name: 'fetchAndCompile', name: 'fetchAndCompile',
@ -88,8 +88,8 @@ export class FetchAndCompile extends Plugin {
const settings = { const settings = {
version: UUPSCompilerVersionV5, version: UUPSCompilerVersionV5,
language: UUPSLanguage, language: UUPSLanguage,
evmVersion: UUPSEvmVersion, evmVersion: UUPSEvmVersionv5,
optimize: UUPSOptimize, optimize: UUPSOptimizev5,
runs: UUPSRuns runs: UUPSRuns
} }
const proxyUrl = 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.0/contracts/proxy/ERC1967/ERC1967Proxy.sol' const proxyUrl = 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.0/contracts/proxy/ERC1967/ERC1967Proxy.sol'

File diff suppressed because one or more lines are too long

@ -117,8 +117,11 @@ export class GistHandler extends Plugin {
const gistIdWorkspace = 'gist ' + gistId const gistIdWorkspace = 'gist ' + gistId
const workspaces = await this.call('filePanel', 'getWorkspaces') const workspaces = await this.call('filePanel', 'getWorkspaces')
const found = workspaces.find((workspace) => workspace.name === gistIdWorkspace) const found = workspaces.find((workspace) => workspace.name === gistIdWorkspace)
if (found) { if (found) {
await this.call('notification', 'alert', `workspace "${gistIdWorkspace}" already exist`) await this.call('notification', 'alert', {
id: 'gistAlert',
message: `workspace "${gistIdWorkspace}" already exists`,
})
return return
} }
await this.call('filePanel', 'createWorkspace', 'gist ' + gistId, '', true) await this.call('filePanel', 'createWorkspace', 'gist ' + gistId, '', true)

@ -0,0 +1,66 @@
export const fetchContractFromBlockscout = async (plugin, endpoint, contractAddress, targetPath, shouldSetFile = true) => {
let data
const compilationTargets = {}
try {
data = await fetch('https://' + endpoint + '/api?module=contract&action=getsourcecode&address=' + contractAddress)
data = await data.json()
// blockscout api doc https://blockscout.com/poa/core/api-docs
if (data.message === 'OK' && data.status === "1") {
if (data.result.length) {
if (!data.result[0].SourceCode || data.result[0].SourceCode === '') {
throw new Error(`contract not verified on Blockscout ${endpoint} network`)
}
}
} else throw new Error('unable to retrieve contract data ' + data.message)
} catch (e) {
throw new Error('unable to retrieve contract data: ' + e.message)
}
if (!data || !data.result) {
return null
}
if (data.result[0].FileName === '') {
const fileName = `${targetPath}/${data.result[0].ContractName}.sol`
if (shouldSetFile) await plugin.call('fileManager', 'setFile', fileName, data.result[0].SourceCode)
compilationTargets[fileName] = { content: data.result[0].SourceCode }
} else {
const sources = {}
sources[data.result[0].FileName] = data.result[0].SourceCode
if (data.result[0].AdditionalSources && Array.isArray(data.result[0].AdditionalSources)) {
for (const object of data.result[0].AdditionalSources) {
sources[object.Filename] = object.SourceCode
}
}
for (let [file, source] of Object.entries(sources)) { // eslint-disable-line
file = file.replace('browser/', '') // should be fixed in the remix IDE end.
file = file.replace(/^\//g, '') // remove first slash.
if (await plugin.call('contentImport', 'isExternalUrl', file)) {
// nothing to do, the compiler callback will handle those
} else {
const path = `${targetPath}/${file}`
const content = source
if (shouldSetFile) await plugin.call('fileManager', 'setFile', path, content)
compilationTargets[path] = { content }
}
}
}
let runs = 0
try {
runs = parseInt(data.result[0].OptimizationRuns)
} catch (e) { }
const settings = {
version: data.result[0].CompilerVersion.replace(/^v/, ''),
language: 'Solidity',
evmVersion: data.result[0].EVMVersion.toLowerCase(),
optimize: data.result[0].OptimizationUsed === 'true',
runs
}
return {
settings,
compilationTargets
}
}

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-debug", "name": "@remix-project/remix-debug",
"version": "0.5.42", "version": "0.5.45",
"description": "Tool to debug Ethereum transactions", "description": "Tool to debug Ethereum transactions",
"contributors": [ "contributors": [
{ {
@ -21,15 +21,15 @@
"test": "./../../node_modules/.bin/ts-node --project ../../tsconfig.base.json --require tsconfig-paths/register ./../../node_modules/.bin/tape ./test/tests.ts" "test": "./../../node_modules/.bin/ts-node --project ../../tsconfig.base.json --require tsconfig-paths/register ./../../node_modules/.bin/tape ./test/tests.ts"
}, },
"dependencies": { "dependencies": {
"@ethereumjs/block": "^4.2.0", "@ethereumjs/block": "5.2.0",
"@ethereumjs/common": "^3.1.1", "@ethereumjs/common": "4.3.0",
"@ethereumjs/tx": "^4.1.1", "@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "^8.0.5", "@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "^6.4.1", "@ethereumjs/vm": "8.0.0",
"@remix-project/remix-astwalker": "^0.0.72", "@remix-project/remix-astwalker": "^0.0.75",
"@remix-project/remix-lib": "^0.5.49", "@remix-project/remix-lib": "^0.5.52",
"@remix-project/remix-simulator": "^0.2.42", "@remix-project/remix-simulator": "^0.2.45",
"@remix-project/remix-solidity": "^0.5.28", "@remix-project/remix-solidity": "^0.5.31",
"ansi-gray": "^0.1.1", "ansi-gray": "^0.1.1",
"async": "^2.6.2", "async": "^2.6.2",
"color-support": "^1.1.3", "color-support": "^1.1.3",
@ -69,6 +69,6 @@
}, },
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme", "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme",
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "817089ab1f206f5e195756a4051afb812ec26901", "gitHead": "aebbd10b67952c3aa0cbf7e82944cd91fcd6f48c",
"types": "./src/index.d.ts" "types": "./src/index.d.ts"
} }

@ -1,6 +1,8 @@
'use strict' 'use strict'
import { bytesToHex } from '@ethereumjs/util'
import { Common } from '@ethereumjs/common' import { Common } from '@ethereumjs/common'
import { getOpcodesForHF, OpcodeList } from '@ethereumjs/evm/dist/opcodes/codes' // TODO fix the import when getOpcodesForHF is exported
import { getOpcodesForHF } from '@ethereumjs/evm'
import getOpcodes from './opcodes' import getOpcodes from './opcodes'
export function nameOpCodes (raw, hardfork) { export function nameOpCodes (raw, hardfork) {
@ -27,7 +29,8 @@ export function nameOpCodes (raw, hardfork) {
i += jumpNum i += jumpNum
} }
const data = (pushData as any).toString('hex') !== '' ? ' ' + (pushData as any).toString('hex') : '' const hexCode = bytesToHex((pushData as any))
const data = hexCode !== '' ? ' ' + hexCode : ''
code.push(pad(pc, roundLog(raw.length, 10)) + ' ' + curOpCode + data) code.push(pad(pc, roundLog(raw.length, 10)) + ' ' + curOpCode + data)
pushData = '' pushData = ''
@ -46,7 +49,7 @@ type Opcode = {
* information about the opcode. * information about the opcode.
*/ */
export function parseCode (raw) { export function parseCode (raw) {
const common = new Common({ chain: 'mainnet', hardfork: 'merge' }) const common = new Common({ chain: 'mainnet', hardfork: 'cancun' })
const opcodes = getOpcodesForHF(common).opcodes const opcodes = getOpcodesForHF(common).opcodes
const code = [] const code = []

@ -2,7 +2,7 @@
import { parseCode } from './codeUtils' import { parseCode } from './codeUtils'
import { util } from '@remix-project/remix-lib' import { util } from '@remix-project/remix-lib'
import { bufferToHex } from '@ethereumjs/util' import { bytesToHex } from '@ethereumjs/util'
function createExpressions (instructions) { function createExpressions (instructions) {
const expressions = [] const expressions = []
@ -37,7 +37,7 @@ function createExpressions (instructions) {
function toString (expr) { function toString (expr) {
if (expr.name.slice(0, 4) === 'PUSH') { if (expr.name.slice(0, 4) === 'PUSH') {
return bufferToHex(expr.pushData) return bytesToHex(expr.pushData)
} else if (expr.name === 'JUMPDEST') { } else if (expr.name === 'JUMPDEST') {
return expr.label + ':' return expr.label + ':'
} else if (expr.args) { } else if (expr.args) {

@ -2,7 +2,7 @@
import { hash } from '@remix-project/remix-lib' import { hash } from '@remix-project/remix-lib'
import { RefType } from './RefType' import { RefType } from './RefType'
import { normalizeHex } from './util' import { normalizeHex } from './util'
import { toBuffer, setLengthLeft, bufferToHex, addHexPrefix } from '@ethereumjs/util' import { toBytes, setLengthLeft, bytesToHex, addHexPrefix } from '@ethereumjs/util'
import BN from 'bn.js' import BN from 'bn.js'
export class Mapping extends RefType { export class Mapping extends RefType {
@ -44,7 +44,7 @@ export class Mapping extends RefType {
} }
async decodeMappingsLocation (preimages, location, storageResolver) { async decodeMappingsLocation (preimages, location, storageResolver) {
const mapSlot = normalizeHex(bufferToHex(location.slot)) const mapSlot = normalizeHex('0x' + location.slot.toString(16))
if (!preimages[mapSlot]) { if (!preimages[mapSlot]) {
return {} return {}
} }
@ -66,11 +66,11 @@ function getMappingLocation (key, position) {
// > the value corresponding to a mapping key k is located at keccak256(k . p) where . is concatenation. // > the value corresponding to a mapping key k is located at keccak256(k . p) where . is concatenation.
// key should be a hex string, and position an int // key should be a hex string, and position an int
const mappingK = toBuffer(addHexPrefix(key)) const mappingK = toBytes(addHexPrefix(key))
let mappingP = toBuffer(addHexPrefix(position)) let mappingP = toBytes(addHexPrefix(position))
mappingP = setLengthLeft(mappingP, 32) mappingP = setLengthLeft(mappingP, 32)
const mappingKeyBuf = concatTypedArrays(mappingK, mappingP) const mappingKeyBuf = concatTypedArrays(mappingK, mappingP)
const mappingStorageLocation: Buffer = hash.keccak(mappingKeyBuf) const mappingStorageLocation: Uint8Array = hash.keccak(mappingKeyBuf)
const mappingStorageLocationinBn: BN = new BN(mappingStorageLocation, 16) const mappingStorageLocationinBn: BN = new BN(mappingStorageLocation, 16)
return mappingStorageLocationinBn return mappingStorageLocationinBn
} }

@ -1,5 +1,5 @@
'use strict' 'use strict'
import { bufferToHex, unpadHexString } from '@ethereumjs/util' import { unpadHex } from '@ethereumjs/util'
import BN from 'bn.js' import BN from 'bn.js'
export function decodeIntFromHex (value, byteLength, signed) { export function decodeIntFromHex (value, byteLength, signed) {
@ -11,7 +11,7 @@ export function decodeIntFromHex (value, byteLength, signed) {
} }
export function readFromStorage (slot, storageResolver): Promise<string> { export function readFromStorage (slot, storageResolver): Promise<string> {
const hexSlot = '0x' + normalizeHex(bufferToHex(slot)) const hexSlot = '0x' + normalizeHex(slot.toString(16))
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
storageResolver.storageSlot(hexSlot, (error, slot) => { storageResolver.storageSlot(hexSlot, (error, slot) => {
if (error) { if (error) {
@ -58,7 +58,7 @@ export function toBN (value) {
if (value instanceof BN) { if (value instanceof BN) {
return value return value
} else if (value.match && value.match(/^(0x)?([a-f0-9]*)$/)) { } else if (value.match && value.match(/^(0x)?([a-f0-9]*)$/)) {
value = unpadHexString(value) value = unpadHex(value)
value = value.replace('0x', '') value = value.replace('0x', '')
value = new BN(value === '' ? '0' : value, 16) value = new BN(value === '' ? '0' : value, 16)
} else if (!isNaN(value)) { } else if (!isNaN(value)) {

@ -44,7 +44,7 @@ export function isSSTOREInstruction (step) {
} }
export function isSHA3Instruction (step) { export function isSHA3Instruction (step) {
return step.op === 'SHA3' return step.op === 'SHA3' || step.op === 'KECCAK256'
} }
export function newContextStorage (step) { export function newContextStorage (step) {

@ -40,7 +40,7 @@ export class TraceManager {
const networkId = await this.web3.eth.net.getId() const networkId = await this.web3.eth.net.getId()
this.fork = execution.forkAt(networkId, tx.blockNumber) this.fork = execution.forkAt(networkId, tx.blockNumber)
} catch (e) { } catch (e) {
this.fork = 'merge' this.fork = 'cancun'
console.log(`unable to detect fork, defaulting to ${this.fork}..`) console.log(`unable to detect fork, defaulting to ${this.fork}..`)
console.error(e) console.error(e)
} }

@ -10,7 +10,7 @@ import { InternalCallTree } from '../../../src/solidity-decoder/internalCallTree
import * as vmCall from '../../vmCall' import * as vmCall from '../../vmCall'
import { StorageResolver } from '../../../src/storage/storageResolver' import { StorageResolver } from '../../../src/storage/storageResolver'
import { StorageViewer } from '../../../src/storage/storageViewer' import { StorageViewer } from '../../../src/storage/storageViewer'
import { Address, bufferToHex } from '@ethereumjs/util' import { Address, bytesToHex } from '@ethereumjs/util'
module.exports = async function testMappingStorage (st, cb) { module.exports = async function testMappingStorage (st, cb) {
const mappingStorage = require('../contracts/mappingStorage') const mappingStorage = require('../contracts/mappingStorage')

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-lib", "name": "@remix-project/remix-lib",
"version": "0.5.49", "version": "0.5.52",
"description": "Library to various Remix tools", "description": "Library to various Remix tools",
"contributors": [ "contributors": [
{ {
@ -17,7 +17,7 @@
"test": "./../../node_modules/.bin/ts-node --require tsconfig-paths/register ./../../node_modules/.bin/tape ./test/tests.ts" "test": "./../../node_modules/.bin/ts-node --require tsconfig-paths/register ./../../node_modules/.bin/tape ./test/tests.ts"
}, },
"dependencies": { "dependencies": {
"@ethereumjs/util": "^8.0.5", "@ethereumjs/util": "9.0.3",
"async": "^2.1.2", "async": "^2.1.2",
"create-hash": "^1.2.0", "create-hash": "^1.2.0",
"ethers": "^5.7.2", "ethers": "^5.7.2",
@ -55,6 +55,6 @@
}, },
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme", "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme",
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "817089ab1f206f5e195756a4051afb812ec26901", "gitHead": "aebbd10b67952c3aa0cbf7e82944cd91fcd6f48c",
"types": "./src/index.d.ts" "types": "./src/index.d.ts"
} }

@ -61,7 +61,15 @@ const forks = {
}, },
{ {
number: 15537394, number: 15537394,
name: 'merge' name: 'paris'
},
{
number: 17034870,
name: 'shanghai'
},
{
number: 19426587,
name: 'cancun'
} }
], ],
3: [ 3: [

@ -1,6 +1,6 @@
import { eachOf } from 'async' import { eachOf } from 'async'
import { randomBytes } from 'crypto' import { randomBytes } from 'crypto'
import { toChecksumAddress } from '@ethereumjs/util' import { toChecksumAddress, bytesToHex } from '@ethereumjs/util'
export class LogsManager { export class LogsManager {
notificationCallbacks notificationCallbacks
@ -19,8 +19,9 @@ export class LogsManager {
checkBlock (blockNumber, block, web3) { checkBlock (blockNumber, block, web3) {
eachOf(block.transactions, (tx: any, i, next) => { eachOf(block.transactions, (tx: any, i, next) => {
const txHash = '0x' + tx.hash().toString('hex') const txHash = bytesToHex(tx.hash())
web3.eth.getTransactionReceipt(txHash, (_error, receipt) => { web3.eth.getTransactionReceipt(txHash, (_error, receipt) => {
if (!receipt) return next()
for (const log of receipt.logs) { for (const log of receipt.logs) {
this.oldLogs.push({ type: 'block', blockNumber, block, tx, log, txNumber: i, receipt }) this.oldLogs.push({ type: 'block', blockNumber, block, tx, log, txNumber: i, receipt })
const subscriptions = this.getSubscriptionsFor({ type: 'block', blockNumber, block, tx, log, receipt}) const subscriptions = this.getSubscriptionsFor({ type: 'block', blockNumber, block, tx, log, receipt})
@ -28,8 +29,8 @@ export class LogsManager {
const result = { const result = {
logIndex: '0x1', // 1 logIndex: '0x1', // 1
blockNumber: blockNumber, blockNumber: blockNumber,
blockHash: ('0x' + block.hash().toString('hex')), blockHash: bytesToHex(block.hash()),
transactionHash: ('0x' + tx.hash().toString('hex')), transactionHash: bytesToHex(tx.hash()),
transactionIndex: '0x' + i.toString(16), transactionIndex: '0x' + i.toString(16),
// TODO: if it's a contract deploy, it should be that address instead // TODO: if it's a contract deploy, it should be that address instead
address: log.address, address: log.address,
@ -139,7 +140,7 @@ export class LogsManager {
if (filterType === 'block') { if (filterType === 'block') {
const blocks = this.oldLogs.filter(x => x.type === 'block').filter(x => tracking.block === undefined || x.blockNumber >= tracking.block) const blocks = this.oldLogs.filter(x => x.type === 'block').filter(x => tracking.block === undefined || x.blockNumber >= tracking.block)
tracking.block = blocks[blocks.length - 1] tracking.block = blocks[blocks.length - 1]
return blocks.map(block => ('0x' + block.hash().toString('hex'))) return blocks.map(block => bytesToHex(block.hash()))
} }
if (filterType === 'pendingTransactions') { if (filterType === 'pendingTransactions') {
return [] return []
@ -147,13 +148,13 @@ export class LogsManager {
} }
getLogsByTxHash (hash) { getLogsByTxHash (hash) {
return this.oldLogs.filter((log) => '0x' + log.tx.hash().toString('hex') === hash) return this.oldLogs.filter((log) => bytesToHex(log.tx.hash()) === hash)
.map((log) => { .map((log) => {
return { return {
logIndex: '0x1', // 1 logIndex: '0x1', // 1
blockNumber: log.blockNumber, blockNumber: log.blockNumber,
blockHash: ('0x' + log.block.hash().toString('hex')), blockHash: bytesToHex(log.block.hash()),
transactionHash: ('0x' + log.tx.hash().toString('hex')), transactionHash: bytesToHex(log.tx.hash()),
transactionIndex: '0x' + log.txNumber.toString(16), transactionIndex: '0x' + log.txNumber.toString(16),
// TODO: if it's a contract deploy, it should be that address instead // TODO: if it's a contract deploy, it should be that address instead
address: log.log.address, address: log.log.address,
@ -170,8 +171,8 @@ export class LogsManager {
results.push({ results.push({
logIndex: '0x1', // 1 logIndex: '0x1', // 1
blockNumber: log.blockNumber, blockNumber: log.blockNumber,
blockHash: ('0x' + log.block.hash().toString('hex')), blockHash: bytesToHex(log.block.hash()),
transactionHash: ('0x' + log.tx.hash().toString('hex')), transactionHash: bytesToHex(log.tx.hash()),
transactionIndex: '0x' + log.txNumber.toString(16), transactionIndex: '0x' + log.txNumber.toString(16),
// TODO: if it's a contract deploy, it should be that address instead // TODO: if it's a contract deploy, it should be that address instead
address: log.log.address, address: log.log.address,

@ -409,7 +409,7 @@ export function decodeResponse (response, fnabi) {
const name = fnabi.outputs[i].name const name = fnabi.outputs[i].name
json[i] = outputTypes[i] + ': ' + (name ? name + ' ' + decodedObj[i] : decodedObj[i]) json[i] = outputTypes[i] + ': ' + (name ? name + ' ' + decodedObj[i] : decodedObj[i])
} }
return json return json
} catch (e) { } catch (e) {
return { error: 'Failed to decode output: ' + e } return { error: 'Failed to decode output: ' + e }

@ -1,6 +1,6 @@
'use strict' 'use strict'
import { ethers } from 'ethers' import { ethers } from 'ethers'
import { toBuffer, addHexPrefix } from '@ethereumjs/util' import { toBytes, addHexPrefix } from '@ethereumjs/util'
import { EventManager } from '../eventManager' import { EventManager } from '../eventManager'
import { compareByteCode, getinputParameters } from '../util' import { compareByteCode, getinputParameters } from '../util'
import { decodeResponse } from './txFormat' import { decodeResponse } from './txFormat'
@ -64,9 +64,9 @@ export class TxListener {
let execResult let execResult
if (this.executionContext.isVM()) { if (this.executionContext.isVM()) {
execResult = await this.executionContext.web3().remix.getExecutionResultFromSimulator(txResult.transactionHash) execResult = await this.executionContext.web3().remix.getExecutionResultFromSimulator(txResult.transactionHash)
returnValue = toBuffer(execResult.returnValue) returnValue = toBytes(execResult.returnValue)
} else { } else {
returnValue = toBuffer(addHexPrefix(txResult.result)) returnValue = toBytes(addHexPrefix(txResult.result))
} }
const call = { const call = {
from: from, from: from,
@ -374,7 +374,7 @@ export class TxListener {
} }
_decodeInputParams (data, abi) { _decodeInputParams (data, abi) {
data = toBuffer(addHexPrefix(data)) data = toBytes(addHexPrefix(data))
if (!data.length) data = new Uint8Array(32 * abi.inputs.length) // ensuring the data is at least filled by 0 cause `AbiCoder` throws if there's not enough data if (!data.length) data = new Uint8Array(32 * abi.inputs.length) // ensuring the data is at least filled by 0 cause `AbiCoder` throws if there's not enough data
const inputTypes = [] const inputTypes = []

@ -1,9 +1,10 @@
'use strict' 'use strict'
import { RunBlockResult, RunTxResult } from '@ethereumjs/vm' import { RunBlockResult, RunTxResult } from '@ethereumjs/vm'
import { ConsensusType } from '@ethereumjs/common' import { ConsensusType } from '@ethereumjs/common'
import { Transaction, FeeMarketEIP1559Transaction } from '@ethereumjs/tx' import { LegacyTransaction, FeeMarketEIP1559Transaction } from '@ethereumjs/tx'
import { Block } from '@ethereumjs/block' import { Block } from '@ethereumjs/block'
import { bufferToHex, Address } from '@ethereumjs/util' import { bytesToHex, Address, hexToBytes } from '@ethereumjs/util'
import { EVM } from '@ethereumjs/evm'
import type { Account } from '@ethereumjs/util' import type { Account } from '@ethereumjs/util'
import { EventManager } from '../eventManager' import { EventManager } from '../eventManager'
import { LogsManager } from './logsManager' import { LogsManager } from './logsManager'
@ -13,7 +14,7 @@ export type VMexecutionResult = {
result: RunTxResult, result: RunTxResult,
transactionHash: string transactionHash: string
block: Block, block: Block,
tx: Transaction tx: LegacyTransaction
} }
export type VMExecutionCallBack = (error: string | Error, result?: VMexecutionResult) => void export type VMExecutionCallBack = (error: string | Error, result?: VMexecutionResult) => void
@ -24,24 +25,23 @@ export class TxRunnerVM {
pendingTxs pendingTxs
vmaccounts vmaccounts
queusTxs queusTxs
blocks blocks: Uint8Array[]
logsManager logsManager
commonContext commonContext
blockParentHash blockParentHash
nextNonceForCall: number nextNonceForCall: number
standaloneTx: boolean
getVMObject: () => any getVMObject: () => any
constructor (vmaccounts, api, getVMObject, blockNumber) { constructor (vmaccounts, api, getVMObject, blocks: Uint8Array[] = []) {
this.event = new EventManager() this.event = new EventManager()
this.logsManager = new LogsManager() this.logsManager = new LogsManager()
// has a default for now for backwards compatibility // has a default for now for backwards compatibility
this.getVMObject = getVMObject this.getVMObject = getVMObject
this.commonContext = this.getVMObject().common this.commonContext = this.getVMObject().common
this.blockNumber = blockNumber || 0
this.pendingTxs = {} this.pendingTxs = {}
this.vmaccounts = vmaccounts this.vmaccounts = vmaccounts
this.queusTxs = [] this.queusTxs = []
this.blocks = []
/* /*
txHash is generated using the nonce, txHash is generated using the nonce,
in order to have unique transaction hash, we need to keep using different nonce (in case of a call) in order to have unique transaction hash, we need to keep using different nonce (in case of a call)
@ -51,7 +51,15 @@ export class TxRunnerVM {
this.nextNonceForCall = 0 this.nextNonceForCall = 0
const vm = this.getVMObject().vm const vm = this.getVMObject().vm
this.blockParentHash = vm.blockchain.genesisBlock.hash() if (Array.isArray(blocks) && (blocks || []).length > 0) {
const lastBlock = Block.fromRLPSerializedBlock(blocks[blocks.length - 1], { common: this.commonContext })
this.blockParentHash = lastBlock.hash()
this.blocks = blocks
} else {
this.blockParentHash = vm.blockchain.genesisBlock.hash()
this.blocks = [vm.blockchain.genesisBlock.serialize()]
}
} }
execute (args: InternalTransaction, confirmationCb, gasEstimationForceSend, promptCb, callback: VMExecutionCallBack) { execute (args: InternalTransaction, confirmationCb, gasEstimationForceSend, promptCb, callback: VMExecutionCallBack) {
@ -67,7 +75,7 @@ export class TxRunnerVM {
} }
} }
runInVm (from: string, to: string, data: string, value: string, gasLimit: number, useCall: boolean, callback: VMExecutionCallBack) { async runInVm (from: string, to: string, data: string, value: string, gasLimit: number, useCall: boolean, callback: VMExecutionCallBack) {
let account let account
if (!from && useCall && Object.keys(this.vmaccounts).length) { if (!from && useCall && Object.keys(this.vmaccounts).length) {
from = Object.keys(this.vmaccounts)[0] from = Object.keys(this.vmaccounts)[0]
@ -78,76 +86,90 @@ export class TxRunnerVM {
return callback('Invalid account selected') return callback('Invalid account selected')
} }
this.getVMObject().stateManager.getAccount(Address.fromString(from)).then((res: Account) => { try {
const res = await this.getVMObject().stateManager.getAccount(Address.fromString(from))
const EIP1559 = this.commonContext.hardfork() !== 'berlin' // berlin is the only pre eip1559 fork that we handle. const EIP1559 = this.commonContext.hardfork() !== 'berlin' // berlin is the only pre eip1559 fork that we handle.
let tx let tx
if (!EIP1559) { if (!EIP1559) {
tx = Transaction.fromTxData({ tx = LegacyTransaction.fromTxData({
nonce: useCall ? this.nextNonceForCall : res.nonce, nonce: useCall ? this.nextNonceForCall : res.nonce,
gasPrice: '0x1', gasPrice: '0x1',
gasLimit: gasLimit, gasLimit: gasLimit,
to: to, to: to,
value: value, value: value,
data: Buffer.from(data.slice(2), 'hex') data: hexToBytes(data)
}, { common: this.commonContext }).sign(account.privateKey) }, { common: this.commonContext }).sign(account.privateKey)
} else { } else {
tx = FeeMarketEIP1559Transaction.fromTxData({ tx = FeeMarketEIP1559Transaction.fromTxData({
nonce: useCall ? this.nextNonceForCall : res.nonce, nonce: useCall ? this.nextNonceForCall : res.nonce,
maxPriorityFeePerGas: '0x01', maxPriorityFeePerGas: '0x01',
maxFeePerGas: '0x1', maxFeePerGas: '0x7',
gasLimit: gasLimit, gasLimit: gasLimit,
to: to, to: to,
value: value, value: value,
data: Buffer.from(data.slice(2), 'hex') data: hexToBytes(data)
}).sign(account.privateKey) }).sign(account.privateKey)
} }
if (useCall) this.nextNonceForCall++ if (useCall) this.nextNonceForCall++
const coinbases = ['0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a', '0x8945a1288dc78a6d8952a92c77aee6730b414778', '0x94d76e24f818426ae84aa404140e8d5f60e10e7e'] const coinbases = ['0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a', '0x8945a1288dc78a6d8952a92c77aee6730b414778', '0x94d76e24f818426ae84aa404140e8d5f60e10e7e']
const difficulties = [69762765929000, 70762765929000, 71762765929000] const difficulties = [69762765929000, 70762765929000, 71762765929000]
const difficulty = this.commonContext.consensusType() === ConsensusType.ProofOfStake ? 0 : difficulties[this.blockNumber % difficulties.length] const difficulty = this.commonContext.consensusType() === ConsensusType.ProofOfStake ? 0 : difficulties[this.blocks.length % difficulties.length]
const blocknumber = this.blockNumber + 1
const block = Block.fromBlockData({ const block = Block.fromBlockData({
header: { header: {
timestamp: new Date().getTime() / 1000 | 0, timestamp: new Date().getTime() / 1000 | 0,
number: blocknumber, number: this.blocks.length,
coinbase: coinbases[blocknumber % coinbases.length], coinbase: coinbases[this.blocks.length % coinbases.length],
difficulty, difficulty,
gasLimit, gasLimit,
baseFeePerGas: EIP1559 ? '0x1' : undefined, baseFeePerGas: EIP1559 ? '0x1' : undefined,
parentHash: this.blockParentHash parentHash: this.blockParentHash
}, },
transactions: [tx] transactions: [tx]
}, { common: this.commonContext, hardforkByBlockNumber: false, hardforkByTTD: undefined }) }, { common: this.commonContext })
if (!useCall) { if (!this.standaloneTx) {
this.blockNumber = this.blockNumber + 1
this.blockParentHash = block.hash() this.blockParentHash = block.hash()
this.runBlockInVm(tx, block, (err, result) => { this.runBlockInVm(tx, block, async (err, result) => {
if (!err) this.getVMObject().vm.blockchain.putBlock(block) if (!err) {
if (!useCall) {
this.getVMObject().vm.blockchain.putBlock(block)
this.blocks.push(block.serialize())
}
}
callback(err, result) callback(err, result)
}) })
} else { } else {
this.getVMObject().stateManager.checkpoint().then(() => { await this.getVMObject().vm.evm.journal.checkpoint()
this.runBlockInVm(tx, block, (err, result) => { this.runTxInVm(tx, block, async (err, result) => {
this.getVMObject().stateManager.revert().then(() => { await this.getVMObject().vm.evm.journal.revert()
callback(err, result) callback(err, result)
})
})
}) })
} }
}).catch((e) => { } catch (e) {
callback(e) callback(e)
}
}
runTxInVm (tx, block, callback) {
this.getVMObject().vm.runTx({ tx, skipNonce: true, skipBlockValidation: true, skipBalance: false }).then((result: RunTxResult) => {
callback(null, {
result,
transactionHash: bytesToHex(Buffer.from(tx.hash())),
block,
tx
})
}).catch(function (err) {
callback(err)
}) })
} }
runBlockInVm (tx, block, callback) { runBlockInVm (tx, block, callback) {
this.getVMObject().vm.runBlock({ block: block, generate: true, skipBlockValidation: true, skipBalance: false, skipNonce: true }).then((results: RunBlockResult) => { this.getVMObject().vm.runBlock({ block: block, generate: true, skipNonce: true, skipBlockValidation: true, skipBalance: false }).then((results: RunBlockResult) => {
const result: RunTxResult = results.results[0] const result: RunTxResult = results.results[0]
callback(null, { callback(null, {
result, result,
transactionHash: bufferToHex(Buffer.from(tx.hash())), transactionHash: bytesToHex(Buffer.from(tx.hash())),
block, block,
tx tx
}) })

@ -1,6 +1,6 @@
'use strict' 'use strict'
import { BN } from 'bn.js' import { BN } from 'bn.js'
import { bufferToHex } from '@ethereumjs/util' import { bytesToHex } from '@ethereumjs/util'
import { isBigInt } from 'web3-validator' import { isBigInt } from 'web3-validator'
export function toInt (h) { export function toInt (h) {
@ -27,7 +27,7 @@ function convertToString (v) {
} else if (v._isBigNumber) { } else if (v._isBigNumber) {
return toInt(v._hex) return toInt(v._hex)
} else if (v._isBuffer) { } else if (v._isBuffer) {
return bufferToHex(v) return bytesToHex(v)
} else if (typeof v === 'object') { } else if (typeof v === 'object') {
const retObject = {} const retObject = {}
for (const i in v) { for (const i in v) {

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

Loading…
Cancel
Save