Merge branch 'master' into m10

pull/1635/head
Rob 3 years ago committed by GitHub
commit 5de3aa4f3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      .circleci/config.yml
  2. 1
      .gitignore
  3. 9
      apps/debugger/src/app/debugger-api.ts
  4. 2
      apps/remix-ide-e2e/src/commands/addFile.ts
  5. 1
      apps/remix-ide-e2e/src/commands/executeScript.ts
  6. 7
      apps/remix-ide-e2e/src/commands/journalLastChildIncludes.ts
  7. 3
      apps/remix-ide-e2e/src/commands/testFunction.ts
  8. 1
      apps/remix-ide-e2e/src/commands/verifyContracts.ts
  9. 17
      apps/remix-ide-e2e/src/tests/ballot.test.ts
  10. 2
      apps/remix-ide-e2e/src/tests/compiler_api.test.ts
  11. 3
      apps/remix-ide-e2e/src/tests/debugger.spec.ts
  12. 4
      apps/remix-ide-e2e/src/tests/defaultLayout.test.ts
  13. 6
      apps/remix-ide-e2e/src/tests/editor.spec.ts
  14. 8
      apps/remix-ide-e2e/src/tests/fileManager_api.spec.ts
  15. 1
      apps/remix-ide-e2e/src/tests/libraryDeployment.test.ts
  16. 89
      apps/remix-ide-e2e/src/tests/solidityUnittests.spec.ts
  17. 91
      apps/remix-ide-e2e/src/tests/terminal.test.ts
  18. 13
      apps/remix-ide-e2e/src/tests/transactionExecution.spec.ts
  19. 28
      apps/remix-ide-e2e/src/tests/workspace.test.ts
  20. 4
      apps/remix-ide-e2e/src/types/index.d.ts
  21. 6
      apps/remix-ide/src/app.js
  22. 2
      apps/remix-ide/src/app/components/main-panel.js
  23. 835
      apps/remix-ide/src/app/panels/terminal.js
  24. 4
      apps/remix-ide/src/app/tabs/compile-tab.js
  25. 9
      apps/remix-ide/src/app/tabs/runTab/contractDropdown.js
  26. 41
      apps/remix-ide/src/app/tabs/test-tab.js
  27. 1
      apps/remix-ide/src/blockchain/execution-context.js
  28. 1
      apps/remix-ide/src/lib/cmdInterpreterAPI.js
  29. 1
      apps/solidity-compiler/src/app/compiler.ts
  30. 18
      apps/solidity-compiler/webpack.config.js
  31. 3
      libs/remix-analyzer/.eslintrc
  32. 6
      libs/remix-analyzer/package.json
  33. 3
      libs/remix-astwalker/.eslintrc
  34. 6
      libs/remix-astwalker/package.json
  35. 1
      libs/remix-astwalker/src/astWalker.ts
  36. 1
      libs/remix-astwalker/src/sourceMappings.ts
  37. 2
      libs/remix-core-plugin/src/lib/compiler-artefacts.ts
  38. 9
      libs/remix-debug/package.json
  39. 2
      libs/remix-debug/src/storage/storageResolver.ts
  40. 24
      libs/remix-debug/test/debugger.ts
  41. 19
      libs/remix-debug/test/decoder/localDecoder.ts
  42. 19
      libs/remix-debug/test/decoder/localsTests/calldata.ts
  43. 14
      libs/remix-debug/test/decoder/localsTests/int.ts
  44. 16
      libs/remix-debug/test/decoder/localsTests/misc.ts
  45. 14
      libs/remix-debug/test/decoder/localsTests/misc2.ts
  46. 14
      libs/remix-debug/test/decoder/localsTests/structArray.ts
  47. 34
      libs/remix-debug/test/decoder/stateTests/mapping.ts
  48. 76
      libs/remix-debug/test/decoder/vmCall.ts
  49. 2
      libs/remix-debug/test/tests.ts
  50. 73
      libs/remix-debug/test/vmCall.ts
  51. 3
      libs/remix-lib/.eslintrc
  52. 6
      libs/remix-lib/package.json
  53. 25
      libs/remix-lib/src/execution/logsManager.ts
  54. 1
      libs/remix-lib/src/execution/txRunnerVM.ts
  55. 12
      libs/remix-lib/src/web3Provider/web3VmProvider.ts
  56. 8
      libs/remix-simulator/package.json
  57. 5
      libs/remix-simulator/src/methods/blocks.ts
  58. 32
      libs/remix-simulator/src/methods/transactions.ts
  59. 46
      libs/remix-simulator/src/vm-context.ts
  60. 28
      libs/remix-simulator/test/blocks.ts
  61. 3
      libs/remix-solidity/.eslintrc
  62. 6
      libs/remix-solidity/package.json
  63. 3
      libs/remix-tests/.eslintrc
  64. 2
      libs/remix-tests/jest.config.js
  65. 8
      libs/remix-tests/package.json
  66. 3
      libs/remix-tests/src/compiler.ts
  67. 5
      libs/remix-tests/src/deployer.ts
  68. 4
      libs/remix-tests/src/runTestFiles.ts
  69. 8
      libs/remix-tests/src/runTestSources.ts
  70. 32
      libs/remix-tests/src/testRunner.ts
  71. 5
      libs/remix-tests/src/types.ts
  72. 12
      libs/remix-tests/tests/examples_0/assert_ok_without_console_test.sol
  73. 20
      libs/remix-tests/tests/testRunner.cli.spec.ts
  74. 108
      libs/remix-tests/tests/testRunner.spec.ts
  75. 8
      libs/remix-ui/debugger-ui/src/lib/idebugger-api.ts
  76. 6
      libs/remix-ui/debugger-ui/src/types/index.ts
  77. 2
      libs/remix-ui/file-explorer/src/lib/file-explorer.tsx
  78. 2
      libs/remix-ui/file-explorer/src/lib/types/index.ts
  79. 1
      libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx
  80. 1
      libs/remix-ui/modal-dialog/src/lib/types/index.ts
  81. 2
      libs/remix-ui/plugin-manager/src/lib/components/ActivePluginCard.tsx
  82. 2
      libs/remix-ui/plugin-manager/src/lib/components/ActivePluginCardContainer.tsx
  83. 2
      libs/remix-ui/plugin-manager/src/lib/components/InactivePluginCard.tsx
  84. 2
      libs/remix-ui/plugin-manager/src/lib/components/InactivePluginCardContainer.tsx
  85. 4
      libs/remix-ui/plugin-manager/src/lib/components/LocalPluginForm.tsx
  86. 2
      libs/remix-ui/plugin-manager/src/lib/components/moduleHeading.tsx
  87. 2
      libs/remix-ui/plugin-manager/src/lib/components/permissionsSettings.tsx
  88. 2
      libs/remix-ui/plugin-manager/src/lib/components/rootView.tsx
  89. 2
      libs/remix-ui/plugin-manager/src/lib/remix-ui-plugin-manager.tsx
  90. 11
      libs/remix-ui/plugin-manager/src/types.d.ts
  91. 2
      libs/remix-ui/publish-to-storage/src/lib/publish-to-storage.tsx
  92. 1
      libs/remix-ui/solidity-compiler/src/lib/actions/compiler.ts
  93. 2
      libs/remix-ui/solidity-compiler/src/lib/logic/compileTabLogic.ts
  94. 2
      libs/remix-ui/solidity-compiler/src/lib/solidity-compiler.tsx
  95. 6
      libs/remix-ui/solidity-compiler/src/lib/types/index.ts
  96. 2
      libs/remix-ui/static-analyser/src/lib/remix-ui-static-analyser.tsx
  97. 4
      libs/remix-ui/terminal/.babelrc
  98. 19
      libs/remix-ui/terminal/.eslintrc
  99. 7
      libs/remix-ui/terminal/README.md
  100. 4
      libs/remix-ui/terminal/package.json
  101. Some files were not shown because too many files have changed in this diff Show More

@ -51,6 +51,7 @@ jobs:
- checkout
- run: npm install
- run: npm run build:libs
- run: cd dist/libs/remix-tests && npm install
- run: npm run test:libs
remix-ide-chrome-1:

1
.gitignore vendored

