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

pull/1647/head
filip mertens 3 years ago
commit bd502b6b44
  1. 10
      apps/remix-ide-e2e/src/commands/journalChildIncludes.ts
  2. 84
      apps/remix-ide-e2e/src/tests/terminal.test.ts
  3. 2
      apps/remix-ide-e2e/src/types/index.d.ts
  4. 13
      apps/remix-ide/src/app/editor/editor.js
  5. 15
      apps/remix-ide/src/app/panels/tab-proxy.js
  6. 22
      apps/remix-ide/src/app/panels/terminal.js
  7. 9
      apps/remix-ide/src/app/tabs/theme-module.js
  8. 15
      libs/remix-lib/src/execution/txRunnerVM.ts
  9. 70
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
  10. 1384
      libs/remix-ui/editor/src/lib/syntax.ts
  11. 5
      libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx
  12. 2
      libs/remix-ui/terminal/src/lib/components/Context.tsx
  13. 2
      libs/remix-ui/terminal/src/lib/components/RenderKnownTransactions.tsx
  14. 286
      libs/remix-ui/terminal/src/lib/components/Table.tsx
  15. 19
      libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
  16. 3
      libs/remix-ui/terminal/src/lib/types/terminalTypes.ts

@ -5,10 +5,10 @@ import EventEmitter from 'events'
Checks if any child elements of journal (console) contains a matching value.
*/
class JournalChildIncludes extends EventEmitter {
command (this: NightwatchBrowser, val: string): NightwatchBrowser {
command (this: NightwatchBrowser, val: string, opts = { shouldHaveOnlyOneOccurence: false }): NightwatchBrowser {
let isTextFound = false
const browser = this.api
let occurence = 0
this.api.elements('css selector', '*[data-id="terminalJournal"]', (res) => {
Array.isArray(res.value) && res.value.forEach(function (jsonWebElement) {
const jsonWebElementId = jsonWebElement.ELEMENT || jsonWebElement[Object.keys(jsonWebElement)[0]]
@ -16,12 +16,16 @@ class JournalChildIncludes extends EventEmitter {
browser.elementIdText(jsonWebElementId, (jsonElement) => {
const text = jsonElement.value
if (typeof text === 'string' && text.indexOf(val) !== -1) isTextFound = true
if (typeof text === 'string' && text.indexOf(val) !== -1) {
isTextFound = true
occurence++
}
})
})
})
browser.perform(() => {
browser.assert.ok(isTextFound, isTextFound ? `<*[data-id="terminalJournal"]> contains ${val}.` : `${val} not found in <*[data-id="terminalJournal"]> div:last-child>`)
if (opts.shouldHaveOnlyOneOccurence) browser.assert.ok(occurence === 1, `${occurence} occurence found of "${val}"`)
this.emit('complete')
})
return this

@ -118,6 +118,32 @@ module.exports = {
.waitForElementContainsText('*[data-id="terminalJournal"]', 'newOwner', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '0xd9145CCE52D386f254917e481eB44e9943F39138', 60000)
},
'Should print hardhat logs': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="terminalClearConsole"]') // clear the terminal
.addFile('printHardhatlog.sol', { content: hardhatLog })
.clickLaunchIcon('solidity')
.waitForElementVisible('[for="autoCompile"]')
.click('[for="autoCompile"]')
.testContracts('printHardhatlog.sol', { content: hardhatLog }, ['OwnerTest'])
.clickLaunchIcon('udapp')
.click('*[data-id="deployAndRunClearInstances"]')
.selectContract('OwnerTest')
.createContract('')
.pause(1000)
.journalChildIncludes('constructor', { shouldHaveOnlyOneOccurence: true })
.pause(5000)
.click('*[data-id="terminalClearConsole"]') // clear the terminal
.clickInstance(0)
.clickFunction('changeOwner - transact (not payable)', { types: 'address newOwner', values: '0xd9145CCE52D386f254917e481eB44e9943F39138' })
.pause(1000)
.journalChildIncludes('inside changeOwner', { shouldHaveOnlyOneOccurence: true })
.clickFunction('getOwner - call')
.pause(1000)
.journalChildIncludes('inside getOwner', { shouldHaveOnlyOneOccurence: true })
},
'Should display auto-complete menu': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="terminalCli"]')
@ -233,3 +259,61 @@ const deployWithEthersJs = `
console.log(e.message)
}
})()`
const hardhatLog = `
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "hardhat/console.sol";
/**
* @title Owner
* @dev Set & change owner
*/
contract OwnerTest {
address private owner;
// event for EVM logging
event OwnerSet(address indexed oldOwner, address indexed newOwner);
// modifier to check if caller is owner
modifier isOwner() {
// If the first argument of 'require' evaluates to 'false', execution terminates and all
// changes to the state and to Ether balances are reverted.
// This used to consume all gas in old EVM versions, but not anymore.
// It is often a good idea to use 'require' to check if functions are called correctly.
// As a second argument, you can also provide an explanation about what went wrong.
require(msg.sender == owner, "Caller is not owner");
_;
}
/**
* @dev Set contract deployer as owner
*/
constructor() {
console.log("constructor");
owner = msg.sender; // 'msg.sender' is sender of current call, contract deployer for a constructor
emit OwnerSet(address(0), owner);
}
/**
* @dev Change owner
* @param newOwner address of new owner
*/
function changeOwner(address newOwner) public isOwner {
console.log("inside changeOwner");
emit OwnerSet(owner, newOwner);
owner = newOwner;
}
/**
* @dev Return owner address
* @return address of owner
*/
function getOwner() external view returns (address) {
console.log("inside getOwner");
return owner;
}
}`

@ -23,7 +23,7 @@ declare module 'nightwatch' {
journalLastChildIncludes(val: string): NightwatchBrowser,
executeScript(script: string): NightwatchBrowser,
clearEditableContent(cssSelector: string): NightwatchBrowser,
journalChildIncludes(val: string): NightwatchBrowser,
journalChildIncludes(val: string, opts = { shouldHaveOnlyOneOccurence: boolean }): NightwatchBrowser,
debugTransaction(index: number): NightwatchBrowser,
checkElementStyle(cssSelector: string, styleProperty: string, expectedResult: string): NightwatchBrowser,
openFile(name: string): NightwatchBrowser,

@ -97,7 +97,7 @@ class Editor extends Plugin {
this.emit(name, ...params) // plugin stack
}
onActivation () {
async onActivation () {
this.activated = true
this.on('sidePanel', 'focusChanged', (name) => {
this.keepDecorationsFor(name, 'sourceAnnotationsPerFile')
@ -108,14 +108,15 @@ class Editor extends Plugin {
})
const translateTheme = (theme) => this._themes[theme.name === 'Dark' ? 'remixDark' : theme.quality]
this.on('theme', 'themeChanged', (theme) => {
this.currentTheme = translateTheme(theme)
this.renderComponent()
})
this.call('theme', 'currentTheme', (theme) => {
this.on('theme', 'themeLoaded', (theme) => {
this.currentTheme = translateTheme(theme)
this.renderComponent()
})
try {
this.currentTheme = translateTheme(await this.call('theme', 'currentTheme'))
} catch (e) {
console.log('unable to select the theme ' + e.message)
}
this.renderComponent()
}

@ -191,13 +191,6 @@ export class TabProxy extends Plugin {
}
}
switchToActiveTab () {
const active = this.tabsApi.active()
if (active && this._handlers[active]) {
this.switchTab(active)
}
}
renameTab (oldName, newName) {
this.addTab(newName, '', () => {
this.fileManager.open(newName)
@ -271,10 +264,14 @@ export class TabProxy extends Plugin {
removeTab (name) {
delete this._handlers[name]
this.switchToActiveTab()
this.loadedTabs = this.loadedTabs.filter(tab => tab.name !== name)
let previous = null
this.loadedTabs = this.loadedTabs.filter((tab, index) => {
if (tab.name === name) previous = this.loadedTabs[index - 1]
return tab.name !== name
})
this.renderComponent()
this.updateImgStyles()
if (previous) this.switchTab(previous.name)
}
addHandler (type, fn) {

@ -86,8 +86,6 @@ class Terminal extends Plugin {
this.call('menuicons', 'select', 'debugger')
this.call('debugger', 'debug', hash)
})
this.logHtmlResponse = []
this.logResponse = []
}
onActivation () {
@ -102,23 +100,11 @@ class Terminal extends Plugin {
}
logHtml (html) {
this.logHtmlResponse.push(html.innerText)
this.renderComponent()
this.resetLogHtml()
}
resetLogHtml () {
this.logHtmlResponse = []
this.terminalApi.logHtml(html)
}
log (message) {
this.logResponse.push(message)
this.renderComponent()
this.resetLog()
}
resetLog () {
this.logResponse = []
this.terminalApi.log(message)
}
render () {
@ -126,9 +112,11 @@ class Terminal extends Plugin {
}
renderComponent () {
const onReady = (api) => { this.terminalApi = api }
ReactDOM.render(
<RemixUiTerminal
plugin = {this}
plugin={this}
onReady={onReady}
/>,
this.element
)

@ -79,10 +79,17 @@ export class ThemeModule extends Plugin {
throw new Error(`Theme ${themeName} doesn't exist`)
}
const next = themeName || this.active // Name
if (next === this.active) return
_paq.push(['trackEvent', 'themeModule', 'switchTo', next])
const nextTheme = this.themes[next] // Theme
if (!this.forced) this._deps.config.set('settings/theme', next)
document.getElementById('theme-link').setAttribute('href', nextTheme.url)
document.getElementById('theme-link').remove()
const theme = yo`<link rel="stylesheet" href="${nextTheme.url}" id="theme-link"/>`
theme.addEventListener('load', () => {
this.emit('themeLoaded', nextTheme)
this.events.emit('themeLoaded', nextTheme)
})
document.head.insertBefore(theme, document.head.firstChild)
document.documentElement.style.setProperty('--theme', nextTheme.quality)
if (themeName) this.active = themeName
// TODO: Only keep `this.emit` (issue#2210)

@ -15,6 +15,7 @@ export class TxRunnerVM {
blocks
logsManager
commonContext
nextNonceForCall: number
getVMObject: () => any
constructor (vmaccounts, api, getVMObject) {
@ -31,6 +32,13 @@ export class TxRunnerVM {
this.vmaccounts = vmaccounts
this.queusTxs = []
this.blocks = []
/*
txHash is generated using the nonce,
in order to have unique transaction hash, we need to keep using different nonce (in case of a call)
so we increment this value after each call.
For this to function we also need to skip nonce validation, in the vm: `{ skipNonce: true }`
*/
this.nextNonceForCall = 0
}
execute (args, confirmationCb, gasEstimationForceSend, promptCb, callback) {
@ -75,7 +83,7 @@ export class TxRunnerVM {
let tx
if (!EIP1559) {
tx = Transaction.fromTxData({
nonce: new BN(res.nonce),
nonce: useCall ? this.nextNonceForCall : new BN(res.nonce),
gasPrice: '0x1',
gasLimit: gasLimit,
to: to,
@ -84,7 +92,7 @@ export class TxRunnerVM {
}, { common: this.commonContext }).sign(account.privateKey)
} else {
tx = FeeMarketEIP1559Transaction.fromTxData({
nonce: new BN(res.nonce),
nonce: useCall ? this.nextNonceForCall : new BN(res.nonce),
maxPriorityFeePerGas: '0x01',
maxFeePerGas: '0x1',
gasLimit: gasLimit,
@ -93,6 +101,7 @@ export class TxRunnerVM {
data: Buffer.from(data.slice(2), 'hex')
}).sign(account.privateKey)
}
if (useCall) this.nextNonceForCall++
const coinbases = ['0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a', '0x8945a1288dc78a6d8952a92c77aee6730b414778', '0x94d76e24f818426ae84aa404140e8d5f60e10e7e']
const difficulties = [new BN('69762765929000', 10), new BN('70762765929000', 10), new BN('71762765929000', 10)]
@ -127,7 +136,7 @@ export class TxRunnerVM {
}
runBlockInVm (tx, block, callback) {
this.getVMObject().vm.runBlock({ block: block, generate: true, skipBlockValidation: true, skipBalance: false }).then((results) => {
this.getVMObject().vm.runBlock({ block: block, generate: true, skipBlockValidation: true, skipBalance: false, skipNonce: true }).then((results) => {
const result = results.results[0]
if (result) {
const status = result.execResult.exceptionError ? 0 : 1

@ -1,6 +1,7 @@
import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint-disable-line
import Editor from '@monaco-editor/react'
import { reducerActions, reducerListener, initialState } from './actions/editor'
import { language } from './syntax'
import './remix-ui-editor.css'
@ -77,13 +78,39 @@ export const EditorUI = (props: EditorUIProps) => {
const [editorModelsState, dispatch] = useReducer(reducerActions, initialState)
const defineAndSetDarkTheme = (monaco) => {
// see https://microsoft.github.io/monaco-editor/playground.html#customizing-the-appearence-exposed-colors
const lightColor = window.getComputedStyle(document.documentElement).getPropertyValue('--light').trim()
const infoColor = window.getComputedStyle(document.documentElement).getPropertyValue('--info').trim()
const darkColor = window.getComputedStyle(document.documentElement).getPropertyValue('--dark').trim()
const grayColor = window.getComputedStyle(document.documentElement).getPropertyValue('--gray-dark').trim()
monaco.editor.defineTheme('remix-dark', {
base: 'vs-dark',
inherit: true, // can also be false to completely replace the builtin rules
rules: [
{ background: darkColor.replace('#', '') },
{ token: 'keyword.external', foreground: infoColor }
],
colors: {
'editor.background': darkColor,
'editorSuggestWidget.background': lightColor,
'editorSuggestWidget.selectedBackground': lightColor,
'editorSuggestWidget.highlightForeground': infoColor,
'editor.lineHighlightBorder': lightColor,
'editor.lineHighlightBackground': grayColor,
'editorGutter.background': lightColor
}
})
monacoRef.current.editor.setTheme('remix-dark')
}
useEffect(() => {
if (!monacoRef.current) return
monacoRef.current.editor.setTheme(props.theme)
if (props.theme === 'remix-dark') {
defineAndSetDarkTheme(monacoRef.current)
} else monacoRef.current.editor.setTheme(props.theme)
}, [props.theme])
if (monacoRef.current) monacoRef.current.editor.setTheme(props.theme)
const setAnnotationsbyFile = (uri) => {
if (props.sourceAnnotationsPerFile[uri]) {
const model = editorModelsState[uri]?.model
@ -137,8 +164,10 @@ export const EditorUI = (props: EditorUIProps) => {
useEffect(() => {
if (!editorRef.current) return
currentFileRef.current = props.currentFile
editorRef.current.setModel(editorModelsState[props.currentFile].model)
const file = editorModelsState[props.currentFile]
editorRef.current.setModel(file.model)
editorRef.current.updateOptions({ readOnly: editorModelsState[props.currentFile].readOnly })
if (file.language === 'sol') monacoRef.current.editor.setModelLanguage(file.model, 'remix-solidity')
setAnnotationsbyFile(props.currentFile)
setMarkerbyFile(props.currentFile)
}, [props.currentFile])
@ -207,7 +236,9 @@ export const EditorUI = (props: EditorUIProps) => {
function handleEditorDidMount (editor) {
editorRef.current = editor
monacoRef.current.editor.setTheme(props.theme)
if (props.theme === 'remix-dark') {
defineAndSetDarkTheme(monacoRef.current)
} else monacoRef.current.editor.setTheme(props.theme)
reducerListener(props.plugin, dispatch, monacoRef.current, editorRef.current, props.events)
props.events.onEditorMounted()
editor.onMouseUp((e) => {
@ -215,29 +246,20 @@ export const EditorUI = (props: EditorUIProps) => {
(window as any).addRemixBreakpoint(e.target.position)
}
})
editor.addCommand(monacoRef.current.KeyMod.CtrlCmd | monacoRef.current.KeyCode.US_EQUAL, () => {
editor.updateOptions({ fontSize: editor.getOption(42).fontSize + 1 })
})
editor.addCommand(monacoRef.current.KeyMod.CtrlCmd | monacoRef.current.KeyCode.US_MINUS, () => {
editor.updateOptions({ fontSize: editor.getOption(42).fontSize - 1 })
})
}
function handleEditorWillMount (monaco) {
monacoRef.current = monaco
// see https://microsoft.github.io/monaco-editor/playground.html#customizing-the-appearence-exposed-colors
const lightColor = window.getComputedStyle(document.documentElement).getPropertyValue('--light').trim()
const infoColor = window.getComputedStyle(document.documentElement).getPropertyValue('--info').trim()
const darkColor = window.getComputedStyle(document.documentElement).getPropertyValue('--dark').trim()
const grayColor = window.getComputedStyle(document.documentElement).getPropertyValue('--gray-dark').trim()
monaco.editor.defineTheme('remix-dark', {
base: 'vs-dark',
inherit: true, // can also be false to completely replace the builtin rules
rules: [{ background: darkColor.replace('#', '') }],
colors: {
'editor.background': darkColor,
'editorSuggestWidget.background': lightColor,
'editorSuggestWidget.selectedBackground': lightColor,
'editorSuggestWidget.highlightForeground': infoColor,
'editor.lineHighlightBorder': lightColor,
'editor.lineHighlightBackground': grayColor,
'editorGutter.background': lightColor
}
})
// Register a new language
monacoRef.current.languages.register({ id: 'remix-solidity' })
// Register a tokens provider for the language
monacoRef.current.languages.setMonarchTokensProvider('remix-solidity', language)
}
return (

File diff suppressed because it is too large Load Diff

@ -35,10 +35,10 @@ export const TabsUI = (props: TabsUIProps) => {
const classNameImg = 'my-1 mr-1 text-dark ' + tab.iconClass
const classNameTab = 'nav-item nav-link d-flex justify-content-center align-items-center px-2 py-1 tab' + (index === currentIndexRef.current ? ' active' : '')
return (
<div ref={el => { tabsRef.current[index] = el }} className={classNameTab} title={tab.tooltip}>
<div onClick={() => { props.onSelect(index); currentIndexRef.current = index; setSelectedIndex(index) }} ref={el => { tabsRef.current[index] = el }} className={classNameTab} title={tab.tooltip}>
{tab.icon ? (<img className="my-1 mr-1 iconImage" src={tab.icon} />) : (<i className={classNameImg}></i>)}
<span className="title-tabs">{tab.title}</span>
<span className="close-tabs" onClick={() => props.onClose(index)}>
<span className="close-tabs" onClick={(event) => { props.onClose(index); event.stopPropagation() }}>
<i className="text-dark fas fa-times"></i>
</span>
</div>
@ -71,7 +71,6 @@ export const TabsUI = (props: TabsUIProps) => {
<Tabs
className="tab-scroll"
selectedIndex={selectedIndex}
onSelect={index => { props.onSelect(index); currentIndexRef.current = index; setSelectedIndex(index) }}
>
<TabList className="d-flex flex-row justify-content-center align-items-center">
{props.tabs.map((tab, i) => <Tab className="py-1" key={tab.name}>{renderTab(tab, i)}</Tab>)}

@ -12,7 +12,7 @@ const Context = ({ opts, blockchain }) => {
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 logs = opts.logs && opts.logs.decoded && opts.logs.decoded.length ? opts.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

@ -21,7 +21,7 @@ const RenderKnownTransactions = ({ tx, receipt, resolvedData, logs, index, plugi
const from = tx.from
const to = resolvedData.contractName + '.' + resolvedData.fn
const txType = 'knownTx'
const options = { from, to, tx }
const options = { from, to, tx, logs }
return (
<span id={`tx${tx.hash}`} key={index}>
<div className="log" onClick={(event) => txDetails(event, tx)}>

@ -36,125 +36,219 @@ const showTable = (opts, showTableHash) => {
}
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}`}>
<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.status !== undefined ? (
<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>
) : null}
{opts.hash && !opts.isCall ? (
<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}/>
<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}/>
<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']}/>
<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']}/>
<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}`}>
<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')}/>
<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`}/>
<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}

@ -24,7 +24,7 @@ export interface ClipboardEvent<T = Element> extends SyntheticEvent<T, any> {
}
export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
const { call, _deps, on, config, event, gistHandler, logHtmlResponse, logResponse, version } = props.plugin
const { call, _deps, on, config, event, gistHandler, version } = props.plugin
const [toggleDownUp, setToggleDownUp] = useState('fa-angle-double-down')
const [_cmdIndex, setCmdIndex] = useState(-1)
const [_cmdTemp, setCmdTemp] = useState('')
@ -84,12 +84,15 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
}
useEffect(() => {
scriptRunnerDispatch({ type: 'html', payload: { message: logHtmlResponse } })
}, [logHtmlResponse])
useEffect(() => {
scriptRunnerDispatch({ type: 'log', payload: { message: logResponse } })
}, [logResponse])
props.onReady({
logHtml: (html) => {
scriptRunnerDispatch({ type: 'html', payload: { message: [html.innerText] } })
},
log: (message) => {
scriptRunnerDispatch({ type: 'log', payload: { message: [message] } })
}
})
}, [])
// events
useEffect(() => {
@ -115,7 +118,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
useEffect(() => {
scrollToBottom()
}, [newstate.journalBlocks.length, logHtmlResponse.length, toaster])
}, [newstate.journalBlocks.length, toaster])
function execute (file, cb) {
function _execute (content, cb) {

@ -24,5 +24,6 @@ export const LISTEN_ON_NETWORK = 'listenOnNetWork'
export const CMD_HISTORY = 'cmdHistory'
export interface RemixUiTerminalProps {
plugin: any
plugin: any,
onReady: (api: any) => void
}

Loading…
Cancel
Save