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:
schedule:
- cron: "0 8-17/8 * * 1-5"
- cron: "0 8 * * 1-5"
workflow_dispatch:
jobs:
@ -14,4 +14,4 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
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") {
await plugin.compile(appState.filePath, { version: appState.version, prime: appState.primeValue })
} else {
console.log('Exisiting circuit compilation in progress')
console.log('Existing circuit compilation in progress')
}
} catch (e) {
plugin.internalEvents.emit('circuit_compiling_errored', e)
@ -19,7 +19,7 @@ export const generateR1cs = async (plugin: CircomPluginClient, appState: AppStat
if (appState.status !== "generating") {
await plugin.generateR1cs(appState.filePath, { version: appState.version, prime: appState.primeValue })
} else {
console.log('Exisiting r1cs generation in progress')
console.log('Existing r1cs generation in progress')
}
} catch (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)
} else {
console.log('Exisiting witness computation in progress')
console.log('Existing witness computation in progress')
}
} catch (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) => {
let value = e.target.value
try {
value = remixLib.execution.txFormat.parseFunctionParams(value)
} catch (e) {
if (value.startsWith('[') && value.endsWith(']')) {
try {
value = remixLib.execution.txFormat.parseFunctionParams(value)
} catch (e) {
// do nothing
}
} else if (value.startsWith('[') && !value.endsWith(']')) {
// do nothing
} else {
try {
value = remixLib.execution.txFormat.parseFunctionParams(value)
} catch (e) {
// do nothing
}
}
setWitnessValues({
...witnessValues,

@ -92,7 +92,7 @@ addRepository(repoName, branch)
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_
@ -117,7 +117,7 @@ tags:
```
(function () {
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', 'startTutorial', "ethereum/remix-workshops", "master", "basics")
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()}`
console.log('loading ', url)
const {data} = yield axios.get(url)
console.log(data)
const repoId = `${payload.name}-${payload.branch}`
for (let i = 0; i < data.ids.length; i++) {

@ -6,8 +6,8 @@
"npm": "^6.14.15"
},
"dependencies": {
"@openzeppelin/contracts": "^5.0.0",
"@openzeppelin/contracts-upgradeable": "^5.0.0",
"@openzeppelin/contracts": "^5.0.2",
"@openzeppelin/contracts-upgradeable": "^5.0.2",
"@openzeppelin/upgrades-core": "^1.30.0",
"@openzeppelin/wizard": "^0.4.0",
"@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
browser.element('css selector', '[data-id="verticalIconsKindfilePanel"] img[data-id="selected"]', (result) => {
if (result.status === 0) {
done()
done()
} else browser.clickLaunchIcon('filePanel').perform(() => {
done()
})

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

@ -95,7 +95,7 @@ module.exports = {
.waitForElementVisible('#stepdetail')
.waitForElementVisible({
locateStrategy: 'xpath',
selector: '//*[@data-id="treeViewLivm trace step" and contains(.,"531")]',
selector: '//*[@data-id="treeViewLivm trace step" and contains(.,"475")]',
})
.getEditorValue((content) => {
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
'Should call the debugger api: getTrace #group4': function (browser: NightwatchBrowser) {
let txhash
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()')
.pause(3000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '{"gas":"0x5752","return":"0x0000000000000000000000000000000000000000000000000000000000000000","structLogs":', 60000)
},
// depends on Should debug using generated sources
'Should call the debugger api: debug #group4': function (browser: NightwatchBrowser) {
let txhash
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()')
.pause(3000)
.clickLaunchIcon('debugger')
@ -495,7 +519,7 @@ const localVariable_step717_ABIEncoder = { // eslint-disable-line
const jsGetTrace = `(async () => {
try {
const result = await remix.call('debugger', 'getTrace', '0x00a9f5b1ac2c9cb93e5890ea86c81efbd36b619ef2378136ef74d8c6171ddda6')
const result = await remix.call('debugger', 'getTrace', '<txhash>')
console.log('result ', result)
} catch (e) {
console.log(e.message)
@ -504,7 +528,7 @@ const jsGetTrace = `(async () => {
const jsDebug = `(async () => {
try {
const result = await remix.call('debugger', 'debug', '0x00a9f5b1ac2c9cb93e5890ea86c81efbd36b619ef2378136ef74d8c6171ddda6')
const result = await remix.call('debugger', 'debug', '<txhash>')
console.log('result ', result)
} catch (e) {
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(() => {
(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')
.clickLaunchIcon('solidity') // compile
.testContracts('Owner_1.sol', { content: verifiedContract }, ['Owner'])
@ -42,7 +42,7 @@ module.exports = {
.frame(0)
.click('[data-id="home"]')
.setValue('select[name="contractName"]', 'Owner')
.setValue('*[name="contractAddress"]', ['0x9981c9d00103da481c3c65b22a79582a3e3ff50b', browser.Keys.TAB])
.setValue('*[name="contractAddress"]', ['0xfF6A41815582cFD18855c5B90efD1d45784fd4f5', browser.Keys.TAB])
.click('[data-id="verify-contract"]')
.waitForElementVisible('[data-id="verify-result"]')
.waitForElementContainsText('[data-id="verify-result"]', 'Contract source code already verified', 15000)

@ -152,7 +152,7 @@ module.exports = {
.scrollAndClick('*[data-id="settingsTabLocaleLabelen"]')
.pause(2000)
.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="settingsAutoCompleteLabel"]', 'Enable code completion in editor')
.assert.containsText('*[data-id="settingsShowGasLabel"]', 'Display gas estimates in editor')

@ -38,7 +38,7 @@ module.exports = {
.executeScriptInTerminal(`remix.loadgist('${gistid}')`)
// .perform((done) => { if (runtimeBrowser === 'chrome') { browser.openFile('gists') } done() })
.waitForElementVisible(`[data-id="treeViewLitreeViewItemREADME.txt"]`)
.openFile(`README.txt`)
// Remix publish to gist
/* .click('*[data-id="fileExplorerNewFilepublishToGist"]')
@ -111,7 +111,7 @@ module.exports = {
.click('[data-id="settingsTabRemoveGistToken"]')
.clickLaunchIcon('filePanel')
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacepublishToGist"]')
.click('*[data-id="workspacepublishToGist"]')
.waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
.execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
.pause(10000)
@ -145,24 +145,24 @@ module.exports = {
.openFile(`README.txt`)
.waitForElementVisible(`div[data-path='gist ${testData.validGistId}/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) {
const gistId = '1b179bf1b92c8b0664b4cbe61774e15d'
browser
.url('http://127.0.0.1:8080/#gist=' + gistId) // loading the gist
.refreshPage()
.currentWorkspaceIs('gist ' + gistId)
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 15000)
.waitForElementVisible(`#fileExplorerView li[data-path='contracts']`, 30000)
.openFile(`contracts/2_Owner.sol`)
.getEditorValue((content) => {
browser.assert.ok(content.indexOf('contract Owner {') !== -1)
})
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacepublishToGist"]')
.modalFooterOKClick('fileSystem')
.waitForElementVisible('*[data-shared="tooltipPopup"]', 5000)
.assert.containsText('*[data-shared="tooltipPopup"]', 'Saving gist (' + gistId + ') ...')
}
'Load Gist from URL and verify truncated files are loaded #group3': function (browser: NightwatchBrowser) {
const gistId = '1b179bf1b92c8b0664b4cbe61774e15d'
browser
.url('http://127.0.0.1:8080/#gist=' + gistId) // loading the gist
.refreshPage()
.currentWorkspaceIs('gist ' + gistId)
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 15000)
.waitForElementVisible(`#fileExplorerView li[data-path='contracts']`, 30000)
.openFile(`contracts/2_Owner.sol`)
.getEditorValue((content) => {
browser.assert.ok(content.indexOf('contract Owner {') !== -1)
})
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacepublishToGist"]')
.modalFooterOKClick('fileSystem')
.waitForElementVisible('*[data-shared="tooltipPopup"]', 5000)
.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) {
browser.waitForElementVisible('*[data-id="settingsRemixRunSignMsg"]')
.switchEnvironment('vm-merge')
.switchEnvironment('vm-paris')
.pause(2000)
.click('*[data-id="settingsRemixRunSignMsg"]')
.pause(2000)
@ -82,21 +82,21 @@ module.exports = {
instanceAddress = address
console.log('instanceAddress', instanceAddress)
browser
.waitForElementVisible(`#instance${instanceAddress} [data-id="instanceContractBal"]`)
.waitForElementVisible(`#instance${instanceAddress} [data-id="instanceContractBal"]`)
//*[@id="instance0xbBF289D846208c16EDc8474705C748aff07732dB" and contains(.,"Balance") and contains(.,'0.000000000000000111')]
.waitForElementVisible({
locateStrategy: 'xpath',
selector: `//*[@id="instance${instanceAddress}" and contains(.,"Balance") and contains(.,'0.000000000000000111')]`,
timeout: 60000
})
.waitForElementVisible({
locateStrategy: 'xpath',
selector: `//*[@id="instance${instanceAddress}" and contains(.,"Balance") and contains(.,'0.000000000000000111')]`,
timeout: 60000
})
//.waitForElementContainsText(`#instance${instanceAddress} [data-id="instanceContractBal"]`, 'Balance: 0.000000000000000111 ETH', 60000)
.clickFunction('sendSomeEther - transact (not payable)', { types: 'uint256 num', values: '2' })
.pause(1000)
.waitForElementVisible({
locateStrategy: 'xpath',
selector: `//*[@id="instance${instanceAddress}" and contains(.,"Balance") and contains(.,'0.000000000000000109')]`,
timeout: 60000
})
.clickFunction('sendSomeEther - transact (not payable)', { types: 'uint256 num', values: '2' })
.pause(1000)
.waitForElementVisible({
locateStrategy: 'xpath',
selector: `//*[@id="instance${instanceAddress}" and contains(.,"Balance") and contains(.,'0.000000000000000109')]`,
timeout: 60000
})
})
},
@ -238,6 +238,95 @@ module.exports = {
.executeScriptInTerminal('web3.eth.getAccounts()')
.journalLastChildIncludes('[ "0x76a3ABb5a12dcd603B52Ed22195dED17ee82708f" ]')
.end()
},
'Should ensure that save environment state is checked by default #group4 #group5': function (browser: NightwatchBrowser) {
browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]')
.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) {
browser
.clickLaunchIcon('udapp')
.switchEnvironment('vm-cancun')
.clickLaunchIcon('solidity')
.setSolidityCompilerVersion('builtin')
.click('.remixui_compilerConfigSection')
.setValue('#evmVersionSelector', 'cancun') // Temporary fix
.clickLaunchIcon('filePanel')
.click('*[data-id="treeViewLitreeViewItemcontracts"]')
.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
browser.perform((done) => {
browser.getAddressAtPosition(0, (address) => {

@ -319,7 +319,7 @@ module.exports = {
.execute(() => {
(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)
.modalFooterOKClick('vm-custom-fork')
.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) {
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')

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

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

@ -1,34 +1,45 @@
#!/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
# check if curl is installed
if ! command -v curl &> /dev/null
then
# Check if curl and jq are installed
if ! command -v curl &> /dev/null; then
echo "curl could not be found"
exit
exit 1
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
# get the latest version without jq
latest=$(grep 'latestRelease' list.json | cut -d '"' -f 4)
echo "latest version: $latest"
# get url
url=$(grep "\"$latest\":" list.json | cut -d '"' -f 4)
echo "url: $url"
path="https://binaries.soliditylang.org/bin/$url"
echo "path: $path"
# download the file to ./apps/remix-ide/src/assets/js/soljson.js
curl -s $path > ./apps/remix-ide/src/assets/js/soljson.js
# if directory ./apps/remix-ide/src/assets/js/soljson does not exist, create it
# Use jq to extract the path for the specified version from the builds array
check=$(grep "\"$defaultVersion\"" list.json)
if [ -z "$check" ]; then
echo "The specified version $defaultVersion could not be found in the list"
exit 1
fi
echo "Path for the specified version: $defaultVersion"
fullPath="https://binaries.soliditylang.org/bin/$defaultVersion"
echo "Download fullPath: $fullPath"
# Ensure the target directory exists
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
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
# remove list.json
# Clean up by removing the list.json
rm list.json

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

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

@ -24,7 +24,7 @@ const profile = {
methods: ['closeAllFiles', 'closeFile', 'file', 'exists', 'open', 'writeFile', 'writeMultipleFiles', 'writeFileNoRewrite',
'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', 'readdir', 'dirList', 'fileList', 'remove', 'getCurrentFile', 'getFile',
'getFolder', 'setFile', 'switchFile', 'refresh', 'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath',
'saveCurrentFile', 'setBatchFiles', 'isGitRepo', 'isFile', 'isDirectory', 'hasGitSubmodule'
'saveCurrentFile', 'setBatchFiles', 'isGitRepo', 'isFile', 'isDirectory', 'hasGitSubmodule', 'copyFolderToJson'
],
kind: 'file-system'
}
@ -1041,6 +1041,14 @@ class FileManager extends Plugin {
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

@ -224,9 +224,23 @@ export class TabProxy extends Plugin {
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 = '') {
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('/')
const tabPath = slash.reverse()
const tempTitle = []
@ -292,7 +306,7 @@ export class TabProxy extends Plugin {
if (!previous && tab.name === name) {
if(index - 1 >= 0 && this.loadedTabs[index - 1])
previous = this.loadedTabs[index - 1]
else if (index + 1 && this.loadedTabs[index + 1])
else if (index + 1 && this.loadedTabs[index + 1])
previous = this.loadedTabs[index + 1]
}
return tab.name !== name

@ -1,12 +1,12 @@
/* global Node, requestAnimationFrame */ // 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 * as packageJson from '../../../../../package.json'
import {Registry} from '@remix-project/remix-lib'
import { PluginViewWrapper } from '@remix-ui/helper'
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 { RemixUiXterminals } from '@remix-ui/xterm'
@ -26,6 +26,34 @@ const profile = {
}
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) {
super(profile)
this.fileImport = new CompilerImports()
@ -75,7 +103,7 @@ class Terminal extends Plugin {
this._INDEX.commandsMain = {}
if (opts.shell) this._shell = opts.shell // ???
register(this)
this.event.register('debuggingRequested', async (hash) => {
this.event.register('debuggingRequested', async (hash: any) => {
// TODO should probably be in the run module
if (!await this._opts.appManager.isActive('debugger')) await this._opts.appManager.activatePlugin('debugger')
this.call('menuicons', 'select', 'debugger')
@ -114,13 +142,12 @@ class Terminal extends Plugin {
}
updateComponent(state) {
return (Registry.getInstance().get('platform').api.isDesktop()) ? <RemixUiXterminals onReady={state.onReady} plugin={state.plugin}>
</RemixUiXterminals>
: <RemixUiTerminal
return(
<RemixUITerminalWrapper
plugin={state.plugin}
onReady={state.onReady}
visible={true}
/>
/>)
}
renderComponent() {

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

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

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

@ -46,17 +46,17 @@ export class MergeVMProvider extends BasicVMProvider {
constructor(blockchain) {
super(
{
name: 'vm-merge',
displayName: 'Remix VM (Merge)',
name: 'vm-paris',
displayName: 'Remix VM (Paris)',
kind: 'provider',
description: 'Remix VM (Merge)',
description: 'Remix VM (Paris)',
methods: ['sendAsync', 'init'],
version: packageJson.version
},
blockchain
)
this.blockchain = blockchain
this.fork = 'merge'
this.fork = 'paris'
}
}
@ -113,3 +113,21 @@ export class ShanghaiVMProvider extends BasicVMProvider {
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.workspace.addscriptetherscan": "Adds scripts which can be used to interact with the Etherscan API",
"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.addscriptdeployer": "Add contract deployer scripts",
"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.copyFolderFailedMsg": "Unexpected error while copying folder: {src}",
"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.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?",

@ -17,6 +17,9 @@
"settings.etherscanTokenTitle": "EtherScan Access Token",
"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.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.remove": "Remove",
"settings.themes": "Themes",
@ -40,5 +43,6 @@
"settings.copilot": "Solidity copilot - Alpha",
"settings.copilot.activate": "Load & Activate copilot",
"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.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.debug": "Debug",
"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._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.deployAndRunNoInstanceText": "Currently you have no contract instances to interact with.",
"udapp.tooltipText6": "Autogenerated generic user interfaces for interaction with deployed contracts",
"udapp.deployAndRunNoInstanceText": "Currently you have no unpinned contracts to interact with.",
"udapp.tooltipText6": "Autogenerated generic user interfaces for interaction with deployed/unpinned contracts",
"udapp.savedContracts": "Pinned Contracts",
"udapp.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.transactionsRecorded": "Transactions recorded",
@ -98,7 +106,8 @@
"udapp.tooltipText13": "Deployed {date}",
"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.tooltipText9": "The Calldata to send to fallback function of the contract.",
"udapp.tooltipText10": "Send data to contract.",

@ -86,7 +86,7 @@
"filePanel.copyFolderFailed": "Copia de Carpeta Fallida",
"filePanel.copyFolderFailedMsg": "Error inesperado al copiar la carpeta: {src}",
"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.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?",

@ -36,5 +36,6 @@
"settings.port": "PUERTO",
"settings.projectID": "ID DEL 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.tooltipText13": "Publicado en {date}",
"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.tooltipText9": "El datos de llamada a enviar a la función fallback del contrato.",
"udapp.tooltipText10": "Enviar datos al contrato.",

@ -86,7 +86,7 @@
"filePanel.copyFolderFailed": "Échec de la copie du dossier",
"filePanel.copyFolderFailedMsg": "Erreur inattendue lors de la copie du fichier : {src}",
"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.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?",

@ -36,5 +36,6 @@
"settings.port": "PORT",
"settings.projectID": "ID 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.tooltipText13": "Déployé {date}",
"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.tooltipText9": "Les Calldata à envoyer à la fonction fallback du contrat.",
"udapp.tooltipText10": "Envoyer des données au contrat.",

@ -86,7 +86,7 @@
"filePanel.copyFolderFailed": "Copia Cartella Non Riuscita",
"filePanel.copyFolderFailedMsg": "Errore inatteso durante la copia della cartella: {src}",
"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.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?",

@ -36,5 +36,6 @@
"settings.port": "PORTA",
"settings.projectID": "ID 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.tooltipText13": "Deploiato",
"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.tooltipText9": "Il Calldata per inviare alla funzione di fallback del contratto.",
"udapp.tooltipText10": "Invia dati al contratto.",

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

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

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

@ -1,6 +1,6 @@
var async = require('async')
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 { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../../.././../../package.json'
@ -43,7 +43,7 @@ class Recorder extends Plugin {
}
if (!to) {
var abi = payLoad.contractABI
var keccak = bufferToHex(hash.keccakFromString(JSON.stringify(abi)))
var keccak = bytesToHex(hash.keccakFromString(JSON.stringify(abi)))
record.abi = keccak
record.contractName = payLoad.contractName
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.
const data = await this.call('compilerArtefacts', 'getArtefactsByContractName', tx.record.contractName)
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
tx.record.abi = updatedABIKeccak
}

@ -58,11 +58,27 @@ export class Web3ProviderModule extends Plugin {
const contractAddressStr = addressToString(receipt.contractAddress)
const contractData = await this.call('compilerArtefacts', 'getContractDataFromAddress', contractAddressStr)
if (contractData) {
this.call('udapp', 'addInstance', contractAddressStr, contractData.contract.abi, contractData.name)
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)
}
}, 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)

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

@ -1091,9 +1091,22 @@
"bzzr://c604bdd6384bf73594cd0e5cfbe979048191549ebc88e70996346f3b744c0680",
"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": {
"0.8.25": "soljson-v0.8.25+commit.b61c2a91.js",
"0.8.24": "soljson-v0.8.24+commit.e11b9ed9.js",
"0.8.23": "soljson-v0.8.23+commit.f704f362.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.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 {fromWei, toBigInt, toWei} from 'web3-utils'
import {Plugin} from '@remixproject/engine'
import {toBuffer, addHexPrefix} from '@ethereumjs/util'
import {toBytes, addHexPrefix} from '@ethereumjs/util'
import {EventEmitter} from 'events'
import {format} from 'util'
import {ExecutionContext} from './execution-context'
@ -135,7 +135,8 @@ export class Blockchain extends Plugin {
setupEvents() {
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.detectNetwork((error, network) => {
this.networkStatus = {network, error}
@ -286,7 +287,7 @@ export class Blockchain extends Plugin {
await this.saveDeployedContractStorageLayout(implementationContractObject, address, networkInfo)
this.events.emit('newProxyDeployment', address, new Date().toISOString(), implementationContractObject.contractName)
_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)
@ -336,7 +337,7 @@ export class Blockchain extends Plugin {
}
await this.saveDeployedContractStorageLayout(newImplementationContractObject, proxyAddress, networkInfo)
_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)
}
@ -643,8 +644,23 @@ export class Blockchain extends Plugin {
})
}
async resetEnvironment() {
await this.getCurrentProvider().resetEnvironment()
async loadContext(context: string) {
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
const web3Runner = new TxRunnerWeb3(
{
@ -677,7 +693,7 @@ export class Blockchain extends Plugin {
view on etherscan
</a>
)
}
}
})
})
this.txRunner = new TxRunner(web3Runner, {})
@ -889,8 +905,16 @@ export class Blockchain extends Plugin {
let execResult
let returnValue = null
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) {
const finalLogs = (
<div>
@ -920,8 +944,8 @@ export class Blockchain extends Plugin {
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.
returnValue = execResult
? toBuffer(execResult.returnValue)
: toBuffer(addHexPrefix(txResult.result) || '0x0000000000000000000000000000000000000000000000000000000000000000')
? toBytes(execResult.returnValue)
: toBytes(addHexPrefix(txResult.result) || '0x0000000000000000000000000000000000000000000000000000000000000000')
const compiledContracts = await this.call('compilerArtefacts', 'getAllContractDatas')
const vmError = txExecution.checkError({ errorMessage: execResult.exceptionError ? execResult.exceptionError.error : '', errorData: execResult.returnValue }, compiledContracts)
if (vmError.error) {
@ -930,7 +954,7 @@ export class Blockchain extends Plugin {
}
}
if (!isVM && tx && tx.useCall) {
returnValue = toBuffer(addHexPrefix(txResult.result))
returnValue = toBytes(addHexPrefix(txResult.result))
}
let address = null

@ -3,6 +3,7 @@
import Web3 from 'web3'
import { execution } from '@remix-project/remix-lib'
import EventManager from '../lib/events'
import { bytesToHex } from '@ethereumjs/util'
const _paq = window._paq = window._paq || []
let web3
@ -22,11 +23,11 @@ web3.eth.setConfig(config)
export class ExecutionContext {
constructor () {
this.event = new EventManager()
this.executionContext = 'vm-shanghai'
this.executionContext = 'vm-cancun'
this.lastBlock = null
this.blockGasLimitDefault = 4300000
this.blockGasLimit = this.blockGasLimitDefault
this.currentFork = 'shanghai'
this.currentFork = 'cancun'
this.mainNetGenesisHash = '0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3'
this.customNetWorks = {}
this.blocks = {}
@ -36,7 +37,7 @@ export class ExecutionContext {
}
init (config) {
this.executionContext = 'vm-shanghai'
this.executionContext = 'vm-cancun'
this.event.trigger('contextChanged', [this.executionContext])
}
@ -71,40 +72,49 @@ export class ExecutionContext {
}
detectNetwork (callback) {
if (this.isVM()) {
callback(null, { id: '-', name: 'VM' })
} else {
if (!web3.currentProvider) {
return callback('No provider set')
}
const cb = (err, id) => {
let name = null
if (err) name = 'Unknown'
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
else if (id === 1) name = 'Main'
else if (id === 3) name = 'Ropsten'
else if (id === 4) name = 'Rinkeby'
else if (id === 5) name = 'Goerli'
else if (id === 42) name = 'Kovan'
else if (id === 11155111) name = 'Sepolia'
else name = 'Custom'
if (id === 1) {
web3.eth.getBlock(0).then((block) => {
if (block && block.hash !== this.mainNetGenesisHash) name = 'Custom'
callback(err, { id, name, lastBlock: this.lastBlock, currentFork: this.currentFork })
}).catch((error) => callback(error))
} else {
callback(err, { id, name, lastBlock: this.lastBlock, currentFork: this.currentFork })
return new Promise((resolve, reject) => {
if (this.isVM()) {
callback && callback(null, { id: '-', name: 'VM' })
return resolve({ id: '-', name: 'VM' })
} else {
if (!web3.currentProvider) {
callback && callback('No provider set')
return reject('No provider set')
}
const cb = (err, id) => {
let name = null
if (err) name = 'Unknown'
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
else if (id === 1) name = 'Main'
else if (id === 3) name = 'Ropsten'
else if (id === 4) name = 'Rinkeby'
else if (id === 5) name = 'Goerli'
else if (id === 42) name = 'Kovan'
else if (id === 11155111) name = 'Sepolia'
else name = 'Custom'
if (id === 1) {
web3.eth.getBlock(0).then((block) => {
if (block && block.hash !== this.mainNetGenesisHash) name = 'Custom'
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) {
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]
this.event.trigger('removeProvider', [name])
}
@ -164,7 +174,7 @@ export class ExecutionContext {
try {
this.currentFork = execution.forkAt(await web3.eth.net.getId(), block.number)
} catch (e) {
this.currentFork = 'merge'
this.currentFork = 'cancun'
console.log(`unable to detect fork, defaulting to ${this.currentFork}..`)
console.error(e)
}
@ -195,4 +205,32 @@ export class ExecutionContext {
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 { hashPersonalMessage, isHexString } from '@ethereumjs/util'
import { hashPersonalMessage, isHexString, bytesToHex } from '@ethereumjs/util'
import { ExecutionContext } from '../execution-context'
export class InjectedProvider {
@ -42,7 +42,7 @@ export class InjectedProvider {
try {
message = isHexString(message) ? message : Web3.utils.utf8ToHex(message)
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 (e) {
cb(e.message)

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

@ -1,6 +1,6 @@
import Web3, { FMT_BYTES, FMT_NUMBER, LegacySendAsyncProvider } from 'web3'
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 { ExecutionContext } from '../execution-context'
@ -12,9 +12,7 @@ export class VMProvider {
sendAsync: (query: JSONRPCRequestPayload, callback: JSONRPCResponseCallback) => void
}
newAccountCallback: {[stamp: number]: (error: Error, address: string) => void}
constructor (executionContext: ExecutionContext) {
this.executionContext = executionContext
this.worker = null
this.provider = null
@ -29,7 +27,7 @@ export class VMProvider {
})
}
async resetEnvironment () {
async resetEnvironment (stringifiedState?: string) {
if (this.worker) this.worker.terminate()
this.worker = new Worker(new URL('./worker-vm', import.meta.url))
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
// can be removed later when we update the API
createVMAccount (newAccount) {
const { privateKey, balance } = newAccount
this.worker.postMessage({ cmd: 'addAccount', privateKey: privateKey, balance })
const privKey = Buffer.from(privateKey, 'hex')
return '0x' + privateToAddress(privKey).toString('hex')
return bytesToHex(privateToAddress(privKey))
}
newAccount (_passwordPromptCb, cb) {
@ -109,7 +132,7 @@ export class VMProvider {
const messageHash = hashPersonalMessage(Buffer.from(message))
message = isHexString(message) ? message : Web3.utils.utf8ToHex(message)
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))
}

@ -6,7 +6,7 @@ self.onmessage = (e: MessageEvent) => {
switch (data.cmd) {
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(() => {
self.postMessage({
cmd: 'initiateResult',

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

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

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

@ -168,7 +168,7 @@ Before starting coding, we should ensure all devs / contributors are aware of:
### 3) Documentation:
- 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, ...)
---

@ -6,7 +6,7 @@ const version = require('../../package.json').version
const fs = require('fs')
const TerserPlugin = require('terser-webpack-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const axios = require('axios')
const path = require('path')
const versionData = {
version: version,
@ -16,9 +16,10 @@ const versionData = {
const loadLocalSolJson = async () => {
//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 })
// show output
//console.log(child)
console.log(child)
}
fs.writeFileSync(__dirname + '/src/assets/version.json', JSON.stringify(versionData))
@ -74,7 +75,7 @@ module.exports = composePlugins(withNx(), withReact(), (config) => {
// add externals
config.externals = {
...config.externals,
solc: 'solc'
solc: 'solc',
}
// 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
if(process.env.NX_DESKTOP_FROM_DIST){
@ -112,7 +124,7 @@ module.exports = composePlugins(withNx(), withReact(), (config) => {
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
url: ['url', 'URL'],
process: 'process/browser',
process: 'process/browser'
})
)

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

@ -520,9 +520,9 @@
semver "^7.3.5"
"@openzeppelin/contracts@^4.7.3":
version "4.9.3"
resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.3.tgz#00d7a8cf35a475b160b3f0293a6403c511099364"
integrity sha512-He3LieZ1pP2TNt5JbkPA4PNT9WC3gOTOlDcFGJW4Le4QKqwmiNJCRt44APfxMxvq7OugU/cqYuPcSBzOw38DAg==
version "4.9.6"
resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.6.tgz#2a880a24eb19b4f8b25adc2a5095f2aa27f39677"
integrity sha512-xSmezSupL+y9VkHZJGDoCBpmnB2ogM13ccaYDWqJTfS3dbuHkgjuwDFUmaFauBCboQMGB/S5UqUl2y54X99BmA==
"@openzeppelin/wizard@^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"
integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==
body-parser@1.20.1:
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:
body-parser@1.20.2, body-parser@^1.16.0:
version "1.20.2"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd"
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"
integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
cookie@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
cookie@0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
core-util-is@1.0.2:
version "1.0.2"
@ -2173,13 +2155,14 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1"
is-symbol "^1.0.2"
es5-ext@^0.10.35, es5-ext@^0.10.50:
version "0.10.62"
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5"
integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==
es5-ext@^0.10.35, es5-ext@^0.10.50, es5-ext@^0.10.62, es5-ext@~0.10.14:
version "0.10.63"
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.63.tgz#9c222a63b6a332ac80b1e373b426af723b895bd6"
integrity sha512-hUCZd2Byj/mNKjfP9jXrdVZ62B8KuA/VoK7X8nUh5qT+AxDmcbvZz041oDVZdbIN1qW6XY9VDNwzkvKnZvK2TQ==
dependencies:
es6-iterator "^2.0.3"
es6-symbol "^3.1.3"
esniff "^2.0.1"
next-tick "^1.1.0"
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"
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:
version "1.8.1"
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"
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:
version "4.0.4"
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"
integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==
express@^4.14.0, express@^4.18.2:
version "4.18.2"
resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59"
integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==
express@^4.14.0, express@^4.19.2:
version "4.19.2"
resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465"
integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==
dependencies:
accepts "~1.3.8"
array-flatten "1.1.1"
body-parser "1.20.1"
body-parser "1.20.2"
content-disposition "0.5.4"
content-type "~1.0.4"
cookie "0.5.0"
cookie "0.6.0"
cookie-signature "1.0.6"
debug "2.6.9"
depd "2.0.0"
@ -2489,9 +2490,9 @@ finalhandler@1.2.0:
unpipe "~1.0.0"
follow-redirects@^1.15.0:
version "1.15.3"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a"
integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==
version "1.15.6"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
for-each@^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"
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:
version "2.5.2"
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",
"location": "hiddenPanel",
"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",
"maintainedBy": "Remix",
"authorContact": "remix@ethereum.org"

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

@ -222,3 +222,47 @@ html, body, #root, main {
margin: 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 {CompilationResult} from '@remixproject/plugin-api'
@ -11,11 +11,14 @@ import LocalUrlInput from './components/LocalUrl'
import ToggleButtonGroup from 'react-bootstrap/ToggleButtonGroup'
import ToggleButton from 'react-bootstrap/ToggleButton'
import Button from 'react-bootstrap/Button'
import Accordion from 'react-bootstrap/Accordion'
import Card from 'react-bootstrap/Card'
import './app.css'
import {CustomTooltip} from '@remix-ui/helper'
import {Form} from 'react-bootstrap'
import {CompileErrorCard} from './components/CompileErrorCard'
import CustomAccordionToggle from './components/CustomAccordionToggle'
interface AppState {
status: 'idle' | 'inProgress'
@ -37,11 +40,16 @@ const App = () => {
localUrl: 'http://localhost:8000/',
})
const spinnerIcon = useRef(null)
useEffect(() => {
async function start() {
try {
await remixClient.loaded()
remixClient.onFileChange((name) => setContract(name))
remixClient.onFileChange((name) => {
setOutput({})
setContract(name)
})
remixClient.onNoFileSelected(() => setContract(''))
} catch (err) {
console.log(err)
@ -68,9 +76,6 @@ const App = () => {
useEffect(() => {
remixClient.eventEmitter.on('setOutput', (payload) => {
if (payload.status === 'failed') {
console.error('Error in the compiler', payload)
}
setOutput(payload)
})
@ -98,17 +103,17 @@ const App = () => {
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 (
<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>
<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.">
@ -117,25 +122,55 @@ const App = () => {
</Button>
</CustomTooltip>
</div>
<Form>
<div className="d-flex flex-row gap-5 mb-3 mt-2">
<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" />
<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'}} />
<Accordion className="border-0 w-100 mb-3 accordion-background">
<div className="border-0">
<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>
</Form>
<span className="px-3 mt-1 mb-1 small text-warning">Specify the compiler version & EVM version in the .vy file</span>
<LocalUrlInput url={state.localUrl} setUrl={setLocalUrl} environment={state.environment} />
</Accordion>
<span className="px-3 mt-3 mb-3 small text-warning">
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">
<CompilerButton compilerUrl={compilerUrl()} contract={contract} setOutput={(name, update) => setOutput({...output, [name]: update})} resetCompilerState={resetCompilerResultState} />
</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' ? (
<>
<VyperResult output={output} plugin={remixClient} />
</>
) : output.status === 'failed' ? (
<CompileErrorCard output={output} />
<CompileErrorCard output={output} plugin={remixClient} />
) : null}
</article>
</section>

@ -1,12 +1,17 @@
import {CopyToClipboard} from '@remix-ui/clipboard'
import Reaact from 'react'
import { RemixClient } from '../utils'
export function CompileErrorCard(props: any) {
export function CompileErrorCard(props: { output: any, plugin: RemixClient }) {
return (
<div id="vyperErrorResult" className="px-2 mx-3 alert alert-danger error" title={props.output.message}>
<i className="fas fa-exclamation-circle text-danger"></i>
<div
id="vyperErrorResult"
className=" d-flex flex-column p-2 alert alert-danger error vyper-compile-error vyper-panel-width"
title={props.output?.title}
>
<span
data-id="error-message"
className="text-center"
className="text-left"
style={{
overflowX: 'hidden',
textOverflow: 'ellipsis',
@ -14,6 +19,16 @@ export function CompileErrorCard(props: any) {
>
{props.output.message.trim()}
</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>
)
}

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

@ -31,9 +31,7 @@ export interface VyperCompilationError {
export type VyperCompilationOutput = VyperCompilationResult | VyperCompilationError
/** Check if the output is an error */
export function isCompilationError(output: VyperCompilationOutput): output is VyperCompilationError {
return output.status === 'failed'
}
export const isCompilationError = (output: VyperCompilationOutput): output is VyperCompilationError => output.status === 'failed'
export function normalizeContractPath(contractPath: string): string[] {
const paths = contractPath.split('/')
@ -52,22 +50,113 @@ function parseErrorString(errorString) {
// Split the string into lines
let lines = errorString.trim().split('\n')
// Extract the line number and message
let message = lines[1].trim()
let message = errorString.trim()
let targetLine = lines[2].split(',')
let lineColumn = targetLine[targetLine.length - 1].split(' ')[2].split(':')
let tline = lines[2].trim().split(' ')[1].split(':')
const errorObject = {
status: 'failed',
message: message,
column: parseInt(lineColumn[1]),
line: parseInt(lineColumn[0])
column: tline[1],
line: tline[0]
}
message = null
targetLine = null
lineColumn = null
lines = null
tline = null
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
* @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.')
}
let contractName = contract['name']
const compilePackage = {
manifest: 'ethpm/3',
sources: {
[contractName] : {content : contract.content}
[contractName] : {content : fixContractContent(contract.content)}
}
}
let response = await axios.post(`${url}compile`, compilePackage )
@ -181,15 +272,11 @@ export async function compileContract(contract: string, compilerUrl: string, set
try {
_contract = await remixClient.getContract()
} catch (e: any) {
// if (setOutput === null || setOutput === undefined) {
const compileResult = {
const errorGettingContract = {
status: 'failed',
message: e.message
}
remixClient.eventEmitter.emit('setOutput', compileResult)
// } else {
// setOutput('', {status: 'failed', message: e.message})
// }
remixClient.eventEmitter.emit('setOutput', errorGettingContract)
return
}
remixClient.changeStatus({
@ -198,76 +285,19 @@ export async function compileContract(contract: string, compilerUrl: string, set
title: 'Compiling'
})
let output
try {
output = await compile(compilerUrl, _contract)
console.log('checking compile result', output)
remixClient.eventEmitter.emit('setOutput', output)
} catch (e: any) {
// try {
output = await compile(compilerUrl, _contract)
if (output.status === 'failed') {
remixClient.changeStatus({
key: 'failed',
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: e.message})
remixClient.eventEmitter.emit('setOutput', {status: 'failed', message: output.message, title: 'Error compiling...', line: output.line, column: output.column})
output = null
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
// remixClient.discardHighlight()
remixClient.changeStatus({
@ -278,12 +308,12 @@ export async function compileContract(contract: string, compilerUrl: string, set
const data = toStandardOutput(_contract.name, output)
remixClient.compilationFinish(_contract.name, _contract.content, data)
const contractName = _contract['name']
const compileResult = compileReturnType(output, contractName)
if (setOutput === null || setOutput === undefined) {
const contractName = _contract['name']
const compileResult = compileReturnType()
remixClient.eventEmitter.emit('setOutput', { contractName, compileResult })
} else {
setOutput(_contract.name, compileReturnType())
remixClient.eventEmitter.emit('setOutput', { contractName, compileResult })
}
} catch (err: any) {
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() {
try {
// @ts-ignore
@ -144,4 +161,3 @@ export class RemixClient extends PluginClient {
}
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" />
<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>
<body>
<div id="root"></div>
<script src="https://kit.fontawesome.com/41dd021e94.js" crossorigin="anonymous"></script>
</body>
</html>

@ -1,12 +1,12 @@
{
"name": "vyper",
"displayName": "Vyper",
"displayName": "Vyper Compiler",
"methods": ["getCompilationResult", "compile", "vyperCompileCustomAction"],
"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",
"kind": "compiler",
"icon": "data:image/svg+xml;base64,PHN2ZyBpZD0iRmxhdF9Mb2dvIiBkYXRhLW5hbWU9IkZsYXQgTG9nbyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMjA0OCAxNzczLjYyIj4gIDx0aXRsZT52eXBlci1sb2dvLWZsYXQ8L3RpdGxlPiAgPHBvbHlsaW5lIHBvaW50cz0iMTAyNCA4ODYuODEgNzY4IDEzMzAuMjIgMTAyNCAxNzczLjYyIDEyODAgMTMzMC4yMiAxMDI0IDg4Ni44MSIgc3R5bGU9ImZpbGw6IzMzMyIvPiAgPHBvbHlsaW5lIHBvaW50cz0iMTI4MCA0NDMuNDEgMTAyNCA4ODYuODEgMTI4MCAxMzMwLjIyIDE1MzYgODg2LjgxIDEyODAgNDQzLjQxIiBzdHlsZT0iZmlsbDojNjY2Ii8+ICA8cG9seWxpbmUgcG9pbnRzPSI3NjggNDQzLjQxIDUxMiA4ODYuODEgNzY4IDEzMzAuMjIgMTAyNCA4ODYuODEgNzY4IDQ0My40MSIgc3R5bGU9ImZpbGw6IzY2NiIvPiAgPHBvbHlsaW5lIHBvaW50cz0iMTUzNiAwIDEyODAgNDQzLjQxIDE1MzYgODg2LjgxIDE3OTIgNDQzLjQxIDE1MzYgMCIgc3R5bGU9ImZpbGw6IzhjOGM4YyIvPiAgPHBvbHlsaW5lIHBvaW50cz0iMTE1MiAyMjEuNyA4OTYgMjIxLjcgNzY4IDQ0My40MSAxMDI0IDg4Ni44MSAxMjgwIDQ0My40MSAxMTUyIDIyMS43IiBzdHlsZT0iZmlsbDojOGM4YzhjIi8+ICA8cG9seWxpbmUgcG9pbnRzPSI1MTIgMCAyNTYgNDQzLjQxIDUxMiA4ODYuODEgNzY4IDQ0My40MSA1MTIgMCIgc3R5bGU9ImZpbGw6IzhjOGM4YyIvPiAgPHBvbHlsaW5lIHBvaW50cz0iMjA0OCAwIDE1MzYgMCAxNzkyIDQ0My40IDIwNDggMCIgc3R5bGU9ImZpbGw6I2IyYjJiMiIvPiAgPHBvbHlsaW5lIHBvaW50cz0iNTEyIDAgMCAwIDI1NiA0NDMuNCA1MTIgMCIgc3R5bGU9ImZpbGw6I2IyYjJiMiIvPjwvc3ZnPg==",
"icon": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzM4IiBoZWlnaHQ9IjM3NiIgdmlld0JveD0iMCAwIDMzOCAzNzYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0xOTUuMzA0IDMxMS44MzdMODIuNTE4IDE5OS4wODRDNzcuOTI0MSAxOTQuMzA0IDc1LjM5MjcgMTg3LjgzNyA3NS4zOTI3IDE4MC42MlYxOS42OTE0Qzc1LjM5MjcgMTAuMzE4OCA2Ni4wMTc0IDAuOTQ2MTI3IDU2LjY0MiAwLjk0NjEyN0gxOS4wNDY3QzkuNjcxMjggMC45NDYxMjcgMC4yOTU4OTggMTAuMzE4OCAwLjI5NTg5OCAxOS42OTE0VjIwNy4xNDVDMC4yOTU4OTggMjE3LjA4IDMuOTUyMyAyMjYuNjQgMTAuOTgzOCAyMzMuNjY5TDE0Mi4yMzkgMzY0Ljg4NkMxNDkuNTUyIDM3Mi4xOTcgMTU5LjExNSAzNzUuODUyIDE2OC43NzIgMzc1Ljg1MkgxODcuNTIyQzE5Ny45MjkgMzc1Ljg1MiAyMDYuMjczIDM2Ny40MTcgMjA2LjI3MyAzNTcuMTA3VjMzOC40NTZDMjA2LjI3MyAzMjguODAyIDIwMi42MTcgMzE5LjI0MiAxOTUuMzA0IDMxMS45MzFWMzExLjgzN1oiIGZpbGw9IiMxODBDMjUiLz4KPHBhdGggZD0iTTMzNy44MSAxOS41OTc3QzMzNy44MSAxMC4xMzEzIDMyOC41MjkgMC44NTI0MTcgMzE5LjA1OSAwLjg1MjQxN0gyODEuNDY0QzI3Mi4wODkgMC44NTI0MTcgMjYyLjcxMyAxMC4yMjUxIDI2Mi43MTMgMTkuNTk3N1YxODAuNDMzQzI2Mi43MTMgMTg3LjY1IDI1OS45MDEgMTk0LjExNyAyNTUuMjEzIDE5OC45OUwyMTcuNDMgMjM2Ljc2MkMyMTAuMTE4IDI0NC4wNzMgMjA2LjQ2MSAyNTMuNjMzIDIwNi40NjEgMjYzLjI4N1YyODIuMDMyQzIwNi40NjEgMjkyLjQzNiAyMTQuODk5IDMwMC43NzggMjI1LjIxMiAzMDAuNzc4SDI0My45NjNDMjUzLjUyNiAzMDAuNzc4IDI2My4xODIgMjk3LjEyMiAyNzAuNDk1IDI4OS44MTFMMzI2Ljc0NyAyMzMuNTc2QzMzMy43NzkgMjI2LjU0NiAzMzcuNzE2IDIxNi45ODYgMzM3LjcxNiAyMDcuMDUxVjE5LjU5NzdIMzM3LjgxWiIgZmlsbD0iIzE4MEMyNSIvPgo8L3N2Zz4K",
"location": "sidePanel",
"repo": "https://github.com/ethereum/remix-project/tree/master/apps/vyper",
"maintainedBy": "Remix",

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

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

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

@ -8,3 +8,4 @@ export * from './types/contract'
export { LinkLibraries, DeployLibraries } from './lib/link-libraries'
export { OpenZeppelinProxy } from './lib/openzeppelin-proxy'
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 { fetchContractFromEtherscan } from './helpers/fetch-etherscan'
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 = {
name: 'fetchAndCompile',
@ -88,8 +88,8 @@ export class FetchAndCompile extends Plugin {
const settings = {
version: UUPSCompilerVersionV5,
language: UUPSLanguage,
evmVersion: UUPSEvmVersion,
optimize: UUPSOptimize,
evmVersion: UUPSEvmVersionv5,
optimize: UUPSOptimizev5,
runs: UUPSRuns
}
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 workspaces = await this.call('filePanel', 'getWorkspaces')
const found = workspaces.find((workspace) => workspace.name === gistIdWorkspace)
if (found) {
await this.call('notification', 'alert', `workspace "${gistIdWorkspace}" already exist`)
if (found) {
await this.call('notification', 'alert', {
id: 'gistAlert',
message: `workspace "${gistIdWorkspace}" already exists`,
})
return
}
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",
"version": "0.5.42",
"version": "0.5.45",
"description": "Tool to debug Ethereum transactions",
"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"
},
"dependencies": {
"@ethereumjs/block": "^4.2.0",
"@ethereumjs/common": "^3.1.1",
"@ethereumjs/tx": "^4.1.1",
"@ethereumjs/util": "^8.0.5",
"@ethereumjs/vm": "^6.4.1",
"@remix-project/remix-astwalker": "^0.0.72",
"@remix-project/remix-lib": "^0.5.49",
"@remix-project/remix-simulator": "^0.2.42",
"@remix-project/remix-solidity": "^0.5.28",
"@ethereumjs/block": "5.2.0",
"@ethereumjs/common": "4.3.0",
"@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0",
"@remix-project/remix-astwalker": "^0.0.75",
"@remix-project/remix-lib": "^0.5.52",
"@remix-project/remix-simulator": "^0.2.45",
"@remix-project/remix-solidity": "^0.5.31",
"ansi-gray": "^0.1.1",
"async": "^2.6.2",
"color-support": "^1.1.3",
@ -69,6 +69,6 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme",
"typings": "src/index.d.ts",
"gitHead": "817089ab1f206f5e195756a4051afb812ec26901",
"gitHead": "aebbd10b67952c3aa0cbf7e82944cd91fcd6f48c",
"types": "./src/index.d.ts"
}

@ -1,6 +1,8 @@
'use strict'
import { bytesToHex } from '@ethereumjs/util'
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'
export function nameOpCodes (raw, hardfork) {
@ -27,7 +29,8 @@ export function nameOpCodes (raw, hardfork) {
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)
pushData = ''
@ -46,7 +49,7 @@ type Opcode = {
* information about the opcode.
*/
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 code = []

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

@ -2,7 +2,7 @@
import { hash } from '@remix-project/remix-lib'
import { RefType } from './RefType'
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'
export class Mapping extends RefType {
@ -44,7 +44,7 @@ export class Mapping extends RefType {
}
async decodeMappingsLocation (preimages, location, storageResolver) {
const mapSlot = normalizeHex(bufferToHex(location.slot))
const mapSlot = normalizeHex('0x' + location.slot.toString(16))
if (!preimages[mapSlot]) {
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.
// key should be a hex string, and position an int
const mappingK = toBuffer(addHexPrefix(key))
let mappingP = toBuffer(addHexPrefix(position))
const mappingK = toBytes(addHexPrefix(key))
let mappingP = toBytes(addHexPrefix(position))
mappingP = setLengthLeft(mappingP, 32)
const mappingKeyBuf = concatTypedArrays(mappingK, mappingP)
const mappingStorageLocation: Buffer = hash.keccak(mappingKeyBuf)
const mappingStorageLocation: Uint8Array = hash.keccak(mappingKeyBuf)
const mappingStorageLocationinBn: BN = new BN(mappingStorageLocation, 16)
return mappingStorageLocationinBn
}

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

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

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

@ -10,7 +10,7 @@ import { InternalCallTree } from '../../../src/solidity-decoder/internalCallTree
import * as vmCall from '../../vmCall'
import { StorageResolver } from '../../../src/storage/storageResolver'
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) {
const mappingStorage = require('../contracts/mappingStorage')

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

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

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

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

@ -1,6 +1,6 @@
'use strict'
import { ethers } from 'ethers'
import { toBuffer, addHexPrefix } from '@ethereumjs/util'
import { toBytes, addHexPrefix } from '@ethereumjs/util'
import { EventManager } from '../eventManager'
import { compareByteCode, getinputParameters } from '../util'
import { decodeResponse } from './txFormat'
@ -64,9 +64,9 @@ export class TxListener {
let execResult
if (this.executionContext.isVM()) {
execResult = await this.executionContext.web3().remix.getExecutionResultFromSimulator(txResult.transactionHash)
returnValue = toBuffer(execResult.returnValue)
returnValue = toBytes(execResult.returnValue)
} else {
returnValue = toBuffer(addHexPrefix(txResult.result))
returnValue = toBytes(addHexPrefix(txResult.result))
}
const call = {
from: from,
@ -374,7 +374,7 @@ export class TxListener {
}
_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
const inputTypes = []

@ -1,9 +1,10 @@
'use strict'
import { RunBlockResult, RunTxResult } from '@ethereumjs/vm'
import { ConsensusType } from '@ethereumjs/common'
import { Transaction, FeeMarketEIP1559Transaction } from '@ethereumjs/tx'
import { LegacyTransaction, FeeMarketEIP1559Transaction } from '@ethereumjs/tx'
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 { EventManager } from '../eventManager'
import { LogsManager } from './logsManager'
@ -13,7 +14,7 @@ export type VMexecutionResult = {
result: RunTxResult,
transactionHash: string
block: Block,
tx: Transaction
tx: LegacyTransaction
}
export type VMExecutionCallBack = (error: string | Error, result?: VMexecutionResult) => void
@ -24,24 +25,23 @@ export class TxRunnerVM {
pendingTxs
vmaccounts
queusTxs
blocks
blocks: Uint8Array[]
logsManager
commonContext
blockParentHash
nextNonceForCall: number
standaloneTx: boolean
getVMObject: () => any
constructor (vmaccounts, api, getVMObject, blockNumber) {
constructor (vmaccounts, api, getVMObject, blocks: Uint8Array[] = []) {
this.event = new EventManager()
this.logsManager = new LogsManager()
// has a default for now for backwards compatibility
this.getVMObject = getVMObject
this.commonContext = this.getVMObject().common
this.blockNumber = blockNumber || 0
this.commonContext = this.getVMObject().common
this.pendingTxs = {}
this.vmaccounts = vmaccounts
this.queusTxs = []
this.blocks = []
/*
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)
@ -51,7 +51,15 @@ export class TxRunnerVM {
this.nextNonceForCall = 0
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) {
@ -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
if (!from && useCall && Object.keys(this.vmaccounts).length) {
from = Object.keys(this.vmaccounts)[0]
@ -78,76 +86,90 @@ export class TxRunnerVM {
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.
let tx
if (!EIP1559) {
tx = Transaction.fromTxData({
tx = LegacyTransaction.fromTxData({
nonce: useCall ? this.nextNonceForCall : res.nonce,
gasPrice: '0x1',
gasLimit: gasLimit,
to: to,
value: value,
data: Buffer.from(data.slice(2), 'hex')
data: hexToBytes(data)
}, { common: this.commonContext }).sign(account.privateKey)
} else {
tx = FeeMarketEIP1559Transaction.fromTxData({
nonce: useCall ? this.nextNonceForCall : res.nonce,
maxPriorityFeePerGas: '0x01',
maxFeePerGas: '0x1',
maxFeePerGas: '0x7',
gasLimit: gasLimit,
to: to,
value: value,
data: Buffer.from(data.slice(2), 'hex')
data: hexToBytes(data)
}).sign(account.privateKey)
}
if (useCall) this.nextNonceForCall++
const coinbases = ['0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a', '0x8945a1288dc78a6d8952a92c77aee6730b414778', '0x94d76e24f818426ae84aa404140e8d5f60e10e7e']
const difficulties = [69762765929000, 70762765929000, 71762765929000]
const difficulty = this.commonContext.consensusType() === ConsensusType.ProofOfStake ? 0 : difficulties[this.blockNumber % difficulties.length]
const blocknumber = this.blockNumber + 1
const difficulty = this.commonContext.consensusType() === ConsensusType.ProofOfStake ? 0 : difficulties[this.blocks.length % difficulties.length]
const block = Block.fromBlockData({
header: {
timestamp: new Date().getTime() / 1000 | 0,
number: blocknumber,
coinbase: coinbases[blocknumber % coinbases.length],
number: this.blocks.length,
coinbase: coinbases[this.blocks.length % coinbases.length],
difficulty,
gasLimit,
baseFeePerGas: EIP1559 ? '0x1' : undefined,
parentHash: this.blockParentHash
},
transactions: [tx]
}, { common: this.commonContext, hardforkByBlockNumber: false, hardforkByTTD: undefined })
}, { common: this.commonContext })
if (!useCall) {
this.blockNumber = this.blockNumber + 1
if (!this.standaloneTx) {
this.blockParentHash = block.hash()
this.runBlockInVm(tx, block, (err, result) => {
if (!err) this.getVMObject().vm.blockchain.putBlock(block)
this.runBlockInVm(tx, block, async (err, result) => {
if (!err) {
if (!useCall) {
this.getVMObject().vm.blockchain.putBlock(block)
this.blocks.push(block.serialize())
}
}
callback(err, result)
})
} else {
this.getVMObject().stateManager.checkpoint().then(() => {
this.runBlockInVm(tx, block, (err, result) => {
this.getVMObject().stateManager.revert().then(() => {
callback(err, result)
})
})
await this.getVMObject().vm.evm.journal.checkpoint()
this.runTxInVm(tx, block, async (err, result) => {
await this.getVMObject().vm.evm.journal.revert()
callback(err, result)
})
}
}).catch((e) => {
} catch (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) {
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]
callback(null, {
result,
transactionHash: bufferToHex(Buffer.from(tx.hash())),
transactionHash: bytesToHex(Buffer.from(tx.hash())),
block,
tx
})

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

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

Loading…
Cancel
Save