@ -30,6 +30,7 @@ soljson.js
*.launch
.settings/
*.sublime-workspace
.vscode/
# IDE - VSCode
.vscode/*

@ -4,6 +4,9 @@ import { CompilationOutput, Sources } from '@remix-ui/debugger-ui'
import type { CompilationResult } from '@remix-project/remix-solidity-ts'
export const DebuggerApiMixin = (Base) => class extends Base {
initialWeb3
initDebuggerApi () {
this.debugHash = null
@ -16,6 +19,8 @@ export const DebuggerApiMixin = (Base) => class extends Base {
}
}
this._web3 = new Web3(this.web3Provider)
// this._web3 can be overwritten and reset to initial value in 'debug' method
this.initialWeb3 = this._web3
remixDebug.init.extendWeb3(this._web3)
this.offsetToLineColumnConverter = {
@ -123,7 +128,9 @@ export const DebuggerApiMixin = (Base) => class extends Base {
debug (hash, web3?) {
this.debugHash = hash
if (web3) remixDebug.init.extendWeb3(web3)
if (web3) this._web3 = web3
else this._web3 = this.initialWeb3
remixDebug.init.extendWeb3(this._web3)
if (this.onDebugRequestedListener) this.onDebugRequestedListener(hash, web3)
}

@ -17,7 +17,7 @@ function addFile (browser: NightwatchBrowser, name: string, content: NightwatchC
browser.clickLaunchIcon('udapp')
.clickLaunchIcon('filePanel')
.click('li[data-id="treeViewLitreeViewItemREADME.txt"]') // focus on root directory
.click('.newFile')
.click('[data-id="fileExplorerNewFilecreateNewFile"]')
.waitForElementContainsText('*[data-id$="/blank"]', '', 60000)
.sendKeys('*[data-id$="/blank"] .remixui_items', name)
.sendKeys('*[data-id$="/blank"] .remixui_items', browser.Keys.ENTER)

@ -6,6 +6,7 @@ class ExecuteScript extends EventEmitter {
this.api
.clearEditableContent('*[data-id="terminalCliInput"]')
.click('*[data-id="terminalCli"]')
.setValue('*[data-id="terminalCliInput"]', [this.api.Keys.CONTROL, 'a', this.api.Keys.DELETE])
.sendKeys('*[data-id="terminalCliInput"]', script)
.sendKeys('*[data-id="terminalCliInput"]', this.api.Keys.ENTER)
.sendKeys('*[data-id="terminalCliInput"]', this.api.Keys.ENTER)

@ -7,11 +7,12 @@ import EventEmitter from 'events'
class JournalLastChildIncludes extends EventEmitter {
command (this: NightwatchBrowser, val: string): NightwatchBrowser {
this.api
.waitForElementVisible('*[data-id="terminalJournal"] > div:last-child', 10000)
.getText('*[data-id="terminalJournal"] > div:last-child', (result) => {
.waitForElementVisible('*[data-id="terminalJournal"]', 10000)
.pause(1000)
.getText('*[data-id="terminalJournal"]', (result) => {
console.log('JournalLastChildIncludes', result.value)
if (typeof result.value === 'string' && result.value.indexOf(val) === -1) return this.api.assert.fail(`wait for ${val} in ${result.value}`)
else this.api.assert.ok(true, `<*[data-id="terminalJournal"] > div:last-child> contains ${val}.`)
else this.api.assert.ok(true, `<*[data-id="terminalJournal"]> contains ${val}.`)
this.emit('complete')
})
return this

@ -24,8 +24,8 @@ class TestFunction extends EventEmitter {
.perform((done) => {
browser.waitForElementVisible(`[data-id="block_tx${txHash}"]`, 60000)
.click(`[data-id="block_tx${txHash}"]`)
.pause(3000)
.waitForElementVisible(`*[data-id="txLoggerTable${txHash}"]`, 60000)
.pause(10000)
// fetch and format transaction logs as key => pair object
.elements('css selector', `*[data-shared="key_${txHash}"]`, (res) => {
Array.isArray(res.value) && res.value.forEach(function (jsonWebElement) {
@ -58,7 +58,6 @@ class TestFunction extends EventEmitter {
.perform(() => {
Object.keys(expectedValue).forEach(key => {
let equal = false
try {
const receivedValue = JSON.parse(logs[key])

@ -17,6 +17,7 @@ function verifyContracts (browser: NightwatchBrowser, compiledContractNames: str
browser
.clickLaunchIcon('solidity')
.pause(opts.wait)
.pause(5000)
.waitForElementPresent('*[data-id="compiledContracts"] option', 60000)
.perform((done) => {
if (opts.version) {

@ -56,8 +56,7 @@ module.exports = {
.waitForElementVisible('#stepdetail')
.goToVMTraceStep(144)
.pause(2000)
// Should be uncommented while fixing https://github.com/ethereum/remix-project/issues/1644
// .checkVariableDebug('soliditystate', stateCheck)
.checkVariableDebug('soliditystate', stateCheck)
.checkVariableDebug('soliditylocals', localsCheck)
},
@ -82,8 +81,16 @@ module.exports = {
'Deploy and use Ballot using external web3': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="settingsWeb3Mode"]')
.click('option[value="web3"]')
.pause(5000)
.modalFooterOKClick()
.execute(function () {
const env: any = document.getElementById('selectExEnvOptions')
return env.value
}, [], function (result) {
console.log({ result })
browser.assert.ok(result.value === 'web3', 'Web3 Provider not selected')
})
.clickLaunchIcon('solidity')
.testContracts('Untitled.sol', sources[0]['Untitled.sol'], ['Ballot'])
.clickLaunchIcon('udapp')
@ -117,7 +124,7 @@ const localsCheck = {
type: 'address'
}
}
/*
const stateCheck = {
chairperson: {
value: '0xCA35B7D915458EF540ADE6068DFE2F44E8FA733C',
@ -175,8 +182,6 @@ const stateCheck = {
immutable: false
}
}
*/
const ballotABI = `[
{
"inputs": [

@ -21,7 +21,7 @@ module.exports = {
browser
.addFile('test_jsCompile.js', { content: jsCompile })
.executeScript('remix.exeCurrent()')
.waitForElementContainsText('*[data-id="terminalJournal"]', '"languageversion": "0.6.8+commit.0bbfe453"', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '"languageversion":"0.6.8+commit.0bbfe453"', 60000)
.click('*[data-id="terminalClearConsole"]')
},

@ -187,7 +187,8 @@ module.exports = {
browser
.addFile('test_jsGetTrace.js', { content: jsGetTrace })
.executeScript('remix.exeCurrent()')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'result { "gas": "0x575f", "return": "0x0000000000000000000000000000000000000000000000000000000000000000", "structLogs":', 60000)
.pause(1000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '{"gas":"0x575f","return":"0x0000000000000000000000000000000000000000000000000000000000000000","structLogs":', 60000)
},
'Should call the debugger api: debug': function (browser: NightwatchBrowser) {

@ -50,11 +50,11 @@ module.exports = {
'Toggles Terminal': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('div[data-id="terminalContainer"]')
.assert.visible('div[data-id="terminalContainerDisplay"]')
.assert.elementPresent('div[data-id="terminalContainerDisplay"]')
.click('i[data-id="terminalToggleIcon"]')
.checkElementStyle('div[data-id="terminalToggleMenu"]', 'height', '35px')
.click('i[data-id="terminalToggleIcon"]')
.assert.visible('div[data-id="terminalContainerDisplay"]')
.assert.elementPresent('div[data-id="terminalContainerDisplay"]')
},
'Switch Tabs using tabs icon': function (browser: NightwatchBrowser) {

@ -34,8 +34,8 @@ module.exports = {
browser.waitForElementVisible('*[data-id="editorInput"]')
.waitForElementVisible('*[class="ace_content"]')
.click('*[class="ace_content"]')
.editorScroll('down', 27) // scroll down to line 27 and add the error word
.sendKeys('*[class="ace_text-input"]', 'error')
.pause(2000)
.waitForElementVisible('.ace_error', 120000)
.checkAnnotations('error', 28)
.clickLaunchIcon('udapp')
@ -92,9 +92,13 @@ module.exports = {
.openFile('sourcehighlight.js')
.executeScript('remix.exeCurrent()')
.editorScroll('down', 60)
.pause(1000)
.waitForElementPresent('.highlightLine32', 60000)
.pause(1000)
.checkElementStyle('.highlightLine32', 'background-color', 'rgb(8, 108, 181)')
.pause(1000)
.waitForElementPresent('.highlightLine40', 60000)
.pause(1000)
.checkElementStyle('.highlightLine40', 'background-color', 'rgb(8, 108, 181)')
.waitForElementPresent('.highlightLine50', 60000)
.checkElementStyle('.highlightLine50', 'background-color', 'rgb(8, 108, 181)')

@ -11,6 +11,7 @@ module.exports = {
browser
.addFile('file.js', { content: executeFile })
.executeScript('remix.exeCurrent()')
.pause(1000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'file.js', 60000)
},
@ -72,7 +73,8 @@ module.exports = {
browser
.addFile('readdirFile.js', { content: executeReaddir })
.executeScript('remix.exeCurrent()')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Test_Folder isDirectory true', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Test_Folder isDirectory', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'true', 5000)
},
'Should execute `remove` api from file manager external api': function (browser: NightwatchBrowser) {
@ -175,8 +177,8 @@ const executeMkdir = `
const executeReaddir = `
const run = async () => {
const result = await remix.call('fileManager', 'readdir', '/')
console.log('Test_Folder isDirectory ', result["Test_Folder"].isDirectory)
const output = result["Test_Folder"].isDirectory
console.log('Test_Folder isDirectory ', output)
}
run()

@ -77,6 +77,7 @@ function checkDeployShouldFail (browser: NightwatchBrowser, callback: VoidFuncti
.clickLaunchIcon('udapp')
.selectContract('test') // deploy lib
.createContract('')
.pause(2000)
.getText('div[class^="terminal"]', (value) => {
console.log('value: ', value)
})

@ -164,6 +164,8 @@ module.exports = {
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
// eslint-disable-next-line dot-notation
.execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_new' })
.pause(5000)
.waitForElementPresent('*[data-id="workspacesModalDialogModalDialogModalFooter-react"] .modal-ok')
.click('*[data-id="workspacesModalDialogModalDialogModalFooter-react"] .modal-ok')
.click('*[data-id="workspacesSelect"] option[value="workspace_new"]')
// end of creating
@ -181,6 +183,7 @@ module.exports = {
.clickLaunchIcon('solidityUnitTesting')
.pause(2000)
.verify.attributeEquals('*[data-id="uiPathInput"]', 'value', 'tests')
.pause(2000)
.scrollAndClick('#runTestsTabRunAction')
.waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000)
.waitForElementPresent('#solidityUnittestsOutput div[class^="testPass"]', 60000)
@ -201,13 +204,13 @@ module.exports = {
.waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000)
.waitForElementPresent('#solidityUnittestsOutput div[class^="testPass"]', 60000)
.waitForElementContainsText('#solidityUnittestsOutput', 'tests/hhLogs_test.sol', 60000)
.assert.containsText('#journal > div:nth-child(3) > span > div', 'Before all:')
.assert.containsText('#journal > div:nth-child(3) > span > div', 'Inside beforeAll')
.assert.containsText('#journal > div:nth-child(4) > span > div', 'Check sender:')
.assert.containsText('#journal > div:nth-child(4) > span > div', 'msg.sender is 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4')
.assert.containsText('#journal > div:nth-child(5) > span > div', 'Check int logs:')
.assert.containsText('#journal > div:nth-child(5) > span > div', '10 20')
.assert.containsText('#journal > div:nth-child(5) > span > div', 'Number is 25')
.assert.containsText('#journal > div:nth-child(2) > span', 'Before all:')
.assert.containsText('#journal > div:nth-child(2) > span', 'Inside beforeAll')
.assert.containsText('#journal > div:nth-child(3) > span', 'Check sender:')
.assert.containsText('#journal > div:nth-child(3) > span', 'msg.sender is 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4')
.assert.containsText('#journal > div:nth-child(4) > span', 'Check int logs:')
.assert.containsText('#journal > div:nth-child(4) > span', '10 20')
.assert.containsText('#journal > div:nth-child(4) > span', 'Number is 25')
.openFile('tests/hhLogs_test.sol')
.removeFile('tests/hhLogs_test.sol', 'workspace_new')
},
@ -223,13 +226,13 @@ module.exports = {
.pause(2000)
.waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000)
.waitForElementContainsText('#solidityUnittestsOutput', 'tests/ballotFailedLog_test.sol', 60000)
.assert.containsText('#journal > div:nth-child(6) > span > div', 'Check winning proposal:')
.assert.containsText('#journal > div:nth-child(6) > span > div', 'Inside checkWinningProposal')
.assert.containsText('#journal > div:nth-child(5) > span', 'Check winning proposal:')
.assert.containsText('#journal > div:nth-child(5) > span', 'Inside checkWinningProposal')
.openFile('tests/ballotFailedLog_test.sol')
.removeFile('tests/ballotFailedLog_test.sol', 'workspace_new')
},
'Debug failed test using debugger': function (browser: NightwatchBrowser) {
'Debug tests using debugger': function (browser: NightwatchBrowser) {
browser
.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.addFile('tests/ballotFailedDebug_test.sol', sources[0]['tests/ballotFailedDebug_test.sol'])
@ -239,21 +242,50 @@ module.exports = {
.click('#runTestsTabRunAction')
.waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000)
.waitForElementContainsText('#solidityUnittestsOutput', 'tests/ballotFailedDebug_test.sol', 60000)
.waitForElementContainsText('#solidityUnittestsOutput', '✘ Check winning proposal', 60000)
.waitForElementContainsText('#solidityUnittestsOutput', '✘ Check winning proposal failed', 60000)
.waitForElementContainsText('#solidityUnittestsOutput', '✓ Check winning proposal passed', 60000)
.waitForElementContainsText('#solidityUnittestsOutput', '✘ Check winning proposal again', 60000)
.waitForElementContainsText('#solidityUnittestsOutput', '✓ Check winnin proposal with return value', 60000)
.click('.fa-bug')
.click('#Check_winning_proposal_failed')
.waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposal()', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalFailed()', 60000)
.click('*[data-id="dropdownPanelSolidityLocals"]')
.waitForElementContainsText('*[data-id="solidityLocals"]', 'no locals', 60000)
// eslint-disable-next-line dot-notation
.execute(function () { document.getElementById('slider')['value'] = '235' }) // It only moves slider to 235 but vm traces are not updated
.execute(function () { document.getElementById('slider')['value'] = '315' }) // It only moves slider to 315 but vm traces are not updated
.setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW))
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposal()', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalFailed()', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'vote(proposal)', 60000)
.pause(2000)
// Should be uncommented while fixing https://github.com/ethereum/remix-project/issues/1644
// .checkVariableDebug('soliditylocals', locals)
.pause(1000)
.checkVariableDebug('soliditylocals', locals)
.clickLaunchIcon('solidityUnitTesting')
.scrollAndClick('#Check_winning_proposal_passed')
.waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalPassed()', 60000)
// eslint-disable-next-line dot-notation
.execute(function () { document.getElementById('slider')['value'] = '1450' })
.setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW))
.waitForElementContainsText('*[data-id="functionPanel"]', 'equal(a, b, message)', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalPassed()', 60000)
.pause(1000)
.clickLaunchIcon('solidityUnitTesting')
.scrollAndClick('#Check_winning_proposal_again')
.waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalAgain()', 60000)
// eslint-disable-next-line dot-notation
.execute(function () { document.getElementById('slider')['value'] = '1150' })
.setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW))
.waitForElementContainsText('*[data-id="functionPanel"]', 'equal(a, b, message)', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalAgain()', 60000)
.pause(1000)
.clickLaunchIcon('solidityUnitTesting')
.scrollAndClick('#Check_winnin_proposal_with_return_value')
.waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinninProposalWithReturnValue()', 60000)
// eslint-disable-next-line dot-notation
.execute(function () { document.getElementById('slider')['value'] = '320' })
.setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW))
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinninProposalWithReturnValue()', 60000)
.clickLaunchIcon('filePanel')
.pause(2000)
.openFile('tests/ballotFailedDebug_test.sol')
@ -269,6 +301,7 @@ module.exports = {
.scrollAndClick('[data-id="pluginManagerComponentDeactivateButtonsolidityUnitTesting"]')
.pause(2000)
.scrollAndClick('[data-id="pluginManagerComponentActivateButtonsolidityUnitTesting"]')
.pause(5000)
.clickLaunchIcon('solidityUnitTesting')
.scrollAndClick('#runTestsTabRunAction')
.waitForElementVisible('*[data-id="testTabSolidityUnitTestsOutputheader"]', 120000)
@ -458,7 +491,7 @@ const sources = [
},
'tests/deployError_test.sol': {
content: `
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
contract failingDeploy {
constructor() {
@ -469,7 +502,7 @@ const sources = [
},
'tests/methodFailure_test.sol': {
content: `
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
contract methodfailure {
function add(uint a, uint b) public {
@ -496,11 +529,20 @@ const sources = [
ballotToTest = new Ballot(proposalNames);
}
function checkWinningProposal () public {
ballotToTest.vote(1); // This will revert the transaction
function checkWinningProposalFailed () public {
ballotToTest.vote(1);
Assert.equal(ballotToTest.winningProposal(), uint(0), "proposal at index 0 should be the winning proposal");
}
function checkWinningProposalPassed () public {
ballotToTest.vote(0);
Assert.equal(ballotToTest.winningProposal(), uint(0), "proposal at index 0 should be the winning proposal");
}
function checkWinningProposalAgain () public {
Assert.equal(ballotToTest.winningProposal(), uint(1), "proposal at index 0 should be the winning proposal");
}
function checkWinninProposalWithReturnValue () public view returns (bool) {
return ballotToTest.winningProposal() == 0;
}
@ -558,7 +600,7 @@ const sources = [
}
}
]
/*
const locals = {
sender: {
value: {
@ -586,4 +628,3 @@ const locals = {
type: 'uint256'
}
}
*/

@ -11,6 +11,7 @@ module.exports = {
browser
.waitForElementVisible('*[data-id="terminalCli"]', 10000)
.executeScript('console.log(1 + 1)')
.pause(2000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '2', 60000)
},
@ -30,24 +31,14 @@ module.exports = {
.assert.visible('*[data-id="autoCompletePopUpAutoCompleteItem"]')
},
'Should execute remix.help() command': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="terminalCli"]')
.executeScript('remix.help()')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'remix.loadgist(id)', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'remix.loadurl(url)', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'remix.execute(filepath)', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'remix.exeCurrent()', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'remix.help()', 60000)
},
'Async/Await Script': function (browser: NightwatchBrowser) {
browser
.addFile('asyncAwait.js', { content: asyncAwait })
.openFile('asyncAwait.js')
.executeScript('remix.execute(\'asyncAwait.js\')')
.executeScript('remix.execute("asyncAwait.js")')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Waiting Promise', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'result - Promise Resolved', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'result - ', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Promise Resolved', 60000)
},
'Call Remix File Manager from a script': function (browser: NightwatchBrowser) {
@ -62,7 +53,7 @@ module.exports = {
'Call web3.eth.getAccounts() using JavaScript VM': function (browser: NightwatchBrowser) {
browser
.executeScript('web3.eth.getAccounts()')
.waitForElementContainsText('*[data-id="terminalJournal"]', '"0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2", "0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c", "0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db", "0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB", "0x617F2E2fD72FD9D5503197092aC168c91465E7f2", "0x17F6AD8Ef982297579C203069C1DbfFE4348c372", "0x14723A09ACff6D2A60DcdF7aA4AFf308FDDC160C"', 80000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '["0x5B38Da6a701c568545dCfcB03FcB875f56beddC4","0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2","0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c","0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db","0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB","0x617F2E2fD72FD9D5503197092aC168c91465E7f2","0x17F6AD8Ef982297579C203069C1DbfFE4348c372","0x14723A09ACff6D2A60DcdF7aA4AFf308FDDC160C","0x5c6B0f7Bf3E7ce046039Bd8FABdfD3f9F5021678","0x03C6FcED478cBbC9a4FAB34eF9f40767739D1Ff7","0x1aE0EA34a72D944a8C7603FfB3eC30a6669E454C","0x0A098Eda01Ce92ff4A4CCb7A4fFFb5A43EBC70DC","0x4B0897b0513fdC7C541B6d9D7E929C4e5364D2dB","0x583031D1113aD414F02576BD6afaBfb302140225","0xdD870fA1b7C4700F2BD7f44238821C26f7392148"]', 80000)
},
'Call web3.eth.getAccounts() using Web3 Provider': function (browser: NightwatchBrowser) {
@ -72,9 +63,9 @@ module.exports = {
.click('*[data-id="settingsWeb3Mode"]')
.modalFooterOKClick()
.executeScript('web3.eth.getAccounts()')
.waitForElementContainsText('*[data-id="terminalJournal"]', '[ "', 60000) // we check if an array is present, don't need to check for the content
.waitForElementContainsText('*[data-id="terminalJournal"]', '" ]', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '", "', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '["', 60000) // we check if an array is present, don't need to check for the content
.waitForElementContainsText('*[data-id="terminalJournal"]', '"]', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '","', 60000)
},
'Call Remix File Resolver (external URL) from a script': function (browser: NightwatchBrowser) {
@ -107,6 +98,35 @@ module.exports = {
.executeScript('remix.execute(\'resolveExternalUrlAndSaveToaPath.js\')')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'abstract contract ERC20Burnable', 60000)
.openFile('.deps/github/newFile.sol')
},
'Deploy "Owner" using an ether.js script, listen to event and check event are logged in the terminal': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('settings')
.clickLaunchIcon('udapp')
.click('*[data-id="settingsVMLondonMode"]')
.click('*[data-id="terminalClearConsole"]') // clear the terminal
.clickLaunchIcon('filePanel')
.click('*[data-id="treeViewDivtreeViewItem"]') // make sure we create the file at the root folder
.addFile('deployWithEthersJs.js', { content: deployWithEthersJs })
.openFile('deployWithEthersJs.js')
.pause(1000)
.openFile('contracts/2_Owner.sol')
.clickLaunchIcon('solidity')
.click('*[data-id="compilerContainerCompileBtn"]') // compile Owner
.executeScript('remix.execute(\'deployWithEthersJs.js\')')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Contract Address:', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '0xd9145CCE52D386f254917e481eB44e9943F39138', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Deployment successful.', 60000)
.addAtAddressInstance('0xd9145CCE52D386f254917e481eB44e9943F39138', true, true)
.click('*[data-id="terminalClearConsole"]') // clear the terminal
.waitForElementPresent('*[data-id="universalDappUiContractActionWrapper"]', 60000)
.click('*[data-id="universalDappUiTitleExpander"]')
.clickFunction('changeOwner - transact (not payable)', { types: 'address newOwner', values: '0xd9145CCE52D386f254917e481eB44e9943F39138' }) // execute the "changeOwner" function
.waitForElementContainsText('*[data-id="terminalJournal"]', 'previousOwner', 60000) // check that the script is logging the event
.waitForElementContainsText('*[data-id="terminalJournal"]', '0x5B38Da6a701c568545dCfcB03FcB875f56beddC4', 60000) // check that the script is logging the event
.waitForElementContainsText('*[data-id="terminalJournal"]', 'newOwner', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '0xd9145CCE52D386f254917e481eB44e9943F39138', 60000)
.end()
}
}
@ -180,3 +200,40 @@ const resolveUrl = `
}
})()
`
const deployWithEthersJs = `
// Right click on the script name and hit "Run" to execute
(async () => {
try {
console.log('Running deployWithEthers script...')
const constructorArgs = [] // Put constructor args (if any) here for your contract
// Note that the script needs the ABI which is generated from the compilation artifact.
// Make sure contract is compiled and artifacts are generated
const artifactsPath = 'contracts/artifacts/Owner.json' // Change this for different path
const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath))
// 'web3Provider' is a remix global variable object
const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner()
let factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer);
let contract = await factory.deploy(...constructorArgs);
console.log('Contract Address: ', contract.address);
// The contract is NOT deployed yet; we must wait until it is mined
await contract.deployed()
console.log('Deployment successful.')
contract.on('OwnerSet', (previousOwner, newOwner) => {
console.log('previousOwner' , previousOwner)
console.log('newOwner' , newOwner)
})
console.log('ok')
} catch (e) {
console.log(e.message)
}
})()`

@ -147,12 +147,13 @@ module.exports = {
.waitForElementPresent('.instance:nth-of-type(3)')
.click('.instance:nth-of-type(3) > div > button')
.clickFunction('g - transact (not payable)')
.pause(5000)
.journalLastChildIncludes('Error provided by the contract:')
.journalLastChildIncludes('CustomError : error description')
.journalLastChildIncludes('Parameters:')
.journalLastChildIncludes('"value": "2",')
.journalLastChildIncludes('"value": "3",')
.journalLastChildIncludes('"value": "error_string_2",')
.journalLastChildIncludes('"value": "2"')
.journalLastChildIncludes('"value": "3"')
.journalLastChildIncludes('"value": "error_string_2"')
.journalLastChildIncludes('"documentation": "param1"')
.journalLastChildIncludes('"documentation": "param2"')
.journalLastChildIncludes('"documentation": "param3"')
@ -170,9 +171,9 @@ module.exports = {
.journalLastChildIncludes('Error provided by the contract:')
.journalLastChildIncludes('CustomError : error description')
.journalLastChildIncludes('Parameters:')
.journalLastChildIncludes('"value": "2",')
.journalLastChildIncludes('"value": "3",')
.journalLastChildIncludes('"value": "error_string_2",')
.journalLastChildIncludes('"value": "2"')
.journalLastChildIncludes('"value": "3"')
.journalLastChildIncludes('"value": "error_string_2"')
.journalLastChildIncludes('"documentation": "param1"')
.journalLastChildIncludes('"documentation": "param2"')
.journalLastChildIncludes('"documentation": "param3"')

@ -19,7 +19,7 @@ module.exports = {
browser
.pause(5000)
.refresh()
.pause(2000)
.pause(5000)
.getEditorValue((content) => {
browser.assert.ok(content.indexOf('contract Ballot {') !== -1, 'content doesn\'t include Ballot contract')
})
@ -35,19 +35,28 @@ module.exports = {
.clickLaunchIcon('filePanel')
.click('*[data-id="workspaceCreate"]') // create workspace_name
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
.waitForElementVisible('[data-id="workspacesModalDialogModalDialogModalFooter-react"] > span')
// eslint-disable-next-line dot-notation
.execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_name' })
.click('*[data-id="workspacesModalDialogModalDialogModalFooter-react"] .modal-ok')
.pause(1000)
.click('span[data-id="workspacesModalDialog-modal-footer-ok-react"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]')
.pause(1000)
.addFile('test.sol', { content: 'test' })
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtest.sol"]')
.click('*[data-id="workspaceCreate"]') // create workspace_name_1
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
// eslint-disable-next-line dot-notation
.execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_name_1' })
.click('*[data-id="workspacesModalDialogModalDialogModalFooter-react"] .modal-ok')
.waitForElementVisible('span[data-id="workspacesModalDialog-modal-footer-ok-react"]')
// eslint-disable-next-line dot-notation
.execute(function () { document.querySelector('span[data-id="workspacesModalDialog-modal-footer-ok-react"]') })
.pause(2000)
.click('span[data-id="workspacesModalDialog-modal-footer-ok-react"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]')
.pause(2000)
.waitForElementNotPresent('*[data-id="treeViewLitreeViewItemtest.sol"]')
.pause(2000)
.click('*[data-id="workspacesSelect"] option[value="workspace_name"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]')
},
@ -59,10 +68,15 @@ module.exports = {
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextRename"]')
// eslint-disable-next-line dot-notation
.execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextRename"]')['value'] = 'workspace_name_renamed' })
.click('*[data-id="workspacesModalDialogModalDialogModalFooter-react"] .modal-ok')
.pause(2000)
.waitForElementPresent('span[data-id="workspacesModalDialog-modal-footer-ok-react"]')
.click('span[data-id="workspacesModalDialog-modal-footer-ok-react"]')
.pause(2000)
.click('*[data-id="workspacesSelect"] option[value="workspace_name_1"]')
.pause(2000)
.waitForElementNotPresent('*[data-id="treeViewLitreeViewItemtest.sol"]')
.click('*[data-id="workspacesSelect"] option[value="workspace_name_renamed"]')
.pause(2000)
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtest.sol"]')
},
@ -70,8 +84,10 @@ module.exports = {
browser
.click('*[data-id="workspacesSelect"] option[value="workspace_name_1"]')
.click('*[data-id="workspaceDelete"]') // delete workspace_name_1
.waitForElementVisible('*[data-id="workspacesModalDialogModalDialogModalFooter-react"] .modal-ok')
.click('*[data-id="workspacesModalDialogModalDialogModalFooter-react"] .modal-ok')
.waitForElementVisible('[data-id="workspacesModalDialogModalDialogModalFooter-react"] > span')
.pause(2000)
.click('[data-id="workspacesModalDialogModalDialogModalFooter-react"] > span')
.pause(2000)
.waitForElementNotPresent('*[data-id="workspacesSelect"] option[value="workspace_name_1"]')
.end()
},

@ -1,6 +1,6 @@
// Merge custom command types with nightwatch types
import { NightwatchBrowser } from 'nightwatch'
/* eslint-disable no-use-before-define */
import { NightwatchBrowser } from 'nightwatch' // eslint-disable-line @typescript-eslint/no-unused-vars
declare module 'nightwatch' {
export interface NightwatchCustomCommands {

@ -287,7 +287,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
registry.put({ api: offsetToLineColumnConverter, name: 'offsettolinecolumnconverter' })
// -------------------Terminal----------------------------------------
makeUdapp(blockchain, compilersArtefacts, (domEl) => terminal.logHtml(domEl))
const terminal = new Terminal(
{ appManager, blockchain },
{
@ -299,9 +299,9 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
newpos = (newpos < height - limitDown) ? newpos : height - limitDown
return height - newpos
}
}
},
registry
)
makeUdapp(blockchain, compilersArtefacts, (domEl) => terminal.logHtml(domEl))
const contextualListener = new ContextualListener({ editor })

@ -31,7 +31,7 @@ export class MainPanel extends AbstractPanel {
render () {
return yo`
<div class=${css.pluginsContainer} data-id="mainPanelPluginsContainer">
<div class=${css.pluginsContainer} data-id="mainPanelPluginsContainer" id='mainPanelPluginsContainer-id'>
${this.view}
</div>`
}

@ -1,29 +1,24 @@
/* global Node, requestAnimationFrame */
/* global Node, requestAnimationFrame */ // eslint-disable-line
import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom'
import { RemixUiTerminal } from '@remix-ui/terminal' // eslint-disable-line
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../../../package.json'
import * as remixBleach from '../../lib/remixBleach'
const vm = require('vm')
const EventManager = require('../../lib/events')
var yo = require('yo-yo')
var javascriptserialize = require('javascript-serialize')
var jsbeautify = require('js-beautify')
var type = require('component-type')
var vm = require('vm')
var EventManager = require('../../lib/events')
const CommandInterpreterAPI = require('../../lib/cmdInterpreterAPI')
const AutoCompletePopup = require('../ui/auto-complete-popup')
var CommandInterpreterAPI = require('../../lib/cmdInterpreterAPI')
var AutoCompletePopup = require('../ui/auto-complete-popup')
var TxLogger = require('../../app/ui/txLogger')
import { CompilerImports } from '@remix-project/core-plugin' // eslint-disable-line
const globalRegistry = require('../../global/registry')
const SourceHighlighter = require('../../app/editor/sourceHighlighter')
const GistHandler = require('../../lib/gist-handler')
var csjs = require('csjs-inject')
var css = require('./styles/terminal-styles')
var KONSOLES = []
const KONSOLES = []
function register (api) { KONSOLES.push(api) }
var ghostbar = yo`<div class=${css.ghostbar} bg-secondary></div>`
const profile = {
displayName: 'Terminal',
name: 'terminal',
@ -34,77 +29,72 @@ const profile = {
}
class Terminal extends Plugin {
constructor (opts, api) {
constructor (opts, api, registry) {
super(profile)
var self = this
self.event = new EventManager()
self.blockchain = opts.blockchain
self._api = api
self._opts = opts
self.data = {
this.fileImport = new CompilerImports()
this.gistHandler = new GistHandler()
this.event = new EventManager()
this.registry = registry
this.globalRegistry = globalRegistry
this.element = document.createElement('div')
this.element.setAttribute('class', 'panel')
this.element.setAttribute('id', 'terminal-view')
this.element.setAttribute('data-id', 'terminalContainer-view')
this.eventsDecoder = this.globalRegistry.get('eventsDecoder').api
this.txListener = this.globalRegistry.get('txlistener').api
this.sourceHighlighter = new SourceHighlighter()
this._deps = {
fileManager: this.registry.get('filemanager').api,
editor: this.registry.get('editor').api,
compilersArtefacts: this.registry.get('compilersartefacts').api,
offsetToLineColumnConverter: this.registry.get('offsettolinecolumnconverter').api
}
this.commandHelp = {
'remix.loadgist(id)': 'Load a gist in the file explorer.',
'remix.loadurl(url)': 'Load the given url in the file explorer. The url can be of type github, swarm, ipfs or raw http',
'remix.execute(filepath)': 'Run the script specified by file path. If filepath is empty, script currently displayed in the editor is executed.',
'remix.exeCurrent()': 'Run the script currently displayed in the editor',
'remix.help()': 'Display this help message'
}
this.blockchain = opts.blockchain
this.vm = vm
this._api = api
this._opts = opts
this.config = registry.get('config').api
this.version = packageJson.version
this.data = {
lineLength: opts.lineLength || 80, // ????
session: [],
activeFilters: { commands: {}, input: '' },
filterFns: {}
}
self._view = { el: null, bar: null, input: null, term: null, journal: null, cli: null }
self._components = {}
self._components.cmdInterpreter = new CommandInterpreterAPI(this, null, self.blockchain)
self._components.autoCompletePopup = new AutoCompletePopup(self._opts)
self._components.autoCompletePopup.event.register('handleSelect', function (input) {
const textList = self._view.input.innerText.split(' ')
textList.pop()
textList.push(input)
self._view.input.innerText = textList
self._view.input.focus()
self.putCursor2End(self._view.input)
})
self._commands = {}
self.commands = {}
self._JOURNAL = []
self._jobs = []
self._INDEX = {}
self._INDEX.all = []
self._INDEX.allMain = []
self._INDEX.commands = {}
self._INDEX.commandsMain = {}
self.registerCommand('html', self._blocksRenderer('html'), { activate: true })
self.registerCommand('log', self._blocksRenderer('log'), { activate: true })
self.registerCommand('info', self._blocksRenderer('info'), { activate: true })
self.registerCommand('warn', self._blocksRenderer('warn'), { activate: true })
self.registerCommand('error', self._blocksRenderer('error'), { activate: true })
self.registerCommand('script', function execute (args, scopedCommands, append) {
var script = String(args[0])
self._shell(script, scopedCommands, function (error, output) {
if (error) scopedCommands.error(error)
else if (output) scopedCommands.log(output)
this._view = { el: null, bar: null, input: null, term: null, journal: null, cli: null }
this._components = {}
this._components.cmdInterpreter = new CommandInterpreterAPI(this, null, this.blockchain)
this._components.autoCompletePopup = new AutoCompletePopup(this._opts)
this._commands = {}
this.commands = {}
this._JOURNAL = []
this._jobs = []
this._INDEX = {}
this._INDEX.all = []
this._INDEX.allMain = []
this._INDEX.commands = {}
this._INDEX.commandsMain = {}
if (opts.shell) this._shell = opts.shell // ???
register(this)
this.event.register('debuggingRequested', async (hash) => {
// 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')
this.call('debugger', 'debug', hash)
})
}, { activate: true })
function basicFilter (value, query) { try { return value.indexOf(query) !== -1 } catch (e) { return false } }
self.registerFilter('log', basicFilter)
self.registerFilter('info', basicFilter)
self.registerFilter('warn', basicFilter)
self.registerFilter('error', basicFilter)
self.registerFilter('script', basicFilter)
if (opts.shell) self._shell = opts.shell // ???
register(self)
this.logHtmlResponse = []
this.logResponse = []
}
onActivation () {
this.on('scriptRunner', 'log', (msg) => {
this.commands.log.apply(this.commands, msg.data)
})
this.on('scriptRunner', 'info', (msg) => {
this.commands.info.apply(this.commands, msg.data)
})
this.on('scriptRunner', 'warn', (msg) => {
this.commands.warn.apply(this.commands, msg.data)
})
this.on('scriptRunner', 'error', (msg) => {
this.commands.error.apply(this.commands, msg.data)
})
this.renderComponent()
}
onDeactivation () {
@ -114,690 +104,43 @@ class Terminal extends Plugin {
this.off('scriptRunner', 'error')
}
log (message) {
var command = this.commands[message.type]
if (typeof command === 'function') {
if (typeof message.value === 'string' && message.type === 'html') {
var el = document.createElement('div')
el.innerHTML = remixBleach.sanitize(message.value, {
list: [
'a',
'b',
'p',
'em',
'strong',
'div',
'span',
'ul',
'li',
'ol',
'hr'
]
})
message.value = el
}
command(message.value)
};
}
logHtml (html) {
var command = this.commands.html
if (typeof command === 'function') command(html)
}
focus () {
if (this._view.input) this._view.input.focus()
}
render () {
var self = this
if (self._view.el) return self._view.el
self._view.journal = yo`<div id="journal" class=${css.journal} data-id="terminalJournal"></div>`
self._view.input = yo`
<span class=${css.input} onload=${() => { this.focus() }} onpaste=${paste} onkeydown=${change}></span>
`
self._view.input.setAttribute('spellcheck', 'false')
self._view.input.setAttribute('contenteditable', 'true')
self._view.input.setAttribute('id', 'terminalCliInput')
self._view.input.setAttribute('data-id', 'terminalCliInput')
self._view.input.innerText = '\n'
self._view.cli = yo`
<div id="terminalCli" data-id="terminalCli" class="${css.cli}" onclick=${focusinput}>
<span class=${css.prompt}>${'>'}</span>
${self._view.input}
</div>
`
self._view.icon = yo`
<i onmouseenter=${hover} onmouseleave=${hover} onmousedown=${minimize}
class="mx-2 ${css.toggleTerminal} fas fa-angle-double-down" data-id="terminalToggleIcon"></i>`
self._view.dragbar = yo`
<div onmousedown=${mousedown} class=${css.dragbarHorizontal}></div>`
self._view.pendingTxCount = yo`<div class="mx-2" title='Pending Transactions'>0</div>`
self._view.inputSearch = yo`<input
spellcheck="false"
type="text"
class="border ${css.filter} form-control"
id="searchInput"
onkeydown=${filter}
placeholder="Search with transaction hash or address"
data-id="terminalInputSearch">
</input>`
self._view.bar = yo`
<div class="${css.bar}">
${self._view.dragbar}
<div class="${css.menu} border-top border-dark bg-light" data-id="terminalToggleMenu">
${self._view.icon}
<div class="mx-2" id="clearConsole" data-id="terminalClearConsole" onclick=${clear}>
<i class="fas fa-ban" aria-hidden="true" title="Clear console"
onmouseenter=${hover} onmouseleave=${hover}></i>
</div>
${self._view.pendingTxCount}
<div class=${css.verticalLine}></div>
<div class="pt-1 h-80 mx-3 align-items-center ${css.listenOnNetwork} custom-control custom-checkbox">
<input
class="custom-control-input"
id="listenNetworkCheck"
onchange=${listenOnNetwork}
type="checkbox"
title="If checked Remix will listen on all transactions mined in the current environment and not only transactions created by you"
>
<label
class="pt-1 form-check-label custom-control-label text-nowrap""
title="If checked Remix will listen on all transactions mined in the current environment and not only transactions created by you"
for="listenNetworkCheck"
>
listen on network
</label>
</div>
<div class=${css.search}>
<i class="fas fa-search ${css.searchIcon} bg-light" aria-hidden="true"></i>
${self._view.inputSearch}
</div>
</div>
</div>
`
self._view.term = yo`
<div class="${css.terminal_container}" tabindex="-1" data-id="terminalContainer" onscroll=${throttle(reattach, 10)} onkeydown=${focusinput}>
${self._components.autoCompletePopup.render()}
<div data-id="terminalContainerDisplay" style="
position: absolute;
height: 100%;
width: 100%;
opacity: 0.1;
z-index: -1;
"></div>
<div class=${css.terminal}>
${self._view.journal}
${self._view.cli}
</div>
</div>
`
self._view.el = yo`
<div class="${css.panel}" style="height: 180px;">
${self._view.bar}
${self._view.term}
</div>
`
setInterval(async () => {
try {
self._view.pendingTxCount.innerHTML = await self.call('udapp', 'pendingTransactionsCount')
} catch (err) {}
}, 1000)
function listenOnNetwork (ev) {
self.event.trigger('listenOnNetWork', [ev.currentTarget.checked])
}
function paste (event) {
const selection = window.getSelection()
if (!selection.rangeCount) return false
event.preventDefault()
event.stopPropagation()
var clipboard = (event.clipboardData || window.clipboardData)
var text = clipboard.getData('text/plain')
text = text.replace(/[^\x20-\xFF]/gi, '') // remove non-UTF-8 characters
var temp = document.createElement('div')
temp.innerHTML = text
var textnode = document.createTextNode(temp.textContent)
selection.getRangeAt(0).insertNode(textnode)
selection.empty()
self.scroll2bottom()
placeCaretAtEnd(event.currentTarget)
}
function placeCaretAtEnd (el) {
el.focus()
var range = document.createRange()
range.selectNodeContents(el)
range.collapse(false)
var sel = window.getSelection()
sel.removeAllRanges()
sel.addRange(range)
}
function throttle (fn, wait) {
var time = Date.now()
return function debounce () {
if ((time + wait - Date.now()) < 0) {
fn.apply(this, arguments)
time = Date.now()
}
}
}
var css2 = csjs`
.anchor {
position : static;
border-top : 2px dotted blue;
height : 10px;
this.logHtmlResponse.push(html.innerText)
this.renderComponent()
this.resetLogHtml()
}
.overlay {
position : absolute;
width : 100%;
display : flex;
align-items : center;
justify-content : center;
bottom : 0;
right : 15px;
min-height : 20px;
}
.text {
z-index : 2;
color : black;
font-weight : bold;
pointer-events : none;
}
.background {
z-index : 1;
opacity : 0.8;
background-color : #a6aeba;
cursor : pointer;
}
.ul {
padding-left : 20px;
padding-bottom : 5px;
}
`
var text = yo`<div class="${css2.overlay} ${css2.text}"></div>`
var background = yo`<div class="${css2.overlay} ${css2.background}"></div>`
var placeholder = yo`<div class=${css2.anchor}>${background}${text}</div>`
var inserted = false
window.addEventListener('resize', function (event) {
self.event.trigger('resize', [])
self.event.trigger('resize', [])
})
function focusinput (event) {
if (
event.altKey ||
event.ctrlKey ||
event.metaKey ||
event.shiftKey ||
event.key === 'Down' ||
event.key === 'ArrowDown' ||
event.key === 'Up' ||
event.key === 'ArrowUp' ||
event.key === 'Left' ||
event.key === 'ArrowLeft' ||
event.key === 'Right' ||
event.key === 'ArrowRight' ||
event.key === 'Esc' ||
event.key === 'Escape'
) return
refocus()
}
function refocus () {
self._view.input.focus()
reattach({ currentTarget: self._view.term })
delete self.scroll2bottom
self.scroll2bottom()
}
function reattach (event) {
var el = event.currentTarget
var isBottomed = el.scrollHeight - el.scrollTop - el.clientHeight < 30
if (isBottomed) {
if (inserted) {
text.innerText = ''
background.onclick = undefined
if (placeholder.parentElement) self._view.journal.removeChild(placeholder)
}
inserted = false
delete self.scroll2bottom
} else {
if (!inserted) self._view.journal.appendChild(placeholder)
inserted = true
check()
if (!placeholder.nextElementSibling) {
placeholder.style.display = 'none'
} else {
placeholder.style = ''
}
self.scroll2bottom = function () {
var next = placeholder.nextElementSibling
if (next) {
placeholder.style = ''
check()
var messages = 1
while ((next = next.nextElementSibling)) messages += 1
text.innerText = `${messages} new unread log entries`
} else {
placeholder.style.display = 'none'
}
}
}
}
function check () {
var pos1 = self._view.term.offsetHeight + self._view.term.scrollTop - (self._view.el.offsetHeight * 0.15)
var pos2 = placeholder.offsetTop
if ((pos1 - pos2) > 0) {
text.style.display = 'none'
background.style.position = 'relative'
background.style.opacity = 0.3
background.style.right = 0
background.style.borderBox = 'content-box'
background.style.padding = '2px'
background.style.height = (self._view.journal.offsetHeight - (placeholder.offsetTop + placeholder.offsetHeight)) + 'px'
background.onclick = undefined
background.style.cursor = 'default'
background.style.pointerEvents = 'none'
} else {
background.style = ''
text.style = ''
background.onclick = function (event) {
placeholder.scrollIntoView()
check()
}
}
}
function hover (event) { event.currentTarget.classList.toggle(css.hover) }
function minimize (event) {
event.preventDefault()
event.stopPropagation()
if (event.button === 0) {
var classList = self._view.icon.classList
classList.toggle('fa-angle-double-down')
classList.toggle('fa-angle-double-up')
self.event.trigger('resize', [])
}
}
var filtertimeout = null
function filter (event) {
if (filtertimeout) {
clearTimeout(filtertimeout)
}
filtertimeout = setTimeout(() => {
self.updateJournal({ type: 'search', value: self._view.inputSearch.value })
self.scroll2bottom()
}, 500)
}
function clear (event) {
refocus()
self._view.journal.innerHTML = ''
}
// ----------------- resizeable ui ---------------
function mousedown (event) {
event.preventDefault()
if (event.which === 1) {
moveGhostbar(event)
document.body.appendChild(ghostbar)
document.addEventListener('mousemove', moveGhostbar)
document.addEventListener('mouseup', removeGhostbar)
document.addEventListener('keydown', cancelGhostbar)
}
}
function cancelGhostbar (event) {
if (event.keyCode === 27) {
document.body.removeChild(ghostbar)
document.removeEventListener('mousemove', moveGhostbar)
document.removeEventListener('mouseup', removeGhostbar)
document.removeEventListener('keydown', cancelGhostbar)
}
}
function moveGhostbar (event) { // @NOTE HORIZONTAL ghostbar
ghostbar.style.top = self._api.getPosition(event) + 'px'
}
function removeGhostbar (event) {
if (self._view.icon.classList.contains('fa-angle-double-up')) {
self._view.icon.classList.toggle('fa-angle-double-down')
self._view.icon.classList.toggle('fa-angle-double-up')
}
document.body.removeChild(ghostbar)
document.removeEventListener('mousemove', moveGhostbar)
document.removeEventListener('mouseup', removeGhostbar)
document.removeEventListener('keydown', cancelGhostbar)
self.event.trigger('resize', [self._api.getPosition(event)])
}
self._cmdHistory = []
self._cmdIndex = -1
self._cmdTemp = ''
var intro = yo`
<div><div> - Welcome to Remix ${packageJson.version} - </div><br>
<div>You can use this terminal to: </div>
<ul class=${css2.ul}>
<li>Check transactions details and start debugging.</li>
<li>Execute JavaScript scripts:
<br />
<i> - Input a script directly in the command line interface </i>
<br />
<i> - Select a Javascript file in the file explorer and then run \`remix.execute()\` or \`remix.exeCurrent()\` in the command line interface </i>
<br />
<i> - Right click on a JavaScript file in the file explorer and then click \`Run\` </i>
</li>
</ul>
<div>The following libraries are accessible:</div>
<ul class=${css2.ul}>
<li><a target="_blank" href="https://web3js.readthedocs.io/en/1.0/">web3 version 1.0.0</a></li>
<li><a target="_blank" href="https://docs.ethers.io">ethers.js</a> </li>
<li><a target="_blank" href="https://www.npmjs.com/package/swarmgw">swarmgw</a> </li>
<li>remix (run remix.help() for more info)</li>
</ul>
</div>
`
self._shell('remix.help()', self.commands, () => {})
self.commands.html(intro)
self._components.txLogger = new TxLogger(this, self.blockchain)
self._components.txLogger.event.register('debuggingRequested', async (hash) => {
// TODO should probably be in the run module
if (!await self._opts.appManager.isActive('debugger')) await self._opts.appManager.activatePlugin('debugger')
this.call('menuicons', 'select', 'debugger')
this.call('debugger', 'debug', hash)
})
return self._view.el
function wrapScript (script) {
const isKnownScript = ['remix.', 'git'].some(prefix => script.trim().startsWith(prefix))
if (isKnownScript) return script
return `
try {
const ret = ${script};
if (ret instanceof Promise) {
ret.then((result) => { console.log(result) }).catch((error) => { console.log(error) })
} else {
console.log(ret)
}
} catch (e) {
console.log(e.message)
}
`
}
function change (event) {
if (self._components.autoCompletePopup.handleAutoComplete(
event,
self._view.input.innerText)) return
if (self._view.input.innerText.length === 0) self._view.input.innerText += '\n'
if (event.which === 13) {
if (event.ctrlKey) { // <ctrl+enter>
self._view.input.innerText += '\n'
self.putCursor2End(self._view.input)
self.scroll2bottom()
self._components.autoCompletePopup.removeAutoComplete()
} else { // <enter>
self._cmdIndex = -1
self._cmdTemp = ''
event.preventDefault()
var script = self._view.input.innerText.trim()
self._view.input.innerText = '\n'
if (script.length) {
self._cmdHistory.unshift(script)
self.commands.script(wrapScript(script))
}
self._components.autoCompletePopup.removeAutoComplete()
}
} else if (event.which === 38) { // <arrowUp>
var len = self._cmdHistory.length
if (len === 0) return event.preventDefault()
if (self._cmdHistory.length - 1 > self._cmdIndex) {
self._cmdIndex++
}
self._view.input.innerText = self._cmdHistory[self._cmdIndex]
self.putCursor2End(self._view.input)
self.scroll2bottom()
} else if (event.which === 40) { // <arrowDown>
if (self._cmdIndex > -1) {
self._cmdIndex--
}
self._view.input.innerText = self._cmdIndex >= 0 ? self._cmdHistory[self._cmdIndex] : self._cmdTemp
self.putCursor2End(self._view.input)
self.scroll2bottom()
} else {
self._cmdTemp = self._view.input.innerText
}
}
resetLogHtml () {
this.logHtmlResponse = []
}
putCursor2End (editable) {
var range = document.createRange()
range.selectNode(editable)
var child = editable
var chars
while (child) {
if (child.lastChild) child = child.lastChild
else break
if (child.nodeType === Node.TEXT_NODE) {
chars = child.textContent.length
} else {
chars = child.innerHTML.length
}
log (message) {
this.logResponse.push(message)
this.renderComponent()
this.resetLog()
}
range.setEnd(child, chars)
var toStart = true
var toEnd = !toStart
range.collapse(toEnd)
var sel = window.getSelection()
sel.removeAllRanges()
sel.addRange(range)
editable.focus()
resetLog () {
this.logResponse = []
}
updateJournal (filterEvent) {
var self = this
var commands = self.data.activeFilters.commands
var value = filterEvent.value
if (filterEvent.type === 'select') {
commands[value] = true
if (!self._INDEX.commandsMain[value]) return
self._INDEX.commandsMain[value].forEach(item => {
item.root.steps.forEach(item => { self._JOURNAL[item.gidx] = item })
self._JOURNAL[item.gidx] = item
})
} else if (filterEvent.type === 'deselect') {
commands[value] = false
if (!self._INDEX.commandsMain[value]) return
self._INDEX.commandsMain[value].forEach(item => {
item.root.steps.forEach(item => { self._JOURNAL[item.gidx].hide = true })
self._JOURNAL[item.gidx].hide = true
})
} else if (filterEvent.type === 'search') {
if (value !== self.data.activeFilters.input) {
var query = self.data.activeFilters.input = value
var items = self._JOURNAL
for (var gidx = 0, len = items.length; gidx < len; gidx++) {
var item = items[gidx]
if (item && self.data.filterFns[item.cmd]) {
var show = query.length ? self.data.filterFns[item.cmd](item.args, query) : true
item.hide = !show
}
}
}
}
var df = document.createDocumentFragment()
self._JOURNAL.forEach(item => {
if (item && item.el && !item.hide) df.appendChild(item.el)
})
self._view.journal.innerHTML = ''
requestAnimationFrame(function updateDOM () {
self._view.journal.appendChild(df)
})
render () {
return this.element
}
_appendItem (item) {
var self = this
var { el, gidx } = item
self._JOURNAL[gidx] = item
if (!self._jobs.length) {
requestAnimationFrame(function updateTerminal () {
self._jobs.forEach(el => self._view.journal.appendChild(el))
self.scroll2bottom()
self._jobs = []
})
}
if (self.data.activeFilters.commands[item.cmd]) self._jobs.push(el)
renderComponent () {
ReactDOM.render(
<RemixUiTerminal
plugin = {this}
/>,
this.element
)
}
scroll2bottom () {
var self = this
setTimeout(function () {
self._view.term.scrollTop = self._view.term.scrollHeight
}, 0)
}
_blocksRenderer (mode) {
if (mode === 'html') {
return function logger (args, scopedCommands, append) {
if (args.length) append(args[0])
}
}
mode = {
log: 'text-info',
info: 'text-info',
warn: 'text-warning',
error: 'text-danger'
}[mode] // defaults
if (mode) {
const filterUndefined = (el) => el !== undefined && el !== null
return function logger (args, scopedCommands, append) {
var types = args.filter(filterUndefined).map(type)
var values = javascriptserialize.apply(null, args.filter(filterUndefined)).map(function (val, idx) {
if (typeof args[idx] === 'string') {
const el = document.createElement('div')
el.innerHTML = args[idx].replace(/(\r\n|\n|\r)/gm, '<br>')
val = el.children.length === 0 ? el.firstChild : el
}
if (types[idx] === 'element') val = jsbeautify.html(val)
return val
})
if (values.length) {
append(yo`<span class="${mode}" >${values}</span>`)
}
}
} else {
throw new Error('mode is not supported')
}
}
_scopeCommands (append) {
var self = this
var scopedCommands = {}
Object.keys(self.commands).forEach(function makeScopedCommand (cmd) {
var command = self._commands[cmd]
scopedCommands[cmd] = function _command () {
var args = [...arguments]
command(args, scopedCommands, el => append(cmd, args, blockify(el)))
}
})
return scopedCommands
}
registerFilter (commandName, filterFn) {
this.data.filterFns[commandName] = filterFn
}
registerCommand (name, command, opts) {
var self = this
name = String(name)
if (self._commands[name]) throw new Error(`command "${name}" exists already`)
if (typeof command !== 'function') throw new Error(`invalid command: ${command}`)
self._commands[name] = command
self._INDEX.commands[name] = []
self._INDEX.commandsMain[name] = []
self.commands[name] = function _command () {
var args = [...arguments]
var steps = []
var root = { steps, cmd: name }
var ITEM = { root, cmd: name }
root.gidx = self._INDEX.allMain.push(ITEM) - 1
root.idx = self._INDEX.commandsMain[name].push(ITEM) - 1
function append (cmd, params, el) {
var item
if (cmd) { // subcommand
item = { el, cmd, root }
} else { // command
item = ITEM
item.el = el
cmd = name
}
item.gidx = self._INDEX.all.push(item) - 1
item.idx = self._INDEX.commands[cmd].push(item) - 1
item.step = steps.push(item) - 1
item.args = params
self._appendItem(item)
}
var scopedCommands = self._scopeCommands(append)
command(args, scopedCommands, el => append(null, args, blockify(el)))
}
var help = typeof command.help === 'string' ? command.help : [
'// no help available for:',
`terminal.commands.${name}(...)`
].join('\n')
self.commands[name].toString = _ => { return help }
self.commands[name].help = help
self.data.activeFilters.commands[name] = opts && opts.activate
if (opts.filterFn) {
self.registerFilter(name, opts.filterFn)
}
return self.commands[name]
}
async _shell (script, scopedCommands, done) { // default shell
if (script.indexOf('remix:') === 0) {
return done(null, 'This type of command has been deprecated and is not functionning anymore. Please run remix.help() to list available commands.')
}
var self = this
if (script.indexOf('remix.') === 0) {
// we keep the old feature. This will basically only be called when the command is querying the "remix" object.
// for all the other case, we use the Code Executor plugin
var context = domTerminalFeatures(self, scopedCommands, self.blockchain)
try {
var cmds = vm.createContext(context)
var result = vm.runInContext(script, cmds)
return done(null, result)
} catch (error) {
return done(error.message)
}
}
try {
let result
if (script.trim().startsWith('git')) {
// result = await this.call('git', 'execute', script)
} else {
result = await this.call('scriptRunner', 'execute', script)
}
if (result) self.commands.html(yo`<pre>${result}</pre>`)
done()
} catch (error) {
done(error.message || error)
}
}
}
function domTerminalFeatures (self, scopedCommands, blockchain) {
return {
remix: self._components.cmdInterpreter
}
}
function blockify (el) { return yo`<div class="px-4 ${css.block}" data-id="block_${el.getAttribute ? el.getAttribute('id') : ''}">${el}</div>` }
module.exports = Terminal

@ -124,7 +124,11 @@ class CompileTab extends CompilerApiMixin(ViewPlugin) { // implements ICompilerA
path: [],
pattern: []
})
try {
this.currentFile = await this.call('fileManager', 'file')
} catch (error) {
if (error.message !== 'Error: No such file or directory No file selected') throw error
}
}
getCompilerParameters () {

@ -218,11 +218,12 @@ class ContractDropdownUI {
if (this.selectContractNames.value === '') this.enableAtAddress(false)
} else {
this.loadType = 'other'
this.createPanel.style.display = 'none'
this.orLabel.style.display = 'none'
this.compFails.style.display = 'none'
this.contractNamesContainer.style.display = 'none'
this.createPanel.style.display = 'block'
this.orLabel.style.display = 'block'
this.contractNamesContainer.style.display = 'block'
this.selectContractNames.style.display = 'block'
this.abiLabel.style.display = 'none'
if (this.selectContractNames.value === '') this.enableAtAddress(false)
}
}

@ -247,6 +247,14 @@ module.exports = class TestTab extends ViewPlugin {
testCallback (result, runningTests) {
this.testsOutput.hidden = false
let debugBtn = yo``
if ((result.type === 'testPass' || result.type === 'testFailure') && result.debugTxHash) {
const { web3, debugTxHash } = result
debugBtn = yo`<div id=${result.value.replaceAll(' ', '_')} class="btn border btn btn-sm ml-1" title="Start debugging" onclick=${() => this.startDebug(debugTxHash, web3)}>
<i class="fas fa-bug"></i>
</div>`
debugBtn.style.cursor = 'pointer'
}
if (result.type === 'contract') {
this.testSuite = result.value
if (this.testSuites) {
@ -268,29 +276,18 @@ module.exports = class TestTab extends ViewPlugin {
<div
id="${this.runningTestFileName}"
data-id="testTabSolidityUnitTestsOutputheader"
class="${css.testPass} ${css.testLog} bg-light mb-2 text-success border-0"
class="${css.testPass} ${css.testLog} bg-light mb-2 px-2 text-success border-0"
onclick=${() => this.discardHighlight()}
>
${result.value}
<div class="d-flex my-1 align-items-start justify-content-between">
<span style="margin-block: auto" > ${result.value}</span>
${debugBtn}
</div>
</div>
`)
} else if (result.type === 'testFailure') {
if (result.hhLogs && result.hhLogs.length) this.printHHLogs(result.hhLogs, result.value)
if (!result.assertMethod) {
let debugBtn = yo``
if (result.errMsg.includes('Transaction has been reverted by the EVM')) {
const txHash = JSON.parse(result.errMsg.replace('Transaction has been reverted by the EVM:', '')).transactionHash
const { web3 } = result
debugBtn = yo`<div
class="btn border btn btn-sm ml-1"
title="Start debugging"
onclick=${() => this.startDebug(txHash, web3)}
>
<i class="fas fa-bug"></i>
</div>`
debugBtn.style.visibility = 'visible'
debugBtn.style.cursor = 'pointer'
} else debugBtn.style.visibility = 'hidden'
this.testsOutput.appendChild(yo`
<div
class="bg-light mb-2 px-2 ${css.testLog} d-flex flex-column text-danger border-0"
@ -315,7 +312,10 @@ module.exports = class TestTab extends ViewPlugin {
id="UTContext${result.context}"
onclick=${() => this.highlightLocation(result.location, runningTests, result.filename)}
>
<div class="d-flex my-1 align-items-start justify-content-between">
<span> ${result.value}</span>
${debugBtn}
</div>
<span class="text-dark">Error Message:</span>
<span class="pb-2 text-break">"${result.errMsg}"</span>
<span class="text-dark">Assertion:</span>
@ -499,7 +499,7 @@ module.exports = class TestTab extends ViewPlugin {
usingWorker: canUseWorker(currentVersion),
runs
}
this.testRunner.runTestSources(runningTest, compilerConfig, () => {}, () => {}, (error, result) => {
this.testRunner.runTestSources(runningTest, compilerConfig, () => {}, () => {}, null, (error, result) => {
if (error) return reject(error)
resolve(result)
}, (url, cb) => {
@ -527,17 +527,22 @@ module.exports = class TestTab extends ViewPlugin {
usingWorker: canUseWorker(currentVersion),
runs
}
const deployCb = async (file, contractAddress) => {
const compilerData = await this.call('compilerArtefacts', 'getCompilerAbstract', file)
await this.call('compilerArtefacts', 'addResolvedContract', contractAddress, compilerData)
}
this.testRunner.runTestSources(
runningTests,
compilerConfig,
(result) => this.testCallback(result, runningTests),
(_err, result, cb) => this.resultsCallback(_err, result, cb),
deployCb,
(error, result) => {
this.updateFinalResult(error, result, testFilePath)
callback(error)
}, (url, cb) => {
return this.contentImport.resolveAndSave(url).then((result) => cb(null, result)).catch((error) => cb(error.message))
}
}, { testFilePath }
)
}).catch((error) => {
if (error) return // eslint-disable-line

@ -76,7 +76,6 @@ export class ExecutionContext {
if (err) name = 'Unknown'
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
else if (id === 1) name = 'Main'
else if (id === 2) name = 'Morden (deprecated)'
else if (id === 3) name = 'Ropsten'
else if (id === 4) name = 'Rinkeby'
else if (id === 5) name = 'Goerli'

@ -93,7 +93,6 @@ class CmdInterpreterAPI {
if (cb) cb()
return
}
self._components.terminal.commands.script(content)
}

@ -30,7 +30,6 @@ const defaultCompilerParameters = {
evmVersion: null, // compiler default
language: 'Solidity'
}
export class CompilerClientApi extends CompilerApiMixin(PluginClient) implements ICompilerApi {
constructor () {
super()

@ -1,9 +1,9 @@
const nxWebpack = require('@nrwl/react/plugins/webpack')
const TerserPlugin = require('terser-webpack-plugin')
module.exports = config => {
const nxWebpackConfig = nxWebpack(config)
return {
const webpackConfig = {
...nxWebpackConfig,
node: {
fs: 'empty',
@ -14,4 +14,18 @@ module.exports = config => {
child_process: 'empty'
}
}
if (process.env.NODE_ENV === 'production') {
return {
...webpackConfig,
mode: 'production',
devtool: 'source-map',
optimization: {
minimize: true,
minimizer: [new TerserPlugin()]
}
}
} else {
return webpackConfig
}
}

@ -4,7 +4,8 @@
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "off",
"no-unused-vars": "off",
"dot-notation": "off"
"dot-notation": "off",
"no-use-before-define": "off"
},
"ignorePatterns": ["!**/*"]
}

@ -19,9 +19,9 @@
}
],
"dependencies": {
"@ethereumjs/block": "^3.4.0",
"@ethereumjs/tx": "^3.3.0",
"@ethereumjs/vm": "^5.5.0",
"@ethereumjs/block": "^3.5.1",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-astwalker": "^0.0.37",
"@remix-project/remix-lib": "^0.5.7",
"async": "^2.6.2",

@ -3,7 +3,8 @@
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/prefer-namespace-keyword": "off",
"no-unused-vars": "off"
"no-unused-vars": "off",
"no-use-before-define": "off"
},
"ignorePatterns": ["!**/*"]
}

@ -34,9 +34,9 @@
]
},
"dependencies": {
"@ethereumjs/block": "^3.4.0",
"@ethereumjs/tx": "^3.3.0",
"@ethereumjs/vm": "^5.5.0",
"@ethereumjs/block": "^3.5.1",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.7",
"@types/tape": "^4.2.33",
"async": "^2.6.2",

@ -39,6 +39,7 @@ export function isYulAstNode (node: Record<string, unknown>): boolean {
* in each case, if the event emits false it does not descend into children.
* If no event for the current type, children are visited.
*/
// eslint-disable-next-line no-redeclare
export class AstWalker extends EventEmitter {
manageCallback (
node: AstNode,

@ -58,6 +58,7 @@ export function sourceLocationFromSrc (src: string): Location {
* Routines for retrieving solc AST object(s) using some criteria, usually
* includng "src' information.
*/
// eslint-disable-next-line no-redeclare
export class SourceMappings {
readonly source: string;
readonly lineBreaks: Array<number>;

@ -4,7 +4,7 @@ import { CompilerAbstract } from '@remix-project/remix-solidity'
const profile = {
name: 'compilerArtefacts',
methods: ['get', 'addResolvedContract'],
methods: ['get', 'addResolvedContract', 'getCompilerAbstract'],
events: [],
version: '0.0.1'
}

@ -18,12 +18,13 @@
],
"main": "src/index.js",
"dependencies": {
"@ethereumjs/block": "^3.4.0",
"@ethereumjs/common": "^2.2.0",
"@ethereumjs/tx": "^3.3.0",
"@ethereumjs/vm": "^5.5.0",
"@ethereumjs/block": "^3.5.1",
"@ethereumjs/common": "^2.5.0",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-astwalker": "^0.0.37",
"@remix-project/remix-lib": "^0.5.7",
"@remix-project/remix-simulator": "^0.2.7",
"async": "^2.6.2",
"commander": "^2.19.0",
"deep-equal": "^1.0.1",

@ -133,7 +133,7 @@ export class StorageResolver {
resolve([{}, null])
} else {
this.web3.debug.storageRangeAt(
tx.blockHash, tx.transactionIndex === undefined ? tx.hash : tx.transactionIndex,
tx.blockHash, tx.hash,
address,
start,
maxSize,

@ -7,7 +7,6 @@ import { BreakpointManager } from '../src/code/breakpointManager'
var compiler = require('solc')
var vmCall = require('./vmCall')
var remixLib = require('@remix-project/remix-lib')
var ballot = `pragma solidity >=0.4.22 <0.8.0;
@ -151,19 +150,17 @@ contract Ballot {
`;
(async () => {
var privateKey = Buffer.from('dae9801649ba2d95a21e688b56f77905e5667c44ce868ec83f82e838712a2c7a', 'hex')
var vm = await vmCall.initVM(privateKey)
var privateKey = Buffer.from('503f38a9c967ed597e47fe25643985f032b072db8075426a92110f82df48dfcb', 'hex')
var output = compiler.compile(compilerInput(ballot))
output = JSON.parse(output)
var web3VM = new remixLib.vm.Web3VMProvider()
web3VM.setVM(vm)
const param = '0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000148656c6c6f20576f726c64210000000000000000000000000000000000000000'
vmCall.sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, output.contracts['test.sol']['Ballot'].evm.bytecode.object + param, (error, txHash) => {
console.log(error, txHash)
const web3 = await vmCall.getWeb3()
vmCall.sendTx(web3, {nonce: 0, privateKey: privateKey}, null, 0, output.contracts['test.sol']['Ballot'].evm.bytecode.object + param, (error, hash) => {
console.log(error, hash)
if (error) {
throw error
} else {
web3VM.eth.getTransaction(txHash, (error, tx) => {
web3.eth.getTransaction(hash, (error, tx) => {
if (error) {
throw error
} else {
@ -171,7 +168,7 @@ contract Ballot {
compilationResult: function () {
return { data: output }
},
web3: web3VM
web3: web3
})
debugManager.callTree.event.register('callTreeReady', () => {
@ -230,7 +227,7 @@ function testDebugging (debugManager) {
var storageView = debugManager.storageViewAt(196, address)
storageView.storageRange().then((storage) => {
t.equal(JSON.stringify(storage), JSON.stringify({ '0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563': { key: '0x0000000000000000000000000000000000000000000000000000000000000000', value: '0x0000000000000000000000004b0897b0513fdc7c541b6d9d7e929c4e5364d2db' } }))
t.equal(JSON.stringify(storage), JSON.stringify({ '0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563': { key: '0x0000000000000000000000000000000000000000000000000000000000000000', value: '0x0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4' } }))
}).catch((error) => {
if (error) return t.end(error)
})
@ -245,7 +242,7 @@ function testDebugging (debugManager) {
const state = await debugManager.extractStateAt(312)
const decodedState = await debugManager.decodeStateAt(312, state)
console.log(decodedState)
t.equal(decodedState['chairperson'].value, '0x4B0897B0513FDC7C541B6D9D7E929C4E5364D2DB')
t.equal(decodedState['chairperson'].value, '0x5B38DA6A701C568545DCFCB03FCB875F56BEDDC4')
t.equal(decodedState['chairperson'].type, 'address')
t.equal(decodedState['proposals'].value[0].value.voteCount.value, '0')
t.equal(decodedState['proposals'].value[0].value.voteCount.type, 'uint256')
@ -259,13 +256,14 @@ function testDebugging (debugManager) {
tape('traceManager.decodeLocalsAt', async (t) => {
t.plan(1)
const tested = JSON.parse('{"proposalNames":{"value":[{"value":"0x48656C6C6F20576F726C64210000000000000000000000000000000000000000","type":"bytes32"}],"length":"0x1","type":"bytes32[]","cursor":1,"hasNext":false},"p":{"value":"45","type":"uint256"},"addressLocal":{"value":"0x4B0897B0513FDC7C541B6D9D7E929C4E5364D2DB","type":"address"},"i":{"value":"2","type":"uint256"},"proposalsLocals":{"value":[{"value":{"name":{"value":"0x48656C6C6F20576F726C64210000000000000000000000000000000000000000","type":"bytes32"},"voteCount":{"value":"0","type":"uint256"}},"type":"struct Ballot.Proposal"}],"length":"0x1","type":"struct Ballot.Proposal[]"}}')
const tested = JSON.parse('{"proposalNames":{"value":[{"value":"0x48656C6C6F20576F726C64210000000000000000000000000000000000000000","type":"bytes32"}],"length":"0x1","type":"bytes32[]","cursor":1,"hasNext":false},"p":{"value":"45","type":"uint256"},"addressLocal":{"value":"0x5B38DA6A701C568545DCFCB03FCB875F56BEDDC4","type":"address"},"i":{"value":"2","type":"uint256"},"proposalsLocals":{"value":[{"value":{"name":{"value":"0x48656C6C6F20576F726C64210000000000000000000000000000000000000000","type":"bytes32"},"voteCount":{"value":"0","type":"uint256"}},"type":"struct Ballot.Proposal"}],"length":"0x1","type":"struct Ballot.Proposal[]"}}')
try {
const address = debugManager.traceManager.getCurrentCalledAddressAt(327)
const location = await debugManager.sourceLocationFromVMTraceIndex(address, 327)
debugManager.decodeLocalsAt(327, location, (error, decodedlocals) => {
if (error) return t.end(error)
t.ok(deepequal(decodedlocals, tested), `locals does not match. expected: ${JSON.stringify(tested)} - current: ${decodedlocals}`)
const res = deepequal(decodedlocals, tested)
t.ok(res, `test if locals does match. expected: ${JSON.stringify(tested)} - current: ${JSON.stringify(decodedlocals)}`)
})
} catch (error) {
return t.end(error)

@ -5,7 +5,7 @@ var intLocal = require('./contracts/intLocal')
var miscLocal = require('./contracts/miscLocal')
var structArrayLocal = require('./contracts/structArrayLocal')
var calldataLocal = require('./contracts/calldata')
var vmCall = require('./vmCall')
var vmCall = require('../vmCall')
var intLocalTest = require('./localsTests/int')
var miscLocalTest = require('./localsTests/misc')
var misc2LocalTest = require('./localsTests/misc2')
@ -15,29 +15,28 @@ var compilerInput = require('../helpers/compilerHelper').compilerInput
tape('solidity', function (t) {
t.test('local decoder', async function (st) {
var privateKey = Buffer.from('dae9801649ba2d95a21e688b56f77905e5667c44ce868ec83f82e838712a2c7a', 'hex')
var vm = await vmCall.initVM(st, privateKey)
await test(st, vm, privateKey)
var privateKey = Buffer.from('503f38a9c967ed597e47fe25643985f032b072db8075426a92110f82df48dfcb', 'hex')
await test(st, privateKey)
})
})
async function test (st, vm, privateKey) {
async function test (st, privateKey) {
var output = compiler.compile(compilerInput(intLocal.contract))
output = JSON.parse(output)
await intLocalTest(st, vm, privateKey, output.contracts['test.sol']['intLocal'].evm.bytecode.object, output)
await intLocalTest(st, privateKey, output.contracts['test.sol']['intLocal'].evm.bytecode.object, output)
output = compiler.compile(compilerInput(miscLocal.contract))
output = JSON.parse(output)
await miscLocalTest(st, vm, privateKey, output.contracts['test.sol']['miscLocal'].evm.bytecode.object, output)
await miscLocalTest(st, privateKey, output.contracts['test.sol']['miscLocal'].evm.bytecode.object, output)
output = compiler.compile(compilerInput(miscLocal.contract))
output = JSON.parse(output)
await misc2LocalTest(st, vm, privateKey, output.contracts['test.sol']['miscLocal2'].evm.bytecode.object, output)
await misc2LocalTest(st, privateKey, output.contracts['test.sol']['miscLocal2'].evm.bytecode.object, output)
output = compiler.compile(compilerInput(structArrayLocal.contract))
output = JSON.parse(output)
await structArrayLocalTest(st, vm, privateKey, output.contracts['test.sol']['structArrayLocal'].evm.bytecode.object, output)
await structArrayLocalTest(st, privateKey, output.contracts['test.sol']['structArrayLocal'].evm.bytecode.object, output)
output = compiler.compile(compilerInput(calldataLocal.contract))
output = JSON.parse(output)
await calldataLocalTest(st, vm, privateKey, output.contracts['test.sol']['calldataLocal'].evm.bytecode.object, output)
await calldataLocalTest(st, privateKey, output.contracts['test.sol']['calldataLocal'].evm.bytecode.object, output)
st.end()
}

@ -1,7 +1,7 @@
'use strict'
import deepequal from 'deep-equal'
import { sendTx } from '../vmCall'
import * as vmCall from '../../vmCall'
import { TraceManager } from '../../../src/trace/traceManager'
import { CodeManager } from '../../../src/code/codeManager'
import { SolidityProxy } from '../../../src/solidity-decoder/solidityProxy'
@ -9,23 +9,26 @@ import { InternalCallTree } from '../../../src/solidity-decoder/internalCallTree
import { EventManager } from '../../../src/eventManager'
import * as helper from './helper'
module.exports = async function (st, vm, privateKey, contractBytecode, compilationResult) {
module.exports = async function (st, privateKey, contractBytecode, compilationResult) {
let txHash
let web3
try {
let data = await sendTx(vm, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode)
const to = (data as any).result.createdAddress.toString()
web3 = await (vmCall as any).getWeb3()
let hash = await (vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode)
const receipt = await web3.eth.getTransactionReceipt(hash)
const to = receipt.contractAddress
console.log('to', to)
// call to level11
data = await sendTx(vm, { nonce: 1, privateKey: privateKey }, to, 0, 'a372a595000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000000')
txHash = (data as any).hash
txHash = await (vmCall as any).sendTx(web3, { nonce: 1, privateKey: privateKey }, to, 0, 'a372a595000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000000')
} catch (e) {
return st.fail(e)
}
return new Promise((resolve) => {
vm.web3.eth.getTransaction(txHash, function (error, tx) {
web3.eth.getTransaction(txHash, function (error, tx) {
if (error) {
return st.fail(error)
}
var traceManager = new TraceManager({ web3: vm.web3 })
var traceManager = new TraceManager({ web3 })
var codeManager = new CodeManager(traceManager)
codeManager.clear()
var solidityProxy = new SolidityProxy({ getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), getCode: codeManager.getCode.bind(codeManager) })

@ -1,6 +1,6 @@
'use strict'
import { sendTx } from '../vmCall'
import * as vmCall from '../../vmCall'
import { TraceManager } from '../../../src/trace/traceManager'
import { CodeManager } from '../../../src/code/codeManager'
import { contractCreationToken } from '../../../src/trace/traceHelper'
@ -9,19 +9,19 @@ import { InternalCallTree } from '../../../src/solidity-decoder/internalCallTree
import { EventManager } from '../../../src/eventManager'
import * as helper from './helper'
module.exports = function (st, vm, privateKey, contractBytecode, compilationResult) {
return new Promise((resolve) => {
sendTx(vm, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode, function (error, data) {
module.exports = function (st, privateKey, contractBytecode, compilationResult) {
return new Promise(async (resolve) => {
let web3 = await (vmCall as any).getWeb3();
(vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode, function (error, hash) {
if (error) {
return st.fail(error)
}
const txHash = data.hash
vm.web3.eth.getTransaction(txHash, function (error, tx) {
web3.eth.getTransaction(hash, function (error, tx) {
if (error) {
return st.fail(error)
}
tx.to = contractCreationToken('0')
var traceManager = new TraceManager({ web3: vm.web3 })
var traceManager = new TraceManager({ web3 })
var codeManager = new CodeManager(traceManager)
codeManager.clear()
var solidityProxy = new SolidityProxy({ getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), getCode: codeManager.getCode.bind(codeManager) })

@ -1,5 +1,5 @@
'use strict'
import { sendTx } from '../vmCall'
import * as vmCall from '../../vmCall'
import { contractCreationToken } from '../../../src/trace/traceHelper'
import { SolidityProxy } from '../../../src/solidity-decoder/solidityProxy'
import { InternalCallTree } from '../../../src/solidity-decoder/internalCallTree'
@ -8,19 +8,19 @@ import * as helper from './helper'
import { TraceManager } from '../../../src/trace/traceManager'
import { CodeManager } from '../../../src/code/codeManager'
module.exports = function (st, vm, privateKey, contractBytecode, compilationResult) {
return new Promise((resolve) => {
sendTx(vm, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode, function (error, data) {
module.exports = function (st, privateKey, contractBytecode, compilationResult) {
return new Promise(async (resolve) => {
const web3 = await (vmCall as any).getWeb3();
(vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode, function (error, hash) {
if (error) {
return st.fail(error)
}
const txHash = data.hash
vm.web3.eth.getTransaction(txHash, function (error, tx) {
web3.eth.getTransaction(hash, function (error, tx) {
if (error) {
return st.fail(error)
}
tx.to = contractCreationToken('0')
var traceManager = new TraceManager({ web3: vm.web3 })
var traceManager = new TraceManager({ web3 })
var codeManager = new CodeManager(traceManager)
codeManager.clear()
var solidityProxy = new SolidityProxy({ getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), getCode: codeManager.getCode.bind(codeManager) })
@ -36,7 +36,7 @@ module.exports = function (st, vm, privateKey, contractBytecode, compilationResu
st.equals(locals['boolFalse'].value, false)
st.equals(locals['boolTrue'].value, true)
st.equals(locals['testEnum'].value, 'three')
st.equals(locals['sender'].value, '0x4B0897B0513FDC7C541B6D9D7E929C4E5364D2DB')
st.equals(locals['sender'].value, '0x5B38DA6A701C568545DCFCB03FCB875F56BEDDC4')
st.equals(locals['_bytes1'].value, '0x99')
st.equals(locals['__bytes1'].value, '0x99')
st.equals(locals['__bytes2'].value, '0x99AB')

@ -1,5 +1,5 @@
'use strict'
import { sendTx } from '../vmCall'
import * as vmCall from '../../vmCall'
import { contractCreationToken } from '../../../src/trace/traceHelper'
import { SolidityProxy } from '../../../src/solidity-decoder/solidityProxy'
import { InternalCallTree } from '../../../src/solidity-decoder/internalCallTree'
@ -8,19 +8,19 @@ import * as helper from './helper'
import { TraceManager } from '../../../src/trace/traceManager'
import { CodeManager } from '../../../src/code/codeManager'
module.exports = function (st, vm, privateKey, contractBytecode, compilationResult) {
return new Promise((resolve) => {
sendTx(vm, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode, function (error, data) {
module.exports = function (st, privateKey, contractBytecode, compilationResult) {
return new Promise(async (resolve) => {
const web3 = await (vmCall as any).getWeb3();
(vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode, function (error, hash) {
if (error) {
return st.fail(error)
}
const txHash = data.hash
vm.web3.eth.getTransaction(txHash, function (error, tx) {
web3.eth.getTransaction(hash, function (error, tx) {
if (error) {
return st.fail(error)
}
tx.to = contractCreationToken('0')
var traceManager = new TraceManager({ web3: vm.web3 })
var traceManager = new TraceManager({ web3 })
var codeManager = new CodeManager(traceManager)
codeManager.clear()
var solidityProxy = new SolidityProxy({ getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), getCode: codeManager.getCode.bind(codeManager) })

@ -1,5 +1,5 @@
'use strict'
import { sendTx } from '../vmCall'
import * as vmCall from '../../vmCall'
import { contractCreationToken } from '../../../src/trace/traceHelper'
import { SolidityProxy } from '../../../src/solidity-decoder/solidityProxy'
import { InternalCallTree } from '../../../src/solidity-decoder/internalCallTree'
@ -8,19 +8,19 @@ import * as helper from './helper'
import { TraceManager } from '../../../src/trace/traceManager'
import { CodeManager } from '../../../src/code/codeManager'
module.exports = function (st, vm, privateKey, contractBytecode, compilationResult) {
return new Promise((resolve) => {
sendTx(vm, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode, function (error, data) {
module.exports = function (st, privateKey, contractBytecode, compilationResult) {
return new Promise(async (resolve) => {
const web3 = await (vmCall as any).getWeb3();
(vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode, function (error, hash) {
if (error) {
return st.fail(error)
}
const txHash = data.hash
vm.web3.eth.getTransaction(txHash, function (error, tx) {
web3.eth.getTransaction(hash, function (error, tx) {
if (error) {
return st.fail(error)
}
tx.to = contractCreationToken('0')
var traceManager = new TraceManager({ web3: vm.web3 })
var traceManager = new TraceManager({ web3 })
var codeManager = new CodeManager(traceManager)
codeManager.clear()
var solidityProxy = new SolidityProxy({ getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), getCode: codeManager.getCode.bind(codeManager) })

@ -2,57 +2,59 @@ import { compilerInput } from '../../helpers/compilerHelper'
import { TraceManager } from '../../../src/trace/traceManager'
import { compile } from 'solc'
import * as stateDecoder from '../../../src/solidity-decoder/stateDecoder'
import { sendTx, initVM } from '../vmCall'
import * as vmCall from '../../vmCall'
import { StorageResolver } from '../../../src/storage/storageResolver'
import { StorageViewer } from '../../../src/storage/storageViewer'
import { Address, bufferToHex } from 'ethereumjs-util'
module.exports = async function testMappingStorage (st, cb) {
var mappingStorage = require('../contracts/mappingStorage')
var privateKey = Buffer.from('dae9801649ba2d95a21e688b56f77905e5667c44ce868ec83f82e838712a2c7a', 'hex')
var vm = await initVM(st, privateKey)
var privateKey = Buffer.from('503f38a9c967ed597e47fe25643985f032b072db8075426a92110f82df48dfcb', 'hex')
var output = compile(compilerInput(mappingStorage.contract))
output = JSON.parse(output)
sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, output.contracts['test.sol']['SimpleMappingState'].evm.bytecode.object, function (error, data) {
output = JSON.parse(output);
const web3 = await (vmCall as any).getWeb3();
(vmCall as any).sendTx(web3, {nonce: 0, privateKey: privateKey}, null, 0, output.contracts['test.sol']['SimpleMappingState'].evm.bytecode.object, function (error, hash) {
if (error) {
console.log(error)
st.end(error)
} else {
const txHash = data.hash
vm.web3.eth.getTransaction(txHash, (error, tx) => {
web3.eth.getTransactionReceipt(hash, (error, tx) => {
if (error) {
console.log(error)
st.end(error)
} else {
testMapping(st, vm, privateKey, tx.contractAddress, output, cb)
// const storage = await this.vm.stateManager.dumpStorage(data.to)
// (vmCall as any).web3().eth.getCode(tx.contractAddress).then((code) => console.log('code:', code))
// (vmCall as any).web3().debug.traceTransaction(hash).then((code) => console.log('trace:', code))
testMapping(st, privateKey, tx.contractAddress, output, web3, cb)
// st.end()
}
})
}
})
}
function testMapping (st, vm, privateKey, contractAddress, output, cb) {
sendTx(vm, {nonce: 1, privateKey: privateKey}, contractAddress, 0, '2fd0a83a00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001074686973206973206120737472696e6700000000000000000000000000000000',
function (error, data) {
function testMapping (st, privateKey, contractAddress, output, web3, cb) {
(vmCall as any).sendTx(web3, {nonce: 1, privateKey: privateKey}, contractAddress, 0, '2fd0a83a00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001074686973206973206120737472696e6700000000000000000000000000000000',
function (error, hash) {
if (error) {
console.log(error)
st.end(error)
} else {
const txHash = data.hash
vm.web3.eth.getTransaction(txHash, (error, tx) => {
web3.eth.getTransaction(hash, (error, tx) => {
if (error) {
console.log(error)
st.end(error)
} else {
var traceManager = new TraceManager({web3: vm.web3})
var traceManager = new TraceManager({web3})
traceManager.resolveTrace(tx).then(() => {
var storageViewer = new StorageViewer({
stepIndex: 268,
tx: tx,
address: contractAddress
}, new StorageResolver({web3: vm.web3}), traceManager)
}, new StorageResolver({web3}), traceManager)
var stateVars = stateDecoder.extractStateVariables('SimpleMappingState', output.sources)
stateDecoder.decodeState(stateVars, storageViewer).then((result) => {
console.log('ok', JSON.stringify(result))
st.equal(result['_num'].value, '1')
st.equal(result['_num'].type, 'uint256')
st.equal(result['_iBreakSolidityState'].type, 'mapping(string => uint256)')

@ -1,76 +0,0 @@
'use strict'
import { Transaction as Tx } from '@ethereumjs/tx'
import { Block } from '@ethereumjs/block'
import { BN, bufferToHex, Address } from 'ethereumjs-util'
import { vm as remixlibVM } from '@remix-project/remix-lib'
import VM from '@ethereumjs/vm'
import Common from '@ethereumjs/common'
export function sendTx (vm, from, to, value, data, cb?) {
cb = cb || (() => {})
return new Promise ((resolve, reject) => {
var tx = new Tx({
nonce: new BN(from.nonce++),
// gasPrice: new BN(1),
gasLimit: new BN(3000000, 10),
to: to,
value: new BN(value, 10),
data: Buffer.from(data, 'hex')
})
tx = tx.sign(from.privateKey)
var block = Block.fromBlockData({
header: {
timestamp: new Date().getTime() / 1000 | 0,
number: 0
}
}) // still using default common
try {
vm.runTx({block: block, tx: tx, skipBalance: true, skipNonce: true}).then(function (result) {
setTimeout(() => {
const hash = bufferToHex(tx.hash())
cb(null, { hash, result })
resolve({ hash, result })
}, 500)
}).catch((error) => {
console.error(error)
cb(error)
reject(error)
})
} catch (e) {
console.error(e)
}
})
}
async function createVm (hardfork) {
const common = new Common({ chain: 'mainnet', hardfork })
const vm = new VM({ common })
await vm.init()
return { vm, stateManager: vm.stateManager }
}
/*
Init VM / Send Transaction
*/
export async function initVM (st, privateKey) {
var VM = await createVm('berlin')
const vm = VM.vm
var address = Address.fromPrivateKey(privateKey)
try {
let account = await vm.stateManager.getAccount(address)
account.balance = new BN('f00000000000000001', 16)
await vm.stateManager.putAccount(address, account)
} catch (error) {
console.log(error)
}
var web3Provider = new remixlibVM.Web3VMProvider()
web3Provider.setVM(vm)
vm.web3 = web3Provider
return vm
}

@ -1,5 +1,5 @@
'use strict'
require('./vmCall')
require('./traceManager')
require('./codeManager')
require('./disassembler')

@ -1,63 +1,44 @@
'use strict'
import { Block } from '@ethereumjs/block'
import { Transaction } from '@ethereumjs/tx'
import VM from '@ethereumjs/vm'
import { rlp, keccak, bufferToHex } from 'ethereumjs-util'
import { extendWeb3 } from '../src/init'
var utileth = require('ethereumjs-util')
var Tx = require('@ethereumjs/tx').Transaction
var BN = require('ethereumjs-util').BN
var remixLib = require('@remix-project/remix-lib')
const { Provider, extend } = require('@remix-project/remix-simulator')
const Web3 = require('web3')
function sendTx (vm, from, to, value, data, cb) {
var tx = new Tx({
nonce: new BN(from.nonce++),
// gasPrice: new BN(1),
gasLimit: new BN(3000000, 10),
to: to,
value: new BN(value, 10),
data: Buffer.from(data, 'hex')
})
tx = tx.sign(from.privateKey)
var block = Block.fromBlockData({
header: {
timestamp: new Date().getTime() / 1000 | 0,
number: 0
}
}) // still using default common
vm.runTx({block: block, tx: tx, skipBalance: true, skipNonce: true}).then(function (result) {
setTimeout(() => {
cb(null, utileth.bufferToHex(tx.hash()))
}, 500)
}).catch((error) => {
console.error(error)
cb(error)
})
async function getWeb3 () {
const remixSimulatorProvider = new Provider({ fork: 'berlin' })
await remixSimulatorProvider.init()
await remixSimulatorProvider.Accounts.resetAccounts()
const web3 = new Web3(remixSimulatorProvider)
extendWeb3(web3)
return web3
}
/*
Init VM / Send Transaction
*/
async function initVM (privateKey) {
var address = utileth.Address.fromPrivateKey(privateKey)
var vm = new VM({
activatePrecompiles: true
})
await vm.init()
async function sendTx (web3, from, to, value, data, cb) {
try {
let account = await vm.stateManager.getAccount(address)
account.balance = new BN('f00000000000000001', 16)
await vm.stateManager.putAccount(address, account)
} catch (error) {
console.log(error)
cb = cb || (() => {})
const receipt = await web3.eth.sendTransaction({
from: utileth.Address.fromPrivateKey(from.privateKey).toString('hex'),
to,
value,
data,
gas: 7000000
})
cb(null, receipt.transactionHash)
return receipt.transactionHash
} catch (e) {
cb(e)
}
var web3Provider = new remixLib.vm.Web3VMProvider()
web3Provider.setVM(vm)
vm.web3 = web3Provider
return vm
}
module.exports = {
sendTx: sendTx,
initVM: initVM
sendTx,
getWeb3
}

@ -3,7 +3,8 @@
"rules": {
"standard/no-callback-literal": "off",
"no-unused-vars": "off",
"dot-notation": "off"
"dot-notation": "off",
"no-use-before-define": "off"
},
"env": {
"browser": true,

@ -14,9 +14,9 @@
],
"main": "src/index.js",
"dependencies": {
"@ethereumjs/block": "^3.4.0",
"@ethereumjs/tx": "^3.3.0",
"@ethereumjs/vm": "^5.5.0",
"@ethereumjs/block": "^3.5.1",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"async": "^2.1.2",
"ethereumjs-util": "^7.0.10",
"ethers": "^4.0.40",

@ -55,10 +55,10 @@ export class LogsManager {
if (queryFilter.topics.filter((logTopic) => changeEvent.log.topics.indexOf(logTopic) >= 0).length === 0) return false
if (queryType === 'logs') {
if ((queryFilter.address === ('0x' + changeEvent.tx.to.toString('hex'))) && (queryFilter.address === ('0x' + changeEvent.tx.from.toString('hex')))) {
if (!queryFilter.toBlock) {
return true
} else if (parseInt(queryFilter.toBlock) > parseInt(changeEvent.blockNumber)) {
const fromBlock = queryFilter.fromBlock || '0x0'
const toBlock = queryFilter.toBlock || this.oldLogs.length ? this.oldLogs[this.oldLogs.length - 1].blockNumber : '0x0'
if ((queryFilter.address === (changeEvent.tx.to || '').toString()) || queryFilter.address === (changeEvent.tx.getSenderAddress().toString())) {
if ((parseInt(toBlock) >= parseInt(changeEvent.blockNumber)) && (parseInt(fromBlock) <= parseInt(changeEvent.blockNumber))) {
return true
}
}
@ -144,6 +144,23 @@ export class LogsManager {
}
}
getLogsByTxHash (hash) {
return this.oldLogs.filter((log) => '0x' + log.tx.hash().toString('hex') === hash)
.map((log) => {
return {
logIndex: '0x1', // 1
blockNumber: log.blockNumber,
blockHash: ('0x' + log.block.hash().toString('hex')),
transactionHash: ('0x' + log.tx.hash().toString('hex')),
transactionIndex: '0x' + log.txNumber.toString(16),
// TODO: if it's a contract deploy, it should be that address instead
address: log.log.address,
data: log.log.data,
topics: log.log.topics
}
})
}
getLogsFor (params) {
const results = []
for (const log of this.oldLogs) {

@ -13,7 +13,6 @@ export class TxRunnerVM {
vmaccounts
queusTxs
blocks
txs
logsManager
commonContext
getVMObject: () => any

@ -129,11 +129,7 @@ export class Web3VmProvider {
this.storageCache[this.processingHash] = {}
if (data.to) {
try {
// dumpStorage throws error as 'Missing Node in DB'
// This can be uncommented once that error is handled
// https://github.com/ethereum/remix-project/issues/1644
// const storage = await this.vm.stateManager.dumpStorage(data.to)
const storage = {}
const storage = await this.vm.stateManager.dumpStorage(data.to)
this.storageCache[this.processingHash][tx['to']] = storage
this.lastProcessedStorageTxHash[tx['to']] = this.processingHash
} catch (e) {
@ -249,11 +245,7 @@ export class Web3VmProvider {
if (!this.storageCache[this.processingHash][this.processingAddress]) {
const account = Address.fromString(this.processingAddress)
try {
// dumpStorage throws error as 'Missing Node in DB'
// This can be uncommented once that error is handled
// https://github.com/ethereum/remix-project/issues/1644
// const storage = await this.vm.stateManager.dumpStorage(account)
const storage = {}
const storage = await this.vm.stateManager.dumpStorage(account)
this.storageCache[this.processingHash][this.processingAddress] = storage
this.lastProcessedStorageTxHash[this.processingAddress] = this.processingHash
} catch (e) {

@ -14,10 +14,10 @@
],
"main": "src/index.js",
"dependencies": {
"@ethereumjs/block": "^3.4.0",
"@ethereumjs/common": "^2.2.0",
"@ethereumjs/tx": "^3.3.0",
"@ethereumjs/vm": "^5.5.0",
"@ethereumjs/block": "^3.5.1",
"@ethereumjs/common": "^2.5.0",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.7",
"ansi-gray": "^0.1.1",
"async": "^3.1.0",

@ -1,13 +1,10 @@
export class Blocks {
vmContext
coinbase: string
blockNumber: number
constructor (vmContext, _options) {
this.vmContext = vmContext
const options = _options || {}
this.coinbase = options.coinbase || '0x0000000000000000000000000000000000000000'
this.blockNumber = 0
}
methods (): Record<string, unknown> {
@ -107,7 +104,7 @@ export class Blocks {
}
eth_blockNumber (payload, cb) {
cb(null, this.blockNumber)
cb(null, parseInt(this.vmContext.latestBlockNumber))
}
eth_getBlockTransactionCountByHash (payload, cb) {

@ -11,6 +11,7 @@ export class Transactions {
tags
txRunnerVMInstance
txRunnerInstance
TX_INDEX = '0x0' // currently there's always only 1 tx per block, so the transaction index will always be 0x0
constructor (vmContext) {
this.vmContext = vmContext
@ -71,7 +72,7 @@ export class Transactions {
if (!error && result) {
this.vmContext.addBlock(result.block)
const hash = '0x' + result.tx.hash().toString('hex')
this.vmContext.trackTx(hash, result.block)
this.vmContext.trackTx(hash, result.block, result.tx)
this.vmContext.trackExecResult(hash, result.result.execResult)
return cb(null, result.transactionHash)
}
@ -95,17 +96,19 @@ export class Transactions {
return cb(error)
}
const txBlock = this.vmContext.txs[receipt.hash]
const txBlock = this.vmContext.blockByTxHash[receipt.hash]
const logs = this.vmContext.logsManager.getLogsByTxHash(receipt.hash)
const r: Record <string, unknown> = {
transactionHash: receipt.hash,
transactionIndex: '0x00',
transactionIndex: this.TX_INDEX,
blockHash: '0x' + txBlock.hash().toString('hex'),
blockNumber: '0x' + txBlock.header.number.toString('hex'),
gasUsed: receipt.gasUsed,
cumulativeGasUsed: receipt.gasUsed, // only 1 tx per block
contractAddress: receipt.contractAddress,
logs: receipt.logs,
logs,
status: receipt.status,
to: receipt.to
}
@ -151,7 +154,7 @@ export class Transactions {
if (!error && result) {
this.vmContext.addBlock(result.block)
const hash = '0x' + result.tx.hash().toString('hex')
this.vmContext.trackTx(hash, result.block)
this.vmContext.trackTx(hash, result.block, result.tx)
this.vmContext.trackExecResult(hash, result.result.execResult)
this.tags[tag] = result.transactionHash
// calls are not supposed to return a transaction hash. we do this for keeping track of it and allowing debugging calls.
@ -185,7 +188,8 @@ export class Transactions {
return cb(error)
}
const txBlock = this.vmContext.txs[receipt.transactionHash]
const txBlock = this.vmContext.blockByTxHash[receipt.transactionHash]
const tx = this.vmContext.txByHash[receipt.transactionHash]
// TODO: params to add later
const r: Record<string, unknown> = {
@ -198,8 +202,8 @@ export class Transactions {
gasPrice: '0x4a817c800', // 20000000000
hash: receipt.transactionHash,
input: receipt.input,
nonce: 2, // 0x15 // the nonce should be updated
// "transactionIndex": 0,
nonce: '0x' + tx.nonce.toString('hex'),
transactionIndex: this.TX_INDEX,
value: receipt.value
// "value":"0xf3dbb76162000" // 4290000000000000
// "v": "0x25", // 37
@ -234,6 +238,8 @@ export class Transactions {
return cb(error)
}
const tx = this.vmContext.txByHash[receipt.transactionHash]
// TODO: params to add later
const r: Record<string, unknown> = {
blockHash: '0x' + txBlock.hash().toString('hex'),
@ -245,8 +251,8 @@ export class Transactions {
gasPrice: '0x4a817c800', // 20000000000
hash: receipt.transactionHash,
input: receipt.input,
nonce: 2, // 0x15 // the nonce should be updated
// "transactionIndex": 0,
nonce: '0x' + tx.nonce.toString('hex'),
transactionIndex: this.TX_INDEX,
value: receipt.value
// "value":"0xf3dbb76162000" // 4290000000000000
// "v": "0x25", // 37
@ -277,6 +283,8 @@ export class Transactions {
return cb(error)
}
const tx = this.vmContext.txByHash[receipt.transactionHash]
// TODO: params to add later
const r: Record<string, unknown> = {
blockHash: '0x' + txBlock.hash().toString('hex'),
@ -288,8 +296,8 @@ export class Transactions {
gasPrice: '0x4a817c800', // 20000000000
hash: receipt.transactionHash,
input: receipt.input,
nonce: 2, // 0x15 // the nonce should be updated
// "transactionIndex": 0,
nonce: '0x' + tx.nonce.toString('hex'),
transactionIndex: this.TX_INDEX,
value: receipt.value
// "value":"0xf3dbb76162000" // 4290000000000000
// "v": "0x25", // 37

@ -24,18 +24,13 @@ class StateManagerCommonStorageDump extends StateManager {
return super.putContractStorage(address, key, value)
}
async dumpStorage (address) {
let trie
try {
trie = await this._getStorageTrie(address)
} catch (e) {
console.log(e)
throw e
}
return new Promise<StorageDump>((resolve, reject) => {
try {
async dumpStorage (address): Promise<StorageDump> {
return new Promise((resolve, reject) => {
this._getStorageTrie(address)
.then((trie) => {
const storage = {}
const stream = trie.createReadStream()
stream.on('data', (val) => {
const value = rlp.decode(val.value)
storage['0x' + val.key.toString('hex')] = {
@ -43,12 +38,13 @@ class StateManagerCommonStorageDump extends StateManager {
value: '0x' + value.toString('hex')
}
})
stream.on('end', function () {
stream.on('end', () => {
resolve(storage)
})
} catch (e) {
})
.catch((e) => {
reject(e)
}
})
})
}
@ -60,19 +56,18 @@ class StateManagerCommonStorageDump extends StateManager {
}
async setStateRoot (stateRoot) {
await this._cache.flush()
if (stateRoot === this._trie.EMPTY_TRIE_ROOT) {
this._trie.root = stateRoot
this._cache.clear()
this._storageTries = {}
return
if (this._checkpointCount !== 0) {
throw new Error('Cannot set state root with uncommitted checkpoints')
}
await this._cache.flush()
if (!stateRoot.equals(this._trie.EMPTY_TRIE_ROOT)) {
const hasRoot = await this._trie.checkRoot(stateRoot)
if (!hasRoot) {
throw new Error('State trie does not contain state root')
}
}
this._trie.root = stateRoot
this._cache.clear()
@ -90,7 +85,8 @@ export class VMContext {
customNetWorks
blocks
latestBlockNumber
txs
blockByTxHash
txByHash
currentVm
web3vm
logsManager
@ -103,7 +99,8 @@ export class VMContext {
this.currentVm = this.createVm(this.currentFork)
this.blocks = {}
this.latestBlockNumber = 0
this.txs = {}
this.blockByTxHash = {}
this.txByHash = {}
this.exeResults = {}
this.logsManager = new execution.LogsManager()
}
@ -156,8 +153,9 @@ export class VMContext {
this.logsManager.checkBlock(blockNumber, block, this.web3())
}
trackTx (tx, block) {
this.txs[tx] = block
trackTx (txHash, block, tx) {
this.blockByTxHash[txHash] = block
this.txByHash[txHash] = tx
}
trackExecResult (tx, execReult) {

@ -115,8 +115,6 @@ describe('blocks', () => {
assert.deepEqual(numberTransactions, correctBlock.uncles.length)
})
})
/*
describe('eth_getStorageAt', () => {
it('should get storage at position at given address', async () => {
const abi: any = [
@ -201,30 +199,28 @@ describe('blocks', () => {
}
]
// const code = '0x608060405234801561001057600080fd5b506040516020806102018339810180604052602081101561003057600080fd5b810190808051906020019092919050505080600081905550506101a9806100586000396000f3fe60806040526004361061005c576000357c0100000000000000000000000000000000000000000000000000000000900480632a1afcd91461006157806360fe47b11461008c5780636d4ce63c146100c7578063ce01e1ec146100f2575b600080fd5b34801561006d57600080fd5b5061007661012d565b6040518082815260200191505060405180910390f35b34801561009857600080fd5b506100c5600480360360208110156100af57600080fd5b8101908080359060200190929190505050610133565b005b3480156100d357600080fd5b506100dc61013d565b6040518082815260200191505060405180910390f35b3480156100fe57600080fd5b5061012b6004803603602081101561011557600080fd5b8101908080359060200190929190505050610146565b005b60005481565b8060008190555050565b60008054905090565b80600081905550807f63a242a632efe33c0e210e04e4173612a17efa4f16aa4890bc7e46caece80de060405160405180910390a25056fea165627a7a7230582063160eb16dc361092a85ced1a773eed0b63738b83bea1e1c51cf066fa90e135d0029'
const code = '0x608060405234801561001057600080fd5b506040516020806102018339810180604052602081101561003057600080fd5b810190808051906020019092919050505080600081905550506101a9806100586000396000f3fe60806040526004361061005c576000357c0100000000000000000000000000000000000000000000000000000000900480632a1afcd91461006157806360fe47b11461008c5780636d4ce63c146100c7578063ce01e1ec146100f2575b600080fd5b34801561006d57600080fd5b5061007661012d565b6040518082815260200191505060405180910390f35b34801561009857600080fd5b506100c5600480360360208110156100af57600080fd5b8101908080359060200190929190505050610133565b005b3480156100d357600080fd5b506100dc61013d565b6040518082815260200191505060405180910390f35b3480156100fe57600080fd5b5061012b6004803603602081101561011557600080fd5b8101908080359060200190929190505050610146565b005b60005481565b8060008190555050565b60008054905090565b80600081905550807f63a242a632efe33c0e210e04e4173612a17efa4f16aa4890bc7e46caece80de060405160405180910390a25056fea165627a7a7230582063160eb16dc361092a85ced1a773eed0b63738b83bea1e1c51cf066fa90e135d0029'
// const contract = new web3.eth.Contract(abi)
// const accounts = await web3.eth.getAccounts()
const contract = new web3.eth.Contract(abi)
const accounts = await web3.eth.getAccounts()
// const contractInstance: any = await contract.deploy({ data: code, arguments: [100] }).send({ from: accounts[0], gas: 400000 })
// contractInstance.currentProvider = web3.eth.currentProvider
// contractInstance.givenProvider = web3.eth.currentProvider
const contractInstance: any = await contract.deploy({ data: code, arguments: [100] }).send({ from: accounts[0], gas: 400000 })
contractInstance.currentProvider = web3.eth.currentProvider
contractInstance.givenProvider = web3.eth.currentProvider
// await contractInstance.methods.set(100).send({ from: accounts[0].toLowerCase(), gas: 400000 })
// let storage = await web3.eth.getStorageAt(contractInstance.options.address, 0)
// assert.deepEqual(storage, '0x64')
await contractInstance.methods.set(100).send({ from: accounts[0].toLowerCase(), gas: 400000 })
let storage = await web3.eth.getStorageAt(contractInstance.options.address, 0)
assert.deepEqual(storage, '0x64')
// await contractInstance.methods.set(200).send({ from: accounts[0], gas: 400000 })
// storage = await web3.eth.getStorageAt(contractInstance.options.address, 0)
// assert.deepEqual(storage, '0x64')
await contractInstance.methods.set(200).send({ from: accounts[0], gas: 400000 })
storage = await web3.eth.getStorageAt(contractInstance.options.address, 0)
assert.deepEqual(storage, '0x64')
await contractInstance.methods.set(200).send({ from: accounts[0], gas: 400000 })
storage = await web3.eth.getStorageAt(contractInstance.options.address, 0)
assert.deepEqual(storage, '0xc8')
})
})
*/
describe('eth_call', () => {
it('should get a value', async () => {
const abi: any = [

@ -2,7 +2,8 @@
"extends": "../../.eslintrc",
"rules": {
"dot-notation": "off",
"no-unused-vars": "off"
"no-unused-vars": "off",
"no-use-before-define": "off"
},
"env": {
"browser": true,

@ -15,9 +15,9 @@
}
],
"dependencies": {
"@ethereumjs/block": "^3.4.0",
"@ethereumjs/tx": "^3.3.0",
"@ethereumjs/vm": "^5.5.0",
"@ethereumjs/block": "^3.5.1",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.7",
"async": "^2.6.2",
"eslint-scope": "^5.0.0",

@ -2,7 +2,8 @@
"extends": "../../.eslintrc",
"rules": {
"dot-notation": "off",
"no-unused-vars": "off"
"no-unused-vars": "off",
"no-use-before-define": "off"
},
"env": {
"browser": true,

@ -6,7 +6,7 @@ module.exports = {
transform: {
'^.+\\.[tj]sx?$': 'ts-jest',
},
transformIgnorePatterns: ["/node_modules/", "\\.pnp\\.[^\\\/]+$"],
transformIgnorePatterns: ["/node_modules/", "/dist/", "\\.pnp\\.[^\\\/]+$"],
rootDir: "./",
testTimeout: 40000,
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html', 'json'],

@ -35,10 +35,10 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-tests#readme",
"dependencies": {
"@ethereumjs/block": "^3.4.0",
"@ethereumjs/common": "^2.2.0",
"@ethereumjs/tx": "^3.3.0",
"@ethereumjs/vm": "^5.5.0",
"@ethereumjs/block": "^3.5.1",
"@ethereumjs/common": "^2.5.0",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.7",
"@remix-project/remix-simulator": "^0.2.7",
"@remix-project/remix-solidity": "^0.4.7",

@ -171,8 +171,9 @@ export function compileFileOrFiles (filename: string, isDirectory: boolean, opts
* @param cb Callback
*/
export function compileContractSources (sources: SrcIfc, compilerConfig: CompilerConfiguration, importFileCb: any, opts: any, cb): void {
let compiler, filepath: string
let compiler
const accounts: string[] = opts.accounts || []
const filepath = opts.testFilePath || ''
// Iterate over sources keys. Inject test libraries. Inject test library import statements.
if (!('remix_tests.sol' in sources) && !('tests.sol' in sources)) {
sources['tests.sol'] = { content: require('../sol/tests.sol.js') }

@ -11,7 +11,7 @@ import { compilationInterface } from './types'
* @param callback Callback
*/
export function deployAll (compileResult: compilationInterface, web3: Web3, withDoubleGas: boolean, callback) {
export function deployAll (compileResult: compilationInterface, web3: Web3, withDoubleGas: boolean, deployCb, callback) {
const compiledObject = {}
const contracts = {}
let accounts: string[] = []
@ -70,7 +70,7 @@ export function deployAll (compileResult: compilationInterface, web3: Web3, with
deployObject.send({
from: accounts[0],
gas: gas
}).on('receipt', function (receipt) {
}).on('receipt', async function (receipt) {
contractObject.options.address = receipt.contractAddress
contractObject.options.from = accounts[0]
contractObject.options.gas = 5000 * 1000
@ -79,6 +79,7 @@ export function deployAll (compileResult: compilationInterface, web3: Web3, with
contracts[contractName] = contractObject
contracts[contractName].filename = filename
if (deployCb) await deployCb(filename, receipt.contractAddress)
callback(null, { receipt: { contractAddress: receipt.contractAddress } }) // TODO this will only work with JavaScriptV VM
}).on('error', function (err) {
console.error(err)

@ -61,13 +61,13 @@ export function runTestFiles (filepath: string, isDirectory: boolean, web3: Web3
for (const filename in asts) {
if (filename.endsWith('_test.sol')) { sourceASTs[filename] = asts[filename].ast }
}
deployAll(compilationResult, web3, false, (err, contracts) => {
deployAll(compilationResult, web3, false, null, (err, contracts) => {
if (err) {
// If contract deployment fails because of 'Out of Gas' error, try again with double gas
// This is temporary, should be removed when remix-tests will have a dedicated UI to
// accept deployment params from UI
if (err.message.includes('The contract code couldn\'t be stored, please check your gas limit')) {
deployAll(compilationResult, web3, true, (error, contracts) => {
deployAll(compilationResult, web3, true, null, (error, contracts) => {
if (error) next([{ message: 'contract deployment failed after trying twice: ' + error.message, severity: 'error' }]) // IDE expects errors in array
else next(null, compilationResult, contracts)
})

@ -39,7 +39,7 @@ export class UnitTestRunner {
* @param importFileCb Import file callback
* @param opts Options
*/
async runTestSources (contractSources: SrcIfc, compilerConfig: CompilerConfiguration, testCallback, resultCallback, finalCallback: any, importFileCb, opts: Options) {
async runTestSources (contractSources: SrcIfc, compilerConfig: CompilerConfiguration, testCallback, resultCallback, deployCb:any, finalCallback: any, importFileCb, opts: Options) {
opts = opts || {}
const sourceASTs: any = {}
const web3 = opts.web3 || await this.createWeb3Provider()
@ -53,19 +53,19 @@ export class UnitTestRunner {
})
},
(next) => {
compileContractSources(contractSources, compilerConfig, importFileCb, { accounts, event: this.event }, next)
compileContractSources(contractSources, compilerConfig, importFileCb, { accounts, testFilePath: opts.testFilePath, event: this.event }, next)
},
function deployAllContracts (compilationResult: compilationInterface, asts: ASTInterface, next) {
for (const filename in asts) {
if (filename.endsWith('_test.sol')) { sourceASTs[filename] = asts[filename].ast }
}
deployAll(compilationResult, web3, false, (err, contracts) => {
deployAll(compilationResult, web3, false, deployCb, (err, contracts) => {
if (err) {
// If contract deployment fails because of 'Out of Gas' error, try again with double gas
// This is temporary, should be removed when remix-tests will have a dedicated UI to
// accept deployment params from UI
if (err.message.includes('The contract code couldn\'t be stored, please check your gas limit')) {
deployAll(compilationResult, web3, true, (error, contracts) => {
deployAll(compilationResult, web3, true, deployCb, (error, contracts) => {
if (error) next([{ message: 'contract deployment failed after trying twice: ' + error.message, severity: 'error' }]) // IDE expects errors in array
else next(null, compilationResult, contracts)
})

@ -244,6 +244,7 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
if (func.inputs && func.inputs.length > 0) { return resultsCallback(new Error(`Method '${func.name}' can not have parameters inside a test contract`), { passingNum, failureNum, timePassed }) }
const method = testObject.methods[func.name].apply(testObject.methods[func.name], [])
const startTime = Date.now()
let debugTxHash:string
if (func.constant) {
sendParams = {}
const tagTimestamp = 'remix_tests_tag' + Date.now()
@ -251,18 +252,20 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
method.call(sendParams).then(async (result) => {
const time = (Date.now() - startTime) / 1000.0
let tagTxHash
let hhLogs
if (web3.eth && web3.eth.getHashFromTagBySimulator) tagTxHash = await web3.eth.getHashFromTagBySimulator(tagTimestamp)
if (web3.eth && web3.eth.getHHLogsForTx) hhLogs = await web3.eth.getHHLogsForTx(tagTxHash)
debugTxHash = tagTxHash
if (result) {
const resp: TestResultInterface = {
type: 'testPass',
value: changeCase.sentenceCase(func.name),
filename: testObject.filename,
time: time,
context: testName
context: testName,
web3,
debugTxHash
}
if (hhLogs) resp.hhLogs = hhLogs
if (hhLogs && hhLogs.length) resp.hhLogs = hhLogs
testCallback(undefined, resp)
passingNum += 1
timePassed += time
@ -273,9 +276,11 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
filename: testObject.filename,
time: time,
errMsg: 'function returned false',
context: testName
context: testName,
web3,
debugTxHash
}
if (hhLogs) resp.hhLogs = hhLogs
if (hhLogs && hhLogs.length) resp.hhLogs = hhLogs
testCallback(undefined, resp)
failureNum += 1
timePassed += time
@ -294,6 +299,7 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
sendParams.gas = 10000000 * 8
method.send(sendParams).on('receipt', async (receipt) => {
try {
debugTxHash = receipt.transactionHash
if (web3.eth && web3.eth.getHHLogsForTx) hhLogs = await web3.eth.getHHLogsForTx(receipt.transactionHash)
const time: number = (Date.now() - startTime) / 1000.0
const assertionEventHashes = assertionEvents.map(e => Web3.utils.sha3(e.name + '(' + e.params.join() + ')'))
@ -323,9 +329,10 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
returned: testEvent[3],
expected: testEvent[4],
location,
web3
web3,
debugTxHash
}
if (hhLogs) resp.hhLogs = hhLogs
if (hhLogs && hhLogs.length) resp.hhLogs = hhLogs
testCallback(undefined, resp)
failureNum += 1
timePassed += time
@ -342,13 +349,15 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
value: changeCase.sentenceCase(func.name),
filename: testObject.filename,
time: time,
context: testName
context: testName,
web3,
debugTxHash
}
if (hhLogs) resp.hhLogs = hhLogs
if (hhLogs && hhLogs.length) resp.hhLogs = hhLogs
testCallback(undefined, resp)
passingNum += 1
timePassed += time
} else if (hhLogs) {
} else if (hhLogs && hhLogs.length) {
const resp: TestResultInterface = {
type: 'logOnly',
value: changeCase.sentenceCase(func.name),
@ -380,7 +389,8 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
if (err.message.includes('Transaction has been reverted by the EVM')) {
const txHash = JSON.parse(err.message.replace('Transaction has been reverted by the EVM:', '')).transactionHash
if (web3.eth && web3.eth.getHHLogsForTx) hhLogs = await web3.eth.getHHLogsForTx(txHash)
if (hhLogs) resp.hhLogs = hhLogs
if (hhLogs && hhLogs.length) resp.hhLogs = hhLogs
resp.debugTxHash = txHash
}
testCallback(undefined, resp)
failureNum += 1

@ -38,6 +38,7 @@ export interface TestResultInterface {
location?: string
hhLogs?: []
web3?: any
debugTxHash?: string
}
export interface TestCbInterface {
(error: Error | null | undefined, result: TestResultInterface) : void;
@ -48,6 +49,7 @@ export interface ResultCbInterface {
export interface Options {
accounts?: string[] | null,
testFilePath?: string
web3?: any
}
@ -58,13 +60,12 @@ export interface CompilerConfiguration {
usingWorker?: boolean,
runs: number
}
export interface CompilationErrors {
name: string,
errors: Array<Error>,
message: string
}
// eslint-disable-next-line no-redeclare
export class CompilationErrors extends Error {
constructor (errors: Array<any>) {
const mapError = errors.map((e) => { return e.formattedMessage || e.message })

@ -0,0 +1,12 @@
import "remix_tests.sol"; // this import is automatically injected by Remix.
contract AssertOkTest {
function okPassTest() public {
Assert.ok(true, "okPassTest passes");
}
function okFailTest() public {
Assert.ok(false, "okFailTest fails");
}
}

@ -10,7 +10,9 @@ describe('testRunner: remix-tests CLI', () => {
if(result) {
const dirContent = result.stdout.toString()
// Install dependencies if 'node_modules' is not already present
if(!dirContent.includes('node_modules')) execSync('npm install', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') })
if(!dirContent.includes('node_modules')) {
execSync('npm install', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') })
}
}
@ -40,7 +42,7 @@ Commands:
})
test('remix-tests running a test file', () => {
const res = spawnSync(executablePath, [resolve(__dirname + '/examples_0/assert_ok_test.sol')])
const res = spawnSync(executablePath, [resolve(__dirname + '/examples_0/assert_ok_without_console_test.sol')])
// match initial lines
expect(res.stdout.toString().trim()).toMatch(/:: Running remix-tests - Unit testing for solidity ::/)
expect(res.stdout.toString().trim()).toMatch(/creation of library remix_tests.sol:Assert pending.../)
@ -55,7 +57,7 @@ Commands:
})
test('remix-tests running a test file with custom compiler version', () => {
const res = spawnSync(executablePath, ['--compiler', '0.7.4', resolve(__dirname + '/examples_0/assert_ok_test.sol')])
const res = spawnSync(executablePath, ['--compiler', '0.7.4', resolve(__dirname + '/examples_0/assert_ok_without_console_test.sol')])
// match initial lines
expect(res.stdout.toString().trim().includes('Compiler version set to 0.7.4. Latest version is')).toBeTruthy()
expect(res.stdout.toString().trim().includes('Loading remote solc version v0.7.4+commit.3f05b770 ...')).toBeTruthy()
@ -69,13 +71,13 @@ Commands:
})
test('remix-tests running a test file with unavailable custom compiler version (should fail)', () => {
const res = spawnSync(executablePath, ['--compiler', '1.10.4', resolve(__dirname + '/examples_0/assert_ok_test.sol')])
const res = spawnSync(executablePath, ['--compiler', '1.10.4', resolve(__dirname + '/examples_0/assert_ok_without_console_test.sol')])
// match initial lines
expect(res.stdout.toString().trim().includes('No compiler found in releases with version 1.10.4')).toBeTruthy()
})
test('remix-tests running a test file with custom EVM', () => {
const res = spawnSync(executablePath, ['--evm', 'petersburg', resolve(__dirname + '/examples_0/assert_ok_test.sol')])
const res = spawnSync(executablePath, ['--evm', 'petersburg', resolve(__dirname + '/examples_0/assert_ok_without_console_test.sol')])
// match initial lines
expect(res.stdout.toString().trim().includes('EVM set to petersburg')).toBeTruthy()
expect(res.stdout.toString().trim()).toMatch(/:: Running remix-tests - Unit testing for solidity ::/)
@ -88,7 +90,7 @@ Commands:
})
test('remix-tests running a test file by enabling optimization', () => {
const res = spawnSync(executablePath, ['--optimize', 'true', resolve(__dirname + '/examples_0/assert_ok_test.sol')])
const res = spawnSync(executablePath, ['--optimize', 'true', resolve(__dirname + '/examples_0/assert_ok_without_console_test.sol')])
// match initial lines
expect(res.stdout.toString().trim().includes('Optimization is enabled')).toBeTruthy()
expect(res.stdout.toString().trim()).toMatch(/:: Running remix-tests - Unit testing for solidity ::/)
@ -101,7 +103,7 @@ Commands:
})
test('remix-tests running a test file by enabling optimization and setting runs', () => {
const res = spawnSync(executablePath, ['--optimize', 'true', '--runs', '300', resolve(__dirname + '/examples_0/assert_ok_test.sol')])
const res = spawnSync(executablePath, ['--optimize', 'true', '--runs', '300', resolve(__dirname + '/examples_0/assert_ok_without_console_test.sol')])
// match initial lines
expect(res.stdout.toString().trim().includes('Optimization is enabled')).toBeTruthy()
expect(res.stdout.toString().trim().includes('Runs set to 300')).toBeTruthy()
@ -115,13 +117,13 @@ Commands:
})
test('remix-tests running a test file without enabling optimization and setting runs (should fail)', () => {
const res = spawnSync(executablePath, ['--runs', '300', resolve(__dirname + '/examples_0/assert_ok_test.sol')])
const res = spawnSync(executablePath, ['--runs', '300', resolve(__dirname + '/examples_0/assert_ok_without_console_test.sol')])
// match initial lines
expect(res.stdout.toString().trim().includes('Optimization should be enabled for runs')).toBeTruthy()
})
test('remix-tests running a test file with all options', () => {
const res = spawnSync(executablePath, ['--compiler', '0.7.5', '--evm', 'istanbul', '--optimize', 'true', '--runs', '250', resolve(__dirname + '/examples_0/assert_ok_test.sol')])
const res = spawnSync(executablePath, ['--compiler', '0.7.5', '--evm', 'istanbul', '--optimize', 'true', '--runs', '250', resolve(__dirname + '/examples_0/assert_ok_without_console_test.sol')])
// match initial lines
expect(res.stdout.toString().trim().includes('Compiler version set to 0.7.5. Latest version is')).toBeTruthy()
expect(res.stdout.toString().trim().includes('Loading remote solc version v0.7.5+commit.eb77ed08 ...')).toBeTruthy()

@ -67,7 +67,7 @@ async function compileAndDeploy(filename: string, callback: Function) {
}
try {
compilationData = compilationResult
deployAll(compilationResult, web3, false, next)
deployAll(compilationResult, web3, false, null, next)
} catch (e) {
throw e
}
@ -128,8 +128,8 @@ describe('testRunner', () => {
deepEqualExcluding(tests, [
{ type: 'accountList', value: accounts },
{ type: 'contract', value: 'AssertOkTest', filename: __dirname + '/examples_0/assert_ok_test.sol' },
{ type: 'testPass', value: 'Ok pass test', filename: __dirname + '/examples_0/assert_ok_test.sol', context: 'AssertOkTest', hhLogs: hhLogs1 },
{ type: 'testFailure', value: 'Ok fail test', filename: __dirname + '/examples_0/assert_ok_test.sol', errMsg: 'okFailTest fails', context: 'AssertOkTest', hhLogs: hhLogs2, assertMethod: 'ok', location: '370:36:0', expected: 'true', returned: 'false'},
{ type: 'testPass', debugTxHash: '0x5b665752a4faf83229259b9b2811d3295be0af633b0051d4b90042283ef55707', value: 'Ok pass test', filename: __dirname + '/examples_0/assert_ok_test.sol', context: 'AssertOkTest', hhLogs: hhLogs1 },
{ type: 'testFailure', debugTxHash: '0xa0a30ad042a7fc3495f72be7ba788d705888ffbbec7173f60bb27e07721510f2',value: 'Ok fail test', filename: __dirname + '/examples_0/assert_ok_test.sol', errMsg: 'okFailTest fails', context: 'AssertOkTest', hhLogs: hhLogs2, assertMethod: 'ok', location: '370:36:0', expected: 'true', returned: 'false'},
], ['time', 'web3'])
})
@ -158,18 +158,18 @@ describe('testRunner', () => {
deepEqualExcluding(tests, [
{ type: 'accountList', value: accounts },
{ type: 'contract', value: 'AssertEqualTest', filename: __dirname + '/examples_0/assert_equal_test.sol' },
{ type: 'testPass', value: 'Equal uint pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' },
{ type: 'testFailure', value: 'Equal uint fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalUintFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '273:57:0', expected: '2', returned: '1'},
{ type: 'testPass', value: 'Equal int pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' },
{ type: 'testFailure', value: 'Equal int fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalIntFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '493:45:0', expected: '2', returned: '-1'},
{ type: 'testPass', value: 'Equal bool pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' },
{ type: 'testFailure', value: 'Equal bool fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalBoolFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '708:52:0', expected: false, returned: true},
{ type: 'testPass', value: 'Equal address pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' },
{ type: 'testFailure', value: 'Equal address fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalAddressFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '1015:130:0', expected: '0x1c6637567229159d1eFD45f95A6675e77727E013', returned: '0x7994f14563F39875a2F934Ce42cAbF48a93FdDA9'},
{ type: 'testPass', value: 'Equal bytes32 pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' },
{ type: 'testFailure', value: 'Equal bytes32 fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalBytes32FailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '1670:48:0', expected: '0x72656d6978000000000000000000000000000000000000000000000000000000', returned: '0x72656d6979000000000000000000000000000000000000000000000000000000'},
{ type: 'testPass', value: 'Equal string pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' },
{ type: 'testFailure', value: 'Equal string fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalStringFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '1916:81:0', expected: 'remix-tests', returned: 'remix'}
{ type: 'testPass', debugTxHash: '0xbe77baee10f8a044a68fbb83abf57ce1ca63b8739f3b2dcd122dab0ee44fd0e9', value: 'Equal uint pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' },
{ type: 'testFailure', debugTxHash: '0xfc9691b0cd0a49dbefed5cd3fad32158dd229e5bb7b0eb11da3c72054eafae8b', value: 'Equal uint fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalUintFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '273:57:0', expected: '2', returned: '1'},
{ type: 'testPass', debugTxHash: '0xbc142789e5a51841781536a9291c9022896b0c7453140fdc98996638c0d76045', value: 'Equal int pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' },
{ type: 'testFailure', debugTxHash: '0xcc28211a4ab3149b1122fb47f45529a4edddbafa076d2338cc3754ab0629eaa1', value: 'Equal int fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalIntFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '493:45:0', expected: '2', returned: '-1'},
{ type: 'testPass', debugTxHash: '0x4f5570fc7da86f09aafb436ff3b4c46aa885f71680a233234433d0ef0346206b', value: 'Equal bool pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' },
{ type: 'testFailure', debugTxHash: '0x28dc2d146dee77a2d6446efb088e5f9d008a3c7a14116e798401b68470da017f', value: 'Equal bool fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalBoolFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '708:52:0', expected: false, returned: true},
{ type: 'testPass', debugTxHash: '0x0abc8fa8831efa3a8c82c758d045c1382f71b6a7f7e9135ffbe9e40059f84617', value: 'Equal address pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' },
{ type: 'testFailure', debugTxHash: '0x5ec200fb053539b8165a6b6ab36e9229a870c4752b0d6ff2786c4d5a66d5b35d', value: 'Equal address fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalAddressFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '1015:130:0', expected: '0x1c6637567229159d1eFD45f95A6675e77727E013', returned: '0x7994f14563F39875a2F934Ce42cAbF48a93FdDA9'},
{ type: 'testPass', debugTxHash: '0xb6c34f5baa6916569d122bcb1210fcd07fb126f4b859fea58db5328e5f1dab85', value: 'Equal bytes32 pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' },
{ type: 'testFailure', debugTxHash: '0xb3af74a384b8b6ddacbc03a480ae48e233415b1570717ca7023530023a871be6', value: 'Equal bytes32 fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalBytes32FailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '1670:48:0', expected: '0x72656d6978000000000000000000000000000000000000000000000000000000', returned: '0x72656d6979000000000000000000000000000000000000000000000000000000'},
{ type: 'testPass', debugTxHash: '0x8537e74941b511b5c745b398e55435748adcdf637659247e0d573fb681ee4833', value: 'Equal string pass test', filename: __dirname + '/examples_0/assert_equal_test.sol', context: 'AssertEqualTest' },
{ type: 'testFailure', debugTxHash: '0x30d44498e63ac51f1412062b849144c103e19a4dc9daf81c5e84bd984ef738a6', value: 'Equal string fail test', filename: __dirname + '/examples_0/assert_equal_test.sol', errMsg: 'equalStringFailTest fails', context: 'AssertEqualTest', assertMethod: 'equal', location: '1916:81:0', expected: 'remix-tests', returned: 'remix'}
], ['time', 'web3'])
})
})
@ -197,18 +197,18 @@ describe('testRunner', () => {
deepEqualExcluding(tests, [
{ type: 'accountList', value: accounts },
{ type: 'contract', value: 'AssertNotEqualTest', filename: __dirname + '/examples_0/assert_notEqual_test.sol' },
{ type: 'testPass', value: 'Not equal uint pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' },
{ type: 'testFailure', value: 'Not equal uint fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualUintFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '288:63:0', expected: '1', returned: '1'},
{ type: 'testPass', value: 'Not equal int pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' },
{ type: 'testFailure', value: 'Not equal int fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualIntFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '525:52:0', expected: '-2', returned: '-2'},
{ type: 'testPass', value: 'Not equal bool pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' },
{ type: 'testFailure', value: 'Not equal bool fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualBoolFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '760:57:0', expected: true, returned: true},
{ type: 'testPass', value: 'Not equal address pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' },
{ type: 'testFailure', value: 'Not equal address fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualAddressFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '1084:136:0', expected: 0x7994f14563F39875a2F934Ce42cAbF48a93FdDA9, returned: 0x7994f14563F39875a2F934Ce42cAbF48a93FdDA9},
{ type: 'testPass', value: 'Not equal bytes32 pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' },
{ type: 'testFailure', value: 'Not equal bytes32 fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualBytes32FailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '1756:54:0', expected: '0x72656d6978000000000000000000000000000000000000000000000000000000', returned: '0x72656d6978000000000000000000000000000000000000000000000000000000'},
{ type: 'testPass', value: 'Not equal string pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' },
{ type: 'testFailure', value: 'Not equal string fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualStringFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '2026:81:0', expected: 'remix', returned: 'remix'},
{ type: 'testPass', debugTxHash: '0xb0ac5cde13a5005dc1b4efbb66fb3a5d6f0697467aedd6165ed1c8ee552939bc', value: 'Not equal uint pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' },
{ type: 'testFailure', debugTxHash: '0x69d25ed9b9a010e97e0f7282313d4018c77a8873fd5f2e0b12483701febdd6b4', value: 'Not equal uint fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualUintFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '288:63:0', expected: '1', returned: '1'},
{ type: 'testPass', debugTxHash: '0x19a743cfb44b273c78b3271d603412d31087974309a70595bc5d15097a52c5c5', value: 'Not equal int pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' },
{ type: 'testFailure', debugTxHash: '0x8dfce61b71a9ea65fb00c471370413779626f290b71d41f8be8408674e64f4d2', value: 'Not equal int fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualIntFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '525:52:0', expected: '-2', returned: '-2'},
{ type: 'testPass', debugTxHash: '0x12bc9eb3a653ebe4c7ab954c144dab4848295c88d71d17cb86a41e8a004419ba', value: 'Not equal bool pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' },
{ type: 'testFailure', debugTxHash: '0x901b9cd631f8f29841243a257d1914060b9c36d88ee7d8b624de76dad4a34c85', value: 'Not equal bool fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualBoolFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '760:57:0', expected: true, returned: true},
{ type: 'testPass', debugTxHash: '0xf9e48bac26d3a2871ceb92974b897cae61e60bbc4db115b7e8eff4ac0390e4a5', value: 'Not equal address pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' },
{ type: 'testFailure', debugTxHash: '0x4e83a17426bc79b147ddd30a5434a2430a8302b3ce78b6979088ac5eceac5d3c', value: 'Not equal address fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualAddressFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '1084:136:0', expected: 0x7994f14563F39875a2F934Ce42cAbF48a93FdDA9, returned: 0x7994f14563F39875a2F934Ce42cAbF48a93FdDA9},
{ type: 'testPass', debugTxHash: '0xfb4b30bb8373eeb6b09e38ad07880b86654f72780b41d7cf7554a112a04a0f53', value: 'Not equal bytes32 pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' },
{ type: 'testFailure', debugTxHash: '0x43edf8bc68229415ee63f63f5303351a0dfecf9f3eb2ec35ffd2c10c60cf7005', value: 'Not equal bytes32 fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualBytes32FailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '1756:54:0', expected: '0x72656d6978000000000000000000000000000000000000000000000000000000', returned: '0x72656d6978000000000000000000000000000000000000000000000000000000'},
{ type: 'testPass', debugTxHash: '0x712932edc040596e2b02ddc06a48b773f5fccc7346d55cefc5d1c52528ce3168', value: 'Not equal string pass test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', context: 'AssertNotEqualTest' },
{ type: 'testFailure', debugTxHash: '0x961ce7425fdd4049aeb678ea20a0441eb837c1fe26b0d010593fc07d668321e6', value: 'Not equal string fail test', filename: __dirname + '/examples_0/assert_notEqual_test.sol', errMsg: 'notEqualStringFailTest fails', context: 'AssertNotEqualTest', assertMethod: 'notEqual', location: '2026:81:0', expected: 'remix', returned: 'remix'},
], ['time', 'web3'])
})
})
@ -235,14 +235,14 @@ describe('testRunner', () => {
deepEqualExcluding(tests, [
{ type: 'accountList', value: accounts },
{ type: 'contract', value: 'AssertGreaterThanTest', filename: __dirname + '/examples_0/assert_greaterThan_test.sol' },
{ type: 'testPass', value: 'Greater than uint pass test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', context: 'AssertGreaterThanTest' },
{ type: 'testFailure', value: 'Greater than uint fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanUintFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '303:69:0', expected: '4', returned: '1'},
{ type: 'testPass', value: 'Greater than int pass test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', context: 'AssertGreaterThanTest' },
{ type: 'testFailure', value: 'Greater than int fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanIntFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '569:67:0', expected: '1', returned: '-1'},
{ type: 'testPass', value: 'Greater than uint int pass test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', context: 'AssertGreaterThanTest' },
{ type: 'testFailure', value: 'Greater than uint int fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanUintIntFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '845:71:0', expected: '2', returned: '1'},
{ type: 'testPass', value: 'Greater than int uint pass test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', context: 'AssertGreaterThanTest' },
{ type: 'testFailure', value: 'Greater than int uint fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanIntUintFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '1125:76:0', expected: '115792089237316195423570985008687907853269984665640564039457584007913129639836', returned: '100'}
{ type: 'testPass', debugTxHash: '0x81cf46560b522280ac60bd5c8efedad4598957d33435a898c23eefb13ca6104f', value: 'Greater than uint pass test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', context: 'AssertGreaterThanTest' },
{ type: 'testFailure', debugTxHash: '0x7090dc27ac06e1afd66963992bdd9188200d0404d43b95cfa5d925bbe6eba3ed', value: 'Greater than uint fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanUintFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '303:69:0', expected: '4', returned: '1'},
{ type: 'testPass', debugTxHash: '0xd57b40ed464763baf128f8a72efcd198e825e0b8f498cef90aed23045d0196db', value: 'Greater than int pass test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', context: 'AssertGreaterThanTest' },
{ type: 'testFailure', debugTxHash: '0x6c7b84bd8fc452b7839e11129d3818fa69dfd9b914e55556b39fdc68b70fc1b5', value: 'Greater than int fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanIntFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '569:67:0', expected: '1', returned: '-1'},
{ type: 'testPass', debugTxHash: '0xc5883db70b83a1d3afff24a9f0555de3edd7776e5ec157cc2110e426e5be2594', value: 'Greater than uint int pass test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', context: 'AssertGreaterThanTest' },
{ type: 'testFailure', debugTxHash: '0xa534085a6bbdcf73a68bdef6a1421218c11ac0ec1af398f9445defeea31cea6e', value: 'Greater than uint int fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanUintIntFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '845:71:0', expected: '2', returned: '1'},
{ type: 'testPass', debugTxHash: '0x36a7139445d76f6072fab4cc0717461068276748622c0dfc3f092d548b197de8', value: 'Greater than int uint pass test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', context: 'AssertGreaterThanTest' },
{ type: 'testFailure', debugTxHash: '0x7890f7b8f2eabae581b6f70d55d2d3bfa64ddd7753d5f892dbdf86ced96945fe', value: 'Greater than int uint fail test', filename: __dirname + '/examples_0/assert_greaterThan_test.sol', errMsg: 'greaterThanIntUintFailTest fails', context: 'AssertGreaterThanTest', assertMethod: 'greaterThan', location: '1125:76:0', expected: '115792089237316195423570985008687907853269984665640564039457584007913129639836', returned: '100'}
], ['time', 'web3'])
})
})
@ -270,14 +270,14 @@ describe('testRunner', () => {
deepEqualExcluding(tests, [
{ type: 'accountList', value: accounts },
{ type: 'contract', value: 'AssertLesserThanTest', filename: __dirname + '/examples_0/assert_lesserThan_test.sol' },
{ type: 'testPass', value: 'Lesser than uint pass test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', context: 'AssertLesserThanTest' },
{ type: 'testFailure', value: 'Lesser than uint fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanUintFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '298:67:0', expected: '2', returned: '4'},
{ type: 'testPass', value: 'Lesser than int pass test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', context: 'AssertLesserThanTest' },
{ type: 'testFailure', value: 'Lesser than int fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanIntFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '557:65:0', expected: '-1', returned: '1'},
{ type: 'testPass', value: 'Lesser than uint int pass test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', context: 'AssertLesserThanTest' },
{ type: 'testFailure', value: 'Lesser than uint int fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanUintIntFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '826:71:0', expected: '-1', returned: '115792089237316195423570985008687907853269984665640564039457584007913129639935'},
{ type: 'testPass', value: 'Lesser than int uint pass test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', context: 'AssertLesserThanTest' },
{ type: 'testFailure', value: 'Lesser than int uint fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanIntUintFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '1105:69:0', expected: '1', returned: '1'},
{ type: 'testPass', debugTxHash: '0x47875047c1fff8a7b1cc1603418960cd2a3afe8a9c59337b19fb463a85d6e47e', value: 'Lesser than uint pass test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', context: 'AssertLesserThanTest' },
{ type: 'testFailure', debugTxHash: '0xf6fd459d0b28d0d85c56dd69d953331291e1c234c8a263150252e35da0ed6671', value: 'Lesser than uint fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanUintFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '298:67:0', expected: '2', returned: '4'},
{ type: 'testPass', debugTxHash: '0x761d95111764af396634474899ff1db218d5e514d6de6bc3260af15b1f5b929f', value: 'Lesser than int pass test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', context: 'AssertLesserThanTest' },
{ type: 'testFailure', debugTxHash: '0xc17697ef2df92c22707639caa9355bdf0d98dbb18157e72b8b257bb0eb2beb4e', value: 'Lesser than int fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanIntFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '557:65:0', expected: '-1', returned: '1'},
{ type: 'testPass', debugTxHash: '0xf0721b28c547c1c64948661d677cf6afc10d139315726280162a984f2f7e5d9c', value: 'Lesser than uint int pass test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', context: 'AssertLesserThanTest' },
{ type: 'testFailure', debugTxHash: '0x0757289229b58043c101cb311df8db16d1b30944747493e1491daa9aca6aa30e', value: 'Lesser than uint int fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanUintIntFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '826:71:0', expected: '-1', returned: '115792089237316195423570985008687907853269984665640564039457584007913129639935'},
{ type: 'testPass', debugTxHash: '0x316feb8f80c04b12194262dd80b6b004232eab00d7f7c3846badf6e92684e177', value: 'Lesser than int uint pass test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', context: 'AssertLesserThanTest' },
{ type: 'testFailure', debugTxHash: '0x65c5ab3cb85f163eefe3321cc4444defa99154d3cbe415b9384bbd2627449b6a', value: 'Lesser than int uint fail test', filename: __dirname + '/examples_0/assert_lesserThan_test.sol', errMsg: 'lesserThanIntUintFailTest fails', context: 'AssertLesserThanTest', assertMethod: 'lesserThan', location: '1105:69:0', expected: '1', returned: '1'},
], ['time', 'web3'])
})
})
@ -305,10 +305,10 @@ describe('testRunner', () => {
deepEqualExcluding(tests, [
{ type: 'accountList', value: accounts },
{ type: 'contract', value: 'MyTest', filename: __dirname + '/examples_1/simple_storage_test.sol' },
{ type: 'testPass', value: 'Initial value should be100', filename: __dirname + '/examples_1/simple_storage_test.sol', context: 'MyTest' },
{ type: 'testPass', value: 'Initial value should not be200', filename: __dirname + '/examples_1/simple_storage_test.sol', context: 'MyTest' },
{ type: 'testFailure', value: 'Should trigger one fail', filename: __dirname + '/examples_1/simple_storage_test.sol', errMsg: 'uint test 1 fails', context: 'MyTest', assertMethod: 'equal', location: '532:51:1', expected: '2', returned: '1'},
{ type: 'testPass', value: 'Should trigger one pass', filename: __dirname + '/examples_1/simple_storage_test.sol', context: 'MyTest' }
{ type: 'testPass', debugTxHash: '0x5a805403a12f0431c5dd190d31a87eb62758f09dddc0c6ee7ee6899c5e7eba71', value: 'Initial value should be100', filename: __dirname + '/examples_1/simple_storage_test.sol', context: 'MyTest' },
{ type: 'testPass', debugTxHash: '0xd0ae7cb5a3a0f5e8f7bf90129e3daba36f649a5c1176ad54609f7b7615bef7dd', value: 'Initial value should not be200', filename: __dirname + '/examples_1/simple_storage_test.sol', context: 'MyTest' },
{ type: 'testFailure', debugTxHash: '0xb0d613434f2fd7060f97d4ca8bbfd8f2deeebed83062a25044f0237bd38b3229', value: 'Should trigger one fail', filename: __dirname + '/examples_1/simple_storage_test.sol', errMsg: 'uint test 1 fails', context: 'MyTest', assertMethod: 'equal', location: '532:51:1', expected: '2', returned: '1'},
{ type: 'testPass', debugTxHash: '0x5ee675ec81b550386b2fdd359ae3530e49dd3e02145e877a4a5f68753ac4e341', value: 'Should trigger one pass', filename: __dirname + '/examples_1/simple_storage_test.sol', context: 'MyTest' }
], ['time', 'web3'])
})
})
@ -336,8 +336,8 @@ describe('testRunner', () => {
deepEqualExcluding(tests, [
{ type: 'accountList', value: accounts },
{ type: 'contract', value: 'MyTest', filename: __dirname + '/examples_2/simple_storage_test.sol' },
{ type: 'testPass', value: 'Initial value should be100', filename: __dirname + '/examples_2/simple_storage_test.sol', context: 'MyTest' },
{ type: 'testPass', value: 'Value is set200', filename: __dirname + '/examples_2/simple_storage_test.sol', context: 'MyTest' }
{ type: 'testPass', debugTxHash: '0xa700d29204f1ddb40ef66f151c44387f905d405b6da10380111a751451af2fe1', value: 'Initial value should be100', filename: __dirname + '/examples_2/simple_storage_test.sol', context: 'MyTest' },
{ type: 'testPass', debugTxHash: '0x2c037b78a435e5964615f838ea65f077f3b15d8552d514b3551d0fb87419e444', value: 'Value is set200', filename: __dirname + '/examples_2/simple_storage_test.sol', context: 'MyTest' }
], ['time', 'web3'])
})
})
@ -362,8 +362,8 @@ describe('testRunner', () => {
deepEqualExcluding(tests, [
{ type: 'accountList', value: accounts },
{ type: 'contract', value: 'StringTest', filename: __dirname + '/examples_3/simple_string_test.sol' },
{ type: 'testPass', value: 'Initial value should be hello world', filename: __dirname + '/examples_3/simple_string_test.sol', context: 'StringTest' },
{ type: 'testPass', value: 'Value should not be hello wordl', filename: __dirname + '/examples_3/simple_string_test.sol', context: 'StringTest' }
{ type: 'testPass', debugTxHash: '0x4e160dbc81f88d3d87b39d81651c42b0ea8e3aaa10c1a57394467e073bbcb2a4', value: 'Initial value should be hello world', filename: __dirname + '/examples_3/simple_string_test.sol', context: 'StringTest' },
{ type: 'testPass', debugTxHash: '0x47030578c5bcb990d837356430697d061a02813e3322fa3323f6b5f78176eea6', value: 'Value should not be hello wordl', filename: __dirname + '/examples_3/simple_string_test.sol', context: 'StringTest' }
], ['time', 'web3'])
})
})
@ -388,9 +388,9 @@ describe('testRunner', () => {
deepEqualExcluding(tests, [
{ type: 'accountList', value: accounts },
{ type: 'contract', value: 'StorageResolveTest', filename: __dirname + '/examples_5/test/simple_storage_test.sol' },
{ type: 'testPass', value: 'Initial value should be100', filename: __dirname + '/examples_5/test/simple_storage_test.sol', context: 'StorageResolveTest' },
{ type: 'testPass', value: 'Check if even', filename: __dirname + '/examples_5/test/simple_storage_test.sol', context: 'StorageResolveTest' },
{ type: 'testPass', value: 'Check if odd', filename: __dirname + '/examples_5/test/simple_storage_test.sol', context: 'StorageResolveTest' }
{ type: 'testPass', debugTxHash: '0x85e901e9160c4a17725d020f030c7cbb020d36da1fda8422d990391df3cbfcbb', value: 'Initial value should be100', filename: __dirname + '/examples_5/test/simple_storage_test.sol', context: 'StorageResolveTest' },
{ type: 'testPass', debugTxHash: '0x1abb2456746b416cddcaf2f3fe960103e740e9772c47a0f1d65d48394facb21a', value: 'Check if even', filename: __dirname + '/examples_5/test/simple_storage_test.sol', context: 'StorageResolveTest' },
{ type: 'testPass', debugTxHash: '0xfcc2332a24d2780390e85a06343fab81c4dc20c12cf5455d746641a9c3e8db03', value: 'Check if odd', filename: __dirname + '/examples_5/test/simple_storage_test.sol', context: 'StorageResolveTest' }
], ['time', 'web3'])
})
})

@ -1,10 +1,6 @@
import type { CompilationResult, CompilationSource } from '@remix-project/remix-solidity-ts' // eslint-disable-line
export interface DebuggerUIProps {
debuggerAPI: IDebuggerApi
}
export interface LineColumnLocation {
start: {
line: number, column: number
@ -68,3 +64,7 @@ export interface IDebuggerApi {
web3: () => any // returns an instance of web3.js
showMessage (title: string, message: string): void
}
export interface DebuggerUIProps {
debuggerAPI: IDebuggerApi
}

@ -1,3 +1,5 @@
/* eslint-disable no-undef */
export interface ExtractData {
children?: Array<{key: number | string, value: ExtractData}>
self?: string | number,
@ -13,7 +15,7 @@ export interface ExtractData {
}
export type ExtractFunc = (json: any, parent?: any) => ExtractData
export type FormatSelfFunc = (key: string | number, data: ExtractData) => JSX.Element
export interface DropdownPanelProps {
dropdownName: string,
dropdownMessage?: string,
@ -32,5 +34,3 @@ export interface DropdownPanelProps {
headStyle?: React.CSSProperties,
hexHighlight?: boolean // highlight non zero value of hex value
}
export type FormatSelfFunc = (key: string | number, data: ExtractData) => JSX.Element

@ -636,7 +636,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
return { ...prevState, focusModal: { ...state.focusModal, hide: true } }
})
}
// eslint-disable-next-line no-undef
const modal = (title: string, message: string | JSX.Element, okLabel: string, okFn: () => void, cancelLabel?: string, cancelFn?: () => void) => {
setState(prevState => {
return {

@ -1,4 +1,5 @@
import { customAction } from '@remixproject/plugin-api/lib/file-system/file-panel'
export type MenuItems = action[] // eslint-disable-line no-use-before-define
/* eslint-disable-next-line */
export interface FileExplorerProps {
@ -34,7 +35,6 @@ export interface FileExplorerMenuProps {
export type action = { name: string, type: string[], path: string[], extension: string[], pattern: string[], id: string, multiselect: boolean, label: string }
export type MenuItems = action[]
export interface FileExplorerContextMenuProps {
actions: action[],
createNewFile: (folder?: string) => void,

@ -4,6 +4,7 @@ import { ModalDialogProps } from './types' // eslint-disable-line
import './remix-ui-modal-dialog.css'
declare global {
// eslint-disable-next-line no-unused-vars
interface Window { testmode: boolean; }
}

@ -1,3 +1,4 @@
/* eslint-disable no-undef */
export interface ModalDialogProps {
id?: string
title?: string,

@ -1,4 +1,4 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
// eslint-disable-next-line @typescript-eslint/no-unused-vars, no-use-before-define
import React from 'react'
import '../remix-ui-plugin-manager.css'
interface PluginCardProps {

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { Profile } from '@remixproject/plugin-utils'
import React from 'react'
import React from 'react' // eslint-disable-line no-use-before-define
import { PluginManagerComponent } from '../../types'
import ActivePluginCard from './ActivePluginCard'
import ModuleHeading from './moduleHeading'

@ -1,5 +1,5 @@
import { Profile } from '@remixproject/plugin-utils'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-use-before-define
import React from 'react'
import '../remix-ui-plugin-manager.css'
interface PluginCardProps {

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { Profile } from '@remixproject/plugin-utils'
import React from 'react'
import React from 'react' // eslint-disable-line no-use-before-define
import { PluginManagerComponent, PluginManagerProfile } from '../../types'
import InactivePluginCard from './InactivePluginCard'
import ModuleHeading from './moduleHeading'

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useEffect, useReducer, useState } from 'react'
import React, { useEffect, useReducer, useState } from 'react' // eslint-disable-line no-use-before-define
import { ModalDialog } from '@remix-ui/modal-dialog'
import { Toaster } from '@remix-ui/toaster'
import { IframePlugin, WebsocketPlugin } from '@remixproject/engine-web'
@ -52,7 +52,7 @@ function LocalPluginForm ({ closeModal, visible, pluginManager }: LocalPluginFor
setMethods(Array.isArray(storagePlugin.methods) ? storagePlugin.methods.join(',') : storagePlugin.methods)
setType(storagePlugin.type)
setDisplayName(storagePlugin.displayName)
setCanactivate(Array.isArray(storagePlugin.canActivate) ? storagePlugin.canActivate.join(',') : storagePlugin.canActivate)
setCanactivate(Array.isArray(storagePlugin.canActivate) ? storagePlugin.canActivate.join(',') : storagePlugin.canActivate || '')
}, [])
const handleModalOkClick = async () => {

@ -1,4 +1,4 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-unused-vars,no-use-before-define */
import React from 'react'
interface ModuleHeadingProps {

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { Fragment, useState } from 'react'
import React, { Fragment, useState } from 'react' // eslint-disable-line no-use-before-define
/* eslint-disable-line */
import { ModalDialog } from '@remix-ui/modal-dialog'
import useLocalStorage from '../custom-hooks/useLocalStorage'

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { Fragment, ReactNode, useEffect, useState } from 'react'
import React, { Fragment, ReactNode, useEffect, useState } from 'react' // eslint-disable-line no-use-before-define
import { PluginManagerComponent, PluginManagerSettings } from '../../types'
import PermisssionsSettings from './permissionsSettings'
import { Profile } from '@remixproject/plugin-utils'

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { Profile } from '@remixproject/plugin-utils'
import React, { useState } from 'react'
import React, { useState } from 'react' // eslint-disable-line no-use-before-define
import { RemixUiPluginManagerProps } from '../types'
import ActivePluginCardContainer from './components/ActivePluginCardContainer'
import InactivePluginCardContainer from './components/InactivePluginCardContainer'

@ -32,7 +32,7 @@ export class RemixAppManager extends PluginManager {
constructor()
event: EventEmitter
pluginsDirectory: string
pluginLoader: PluginLoader
pluginLoader: PluginLoader // eslint-disable-line no-use-before-define
permissionHandler: PermissionHandler
getAll(): import('@remixproject/plugin-utils').Profile<any>[]
getIds(): string[]
@ -70,11 +70,11 @@ export class PluginManagerComponent extends ViewPlugin extends Plugin implements
constructor(appManager: RemixAppManager, engine: Engine)
appManager: RemixAppManager
pluginSettings: PluginManagerSettings
app: PluginApi<any>
app: PluginApi<any> // eslint-disable-line no-undef
engine: Engine
htmlElement: HTMLDivElement
views: { root: null, items: {} }
localPlugin: LocalPlugin
localPlugin: LocalPlugin // eslint-disable-line no-use-before-define
pluginNames: string[]
inactivePlugins: Profile[]
activePlugins: Profile[]
@ -133,7 +133,7 @@ declare class LocalPlugin {
}
export interface PluginManagerContextProviderProps {
children: React.ReactNode
children: React.ReactNode // eslint-disable-line no-undef
pluginComponent: PluginManagerComponent
}
@ -153,7 +153,7 @@ declare class PluginLoader {
set(plugin: any, actives: any): void
get(): any
}
// eslint-disable-next-line no-redeclare
export type PluginManagerSettings = {
openDialog: () => void
onValidation: () => void
@ -197,6 +197,7 @@ export type PluginManagerProfile = Profile & {
type: 'iframe' | 'ws'
hash: string
}
// eslint-disable-next-line no-redeclare
export type LocalPlugin = {
create: () => Profile
updateName: (target: string) => void

@ -79,7 +79,7 @@ export const PublishToStorage = (props: RemixUiPublishToStorageProps) => {
resetStorage()
}
const modal = async (title: string, message: string | JSX.Element) => {
const modal = async (title: string, message: string | JSX.Element) => { // eslint-disable-line no-undef
await setState(prevState => {
return {
...prevState,

@ -42,7 +42,6 @@ export const listenToEvents = (compileTabLogic: CompileTabLogic, api) => (dispat
api.onContentChanged = () => {
dispatch(setEditorMode('contentChanged'))
}
compileTabLogic.compiler.event.register('loadingCompiler', () => {
dispatch(setCompilerMode('loadingCompiler'))
})

@ -80,6 +80,7 @@ export class CompileTabLogic {
return new Promise((resolve, reject) => {
this.api.readFile(target).then((content) => {
const sources = { [target]: { content } }
this.event.emit('removeAnnotations')
this.event.emit('startingCompilation')
// setTimeout fix the animation on chrome... (animation triggered by 'staringCompilation')
setTimeout(() => { this.compiler.compile(sources, target); resolve(true) }, 100)
@ -122,7 +123,6 @@ export class CompileTabLogic {
}
// TODO readd saving current file
this.api.saveCurrentFile()
this.event.emit('removeAnnotations')
var currentFile = this.api.currentFile
return this.compileFile(currentFile)
} catch (err) {

@ -73,7 +73,7 @@ export const SolidityCompiler = (props: SolidityCompilerProps) => {
setCurrentVersion(value)
api.setCompilerParameters({ version: value })
}
// eslint-disable-next-line no-undef
const modal = async (title: string, message: string | JSX.Element, okLabel: string, okFn: () => void, cancelLabel?: string, cancelFn?: () => void) => {
await setState(prevState => {
return {

@ -10,8 +10,8 @@ export interface CompilerContainerProps {
api: ICompilerApi,
compileTabLogic: CompileTabLogic,
isHardhatProject: boolean,
tooltip: (message: string | JSX.Element) => void,
modal: (title: string, message: string | JSX.Element, okLabel: string, okFn: () => void, cancelLabel?: string, cancelFn?: () => void) => void,
tooltip: (message: string | JSX.Element) => void, // eslint-disable-line no-undef
modal: (title: string, message: string | JSX.Element, okLabel: string, okFn: () => void, cancelLabel?: string, cancelFn?: () => void) => void, // eslint-disable-line no-undef
compiledFileName: string,
updateCurrentVersion: any,
configurationSettings: ConfigurationSettings
@ -21,6 +21,6 @@ export interface ContractSelectionProps {
contractMap: {
file: string
} | Record<string, any>,
modal: (title: string, message: string | JSX.Element, okLabel: string, okFn: () => void, cancelLabel?: string, cancelFn?: () => void) => void,
modal: (title: string, message: string | JSX.Element, okLabel: string, okFn: () => void, cancelLabel?: string, cancelFn?: () => void) => void, // eslint-disable-line no-undef
contractsDetails: Record<string, any>
}

@ -1,4 +1,4 @@
import React, { useEffect, useState, useReducer } from 'react'
import React, { useEffect, useState, useReducer } from 'react' // eslint-disable-line
import Button from './Button/StaticAnalyserButton' // eslint-disable-line
import { util } from '@remix-project/remix-lib'
import _ from 'lodash'

@ -0,0 +1,4 @@
{
"presets": ["@nrwl/react/babel"],
"plugins": []
}

@ -0,0 +1,19 @@
{
"env": {
"browser": true,
"es6": true
},
"extends": "../../../.eslintrc",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 11,
"sourceType": "module"
},
"rules": {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "error"
}
}

@ -0,0 +1,7 @@
# remix-ui-terminal
This library was generated with [Nx](https://nx.dev).
## Running unit tests
Run `nx test remix-ui-terminal` to execute the unit tests via [Jest](https://jestjs.io).

@ -0,0 +1,4 @@
{
"name": "remix-ui-terminal",
"version": "0.0.1"
}

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

Loading…
Cancel
Save