Commit 7cc349b6 authored by bunsenstraat's avatar bunsenstraat

Merge branch 'e2epluginapi2' of https://github.com/ethereum/remix-project into e2epluginapi2

parents 4a9a9c28 6776be61
...@@ -30,6 +30,7 @@ soljson.js ...@@ -30,6 +30,7 @@ soljson.js
*.launch *.launch
.settings/ .settings/
*.sublime-workspace *.sublime-workspace
.vscode/
# IDE - VSCode # IDE - VSCode
.vscode/* .vscode/*
......
...@@ -4,6 +4,9 @@ import { CompilationOutput, Sources } from '@remix-ui/debugger-ui' ...@@ -4,6 +4,9 @@ import { CompilationOutput, Sources } from '@remix-ui/debugger-ui'
import type { CompilationResult } from '@remix-project/remix-solidity-ts' import type { CompilationResult } from '@remix-project/remix-solidity-ts'
export const DebuggerApiMixin = (Base) => class extends Base { export const DebuggerApiMixin = (Base) => class extends Base {
initialWeb3
initDebuggerApi () { initDebuggerApi () {
this.debugHash = null this.debugHash = null
...@@ -16,6 +19,8 @@ export const DebuggerApiMixin = (Base) => class extends Base { ...@@ -16,6 +19,8 @@ export const DebuggerApiMixin = (Base) => class extends Base {
} }
} }
this._web3 = new Web3(this.web3Provider) 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) remixDebug.init.extendWeb3(this._web3)
this.offsetToLineColumnConverter = { this.offsetToLineColumnConverter = {
...@@ -123,7 +128,9 @@ export const DebuggerApiMixin = (Base) => class extends Base { ...@@ -123,7 +128,9 @@ export const DebuggerApiMixin = (Base) => class extends Base {
debug (hash, web3?) { debug (hash, web3?) {
this.debugHash = hash 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) if (this.onDebugRequestedListener) this.onDebugRequestedListener(hash, web3)
} }
......
...@@ -17,7 +17,7 @@ function addFile (browser: NightwatchBrowser, name: string, content: NightwatchC ...@@ -17,7 +17,7 @@ function addFile (browser: NightwatchBrowser, name: string, content: NightwatchC
browser.clickLaunchIcon('udapp') browser.clickLaunchIcon('udapp')
.clickLaunchIcon('filePanel') .clickLaunchIcon('filePanel')
.click('li[data-id="treeViewLitreeViewItemREADME.txt"]') // focus on root directory .click('li[data-id="treeViewLitreeViewItemREADME.txt"]') // focus on root directory
.click('.newFile') .click('[data-id="fileExplorerNewFilecreateNewFile"]')
.waitForElementContainsText('*[data-id$="/blank"]', '', 60000) .waitForElementContainsText('*[data-id$="/blank"]', '', 60000)
.sendKeys('*[data-id$="/blank"] .remixui_items', name) .sendKeys('*[data-id$="/blank"] .remixui_items', name)
.sendKeys('*[data-id$="/blank"] .remixui_items', browser.Keys.ENTER) .sendKeys('*[data-id$="/blank"] .remixui_items', browser.Keys.ENTER)
......
...@@ -6,6 +6,7 @@ class ExecuteScript extends EventEmitter { ...@@ -6,6 +6,7 @@ class ExecuteScript extends EventEmitter {
this.api this.api
.clearEditableContent('*[data-id="terminalCliInput"]') .clearEditableContent('*[data-id="terminalCliInput"]')
.click('*[data-id="terminalCli"]') .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"]', script)
.sendKeys('*[data-id="terminalCliInput"]', this.api.Keys.ENTER) .sendKeys('*[data-id="terminalCliInput"]', this.api.Keys.ENTER)
.sendKeys('*[data-id="terminalCliInput"]', this.api.Keys.ENTER) .sendKeys('*[data-id="terminalCliInput"]', this.api.Keys.ENTER)
......
...@@ -7,11 +7,12 @@ import EventEmitter from 'events' ...@@ -7,11 +7,12 @@ import EventEmitter from 'events'
class JournalLastChildIncludes extends EventEmitter { class JournalLastChildIncludes extends EventEmitter {
command (this: NightwatchBrowser, val: string): NightwatchBrowser { command (this: NightwatchBrowser, val: string): NightwatchBrowser {
this.api this.api
.waitForElementVisible('*[data-id="terminalJournal"] > div:last-child', 10000) .waitForElementVisible('*[data-id="terminalJournal"]', 10000)
.getText('*[data-id="terminalJournal"] > div:last-child', (result) => { .pause(1000)
.getText('*[data-id="terminalJournal"]', (result) => {
console.log('JournalLastChildIncludes', result.value) 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}`) 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') this.emit('complete')
}) })
return this return this
......
...@@ -24,8 +24,8 @@ class TestFunction extends EventEmitter { ...@@ -24,8 +24,8 @@ class TestFunction extends EventEmitter {
.perform((done) => { .perform((done) => {
browser.waitForElementVisible(`[data-id="block_tx${txHash}"]`, 60000) browser.waitForElementVisible(`[data-id="block_tx${txHash}"]`, 60000)
.click(`[data-id="block_tx${txHash}"]`) .click(`[data-id="block_tx${txHash}"]`)
.pause(3000)
.waitForElementVisible(`*[data-id="txLoggerTable${txHash}"]`, 60000) .waitForElementVisible(`*[data-id="txLoggerTable${txHash}"]`, 60000)
.pause(10000)
// fetch and format transaction logs as key => pair object // fetch and format transaction logs as key => pair object
.elements('css selector', `*[data-shared="key_${txHash}"]`, (res) => { .elements('css selector', `*[data-shared="key_${txHash}"]`, (res) => {
Array.isArray(res.value) && res.value.forEach(function (jsonWebElement) { Array.isArray(res.value) && res.value.forEach(function (jsonWebElement) {
...@@ -58,7 +58,6 @@ class TestFunction extends EventEmitter { ...@@ -58,7 +58,6 @@ class TestFunction extends EventEmitter {
.perform(() => { .perform(() => {
Object.keys(expectedValue).forEach(key => { Object.keys(expectedValue).forEach(key => {
let equal = false let equal = false
try { try {
const receivedValue = JSON.parse(logs[key]) const receivedValue = JSON.parse(logs[key])
......
...@@ -17,6 +17,7 @@ function verifyContracts (browser: NightwatchBrowser, compiledContractNames: str ...@@ -17,6 +17,7 @@ function verifyContracts (browser: NightwatchBrowser, compiledContractNames: str
browser browser
.clickLaunchIcon('solidity') .clickLaunchIcon('solidity')
.pause(opts.wait) .pause(opts.wait)
.pause(5000)
.waitForElementPresent('*[data-id="compiledContracts"] option', 60000) .waitForElementPresent('*[data-id="compiledContracts"] option', 60000)
.perform((done) => { .perform((done) => {
if (opts.version) { if (opts.version) {
......
...@@ -81,8 +81,16 @@ module.exports = { ...@@ -81,8 +81,16 @@ module.exports = {
'Deploy and use Ballot using external web3': function (browser: NightwatchBrowser) { 'Deploy and use Ballot using external web3': function (browser: NightwatchBrowser) {
browser browser
.click('*[data-id="settingsWeb3Mode"]') .click('option[value="web3"]')
.pause(5000)
.modalFooterOKClick() .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') .clickLaunchIcon('solidity')
.testContracts('Untitled.sol', sources[0]['Untitled.sol'], ['Ballot']) .testContracts('Untitled.sol', sources[0]['Untitled.sol'], ['Ballot'])
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
......
...@@ -21,7 +21,7 @@ module.exports = { ...@@ -21,7 +21,7 @@ module.exports = {
browser browser
.addFile('test_jsCompile.js', { content: jsCompile }) .addFile('test_jsCompile.js', { content: jsCompile })
.executeScript('remix.exeCurrent()') .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"]') .click('*[data-id="terminalClearConsole"]')
}, },
......
...@@ -187,7 +187,8 @@ module.exports = { ...@@ -187,7 +187,8 @@ module.exports = {
browser browser
.addFile('test_jsGetTrace.js', { content: jsGetTrace }) .addFile('test_jsGetTrace.js', { content: jsGetTrace })
.executeScript('remix.exeCurrent()') .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) { 'Should call the debugger api: debug': function (browser: NightwatchBrowser) {
......
...@@ -50,11 +50,11 @@ module.exports = { ...@@ -50,11 +50,11 @@ module.exports = {
'Toggles Terminal': function (browser: NightwatchBrowser) { 'Toggles Terminal': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('div[data-id="terminalContainer"]') browser.waitForElementVisible('div[data-id="terminalContainer"]')
.assert.visible('div[data-id="terminalContainerDisplay"]') .assert.elementPresent('div[data-id="terminalContainerDisplay"]')
.click('i[data-id="terminalToggleIcon"]') .click('i[data-id="terminalToggleIcon"]')
.checkElementStyle('div[data-id="terminalToggleMenu"]', 'height', '35px') .checkElementStyle('div[data-id="terminalToggleMenu"]', 'height', '35px')
.click('i[data-id="terminalToggleIcon"]') .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) { 'Switch Tabs using tabs icon': function (browser: NightwatchBrowser) {
......
...@@ -34,8 +34,8 @@ module.exports = { ...@@ -34,8 +34,8 @@ module.exports = {
browser.waitForElementVisible('*[data-id="editorInput"]') browser.waitForElementVisible('*[data-id="editorInput"]')
.waitForElementVisible('*[class="ace_content"]') .waitForElementVisible('*[class="ace_content"]')
.click('*[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') .sendKeys('*[class="ace_text-input"]', 'error')
.pause(2000)
.waitForElementVisible('.ace_error', 120000) .waitForElementVisible('.ace_error', 120000)
.checkAnnotations('error', 28) .checkAnnotations('error', 28)
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
...@@ -92,9 +92,13 @@ module.exports = { ...@@ -92,9 +92,13 @@ module.exports = {
.openFile('sourcehighlight.js') .openFile('sourcehighlight.js')
.executeScript('remix.exeCurrent()') .executeScript('remix.exeCurrent()')
.editorScroll('down', 60) .editorScroll('down', 60)
.pause(1000)
.waitForElementPresent('.highlightLine32', 60000) .waitForElementPresent('.highlightLine32', 60000)
.pause(1000)
.checkElementStyle('.highlightLine32', 'background-color', 'rgb(8, 108, 181)') .checkElementStyle('.highlightLine32', 'background-color', 'rgb(8, 108, 181)')
.pause(1000)
.waitForElementPresent('.highlightLine40', 60000) .waitForElementPresent('.highlightLine40', 60000)
.pause(1000)
.checkElementStyle('.highlightLine40', 'background-color', 'rgb(8, 108, 181)') .checkElementStyle('.highlightLine40', 'background-color', 'rgb(8, 108, 181)')
.waitForElementPresent('.highlightLine50', 60000) .waitForElementPresent('.highlightLine50', 60000)
.checkElementStyle('.highlightLine50', 'background-color', 'rgb(8, 108, 181)') .checkElementStyle('.highlightLine50', 'background-color', 'rgb(8, 108, 181)')
......
...@@ -11,6 +11,7 @@ module.exports = { ...@@ -11,6 +11,7 @@ module.exports = {
browser browser
.addFile('file.js', { content: executeFile }) .addFile('file.js', { content: executeFile })
.executeScript('remix.exeCurrent()') .executeScript('remix.exeCurrent()')
.pause(1000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'file.js', 60000) .waitForElementContainsText('*[data-id="terminalJournal"]', 'file.js', 60000)
}, },
...@@ -72,7 +73,8 @@ module.exports = { ...@@ -72,7 +73,8 @@ module.exports = {
browser browser
.addFile('readdirFile.js', { content: executeReaddir }) .addFile('readdirFile.js', { content: executeReaddir })
.executeScript('remix.exeCurrent()') .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) { 'Should execute `remove` api from file manager external api': function (browser: NightwatchBrowser) {
...@@ -175,8 +177,8 @@ const executeMkdir = ` ...@@ -175,8 +177,8 @@ const executeMkdir = `
const executeReaddir = ` const executeReaddir = `
const run = async () => { const run = async () => {
const result = await remix.call('fileManager', 'readdir', '/') const result = await remix.call('fileManager', 'readdir', '/')
const output = result["Test_Folder"].isDirectory
console.log('Test_Folder isDirectory ', result["Test_Folder"].isDirectory) console.log('Test_Folder isDirectory ', output)
} }
run() run()
......
...@@ -77,6 +77,7 @@ function checkDeployShouldFail (browser: NightwatchBrowser, callback: VoidFuncti ...@@ -77,6 +77,7 @@ function checkDeployShouldFail (browser: NightwatchBrowser, callback: VoidFuncti
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.selectContract('test') // deploy lib .selectContract('test') // deploy lib
.createContract('') .createContract('')
.pause(2000)
.getText('div[class^="terminal"]', (value) => { .getText('div[class^="terminal"]', (value) => {
console.log('value: ', value) console.log('value: ', value)
}) })
......
...@@ -11,6 +11,7 @@ module.exports = { ...@@ -11,6 +11,7 @@ module.exports = {
browser browser
.waitForElementVisible('*[data-id="terminalCli"]', 10000) .waitForElementVisible('*[data-id="terminalCli"]', 10000)
.executeScript('console.log(1 + 1)') .executeScript('console.log(1 + 1)')
.pause(2000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '2', 60000) .waitForElementContainsText('*[data-id="terminalJournal"]', '2', 60000)
}, },
...@@ -30,24 +31,14 @@ module.exports = { ...@@ -30,24 +31,14 @@ module.exports = {
.assert.visible('*[data-id="autoCompletePopUpAutoCompleteItem"]') .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) { 'Async/Await Script': function (browser: NightwatchBrowser) {
browser browser
.addFile('asyncAwait.js', { content: asyncAwait }) .addFile('asyncAwait.js', { content: asyncAwait })
.openFile('asyncAwait.js') .openFile('asyncAwait.js')
.executeScript('remix.execute(\'asyncAwait.js\')') .executeScript('remix.execute("asyncAwait.js")')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Waiting Promise', 60000) .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) { 'Call Remix File Manager from a script': function (browser: NightwatchBrowser) {
...@@ -62,19 +53,19 @@ module.exports = { ...@@ -62,19 +53,19 @@ module.exports = {
'Call web3.eth.getAccounts() using JavaScript VM': function (browser: NightwatchBrowser) { 'Call web3.eth.getAccounts() using JavaScript VM': function (browser: NightwatchBrowser) {
browser browser
.executeScript('web3.eth.getAccounts()') .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) { 'Call web3.eth.getAccounts() using Web3 Provider': function (browser: NightwatchBrowser) {
browser browser
.click('*[data-id="terminalClearConsole"]') // clear the terminal .click('*[data-id="terminalClearConsole"]') // clear the terminal
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.click('*[data-id="settingsWeb3Mode"]') .click('*[data-id="settingsWeb3Mode"]')
.modalFooterOKClick() .modalFooterOKClick()
.executeScript('web3.eth.getAccounts()') .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) // 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) .waitForElementContainsText('*[data-id="terminalJournal"]', '","', 60000)
}, },
'Call Remix File Resolver (external URL) from a script': function (browser: NightwatchBrowser) { 'Call Remix File Resolver (external URL) from a script': function (browser: NightwatchBrowser) {
...@@ -124,15 +115,18 @@ module.exports = { ...@@ -124,15 +115,18 @@ module.exports = {
.clickLaunchIcon('solidity') .clickLaunchIcon('solidity')
.click('*[data-id="compilerContainerCompileBtn"]') // compile Owner .click('*[data-id="compilerContainerCompileBtn"]') // compile Owner
.executeScript('remix.execute(\'deployWithEthersJs.js\')') .executeScript('remix.execute(\'deployWithEthersJs.js\')')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Contract Address: 0xd9145CCE52D386f254917e481eB44e9943F39138', 60000) .waitForElementContainsText('*[data-id="terminalJournal"]', 'Contract Address:', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '0xd9145CCE52D386f254917e481eB44e9943F39138', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Deployment successful.', 60000) .waitForElementContainsText('*[data-id="terminalJournal"]', 'Deployment successful.', 60000)
.addAtAddressInstance('0xd9145CCE52D386f254917e481eB44e9943F39138', true, true) .addAtAddressInstance('0xd9145CCE52D386f254917e481eB44e9943F39138', true, true)
.click('*[data-id="terminalClearConsole"]') // clear the terminal .click('*[data-id="terminalClearConsole"]') // clear the terminal
.waitForElementPresent('*[data-id="universalDappUiContractActionWrapper"]', 60000) .waitForElementPresent('*[data-id="universalDappUiContractActionWrapper"]', 60000)
.click('*[data-id="universalDappUiTitleExpander"]') .click('*[data-id="universalDappUiTitleExpander"]')
.clickFunction('changeOwner - transact (not payable)', { types: 'address newOwner', values: '0xd9145CCE52D386f254917e481eB44e9943F39138' }) // execute the "changeOwner" function .clickFunction('changeOwner - transact (not payable)', { types: 'address newOwner', values: '0xd9145CCE52D386f254917e481eB44e9943F39138' }) // execute the "changeOwner" function
.waitForElementContainsText('*[data-id="terminalJournal"]', 'previousOwner0x5B38Da6a701c568545dCfcB03FcB875f56beddC4', 60000) // check that the script is logging the event .waitForElementContainsText('*[data-id="terminalJournal"]', 'previousOwner', 60000) // check that the script is logging the event
.waitForElementContainsText('*[data-id="terminalJournal"]', 'newOwner0xd9145CCE52D386f254917e481eB44e9943F39138', 60000) .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() .end()
} }
} }
......
...@@ -99,7 +99,7 @@ module.exports = { ...@@ -99,7 +99,7 @@ module.exports = {
'decoded output': { 'decoded output': {
0: 'uint256: _uret 2343242', 0: 'uint256: _uret 2343242',
1: 'int256: _iret -4324324', 1: 'int256: _iret -4324324',
2: 'string: _strret string _ string _ string _ string _ string _ string _ string _ string _ string _ string _' 2: 'string: _strret string _ string _ string _ string _ string _ string _ string _ string _ string _ string _'
} }
}) })
.pause(500) .pause(500)
...@@ -147,12 +147,13 @@ module.exports = { ...@@ -147,12 +147,13 @@ module.exports = {
.waitForElementPresent('.instance:nth-of-type(3)') .waitForElementPresent('.instance:nth-of-type(3)')
.click('.instance:nth-of-type(3) > div > button') .click('.instance:nth-of-type(3) > div > button')
.clickFunction('g - transact (not payable)') .clickFunction('g - transact (not payable)')
.pause(5000)
.journalLastChildIncludes('Error provided by the contract:') .journalLastChildIncludes('Error provided by the contract:')
.journalLastChildIncludes('CustomError : error description') .journalLastChildIncludes('CustomError : error description')
.journalLastChildIncludes('Parameters:') .journalLastChildIncludes('Parameters:')
.journalLastChildIncludes('"value": "2",') .journalLastChildIncludes('"value": "2"')
.journalLastChildIncludes('"value": "3",') .journalLastChildIncludes('"value": "3"')
.journalLastChildIncludes('"value": "error_string_2",') .journalLastChildIncludes('"value": "error_string_2"')
.journalLastChildIncludes('"documentation": "param1"') .journalLastChildIncludes('"documentation": "param1"')
.journalLastChildIncludes('"documentation": "param2"') .journalLastChildIncludes('"documentation": "param2"')
.journalLastChildIncludes('"documentation": "param3"') .journalLastChildIncludes('"documentation": "param3"')
...@@ -170,9 +171,9 @@ module.exports = { ...@@ -170,9 +171,9 @@ module.exports = {
.journalLastChildIncludes('Error provided by the contract:') .journalLastChildIncludes('Error provided by the contract:')
.journalLastChildIncludes('CustomError : error description') .journalLastChildIncludes('CustomError : error description')
.journalLastChildIncludes('Parameters:') .journalLastChildIncludes('Parameters:')
.journalLastChildIncludes('"value": "2",') .journalLastChildIncludes('"value": "2"')
.journalLastChildIncludes('"value": "3",') .journalLastChildIncludes('"value": "3"')
.journalLastChildIncludes('"value": "error_string_2",') .journalLastChildIncludes('"value": "error_string_2"')
.journalLastChildIncludes('"documentation": "param1"') .journalLastChildIncludes('"documentation": "param1"')
.journalLastChildIncludes('"documentation": "param2"') .journalLastChildIncludes('"documentation": "param2"')
.journalLastChildIncludes('"documentation": "param3"') .journalLastChildIncludes('"documentation": "param3"')
......
...@@ -19,7 +19,7 @@ module.exports = { ...@@ -19,7 +19,7 @@ module.exports = {
browser browser
.pause(5000) .pause(5000)
.refresh() .refresh()
.pause(2000) .pause(5000)
.getEditorValue((content) => { .getEditorValue((content) => {
browser.assert.ok(content.indexOf('contract Ballot {') !== -1, 'content doesn\'t include Ballot contract') browser.assert.ok(content.indexOf('contract Ballot {') !== -1, 'content doesn\'t include Ballot contract')
}) })
...@@ -35,19 +35,28 @@ module.exports = { ...@@ -35,19 +35,28 @@ module.exports = {
.clickLaunchIcon('filePanel') .clickLaunchIcon('filePanel')
.click('*[data-id="workspaceCreate"]') // create workspace_name .click('*[data-id="workspaceCreate"]') // create workspace_name
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
.waitForElementVisible('[data-id="workspacesModalDialogModalDialogModalFooter-react"] > span')
// eslint-disable-next-line dot-notation // eslint-disable-next-line dot-notation
.execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_name' }) .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"]') .waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]')
.pause(1000)
.addFile('test.sol', { content: 'test' }) .addFile('test.sol', { content: 'test' })
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtest.sol"]') .waitForElementVisible('*[data-id="treeViewLitreeViewItemtest.sol"]')
.click('*[data-id="workspaceCreate"]') // create workspace_name_1 .click('*[data-id="workspaceCreate"]') // create workspace_name_1
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
// eslint-disable-next-line dot-notation // eslint-disable-next-line dot-notation
.execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_name_1' }) .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"]') .waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]')
.pause(2000)
.waitForElementNotPresent('*[data-id="treeViewLitreeViewItemtest.sol"]') .waitForElementNotPresent('*[data-id="treeViewLitreeViewItemtest.sol"]')
.pause(2000)
.click('*[data-id="workspacesSelect"] option[value="workspace_name"]') .click('*[data-id="workspacesSelect"] option[value="workspace_name"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') .waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]')
}, },
...@@ -59,10 +68,15 @@ module.exports = { ...@@ -59,10 +68,15 @@ module.exports = {
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextRename"]') .waitForElementVisible('*[data-id="modalDialogCustomPromptTextRename"]')
// eslint-disable-next-line dot-notation // eslint-disable-next-line dot-notation
.execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextRename"]')['value'] = 'workspace_name_renamed' }) .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"]') .click('*[data-id="workspacesSelect"] option[value="workspace_name_1"]')
.pause(2000)
.waitForElementNotPresent('*[data-id="treeViewLitreeViewItemtest.sol"]') .waitForElementNotPresent('*[data-id="treeViewLitreeViewItemtest.sol"]')
.click('*[data-id="workspacesSelect"] option[value="workspace_name_renamed"]') .click('*[data-id="workspacesSelect"] option[value="workspace_name_renamed"]')
.pause(2000)
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtest.sol"]') .waitForElementVisible('*[data-id="treeViewLitreeViewItemtest.sol"]')
}, },
...@@ -70,8 +84,10 @@ module.exports = { ...@@ -70,8 +84,10 @@ module.exports = {
browser browser
.click('*[data-id="workspacesSelect"] option[value="workspace_name_1"]') .click('*[data-id="workspacesSelect"] option[value="workspace_name_1"]')
.click('*[data-id="workspaceDelete"]') // delete workspace_name_1 .click('*[data-id="workspaceDelete"]') // delete workspace_name_1
.waitForElementVisible('*[data-id="workspacesModalDialogModalDialogModalFooter-react"] .modal-ok') .waitForElementVisible('[data-id="workspacesModalDialogModalDialogModalFooter-react"] > span')
.click('*[data-id="workspacesModalDialogModalDialogModalFooter-react"] .modal-ok') .pause(2000)
.click('[data-id="workspacesModalDialogModalDialogModalFooter-react"] > span')
.pause(2000)
.waitForElementNotPresent('*[data-id="workspacesSelect"] option[value="workspace_name_1"]') .waitForElementNotPresent('*[data-id="workspacesSelect"] option[value="workspace_name_1"]')
.end() .end()
}, },
......
...@@ -287,7 +287,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org ...@@ -287,7 +287,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
registry.put({ api: offsetToLineColumnConverter, name: 'offsettolinecolumnconverter' }) registry.put({ api: offsetToLineColumnConverter, name: 'offsettolinecolumnconverter' })
// -------------------Terminal---------------------------------------- // -------------------Terminal----------------------------------------
makeUdapp(blockchain, compilersArtefacts, (domEl) => terminal.logHtml(domEl))
const terminal = new Terminal( const terminal = new Terminal(
{ appManager, blockchain }, { appManager, blockchain },
{ {
...@@ -299,9 +299,9 @@ Please make a backup of your contracts and start using http://remix.ethereum.org ...@@ -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 newpos = (newpos < height - limitDown) ? newpos : height - limitDown
return height - newpos return height - newpos
} }
} },
registry
) )
makeUdapp(blockchain, compilersArtefacts, (domEl) => terminal.logHtml(domEl))
const contextualListener = new ContextualListener({ editor }) const contextualListener = new ContextualListener({ editor })
......
...@@ -31,7 +31,7 @@ export class MainPanel extends AbstractPanel { ...@@ -31,7 +31,7 @@ export class MainPanel extends AbstractPanel {
render () { render () {
return yo` return yo`
<div class=${css.pluginsContainer} data-id="mainPanelPluginsContainer"> <div class=${css.pluginsContainer} data-id="mainPanelPluginsContainer" id='mainPanelPluginsContainer-id'>
${this.view} ${this.view}
</div>` </div>`
} }
......
This diff is collapsed.
...@@ -218,11 +218,12 @@ class ContractDropdownUI { ...@@ -218,11 +218,12 @@ class ContractDropdownUI {
if (this.selectContractNames.value === '') this.enableAtAddress(false) if (this.selectContractNames.value === '') this.enableAtAddress(false)
} else { } else {
this.loadType = 'other' this.loadType = 'other'
this.createPanel.style.display = 'none' this.createPanel.style.display = 'block'
this.orLabel.style.display = 'none' this.orLabel.style.display = 'block'
this.compFails.style.display = 'none' this.contractNamesContainer.style.display = 'block'
this.contractNamesContainer.style.display = 'none' this.selectContractNames.style.display = 'block'
this.abiLabel.style.display = 'none' this.abiLabel.style.display = 'none'
if (this.selectContractNames.value === '') this.enableAtAddress(false)
} }
} }
......
...@@ -247,6 +247,14 @@ module.exports = class TestTab extends ViewPlugin { ...@@ -247,6 +247,14 @@ module.exports = class TestTab extends ViewPlugin {
testCallback (result, runningTests) { testCallback (result, runningTests) {
this.testsOutput.hidden = false 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') { if (result.type === 'contract') {
this.testSuite = result.value this.testSuite = result.value
if (this.testSuites) { if (this.testSuites) {
...@@ -268,29 +276,18 @@ module.exports = class TestTab extends ViewPlugin { ...@@ -268,29 +276,18 @@ module.exports = class TestTab extends ViewPlugin {
<div <div
id="${this.runningTestFileName}" id="${this.runningTestFileName}"
data-id="testTabSolidityUnitTestsOutputheader" 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()} 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> </div>
`) `)
} else if (result.type === 'testFailure') { } else if (result.type === 'testFailure') {
if (result.hhLogs && result.hhLogs.length) this.printHHLogs(result.hhLogs, result.value) if (result.hhLogs && result.hhLogs.length) this.printHHLogs(result.hhLogs, result.value)
if (!result.assertMethod) { 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` this.testsOutput.appendChild(yo`
<div <div
class="bg-light mb-2 px-2 ${css.testLog} d-flex flex-column text-danger border-0" 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 { ...@@ -315,7 +312,10 @@ module.exports = class TestTab extends ViewPlugin {
id="UTContext${result.context}" id="UTContext${result.context}"
onclick=${() => this.highlightLocation(result.location, runningTests, result.filename)} onclick=${() => this.highlightLocation(result.location, runningTests, result.filename)}
> >
<span> ✘ ${result.value}</span> <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="text-dark">Error Message:</span>
<span class="pb-2 text-break">"${result.errMsg}"</span> <span class="pb-2 text-break">"${result.errMsg}"</span>
<span class="text-dark">Assertion:</span> <span class="text-dark">Assertion:</span>
...@@ -499,7 +499,7 @@ module.exports = class TestTab extends ViewPlugin { ...@@ -499,7 +499,7 @@ module.exports = class TestTab extends ViewPlugin {
usingWorker: canUseWorker(currentVersion), usingWorker: canUseWorker(currentVersion),
runs runs
} }
this.testRunner.runTestSources(runningTest, compilerConfig, () => {}, () => {}, (error, result) => { this.testRunner.runTestSources(runningTest, compilerConfig, () => {}, () => {}, null, (error, result) => {
if (error) return reject(error) if (error) return reject(error)
resolve(result) resolve(result)
}, (url, cb) => { }, (url, cb) => {
...@@ -527,17 +527,22 @@ module.exports = class TestTab extends ViewPlugin { ...@@ -527,17 +527,22 @@ module.exports = class TestTab extends ViewPlugin {
usingWorker: canUseWorker(currentVersion), usingWorker: canUseWorker(currentVersion),
runs runs
} }
const deployCb = async (file, contractAddress) => {
const compilerData = await this.call('compilerArtefacts', 'getCompilerAbstract', file)
await this.call('compilerArtefacts', 'addResolvedContract', contractAddress, compilerData)
}
this.testRunner.runTestSources( this.testRunner.runTestSources(
runningTests, runningTests,
compilerConfig, compilerConfig,
(result) => this.testCallback(result, runningTests), (result) => this.testCallback(result, runningTests),
(_err, result, cb) => this.resultsCallback(_err, result, cb), (_err, result, cb) => this.resultsCallback(_err, result, cb),
deployCb,
(error, result) => { (error, result) => {
this.updateFinalResult(error, result, testFilePath) this.updateFinalResult(error, result, testFilePath)
callback(error) callback(error)
}, (url, cb) => { }, (url, cb) => {
return this.contentImport.resolveAndSave(url).then((result) => cb(null, result)).catch((error) => cb(error.message)) return this.contentImport.resolveAndSave(url).then((result) => cb(null, result)).catch((error) => cb(error.message))
} }, { testFilePath }
) )
}).catch((error) => { }).catch((error) => {
if (error) return // eslint-disable-line if (error) return // eslint-disable-line
......
...@@ -93,7 +93,6 @@ class CmdInterpreterAPI { ...@@ -93,7 +93,6 @@ class CmdInterpreterAPI {
if (cb) cb() if (cb) cb()
return return
} }
self._components.terminal.commands.script(content) self._components.terminal.commands.script(content)
} }
......
...@@ -6,7 +6,7 @@ import { CompilerClientApi } from './compiler' ...@@ -6,7 +6,7 @@ import { CompilerClientApi } from './compiler'
const remix = new CompilerClientApi() const remix = new CompilerClientApi()
export const App = () => { export const App = () => {
return ( return (
<div> <div>
<SolidityCompiler api={remix} /> <SolidityCompiler api={remix} />
......
...@@ -30,7 +30,6 @@ const defaultCompilerParameters = { ...@@ -30,7 +30,6 @@ const defaultCompilerParameters = {
evmVersion: null, // compiler default evmVersion: null, // compiler default
language: 'Solidity' language: 'Solidity'
} }
export class CompilerClientApi extends CompilerApiMixin(PluginClient) implements ICompilerApi { export class CompilerClientApi extends CompilerApiMixin(PluginClient) implements ICompilerApi {
constructor () { constructor () {
super() super()
......
...@@ -19,9 +19,9 @@ ...@@ -19,9 +19,9 @@
} }
], ],
"dependencies": { "dependencies": {
"@ethereumjs/block": "^3.4.0", "@ethereumjs/block": "^3.5.1",
"@ethereumjs/tx": "^3.3.0", "@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.0", "@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-astwalker": "^0.0.37", "@remix-project/remix-astwalker": "^0.0.37",
"@remix-project/remix-lib": "^0.5.7", "@remix-project/remix-lib": "^0.5.7",
"async": "^2.6.2", "async": "^2.6.2",
......
...@@ -34,9 +34,9 @@ ...@@ -34,9 +34,9 @@
] ]
}, },
"dependencies": { "dependencies": {
"@ethereumjs/block": "^3.4.0", "@ethereumjs/block": "^3.5.1",
"@ethereumjs/tx": "^3.3.0", "@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.0", "@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.7", "@remix-project/remix-lib": "^0.5.7",
"@types/tape": "^4.2.33", "@types/tape": "^4.2.33",
"async": "^2.6.2", "async": "^2.6.2",
......
...@@ -4,7 +4,7 @@ import { CompilerAbstract } from '@remix-project/remix-solidity' ...@@ -4,7 +4,7 @@ import { CompilerAbstract } from '@remix-project/remix-solidity'
const profile = { const profile = {
name: 'compilerArtefacts', name: 'compilerArtefacts',
methods: ['get', 'addResolvedContract'], methods: ['get', 'addResolvedContract', 'getCompilerAbstract'],
events: [], events: [],
version: '0.0.1' version: '0.0.1'
} }
......
...@@ -18,10 +18,10 @@ ...@@ -18,10 +18,10 @@
], ],
"main": "src/index.js", "main": "src/index.js",
"dependencies": { "dependencies": {
"@ethereumjs/block": "^3.4.0", "@ethereumjs/block": "^3.5.1",
"@ethereumjs/common": "^2.2.0", "@ethereumjs/common": "^2.5.0",
"@ethereumjs/tx": "^3.3.0", "@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.0", "@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-astwalker": "^0.0.37", "@remix-project/remix-astwalker": "^0.0.37",
"@remix-project/remix-lib": "^0.5.7", "@remix-project/remix-lib": "^0.5.7",
"@remix-project/remix-simulator": "^0.2.7", "@remix-project/remix-simulator": "^0.2.7",
......
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
], ],
"main": "src/index.js", "main": "src/index.js",
"dependencies": { "dependencies": {
"@ethereumjs/block": "^3.4.0", "@ethereumjs/block": "^3.5.1",
"@ethereumjs/tx": "^3.3.0", "@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.0", "@ethereumjs/vm": "^5.5.3",
"async": "^2.1.2", "async": "^2.1.2",
"ethereumjs-util": "^7.0.10", "ethereumjs-util": "^7.0.10",
"ethers": "^4.0.40", "ethers": "^4.0.40",
......
...@@ -14,10 +14,10 @@ ...@@ -14,10 +14,10 @@
], ],
"main": "src/index.js", "main": "src/index.js",
"dependencies": { "dependencies": {
"@ethereumjs/block": "^3.4.0", "@ethereumjs/block": "^3.5.1",
"@ethereumjs/common": "^2.2.0", "@ethereumjs/common": "^2.5.0",
"@ethereumjs/tx": "^3.3.0", "@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.0", "@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.7", "@remix-project/remix-lib": "^0.5.7",
"ansi-gray": "^0.1.1", "ansi-gray": "^0.1.1",
"async": "^3.1.0", "async": "^3.1.0",
......
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
} }
], ],
"dependencies": { "dependencies": {
"@ethereumjs/block": "^3.4.0", "@ethereumjs/block": "^3.5.1",
"@ethereumjs/tx": "^3.3.0", "@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.0", "@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.7", "@remix-project/remix-lib": "^0.5.7",
"async": "^2.6.2", "async": "^2.6.2",
"eslint-scope": "^5.0.0", "eslint-scope": "^5.0.0",
......
...@@ -35,10 +35,10 @@ ...@@ -35,10 +35,10 @@
}, },
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-tests#readme", "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-tests#readme",
"dependencies": { "dependencies": {
"@ethereumjs/block": "^3.4.0", "@ethereumjs/block": "^3.5.1",
"@ethereumjs/common": "^2.2.0", "@ethereumjs/common": "^2.5.0",
"@ethereumjs/tx": "^3.3.0", "@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.0", "@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.7", "@remix-project/remix-lib": "^0.5.7",
"@remix-project/remix-simulator": "^0.2.7", "@remix-project/remix-simulator": "^0.2.7",
"@remix-project/remix-solidity": "^0.4.7", "@remix-project/remix-solidity": "^0.4.7",
......
...@@ -171,8 +171,9 @@ export function compileFileOrFiles (filename: string, isDirectory: boolean, opts ...@@ -171,8 +171,9 @@ export function compileFileOrFiles (filename: string, isDirectory: boolean, opts
* @param cb Callback * @param cb Callback
*/ */
export function compileContractSources (sources: SrcIfc, compilerConfig: CompilerConfiguration, importFileCb: any, opts: any, cb): void { 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 accounts: string[] = opts.accounts || []
const filepath = opts.testFilePath || ''
// Iterate over sources keys. Inject test libraries. Inject test library import statements. // Iterate over sources keys. Inject test libraries. Inject test library import statements.
if (!('remix_tests.sol' in sources) && !('tests.sol' in sources)) { if (!('remix_tests.sol' in sources) && !('tests.sol' in sources)) {
sources['tests.sol'] = { content: require('../sol/tests.sol.js') } sources['tests.sol'] = { content: require('../sol/tests.sol.js') }
......
...@@ -11,7 +11,7 @@ import { compilationInterface } from './types' ...@@ -11,7 +11,7 @@ import { compilationInterface } from './types'
* @param callback Callback * @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 compiledObject = {}
const contracts = {} const contracts = {}
let accounts: string[] = [] let accounts: string[] = []
...@@ -70,7 +70,7 @@ export function deployAll (compileResult: compilationInterface, web3: Web3, with ...@@ -70,7 +70,7 @@ export function deployAll (compileResult: compilationInterface, web3: Web3, with
deployObject.send({ deployObject.send({
from: accounts[0], from: accounts[0],
gas: gas gas: gas
}).on('receipt', function (receipt) { }).on('receipt', async function (receipt) {
contractObject.options.address = receipt.contractAddress contractObject.options.address = receipt.contractAddress
contractObject.options.from = accounts[0] contractObject.options.from = accounts[0]
contractObject.options.gas = 5000 * 1000 contractObject.options.gas = 5000 * 1000
...@@ -79,6 +79,7 @@ export function deployAll (compileResult: compilationInterface, web3: Web3, with ...@@ -79,6 +79,7 @@ export function deployAll (compileResult: compilationInterface, web3: Web3, with
contracts[contractName] = contractObject contracts[contractName] = contractObject
contracts[contractName].filename = filename 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 callback(null, { receipt: { contractAddress: receipt.contractAddress } }) // TODO this will only work with JavaScriptV VM
}).on('error', function (err) { }).on('error', function (err) {
console.error(err) console.error(err)
......
...@@ -61,13 +61,13 @@ export function runTestFiles (filepath: string, isDirectory: boolean, web3: Web3 ...@@ -61,13 +61,13 @@ export function runTestFiles (filepath: string, isDirectory: boolean, web3: Web3
for (const filename in asts) { for (const filename in asts) {
if (filename.endsWith('_test.sol')) { sourceASTs[filename] = asts[filename].ast } 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 (err) {
// If contract deployment fails because of 'Out of Gas' error, try again with double gas // 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 // This is temporary, should be removed when remix-tests will have a dedicated UI to
// accept deployment params from UI // accept deployment params from UI
if (err.message.includes('The contract code couldn\'t be stored, please check your gas limit')) { 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 if (error) next([{ message: 'contract deployment failed after trying twice: ' + error.message, severity: 'error' }]) // IDE expects errors in array
else next(null, compilationResult, contracts) else next(null, compilationResult, contracts)
}) })
......
...@@ -39,7 +39,7 @@ export class UnitTestRunner { ...@@ -39,7 +39,7 @@ export class UnitTestRunner {
* @param importFileCb Import file callback * @param importFileCb Import file callback
* @param opts Options * @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 || {} opts = opts || {}
const sourceASTs: any = {} const sourceASTs: any = {}
const web3 = opts.web3 || await this.createWeb3Provider() const web3 = opts.web3 || await this.createWeb3Provider()
...@@ -53,19 +53,19 @@ export class UnitTestRunner { ...@@ -53,19 +53,19 @@ export class UnitTestRunner {
}) })
}, },
(next) => { (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) { function deployAllContracts (compilationResult: compilationInterface, asts: ASTInterface, next) {
for (const filename in asts) { for (const filename in asts) {
if (filename.endsWith('_test.sol')) { sourceASTs[filename] = asts[filename].ast } 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 (err) {
// If contract deployment fails because of 'Out of Gas' error, try again with double gas // 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 // This is temporary, should be removed when remix-tests will have a dedicated UI to
// accept deployment params from UI // accept deployment params from UI
if (err.message.includes('The contract code couldn\'t be stored, please check your gas limit')) { 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 if (error) next([{ message: 'contract deployment failed after trying twice: ' + error.message, severity: 'error' }]) // IDE expects errors in array
else next(null, compilationResult, contracts) else next(null, compilationResult, contracts)
}) })
......
...@@ -244,6 +244,7 @@ export function runTest (testName: string, testObject: any, contractDetails: Com ...@@ -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 }) } 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 method = testObject.methods[func.name].apply(testObject.methods[func.name], [])
const startTime = Date.now() const startTime = Date.now()
let debugTxHash:string
if (func.constant) { if (func.constant) {
sendParams = {} sendParams = {}
const tagTimestamp = 'remix_tests_tag' + Date.now() const tagTimestamp = 'remix_tests_tag' + Date.now()
...@@ -253,13 +254,16 @@ export function runTest (testName: string, testObject: any, contractDetails: Com ...@@ -253,13 +254,16 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
let tagTxHash let tagTxHash
if (web3.eth && web3.eth.getHashFromTagBySimulator) tagTxHash = await web3.eth.getHashFromTagBySimulator(tagTimestamp) if (web3.eth && web3.eth.getHashFromTagBySimulator) tagTxHash = await web3.eth.getHashFromTagBySimulator(tagTimestamp)
if (web3.eth && web3.eth.getHHLogsForTx) hhLogs = await web3.eth.getHHLogsForTx(tagTxHash) if (web3.eth && web3.eth.getHHLogsForTx) hhLogs = await web3.eth.getHHLogsForTx(tagTxHash)
debugTxHash = tagTxHash
if (result) { if (result) {
const resp: TestResultInterface = { const resp: TestResultInterface = {
type: 'testPass', type: 'testPass',
value: changeCase.sentenceCase(func.name), value: changeCase.sentenceCase(func.name),
filename: testObject.filename, filename: testObject.filename,
time: time, time: time,
context: testName context: testName,
web3,
debugTxHash
} }
if (hhLogs && hhLogs.length) resp.hhLogs = hhLogs if (hhLogs && hhLogs.length) resp.hhLogs = hhLogs
testCallback(undefined, resp) testCallback(undefined, resp)
...@@ -272,7 +276,9 @@ export function runTest (testName: string, testObject: any, contractDetails: Com ...@@ -272,7 +276,9 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
filename: testObject.filename, filename: testObject.filename,
time: time, time: time,
errMsg: 'function returned false', errMsg: 'function returned false',
context: testName context: testName,
web3,
debugTxHash
} }
if (hhLogs && hhLogs.length) resp.hhLogs = hhLogs if (hhLogs && hhLogs.length) resp.hhLogs = hhLogs
testCallback(undefined, resp) testCallback(undefined, resp)
...@@ -293,6 +299,7 @@ export function runTest (testName: string, testObject: any, contractDetails: Com ...@@ -293,6 +299,7 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
sendParams.gas = 10000000 * 8 sendParams.gas = 10000000 * 8
method.send(sendParams).on('receipt', async (receipt) => { method.send(sendParams).on('receipt', async (receipt) => {
try { try {
debugTxHash = receipt.transactionHash
if (web3.eth && web3.eth.getHHLogsForTx) hhLogs = await web3.eth.getHHLogsForTx(receipt.transactionHash) if (web3.eth && web3.eth.getHHLogsForTx) hhLogs = await web3.eth.getHHLogsForTx(receipt.transactionHash)
const time: number = (Date.now() - startTime) / 1000.0 const time: number = (Date.now() - startTime) / 1000.0
const assertionEventHashes = assertionEvents.map(e => Web3.utils.sha3(e.name + '(' + e.params.join() + ')')) const assertionEventHashes = assertionEvents.map(e => Web3.utils.sha3(e.name + '(' + e.params.join() + ')'))
...@@ -322,7 +329,8 @@ export function runTest (testName: string, testObject: any, contractDetails: Com ...@@ -322,7 +329,8 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
returned: testEvent[3], returned: testEvent[3],
expected: testEvent[4], expected: testEvent[4],
location, location,
web3 web3,
debugTxHash
} }
if (hhLogs && hhLogs.length) resp.hhLogs = hhLogs if (hhLogs && hhLogs.length) resp.hhLogs = hhLogs
testCallback(undefined, resp) testCallback(undefined, resp)
...@@ -341,7 +349,9 @@ export function runTest (testName: string, testObject: any, contractDetails: Com ...@@ -341,7 +349,9 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
value: changeCase.sentenceCase(func.name), value: changeCase.sentenceCase(func.name),
filename: testObject.filename, filename: testObject.filename,
time: time, time: time,
context: testName context: testName,
web3,
debugTxHash
} }
if (hhLogs && hhLogs.length) resp.hhLogs = hhLogs if (hhLogs && hhLogs.length) resp.hhLogs = hhLogs
testCallback(undefined, resp) testCallback(undefined, resp)
...@@ -380,6 +390,7 @@ export function runTest (testName: string, testObject: any, contractDetails: Com ...@@ -380,6 +390,7 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
const txHash = JSON.parse(err.message.replace('Transaction has been reverted by the EVM:', '')).transactionHash 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 (web3.eth && web3.eth.getHHLogsForTx) hhLogs = await web3.eth.getHHLogsForTx(txHash)
if (hhLogs && hhLogs.length) resp.hhLogs = hhLogs if (hhLogs && hhLogs.length) resp.hhLogs = hhLogs
resp.debugTxHash = txHash
} }
testCallback(undefined, resp) testCallback(undefined, resp)
failureNum += 1 failureNum += 1
......
...@@ -38,6 +38,7 @@ export interface TestResultInterface { ...@@ -38,6 +38,7 @@ export interface TestResultInterface {
location?: string location?: string
hhLogs?: [] hhLogs?: []
web3?: any web3?: any
debugTxHash?: string
} }
export interface TestCbInterface { export interface TestCbInterface {
(error: Error | null | undefined, result: TestResultInterface) : void; (error: Error | null | undefined, result: TestResultInterface) : void;
...@@ -48,6 +49,7 @@ export interface ResultCbInterface { ...@@ -48,6 +49,7 @@ export interface ResultCbInterface {
export interface Options { export interface Options {
accounts?: string[] | null, accounts?: string[] | null,
testFilePath?: string
web3?: any web3?: any
} }
......
This diff is collapsed.
...@@ -42,7 +42,6 @@ export const listenToEvents = (compileTabLogic: CompileTabLogic, api) => (dispat ...@@ -42,7 +42,6 @@ export const listenToEvents = (compileTabLogic: CompileTabLogic, api) => (dispat
api.onContentChanged = () => { api.onContentChanged = () => {
dispatch(setEditorMode('contentChanged')) dispatch(setEditorMode('contentChanged'))
} }
compileTabLogic.compiler.event.register('loadingCompiler', () => { compileTabLogic.compiler.event.register('loadingCompiler', () => {
dispatch(setCompilerMode('loadingCompiler')) dispatch(setCompilerMode('loadingCompiler'))
}) })
......
{
"presets": ["@nrwl/react/babel"],
"plugins": []
}
{
"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"
}
}
# 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).
{
"name": "remix-ui-terminal",
"version": "0.0.1"
}
export * from './lib/remix-ui-terminal'
import React from 'react'
import { EMPTY_BLOCK, KNOWN_TRANSACTION, NEW_BLOCK, NEW_CALL, NEW_TRANSACTION, UNKNOWN_TRANSACTION } from '../types/terminalTypes'
export const registerCommandAction = (name: string, command, activate, dispatch: React.Dispatch<any>) => {
const commands: any = {}
const _commands: any = {}
_commands[name] = command
const data: any = {
session: [],
activeFilters: { commands: {}, input: '' },
filterFns: {}
}
const _INDEX = {
all: [],
allMain: [],
commands: {},
commandsMain: {}
}
const registerFilter = (commandName, filterFn) => {
data.filterFns[commandName] = filterFn
}
commands[name] = function () {
const args = [...arguments]
const steps = []
const root = { steps, cmd: name, gidx: 0, idx: 0 }
const ITEM = { root, cmd: name }
root.gidx = _INDEX.allMain.push(ITEM) - 1
let item
function append (cmd, params, el) {
if (cmd) { // subcommand
item = { el, cmd, root }
} else { // command
item = ITEM
item.el = el
cmd = name
}
item.gidx = _INDEX.all.push(item) - 1
item.idx = _INDEX.commands[cmd].push(item) - 1
item.step = steps.push(item) - 1
item.args = params
}
const scopedCommands = _scopeCommands(append)
command(args, scopedCommands, el => append(null, args, el))
}
const help = typeof command.help === 'string' ? command.help : [
'// no help available for:', `terminal.command.${name}`
].join('\n')
commands[name].toString = () => { return help }
commands[name].help = help
data.activeFilters.commands[name] = activate && activate.activate
if (activate.filterFn) {
registerFilter(name, activate.filterFn)
}
if (name !== (KNOWN_TRANSACTION || UNKNOWN_TRANSACTION || EMPTY_BLOCK)) {
dispatch({ type: name, payload: { commands: commands, _commands: _commands, data: data } })
}
const _scopeCommands = (append) => {
const scopedCommands = {}
Object.keys(commands).forEach(function makeScopedCommand (cmd) {
const command = _commands[cmd]
scopedCommands[cmd] = function _command () {
const args = [...arguments]
command(args, scopedCommands, el => append(cmd, args, el))
}
})
return scopedCommands
}
}
export const filterFnAction = (name: string, filterFn, dispatch: React.Dispatch<any>) => {
const data: any = {
filterFns: {}
}
data.filterFns[name] = filterFn
dispatch({ type: name, payload: { data: data } })
}
export const registerLogScriptRunnerAction = (on, commandName, commandFn, dispatch: React.Dispatch<any>) => {
on('scriptRunner', commandName, (msg) => {
commandFn.log.apply(commandFn, msg.data)
dispatch({ type: commandName, payload: { commandFn, message: msg.data } })
})
}
export const registerInfoScriptRunnerAction = (on, commandName, commandFn, dispatch: React.Dispatch<any>) => {
on('scriptRunner', commandName, (msg) => {
commandFn.info.apply(commandFn, msg.data)
dispatch({ type: commandName, payload: { commandFn, message: msg.data } })
})
}
export const registerWarnScriptRunnerAction = (on, commandName, commandFn, dispatch: React.Dispatch<any>) => {
on('scriptRunner', commandName, (msg) => {
commandFn.warn.apply(commandFn, msg.data)
dispatch({ type: commandName, payload: { commandFn, message: msg.data } })
})
}
export const registerErrorScriptRunnerAction = (on, commandName, commandFn, dispatch: React.Dispatch<any>) => {
on('scriptRunner', commandName, (msg) => {
commandFn.error.apply(commandFn, msg.data)
dispatch({ type: commandName, payload: { commandFn, message: msg.data } })
})
}
export const listenOnNetworkAction = async (event, isListening) => {
event.trigger('listenOnNetWork', [isListening])
}
export const initListeningOnNetwork = (plugins, dispatch: React.Dispatch<any>) => {
plugins.txListener.event.register(NEW_BLOCK, (block) => {
if (!block.transactions || (block.transactions && !block.transactions.length)) {
dispatch({ type: EMPTY_BLOCK, payload: { message: 0 } })
}
})
plugins.txListener.event.register(KNOWN_TRANSACTION, () => {
})
plugins.txListener.event.register(NEW_CALL, (tx, receipt) => {
log(plugins, tx, receipt, dispatch)
// log(this, tx, null)
})
plugins.txListener.event.register(NEW_TRANSACTION, (tx, receipt) => {
log(plugins, tx, receipt, dispatch)
})
const log = async (plugins, tx, receipt, dispatch: React.Dispatch<any>) => {
const resolvedTransaction = await plugins.txListener.resolvedTransaction(tx.hash)
if (resolvedTransaction) {
let compiledContracts = null
if (plugins._deps.compilersArtefacts.__last) {
compiledContracts = await plugins._deps.compilersArtefacts.__last.getContracts()
}
await plugins.eventsDecoder.parseLogs(tx, resolvedTransaction.contractName, compiledContracts, async (error, logs) => {
if (!error) {
await dispatch({ type: KNOWN_TRANSACTION, payload: { message: [{ tx: tx, receipt: receipt, resolvedData: resolvedTransaction, logs: logs }] } })
}
})
} else {
await dispatch({ type: UNKNOWN_TRANSACTION, payload: { message: [{ tx: tx, receipt: receipt }] } })
}
}
plugins.txListener.event.register('debuggingRequested', async (hash) => {
// TODO should probably be in the run module
if (!await plugins.options.appManager.isActive('debugger')) await plugins.options.appManager.activatePlugin('debugger')
plugins.call('menuicons', 'select', 'debugger')
plugins.call('debugger', 'debug', hash)
})
}
export const allPrograms = [
{ ethers: 'The ethers.js library is a compact and complete JavaScript library for Ethereum.' },
{ remix: 'Ethereum IDE and tools for the web.' },
{ web3: 'The web3.js library is a collection of modules which contain specific functionality for the ethereum ecosystem.' }
// { swarmgw: 'This library can be used to upload/download files to Swarm via https://swarm-gateways.net/.' }
]
export const allCommands = [
{ '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.' },
{ '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 or ipfs.' },
// { 'swarmgw.get(url, cb)': 'Download files from Swarm via https://swarm-gateways.net/' },
// { 'swarmgw.put(content, cb)': 'Upload files to Swarm via https://swarm-gateways.net/' },
{ 'ethers.Contract': 'This API provides a graceful connection to a contract deployed on the blockchain, simplifying calling and querying its functions and handling all the binary protocol and conversion as necessarily.' },
// { 'ethers.HDNode': 'A Hierarchical Deterministic Wallet represents a large tree of private keys which can reliably be reproduced from an initial seed.' },
// { 'ethers.Interface': 'The Interface Object is a meta-class that accepts a Solidity (or compatible) Application Binary Interface (ABI) and populates functions to deal with encoding and decoding the parameters to pass in and results returned.' },
{ 'ethers.providers': 'A Provider abstracts a connection to the Ethereum blockchain, for issuing queries and sending state changing transactions.' },
// { 'ethers.SigningKey': 'The SigningKey interface provides an abstraction around the secp256k1 elliptic curve cryptography library.' },
// { 'ethers.utils': 'The utility functions exposed in both the ethers umbrella package and the ethers-utils.' },
// { 'ethers.utils.AbiCoder': 'Create a new ABI Coder object' },
// { 'ethers.utils.RLP': 'This encoding method is used internally for several aspects of Ethereum, such as encoding transactions and determining contract addresses.' },
{ 'ethers.Wallet': 'A wallet manages a private/public key pair which is used to cryptographically sign transactions and prove ownership on the Ethereum network.' },
{ 'ethers.version': 'Contains the version of the ethers container object.' },
{ 'web3.eth': 'Eth module for interacting with the Ethereum network.' },
{ 'web3.eth.accounts': 'The web3.eth.accounts contains functions to generate Ethereum accounts and sign transactions and data.' },
// TODO: need to break down the object return from abi response
// { 'web3.eth.abi': 'The web3.eth.abi functions let you de- and encode parameters to ABI (Application Binary Interface) for function calls to the EVM (Ethereum Virtual Machine).' },
{ 'web3.eth.ens': 'The web3.eth.ens functions let you interacting with ENS.' },
{ 'web3.eth.Iban': 'The web3.eth.Iban function lets convert Ethereum addresses from and to IBAN and BBAN.' },
{ 'web3.eth.net': 'Net module for interacting with network properties.' },
{ 'web3.eth.personal': 'Personal module for interacting with the Ethereum accounts.' },
{ 'web3.eth.subscribe': 'The web3.eth.subscribe function lets you subscribe to specific events in the blockchain.' },
{ 'web3.givenProvider': 'When using web3.js in an Ethereum compatible browser, it will set with the current native provider by that browser. Will return the given provider by the (browser) environment, otherwise null.' },
// { 'web3.modules': 'Contains the version of the web3 container object.' },
{ 'web3.providers': 'Contains the current available providers.' },
{ 'web3.shh': 'Shh module for interacting with the whisper protocol' },
{ 'web3.utils': 'This package provides utility functions for Ethereum dapps and other web3.js packages.' },
{ 'web3.version': 'Contains the version of the web3 container object.' },
{ 'web3.eth.clearSubscriptions();': 'Resets subscriptions.' }
// { 'web3.eth.Contract(jsonInterface[, address][, options])': 'The web3.eth.Contract object makes it easy to interact with smart contracts on the ethereum blockchain.' },
// { 'web3.eth.accounts.create([entropy]);': 'The web3.eth.accounts contains functions to generate Ethereum accounts and sign transactions and data.' },
// { 'web3.eth.getAccounts();': 'Retrieve the list of accounts' },
// { 'web3.eth.accounts.privateKeyToAccount(privateKey [, ignoreLength ]);': 'Get the account from the private key' },
// { 'web3.eth.accounts.signTransaction(tx, privateKey [, callback]);': 'Sign Transaction' },
// { 'web3.eth.accounts.recoverTransaction(rawTransaction);': 'Sign Transaction' },
// { 'web3.eth.accounts.hashMessage(message);': 'Hash message' }
]
import React from 'react' // eslint-disable-line
const CheckTxStatus = ({ tx, type }) => {
if (tx.status === '0x1' || tx.status === true) {
return (<i className='txStatus succeeded fas fa-check-circle'></i>)
}
if (type === 'call' || type === 'unknownCall' || type === 'unknown') {
return (<i className='txStatus call'>call</i>)
} else if (tx.status === '0x0' || tx.status === false) {
return (<i className='txStatus failed fas fa-times-circle'></i>)
} else {
return (<i className='txStatus notavailable fas fa-circle-thin' title='Status not available' ></i>)
}
}
export default CheckTxStatus
import React from 'react' // eslint-disable-line
import helper from 'apps/remix-ide/src/lib/helper'
const remixLib = require('@remix-project/remix-lib')
const typeConversion = remixLib.execution.typeConversion
const Context = ({ opts, blockchain }) => {
const data = opts.tx || ''
const from = opts.from ? helper.shortenHexData(opts.from) : ''
let to = opts.to
if (data.to) to = to + ' ' + helper.shortenHexData(data.to)
const val = data.value
let hash = data.hash ? helper.shortenHexData(data.hash) : ''
const input = data.input ? helper.shortenHexData(data.input) : ''
const logs = data.logs && data.logs.decoded && data.logs.decoded.length ? data.logs.decoded.length : 0
const block = data.receipt ? data.receipt.blockNumber : data.blockNumber || ''
const i = data.receipt ? data.transactionIndex : data.transactionIndex
const value = val ? typeConversion.toInt(val) : 0
if (blockchain.getProvider() === 'vm') {
return (
<div>
<span className='txLog_7Xiho'>
<span className='tx'>[vm]</span>
<div className='txItem'><span className='txItemTitle'>from:</span> {from}</div>
<div className='txItem'><span className='txItemTitle'>to:</span> {to}</div>
<div className='txItem'><span className='txItemTitle'>value:</span> {value} wei</div>
<div className='txItem'><span className='txItemTitle'>data:</span> {input}</div>
<div className='txItem'><span className='txItemTitle'>logs:</span> {logs}</div>
<div className='txItem'><span className='txItemTitle'>hash:</span> {hash}</div>
</span>
</div>)
} else if (blockchain.getProvider() !== 'vm' && data.resolvedData) {
return (
<div>
<span className='txLog_7Xiho'>
<span className='tx'>[block:{block} txIndex:{i}]</span>
<div className='txItem'><span className='txItemTitle'>from:</span> {from}</div>
<div className='txItem'><span className='txItemTitle'>to:</span> {to}</div>
<div className='txItem'><span className='txItemTitle'>value:</span> {value} wei</div>
<div className='txItem'><span className='txItemTitle'>data:</span> {input}</div>
<div className='txItem'><span className='txItemTitle'>logs:</span> {logs}</div>
<div className='txItem'><span className='txItemTitle'>hash:</span> {hash}</div>
</span>
</div>)
} else {
hash = helper.shortenHexData(data.blockHash)
return (
<div>
<span className='txLog'>
<span className='tx'>[block:{block} txIndex:{i}]</span>
<div className='txItem'><span className='txItemTitle'>from:</span> {from}</div>
<div className='txItem'><span className='txItemTitle'>to:</span> {to}</div>
<div className='txItem'><span className='txItemTitle'>value:</span> {value} wei</div>
<div className='txItem'><span className='txItemTitle'>data:</span> {input}</div>
<div className='txItem'><span className='txItemTitle'>logs:</span> {logs}</div>
<div className='txItem'><span className='txItemTitle'>hash:</span> {hash}</div>
</span>
</div>)
}
}
export default Context
import React, { useState } from 'react' // eslint-disable-line
import helper from 'apps/remix-ide/src/lib/helper'
import CheckTxStatus from './ChechTxStatus' // eslint-disable-line
import showTable from './Table'
import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line
const remixLib = require('@remix-project/remix-lib')
const typeConversion = remixLib.execution.typeConversion
const RenderCall = ({ tx, resolvedData, logs, index, plugin, showTableHash, txDetails, modal }) => {
const to = resolvedData.contractName + '.' + resolvedData.fn
const from = tx.from ? tx.from : ' - '
const input = tx.input ? helper.shortenHexData(tx.input) : ''
const txType = 'call'
const debug = (event, tx) => {
event.stopPropagation()
if (tx.isCall && tx.envMode !== 'vm') {
modal('VM mode', 'Cannot debug this call. Debugging calls is only possible in JavaScript VM mode.', 'Ok', true, () => {}, 'Cancel', () => {})
} else {
plugin.event.trigger('debuggingRequested', [tx.hash])
}
}
return (
<span id={`tx${tx.hash}`} key={index}>
<div className="log" onClick={(event) => txDetails(event, tx)}>
<CheckTxStatus tx={tx} type={txType} />
<span className="txLog">
<span className="tx">[call]</span>
<div className='txItem'><span className='txItemTitle'>from:</span> {from}</div>
<div className='txItem'><span className='txItemTitle'>to:</span> {to}</div>
<div className='txItem'><span className='txItemTitle'>data:</span> {input}</div>
</span>
<div className='buttons'>
<div className="debug btn btn-primary btn-sm" onClick={(event) => debug(event, tx)}>Debug</div>
</div>
<i className="terminal_arrow fas fa-angle-down"></i>
</div>
{showTableHash.includes(tx.hash) ? showTable({
hash: tx.hash,
isCall: tx.isCall,
contractAddress: tx.contractAddress,
data: tx,
from,
to,
gas: tx.gas,
input: tx.input,
'decoded input': resolvedData && resolvedData.params ? JSON.stringify(typeConversion.stringify(resolvedData.params), null, '\t') : ' - ',
'decoded output': resolvedData && resolvedData.decodedReturnValue ? JSON.stringify(typeConversion.stringify(resolvedData.decodedReturnValue), null, '\t') : ' - ',
val: tx.value,
logs: logs,
transactionCost: tx.transactionCost,
executionCost: tx.executionCost
}, showTableHash) : null}
</span>
)
}
export default RenderCall
import React, { useState } from 'react' // eslint-disable-line
import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line
import CheckTxStatus from './ChechTxStatus' // eslint-disable-line
import Context from './Context' // eslint-disable-line
import showTable from './Table'
const remixLib = require('@remix-project/remix-lib')
const typeConversion = remixLib.execution.typeConversion
const RenderKnownTransactions = ({ tx, receipt, resolvedData, logs, index, plugin, showTableHash, txDetails, modal }) => {
const debug = (event, tx) => {
event.stopPropagation()
if (tx.isCall && tx.envMode !== 'vm') {
modal('VM mode', 'Cannot debug this call. Debugging calls is only possible in JavaScript VM mode.', 'Ok', true, () => {}, 'Cancel', () => {})
} else {
plugin.event.trigger('debuggingRequested', [tx.hash])
}
}
const from = tx.from
const to = resolvedData.contractName + '.' + resolvedData.fn
const txType = 'knownTx'
const options = { from, to, tx }
return (
<span id={`tx${tx.hash}`} key={index}>
<div className="log" onClick={(event) => txDetails(event, tx)}>
<CheckTxStatus tx={receipt} type={txType} />
<Context opts = { options } blockchain={plugin.blockchain} />
<div className='buttons'>
<div className='debug btn btn-primary btn-sm' data-shared='txLoggerDebugButton' data-id={`txLoggerDebugButton${tx.hash}`} onClick={(event) => debug(event, tx)}>Debug</div>
</div>
<i className = {`terminal_arrow fas ${(showTableHash.includes(tx.hash)) ? 'fa-angle-up' : 'fa-angle-down'}`}></i>
</div>
{showTableHash.includes(tx.hash) ? showTable({
hash: tx.hash,
status: receipt !== null ? receipt.status : null,
isCall: tx.isCall,
contractAddress: tx.contractAddress,
data: tx,
from,
to,
gas: tx.gas,
input: tx.input,
'decoded input': resolvedData && resolvedData.params ? JSON.stringify(typeConversion.stringify(resolvedData.params), null, '\t') : ' - ',
'decoded output': resolvedData && resolvedData.decodedReturnValue ? JSON.stringify(typeConversion.stringify(resolvedData.decodedReturnValue), null, '\t') : ' - ',
logs: logs,
val: tx.value,
transactionCost: tx.transactionCost,
executionCost: tx.executionCost
}, showTableHash) : null}
</span>
)
}
export default RenderKnownTransactions
import React, { useState } from 'react' // eslint-disable-line
import { ModalDialog } from '@remix-ui/modal-dialog'// eslint-disable-line
import CheckTxStatus from './ChechTxStatus' // eslint-disable-line
import Context from './Context' // eslint-disable-line
import showTable from './Table'
const RenderUnKnownTransactions = ({ tx, receipt, index, plugin, showTableHash, txDetails, modal }) => {
const debug = (event, tx) => {
event.stopPropagation()
if (tx.isCall && tx.envMode !== 'vm') {
modal('VM mode', 'Cannot debug this call. Debugging calls is only possible in JavaScript VM mode.', 'Ok', true, () => {}, 'Cancel', () => {})
} else {
plugin.event.trigger('debuggingRequested', [tx.hash])
}
}
const from = tx.from
const to = tx.to
const txType = 'unknown' + (tx.isCall ? 'Call' : 'Tx')
const options = { from, to, tx }
return (
<span id={`tx${tx.hash}`} key={index}>
<div className="log" onClick={(event) => txDetails(event, tx)}>
<CheckTxStatus tx={receipt || tx} type={txType} />
<Context opts = { options } blockchain={plugin.blockchain} />
<div className='buttons'>
<div className='debug btn btn-primary btn-sm' data-shared='txLoggerDebugButton' data-id={`txLoggerDebugButton${tx.hash}`} onClick={(event) => debug(event, tx)}>Debug</div>
</div>
<i className = {`terminal_arrow fas ${(showTableHash.includes(tx.hash)) ? 'fa-angle-up' : 'fa-angle-down'}`}></i>
</div>
{showTableHash.includes(tx.hash) ? showTable({
hash: tx.hash,
status: receipt !== null ? receipt.status : null,
isCall: tx.isCall,
contractAddress: tx.contractAddress,
data: tx,
from,
to,
gas: tx.gas,
input: tx.input,
'decoded output': ' - ',
val: tx.value,
transactionCost: tx.transactionCost,
executionCost: tx.executionCost
}, showTableHash) : null}
</span>
)
}
export default RenderUnKnownTransactions
import React, { useState } from 'react' // eslint-disable-line
import { CopyToClipboard } from '@remix-ui/clipboard' // eslint-disable-line
import helper from 'apps/remix-ide/src/lib/helper'
const remixLib = require('@remix-project/remix-lib')
const typeConversion = remixLib.execution.typeConversion
const showTable = (opts, showTableHash) => {
let msg = ''
let toHash
const data = opts.data // opts.data = data.tx
if (data.to) {
toHash = opts.to + ' ' + data.to
} else {
toHash = opts.to
}
let callWarning = ''
if (opts.isCall) {
callWarning = '(Cost only applies when called by a contract)'
}
if (!opts.isCall) {
if (opts.status !== undefined && opts.status !== null) {
if (opts.status === '0x0' || opts.status === false) {
msg = 'Transaction mined but execution failed'
} else if (opts.status === '0x1' || opts.status === true) {
msg = 'Transaction mined and execution succeed'
}
} else {
msg = 'Status not available at the moment'
}
}
let stringified = ' - '
if (opts.logs && opts.logs.decoded) {
stringified = typeConversion.stringify(opts.logs.decoded)
}
const val = opts.val != null ? typeConversion.toInt(opts.val) : 0
return (
<table className={`txTable ${showTableHash.includes(opts.hash) ? 'active' : ''}`} id='txTable' data-id={`txLoggerTable${opts.hash}`}>
<tbody>
<tr className='tr'>
<td className='td' data-shared={`key_${opts.hash}`}>status</td>
<td className='td' data-id={`txLoggerTableStatus${opts.hash}`} data-shared={`pair_${opts.hash}`}>{`${opts.status} ${msg}`}</td>
</tr>
{opts.hash ? (<tr className='tr'>
<td className='td' data-shared={`key_${opts.hash}`}>transaction hash</td>
<td className='td' data-id={`txLoggerTableHash${opts.hash}`} data-shared={`pair_${opts.hash}`}>{opts.hash}
<CopyToClipboard content={opts.hash}/>
</td>
</tr>) : null }
{
opts.contractAddress ? (
<tr className='tr'>
<td className='td' data-shared={`key_${opts.hash}`}>contract address</td>
<td className='td' data-id={`txLoggerTableContractAddress${opts.hash}`} data-shared={`pair_${opts.hash}`}>{opts.contractAddress}
<CopyToClipboard content={opts.contractAddress}/>
</td>
</tr>
) : null
}
{
opts.from ? (
<tr className='tr'>
<td className='td tableTitle' data-shared={`key_${opts.hash}`}>from</td>
<td className='td' data-id={`txLoggerTableFrom${opts.hash}`} data-shared={`pair_${opts.hash}`}>{opts.from}
<CopyToClipboard content={opts.from}/>
</td>
</tr>
) : null
}
{
opts.to ? (
<tr className='tr'>
<td className='td' data-shared={`key_${opts.hash}`}>to</td>
<td className='td' data-id={`txLoggerTableTo${opts.hash}`} data-shared={`pair_${opts.hash}`}>{toHash}
<CopyToClipboard content={data.to ? data.to : toHash}/>
</td>
</tr>
) : null
}
{
opts.gas ? (
<tr className='tr'>
<td className='td' data-shared={`key_${opts.hash}`}>gas</td>
<td className='td' data-id={`txLoggerTableGas${opts.hash}`} data-shared={`pair_${opts.hash}`}>{opts.gas} gas
<CopyToClipboard content={opts.gas}/>
</td>
</tr>
) : null
}
{
opts.transactionCost ? (
<tr className='tr'>
<td className='td' data-shared={`key_${opts.hash}`}>transaction cost</td>
<td className='td' data-id={`txLoggerTableTransactionCost${opts.hash}`} data-shared={`pair_${opts.hash}`}>{opts.transactionCost} gas {callWarning}
<CopyToClipboard content={opts.transactionCost}/>
</td>
</tr>
) : null
}
{
opts.executionCost ? (
<tr className='tr'>
<td className='td' data-shared={`key_${opts.hash}`}>execution cost</td>
<td className='td' data-id={`txLoggerTableExecutionHash${opts.hash}`} data-shared={`pair_${opts.hash}`}>{opts.executionCost} gas {callWarning}
<CopyToClipboard content={opts.executionCost}/>
</td>
</tr>
) : null
}
{opts.hash ? (
<tr className='tr'>
<td className='td' data-shared={`key_${opts.hash}`}>hash</td>
<td className='td' data-id={`txLoggerTableHash${opts.hash}`} data-shared={`pair_${opts.hash}`}>{opts.hash}
<CopyToClipboard content={opts.hash}/>
</td>
</tr>
) : null}
{opts.input ? (
<tr className='tr'>
<td className='td' data-shared={`key_${opts.hash}`}>input</td>
<td className='td' data-id={`txLoggerTableHash${opts.hash}`} data-shared={`pair_${opts.hash}`}>{helper.shortenHexData(opts.input)}
<CopyToClipboard content={opts.input}/>
</td>
</tr>
) : null}
{opts['decoded input'] ? (
<tr className='tr'>
<td className='td' data-shared={`key_${opts.hash}`}>decoded input</td>
<td className='td' data-id={`txLoggerTableHash${opts.hash}`} data-shared={`pair_${opts.hash}`}>{opts['decoded input'].trim()}
<CopyToClipboard content={opts['decoded input']}/>
</td>
</tr>
) : null}
{opts['decoded output'] ? (
<tr className='tr'>
<td className='td' data-shared={`key_${opts.hash}`}>decoded output</td>
<td className='td' data-id={`txLoggerTableHash${opts.hash}`} data-shared={`pair_${opts.hash}`}>{opts['decoded output']}
<CopyToClipboard content={opts['decoded output']}/>
</td>
</tr>
) : null}
{opts.logs ? (
<tr className='tr'>
<td className='td' data-shared={`key_${opts.hash}`}>logs</td>
<td className='td' data-id={`txLoggerTableHash${opts.hash}`} data-shared={`pair_${opts.hash}`}>
{JSON.stringify(stringified, null, '\t')}
<CopyToClipboard content={JSON.stringify(stringified, null, '\t')}/>
<CopyToClipboard content={JSON.stringify(opts.logs.raw || '0')}/>
</td>
</tr>
) : null}
{opts.val ? (
<tr className='tr'>
<td className='td' data-shared={`key_${opts.hash}`}>val</td>
<td className='td' data-id={`txLoggerTableHash${opts.hash}`} data-shared={`pair_${opts.hash}`}>{val} wei
<CopyToClipboard content={`${val} wei`}/>
</td>
</tr>
) : null}
</tbody>
</table>
)
}
export default showTable
import React, {useEffect, useState} from "react" // eslint-disable-line
export const useKeyPress = (targetKey: string): boolean => {
// State for keeping track of whether key is pressed
const [keyPressed, setKeyPressed] = useState(false)
// If pressed key is our target key then set to true
function downHandler ({ key }): void {
if (key === targetKey) {
setKeyPressed(true)
}
}
// If released key is our target key then set to false
const upHandler = ({ key }): void => {
if (key === targetKey) {
setKeyPressed(false)
}
}
// Add event listeners
useEffect(() => {
window.addEventListener('keydown', downHandler)
window.addEventListener('keyup', upHandler)
// Remove event listeners on cleanup
return () => {
window.removeEventListener('keydown', downHandler)
window.removeEventListener('keyup', upHandler)
}
}, []) // Empty array ensures that effect is only run on mount and unmount
return keyPressed
}
import { CLEAR_CONSOLE, CMD_HISTORY, EMPTY_BLOCK, ERROR, HTML, INFO, KNOWN_TRANSACTION, LISTEN_ON_NETWORK, LOG, NEW_TRANSACTION, SCRIPT, UNKNOWN_TRANSACTION, WARN } from '../types/terminalTypes'
export const initialState = {
journalBlocks: [
],
data: {
// lineLength: props.options.lineLength || 80,
session: [],
activeFilters: { commands: {}, input: '' },
filterFns: {}
},
_commandHistory: [],
_commands: {},
commands: {},
_JOURNAL: [],
_jobs: [],
_INDEX: {
},
_INDEXall: [],
_INDEXallMain: [],
_INDEXcommands: {},
_INDEXcommandsMain: {},
message: []
}
export const registerCommandReducer = (state, action) => {
switch (action.type) {
case HTML :
return {
...state,
_commands: Object.assign(initialState._commands, action.payload._commands),
commands: Object.assign(initialState.commands, action.payload.commands),
data: Object.assign(initialState.data, { ...action.payload.data })
}
case LOG:
return {
...state,
_commands: Object.assign(initialState._commands, action.payload._commands),
commands: Object.assign(initialState.commands, action.payload.commands),
data: Object.assign(initialState.data, { ...action.payload.data })
}
case INFO:
return {
...state,
_commands: Object.assign(initialState._commands, action.payload._commands),
commands: Object.assign(initialState.commands, action.payload.commands),
data: Object.assign(initialState.data, action.payload.data)
}
case WARN:
return {
...state,
_commands: Object.assign(initialState._commands, action.payload._commands),
commands: Object.assign(initialState.commands, action.payload.commands),
data: Object.assign(initialState.data, action.payload.data)
}
case ERROR:
return {
...state,
_commands: Object.assign(initialState._commands, action.payload._commands),
commands: Object.assign(initialState.commands, action.payload.commands),
data: Object.assign(initialState.data, action.payload.data)
}
case SCRIPT:
return {
...state,
_commands: Object.assign(initialState._commands, action.payload._commands),
commands: Object.assign(initialState.commands, action.payload.commands),
data: Object.assign(initialState.data, action.payload.data)
}
case CLEAR_CONSOLE:
return {
...state,
...state.journalBlocks.splice(0)
}
case LISTEN_ON_NETWORK:
return {
...state,
journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: 'text-info' })
}
default :
return { state }
}
}
export const registerFilterReducer = (state, action) => {
switch (action.type) {
case LOG:
return {
...state,
data: Object.assign(initialState.data.filterFns, action.payload.data.filterFns)
}
case INFO:
return {
...state,
data: Object.assign(initialState.data.filterFns, action.payload.data.filterFns)
}
case WARN:
return {
...state,
data: Object.assign(initialState.data.filterFns, action.payload.data.filterFns)
}
case ERROR:
return {
...state,
data: Object.assign(initialState.data.filterFns, action.payload.data.filterFns)
}
case SCRIPT:
return {
...state,
data: Object.assign(initialState.data.filterFns, action.payload.data.filterFns)
}
default :
return { state }
}
}
export const addCommandHistoryReducer = (state, action) => {
switch (action.type) {
case CMD_HISTORY:
return {
...state,
_commandHistory: initialState._commandHistory.unshift(action.payload.script)
}
default :
return { state }
}
}
export const remixWelcomeTextReducer = (state, action) => {
switch (action.type) {
case 'welcomeText' :
return {
...state,
journalBlocks: initialState.journalBlocks.push(action.payload.welcomeText)
}
}
}
export const registerScriptRunnerReducer = (state, action) => {
switch (action.type) {
case HTML:
return {
...state,
journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: 'text-log' })
}
case LOG:
return {
...state,
journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: 'text-info' })
}
case INFO:
return {
...state,
journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: 'text-info' })
}
case WARN:
return {
...state,
journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: 'text-warning' })
}
case ERROR:
return {
...state,
journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: 'text-danger' })
}
case SCRIPT:
return {
...state,
journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: 'text-log' })
}
case KNOWN_TRANSACTION:
return {
...state,
journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: '', name: 'knownTransaction' })
}
case UNKNOWN_TRANSACTION:
return {
...state,
journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: '', name: 'unknownTransaction' })
}
case EMPTY_BLOCK:
return {
...state,
journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: '', name: 'emptyBlock' })
}
case NEW_TRANSACTION:
return {
...state,
journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: '' })
}
}
}
element.style {
height: 323px !important;
}
#terminalCliInput{
width: 95%;
background: transparent;
border: none;
font-weight: bold;
color: #a2a3b4;
border-top-style: hidden;
border-right-style: hidden;
border-left-style: hidden;
border-bottom-style: hidden;
}
#terminalCliInput:focus {
outline: none;
}
.border-primary {
border-color: #007aa6!important;
}
/* seleted option should reflect the theme color */
.selectedOptions {
background-color: #222336;
}
.panel {
position : relative;
display : flex;
flex-direction : column;
font-size : 12px;
min-height : 3em;
}
.bar {
display : flex;
z-index : 2;
}
.menu {
position : relative;
display : flex;
align-items : center;
width : 100%;
max-height : 35px;
min-height : 35px;
}
.toggleTerminal {
cursor : pointer;
}
.toggleTerminal:hover {
color : var(--secondary);
}
.terminal_container {
display : flex;
flex-direction : column;
height : 100%;
overflow-y : auto;
font-family : monospace;
margin : 0px;
background-repeat : no-repeat;
background-position : center 15%;
background-size : auto calc(75% - 1.7em);
}
.terminal {
position : relative;
display : flex;
flex-direction : column;
height : 100%;
}
.journal {
margin-top : auto;
font-family : monospace;
}
.block {
word-break : break-word;
white-space : pre-wrap;
line-height : 2ch;
padding : 1ch;
margin-top : 2ch;
}
.block > pre {
max-height : 200px;
}
.cli {
line-height : 1.7em;
font-family : monospace;
padding : .4em;
color : var(--primary);
}
.prompt {
margin-right : 0.5em;
font-family : monospace;
font-weight : bold;
font-size : 14px;
color : lightgray;
}
.input {
word-break : break-word;
outline : none;
font-family : monospace;
}
.search {
display : flex;
align-items : center;
width : 330px;
padding-left : 20px;
height : 100%;
padding-top : 1px;
padding-bottom : 1px;
}
.filter {
height : 80%;
white-space : nowrap;
overflow : hidden;
text-overflow : ellipsis;
}
.searchIcon {
width : 25px;
border-top-left-radius : 3px;
border-bottom-left-radius : 3px;
display : flex;
align-items : center;
justify-content : center;
margin-right : 5px;
}
.listen {
margin-right : 30px;
min-width : 40px;
height : 13px;
display : flex;
align-items : center;
}
.listenLabel {
min-width: 50px;
}
.verticalLine {
border-left : 1px solid var(--secondary);
height : 65%;
}
.dragbarHorizontal {
position : absolute;
top : 0;
height : 0.2em;
right : 0;
left : 0;
cursor : row-resize;
z-index : 999;
}
.console {
cursor : pointer;
}
.dragbarHorizontal:hover {
background-color: #007AA6;
border:2px solid #007AA6;
}
.listenOnNetwork {
min-height: auto;
}
.ghostbar {
position : absolute;
height : 6px;
opacity : 0.5;
cursor : row-resize;
z-index : 9999;
left : 0;
right : 0;
}
.divider-hitbox {
color: white;
cursor: row-resize;
align-self: stretch;
display: flex;
align-items: center;
padding: 0 1rem;
}
.ul {margin-left: 0; padding-left: 20px;}
.popup {
position : absolute;
text-align : left;
width : 95%;
font-family : monospace;
background-color : var(--secondary);
overflow : auto;
padding-bottom : 13px;
z-index : 80;
bottom : 1em;
border-width : 4px;
left : 2em;
}
.autoCompleteItem {
padding : 4px;
border-radius : 2px;
}
.popup a {
cursor : pointer;
}
.listHandlerShow {
display : block;
}
.listHandlerHide {
display : none;
}
.listHandlerButtonShow {
position : fixed;
width : 46%;
}
.pageNumberAlignment {
font-size : 10px;
float : right;
}
.modalContent {
position : absolute;
margin-left : 20%;
margin-bottom : 32px;
bottom : 0px;
padding : 0;
line-height : 18px;
font-size : 12px;
width : 40%;
box-shadow : 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
-webkit-animation-name: animatebottom;
-webkit-animation-duration: 0.4s;
animation-name : animatetop;
animation-duration: 0.4s
}
@-webkit-keyframes animatetop {
from {bottom: -300px; opacity: 0}
to {bottom: 0; opacity: 1}
}
@keyframes animatetop {
from {bottom: -300px; opacity: 0}
to {bottom: 0; opacity: 1}
}
/* tx logger css*/
.log {
display: flex;
cursor: pointer;
align-items: center;
cursor: pointer;
}
.log:hover {
opacity: 0.8;
}
.txStatus {
display: flex;
font-size: 20px;
margin-right: 20px;
float: left;
}
.succeeded {
color: var(--success);
}
.failed {
color: var(--danger);
}
.terminal_arrow {
color: var(--text-info);
font-size: 20px;
cursor: pointer;
display: flex;
margin-left: 10px;
}
.terminal_arrow:hover {
color: var(--secondary);
}
.notavailable {
}
.call {
font-size: 7px;
border-radius: 50%;
min-width: 20px;
min-height: 20px;
display: flex;
justify-content: center;
align-items: center;
color: var(--text-info);
text-transform: uppercase;
font-weight: bold;
}
.txItem {
color: var(--text-info);
margin-right: 5px;
float: left;
}
.txItemTitle {
font-weight: bold;
}
.tx {
color: var(--text-info);
font-weight: bold;
float: left;
margin-right: 10px;
}
.txTable,
.tr,
.td {
border-collapse: collapse;
font-size: 10px;
color: var(--text-info);
border: 1px solid var(--text-info);
transition: max-height 0.3s, padding 0.3s;
}
table .active {
transition: max-height 0.6s, padding 0.6s;
}
#txTable {
margin-top: 1%;
margin-bottom: 5%;
align-self: center;
width: 85%;
}
.tr, .td {
padding: 4px;
vertical-align: baseline;
}
.td:first-child {
min-width: 30%;
width: 30%;
align-items: baseline;
font-weight: bold;
}
.tableTitle {
width: 25%;
}
.buttons {
display: flex;
margin-left: auto;
}
.debug {
white-space: nowrap;
}
.debug:hover {
opacity: 0.8;
}
/* Style the accordion section */
.accordion__section {
display: flex;
flex-direction: column;
}
/* Style the buttons that are used to open and close the accordion panel */
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
display: flex;
align-items: center;
border: none;
outline: none;
transition: background-color 0.6s ease;
}
/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */
/* .accordion:hover,
.active {
background-color: #ccc;
} */
/* Style the accordion content title */
.accordion__title {
font-family: "Open Sans", sans-serif;
font-weight: 600;
font-size: 14px;
}
/* Style the accordion chevron icon */
.accordion__icon {
margin-left: auto;
transition: transform 0.6s ease;
}
/* Style to rotate icon when state is active */
.rotate {
transform: rotate(90deg);
}
/* Style the accordion content panel. Note: hidden by default */
.accordion__content {
background-color: white;
overflow: hidden;
transition: max-height 0.6s ease;
}
/* Style the accordion content text */
.accordion__text {
font-family: "Open Sans", sans-serif;
font-weight: 400;
font-size: 14px;
padding: 18px;
}
This diff is collapsed.
import React from 'react' // eslint-disable-line
const TerminalWelcomeMessage = ({ packageJson }) => {
return (
<div className="px-4 block" data-id="block_null">
<div> - Welcome to Remix {packageJson} - </div><br />
<div>You can use this terminal to: </div>
<ul className='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 className='ul'>
<li><a target="_blank" href="https://web3js.readthedocs.io/en/1.0/">web3 version 1.5.2</a></li>
<li><a target="_blank" href="https://docs.ethers.io">ethers.js</a> </li>
<li>remix (run remix.help() for more info)</li>
</ul>
</div>
)
}
export default TerminalWelcomeMessage
export interface ROOTS {
steps: any,
cmd: string,
gidx: number,
idx: number
}
export const KNOWN_TRANSACTION = 'knownTransaction'
export const UNKNOWN_TRANSACTION = 'unknownTransaction'
export const EMPTY_BLOCK = 'emptyBlock'
export const NEW_TRANSACTION = 'newTransaction'
export const NEW_BLOCK = 'newBlock'
export const NEW_CALL = 'newCall'
export const HTML = 'html'
export const LOG = 'log'
export const INFO = 'info'
export const WARN = 'warn'
export const ERROR = 'error'
export const SCRIPT = 'script'
export const CLEAR_CONSOLE = 'clearconsole'
export const LISTEN_ON_NETWORK = 'listenOnNetWork'
export const CMD_HISTORY = 'cmdHistory'
export interface RemixUiTerminalProps {
plugin: any
}
export const getKeyOf = (item) => {
return Object.keys(item)[0]
}
export const getValueOf = (item) => {
return Object.values(item)[0]
}
export const Objectfilter = (obj: any, filterValue: any) =>
obj.filter((item: any) => Object.keys(item)[0].indexOf(filterValue) > -1)
export const matched = (arr, value) => arr.map(x => Object.keys(x).some(x => x.startsWith(value))).some(x => x === true)
const findDeep = (object, fn, found = { break: false, value: undefined }) => {
if (typeof object !== 'object' || object === null) return
for (var i in object) {
if (found.break) break
var el = object[i]
if (el && el.innerText !== undefined && el.innerText !== null) el = el.innerText
if (fn(el, i, object)) {
found.value = el
found.break = true
break
} else {
findDeep(el, fn, found)
}
}
return found.value
}
export const find = (args, query) => {
query = query.trim()
const isMatch = !!findDeep(args, function check (value) {
if (value === undefined || value === null) return false
if (typeof value === 'function') return false
if (typeof value === 'object') return false
const contains = String(value).indexOf(query.trim()) !== -1
return contains
})
return isMatch
}
export const 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)
}
`
}
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"jsx": "react",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
}
]
}
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"types": ["node"]
},
"files": [
"../../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
"../../../node_modules/@nrwl/react/typings/image.d.ts"
],
"exclude": ["**/*.spec.ts", "**/*.spec.tsx"],
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
}
...@@ -332,7 +332,7 @@ export const Workspace = (props: WorkspaceProps) => { ...@@ -332,7 +332,7 @@ export const Workspace = (props: WorkspaceProps) => {
return ( return (
<div className='remixui_container'> <div className='remixui_container'>
<ModalDialog { state.modal.message && <ModalDialog
id='workspacesModalDialog' id='workspacesModalDialog'
title={ state.modal.title } title={ state.modal.title }
message={ state.modal.message } message={ state.modal.message }
...@@ -344,6 +344,7 @@ export const Workspace = (props: WorkspaceProps) => { ...@@ -344,6 +344,7 @@ export const Workspace = (props: WorkspaceProps) => {
handleHide={ handleHideModal }> handleHide={ handleHideModal }>
{ (typeof state.modal.message !== 'string') && state.modal.message } { (typeof state.modal.message !== 'string') && state.modal.message }
</ModalDialog> </ModalDialog>
}
<Toaster message={state.toasterMsg} /> <Toaster message={state.toasterMsg} />
<div className='remixui_fileexplorer' onClick={() => resetFocus(true)}> <div className='remixui_fileexplorer' onClick={() => resetFocus(true)}>
<div> <div>
......
...@@ -121,6 +121,9 @@ ...@@ -121,6 +121,9 @@
"remix-ui-renderer": { "remix-ui-renderer": {
"tags": [] "tags": []
}, },
"remix-ui-terminal": {
"tags": []
},
"solidity-compiler": { "solidity-compiler": {
"tags": [] "tags": []
}, },
......
...@@ -45,8 +45,8 @@ ...@@ -45,8 +45,8 @@
"workspace-schematic": "nx workspace-schematic", "workspace-schematic": "nx workspace-schematic",
"dep-graph": "nx dep-graph", "dep-graph": "nx dep-graph",
"help": "nx help", "help": "nx help",
"lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-file-explorer,remix-ui-debugger-ui,remix-ui-workspace,remix-ui-static-analyser,remix-ui-checkbox,remix-ui-settings,remix-core-plugin,remix-ui-renderer,remix-ui-publish-to-storage,remix-ui-solidity-compiler,remix-ui-plugin-manager", "lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-file-explorer,remix-ui-debugger-ui,remix-ui-workspace,remix-ui-static-analyser,remix-ui-checkbox,remix-ui-settings,remix-core-plugin,remix-ui-renderer,remix-ui-publish-to-storage,remix-ui-solidity-compiler,remix-ui-plugin-manager,remix-ui-terminal",
"build:libs": "nx run-many --target=build --parallel=false --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd", "build:libs": "nx run-many --target=build --parallel=false --with-deps=true --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd",
"test:libs": "nx run-many --target=test --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd", "test:libs": "nx run-many --target=test --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd",
"publish:libs": "npm run build:libs && lerna publish --skip-git && npm run bumpVersion:libs", "publish:libs": "npm run build:libs && lerna publish --skip-git && npm run bumpVersion:libs",
"build:e2e": "tsc -p apps/remix-ide-e2e/tsconfig.e2e.json", "build:e2e": "tsc -p apps/remix-ide-e2e/tsconfig.e2e.json",
...@@ -164,6 +164,7 @@ ...@@ -164,6 +164,7 @@
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"fs-extra": "^3.0.1", "fs-extra": "^3.0.1",
"html-react-parser": "^1.3.0",
"http-server": "^0.11.1", "http-server": "^0.11.1",
"intro.js": "^4.1.0", "intro.js": "^4.1.0",
"isbinaryfile": "^3.0.2", "isbinaryfile": "^3.0.2",
......
...@@ -43,8 +43,9 @@ ...@@ -43,8 +43,9 @@
"@remix-project/core-plugin": ["libs/remix-core-plugin/src/index.ts"], "@remix-project/core-plugin": ["libs/remix-core-plugin/src/index.ts"],
"@remix-ui/solidity-compiler": ["libs/remix-ui/solidity-compiler/src/index.ts"], "@remix-ui/solidity-compiler": ["libs/remix-ui/solidity-compiler/src/index.ts"],
"@remix-ui/publish-to-storage": ["libs/remix-ui/publish-to-storage/src/index.ts"], "@remix-ui/publish-to-storage": ["libs/remix-ui/publish-to-storage/src/index.ts"],
"@remix-ui/plugin-manager": ["libs/remix-ui/plugin-manager/src/index.ts"], "@remix-ui/renderer": ["libs/remix-ui/renderer/src/index.ts"],
"@remix-ui/renderer": ["libs/remix-ui/renderer/src/index.ts"] "@remix-ui/terminal": ["libs/remix-ui/terminal/src/index.ts"],
"@remix-ui/plugin-manager": ["libs/remix-ui/plugin-manager/src/index.ts"]
} }
}, },
"exclude": ["node_modules", "tmp"] "exclude": ["node_modules", "tmp"]
......
...@@ -778,9 +778,25 @@ ...@@ -778,9 +778,25 @@
} }
} }
}, },
"remix-ui-terminal": {
"root": "libs/remix-ui/terminal",
"sourceRoot": "libs/remix-ui/terminal/src",
"projectType": "library",
"schematics": {},
"architect": {
"lint": {
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/terminal/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "!libs/remix-ui/terminal/**/*"]
}
}
}
},
"remix-ui-plugin-manager": { "remix-ui-plugin-manager": {
"root": "libs/remix-ui/plugin-manager", "root": "libs/remix-ui/plugin-manager",
"sourceRoot": "libs/remix-ui/plugin-manager/src", "sourceRoot": "libs/remix-ui/plugin-manager/src",
"projectType": "library", "projectType": "library",
"schematics": {}, "schematics": {},
"architect": { "architect": {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment