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

pull/5370/head
filip mertens 2 years ago
commit c300153416
  1. 6
      .circleci/config.yml
  2. 19
      apps/debugger/src/app/debugger-api.ts
  3. 4
      apps/remix-ide-e2e/src/commands/waitForElementContainsText.ts
  4. 1
      apps/remix-ide-e2e/src/local-plugin/src/app/app.tsx
  5. 10
      apps/remix-ide-e2e/src/tests/debugger.test.ts
  6. 1
      apps/remix-ide-e2e/src/tests/libraryDeployment.test.ts
  7. 4
      apps/remix-ide-e2e/src/tests/plugin_api.ts
  8. 2
      apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts
  9. 2
      apps/remix-ide/src/app/tabs/locales/en-US.js
  10. 1
      apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css
  11. 6
      apps/remix-ide/src/blockchain/blockchain.js
  12. 8
      libs/remix-analyzer/package.json
  13. 6
      libs/remix-astwalker/package.json
  14. 3
      libs/remix-core-plugin/src/lib/compiler-artefacts.ts
  15. 28
      libs/remix-core-plugin/src/lib/compiler-fetch-and-compile.ts
  16. 6
      libs/remix-core-plugin/src/lib/constants/uups.ts
  17. 13
      libs/remix-core-plugin/src/lib/offset-line-to-column-converter.ts
  18. 2
      libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts
  19. 10
      libs/remix-debug/package.json
  20. 10
      libs/remix-debug/src/Ethdebugger.ts
  21. 48
      libs/remix-debug/src/debugger/debugger.ts
  22. 4
      libs/remix-debug/src/solidity-decoder/decodeInfo.ts
  23. 244
      libs/remix-debug/src/solidity-decoder/internalCallTree.ts
  24. 4
      libs/remix-debug/src/solidity-decoder/localDecoder.ts
  25. 19
      libs/remix-debug/src/solidity-decoder/solidityProxy.ts
  26. 2
      libs/remix-debug/src/solidity-decoder/types/StringType.ts
  27. 12
      libs/remix-debug/src/source/offsetToLineColumnConverter.ts
  28. 23
      libs/remix-debug/src/source/sourceLocationTracker.ts
  29. 2
      libs/remix-debug/test/decoder/localDecoder.ts
  30. 90
      libs/remix-debug/test/decoder/localsTests/int.ts
  31. 4
      libs/remix-lib/package.json
  32. 23
      libs/remix-lib/src/util.ts
  33. 8
      libs/remix-lib/test/util.ts
  34. 6
      libs/remix-simulator/package.json
  35. 6
      libs/remix-solidity/package.json
  36. 2
      libs/remix-solidity/src/compiler/compiler-utils.ts
  37. 14
      libs/remix-tests/package.json
  38. 4
      libs/remix-tests/tests/testRunner.cli.spec.ts
  39. 0
      libs/remix-tests/tests/testRunner.spec.__
  40. 6
      libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.tsx
  41. 5
      libs/remix-ui/app/src/lib/remix-app/components/modals/matomo.tsx
  42. 6
      libs/remix-ui/app/src/lib/remix-app/remix-app.tsx
  43. 36
      libs/remix-ui/checkbox/src/lib/remix-ui-checkbox.tsx
  44. 13
      libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx
  45. 2
      libs/remix-ui/debugger-ui/src/lib/idebugger-api.ts
  46. 10
      libs/remix-ui/debugger-ui/src/lib/vm-debugger/assembly-items.tsx
  47. 6
      libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx
  48. 4
      libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger.tsx
  49. 24
      libs/remix-ui/debugger-ui/src/reducers/assembly-items.ts
  50. 2
      libs/remix-ui/helper/src/lib/components/custom-dropdown.tsx
  51. 3
      libs/remix-ui/helper/src/lib/components/custom-tooltip.tsx
  52. 3
      libs/remix-ui/helper/src/types/customtooltip.ts
  53. 14
      libs/remix-ui/home-tab/src/lib/components/customButtonGroupAsArrows.tsx
  54. 8
      libs/remix-ui/home-tab/src/lib/components/customNavButtons.tsx
  55. 20
      libs/remix-ui/home-tab/src/lib/components/homeTabFeatured.tsx
  56. 6
      libs/remix-ui/home-tab/src/lib/components/homeTabFeaturedPlugins.tsx
  57. 32
      libs/remix-ui/home-tab/src/lib/components/homeTabFile.tsx
  58. 6
      libs/remix-ui/home-tab/src/lib/components/homeTabGetStarted.tsx
  59. 28
      libs/remix-ui/home-tab/src/lib/components/homeTabLearn.tsx
  60. 2
      libs/remix-ui/home-tab/src/lib/components/homeTabTitle.tsx
  61. 3
      libs/remix-ui/publish-to-storage/src/lib/publishToIPFS.tsx
  62. 48
      libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx
  63. 4
      libs/remix-ui/run-tab/src/lib/components/contractGUI.tsx
  64. 24
      libs/remix-ui/run-tab/src/lib/components/environment.tsx
  65. 2
      libs/remix-ui/run-tab/src/lib/components/gasPrice.tsx
  66. 2
      libs/remix-ui/run-tab/src/lib/components/network.tsx
  67. 6
      libs/remix-ui/run-tab/src/lib/components/recorderCardUI.tsx
  68. 2
      libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx
  69. 4
      libs/remix-ui/run-tab/src/lib/css/run-tab.css
  70. 44
      libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx
  71. 2
      libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx
  72. 4
      libs/remix-ui/static-analyser/src/lib/Button/StaticAnalyserButton.tsx
  73. 2
      libs/remix-ui/static-analyser/src/lib/remix-ui-static-analyser.tsx
  74. 23
      libs/remix-ui/vertical-icons-panel/src/lib/components/Home.tsx
  75. 47
      libs/remix-ui/vertical-icons-panel/src/lib/components/Icon.tsx
  76. 6
      libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx
  77. 2
      libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx
  78. 6
      libs/remix-url-resolver/package.json
  79. 4
      libs/remix-ws-templates/package.json
  80. 2
      libs/remixd/package.json
  81. 2
      package.json
  82. 21
      yarn.lock

@ -64,6 +64,12 @@ jobs:
- v1-deps-{{ checksum "yarn.lock" }}
- run: yarn
- run: cd dist/libs/remix-tests && yarn
- run: cd dist/libs/remix-tests && yarn add @remix-project/remix-url-resolver ../../libs/remix-url-resolver
- run: cd dist/libs/remix-tests && yarn add @remix-project/remix-lib ../../libs/remix-lib
- run: cd dist/libs/remix-tests && yarn add @remix-project/remix-solidity ../../libs/remix-solidity
- run: cd dist/libs/remix-tests && yarn add @remix-project/remix-simulator ../../libs/remix-simulator
- run: cd dist/libs/remix-tests && ./bin/remix-tests ./../../../libs/remix-tests/tests/examples_0/assert_ok_test.sol
- run: node dist/libs/remix-tests/bin/remix-tests ./libs/remix-tests/tests/examples_0/assert_ok_test.sol
- run: yarn run test:libs
remix-ide-browser:

@ -1,7 +1,7 @@
import Web3 from 'web3'
import remixDebug, { TransactionDebugger as Debugger } from '@remix-project/remix-debug'
import { CompilerAbstract } from '@remix-project/remix-solidity'
import { lineText } from '@remix-ui/editor'
export const DebuggerApiMixin = (Base) => class extends Base {
@ -39,10 +39,25 @@ export const DebuggerApiMixin = (Base) => class extends Base {
async discardHighlight () {
await this.call('editor', 'discardHighlight')
await this.call('editor', 'discardLineTexts' as any)
}
async highlight (lineColumnPos, path) {
async highlight (lineColumnPos, path, rawLocation, stepDetail, lineGasCost) {
await this.call('editor', 'highlight', lineColumnPos, path, '', { focus: true })
const label = `${stepDetail.op} costs ${stepDetail.gasCost} gas - this line costs ${lineGasCost} gas - ${stepDetail.gas} gas left`
const linetext: lineText = {
content: label,
position: lineColumnPos,
hide: false,
className: 'text-muted small',
afterContentClassName: 'text-muted small fas fa-gas-pump pl-4',
from: 'debugger',
hoverMessage: [{
value: label,
},
],
}
await this.call('editor', 'addLineText' as any, linetext, path)
}
async getFile (path) {

@ -4,8 +4,10 @@ import EventEmitter from 'events'
class WaitForElementContainsText extends EventEmitter {
command (this: NightwatchBrowser, id: string, value: string, timeout = 10000): NightwatchBrowser {
let waitId // eslint-disable-line
let currentValue
const runid = setInterval(() => {
this.api.getText(id, (result) => {
currentValue = result.value
if (typeof result.value === 'string' && result.value.indexOf(value) !== -1) {
clearInterval(runid)
clearTimeout(waitId)
@ -17,7 +19,7 @@ class WaitForElementContainsText extends EventEmitter {
waitId = setTimeout(() => {
clearInterval(runid)
this.api.assert.fail(`TimeoutError: An error occurred while running .waitForElementContainsText() command on ${id} after ${timeout} milliseconds`)
this.api.assert.fail(`TimeoutError: An error occurred while running .waitForElementContainsText() command on ${id} after ${timeout} milliseconds. expected: ${value} - got: ${currentValue}`)
}, timeout)
return this
}

@ -110,6 +110,7 @@ function App () {
placeholder="Enter payload here..."
value={payload}
onChange={handleChange}
data-id="payload-input"
/>
{profiles.map((profile: Profile) => {
const methods = profile.methods.map((method: string) => {

@ -97,11 +97,6 @@ module.exports = {
locateStrategy: 'xpath',
selector: '//*[@data-id="treeViewLivm trace step" and contains(.,"545")]',
})
.goToVMTraceStep(10)
.waitForElementVisible({
locateStrategy: 'xpath',
selector: '//*[@data-id="treeViewLivm trace step" and contains(.,"10")]',
})
.getEditorValue((content) => {
browser.assert.ok(content.indexOf(`constructor (string memory name_, string memory symbol_) {
_name = name_;
@ -109,6 +104,11 @@ module.exports = {
}`) !== -1,
'current displayed content is not from the ERC20 source code')
})
.goToVMTraceStep(10)
.waitForElementVisible({
locateStrategy: 'xpath',
selector: '//*[@data-id="treeViewLivm trace step" and contains(.,"10")]',
})
},
'Should display correct source highlighting while debugging a contract which has ABIEncoderV2 #group2': function (browser: NightwatchBrowser) {

@ -21,6 +21,7 @@ module.exports = {
let addressRef: string
browser.verifyContracts(['test'])
.clickLaunchIcon('udapp')
.click('#selectExEnv')
.selectContract('test')
.createContract('')
.getAddressAtPosition(0, (address) => {

@ -50,7 +50,7 @@ const debugValues = async function (browser: NightwatchBrowser, field: string, e
const setPayload = async (browser: NightwatchBrowser, payload: any) => {
return new Promise((resolve) => {
if (typeof payload !== 'string') payload = JSON.stringify(payload)
browser.clearValue('//*[@id="payload"]').setValue('//*[@id="payload"]', payload, (result) => {
browser.clearValue('//*[@id="payload"]').pause(500).setValue('//*[@id="payload"]', payload, (result) => {
resolve(result)
})
})
@ -419,7 +419,7 @@ module.exports = {
.addFile('test_modal.js', { content: testModalToasterApi })
.executeScriptInTerminal('remix.execute(\'test_modal.js\')')
.useCss()
.waitForElementVisible('*[data-id="test_id_1_ModalDialogModalBody-react"]', 60000)
.waitForElementVisible('*[data-id="test_id_1_ModalDialogModalBody-react"]', 65000)
.assert.containsText('*[data-id="test_id_1_ModalDialogModalBody-react"]', 'message 1')
.modalFooterOKClick('test_id_1_')
// check the script runner notifications

@ -290,7 +290,7 @@ module.exports = {
.waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalFailed()', 60000)
.waitForElementVisible('*[data-id="dropdownPanelSolidityLocals"]').pause(1000)
.waitForElementContainsText('*[data-id="solidityLocals"]', 'no locals', 60000)
.waitForElementContainsText('*[data-id="solidityLocals"]', 'No data available', 60000)
.goToVMTraceStep(316)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalFailed()', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'vote(proposal)', 60000)

@ -60,7 +60,7 @@ export default {
'filePanel.compileForNahmii': 'Compile for Nahmii',
'filePanel.createNewFile': 'Create New File',
'filePanel.createNewFolder': 'Create New Folder',
'filePanel.publishToGist': 'Publish all the current workspace files (only root) to a github gist',
'filePanel.publishToGist': 'Publish all the current workspace files to a github gist',
'filePanel.uploadFile': 'Load a local file into current workspace',
'filePanel.updateGist': 'Update the current [gist] explorer',

@ -4018,6 +4018,7 @@ input[type="submit"].btn-block {
.card-body {
flex: 1 1 auto;
padding: 1.25rem;
color: #b2b8cd;
}
.card-title {
color: #DFE1EA;

@ -11,7 +11,7 @@ import InjectedProvider from './providers/injected.js'
import NodeProvider from './providers/node.js'
import { execution, EventManager, helpers } from '@remix-project/remix-lib'
import { etherScanLink } from './helper'
import { logBuilder, cancelUpgradeMsg, cancelProxyMsg } from "@remix-ui/helper"
import { logBuilder, cancelUpgradeMsg, cancelProxyMsg, addressToString } from "@remix-ui/helper"
const { txFormat, txExecution, typeConversion, txListener: Txlistener, TxRunner, TxRunnerWeb3, txHelper } = execution
const { txResultHelper: resultToRemixTx } = helpers
const packageJson = require('../../../../package.json')
@ -180,7 +180,7 @@ export class Blockchain extends Plugin {
if (networkInfo.name === 'VM') this.config.set('vm/proxy', address)
else this.config.set(`${networkInfo.name}/${networkInfo.currentFork}/${networkInfo.id}/proxy`, address)
_paq.push(['trackEvent', 'blockchain', 'Deploy With Proxy', 'Proxy deployment successful'])
return this.call('udapp', 'resolveContractAndAddInstance', implementationContractObject, address)
this.call('udapp', 'addInstance', addressToString(address), implementationContractObject.abi, implementationContractObject.name)
}
this.runTx(args, confirmationCb, continueCb, promptCb, finalCb)
@ -223,7 +223,7 @@ export class Blockchain extends Plugin {
return this.call('terminal', 'logHtml', log)
}
_paq.push(['trackEvent', 'blockchain', 'Upgrade With Proxy', 'Upgrade Successful'])
return this.call('udapp', 'resolveContractAndAddInstance', newImplementationContractObject, proxyAddress)
this.call('udapp', 'addInstance', addressToString(proxyAddress), newImplementationContractObject.abi, newImplementationContractObject.name)
}
this.runTx(args, confirmationCb, continueCb, promptCb, finalCb)
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-analyzer",
"version": "0.5.28",
"version": "0.5.29",
"description": "Tool to perform static analysis on Solidity smart contracts",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -22,8 +22,8 @@
"@ethereumjs/block": "^3.5.1",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-astwalker": "^0.0.49",
"@remix-project/remix-lib": "^0.5.19",
"@remix-project/remix-astwalker": "^0.0.50",
"@remix-project/remix-lib": "^0.5.20",
"async": "^2.6.2",
"ethereumjs-util": "^7.0.10",
"ethers": "^5.4.2",
@ -52,5 +52,5 @@
"typescript": "^3.7.5"
},
"typings": "src/index.d.ts",
"gitHead": "2cec195f5a3678b17745155536a1714d9b1a5694"
"gitHead": "569f7d53f6f218d99aa8281929b541ab7e00058f"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-astwalker",
"version": "0.0.49",
"version": "0.0.50",
"description": "Tool to walk through Solidity AST",
"main": "src/index.js",
"scripts": {
@ -37,7 +37,7 @@
"@ethereumjs/block": "^3.5.1",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.19",
"@remix-project/remix-lib": "^0.5.20",
"@types/tape": "^4.2.33",
"async": "^2.6.2",
"ethereumjs-util": "^7.0.10",
@ -54,5 +54,5 @@
"tap-spec": "^5.0.0"
},
"typings": "src/index.d.ts",
"gitHead": "2cec195f5a3678b17745155536a1714d9b1a5694"
"gitHead": "569f7d53f6f218d99aa8281929b541ab7e00058f"
}

@ -198,8 +198,7 @@ export class CompilerArtefacts extends Plugin {
return this.compilersArtefactsPerFile[file]
}
// compilerData is a CompilerAbstract object
addResolvedContract (address, compilerData) {
addResolvedContract (address: string, compilerData: CompilerAbstract) {
this.compilersArtefacts[address] = compilerData
}

@ -4,6 +4,7 @@ import { util } from '@remix-project/remix-lib'
import { toChecksumAddress } from 'ethereumjs-util'
import { fetchContractFromEtherscan } from './helpers/fetch-etherscan'
import { fetchContractFromSourcify } from './helpers/fetch-sourcify'
import { UUPSDeployedByteCode, UUPSCompilerVersion } from './constants/uups'
const profile = {
name: 'fetchAndCompile',
@ -48,6 +49,33 @@ export class FetchAndCompile extends Plugin {
if (resolved) return resolved
if (this.unresolvedAddresses.includes(contractAddress)) return localCompilation()
if (codeAtAddress === '0x' + UUPSDeployedByteCode) { // proxy
const settings = {
version: UUPSCompilerVersion,
language: 'Solidity',
evmVersion: null,
optimize: false,
runs: 0
}
const compilationTargets = {
'proxy.sol': { content: 'import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.0/contracts/proxy/ERC1967/ERC1967Proxy.sol";' }
}
const compData = await compile(
compilationTargets,
settings,
async (url, cb) => {
// we first try to resolve the content from the compilation target using a more appropiate path
const path = `${targetPath}/${url}`
if (compilationTargets[path] && compilationTargets[path].content) {
return cb(null, compilationTargets[path].content)
} else {
await this.call('contentImport', 'resolveAndSave', url).then((result) => cb(null, result)).catch((error) => cb(error.message))
}
})
await this.call('compilerArtefacts', 'addResolvedContract', contractAddress, compData)
return compData
}
// sometimes when doing an internal call, the only available artifact is the Solidity interface.
// resolving addresses of internal call would allow to step over the source code, even if the declaration was made using an Interface.

File diff suppressed because one or more lines are too long

@ -13,9 +13,11 @@ const profile = {
export class OffsetToLineColumnConverter extends Plugin {
lineBreakPositionsByContent: Record<number, Array<number>>
sourceMappingDecoder: any
offsetConvertion: any
constructor () {
super(profile)
this.lineBreakPositionsByContent = {}
this.offsetConvertion = {}
this.sourceMappingDecoder = sourceMappingDecoder
}
@ -45,7 +47,15 @@ export class OffsetToLineColumnConverter extends Plugin {
}
}
}
return this.sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, this.lineBreakPositionsByContent[file])
const token = `${rawLocation.start}:${rawLocation.length}:${file}`
if (this.offsetConvertion[token]) {
return this.offsetConvertion[token]
} else {
const convertion = this.sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, this.lineBreakPositionsByContent[file])
this.offsetConvertion[token] = convertion
return convertion
}
}
/**
@ -64,6 +74,7 @@ export class OffsetToLineColumnConverter extends Plugin {
*/
clear () {
this.lineBreakPositionsByContent = {}
this.offsetConvertion = {}
}
/**

@ -119,4 +119,4 @@ export class OpenZeppelinProxy extends Plugin {
newImplementationContractObject.name = proxyName
this.blockchain.upgradeProxy(proxyAddress, newImplAddress, data, newImplementationContractObject)
}
}
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-debug",
"version": "0.5.19",
"version": "0.5.20",
"description": "Tool to debug Ethereum transactions",
"contributors": [
{
@ -22,9 +22,9 @@
"@ethereumjs/common": "^2.5.0",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-astwalker": "^0.0.49",
"@remix-project/remix-lib": "^0.5.19",
"@remix-project/remix-simulator": "^0.2.19",
"@remix-project/remix-astwalker": "^0.0.50",
"@remix-project/remix-lib": "^0.5.20",
"@remix-project/remix-simulator": "^0.2.20",
"ansi-gray": "^0.1.1",
"async": "^2.6.2",
"color-support": "^1.1.3",
@ -68,5 +68,5 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme",
"typings": "src/index.d.ts",
"gitHead": "2cec195f5a3678b17745155536a1714d9b1a5694"
"gitHead": "569f7d53f6f218d99aa8281929b541ab7e00058f"
}

@ -32,9 +32,11 @@ export class Ethdebugger {
storageResolver
callTree
breakpointManager
offsetToLineColumnConverter
constructor (opts) {
this.compilationResult = opts.compilationResult || function (contractAddress) { return null }
this.offsetToLineColumnConverter = opts.offsetToLineColumnConverter
this.web3 = opts.web3
this.opts = opts
@ -49,7 +51,8 @@ export class Ethdebugger {
this.traceManager,
this.solidityProxy,
this.codeManager,
{ ...opts, includeLocalVariables })
{ ...opts, includeLocalVariables },
this.offsetToLineColumnConverter)
}
setManagers () {
@ -63,7 +66,8 @@ export class Ethdebugger {
this.traceManager,
this.solidityProxy,
this.codeManager,
{ ...this.opts, includeLocalVariables })
{ ...this.opts, includeLocalVariables },
this.offsetToLineColumnConverter)
}
resolveStep (index) {
@ -71,7 +75,7 @@ export class Ethdebugger {
}
setCompilationResult (compilationResult) {
this.solidityProxy.reset((compilationResult && compilationResult.data) || {})
this.solidityProxy.reset((compilationResult && compilationResult.data) || {}, (compilationResult && compilationResult.source && compilationResult.source.sources) || {})
}
async sourceLocationFromVMTraceIndex (address, stepIndex) {

@ -14,6 +14,8 @@ export class Debugger {
breakPointManager
step_manager // eslint-disable-line camelcase
vmDebuggerLogic
currentFile = -1
currentLine = -1
constructor (options) {
this.event = new EventManager()
@ -26,7 +28,8 @@ export class Debugger {
this.debugger = new Ethdebugger({
web3: options.web3,
debugWithGeneratedSources: options.debugWithGeneratedSources,
compilationResult: this.compilationResult
compilationResult: this.compilationResult,
offsetToLineColumnConverter: this.offsetToLineColumnConverter
})
const { traceManager, callTree, solidityProxy } = this.debugger
@ -73,35 +76,56 @@ export class Debugger {
const compilationResultForAddress = await this.compilationResult(address)
if (!compilationResultForAddress) {
this.event.trigger('newSourceLocation', [null])
this.currentFile = -1
this.currentLine = -1
this.vmDebuggerLogic.event.trigger('lineGasCostChanged', [null])
return
}
this.debugger.callTree.sourceLocationTracker.getValidSourceLocationFromVMTraceIndex(address, index, compilationResultForAddress.data.contracts).then(async (rawLocation) => {
this.debugger.callTree.getValidSourceLocationFromVMTraceIndexFromCache(address, index, compilationResultForAddress.data.contracts).then(async (rawLocationAndOpcode) => {
if (compilationResultForAddress && compilationResultForAddress.data) {
const rawLocation = rawLocationAndOpcode.sourceLocation
const stepDetail = rawLocationAndOpcode.stepDetail
const generatedSources = this.debugger.callTree.sourceLocationTracker.getGeneratedSourcesFromAddress(address)
const astSources = Object.assign({}, compilationResultForAddress.data.sources)
const sources = Object.assign({}, compilationResultForAddress.source.sources)
if (generatedSources) {
for (const genSource of generatedSources) {
astSources[genSource.name] = { id: genSource.id, ast: genSource.ast }
sources[genSource.name] = { content: genSource.contents }
}
const lineColumnPos = rawLocationAndOpcode.lineColumnPos
let lineGasCostObj = null
try {
lineGasCostObj = await this.debugger.callTree.getGasCostPerLine(rawLocation.file, lineColumnPos.start.line)
} catch (e) {
console.log(e)
}
const lineColumnPos = await this.offsetToLineColumnConverter.offsetToLineColumn(rawLocation, rawLocation.file, sources, astSources)
this.event.trigger('newSourceLocation', [lineColumnPos, rawLocation, generatedSources, address])
this.event.trigger('newSourceLocation', [lineColumnPos, rawLocation, generatedSources, address, stepDetail, (lineGasCostObj && lineGasCostObj.gasCost) || -1])
this.vmDebuggerLogic.event.trigger('sourceLocationChanged', [rawLocation])
if (this.currentFile !== rawLocation.file || this.currentLine !== lineColumnPos.start.line) {
const instructionIndexes = lineGasCostObj.indexes.map((index) => { // translate from vmtrace index to instruction index
return this.debugger.codeManager.getInstructionIndex(address, index)
})
this.vmDebuggerLogic.event.trigger('lineGasCostChanged', [instructionIndexes, lineColumnPos.start.line ])
this.currentFile = rawLocation.file
this.currentLine = lineColumnPos.start.line
}
} else {
this.event.trigger('newSourceLocation', [null])
this.vmDebuggerLogic.event.trigger('sourceLocationChanged', [null])
this.currentFile = -1
this.currentLine = -1
this.vmDebuggerLogic.event.trigger('lineGasCostChanged', [null])
}
}).catch((_error) => {
this.event.trigger('newSourceLocation', [null])
this.vmDebuggerLogic.event.trigger('sourceLocationChanged', [null])
this.currentFile = -1
this.currentLine = -1
this.vmDebuggerLogic.event.trigger('lineGasCostChanged', [null])
})
// })
} catch (error) {
this.event.trigger('newSourceLocation', [null])
this.vmDebuggerLogic.event.trigger('sourceLocationChanged', [null])
this.currentFile = -1
this.currentLine = -1
this.vmDebuggerLogic.event.trigger('lineGasCostChanged', [null])
return console.log(error)
}
}

@ -241,9 +241,7 @@ function getStructMembers (type, stateDefinitions, contractName, location) {
if (type.indexOf('.') === -1) {
type = contractName + '.' + type
}
if (!contractName) {
contractName = type.split('.')[0]
}
contractName = type.split('.')[0]
const state = stateDefinitions[contractName]
if (state) {
for (const dec of state.stateDefinitions) {

@ -7,6 +7,16 @@ import { parseType } from './decodeInfo'
import { isContractCreation, isCallInstruction, isCreateInstruction, isJumpDestInstruction } from '../trace/traceHelper'
import { extractLocationFromAstVariable } from './types/util'
export type StepDetail = {
depth: number,
gas: number | string,
gasCost: number,
memory: number[],
op: string,
pc: number,
stack: number[],
}
/**
* Tree representing internal jump into function.
* Triggers `callTreeReady` event when tree is ready
@ -27,6 +37,15 @@ export class InternalCallTree {
functionDefinitionByFile
astWalker
reducedTrace
locationAndOpcodePerVMTraceIndex: {
[Key: number]: any
}
gasCostPerLine
offsetToLineColumnConverter
pendingConstructorExecutionAt: number
pendingConstructorId: number
pendingConstructor
constructorsStartExecution
/**
* constructor
@ -37,14 +56,16 @@ export class InternalCallTree {
* @param {Object} codeManager - code manager
* @param {Object} opts - { includeLocalVariables, debugWithGeneratedSources }
*/
constructor (debuggerEvent, traceManager, solidityProxy, codeManager, opts) {
constructor (debuggerEvent, traceManager, solidityProxy, codeManager, opts, offsetToLineColumnConverter?) {
this.includeLocalVariables = opts.includeLocalVariables
this.debugWithGeneratedSources = opts.debugWithGeneratedSources
this.event = new EventManager()
this.solidityProxy = solidityProxy
this.traceManager = traceManager
this.offsetToLineColumnConverter = offsetToLineColumnConverter
this.sourceLocationTracker = new SourceLocationTracker(codeManager, { debugWithGeneratedSources: opts.debugWithGeneratedSources })
debuggerEvent.register('newTraceLoaded', (trace) => {
const time = Date.now()
this.reset()
if (!this.solidityProxy.loaded()) {
this.event.trigger('callTreeBuildFailed', ['compilation result not loaded. Cannot build internal call tree'])
@ -52,11 +73,17 @@ export class InternalCallTree {
// each recursive call to buildTree represent a new context (either call, delegatecall, internal function)
const calledAddress = traceManager.getCurrentCalledAddressAt(0)
const isCreation = isContractCreation(calledAddress)
buildTree(this, 0, '', true, isCreation).then((result) => {
const scopeId = '1'
this.scopeStarts[0] = scopeId
this.scopes[scopeId] = { firstStep: 0, locals: {}, isCreation, gasCost: 0 }
buildTree(this, 0, scopeId, isCreation).then((result) => {
if (result.error) {
this.event.trigger('callTreeBuildFailed', [result.error])
} else {
createReducedTrace(this, traceManager.trace.length - 1)
console.log('call tree build lasts ', (Date.now() - time) / 1000)
this.event.trigger('callTreeReady', [this.scopes, this.scopeStarts])
}
}, (reason) => {
@ -85,10 +112,16 @@ export class InternalCallTree {
this.functionCallStack = []
this.functionDefinitionsByScope = {}
this.scopeStarts = {}
this.gasCostPerLine = {}
this.variableDeclarationByFile = {}
this.functionDefinitionByFile = {}
this.astWalker = new AstWalker()
this.reducedTrace = []
this.locationAndOpcodePerVMTraceIndex = {}
this.pendingConstructorExecutionAt = -1
this.pendingConstructorId = -1
this.constructorsStartExecution = {}
this.pendingConstructor = null
}
/**
@ -123,6 +156,7 @@ export class InternalCallTree {
const scope = this.findScope(vmtraceIndex)
if (!scope) return []
let scopeId = this.scopeStarts[scope.firstStep]
const scopeDetail = this.scopes[scopeId]
const functions = []
if (!scopeId) return functions
let i = 0
@ -132,7 +166,7 @@ export class InternalCallTree {
if (i > 1000) throw new Error('retrieFunctionStack: recursion too deep')
const functionDefinition = this.functionDefinitionsByScope[scopeId]
if (functionDefinition !== undefined) {
functions.push(functionDefinition)
functions.push({ ...functionDefinition, ...scopeDetail })
}
const parent = this.parentScope(scopeId)
if (!parent) break
@ -141,32 +175,42 @@ export class InternalCallTree {
return functions
}
async extractSourceLocation (step) {
async extractSourceLocation (step: number, address?: string) {
try {
const address = this.traceManager.getCurrentCalledAddressAt(step)
const location = await this.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, step, this.solidityProxy.contracts)
return location
if (!address) address = this.traceManager.getCurrentCalledAddressAt(step)
return await this.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, step, this.solidityProxy.contracts)
} catch (error) {
throw new Error('InternalCallTree - Cannot retrieve sourcelocation for step ' + step + ' ' + error)
}
}
async extractValidSourceLocation (step) {
async extractValidSourceLocation (step: number, address?: string) {
try {
const address = this.traceManager.getCurrentCalledAddressAt(step)
const location = await this.sourceLocationTracker.getValidSourceLocationFromVMTraceIndex(address, step, this.solidityProxy.contracts)
return location
if (!address) address = this.traceManager.getCurrentCalledAddressAt(step)
return await this.sourceLocationTracker.getValidSourceLocationFromVMTraceIndex(address, step, this.solidityProxy.contracts)
} catch (error) {
throw new Error('InternalCallTree - Cannot retrieve valid sourcelocation for step ' + step + ' ' + error)
}
}
async getValidSourceLocationFromVMTraceIndexFromCache (address: string, step: number, contracts: any) {
return await this.sourceLocationTracker.getValidSourceLocationFromVMTraceIndexFromCache(address, step, contracts, this.locationAndOpcodePerVMTraceIndex)
}
async getGasCostPerLine(file: number, line: number) {
if (this.gasCostPerLine[file] && this.gasCostPerLine[file][line]) {
return this.gasCostPerLine[file][line]
}
throw new Error('Could not find gas cost per line')
}
}
async function buildTree (tree, step, scopeId, isExternalCall, isCreation) {
async function buildTree (tree, step, scopeId, isCreation, functionDefinition?, contractObj?, sourceLocation?, validSourceLocation?) {
let subScope = 1
tree.scopeStarts[step] = scopeId
tree.scopes[scopeId] = { firstStep: step, locals: {}, isCreation }
if (functionDefinition) {
await registerFunctionParameters(tree, functionDefinition, step, scopeId, contractObj, validSourceLocation)
}
function callDepthChange (step, trace) {
if (step + 1 < trace.length) {
return trace[step].depth !== trace[step + 1].depth
@ -183,30 +227,104 @@ async function buildTree (tree, step, scopeId, isExternalCall, isCreation) {
included.file === source.file)
}
let currentSourceLocation = { start: -1, length: -1, file: -1 }
let currentSourceLocation = sourceLocation || { start: -1, length: -1, file: -1, jump: '-' }
let previousSourceLocation = currentSourceLocation
let previousValidSourceLocation = validSourceLocation || currentSourceLocation
while (step < tree.traceManager.trace.length) {
let sourceLocation
let newLocation = false
let validSourceLocation
let address
try {
sourceLocation = await tree.extractSourceLocation(step)
address = tree.traceManager.getCurrentCalledAddressAt(step)
sourceLocation = await tree.extractSourceLocation(step, address)
if (!includedSource(sourceLocation, currentSourceLocation)) {
tree.reducedTrace.push(step)
currentSourceLocation = sourceLocation
newLocation = true
}
const amountOfSources = tree.sourceLocationTracker.getTotalAmountOfSources(address, tree.solidityProxy.contracts)
if (tree.sourceLocationTracker.isInvalidSourceLocation(currentSourceLocation, amountOfSources)) { // file is -1 or greater than amount of sources
validSourceLocation = previousValidSourceLocation
} else
validSourceLocation = currentSourceLocation
} catch (e) {
return { outStep: step, error: 'InternalCallTree - Error resolving source location. ' + step + ' ' + e }
}
if (!sourceLocation) {
return { outStep: step, error: 'InternalCallTree - No source Location. ' + step }
}
const isCallInstrn = isCallInstruction(tree.traceManager.trace[step])
const isCreateInstrn = isCreateInstruction(tree.traceManager.trace[step])
const stepDetail: StepDetail = tree.traceManager.trace[step]
const nextStepDetail: StepDetail = tree.traceManager.trace[step + 1]
if (stepDetail && nextStepDetail) {
stepDetail.gasCost = parseInt(stepDetail.gas as string) - parseInt(nextStepDetail.gas as string)
}
// gas per line
let lineColumnPos
if (tree.offsetToLineColumnConverter) {
try {
const generatedSources = tree.sourceLocationTracker.getGeneratedSourcesFromAddress(address)
const astSources = Object.assign({}, tree.solidityProxy.sources)
const sources = Object.assign({}, tree.solidityProxy.sourcesCode)
if (generatedSources) {
for (const genSource of generatedSources) {
astSources[genSource.name] = { id: genSource.id, ast: genSource.ast }
sources[genSource.name] = { content: genSource.contents }
}
}
lineColumnPos = await tree.offsetToLineColumnConverter.offsetToLineColumn(validSourceLocation, validSourceLocation.file, sources, astSources)
if (!tree.gasCostPerLine[validSourceLocation.file]) tree.gasCostPerLine[validSourceLocation.file] = {}
if (!tree.gasCostPerLine[validSourceLocation.file][lineColumnPos.start.line]) {
tree.gasCostPerLine[validSourceLocation.file][lineColumnPos.start.line] = {
gasCost: 0,
indexes: []
}
}
tree.gasCostPerLine[validSourceLocation.file][lineColumnPos.start.line].gasCost += stepDetail.gasCost
tree.gasCostPerLine[validSourceLocation.file][lineColumnPos.start.line].indexes.push(step)
} catch (e) {
console.log(e)
}
}
tree.locationAndOpcodePerVMTraceIndex[step] = { sourceLocation, stepDetail, lineColumnPos }
tree.scopes[scopeId].gasCost += stepDetail.gasCost
const contractObj = await tree.solidityProxy.contractObjectAtAddress(address)
const generatedSources = getGeneratedSources(tree, scopeId, contractObj)
const functionDefinition = resolveFunctionDefinition(tree, sourceLocation, generatedSources)
const isInternalTxInstrn = isCallInstruction(stepDetail)
const isCreateInstrn = isCreateInstruction(stepDetail)
// we are checking if we are jumping in a new CALL or in an internal function
if (isCallInstrn || sourceLocation.jump === 'i') {
const constructorExecutionStarts = tree.pendingConstructorExecutionAt > -1 && tree.pendingConstructorExecutionAt < validSourceLocation.start
if (functionDefinition && functionDefinition.kind === 'constructor' && tree.pendingConstructorExecutionAt === -1 && !tree.constructorsStartExecution[functionDefinition.id]) {
tree.pendingConstructorExecutionAt = validSourceLocation.start
tree.pendingConstructorId = functionDefinition.id
tree.pendingConstructor = functionDefinition
// from now on we'll be waiting for a change in the source location which will mark the beginning of the constructor execution.
// constructorsStartExecution allows to keep track on which constructor has already been executed.
}
const internalfunctionCall = functionDefinition && previousSourceLocation.jump === 'i'
if (constructorExecutionStarts || isInternalTxInstrn || internalfunctionCall) {
try {
const externalCallResult = await buildTree(tree, step + 1, scopeId === '' ? subScope.toString() : scopeId + '.' + subScope, isCallInstrn, isCreateInstrn)
const newScopeId = scopeId === '' ? subScope.toString() : scopeId + '.' + subScope
tree.scopeStarts[step] = newScopeId
tree.scopes[newScopeId] = { firstStep: step, locals: {}, isCreation, gasCost: 0 }
// for the ctor we we are at the start of its trace, we have to replay this step in order to catch all the locals:
const nextStep = constructorExecutionStarts ? step : step + 1
if (constructorExecutionStarts) {
tree.constructorsStartExecution[tree.pendingConstructorId] = tree.pendingConstructorExecutionAt
tree.pendingConstructorExecutionAt = -1
tree.pendingConstructorId = -1
await registerFunctionParameters(tree, tree.pendingConstructor, step, newScopeId, contractObj, previousValidSourceLocation)
tree.pendingConstructor = null
}
const externalCallResult = await buildTree(tree, nextStep, newScopeId, isCreateInstrn, functionDefinition, contractObj, sourceLocation, validSourceLocation)
if (externalCallResult.error) {
return { outStep: step, error: 'InternalCallTree - ' + externalCallResult.error }
} else {
@ -216,7 +334,7 @@ async function buildTree (tree, step, scopeId, isExternalCall, isCreation) {
} catch (e) {
return { outStep: step, error: 'InternalCallTree - ' + e.message }
}
} else if ((isExternalCall && callDepthChange(step, tree.traceManager.trace)) || (!isExternalCall && sourceLocation.jump === 'o')) {
} else if (callDepthChange(step, tree.traceManager.trace) || (sourceLocation.jump === 'o' && functionDefinition)) {
// if not, we might be returning from a CALL or internal function. This is what is checked here.
tree.scopes[scopeId].lastStep = step
return { outStep: step + 1 }
@ -224,9 +342,10 @@ async function buildTree (tree, step, scopeId, isExternalCall, isCreation) {
// if not, we are in the current scope.
// We check in `includeVariableDeclaration` if there is a new local variable in scope for this specific `step`
if (tree.includeLocalVariables) {
await includeVariableDeclaration(tree, step, sourceLocation, scopeId, newLocation, previousSourceLocation)
await includeVariableDeclaration(tree, step, sourceLocation, scopeId, contractObj, generatedSources)
}
previousSourceLocation = sourceLocation
previousValidSourceLocation = validSourceLocation
step++
}
}
@ -245,10 +364,33 @@ function getGeneratedSources (tree, scopeId, contractObj) {
return null
}
async function includeVariableDeclaration (tree, step, sourceLocation, scopeId, newLocation, previousSourceLocation) {
const contractObj = await tree.solidityProxy.contractObjectAt(step)
async function registerFunctionParameters (tree, functionDefinition, step, scopeId, contractObj, sourceLocation) {
tree.functionCallStack.push(step)
const functionDefinitionAndInputs = { functionDefinition, inputs: [] }
// means: the previous location was a function definition && JUMPDEST
// => we are at the beginning of the function and input/output are setup
try {
const stack = tree.traceManager.getStackAt(step)
const states = tree.solidityProxy.extractStatesDefinitions()
if (functionDefinition.parameters) {
const inputs = functionDefinition.parameters
const outputs = functionDefinition.returnParameters
// input params
if (inputs && inputs.parameters) {
functionDefinitionAndInputs.inputs = addParams(inputs, tree, scopeId, states, contractObj, sourceLocation, stack.length, inputs.parameters.length, -1)
}
// output params
if (outputs) addParams(outputs, tree, scopeId, states, contractObj, sourceLocation, stack.length, 0, 1)
}
} catch (error) {
console.log(error)
}
tree.functionDefinitionsByScope[scopeId] = functionDefinitionAndInputs
}
async function includeVariableDeclaration (tree, step, sourceLocation, scopeId, contractObj, generatedSources) {
let states = null
const generatedSources = getGeneratedSources(tree, scopeId, contractObj)
const variableDeclarations = resolveVariableDeclaration(tree, sourceLocation, generatedSources)
// using the vm trace step, the current source location and the ast,
// we check if the current vm trace step target a new ast node of type VariableDeclaration
@ -278,49 +420,6 @@ async function includeVariableDeclaration (tree, step, sourceLocation, scopeId,
}
}
}
// we check here if we are at the beginning inside a new function.
// if that is the case, we have to add to locals tree the inputs and output params
const functionDefinition = resolveFunctionDefinition(tree, previousSourceLocation, generatedSources)
if (!functionDefinition) return
const previousIsJumpDest2 = isJumpDestInstruction(tree.traceManager.trace[step - 2])
const previousIsJumpDest1 = isJumpDestInstruction(tree.traceManager.trace[step - 1])
const isConstructor = functionDefinition.kind === 'constructor'
if (newLocation && (previousIsJumpDest1 || previousIsJumpDest2 || isConstructor)) {
tree.functionCallStack.push(step)
const functionDefinitionAndInputs = { functionDefinition, inputs: [] }
// means: the previous location was a function definition && JUMPDEST
// => we are at the beginning of the function and input/output are setup
try {
const stack = tree.traceManager.getStackAt(step)
states = tree.solidityProxy.extractStatesDefinitions()
if (functionDefinition.parameters) {
const inputs = functionDefinition.parameters
const outputs = functionDefinition.returnParameters
// for (const element of functionDefinition.parameters) {
// if (element.nodeType === 'ParameterList') {
// if (!inputs) inputs = element
// else {
// outputs = element
// break
// }
// }
// }
// input params
if (inputs && inputs.parameters) {
functionDefinitionAndInputs.inputs = addParams(inputs, tree, scopeId, states, contractObj, previousSourceLocation, stack.length, inputs.parameters.length, -1)
}
// output params
if (outputs) addParams(outputs, tree, scopeId, states, contractObj, previousSourceLocation, stack.length, 0, 1)
}
} catch (error) {
console.log(error)
}
tree.functionDefinitionsByScope[scopeId] = functionDefinitionAndInputs
}
}
// this extract all the variable declaration for a given ast and file
@ -388,7 +487,8 @@ function addParams (parameterList, tree, scopeId, states, contractObj, sourceLoc
type: parseType(param.typeDescriptions.typeString, states, contractName, location),
stackDepth: stackDepth,
sourceLocation: sourceLocation,
abi: contractObj.contract.abi
abi: contractObj.contract.abi,
isParameter: true
}
params.push(attributesName)
}

@ -11,7 +11,7 @@ export async function solidityLocals (vmtraceIndex, internalTreeCall, stack, mem
let anonymousIncr = 1
for (const local in scope.locals) {
const variable = scope.locals[local]
if (variable.stackDepth < stack.length && variable.sourceLocation.start <= currentSourceLocation.start) {
if (variable.stackDepth < stack.length && (variable.sourceLocation.start <= currentSourceLocation.start || variable.isParameter)) {
let name = variable.name
if (name.indexOf('$') !== -1) {
name = '<' + anonymousIncr + '>'
@ -21,7 +21,7 @@ export async function solidityLocals (vmtraceIndex, internalTreeCall, stack, mem
locals[name] = await variable.type.decodeFromStack(variable.stackDepth, stack, memory, storageResolver, calldata, cursor, variable)
} catch (e) {
console.log(e)
locals[name] = { error: '<decoding failed - ' + e.message + '>' }
locals[name] = { error: '<decoding failed - ' + e.message + '>', type: variable && variable.type && variable.type.typeName || 'unknown' }
}
}
}

@ -10,6 +10,8 @@ export class SolidityProxy {
getCode
sources
contracts
compilationResult
sourcesCode
constructor ({ getCurrentCalledAddressAt, getCode }) {
this.cache = new Cache()
@ -23,9 +25,10 @@ export class SolidityProxy {
*
* @param {Object} compilationResult - result os a compilatiion (diectly returned by the compiler)
*/
reset (compilationResult) {
this.sources = compilationResult.sources
reset (compilationResult, sources?) {
this.sources = compilationResult.sources // ast
this.contracts = compilationResult.contracts
if (sources) this.sourcesCode = sources
this.cache.reset()
}
@ -44,8 +47,18 @@ export class SolidityProxy {
* @param {Int} vmTraceIndex - index in the vm trave where to resolve the executed contract name
* @param {Function} cb - callback returns (error, contractName)
*/
async contractObjectAt (vmTraceIndex) {
async contractObjectAt (vmTraceIndex: number) {
const address = this.getCurrentCalledAddressAt(vmTraceIndex)
return this.contractObjectAtAddress(address)
}
/**
* retrieve the compiled contract name at the @arg vmTraceIndex (cached)
*
* @param {Int} vmTraceIndex - index in the vm trave where to resolve the executed contract name
* @param {Function} cb - callback returns (error, contractName)
*/
async contractObjectAtAddress (address: string) {
if (this.cache.contractObjectByAddress[address]) {
return this.cache.contractObjectByAddress[address]
}

@ -25,7 +25,7 @@ export class StringType extends DynamicByteArray {
return await super.decodeFromStack(stackDepth, stack, memory, storageResolver, calldata, cursor, variableDetails)
} catch (e) {
console.log(e)
return { error: '<decoding failed - ' + e.message + '>' }
return { error: '<decoding failed - ' + e.message + '>', type: this.typeName }
}
}

@ -4,9 +4,11 @@ import { getLinebreakPositions, convertOffsetToLineColumn } from './sourceMappin
export class OffsetToColumnConverter {
lineBreakPositionsByContent
sourceMappingDecoder
offsetConvertion
constructor (compilerEvent) {
this.lineBreakPositionsByContent = {}
this.offsetConvertion = {}
if (compilerEvent) {
compilerEvent.register('compilationFinished', (success, data, source, input, version) => {
this.clear()
@ -26,10 +28,18 @@ export class OffsetToColumnConverter {
}
}
}
return convertOffsetToLineColumn(rawLocation, this.lineBreakPositionsByContent[file])
const token = `${rawLocation.start}:${rawLocation.length}:${file}`
if (this.offsetConvertion[token]) {
return this.offsetConvertion[token]
} else {
const convertion = convertOffsetToLineColumn(rawLocation, this.lineBreakPositionsByContent[file])
this.offsetConvertion[token] = convertion
return convertion
}
}
clear () {
this.lineBreakPositionsByContent = {}
this.offsetConvertion = {}
}
}

@ -87,13 +87,34 @@ export class SourceLocationTracker {
(map.file > amountOfSources - 1) this indicates the current file index exceed the total number of files.
this happens when generated sources should not be considered.
*/
while (vmtraceStepIndex >= 0 && (map.file === -1 || map.file > amountOfSources - 1)) {
while (vmtraceStepIndex >= 0 && this.isInvalidSourceLocation(map, amountOfSources)) {
map = await this.getSourceLocationFromVMTraceIndex(address, vmtraceStepIndex, contracts)
vmtraceStepIndex = vmtraceStepIndex - 1
}
return map
}
isInvalidSourceLocation (sourceLocation, amountOfSources) {
return sourceLocation.file === -1 || sourceLocation.file > amountOfSources - 1
}
async getValidSourceLocationFromVMTraceIndexFromCache (address: string, vmtraceStepIndex: number, contracts: any, cache: Map<number, any>) {
const amountOfSources = this.getTotalAmountOfSources(address, contracts)
let map: any = { file: -1 }
/*
(map.file === -1) this indicates that it isn't associated with a known source code
(map.file > amountOfSources - 1) this indicates the current file index exceed the total number of files.
this happens when generated sources should not be considered.
*/
const originStep = cache[vmtraceStepIndex]
while (vmtraceStepIndex >= 0 && (map.file === -1 || map.file > amountOfSources - 1)) {
map = cache[vmtraceStepIndex].sourceLocation
vmtraceStepIndex = vmtraceStepIndex - 1
originStep.sourceLocation = map
}
return originStep
}
clearCache () {
this.sourceMapByAddress = {}
}

@ -23,7 +23,7 @@ tape('solidity', function (t) {
async function test (st, privateKey) {
var output = compiler.compile(compilerInput(intLocal.contract))
output = JSON.parse(output)
await intLocalTest(st, privateKey, output.contracts['test.sol']['intLocal'].evm.bytecode.object, output)
await intLocalTest(st, privateKey, output.contracts['test.sol']['intLocal'].evm.bytecode.object, output, intLocal.contract)
output = compiler.compile(compilerInput(miscLocal.contract))
output = JSON.parse(output)
await miscLocalTest(st, privateKey, output.contracts['test.sol']['miscLocal'].evm.bytecode.object, output)

@ -7,9 +7,10 @@ import { contractCreationToken } from '../../../src/trace/traceHelper'
import { SolidityProxy } from '../../../src/solidity-decoder/solidityProxy'
import { InternalCallTree } from '../../../src/solidity-decoder/internalCallTree'
import { EventManager } from '../../../src/eventManager'
import * as sourceMappingDecoder from '../../../src/source/sourceMappingDecoder'
import * as helper from './helper'
module.exports = function (st, privateKey, contractBytecode, compilationResult) {
module.exports = function (st, privateKey, contractBytecode, compilationResult, contractCode) {
return new Promise(async (resolve) => {
let web3 = await (vmCall as any).getWeb3();
(vmCall as any).sendTx(web3, { nonce: 0, privateKey: privateKey }, null, 0, contractBytecode, function (error, hash) {
@ -27,22 +28,37 @@ module.exports = function (st, privateKey, contractBytecode, compilationResult)
var solidityProxy = new SolidityProxy({ getCurrentCalledAddressAt: traceManager.getCurrentCalledAddressAt.bind(traceManager), getCode: codeManager.getCode.bind(codeManager) })
solidityProxy.reset(compilationResult)
var debuggerEvent = new EventManager()
var callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true })
const offsetToLineColumnConverter = {
offsetToLineColumn: (rawLocation) => {
return new Promise((resolve) => {
const lineBreaks = sourceMappingDecoder.getLinebreakPositions(contractCode)
resolve(sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, lineBreaks))
})
}
}
var callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalVariables: true }, offsetToLineColumnConverter)
callTree.event.register('callTreeBuildFailed', (error) => {
st.fail(error)
})
callTree.event.register('callTreeNotReady', (reason) => {
st.fail(reason)
})
callTree.event.register('callTreeReady', (scopes, scopeStarts) => {
callTree.event.register('callTreeReady', async (scopes, scopeStarts) => {
try {
let functions1 = callTree.retrieveFunctionsStack(102)
let functions2 = callTree.retrieveFunctionsStack(115)
// test gas cost per line
st.equals((await callTree.getGasCostPerLine(0, 16)).gasCost, 11)
st.equals((await callTree.getGasCostPerLine(0, 32)).gasCost, 84)
let functions1 = callTree.retrieveFunctionsStack(103)
let functions2 = callTree.retrieveFunctionsStack(116)
let functions3 = callTree.retrieveFunctionsStack(13)
st.equals(functions1.length, 1)
st.equals(functions2.length, 2)
st.equals(functions3.length, 0)
st.equals(functions1.length, 2)
st.equals(functions2.length, 3)
st.equals(functions3.length, 1)
st.equal(functions1[0].gasCost, 54)
st.equals(Object.keys(functions1[0])[0], 'functionDefinition')
st.equals(Object.keys(functions1[0])[1], 'inputs')
@ -57,34 +73,34 @@ module.exports = function (st, privateKey, contractBytecode, compilationResult)
st.equals(functions1[0].functionDefinition.name, 'level11')
st.equals(functions2[0].functionDefinition.name, 'level12')
st.equals(functions2[1].functionDefinition.name, 'level11')
st.equals(scopeStarts[0], '')
st.equals(scopeStarts[13], '1')
st.equals(scopeStarts[102], '2')
st.equals(scopeStarts[115], '2.1')
st.equals(scopeStarts[136], '3')
st.equals(scopeStarts[153], '4')
st.equals(scopeStarts[166], '4.1')
st.equals(scopes[''].locals['ui8'].type.typeName, 'uint8')
st.equals(scopes[''].locals['ui16'].type.typeName, 'uint16')
st.equals(scopes[''].locals['ui32'].type.typeName, 'uint32')
st.equals(scopes[''].locals['ui64'].type.typeName, 'uint64')
st.equals(scopes[''].locals['ui128'].type.typeName, 'uint128')
st.equals(scopes[''].locals['ui256'].type.typeName, 'uint256')
st.equals(scopes[''].locals['ui'].type.typeName, 'uint256')
st.equals(scopes[''].locals['i8'].type.typeName, 'int8')
st.equals(scopes[''].locals['i16'].type.typeName, 'int16')
st.equals(scopes[''].locals['i32'].type.typeName, 'int32')
st.equals(scopes[''].locals['i64'].type.typeName, 'int64')
st.equals(scopes[''].locals['i128'].type.typeName, 'int128')
st.equals(scopes[''].locals['i256'].type.typeName, 'int256')
st.equals(scopes[''].locals['i'].type.typeName, 'int256')
st.equals(scopes[''].locals['ishrink'].type.typeName, 'int32')
st.equals(scopes['2'].locals['ui8'].type.typeName, 'uint8')
st.equals(scopes['2.1'].locals['ui81'].type.typeName, 'uint8')
st.equals(scopes['3'].locals['ui81'].type.typeName, 'uint8')
st.equals(scopes['4'].locals['ui8'].type.typeName, 'uint8')
st.equals(scopes['4.1'].locals['ui81'].type.typeName, 'uint8')
st.equals(scopeStarts[0], '1')
st.equals(scopeStarts[10], '1.1')
st.equals(scopeStarts[102], '1.1.1')
st.equals(scopeStarts[115], '1.1.1.1')
st.equals(scopeStarts[136], '1.1.2')
st.equals(scopeStarts[153], '1.1.3')
st.equals(scopeStarts[166], '1.1.3.1')
st.equals(scopes['1.1'].locals['ui8'].type.typeName, 'uint8')
st.equals(scopes['1.1'].locals['ui16'].type.typeName, 'uint16')
st.equals(scopes['1.1'].locals['ui32'].type.typeName, 'uint32')
st.equals(scopes['1.1'].locals['ui64'].type.typeName, 'uint64')
st.equals(scopes['1.1'].locals['ui128'].type.typeName, 'uint128')
st.equals(scopes['1.1'].locals['ui256'].type.typeName, 'uint256')
st.equals(scopes['1.1'].locals['ui'].type.typeName, 'uint256')
st.equals(scopes['1.1'].locals['i8'].type.typeName, 'int8')
st.equals(scopes['1.1'].locals['i16'].type.typeName, 'int16')
st.equals(scopes['1.1'].locals['i32'].type.typeName, 'int32')
st.equals(scopes['1.1'].locals['i64'].type.typeName, 'int64')
st.equals(scopes['1.1'].locals['i128'].type.typeName, 'int128')
st.equals(scopes['1.1'].locals['i256'].type.typeName, 'int256')
st.equals(scopes['1.1'].locals['i'].type.typeName, 'int256')
st.equals(scopes['1.1'].locals['ishrink'].type.typeName, 'int32')
st.equals(scopes['1.1.1'].locals['ui8'].type.typeName, 'uint8')
st.equals(scopes['1.1.1.1'].locals['ui81'].type.typeName, 'uint8')
st.equals(scopes['1.1.2'].locals['ui81'].type.typeName, 'uint8')
st.equals(scopes['1.1.3'].locals['ui8'].type.typeName, 'uint8')
st.equals(scopes['1.1.3.1'].locals['ui81'].type.typeName, 'uint8')
} catch (e) {
st.fail(e.message)
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-lib",
"version": "0.5.19",
"version": "0.5.20",
"description": "Library to various Remix tools",
"contributors": [
{
@ -54,5 +54,5 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme",
"typings": "src/index.d.ts",
"gitHead": "2cec195f5a3678b17745155536a1714d9b1a5694"
"gitHead": "569f7d53f6f218d99aa8281929b541ab7e00058f"
}

@ -239,6 +239,8 @@ export function compareByteCode (code1, code2) {
code2 = replaceLibReference(code2, pos)
code1 = replaceLibReference(code1, pos)
}
code1 = removeImmutableReference(code1, code2)
code1 = extractinputParameters(code1)
code1 = extractSwarmHash(code1)
code1 = extractcborMetadata(code1)
@ -276,6 +278,27 @@ function replaceLibReference (code, pos) {
return code.substring(0, pos) + '0000000000000000000000000000000000000000' + code.substring(pos + 40)
}
function removeByIndex (code, index, length, emptyRef) {
if (!code) return code
return code.slice(0, index) + emptyRef + code.slice(index + length)
}
function removeImmutableReference (code1, code2) {
try {
const refOccurence = code2.match(/7f000000000000000000000000000000000000000000000000000000000000000073/g)
if (!refOccurence) return code1
let offset = 0
refOccurence.map((value) => {
offset = code2.indexOf(value, offset)
code1 = removeByIndex(code1, offset, value.length, '7f000000000000000000000000000000000000000000000000000000000000000073')
offset = offset + 1
})
} catch (e) {
console.log('error removeImmutableReference', e)
}
return code1
}
function findCallInternal (index, rootCall, callsPath) {
const calls = Object.keys(rootCall.calls)
const ret = rootCall

File diff suppressed because one or more lines are too long

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-simulator",
"version": "0.2.19",
"version": "0.2.20",
"description": "Ethereum IDE and tools for the web",
"contributors": [
{
@ -18,7 +18,7 @@
"@ethereumjs/common": "^2.5.0",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.19",
"@remix-project/remix-lib": "^0.5.20",
"ansi-gray": "^0.1.1",
"async": "^3.1.0",
"body-parser": "^1.18.2",
@ -67,5 +67,5 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-simulator#readme",
"typings": "src/index.d.ts",
"gitHead": "2cec195f5a3678b17745155536a1714d9b1a5694"
"gitHead": "569f7d53f6f218d99aa8281929b541ab7e00058f"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-solidity",
"version": "0.5.5",
"version": "0.5.6",
"description": "Tool to load and run Solidity compiler",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -18,7 +18,7 @@
"@ethereumjs/block": "^3.5.1",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.19",
"@remix-project/remix-lib": "^0.5.20",
"async": "^2.6.2",
"eslint-scope": "^5.0.0",
"ethereumjs-util": "^7.0.10",
@ -61,5 +61,5 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-solidity#readme",
"typings": "src/index.d.ts",
"gitHead": "2cec195f5a3678b17745155536a1714d9b1a5694"
"gitHead": "569f7d53f6f218d99aa8281929b541ab7e00058f"
}

@ -52,7 +52,7 @@ export function canUseWorker (selectedVersion) {
}
function browserSupportWorker () {
return document.location.protocol !== 'file:' && Worker !== undefined
return document ? document.location.protocol !== 'file:' && Worker !== undefined : false
}
// returns a promise for minixhr

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-tests",
"version": "0.2.19",
"version": "0.2.20",
"description": "Tool to test Solidity smart contracts",
"main": "src/index.js",
"types": "./src/index.d.ts",
@ -40,13 +40,13 @@
"@ethereumjs/common": "^2.5.0",
"@ethereumjs/tx": "^3.3.2",
"@ethereumjs/vm": "^5.5.3",
"@remix-project/remix-lib": "^0.5.19",
"@remix-project/remix-simulator": "^0.2.19",
"@remix-project/remix-solidity": "^0.5.5",
"@remix-project/remix-url-resolver": "^0.0.40",
"@remix-project/remix-lib": "^0.5.20",
"@remix-project/remix-simulator": "^0.2.20",
"@remix-project/remix-solidity": "^0.5.6",
"@remix-project/remix-url-resolver": "^0.0.41",
"ansi-gray": "^0.1.1",
"async": "^2.6.0",
"axios": ">=0.21.1",
"axios": "1.1.2",
"change-case": "^3.0.1",
"color-support": "^1.1.3",
"colors": "1.4.0",
@ -81,5 +81,5 @@
"typescript": "^3.3.1"
},
"typings": "src/index.d.ts",
"gitHead": "2cec195f5a3678b17745155536a1714d9b1a5694"
"gitHead": "569f7d53f6f218d99aa8281929b541ab7e00058f"
}

@ -11,6 +11,10 @@ describe('testRunner: remix-tests CLI', () => {
const dirContent = result.stdout.toString()
// Install dependencies if 'node_modules' is not already present
if(!dirContent.includes('node_modules')) {
execSync('yarn add @remix-project/remix-lib ../../libs/remix-lib', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') })
execSync('yarn add @remix-project/remix-url-resolver ../../libs/remix-url-resolver', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') })
execSync('yarn add @remix-project/remix-solidity ../../libs/remix-solidity', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') })
execSync('yarn add @remix-project/remix-simulator ../../libs/remix-simulator', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') })
execSync('yarn install', { cwd: resolve(__dirname + '/../../../dist/libs/remix-tests') })
}
}

@ -58,9 +58,10 @@ const DragBar = (props: IRemixDragBarUi) => {
return () => window.removeEventListener('resize', handleResize)
}, [])
function stopDrag(e: MouseEvent, data: any) {
function stopDrag(data: any) {
setDragState(false)
if (data.x < props.minWidth) {
console.log("drag")
if (data.x < props.minWidth + offset) {
setDragBarPosX(offset)
props.setHideStatus(true)
} else {
@ -70,7 +71,6 @@ const DragBar = (props: IRemixDragBarUi) => {
setDragBarPosX(offset + props.refObject.current.offsetWidth)
}, 300)
}
}
function startDrag() {

@ -1,6 +1,11 @@
import React, { useContext, useEffect, useState } from 'react'
import { AppContext } from '../../context/context'
import { useDialogDispatchers } from '../../context/provider'
declare global {
interface Window {
_paq: any
}
}
const _paq = window._paq = window._paq || []
const MatomoDialog = (props) => {

@ -1,4 +1,4 @@
import React, { useContext, useEffect, useRef, useState } from 'react'
import React, { useEffect, useRef, useState } from 'react'
import './style/remix-app.css'
import { RemixUIMainPanel } from '@remix-ui/panel'
import MatomoDialog from './components/modals/matomo'
@ -8,7 +8,6 @@ import { AppProvider } from './context/provider'
import AppDialogs from './components/modals/dialogs'
import DialogViewPlugin from './components/modals/dialogViewPlugin'
import { AppContext } from './context/context'
import { RemixUiVerticalIconsPanel } from '@remix-ui/vertical-icons-panel'
import { IntlProvider } from 'react-intl'
interface IRemixAppUi {
@ -83,11 +82,10 @@ const RemixApp = (props: IRemixAppUi) => {
<AppProvider value={value}>
<OriginWarning></OriginWarning>
<MatomoDialog hide={!appReady}></MatomoDialog>
<div className={`remixIDE ${appReady ? '' : 'd-none'}`} data-id="remixIDE">
<div id="icon-panel" data-id="remixIdeIconPanel" className="iconpanel bg-light">{props.app.menuicons.render()}</div>
<div ref={sidePanelRef} id="side-panel" data-id="remixIdeSidePanel" className={`sidepanel border-right border-left ${hideSidePanel ? 'd-none' : ''}`}>{props.app.sidePanel.render()}</div>
<DragBar resetTrigger={resetTrigger} maximiseTrigger={maximiseTrigger} minWidth={250} refObject={sidePanelRef} hidden={hideSidePanel} setHideStatus={setHideSidePanel}></DragBar>
<DragBar resetTrigger={resetTrigger} maximiseTrigger={maximiseTrigger} minWidth={285} refObject={sidePanelRef} hidden={hideSidePanel} setHideStatus={setHideSidePanel}></DragBar>
<div id="main-panel" data-id="remixIdeMainPanel" className='mainpanel'>
<RemixUIMainPanel Context={AppContext}></RemixUIMainPanel>
</div>

@ -34,10 +34,15 @@ export const RemixUiCheckbox = ({
title,
visibility,
display = 'flex',
tooltipPlacement = 'right-start'
tooltipPlacement = 'right'
}: RemixUiCheckboxProps) => {
const childJSX = (
const childJSXWithTooltip = (
<CustomTooltip
tooltipText={title}
tooltipId={`${name}Tooltip`}
placement={tooltipPlacement}
>
<div className="listenOnNetwork_2A0YE0 custom-control custom-checkbox" style={{ display: display, alignItems: 'center', visibility: visibility } as CSSProperties } onClick={onClick}>
<input
id={id}
@ -53,16 +58,27 @@ export const RemixUiCheckbox = ({
{label}
</label>
</div>
</CustomTooltip>
)
const childJSX = (
<div className="listenOnNetwork_2A0YE0 custom-control custom-checkbox" style={{ display: display, alignItems: 'center', visibility: visibility } as CSSProperties } onClick={onClick}>
<input
id={id}
type={inputType}
onChange={onChange}
style={{ verticalAlign: 'bottom' }}
name={name}
className="custom-control-input"
checked={checked}
/>
<label className="form-check-label custom-control-label" id={`heading${categoryId}`} style={{ paddingTop: '0.15rem' }}>
{name ? <div className="font-weight-bold">{itemName}</div> : ''}
{label}
</label>
</div>
)
return (
<CustomTooltip
tooltipText={title}
tooltipId={`${name}Tooltip`}
placement={tooltipPlacement}
>
{childJSX}
</CustomTooltip>
title ? (childJSXWithTooltip) : (childJSX)
)
}

@ -121,7 +121,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
})
})
debuggerInstance.event.register('newSourceLocation', async (lineColumnPos, rawLocation, generatedSources, address) => {
debuggerInstance.event.register('newSourceLocation', async (lineColumnPos, rawLocation, generatedSources, address, stepDetail, lineGasCost) => {
if (!lineColumnPos) {
await debuggerModule.discardHighlight()
setState(prevState => {
@ -158,7 +158,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
return { ...prevState, sourceLocationStatus: '' }
})
await debuggerModule.discardHighlight()
await debuggerModule.highlight(lineColumnPos, path)
await debuggerModule.highlight(lineColumnPos, path, rawLocation, stepDetail, lineGasCost)
}
}
})
@ -266,13 +266,14 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
console.log(e.message)
}
const localCache = {}
const debuggerInstance = new Debugger({
web3,
offsetToLineColumnConverter: debuggerModule.offsetToLineColumnConverter,
compilationResult: async (address) => {
try {
const ret = await debuggerModule.fetchContractAndCompile(address, currentReceipt)
return ret
if (!localCache[address]) localCache[address] = await debuggerModule.fetchContractAndCompile(address, currentReceipt)
return localCache[address]
} catch (e) {
// debuggerModule.showMessage('Debugging error', 'Unable to fetch a transaction.')
console.error(e)
@ -395,8 +396,8 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
{ state.debugging && <StepManager stepManager={ stepManager } /> }
</div>
<div className="debuggerPanels" ref={panelsRef}>
{ state.debugging && <VmDebuggerHead vmDebugger={ vmDebugger } /> }
{ state.debugging && <VmDebugger vmDebugger={ vmDebugger } currentBlock={ state.currentBlock } currentReceipt={ state.currentReceipt } currentTransaction={ state.currentTransaction } /> }
{ state.debugging && <VmDebuggerHead debugging={state.debugging} vmDebugger={ vmDebugger } /> }
{ state.debugging && <VmDebugger debugging={state.debugging} vmDebugger={ vmDebugger } currentBlock={ state.currentBlock } currentReceipt={ state.currentReceipt } currentTransaction={ state.currentTransaction } /> }
</div>
</div>
)

@ -44,7 +44,7 @@ export interface IDebuggerApi {
onEditorContentChanged: (listener: onEditorContentChanged) => void
onEnvChanged: (listener: onEnvChangedListener) => void
discardHighlight: () => Promise<void>
highlight: (lineColumnPos: LineColumnLocation, path: string) => Promise<void>
highlight: (lineColumnPos: LineColumnLocation, path: string, rawLocation: any, stepDetail: any, highlight: any) => Promise<void>
fetchContractAndCompile: (address: string, currentReceipt: TransactionReceipt) => Promise<CompilerAbstract>
getFile: (path: string) => Promise<string>
setFile: (path: string, content: string) => Promise<void>

@ -1,3 +1,4 @@
import { stateDecoder } from 'dist/libs/remix-debug/src/solidity-decoder'
import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint-disable-line
import { initialState, reducer } from '../../reducers/assembly-items'
import './styles/assembly-items.css'
@ -9,6 +10,7 @@ export const AssemblyItems = ({ registerEvent }) => {
const [nextSelectedItems, setNextSelectedItems] = useState([1])
const [returnInstructionIndexes, setReturnInstructionIndexes] = useState([])
const [outOfGasInstructionIndexes, setOutOfGasInstructionIndexes] = useState([])
const [opcodeTooltipText, setOpcodeTooltipText] = useState('')
const refs = useRef({})
const asmItemsRef = useRef(null)
@ -16,6 +18,10 @@ export const AssemblyItems = ({ registerEvent }) => {
registerEvent && registerEvent('codeManagerChanged', (code, address, index, nextIndexes, returnInstructionIndexes, outOfGasInstructionIndexes) => {
dispatch({ type: 'FETCH_OPCODES_SUCCESS', payload: { code, address, index, nextIndexes, returnInstructionIndexes, outOfGasInstructionIndexes } })
})
registerEvent && registerEvent('lineGasCostChanged', (instructionsIndexes: number[], line: []) => {
dispatch({ type: 'FETCH_INDEXES_FOR_NEW_LINE', payload: { currentLineIndexes: instructionsIndexes || [], line } })
})
}, [])
useEffect(() => {
@ -129,7 +135,9 @@ export const AssemblyItems = ({ registerEvent }) => {
<div className="pl-2 my-1 small instructions" data-id="asmitems" id='asmitems' ref={asmItemsRef}>
{
assemblyItems.display.map((item, i) => {
return <div className="px-1" key={i} ref={ref => { refs.current[i] = ref }}><span>{item}</span></div>
return <div className="px-1" key={i} ref={ref => { refs.current[i] = ref }}>
<span>{item}</span>{assemblyItems.currentLineIndexes.includes(i) ? <span><i><b> - LINE {assemblyItems.line + 1}</b></i></span> : ' - '}
</div>
})
}
</div>

@ -5,7 +5,7 @@ import StepDetail from './step-detail' // eslint-disable-line
import SolidityState from './solidity-state' // eslint-disable-line
import SolidityLocals from './solidity-locals' // eslint-disable-line
export const VmDebuggerHead = ({ vmDebugger: { registerEvent, triggerEvent } }) => {
export const VmDebuggerHead = ({ vmDebugger: { registerEvent, triggerEvent }, debugging }) => {
const [functionPanel, setFunctionPanel] = useState(null)
const [stepDetail, setStepDetail] = useState({
'vm trace step': '-',
@ -31,7 +31,7 @@ export const VmDebuggerHead = ({ vmDebugger: { registerEvent, triggerEvent } })
const functions = []
for (const func of stack) {
functions.push(func.functionDefinition.name + '(' + func.inputs.join(', ') + ')')
functions.push((func.functionDefinition.name || func.functionDefinition.kind) + '(' + func.inputs.join(', ') + ')' + ' - ' + func.gasCost + ' gas')
}
setFunctionPanel(() => functions)
})
@ -95,7 +95,7 @@ export const VmDebuggerHead = ({ vmDebugger: { registerEvent, triggerEvent } })
return { ...solidityLocals, message }
})
})
}, [registerEvent])
}, [debugging])
return (
<div id='vmheadView' className="mt-1 px-2 d-flex">

@ -8,7 +8,7 @@ import ReturnValuesPanel from './dropdown-panel' // eslint-disable-line
import FullStoragesChangesPanel from './full-storages-changes' // eslint-disable-line
import GlobalVariables from './global-variables' // eslint-disable-line
export const VmDebugger = ({ vmDebugger: { registerEvent }, currentBlock, currentReceipt, currentTransaction }) => {
export const VmDebugger = ({ vmDebugger: { registerEvent }, currentBlock, currentReceipt, currentTransaction, debugging }) => {
const [calldataPanel, setCalldataPanel] = useState(null)
const [memoryPanel, setMemoryPanel] = useState(null)
const [callStackPanel, setCallStackPanel] = useState(null)
@ -49,7 +49,7 @@ export const VmDebugger = ({ vmDebugger: { registerEvent }, currentBlock, curren
registerEvent && registerEvent('traceStorageUpdate', (calldata) => {
setFullStoragesChangesPanel(() => calldata)
})
}, [registerEvent])
}, [debugging])
return (
<div id='vmdebugger' className="d-flex">

@ -13,6 +13,7 @@ export const initialState = {
},
display: [],
index: 0,
initialIndex: 0,
nextIndexes: [-1],
returnInstructionIndexes: [],
outOfGasInstructionIndexes: [],
@ -20,7 +21,10 @@ export const initialState = {
bottom: 0,
isRequesting: false,
isSuccessful: false,
hasError: null
hasError: null,
absoluteCurrentLineIndexes: [],
currentLineIndexes: [],
line: -1
}
const reducedOpcode = (opCodes, payload) => {
@ -31,6 +35,7 @@ const reducedOpcode = (opCodes, payload) => {
return {
index: opCodes.index - bottom,
nextIndexes: opCodes.nextIndexes.map(index => index - bottom),
currentLineIndexes: (opCodes.absoluteCurrentLineIndexes && opCodes.absoluteCurrentLineIndexes.map(index => index - bottom)) || [],
display: opCodes.code.slice(bottom, top),
returnInstructionIndexes: payload.returnInstructionIndexes.map((index) => index.instructionIndex - bottom),
outOfGasInstructionIndexes: payload.outOfGasInstructionIndexes.map((index) => index.instructionIndex - bottom)
@ -49,20 +54,23 @@ export const reducer = (state = initialState, action: Action) => {
}
case 'FETCH_OPCODES_SUCCESS': {
const opCodes = action.payload.address === state.opCodes.address ? {
...state.opCodes, index: action.payload.index, nextIndexes: action.payload.nextIndexes
...state.opCodes, index: action.payload.index, nextIndexes: action.payload.nextIndexes, absoluteCurrentLineIndexes: state.absoluteCurrentLineIndexes
} : deepEqual(action.payload.code, state.opCodes.code) ? state.opCodes : action.payload
const reduced = reducedOpcode(opCodes, action.payload)
return {
...state,
opCodes,
display: reduced.display,
initialIndex: action.payload.index,
index: reduced.index,
nextIndexes: reduced.nextIndexes,
isRequesting: false,
isSuccessful: true,
hasError: null,
returnInstructionIndexes: reduced.returnInstructionIndexes,
outOfGasInstructionIndexes: reduced.outOfGasInstructionIndexes
outOfGasInstructionIndexes: reduced.outOfGasInstructionIndexes,
currentLineIndexes: reduced.currentLineIndexes
}
}
case 'FETCH_OPCODES_ERROR': {
@ -73,6 +81,16 @@ export const reducer = (state = initialState, action: Action) => {
hasError: action.payload
}
}
case 'FETCH_INDEXES_FOR_NEW_LINE': {
let bottom = state.initialIndex - 10
bottom = bottom < 0 ? 0 : bottom
return {
...state,
absoluteCurrentLineIndexes: action.payload.currentLineIndexes,
currentLineIndexes: action.payload.currentLineIndexes.map(index => index - bottom),
line: action.payload.line
}
}
default:
throw new Error()
}

@ -13,7 +13,7 @@ export const CustomToggle = React.forwardRef(({ children, onClick, icon, classNa
className={className.replace('dropdown-toggle', '')}
>
<div className="d-flex">
<div className="mr-auto">{ children }</div>
<div className="mr-auto text-nowrap">{ children }</div>
{ icon && <div className="pr-1"><i className={`${icon} pr-1`}></i></div> }
<div><i className="fad fa-sort-circle"></i></div>
</div>

@ -4,7 +4,7 @@ import { OverlayTrigger, Tooltip } from 'react-bootstrap';
import { CustomTooltipType } from '../../types/customtooltip'
export function CustomTooltip({ children, placement, tooltipId, tooltipClasses, tooltipText, tooltipTextClasses }: CustomTooltipType) {
export function CustomTooltip({ children, placement, tooltipId, tooltipClasses, tooltipText, tooltipTextClasses, delay }: CustomTooltipType) {
return (
<Fragment>
@ -15,6 +15,7 @@ export function CustomTooltip({ children, placement, tooltipId, tooltipClasses,
{typeof tooltipText === 'string' ? (<span className={tooltipTextClasses}>{tooltipText}</span>) : (tooltipText)}
</Tooltip>
}
delay={delay}
>
{children}
</OverlayTrigger>

@ -1,5 +1,5 @@
import { Placement } from 'react-bootstrap/esm/Overlay'
import { OverlayTriggerRenderProps } from 'react-bootstrap/esm/OverlayTrigger'
import { OverlayDelay, OverlayTriggerRenderProps } from 'react-bootstrap/esm/OverlayTrigger'
export type CustomTooltipType = {
children: React.ReactElement<any, string | React.JSXElementConstructor<any>> | ((props: OverlayTriggerRenderProps) => React.ReactNode),
@ -8,4 +8,5 @@ export type CustomTooltipType = {
tooltipClasses?:string,
tooltipText: string | JSX.Element,
tooltipTextClasses?: string
delay?: OverlayDelay
}

@ -1,14 +0,0 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import React from 'react'
function CustomButtonGroupAsArrows ({ next, previous }) {
return (
<div style={{ textAlign: "center" }}>
<h4>These buttons can be positioned anywhere you want on the screen</h4>
<button onClick={previous}>Prev</button>
<button onClick={next}>Next</button>
</div>
)
}
export default CustomButtonGroupAsArrows

@ -1,8 +1,8 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import React from 'react'
const CustomNavButtons = ({ next, previous, goToSlide, ...rest }) => {
const { carouselState: { currentSlide, totalItems, itemWidth, containerWidth } } = rest
const CustomNavButtons = ({ parent, next, previous, goToSlide, ...rest }) => {
const { carouselState: { currentSlide, totalItems, containerWidth, transform } } = rest
return (
<div className="mt-1 d-flex justify-content-end carousel-button-group">
<button
@ -14,11 +14,11 @@ const CustomNavButtons = ({ next, previous, goToSlide, ...rest }) => {
</button>
<button
className={
((totalItems - currentSlide) * itemWidth + 5) < containerWidth ? 'disable py-1 border btn' : 'py-1 border btn'}
(Math.abs(transform) >= parent?.current?.containerRef?.current?.scrollWidth - containerWidth) ? 'disable py-1 border btn' : 'py-1 border btn'}
onClick={() => {
if (currentSlide + 1 < totalItems) goToSlide(currentSlide + 1)
}}
disabled ={((totalItems - currentSlide) * itemWidth + 5) < containerWidth}
disabled ={Math.abs(transform) >= parent?.current?.containerRef?.current?.scrollWidth - containerWidth}
>
<i className="fas fa-angle-right"></i>
</button>

@ -3,17 +3,11 @@ import React, { useEffect, useState, useRef, useContext } from 'react'
import { ThemeContext, themes } from '../themeContext'
import Carousel from 'react-multi-carousel'
import 'react-multi-carousel/lib/styles.css'
import CustomNavButtons from './customNavButtons'
const _paq = window._paq = window._paq || [] // eslint-disable-line
function HomeTabFeatured() {
const themeFilter = useContext(ThemeContext)
useEffect(() => {
return () => {
}
}, [])
return (
<div className="pt-3 pl-2" id="hTFeaturedeSection">
<label style={{ fontSize: "1.2rem" }}>Featured</label>
@ -21,7 +15,6 @@ function HomeTabFeatured() {
<div className="w-100 d-flex flex-column" style={{ height: "200px" }}>
<ThemeContext.Provider value={themeFilter}>
<Carousel
customButtonGroup={<CustomNavButtons next={undefined} previous={undefined} goToSlide={undefined} />}
arrows={false}
swipeable={false}
draggable={true}
@ -30,17 +23,18 @@ function HomeTabFeatured() {
renderDotsOutside={true}
ssr={true} // means to render carousel on server-side.
infinite={true}
partialVisible={false}
centerMode={false}
autoPlay={true}
keyBoardControl={true}
containerClass="border carousel-container"
sliderClass="px-2 h-100 justify-content-between"
containerClass="border w-full carousel-container"
sliderClass="h-100 justify-content-between"
deviceType={"desktop"}
itemClass="px-2 carousel-item-padding-10-px"
itemClass=""
autoPlaySpeed={15000}
dotListClass="position-relative mt-2"
>
<div className="d-flex">
<div className="mx-1 px-1 d-flex">
<img src={"assets/img/bgRemi.webp"} style={{ flex: "1", height: "170px", maxWidth: "170px" }} alt="" ></img>
<div className="h6 w-50 p-4" style={{ flex: "1" }}>
<h5>JUMP INTO WEB3</h5>
@ -48,7 +42,7 @@ function HomeTabFeatured() {
<a className="remixui_home_text" onClick={() => _paq.push(['trackEvent', 'hometab', 'featuredSection', 'jumpIntoWeb3'])} target="__blank" href="https://remix-project.org">More</a>
</div>
</div>
<div className="d-flex">
<div className="mx-1 px-1 d-flex">
<img src={"/assets/img/remixRewardUser.webp"} style={{ flex: "1", height: "170px", maxWidth: "170px" }} alt="" ></img>
<div className="h6 p-4" style={{ flex: "1" }}>
<h5>REMIX REWARDS</h5>
@ -59,7 +53,7 @@ function HomeTabFeatured() {
<a className="remixui_home_text" target="__blank" onClick={() => _paq.push(['trackEvent', 'hometab', 'featuredSection', 'remixRewards'])} href="https://rewards.remix.ethereum.eth.limo">More</a>
</div>
</div>
<div className="d-flex">
<div className="mx-1 px-1 d-flex">
<img src={"/assets/img/remixRewardBetaTester.webp"} style={{ flex: "1", height: "170px", maxWidth: "170px" }} alt="" ></img>
<div className="h6 p-4" style={{ flex: "1" }}>
<h5>BETA TESTING</h5>

@ -20,7 +20,7 @@ interface HomeTabFeaturedPluginsProps {
function HomeTabFeaturedPlugins ({plugin}: HomeTabFeaturedPluginsProps) {
const themeFilter = useContext(ThemeContext)
const carouselRef = useRef(null)
const carouselRef = useRef<any>({})
const carouselRefDiv = useRef(null)
useEffect(() => {
@ -47,7 +47,7 @@ function HomeTabFeaturedPlugins ({plugin}: HomeTabFeaturedPluginsProps) {
let nextSlide = 0
if (e.wheelDelta < 0) {
nextSlide = carouselRef.current.state.currentSlide + 1;
if ((carouselRef.current.state.totalItems - carouselRef.current.state.currentSlide) * carouselRef.current.state.itemWidth + 5 < carouselRef.current.state.containerWidth) return // 5 is approx margins
if (Math.abs(carouselRef.current.state.transform) >= carouselRef.current.containerRef.current.scrollWidth - carouselRef.current.state.containerWidth) return
carouselRef.current.goToSlide(nextSlide)
} else {
nextSlide = carouselRef.current.state.currentSlide - 1;
@ -92,7 +92,7 @@ function HomeTabFeaturedPlugins ({plugin}: HomeTabFeaturedPluginsProps) {
ref={carouselRef}
focusOnSelect={true}
customButtonGroup={
<CustomNavButtons next={undefined} previous={undefined} goToSlide={undefined} />
<CustomNavButtons next={undefined} previous={undefined} goToSlide={undefined} parent={carouselRef} />
}
arrows={false}
swipeable={false}

@ -23,13 +23,13 @@ function HomeTabFile ({plugin}: HomeTabFileProps) {
const [state, setState] = useState<{
searchInput: string,
showModalDialog: boolean,
modalInfo: { title: string, loadItem: string, examples: Array<string> },
modalInfo: { title: string, loadItem: string, examples: Array<string>, prefix?: string },
importSource: string,
toasterMsg: string
}>({
searchInput: '',
showModalDialog: false,
modalInfo: { title: '', loadItem: '', examples: [] },
modalInfo: { title: '', loadItem: '', examples: [], prefix: '' },
importSource: '',
toasterMsg: ''
})
@ -42,8 +42,15 @@ function HomeTabFile ({plugin}: HomeTabFileProps) {
_paq.push(['trackEvent', 'hometab', 'filesSection', 'importFrom' + type])
const contentImport = plugin.contentImport
const workspace = plugin.fileManager.getProvider('workspace')
const startsWith = state.importSource.substring(0, 4)
if ((type === 'ipfs' || type === 'IPFS') && (startsWith !== 'ipfs' && startsWith !== "IPFS")) {
setState(prevState => {
return { ...prevState, importSource: startsWith + state.importSource}
})
}
contentImport.import(
state.importSource,
state.modalInfo.prefix + state.importSource,
(loadingMsg) => dispatch({ tooltip: loadingMsg }),
async (error, content, cleanUrl, type, url) => {
if (error) {
@ -93,9 +100,9 @@ function HomeTabFile ({plugin}: HomeTabFileProps) {
plugin.verticalIcons.select('filePanel')
}
const showFullMessage = (title: string, loadItem: string, examples: Array<string>) => {
const showFullMessage = (title: string, loadItem: string, examples: Array<string>, prefix = '') => {
setState(prevState => {
return { ...prevState, showModalDialog: true, modalInfo: { title: title, loadItem: loadItem, examples: examples } }
return { ...prevState, showModalDialog: true, modalInfo: { title: title, loadItem: loadItem, examples: examples, prefix } }
})
}
@ -126,7 +133,9 @@ function HomeTabFile ({plugin}: HomeTabFileProps) {
{ examples }
</div>
</> }
<input
<div className="d-flex flex-row">
{ state.modalInfo.prefix && <span className='text-nowrap align-self-center mr-2'>ipfs://</span> }
<input
ref={inputValue}
type='text'
name='prompt_text'
@ -140,6 +149,7 @@ function HomeTabFile ({plugin}: HomeTabFileProps) {
})
}}
/>
</div>
</div>
</ModalDialog>
<Toaster message={state.toasterMsg} />
@ -155,9 +165,15 @@ function HomeTabFile ({plugin}: HomeTabFileProps) {
<button className="btn p-2 border my-1" style={{width: 'fit-content'}} onClick={() => connectToLocalhost()}><FormattedMessage id='home.connectToLocalhost' defaultMessage='Connect to Localhost' /></button>
<label className="pt-2"><FormattedMessage id='home.loadFrom' defaultMessage='Load From' /></label>
<div className="d-flex">
<button className="btn p-2 border mr-2" data-id="landingPageImportFromGitHubButton" onClick={() => showFullMessage('GitHub', 'github URL', ['https://github.com/0xcert/ethereum-erc721/src/contracts/tokens/nf-token-metadata.sol', 'https://github.com/OpenZeppelin/openzeppelin-solidity/blob/67bca857eedf99bf44a4b6a0fc5b5ed553135316/contracts/access/Roles.sol'])}>GitHub</button>
<button
className="btn p-2 border mr-2"
data-id="landingPageImportFromGitHubButton"
onClick={() => showFullMessage('GitHub', 'github URL', ['https://github.com/0xcert/ethereum-erc721/src/contracts/tokens/nf-token-metadata.sol', 'https://github.com/OpenZeppelin/openzeppelin-solidity/blob/67bca857eedf99bf44a4b6a0fc5b5ed553135316/contracts/access/Roles.sol'])}
>
GitHub
</button>
<button className="btn p-2 border mr-2" data-id="landingPageImportFromGistButton" onClick={() => importFromGist()}>Gist</button>
<button className="btn p-2 border mr-2" onClick={() => showFullMessage('Ipfs', 'ipfs URL', ['ipfs://<ipfs-hash>'])}>IPFS</button>
<button className="btn p-2 border mr-2" onClick={() => showFullMessage('Ipfs', 'ipfs hash', ['ipfs://QmQQfBMkpDgmxKzYaoAtqfaybzfgGm9b2LWYyT56Chv6xH'], "ipfs://")}>IPFS</button>
<button className="btn p-2 border" onClick={() => showFullMessage('Https', 'http/https raw content', ['https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/master/contracts/token/ERC20/ERC20.sol'])}>HTTPS</button>
</div>
</div>

@ -17,7 +17,7 @@ interface HomeTabGetStartedProps {
function HomeTabGetStarted ({plugin}: HomeTabGetStartedProps) {
const themeFilter = useContext(ThemeContext)
const carouselRef = useRef(null)
const carouselRef = useRef<any>({})
const carouselRefDiv = useRef(null)
useEffect(() => {
@ -44,7 +44,7 @@ function HomeTabGetStarted ({plugin}: HomeTabGetStartedProps) {
let nextSlide = 0
if (e.wheelDelta < 0) {
nextSlide = carouselRef.current.state.currentSlide + 1;
if ((carouselRef.current.state.totalItems - carouselRef.current.state.currentSlide) * carouselRef.current.state.itemWidth + 5 < carouselRef.current.state.containerWidth) return // 5 is approx margins
if (Math.abs(carouselRef.current.state.transform) >= carouselRef.current.containerRef.current.scrollWidth - carouselRef.current.state.containerWidth) return
carouselRef.current.goToSlide(nextSlide)
} else {
nextSlide = carouselRef.current.state.currentSlide - 1;
@ -77,7 +77,7 @@ function HomeTabGetStarted ({plugin}: HomeTabGetStartedProps) {
ref={carouselRef}
focusOnSelect={true}
customButtonGroup={
<CustomNavButtons next={undefined} previous={undefined} goToSlide={undefined} />
<CustomNavButtons next={undefined} previous={undefined} goToSlide={undefined} parent={carouselRef} />
}
arrows={false}
swipeable={false}

@ -49,25 +49,27 @@ function HomeTabLearn ({plugin}: HomeTabLearnProps) {
</button>
</div>
<div className="d-flex flex-column">
<button className="d-flex flex-column btn border" onClick={() => setState((prevState) => {return { ...prevState, visibleTutorial: VisibleTutorial.Basics }})}>
<label className="m-0 float-left" style={{fontSize: "1rem"}}>Remix Basics</label>
<label className="d-flex flex-column btn border" onClick={() => setState((prevState) => {return { ...prevState, visibleTutorial: VisibleTutorial.Basics }})}>
<label className="card-title align-self-start m-0 float-left" style={{fontSize: "1rem"}}>Remix Basics</label>
{(state.visibleTutorial === VisibleTutorial.Basics) && <div className="pt-2 d-flex flex-column text-left">
<span>Introduction to Remix's interface and concepts used in Ethereum, as well as the basics of Solidity.</span>
<button className="btn btn-sm btn-secondary mt-2" style={{width: 'fit-content'}} onClick={() => startLearnEthTutorial('basics')}>Get Started</button>
</div>}
</button>
<button className="d-flex flex-column btn border" onClick={() => setState((prevState) => {return { ...prevState, visibleTutorial: VisibleTutorial.Intermediate }})}>
<label className="m-0 float-left" style={{fontSize: "1rem"}}>Remix Intermediate</label>
{(state.visibleTutorial === VisibleTutorial.Intermediate) && <div className="pt-2 d-flex flex-column text-left">Using the web3.js to interact with a contract. Using Recorder tool.
<button className="btn btn-sm btn-secondary mt-2" style={{width: 'fit-content'}} onClick={() => startLearnEthTutorial('useofweb3js')}>Get Started</button>
</label>
<label className="d-flex flex-column btn border" onClick={() => setState((prevState) => {return { ...prevState, visibleTutorial: VisibleTutorial.Intermediate }})}>
<label className="card-title align-self-start m-0 float-left" style={{fontSize: "1rem"}}>Remix Intermediate</label>
{(state.visibleTutorial === VisibleTutorial.Intermediate) && <div className="pt-2 d-flex flex-column text-left">
<span>Using the web3.js to interact with a contract. Using Recorder tool.</span>
<button className="btn btn-sm btn-secondary mt-2" style={{width: 'fit-content'}} onClick={() => startLearnEthTutorial('useofweb3js')}>Get Started</button>
</div>}
</button>
<button className="d-flex flex-column btn border" onClick={() => setState((prevState) => {return { ...prevState, visibleTutorial: VisibleTutorial.Advanced }})}>
<label className="m-0 float-left" style={{fontSize: "1rem"}}>Remix Advanced</label>
{(state.visibleTutorial === VisibleTutorial.Advanced) && <div className="pt-2 d-flex flex-column text-left">Learn the Proxy Pattern and working with Libraries in Remix. Learn to use the Debugger.
<button className="btn btn-sm btn-secondary mt-2" style={{width: 'fit-content'}} onClick={() => startLearnEthTutorial('deploylibraries')}>Get Started</button>
</label>
<label className="d-flex flex-column btn border" onClick={() => setState((prevState) => {return { ...prevState, visibleTutorial: VisibleTutorial.Advanced }})}>
<label className="card-title align-self-start m-0 float-left" style={{fontSize: "1rem"}}>Remix Advanced</label>
{(state.visibleTutorial === VisibleTutorial.Advanced) && <div className="pt-2 d-flex flex-column text-left">
<span>Learn the Proxy Pattern and working with Libraries in Remix. Learn to use the Debugger.</span>
<button className="btn btn-sm btn-secondary mt-2" style={{width: 'fit-content'}} onClick={() => startLearnEthTutorial('deploylibraries')}>Get Started</button>
</div>}
</button>
</label>
</div>
</div>
)

@ -157,7 +157,7 @@ function HomeTabTitle() {
ref={searchInputRef}
type="text"
className="border form-control border-right-0"
id="searchInput"
id="homeTabSearchInput"
placeholder="Search Documentation"
data-id="terminalInputSearch"
/>

@ -1,7 +1,5 @@
import IpfsHttpClient from 'ipfs-http-client'
let ipfsNodes = []
export const publishToIPFS = async (contract, api) => {
@ -93,7 +91,6 @@ export const publishToIPFS = async (contract, api) => {
try {
const result = await ipfsVerifiedPublish(metadataContent, '', api)
try {
contract.metadataHash = result.url.match('dweb:/ipfs/(.+)')[1]
} catch (e) {

@ -17,12 +17,12 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
display: '',
content: ''
})
const [atAddressOptions, setAtAddressOptions] = useState<{ title: string, disabled: boolean }>({
const [atAddressOptions, setAtAddressOptions] = useState<{ title: string | JSX.Element, disabled: boolean }>({
title: 'address of contract',
disabled: true
})
const [loadedAddress, setLoadedAddress] = useState<string>('')
const [contractOptions, setContractOptions] = useState<{ title: string, disabled: boolean }>({
const [contractOptions, setContractOptions] = useState<{ title: string | JSX.Element, disabled: boolean }>({
title: 'Please compile *.sol file to deploy or access a contract',
disabled: true
})
@ -136,12 +136,12 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
if (enable) {
setAtAddressOptions({
disabled: false,
title: 'Interact with the deployed contract - requires the .abi file or compiled .sol file to be selected in the editor (with the same compiler configuration)'
title: <span className="text-start">Interact with the deployed contract - requires the .abi file or <br /> compiled .sol file to be selected in the editor <br />(with the same compiler configuration)</span>
})
} else {
setAtAddressOptions({
disabled: true,
title: loadedAddress ? 'Compile a *.sol file or select a *.abi file.' : 'To interact with a deployed contract, enter its address and compile its source *.sol file (with the same compiler settings) or select its .abi file in the editor. '
title: loadedAddress ? 'Compile a *.sol file or select a *.abi file.' : <span className="text-start">To interact with a deployed contract, either<br /> enter its address and compile its source *.sol file <br />(with the same compiler settings) or select its .abi file in the editor. </span>
})
}
}
@ -155,7 +155,7 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
} else {
setContractOptions({
disabled: true,
title: loadType === 'sol' ? 'Select and compile *.sol file to deploy or access a contract.' : 'When there is a compiled .sol file, the choice of contracts to deploy or to use with AtAddress is made here.'
title: loadType === 'sol' ? 'Select and compile *.sol file to deploy or access a contract.' : <span className="text-start">When there is a compiled .sol file, choose the <br /> contract to deploy or to use with AtAddress.'</span>
})
}
}
@ -236,7 +236,7 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
const checkSumWarning = () => {
return (
<span>
<span className="text-start">
It seems you are not using a checksumed address.
<br />A checksummed address is an address that contains uppercase letters, as specified in <a href="https://eips.ethereum.org/EIPS/eip-55" target="_blank" rel="noreferrer">EIP-55</a>.
<br />Checksummed addresses are meant to help prevent users from sending transactions to the wrong address.
@ -264,10 +264,12 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
{props.remixdActivated ?
(<CustomTooltip
placement={'right'}
tooltipClasses="text-wrap"
tooltipClasses="text-wrap text-left"
tooltipId="info-sync-compiled-contract"
tooltipText="Click here to import contracts compiled from an external framework.
This action is enabled when Remix is connected to an external framework (hardhat, truffle, foundry) through remixd."
tooltipText={<span className="text-left">
Click here to import contracts compiled from an external framework.<br/>
This action is enabled when Remix is connected to an external<br/> framework (hardhat, truffle, foundry) through remixd.
</span>}
>
<button className="btn d-flex py-0" onClick={_ => {
props.syncContracts()
@ -281,17 +283,19 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
<div className="udapp_subcontainer">
<CustomTooltip
placement={"right"}
tooltipClasses="text-nowrap"
tooltipClasses="text-nowrap text-left"
tooltipId="remixUdappContractNamesTooltip"
tooltipText={contractOptions.title}
>
<select ref={contractsRef} value={currentContract} onChange={handleContractChange} className="udapp_contractNames custom-select" disabled={contractOptions.disabled} style={{ display: loadType === 'abi' && !isContractFile(currentFile) ? 'none' : 'block' }}>
{(contractList[currentFile] || []).map((contract, index) => {
return <option key={index} value={contract.alias}>
{contract.alias} - {contract.file}
</option>
})}
</select>
<div id="udappcontractNamesWrapper" className="w-100">
<select ref={contractsRef} value={currentContract} onChange={handleContractChange} className="udapp_contractNames custom-select" disabled={contractOptions.disabled} style={{ display: loadType === 'abi' && !isContractFile(currentFile) ? 'none' : 'block', pointerEvents: contractOptions.disabled ? 'none' : 'auto' }}>
{(contractList[currentFile] || []).map((contract, index) => {
return <option key={index} value={contract.alias}>
{contract.alias} - {contract.file}
</option>
})}
</select>
</div>
</CustomTooltip>
<span className="py-1" style={{ display: abiLabel.display }}>{abiLabel.content}</span>
</div>
@ -324,9 +328,9 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
/>
<CustomTooltip
placement={'right'}
tooltipClasses="text-wrap"
tooltipClasses="text-wrap text-left"
tooltipId="remixIpfsUdappTooltip"
tooltipText="Publishing the source code and metadata to IPFS facilitates source code verification using Sourcify and will greatly foster contract adoption (auditing, debugging, calling it, etc...)"
tooltipText={<span className="text-start">Publishing the source code and metadata to IPFS facilitates<br/> source code verification using Sourcify and will greatly foster<br/> contract adoption (auditing, debugging, calling it, etc...)</span>}
>
<label
htmlFor="deployAndRunPublishToIPFS"
@ -346,7 +350,7 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
<div className="udapp_button udapp_atAddressSect ">
<CustomTooltip
placement={'top-end'}
tooltipClasses="text-wrap"
tooltipClasses="text-wrap text-left"
tooltipId="runAndDeployAddresstooltip"
tooltipText={atAddressOptions.title}
>
@ -358,9 +362,9 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
</CustomTooltip>
<CustomTooltip
placement={'top-end'}
tooltipClasses="text-wrap"
tooltipClasses="text-wrap text-left"
tooltipId="runAndDeployAddressInputtooltip"
tooltipText={"address of contract"}
tooltipText={"Address of contract"}
>
<input
ref={atAddressValue}

@ -556,7 +556,9 @@ export function ContractGUI (props: ContractGUIProps) {
<label className="mt-2 text-left d-block">
Proxy Address :
</label>
<input style={{ height: 32 }} className="form-control udapp_input" data-id="ERC1967AddressInput" placeholder='proxy address' title='Enter previously deployed proxy address on the selected network' onChange={handleSetProxyAddress} onBlur={() => validateProxyAddress(proxyAddress) } />
<CustomTooltip placement="right" tooltipText={'Enter previously deployed proxy address on the selected network'}>
<input style={{ height: 32 }} className="form-control udapp_input" data-id="ERC1967AddressInput" placeholder='proxy address' onChange={handleSetProxyAddress} onBlur={() => validateProxyAddress(proxyAddress) } />
</CustomTooltip>
{ proxyAddressError && <span className='text-lowercase' data-id="errorMsgProxyAddress" style={{ fontSize: '.8em' }}>{ proxyAddressError }</span> }
</div> :
<span className='text-capitalize' data-id="lastDeployedERC1967Address" style={{ fontSize: '.8em' }}>{ proxyAddress || proxyAddressError }</span>

@ -28,20 +28,26 @@ export function EnvironmentUI (props: EnvironmentProps) {
<div className="udapp_crow">
<label id="selectExEnv" className="udapp_settingsLabel">
<FormattedMessage id='udapp.environment' defaultMessage='Environment' />
<CustomTooltip placement={'right'} tooltipClasses="text-nowrap" tooltipId="info-recorder"
tooltipText="Open chainlist and add a new provider for the chain you want to interact to.">
tooltipText="Open chainlist.org and get the connection specs of the chain you want to interact with.">
<a href='https://chainlist.org/' target='_blank'><i style={{ fontSize: 'medium' }} className={'ml-2 fad fa-plug'} aria-hidden="true"></i></a>
</CustomTooltip>
</label>
<div className="udapp_environment">
<Dropdown id="selectExEnvOptions" data-id="settingsSelectEnvOptions" className='udapp_selectExEnvOptions'>
<Dropdown id="selectExEnvOptions" data-id="settingsSelectEnvOptions" className='udapp_selectExEnvOptions'>
<Dropdown.Toggle as={CustomToggle} id="dropdown-custom-components" className="btn btn-light btn-block w-100 d-inline-block border border-dark form-control" icon={null}>
{ isL2(currentProvider) && 'L2 - '}
{ currentProvider && currentProvider.content }
{ currentProvider && bridges[currentProvider.value] && <CustomTooltip placement={'right'} tooltipClasses="text-nowrap" tooltipId="info-recorder" tooltipText="Click to open a bridge for converting L1 mainnet ETH to the selected network currency.">
<i style={{ fontSize: 'medium' }} className={'ml-2 fal fa-plug'} aria-hidden="true" onClick={() => { window.open(bridges[currentProvider.value], '_blank') }}></i>
</CustomTooltip>}
{ currentProvider && bridges[currentProvider.value] && <CustomTooltip
placement={'right'}
tooltipClasses="text-nowrap"
tooltipId="info-recorder"
tooltipText="Click to open a bridge for converting L1 mainnet ETH to the selected network currency."
>
<i style={{ fontSize: 'medium' }} className={'ml-2 fal fa-plug'} aria-hidden="true" onClick={() => { window.open(bridges[currentProvider.value], '_blank') }}></i>
</CustomTooltip>}
</Dropdown.Toggle>
<Dropdown.Menu as={CustomMenu} className='w-100 custom-dropdown-items' data-id="custom-dropdown-items" >
{
@ -53,14 +59,16 @@ export function EnvironmentUI (props: EnvironmentProps) {
}}
data-id={`dropdown-item-${value}`}
>
<span className="pl-3">{ isL2({ value }) && 'L2 - ' }{ content }</span>
<span className="">{ isL2({ value }) && 'L2 - ' }{ content }</span>
</Dropdown.Item>
))
}
</Dropdown.Menu>
</Dropdown>
<CustomTooltip placement={'bottom-start'} tooltipClasses="text-wrap" tooltipId="runAndDeployAddresstooltip"
<CustomTooltip placement={'right-start'} tooltipClasses="text-wrap" tooltipId="runAndDeployAddresstooltip"
tooltipText={<FormattedMessage id='udapp.environmentDocs' defaultMessage='Click for docs about Environment' />}>
<a href="https://remix-ide.readthedocs.io/en/latest/run.html#environment" target="_blank" rel="noreferrer"><i className="udapp_infoDeployAction ml-2 fas fa-info"></i></a>
</CustomTooltip>
</div>

@ -13,7 +13,7 @@ export function GasPriceUI (props: GasPriceProps) {
<div className="udapp_crow">
<label className="udapp_settingsLabel"><FormattedMessage id='udapp.gasLimit' defaultMessage='Gas limit' /></label>
<CustomTooltip
placement={'right-end'}
placement={'right'}
tooltipClasses="text-nowrap"
tooltipId="remixGasPriceTooltip"
tooltipText={"The default gas limit is 3M. Adjust as needed."}

@ -4,7 +4,7 @@ import { NetworkProps } from '../types'
export function NetworkUI (props: NetworkProps) {
return (
<div className="udapp_crow">
<div className="">
<div className="udapp_settingsLabel">
</div>
<div className="udapp_environment" data-id="settingsNetworkEnv">

@ -28,7 +28,7 @@ export function RecorderUI (props: RecorderProps) {
return (
<div className="udapp_cardContainer list-group-item border border-bottom">
<div className="udapp_cardContainer list-group-item border-top border-bottom">
<div className="udapp_recorderSection d-flex justify-content-between" onClick={toggleClass}>
<div className="d-flex justify-content-center align-items-center">
<label className="mt-1 udapp_recorderSectionLabel">
@ -46,7 +46,7 @@ export function RecorderUI (props: RecorderProps) {
placement={'right'}
tooltipClasses="text-wrap"
tooltipId="info-recorder"
tooltipText="Save transactions (deployed contracts and function executions) and replay them in another environment e.g Transactions created in Remix VM can be replayed in the Injected Provider."
tooltipText={<span>Save transactions (deployed contracts and function executions) <br />and replay them in another environment e.g Transactions created <br />in Remix VM can be replayed in the Injected Provider.</span>}
>
<i style={{ fontSize: 'medium' }} className={'ml-2 fal fa-info-circle align-self-center'} aria-hidden="true"></i>
</CustomTooltip>
@ -64,7 +64,7 @@ export function RecorderUI (props: RecorderProps) {
placement={'right'}
tooltipClasses="text-wrap"
tooltipId="tooltip-livemode-recorder"
tooltipText="If contracts are updated after recording transactions, checking this box will run recorded transactions with the latest copy of the compiled contracts"
tooltipText={<span>If contracts are updated after recording transactions,<br/> checking this box will run recorded transactions <br/>with the latest copy of the compiled contracts</span>}
>
<label className="form-check-label custom-control-label" data-id="runtabLivemodeInput" htmlFor="livemode-recorder">Run transactions using the latest compilation result</label>
</CustomTooltip>

@ -336,7 +336,7 @@ export function UniversalDappUI (props: UdappProps) {
placement={"bottom-end"}
tooltipClasses="text-wrap"
tooltipId="receiveEthDocstoolTip"
tooltipText={"check out docs for using 'receive'/'fallback'"}
tooltipText={"Click for docs about using 'receive'/'fallback'"}
>
<a
href="https://solidity.readthedocs.io/en/v0.6.2/contracts.html#receive-ether-function"

@ -45,8 +45,6 @@
width: 164px;
min-width: 164px;
}
.udapp_col2_2 {
}
.udapp_select {
font-weight: normal;
width: 100%;
@ -314,7 +312,7 @@
.udapp_cActionsWrapper {
border-top-left-radius: 0;
border-bottom-left-radius: 0.25rem;
border-top-rightt-radius: 0;
border-top-right-radius: 0;
border-bottom-right-radius: 0.25rem;
padding: 8px 10px 7px;
}

@ -5,6 +5,7 @@ import { CompilerContainerProps } from './types'
import { ConfigurationSettings } from '@remix-project/remix-lib-ts'
import { checkSpecialChars, CustomTooltip, extractNameFromKey } from '@remix-ui/helper'
import { canUseWorker, baseURLBin, baseURLWasm, urlFromVersion, pathToURL, promisedMiniXhr } from '@remix-project/remix-solidity'
import { compilerReducer, compilerInitialState } from './reducers/compiler'
import { resetEditorMode, listenToEvents } from './actions/compiler'
import { getValidLanguage } from '@remix-project/remix-solidity'
@ -732,6 +733,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
setToggleExpander(!toggleExpander)
}
return (
<section>
<article>
@ -860,7 +862,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
tooltipText={<span>{'Language specification available from Compiler >= v0.5.7'}</span>}
>
<div id="compilerLanguageSelectorWrapper">
<select onChange={(e) => handleLanguageChange(e.target.value)} disabled={state.useFileConfiguration} value={state.language} className="custom-select" id="compilierLanguageSelector">
<select onChange={(e) => handleLanguageChange(e.target.value)} disabled={state.useFileConfiguration} value={state.language} className="custom-select" id="compilierLanguageSelector" style={{ pointerEvents: state.useFileConfiguration ? 'none' : 'auto' }}>
<option data-id={state.language === 'Solidity' ? 'selected' : ''} value='Solidity'>Solidity</option>
<option data-id={state.language === 'Yul' ? 'selected' : ''} value='Yul'>Yul</option>
</select>
@ -944,20 +946,26 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
{(configFilePath === '' && state.useFileConfiguration) && <div> No config file selected</div>}
</div>}
>
<span>
{ <i ref={compileIcon} className="fas fa-sync remixui_iconbtn" aria-hidden="true"></i> }
<FormattedMessage id='solidity.compile' defaultMessage='Compile' />
{typeof state.compiledFileName === 'string'
? extractNameFromKey(state.compiledFileName) ||
`<${intl.formatMessage({
id: 'solidity.noFileSelected',
defaultMessage: 'no file selected',
})}>`
: `<${intl.formatMessage({
id: 'solidity.noFileSelected',
defaultMessage: 'no file selected',
})}>`}
</span>
<div className="d-flex align-items-center justify-content-center">
{ <i ref={compileIcon} className="fas fa-sync remixui_iconbtn ml-4" aria-hidden="true"></i> }
<div className="d-flex justify-content-between align-items-center">
<span>
<FormattedMessage id='solidity.compile' defaultMessage='Compile' />
</span>
<span className="ml-1">
{typeof state.compiledFileName === 'string'
? extractNameFromKey(state.compiledFileName) ||
`<${intl.formatMessage({
id: 'solidity.noFileSelected',
defaultMessage: 'no file selected',
})}>`
: `<${intl.formatMessage({
id: 'solidity.noFileSelected',
defaultMessage: 'no file selected',
})}>`}
</span>
</div>
</div>
</CustomTooltip>
</button>
<div className='d-flex align-items-center'>
@ -969,7 +977,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
disabled={(configFilePath === '' && state.useFileConfiguration) || disableCompileButton}
>
<CustomTooltip
placement="auto"
placement="right"
tooltipId="overlay-tooltip-compile-run"
tooltipText={<div className="text-left">
{!(configFilePath === '' && state.useFileConfiguration) && <div><b>Ctrl+Shift+S</b> for compiling and script execution</div>}
@ -982,7 +990,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
</CustomTooltip>
</button>
<CustomTooltip
placement="auto"
placement="right"
tooltipId="overlay-tooltip-compile-run-doc"
tooltipText={<div className="text-left p-2">
<div>Choose the script to execute right after compilation by adding the `dev-run-script` natspec tag, as in:</div>
@ -996,7 +1004,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
contract ContractName {'{}'}<br />
</code>
</pre>
Click to know more
Click the i icon to learn more
</div>}
>
<a href="https://remix-ide.readthedocs.io/en/latest/running_js_scripts.html#compile-a-contract-and-run-a-script-on-the-fly" target="_blank" ><i className="pl-2 ml-2 mt-3 mb-1 fas fa-info text-dark"></i></a>

@ -259,7 +259,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { // eslint-d
finalLogs = finalLogs + '&emsp;' + formattedLog + '\n'
}
_paq.push(['trackEvent', 'solidityUnitTesting', 'hardhat', 'console.log'])
testTab.call('terminal', 'log', { type: 'log', value: finalLogs })
testTab.call('terminal', 'logHtml', { type: 'log', value: finalLogs })
}
const discardHighlight = async () => {

@ -19,12 +19,12 @@ const StaticAnalyserButton = ({
return (
<button className={classList} disabled={disabled} onClick={onClick}>
<CustomTooltip
placement="bottom-start"
placement="right"
tooltipId="ssaRunButtonTooltip"
tooltipClasses="text-nowrap"
tooltipText={title}
>
<span>
<span className="pl-3 pr-4">
{buttonText}
</span>
</CustomTooltip>

@ -458,7 +458,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
expand={false}
>
<div>
<RemixUiCheckbox onClick={() => handleCheckOrUncheckCategory(category)} id={categoryId} inputType="checkbox" label={`Select ${category[0].categoryDisplayName}`} name='checkCategoryEntry' checked={category.map(x => x._index.toString()).every(el => categoryIndex.includes(el))} onChange={() => {}}/>
<RemixUiCheckbox onClick={() => handleCheckOrUncheckCategory(category)} id={categoryId} inputType="checkbox" label={`Select ${category[0].categoryDisplayName}`} name='checkCategoryEntry' checked={category.map(x => x._index.toString()).every(el => categoryIndex.includes(el))} onChange={() => {}} title={category[0].categoryDisplayName} tooltipPlacement="right"/>
</div>
<div className="w-100 d-block px-2 my-1 entries collapse multi-collapse" id={`heading${categoryId}`}>
{category.map((item, i) => {

@ -1,3 +1,4 @@
import { CustomTooltip } from '@remix-ui/helper'
import React from 'react'
import BasicLogo from './BasicLogo'
interface HomeProps {
@ -6,16 +7,20 @@ interface HomeProps {
function Home ({ verticalIconPlugin }: HomeProps) {
return (
<div
className="mt-2 my-1 remixui_homeIcon"
onClick={async () => await verticalIconPlugin.activateHome()}
{...{ plugin: 'home'}}
title="Home"
data-id="verticalIconsHomeIcon"
id="verticalIconsHomeIcon"
<CustomTooltip
placement="right"
tooltipText={"Home"}
>
<BasicLogo />
</div>
<div
className="mt-2 my-1 remixui_homeIcon"
onClick={async () => await verticalIconPlugin.activateHome()}
{...{ plugin: 'home'}}
data-id="verticalIconsHomeIcon"
id="verticalIconsHomeIcon"
>
<BasicLogo />
</div>
</CustomTooltip>
)
}

@ -5,6 +5,7 @@ import Badge from './Badge'
import { iconBadgeReducer, IconBadgeReducerAction } from '../reducers/iconBadgeReducer'
import { Plugin } from '@remixproject/engine'
import { IconRecord } from '../types'
import { CustomTooltip } from '@remix-ui/helper'
export interface IconStatus {
key: string
@ -84,27 +85,33 @@ const Icon = ({
return (
<>
<div
className={`remixui_icon m-2 pt-1`}
onClick={() => {
(verticalIconPlugin as any).toggle(name)
}}
{...{plugin: name}}
title={title}
onContextMenu={(e: any) => {
e.preventDefault()
e.stopPropagation()
handleContextMenu(e)
}}
data-id={`verticalIconsKind${name}`}
id={`verticalIconsKind${name}`}
ref={iconRef}
<CustomTooltip
placement={name === 'settings' ? 'right' : name === 'search' ? 'bottom' :
name === 'udapp' ? 'bottom' : "top"}
tooltipText={title}
delay={{ show: 1000, hide: 0 }}
>
<img data-id={iconRecord.active ? `selected`: ''} className={`${theme === 'dark' ? 'invert' : ''} ${theme} remixui_image ${iconRecord.active ? `selected-${theme}`:''}`} src={icon} alt={name} />
<Badge
badgeStatus={badgeStatus}
/>
</div>
<div
className={`remixui_icon m-2 pt-1`}
onClick={() => {
(verticalIconPlugin as any).toggle(name)
}}
{...{plugin: name}}
onContextMenu={(e: any) => {
e.preventDefault()
e.stopPropagation()
handleContextMenu(e)
}}
data-id={`verticalIconsKind${name}`}
id={`verticalIconsKind${name}`}
ref={iconRef}
>
<img data-id={iconRecord.active ? `selected`: ''} className={`${theme === 'dark' ? 'invert' : ''} ${theme} remixui_image ${iconRecord.active ? `selected-${theme}`:''}`} src={icon} alt={name} />
<Badge
badgeStatus={badgeStatus}
/>
</div>
</CustomTooltip>
{showContext ? (
<VerticalIconsContextMenu
pageX={pageX}

@ -22,9 +22,9 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => {
},
{
action: 'publishToGist',
title: 'Publish all the current workspace files (only root) to a github gist',
title: 'Publish all the current workspace files to a github gist',
icon: 'fab fa-github',
placement: 'top-start'
placement: 'bottom-start'
},
{
action: 'uploadFile',
@ -36,7 +36,7 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => {
action: 'updateGist',
title: 'Update the current [gist] explorer',
icon: 'fab fa-github',
placement: 'right-start'
placement: 'bottom-start'
}
].filter(item => props.menuItems && props.menuItems.find((name) => { return name === item.action })),
actions: {}

@ -264,7 +264,7 @@ export function Workspace () {
<option style={{fontSize: "small"}} value='remixDefault'>Default</option>
<option style={{fontSize: "small"}} value='blank'>Blank</option>
</optgroup>
<optgroup style={{fontSize: "medium"}} label="OpenZepplin">
<optgroup style={{fontSize: "medium"}} label="OpenZeppelin">
<option style={{fontSize: "small"}} value='ozerc20'>ERC20</option>
<option style={{fontSize: "small"}} value='ozerc721'>ERC721</option>
<option style={{fontSize: "small"}} value='ozerc1155'>ERC1155</option>

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-url-resolver",
"version": "0.0.40",
"version": "0.0.41",
"description": "Solidity import url resolver engine",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -25,7 +25,7 @@
"license": "MIT",
"dependencies": {
"@erebos/bzz-node": "^0.13.0",
"axios": ">=0.21.1",
"axios": "1.1.2",
"url": "^0.11.0",
"valid-url": "^1.0.9"
},
@ -41,5 +41,5 @@
"typescript": "^3.1.6"
},
"typings": "src/index.d.ts",
"gitHead": "2cec195f5a3678b17745155536a1714d9b1a5694"
"gitHead": "569f7d53f6f218d99aa8281929b541ab7e00058f"
}

@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-ws-templates",
"version": "1.0.6",
"version": "1.0.7",
"description": "Create a Remix IDE workspace using different templates",
"main": "src/index.js",
"types": "src/index.d.ts",
@ -27,5 +27,5 @@
"ethers": "^5.4.2",
"web3": "^1.5.1"
},
"gitHead": "2cec195f5a3678b17745155536a1714d9b1a5694"
"gitHead": "569f7d53f6f218d99aa8281929b541ab7e00058f"
}

@ -40,7 +40,7 @@
"@remixproject/plugin-api": "^0.3.11",
"@remixproject/plugin-utils": "^0.3.11",
"@remixproject/plugin-ws": "^0.3.11",
"axios": ">=0.21.1",
"axios": "1.1.2",
"chokidar": "^2.1.8",
"commander": "^2.20.3",
"fs-extra": "^3.0.1",

@ -168,7 +168,7 @@
"@types/nightwatch": "^2.3.1",
"ansi-gray": "^0.1.1",
"async": "^2.6.2",
"axios": ">=0.26.0",
"axios": "1.1.2",
"bootstrap": "^5.1.3",
"brace": "^0.8.0",
"change-case": "^4.1.1",

@ -5866,13 +5866,22 @@ axe-core@^4.0.2:
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.5.tgz#78d6911ba317a8262bfee292aeafcc1e04b49cc5"
integrity sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==
axios@*, axios@>=0.26.0:
axios@*:
version "0.26.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.0.tgz#9a318f1c69ec108f8cd5f3c3d390366635e13928"
integrity sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==
dependencies:
follow-redirects "^1.14.8"
axios@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.1.2.tgz#8b6f6c540abf44ab98d9904e8daf55351ca4a331"
integrity sha512-bznQyETwElsXl2RK7HLLwb5GPpOLlycxHCtrpDR/4RqqBzjARaOTo3jz4IgtntWUYee7Ne4S8UHd92VCuzPaWA==
dependencies:
follow-redirects "^1.15.0"
form-data "^4.0.0"
proxy-from-env "^1.1.0"
axios@^0.21.1:
version "0.21.4"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575"
@ -11268,6 +11277,11 @@ follow-redirects@^1.0.0, follow-redirects@^1.12.1, follow-redirects@^1.14.0, fol
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7"
integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==
follow-redirects@^1.15.0:
version "1.15.2"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
for-each@~0.3.3:
version "0.3.3"
resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
@ -19426,6 +19440,11 @@ proxy-addr@~2.0.5:
forwarded "0.2.0"
ipaddr.js "1.9.1"
proxy-from-env@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
prr@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"

Loading…
Cancel
Save