├── .circleci └── config.yml ├── .coveralls.yml ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── README.md ├── jest.config.js ├── package-lock.json ├── package.json ├── public └── index.html ├── src ├── RemixDebugger.tsx ├── components │ └── Header.tsx ├── index.css ├── index.tsx ├── utils │ ├── contract-util.ts │ └── source-utils.ts └── views │ ├── ErrorView.tsx │ ├── HomeView.tsx │ └── index.ts ├── test ├── contract-util.test.ts └── faker.ts ├── tsconfig.json ├── tslint.json ├── webpack.config.js └── webpack.config.production.js /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.0 2 | 3 | aliases: 4 | - &nodejs-docker-image 5 | - image: circleci/node:14.18.0 6 | 7 | - &restore_cache 8 | restore_cache: 9 | name: Restore node_modules cache 10 | keys: 11 | - node-v1-{{ .Branch }}-{{ checksum "package-lock.json" }} 12 | - node-v1-{{ .Branch }}- 13 | - node-v1- 14 | 15 | jobs: 16 | setup: 17 | docker: *nodejs-docker-image 18 | steps: 19 | - checkout 20 | - *restore_cache 21 | - run: 22 | name: Install NPM 23 | command: | 24 | echo 'Installing dependencies' 25 | npm install 26 | - save_cache: 27 | key: node-v1-{{ .Branch }}-{{ checksum "package-lock.json" }} 28 | paths: 29 | - node_modules 30 | 31 | tslint-and-format: 32 | docker: *nodejs-docker-image 33 | steps: 34 | - checkout 35 | - *restore_cache 36 | - run: 37 | name: TSLint 38 | command: npm run tslint 39 | - run: 40 | name: Check formatting (Prettier) 41 | command: npm run check-formatting 42 | 43 | unit-tests: 44 | docker: *nodejs-docker-image 45 | steps: 46 | - checkout 47 | - *restore_cache 48 | - run: 49 | name: Run unit tests with JUnit as reporter 50 | command: npm run test:ci 51 | environment: 52 | JEST_JUNIT_OUTPUT: "reports/junit/js-test-results.xml" 53 | - store_test_results: 54 | path: reports/junit 55 | - store_artifacts: 56 | path: reports/junit 57 | 58 | npm-audit: 59 | docker: *nodejs-docker-image 60 | steps: 61 | - checkout 62 | - *restore_cache 63 | - run: 64 | name: NPM Audit 65 | command: npm audit 66 | 67 | bundle: 68 | docker: *nodejs-docker-image 69 | steps: 70 | - checkout 71 | - *restore_cache 72 | - run: 73 | name: Bundle 74 | command: npm run bundle 75 | 76 | publish: 77 | docker: *nodejs-docker-image 78 | steps: 79 | - checkout 80 | - *restore_cache 81 | - run: 82 | name: Publish 83 | command: npm run publish 84 | 85 | workflows: 86 | version: 2 87 | build-deploy: 88 | jobs: 89 | - setup 90 | - tslint-and-format: 91 | requires: 92 | - setup 93 | - unit-tests: 94 | requires: 95 | - setup 96 | - npm-audit: 97 | requires: 98 | - setup 99 | - bundle: 100 | requires: 101 | - tslint-and-format 102 | - unit-tests 103 | - publish: 104 | context: SolidStudio 105 | requires: 106 | - bundle 107 | filters: 108 | branches: 109 | only: master -------------------------------------------------------------------------------- /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: circleci 2 | repo_token: $COVERALLS_REPO_TOKEN -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Directory for instrumented libs generated by jscoverage/JSCover 9 | lib-cov 10 | 11 | # Coverage directory used by tools like istanbul 12 | coverage 13 | 14 | # Dependency directories 15 | node_modules/ 16 | 17 | # dotenv environment variable files 18 | .env* 19 | 20 | # Mac files 21 | .DS_Store 22 | 23 | dist 24 | TODO* 25 | junit.xml 26 | junit.xml 27 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 14.18.0 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .cache 2 | package.json 3 | package-lock.json 4 | public 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": false, 4 | "singleQuote": false, 5 | "tabWidth": 2, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Control Flow Graph Remix Plugin 3 | 4 | [![CircleCI](https://circleci.com/gh/Machinalabs/remix-control-flow-graph.svg?style=svg)](https://circleci.com/gh/Machinalabs/remix-control-flow-graph) [![Coverage Status](https://coveralls.io/repos/github/solid-studio/remix-control-flow-graph/badge.svg?branch=master)](https://coveralls.io/github/solid-studio/remix-control-flow-graph?branch=master) 5 | 6 | drawing 7 | 8 | ## Features 9 | 10 | - Interactive control flow graph 11 | 12 | - Solidity support 13 | 14 | - Control flow graph generation from bytecode 15 | 16 | - Control flow graph generation and execution trace highlighted (WIP) 17 | 18 | - Source mapping highlight (limited to 1 single Remix contract file) (WIP) 19 | 20 | - EVM state exploration in debug mode (storage viewer, memory viewer, stack viewer) 21 | 22 | ## Install 23 | 24 | ``` 25 | git clone git@github.com:solid-studio/remix-control-flow-graph.git 26 | 27 | npm install 28 | 29 | npm start 30 | ``` 31 | 32 | ## Commands 33 | 34 | > npm start 35 | 36 | > npm test 37 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "roots": [ 3 | "" 4 | ], 5 | "transform": { 6 | "^.+\\.tsx?$": "ts-jest" 7 | }, 8 | "reporters": ["default", "jest-junit"], 9 | "testEnvironment": "node", 10 | "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$", 11 | "moduleFileExtensions": [ 12 | "ts", 13 | "tsx", 14 | "js", 15 | "json" 16 | ] 17 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remix-cfg-plugin", 3 | "version": "1.0.0", 4 | "description": "A Remix plugin to visualise control flow graphs", 5 | "main": "webpack.config.js", 6 | "scripts": { 7 | "start": "webpack-dev-server", 8 | "bundle": "webpack --config webpack.config.production.js", 9 | "test": "jest", 10 | "test:ci": "jest --runInBand --detectOpenHandles --ci --reporters=default --reporters=jest-junit --coverage --coverageReporters=text-lcov | coveralls", 11 | "tslint": "tslint -p . -c tslint.json", 12 | "tslint:fix": "tslint --fix -p . -c tslint.json", 13 | "prettier": "prettier --write \"src/**/*.{ts,,tsx,js,json}\"", 14 | "check-formatting": "prettier --list-different \"src/**/*.{ts,ts,js,json}\"", 15 | "publish": "npm run bundle && surge --project ./dist --domain remix-control-flow-gas.surge.sh" 16 | }, 17 | "keywords": [], 18 | "author": "Solid Studio Team", 19 | "license": "ISC", 20 | "devDependencies": { 21 | "@types/d3": "^5.7.2", 22 | "@types/dagre-d3": "^0.4.39", 23 | "@types/jest": "^27.0.2", 24 | "@types/react": "^16.9.19", 25 | "@types/react-dom": "^16.9.5", 26 | "awesome-typescript-loader": "^3.1.3", 27 | "coveralls": "^3.0.9", 28 | "css-loader": "^3.4.2", 29 | "html-webpack-plugin": "^3.2.0", 30 | "jest": "^27.2.5", 31 | "jest-junit": "^13.0.0", 32 | "prettier": "^1.19.1", 33 | "source-map-loader": "^0.2.4", 34 | "style-loader": "^1.1.3", 35 | "styled-components": "^5.0.0", 36 | "surge": "^0.23.0", 37 | "ts-jest": "^27.0.5", 38 | "ts-loader": "^6.2.1", 39 | "tslint": "^6.0.0", 40 | "tslint-config-prettier": "^1.18.0", 41 | "typescript": "^3.7.5", 42 | "webpack": "^4.41.5", 43 | "webpack-cli": "^4.9.0", 44 | "webpack-dev-server": "^4.3.1" 45 | }, 46 | "dependencies": { 47 | "@ethereum-react/components": "^1.12.1", 48 | "@ethereum-react/types": "^1.6.0", 49 | "@ethereum-react/utilities": "^1.6.0", 50 | "@ethereumjs/common": "^2.4.0", 51 | "@ethereumjs/vm": "^5.5.2", 52 | "@remixproject/plugin": "^0.1.9", 53 | "@types/node": "^13.5.2", 54 | "classnames": "^2.2.6", 55 | "d3": "^5.15.0", 56 | "d3-selection": "^1.4.1", 57 | "dagre-d3": "^0.6.4", 58 | "react": "^16.12.0", 59 | "react-dom": "^16.12.0", 60 | "tslint-react": "^4.2.0" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Remix Control Flow Graph! 7 | 8 | 9 | 10 | 17 | 18 | 52 | 53 | 54 | 55 |
56 | 57 | 58 | -------------------------------------------------------------------------------- /src/RemixDebugger.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react" 2 | import { createIframeClient } from "@remixproject/plugin" 3 | 4 | import { Debugger } from "@ethereum-react/components" 5 | import { ControlFlowGraphCreator } from "@ethereum-react/utilities" 6 | 7 | import { HomeView, ErrorView } from "./views" 8 | import { 9 | getContractByteCode, 10 | getSolidityVersionFromData, 11 | } from "./utils/contract-util" 12 | import { Header } from "./components/Header" 13 | import { Operation, CFGBlocks } from "@ethereum-react/types" 14 | import { 15 | getContractSourceDetails, 16 | getActiveSourceForOp, 17 | } from "./utils/source-utils" 18 | 19 | const devMode = { port: 8080 } 20 | 21 | interface TxDebugData { 22 | blocks: CFGBlocks 23 | traces: any 24 | } 25 | 26 | export const RemixDebugger: React.FC = () => { 27 | const [clientInstance, setClientInstance] = useState(undefined) 28 | const [debuggingTx, setDebuggingTx] = useState(undefined) 29 | const [isInitialized, setIsInitialized] = useState(false) 30 | const [blocks, setBlocks] = useState(undefined) 31 | const [hasError, setHasError] = useState(false) 32 | const [contract, setContract] = useState("") 33 | 34 | const [renderMode, setRenderMode] = useState(undefined) 35 | 36 | useEffect(() => { 37 | const client = createIframeClient({ devMode }) 38 | const loadClient = async () => { 39 | await client.onload() 40 | setClientInstance(client) 41 | 42 | console.log("Remix Control Flow Graph Plugin has been loaded") 43 | 44 | client.udapp.on("newTransaction", async (transaction: any) => { 45 | console.log("A new transaction was sent", transaction) 46 | setRenderMode(null) 47 | 48 | if (!isInitialized) { 49 | setIsInitialized(true) 50 | } 51 | 52 | try { 53 | const { hash, contractAddress } = transaction 54 | 55 | const isContractCreation = contractAddress ? true : false 56 | const traces = await client.call("debugger" as any, "getTrace", hash) 57 | 58 | console.log("hash", hash) 59 | console.log("isContractCreation", isContractCreation) 60 | console.log("contractAddress", contractAddress) 61 | console.log("traces", traces) 62 | 63 | const compilationResult = await client.solidity.getCompilationResult() 64 | console.log("Compilation Result", compilationResult) 65 | 66 | const contractData = await getContractByteCode( 67 | (compilationResult as any).data, 68 | isContractCreation 69 | ) 70 | console.log("Contract data", contractData) 71 | 72 | const solidityVersion = getSolidityVersionFromData( 73 | (compilationResult as any).data 74 | ) 75 | console.log("Solidity version", solidityVersion) 76 | 77 | const controlFlowGraphResult = new ControlFlowGraphCreator().buildControlFlowGraph( 78 | contractData.bytecode, 79 | solidityVersion as any 80 | ) 81 | console.log("Control flow graph result", controlFlowGraphResult) 82 | 83 | const blocks = isContractCreation 84 | ? controlFlowGraphResult.contractConstructor.blocks 85 | : controlFlowGraphResult.contractRuntime.blocks 86 | 87 | if (!blocks) { 88 | throw new Error("Couldn't get the blocks") 89 | } 90 | 91 | const sourceMapDetails = getContractSourceDetails( 92 | contractData.contractFile, 93 | contractData.bytecode, 94 | contractData.sourceMap, 95 | (compilationResult as any).source 96 | ) 97 | 98 | setDebuggingTx({ 99 | contract: `${contractData.contractName} - ${contractData.contractFile}`, 100 | txHash: hash, 101 | traces, 102 | blocks, 103 | bytecode: contractData.bytecode, 104 | source: sourceMapDetails, 105 | }) 106 | 107 | client.emit("statusChanged", { 108 | key: "edited", 109 | type: "success", 110 | title: `Data changed. Run render to update graph`, 111 | }) 112 | 113 | setHasError(false) 114 | } catch (error) { 115 | console.log(`An error ocurrer ${error}`) 116 | setHasError(true) 117 | } 118 | }) 119 | 120 | client.solidity.on( 121 | "compilationFinished", 122 | async (fileName, source, languageVersion, data) => { 123 | console.log("A compilation finished") 124 | 125 | setRenderMode(null) 126 | 127 | if (!isInitialized) { 128 | setIsInitialized(true) 129 | } 130 | 131 | try { 132 | const solidityVersion = getSolidityVersionFromData(data) 133 | console.log("Solidity version", solidityVersion) 134 | 135 | const contractData = await getContractByteCode(data, false) 136 | console.log("Contract data", contractData) 137 | 138 | setContract( 139 | `${contractData.contractName} - ${contractData.contractFile}` 140 | ) 141 | 142 | const controlFlowGraphResult = new ControlFlowGraphCreator().buildControlFlowGraph( 143 | contractData.bytecode, 144 | solidityVersion as any 145 | ) 146 | 147 | console.log("Control flow graph result", controlFlowGraphResult) 148 | 149 | setBlocks(controlFlowGraphResult.contractRuntime.blocks) 150 | // setTraces(undefined) 151 | 152 | client.emit("statusChanged", { 153 | key: "edited", 154 | type: "success", 155 | title: `Data changed. Run render to update graph`, 156 | }) 157 | setHasError(false) 158 | } catch (error) { 159 | console.log(`An error ocurrer ${error}`) 160 | setHasError(true) 161 | } 162 | } 163 | ) 164 | } 165 | 166 | loadClient() 167 | }, []) 168 | 169 | useEffect(() => { 170 | if (hasError) { 171 | clientInstance.emit("statusChanged", { 172 | key: "failed", 173 | type: "error", 174 | title: `There was an error while generating the CFG`, 175 | }) 176 | } 177 | }, [hasError]) 178 | 179 | const renderRequested = renderMode => { 180 | setRenderMode(renderMode) 181 | clientInstance.editor.discardHighlight() 182 | 183 | clientInstance.emit("statusChanged", { 184 | key: "succeed", 185 | type: "success", 186 | title: `Control flow graph successfully generated`, 187 | }) 188 | } 189 | 190 | const highlightLine = async (op: Operation) => { 191 | if (!debuggingTx) { 192 | return 193 | } 194 | 195 | const sourcePart = getActiveSourceForOp(debuggingTx.source, op.offset) 196 | 197 | clientInstance.editor.discardHighlight() 198 | 199 | await clientInstance.editor.highlight( 200 | sourcePart, 201 | debuggingTx.source.contractFile, 202 | "var(--info)" 203 | ) 204 | } 205 | 206 | return hasError ? ( 207 | 208 | ) : isInitialized ? ( 209 |
210 |
219 |
220 | {renderMode === "contract" && ( 221 | 222 | )} 223 | {renderMode === "traces" && debuggingTx && ( 224 | highlightLine(op)} 229 | /> 230 | )} 231 |
232 |
233 | ) : ( 234 | 235 | ) 236 | } 237 | -------------------------------------------------------------------------------- /src/components/Header.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react" 2 | import classNames from "classnames" 3 | 4 | type RenderMode = "contract" | "traces" 5 | 6 | export interface Props { 7 | contractDetails: { contractName: string } 8 | txDetails: { contractName: string; txHash: string } 9 | onRenderRequest: (type: RenderMode) => void 10 | } 11 | 12 | export const Header: React.FC = (props: Props) => { 13 | const [renderMode, setRenderMode] = useState() 14 | return ( 15 |
16 |
17 | 28 | 39 |
40 | 47 | {renderMode && ( 48 |
49 | {renderMode === "contract" && ( 50 |
51 | {/*
52 | 53 |
*/} 54 |
55 | {props.contractDetails.contractName || "-"} 56 |
57 |
58 | )} 59 | 60 | {renderMode === "traces" && ( 61 |
62 | {/*
63 | 64 |
*/} 65 |
66 | {props.txDetails.contractName || "-"} 67 |
68 |
69 | {props.txDetails.txHash || "-"} 70 |
71 |
72 | )} 73 |
74 | )} 75 |
76 | ) 77 | } 78 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | html, body, #root, .sb-show-main { 2 | height: 100%; 3 | } -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import ReactDOM from "react-dom" 3 | 4 | import { RemixDebugger } from "./RemixDebugger" 5 | 6 | import "./index.css" 7 | 8 | ReactDOM.render(, document.getElementById("root")) 9 | -------------------------------------------------------------------------------- /src/utils/contract-util.ts: -------------------------------------------------------------------------------- 1 | import { CompilationResult } from "@remixproject/plugin" 2 | import { CompilerVersion } from "@ethereum-react/types" 3 | 4 | export const getContractByteCode = ( 5 | data: CompilationResult, 6 | isContractCreation: boolean 7 | ) => { 8 | const contracts = data.contracts 9 | 10 | for (const file of Object.keys(contracts)) { 11 | for (const contract of Object.keys(contracts[file])) { 12 | const currentContractEVMData = contracts[file][contract].evm 13 | 14 | const contractData = isContractCreation 15 | ? currentContractEVMData.bytecode 16 | : currentContractEVMData.deployedBytecode 17 | 18 | const bytecode = contractData.object 19 | const sourceMap = contractData.sourceMap 20 | 21 | return { 22 | contractName: contract, 23 | bytecode, 24 | sourceMap, 25 | contractFile: file, 26 | } 27 | } 28 | } 29 | } 30 | 31 | const SOLIDITY_VERSION_4_REGEX = new RegExp(/0.4.\d+/) 32 | const SOLIDITY_VERSION_5_REGEX = new RegExp(/0.5.\d+/) 33 | const SOLIDITY_VERSION_6_REGEX = new RegExp(/0.6.\d+/) 34 | const SOLIDITY_VERSION_7_REGEX = new RegExp(/0.7.\d+/) 35 | const SOLIDITY_VERSION_8_REGEX = new RegExp(/0.8.\d+/) 36 | 37 | export const getSolidityVersionFromData = (data: CompilationResult) => { 38 | const contracts = data.contracts 39 | 40 | for (const file of Object.keys(contracts)) { 41 | for (const contract of Object.keys(contracts[file])) { 42 | const currentContractMetadata = JSON.parse( 43 | contracts[file][contract].metadata 44 | ) 45 | const compilerVersion = currentContractMetadata.compiler.version as string 46 | if (compilerVersion.match(SOLIDITY_VERSION_4_REGEX)) { 47 | return CompilerVersion.SOLIDITY_4 48 | } 49 | if (compilerVersion.match(SOLIDITY_VERSION_5_REGEX)) { 50 | return CompilerVersion.SOLIDITY_5 51 | } 52 | 53 | if (compilerVersion.match(SOLIDITY_VERSION_6_REGEX)) { 54 | return CompilerVersion.SOLIDITY_6 55 | } 56 | 57 | if (compilerVersion.match(SOLIDITY_VERSION_7_REGEX)) { 58 | return CompilerVersion.SOLIDITY_7 59 | } 60 | 61 | if (compilerVersion.match(SOLIDITY_VERSION_8_REGEX)) { 62 | return CompilerVersion.SOLIDITY_8 63 | } 64 | 65 | throw new Error(`Unsupported solidity version ${compilerVersion}`) 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/utils/source-utils.ts: -------------------------------------------------------------------------------- 1 | import { StructLog } from "@ethereum-react/types" 2 | import Common from "@ethereumjs/common" 3 | import { getOpcodesForHF } from "@ethereumjs/vm/dist/evm/opcodes" 4 | 5 | export const getContractSourceDetails = ( 6 | file: string, 7 | bytecode: string, 8 | sourceMap: string, 9 | compilationSources 10 | ) => { 11 | const originalSourceCode = compilationSources 12 | ? compilationSources.sources[file].content 13 | : null 14 | 15 | const [code, instructionsIndexByBytesOffset] = nameOpCodes( 16 | Buffer.from(bytecode, "hex") 17 | ) 18 | return { 19 | sourceCode: originalSourceCode, 20 | sourceMapDetails: { 21 | parsedSourceMap: parseSourceMap(sourceMap), 22 | lineOffsets: buildLineOffsets(originalSourceCode), 23 | pcToInstructionMappings: instructionsIndexByBytesOffset, 24 | codeStartsAtLine: contractStartingLine(originalSourceCode), 25 | }, 26 | contractFile: file, 27 | } 28 | } 29 | 30 | const contractStartingLine = (source: string) => 31 | source.substring(0, source.search(/pragma/)).split("\n").length - 1 32 | 33 | export const buildLineOffsets = (src: string) => { 34 | let accu = 0 35 | return src.split("\n").map(line => { 36 | const ret = accu 37 | accu += line.length + 1 38 | return ret 39 | }) 40 | } 41 | 42 | interface IMapping { 43 | [key: string]: number 44 | } 45 | 46 | export const buildPcToInstructionMapping = (codeHexStr: string) => { 47 | const mapping: IMapping = {} 48 | let instructionIndex = 0 49 | console.log("codeHexStr.length", codeHexStr.length) 50 | console.log("codeHexStr", codeHexStr) 51 | 52 | for (let pc = 0; pc < codeHexStr.length / 2; ) { 53 | mapping[pc] = instructionIndex 54 | 55 | const byteHex = codeHexStr[pc * 2] + codeHexStr[pc * 2 + 1] 56 | const byte = parseInt(byteHex, 16) 57 | 58 | // PUSH instruction has immediates 59 | if (byte >= 0x60 && byte <= 0x7f) { 60 | const n = byte - 0x60 + 1 // number of immediates 61 | pc += n + 1 62 | } else { 63 | pc += 1 64 | } 65 | instructionIndex += 1 66 | } 67 | return mapping 68 | } 69 | 70 | export const normalizeStructLogs = (structLogs: StructLog[]): StructLog[] => { 71 | if (structLogs[0].depth === 1) { 72 | // Geth uses 1-indexed depth counter whilst ganache starts from 0 73 | const newStructLogs = structLogs.map(structLog => ({ 74 | ...structLog, 75 | depth: structLog.depth - 1, 76 | })) 77 | return newStructLogs 78 | } 79 | return structLogs 80 | } 81 | 82 | // https://solidity.readthedocs.io/en/develop/miscellaneous.html#source-mappings 83 | export const parseSourceMap = (sourceMap: string) => { 84 | let prevS: string 85 | let prevL: string 86 | let prevF: string 87 | let prevJ: string 88 | 89 | console.log("SourceMapToParse", sourceMap) 90 | 91 | return sourceMap 92 | .trim() 93 | .split(";") 94 | .map(section => { 95 | let [s, l, f, j] = section.split(":") 96 | 97 | if (s === "" || s === undefined) { 98 | s = prevS 99 | } else { 100 | prevS = s 101 | } 102 | 103 | if (l === "" || l === undefined) { 104 | l = prevL 105 | } else { 106 | prevL = l 107 | } 108 | 109 | if (f === "" || f === undefined) { 110 | f = prevF 111 | } else { 112 | prevF = f 113 | } 114 | 115 | if (j === "" || j === undefined) { 116 | j = prevJ 117 | } else { 118 | prevJ = j 119 | } 120 | 121 | return { s: Number(s), l: Number(l), f: Number(f), j } 122 | }) 123 | } 124 | 125 | export const getActiveSourceForOp = (contractSourceData, opOffset: number) => { 126 | const offsets = contractSourceData.sourceMapDetails.lineOffsets 127 | 128 | const instructionIdx = 129 | contractSourceData.sourceMapDetails.pcToInstructionMappings[opOffset] 130 | 131 | const { 132 | s: start, 133 | l: length, 134 | f: file, 135 | j, 136 | } = contractSourceData.sourceMapDetails.parsedSourceMap[instructionIdx] 137 | 138 | // if (file === -1) { 139 | // return null 140 | // } 141 | 142 | const startingLineIndex = offsets.findIndex(o => o >= start) - 1 143 | 144 | const lineStartingOffset = offsets[startingLineIndex] 145 | const startingColumn = start - lineStartingOffset 146 | 147 | let endingLineIndex = startingLineIndex 148 | 149 | for (let i = startingLineIndex; i < offsets.length; i++) { 150 | const lineOffset = offsets[i + 1] 151 | 152 | if (lineOffset < start + length) { 153 | endingLineIndex = i + 1 154 | } else { 155 | break 156 | } 157 | } 158 | 159 | const endingColumn = start + length - offsets[endingLineIndex] 160 | 161 | return { 162 | start: { line: startingLineIndex, column: startingColumn }, 163 | end: { line: endingLineIndex, column: endingColumn }, 164 | } 165 | } 166 | 167 | export const nameOpCodes = (raw, hardfork = "london") => { 168 | const common = new Common({ chain: "mainnet", hardfork }) 169 | const opcodes = getOpcodesForHF(common) 170 | 171 | let pushData = "" 172 | const codeMap = {} 173 | const code = [] 174 | 175 | for (let i = 0; i < raw.length; i++) { 176 | const pc = i 177 | let curOpCode 178 | try { 179 | curOpCode = opcodes.get(raw[pc]).fullName 180 | } catch (e) { 181 | curOpCode = "INVALID" 182 | } 183 | codeMap[i] = code.length 184 | // no destinations into the middle of PUSH 185 | if (curOpCode.slice(0, 4) === "PUSH") { 186 | const jumpNum = raw[pc] - 0x5f 187 | pushData = raw.slice(pc + 1, pc + jumpNum + 1) 188 | i += jumpNum 189 | } 190 | 191 | const data = 192 | (pushData as any).toString("hex") !== "" 193 | ? " " + (pushData as any).toString("hex") 194 | : "" 195 | 196 | code.push(pad(pc, roundLog(raw.length, 10)) + " " + curOpCode + data) 197 | pushData = "" 198 | } 199 | return [code, codeMap] 200 | } 201 | 202 | export function pad(num, size) { 203 | let s = num + "" 204 | while (s.length < size) s = "0" + s 205 | return s 206 | } 207 | 208 | export function log(num, base) { 209 | return Math.log(num) / Math.log(base) 210 | } 211 | 212 | export function roundLog(num, base) { 213 | return Math.ceil(log(num, base)) 214 | } 215 | -------------------------------------------------------------------------------- /src/views/ErrorView.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | export const ErrorView: React.FC = () => { 4 | return ( 5 |
13 | Error page 19 |
Sorry, something unexpected happened.
20 |
21 | Please raise an issue:{" "} 22 | 26 | Here 27 | 28 |
29 |
30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /src/views/HomeView.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | export const HomeView: React.FC = () => { 4 | return ( 5 |
6 |
7 |
Description
8 |

9 | Visualise the control flow graph of Solidity source code and of the 10 | transaction execution 11 |

12 | 13 |
How to use?
14 |

15 | Compile or execute a transaction and open the control flow graph tab 16 |

17 | 18 |
Required plugins
19 |
    20 |
  • Debugger
  • 21 |
  • Solidity Compiler
  • 22 |
  • Deploy & run transactions
  • 23 |
24 | 25 |
Limitations
26 |
    27 |
  • Debug can only be performed in contracts within 1 file
  • 28 |
29 | 30 |
Links
31 | 47 | 48 |
Contact author
49 | 54 | Machina Labs Team 55 | 56 |
57 |
58 | ) 59 | } 60 | -------------------------------------------------------------------------------- /src/views/index.ts: -------------------------------------------------------------------------------- 1 | export { HomeView } from "./HomeView" 2 | export { ErrorView } from "./ErrorView" 3 | -------------------------------------------------------------------------------- /test/contract-util.test.ts: -------------------------------------------------------------------------------- 1 | import { CompilerVersion } from '@ethereum-react/types' 2 | import { getContractByteCode, getSolidityVersionFromData } from '../src/utils/contract-util' 3 | import { buildFakeCompilationResult, runtimeBytecode, bytecode } from './faker' 4 | 5 | describe("Contract utils test", () => { 6 | describe("getContractByteCode", () => { 7 | test('bytecode for contract creation', () => { 8 | const fakeCompilationResult = buildFakeCompilationResult() 9 | 10 | const result = getContractByteCode(fakeCompilationResult, true) 11 | 12 | expect(result.bytecode).toEqual(bytecode) 13 | }) 14 | 15 | test('bytecode for contract runtime', () => { 16 | const fakeCompilationResult = buildFakeCompilationResult() 17 | 18 | const result = getContractByteCode(fakeCompilationResult, false) 19 | 20 | expect(result.bytecode).toEqual(runtimeBytecode) 21 | }) 22 | }) 23 | 24 | describe("getSolidityVersionFromData", () => { 25 | test('solidity version 4', () => { 26 | const fakeCompilationResult = buildFakeCompilationResult(CompilerVersion.SOLIDITY_4) 27 | 28 | const result = getSolidityVersionFromData(fakeCompilationResult) 29 | 30 | expect(result).toEqual(CompilerVersion.SOLIDITY_4) 31 | }) 32 | 33 | test('solidity version 5', () => { 34 | const fakeCompilationResult = buildFakeCompilationResult(CompilerVersion.SOLIDITY_5) 35 | 36 | const result = getSolidityVersionFromData(fakeCompilationResult) 37 | 38 | expect(result).toEqual(CompilerVersion.SOLIDITY_5) 39 | }) 40 | 41 | test('solidity version 6', () => { 42 | const fakeCompilationResult = buildFakeCompilationResult(CompilerVersion.SOLIDITY_6) 43 | 44 | const result = getSolidityVersionFromData(fakeCompilationResult) 45 | 46 | expect(result).toEqual(CompilerVersion.SOLIDITY_6) 47 | }) 48 | }) 49 | }) -------------------------------------------------------------------------------- /test/faker.ts: -------------------------------------------------------------------------------- 1 | import { CompilerVersion } from "@ethereum-react/types" 2 | import { CompilationResult } from "@remixproject/plugin" 3 | 4 | export const bytecode = "608060405234801561001057600080fd5b5060c78061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d146037578063b05784b8146062575b600080fd5b606060048036036020811015604b57600080fd5b8101908080359060200190929190505050607e565b005b60686088565b6040518082815260200191505060405180910390f35b8060008190555050565b6000805490509056fea264697066735822122078fcdd186f07e48f2aee328c99bd40f9d5f25425a57536fb1cda58aaa09ecec264736f6c63430006010033" 5 | export const runtimeBytecode = "6080604052348015600f57600080fd5b506004361060325760003560e01c80636057361d146037578063b05784b8146062575b600080fd5b606060048036036020811015604b57600080fd5b8101908080359060200190929190505050607e565b005b60686088565b6040518082815260200191505060405180910390f35b8060008190555050565b6000805490509056fea264697066735822122078fcdd186f07e48f2aee328c99bd40f9d5f25425a57536fb1cda58aaa09ecec264736f6c63430006010033" 6 | 7 | export const buildFakeCompilationResult = (compilerVersion: CompilerVersion = CompilerVersion.SOLIDITY_4) => { 8 | const result = { 9 | "contracts": { 10 | "browser/1_Storage.sol": { 11 | "Storage": { 12 | "abi": [ 13 | { 14 | "inputs": [], 15 | "name": "retreive", 16 | "outputs": [ 17 | { 18 | "internalType": "uint256", 19 | "name": "", 20 | "type": "uint256" 21 | } 22 | ], 23 | "stateMutability": "view", 24 | "type": "function" 25 | }, 26 | { 27 | "inputs": [ 28 | { 29 | "internalType": "uint256", 30 | "name": "num", 31 | "type": "uint256" 32 | } 33 | ], 34 | "name": "store", 35 | "outputs": [], 36 | "stateMutability": "nonpayable", 37 | "type": "function" 38 | } 39 | ], 40 | "devdoc": { 41 | "details": "Store & retreive value in a variable", 42 | "methods": { 43 | "retreive()": { 44 | "details": "Return value ", 45 | "returns": { 46 | "_0": "value of 'number'" 47 | } 48 | }, 49 | "store(uint256)": { 50 | "details": "Store value in variable", 51 | "params": { 52 | "num": "value to store" 53 | } 54 | } 55 | }, 56 | "title": "Storage" 57 | }, 58 | "evm": { 59 | "bytecode": { 60 | "linkReferences": {}, 61 | "object": bytecode, 62 | "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0xC7 DUP1 PUSH2 0x1F PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH1 0x32 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x6057361D EQ PUSH1 0x37 JUMPI DUP1 PUSH4 0xB05784B8 EQ PUSH1 0x62 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x60 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH1 0x4B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH1 0x7E JUMP JUMPDEST STOP JUMPDEST PUSH1 0x68 PUSH1 0x88 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST DUP1 PUSH1 0x0 DUP2 SWAP1 SSTORE POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD SWAP1 POP SWAP1 JUMP INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 PUSH25 0xFCDD186F07E48F2AEE328C99BD40F9D5F25425A57536FB1CDA PC 0xAA LOG0 SWAP15 0xCE 0xC2 PUSH5 0x736F6C6343 STOP MOD ADD STOP CALLER ", 63 | "sourceMap": "105:356:0:-:0;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;105:356:0;;;;;;;" 64 | }, 65 | "deployedBytecode": { 66 | "linkReferences": {}, 67 | "object": runtimeBytecode, 68 | "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH1 0x32 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x6057361D EQ PUSH1 0x37 JUMPI DUP1 PUSH4 0xB05784B8 EQ PUSH1 0x62 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x60 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH1 0x4B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH1 0x7E JUMP JUMPDEST STOP JUMPDEST PUSH1 0x68 PUSH1 0x88 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST DUP1 PUSH1 0x0 DUP2 SWAP1 SSTORE POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD SWAP1 POP SWAP1 JUMP INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 PUSH25 0xFCDD186F07E48F2AEE328C99BD40F9D5F25425A57536FB1CDA PC 0xAA LOG0 SWAP15 0xCE 0xC2 PUSH5 0x736F6C6343 STOP MOD ADD STOP CALLER ", 69 | "sourceMap": "105:356:0:-:0;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;105:356:0;;;;;;;;;;;;;;;;;;;;;;;;235:64;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;235:64:0;;;;;;;;;;;;;;;;;:::i;:::-;;380:79;;;:::i;:::-;;;;;;;;;;;;;;;;;;;235:64;289:3;280:6;:12;;;;235:64;:::o;380:79::-;421:7;446:6;;439:13;;380:79;:::o" 70 | }, 71 | "gasEstimates": { 72 | "creation": { 73 | "codeDepositCost": "39800", 74 | "executionCost": "93", 75 | "totalCost": "39893" 76 | }, 77 | "external": { 78 | "retreive()": "1013", 79 | "store(uint256)": "20220" 80 | } 81 | }, 82 | "legacyAssembly": { 83 | ".code": [ 84 | { 85 | "begin": 105, 86 | "end": 461, 87 | "name": "PUSH", 88 | "value": "80" 89 | }, 90 | { 91 | "begin": 105, 92 | "end": 461, 93 | "name": "PUSH", 94 | "value": "40" 95 | }, 96 | { 97 | "begin": 105, 98 | "end": 461, 99 | "name": "MSTORE" 100 | }, 101 | { 102 | "begin": 105, 103 | "end": 461, 104 | "name": "CALLVALUE" 105 | }, 106 | { 107 | "begin": 8, 108 | "end": 17, 109 | "name": "DUP1" 110 | }, 111 | { 112 | "begin": 5, 113 | "end": 7, 114 | "name": "ISZERO" 115 | }, 116 | { 117 | "begin": 5, 118 | "end": 7, 119 | "name": "PUSH [tag]", 120 | "value": "1" 121 | }, 122 | { 123 | "begin": 5, 124 | "end": 7, 125 | "name": "JUMPI" 126 | }, 127 | { 128 | "begin": 30, 129 | "end": 31, 130 | "name": "PUSH", 131 | "value": "0" 132 | }, 133 | { 134 | "begin": 27, 135 | "end": 28, 136 | "name": "DUP1" 137 | }, 138 | { 139 | "begin": 20, 140 | "end": 32, 141 | "name": "REVERT" 142 | }, 143 | { 144 | "begin": 5, 145 | "end": 7, 146 | "name": "tag", 147 | "value": "1" 148 | }, 149 | { 150 | "begin": 5, 151 | "end": 7, 152 | "name": "JUMPDEST" 153 | }, 154 | { 155 | "begin": 105, 156 | "end": 461, 157 | "name": "POP" 158 | }, 159 | { 160 | "begin": 105, 161 | "end": 461, 162 | "name": "PUSH #[$]", 163 | "value": "0000000000000000000000000000000000000000000000000000000000000000" 164 | }, 165 | { 166 | "begin": 105, 167 | "end": 461, 168 | "name": "DUP1" 169 | }, 170 | { 171 | "begin": 105, 172 | "end": 461, 173 | "name": "PUSH [$]", 174 | "value": "0000000000000000000000000000000000000000000000000000000000000000" 175 | }, 176 | { 177 | "begin": 105, 178 | "end": 461, 179 | "name": "PUSH", 180 | "value": "0" 181 | }, 182 | { 183 | "begin": 105, 184 | "end": 461, 185 | "name": "CODECOPY" 186 | }, 187 | { 188 | "begin": 105, 189 | "end": 461, 190 | "name": "PUSH", 191 | "value": "0" 192 | }, 193 | { 194 | "begin": 105, 195 | "end": 461, 196 | "name": "RETURN" 197 | } 198 | ], 199 | ".data": { 200 | "0": { 201 | ".auxdata": "a264697066735822122078fcdd186f07e48f2aee328c99bd40f9d5f25425a57536fb1cda58aaa09ecec264736f6c63430006010033", 202 | ".code": [ 203 | { 204 | "begin": 105, 205 | "end": 461, 206 | "name": "PUSH", 207 | "value": "80" 208 | }, 209 | { 210 | "begin": 105, 211 | "end": 461, 212 | "name": "PUSH", 213 | "value": "40" 214 | }, 215 | { 216 | "begin": 105, 217 | "end": 461, 218 | "name": "MSTORE" 219 | }, 220 | { 221 | "begin": 105, 222 | "end": 461, 223 | "name": "CALLVALUE" 224 | }, 225 | { 226 | "begin": 8, 227 | "end": 17, 228 | "name": "DUP1" 229 | }, 230 | { 231 | "begin": 5, 232 | "end": 7, 233 | "name": "ISZERO" 234 | }, 235 | { 236 | "begin": 5, 237 | "end": 7, 238 | "name": "PUSH [tag]", 239 | "value": "1" 240 | }, 241 | { 242 | "begin": 5, 243 | "end": 7, 244 | "name": "JUMPI" 245 | }, 246 | { 247 | "begin": 30, 248 | "end": 31, 249 | "name": "PUSH", 250 | "value": "0" 251 | }, 252 | { 253 | "begin": 27, 254 | "end": 28, 255 | "name": "DUP1" 256 | }, 257 | { 258 | "begin": 20, 259 | "end": 32, 260 | "name": "REVERT" 261 | }, 262 | { 263 | "begin": 5, 264 | "end": 7, 265 | "name": "tag", 266 | "value": "1" 267 | }, 268 | { 269 | "begin": 5, 270 | "end": 7, 271 | "name": "JUMPDEST" 272 | }, 273 | { 274 | "begin": 105, 275 | "end": 461, 276 | "name": "POP" 277 | }, 278 | { 279 | "begin": 105, 280 | "end": 461, 281 | "name": "PUSH", 282 | "value": "4" 283 | }, 284 | { 285 | "begin": 105, 286 | "end": 461, 287 | "name": "CALLDATASIZE" 288 | }, 289 | { 290 | "begin": 105, 291 | "end": 461, 292 | "name": "LT" 293 | }, 294 | { 295 | "begin": 105, 296 | "end": 461, 297 | "name": "PUSH [tag]", 298 | "value": "2" 299 | }, 300 | { 301 | "begin": 105, 302 | "end": 461, 303 | "name": "JUMPI" 304 | }, 305 | { 306 | "begin": 105, 307 | "end": 461, 308 | "name": "PUSH", 309 | "value": "0" 310 | }, 311 | { 312 | "begin": 105, 313 | "end": 461, 314 | "name": "CALLDATALOAD" 315 | }, 316 | { 317 | "begin": 105, 318 | "end": 461, 319 | "name": "PUSH", 320 | "value": "E0" 321 | }, 322 | { 323 | "begin": 105, 324 | "end": 461, 325 | "name": "SHR" 326 | }, 327 | { 328 | "begin": 105, 329 | "end": 461, 330 | "name": "DUP1" 331 | }, 332 | { 333 | "begin": 105, 334 | "end": 461, 335 | "name": "PUSH", 336 | "value": "6057361D" 337 | }, 338 | { 339 | "begin": 105, 340 | "end": 461, 341 | "name": "EQ" 342 | }, 343 | { 344 | "begin": 105, 345 | "end": 461, 346 | "name": "PUSH [tag]", 347 | "value": "3" 348 | }, 349 | { 350 | "begin": 105, 351 | "end": 461, 352 | "name": "JUMPI" 353 | }, 354 | { 355 | "begin": 105, 356 | "end": 461, 357 | "name": "DUP1" 358 | }, 359 | { 360 | "begin": 105, 361 | "end": 461, 362 | "name": "PUSH", 363 | "value": "B05784B8" 364 | }, 365 | { 366 | "begin": 105, 367 | "end": 461, 368 | "name": "EQ" 369 | }, 370 | { 371 | "begin": 105, 372 | "end": 461, 373 | "name": "PUSH [tag]", 374 | "value": "4" 375 | }, 376 | { 377 | "begin": 105, 378 | "end": 461, 379 | "name": "JUMPI" 380 | }, 381 | { 382 | "begin": 105, 383 | "end": 461, 384 | "name": "tag", 385 | "value": "2" 386 | }, 387 | { 388 | "begin": 105, 389 | "end": 461, 390 | "name": "JUMPDEST" 391 | }, 392 | { 393 | "begin": 105, 394 | "end": 461, 395 | "name": "PUSH", 396 | "value": "0" 397 | }, 398 | { 399 | "begin": 105, 400 | "end": 461, 401 | "name": "DUP1" 402 | }, 403 | { 404 | "begin": 105, 405 | "end": 461, 406 | "name": "REVERT" 407 | }, 408 | { 409 | "begin": 235, 410 | "end": 299, 411 | "name": "tag", 412 | "value": "3" 413 | }, 414 | { 415 | "begin": 235, 416 | "end": 299, 417 | "name": "JUMPDEST" 418 | }, 419 | { 420 | "begin": 235, 421 | "end": 299, 422 | "name": "PUSH [tag]", 423 | "value": "5" 424 | }, 425 | { 426 | "begin": 235, 427 | "end": 299, 428 | "name": "PUSH", 429 | "value": "4" 430 | }, 431 | { 432 | "begin": 235, 433 | "end": 299, 434 | "name": "DUP1" 435 | }, 436 | { 437 | "begin": 235, 438 | "end": 299, 439 | "name": "CALLDATASIZE" 440 | }, 441 | { 442 | "begin": 235, 443 | "end": 299, 444 | "name": "SUB" 445 | }, 446 | { 447 | "begin": 13, 448 | "end": 15, 449 | "name": "PUSH", 450 | "value": "20" 451 | }, 452 | { 453 | "begin": 8, 454 | "end": 11, 455 | "name": "DUP2" 456 | }, 457 | { 458 | "begin": 5, 459 | "end": 16, 460 | "name": "LT" 461 | }, 462 | { 463 | "begin": 2, 464 | "end": 4, 465 | "name": "ISZERO" 466 | }, 467 | { 468 | "begin": 2, 469 | "end": 4, 470 | "name": "PUSH [tag]", 471 | "value": "6" 472 | }, 473 | { 474 | "begin": 2, 475 | "end": 4, 476 | "name": "JUMPI" 477 | }, 478 | { 479 | "begin": 29, 480 | "end": 30, 481 | "name": "PUSH", 482 | "value": "0" 483 | }, 484 | { 485 | "begin": 26, 486 | "end": 27, 487 | "name": "DUP1" 488 | }, 489 | { 490 | "begin": 19, 491 | "end": 31, 492 | "name": "REVERT" 493 | }, 494 | { 495 | "begin": 2, 496 | "end": 4, 497 | "name": "tag", 498 | "value": "6" 499 | }, 500 | { 501 | "begin": 2, 502 | "end": 4, 503 | "name": "JUMPDEST" 504 | }, 505 | { 506 | "begin": 235, 507 | "end": 299, 508 | "name": "DUP2" 509 | }, 510 | { 511 | "begin": 235, 512 | "end": 299, 513 | "name": "ADD" 514 | }, 515 | { 516 | "begin": 235, 517 | "end": 299, 518 | "name": "SWAP1" 519 | }, 520 | { 521 | "begin": 235, 522 | "end": 299, 523 | "name": "DUP1" 524 | }, 525 | { 526 | "begin": 235, 527 | "end": 299, 528 | "name": "DUP1" 529 | }, 530 | { 531 | "begin": 235, 532 | "end": 299, 533 | "name": "CALLDATALOAD" 534 | }, 535 | { 536 | "begin": 235, 537 | "end": 299, 538 | "name": "SWAP1" 539 | }, 540 | { 541 | "begin": 235, 542 | "end": 299, 543 | "name": "PUSH", 544 | "value": "20" 545 | }, 546 | { 547 | "begin": 235, 548 | "end": 299, 549 | "name": "ADD" 550 | }, 551 | { 552 | "begin": 235, 553 | "end": 299, 554 | "name": "SWAP1" 555 | }, 556 | { 557 | "begin": 235, 558 | "end": 299, 559 | "name": "SWAP3" 560 | }, 561 | { 562 | "begin": 235, 563 | "end": 299, 564 | "name": "SWAP2" 565 | }, 566 | { 567 | "begin": 235, 568 | "end": 299, 569 | "name": "SWAP1" 570 | }, 571 | { 572 | "begin": 235, 573 | "end": 299, 574 | "name": "POP" 575 | }, 576 | { 577 | "begin": 235, 578 | "end": 299, 579 | "name": "POP" 580 | }, 581 | { 582 | "begin": 235, 583 | "end": 299, 584 | "name": "POP" 585 | }, 586 | { 587 | "begin": 235, 588 | "end": 299, 589 | "name": "PUSH [tag]", 590 | "value": "7" 591 | }, 592 | { 593 | "begin": 235, 594 | "end": 299, 595 | "name": "JUMP", 596 | "value": "[in]" 597 | }, 598 | { 599 | "begin": 235, 600 | "end": 299, 601 | "name": "tag", 602 | "value": "5" 603 | }, 604 | { 605 | "begin": 235, 606 | "end": 299, 607 | "name": "JUMPDEST" 608 | }, 609 | { 610 | "begin": 235, 611 | "end": 299, 612 | "name": "STOP" 613 | }, 614 | { 615 | "begin": 380, 616 | "end": 459, 617 | "name": "tag", 618 | "value": "4" 619 | }, 620 | { 621 | "begin": 380, 622 | "end": 459, 623 | "name": "JUMPDEST" 624 | }, 625 | { 626 | "begin": 380, 627 | "end": 459, 628 | "name": "PUSH [tag]", 629 | "value": "8" 630 | }, 631 | { 632 | "begin": 380, 633 | "end": 459, 634 | "name": "PUSH [tag]", 635 | "value": "9" 636 | }, 637 | { 638 | "begin": 380, 639 | "end": 459, 640 | "name": "JUMP", 641 | "value": "[in]" 642 | }, 643 | { 644 | "begin": 380, 645 | "end": 459, 646 | "name": "tag", 647 | "value": "8" 648 | }, 649 | { 650 | "begin": 380, 651 | "end": 459, 652 | "name": "JUMPDEST" 653 | }, 654 | { 655 | "begin": 380, 656 | "end": 459, 657 | "name": "PUSH", 658 | "value": "40" 659 | }, 660 | { 661 | "begin": 380, 662 | "end": 459, 663 | "name": "MLOAD" 664 | }, 665 | { 666 | "begin": 380, 667 | "end": 459, 668 | "name": "DUP1" 669 | }, 670 | { 671 | "begin": 380, 672 | "end": 459, 673 | "name": "DUP3" 674 | }, 675 | { 676 | "begin": 380, 677 | "end": 459, 678 | "name": "DUP2" 679 | }, 680 | { 681 | "begin": 380, 682 | "end": 459, 683 | "name": "MSTORE" 684 | }, 685 | { 686 | "begin": 380, 687 | "end": 459, 688 | "name": "PUSH", 689 | "value": "20" 690 | }, 691 | { 692 | "begin": 380, 693 | "end": 459, 694 | "name": "ADD" 695 | }, 696 | { 697 | "begin": 380, 698 | "end": 459, 699 | "name": "SWAP2" 700 | }, 701 | { 702 | "begin": 380, 703 | "end": 459, 704 | "name": "POP" 705 | }, 706 | { 707 | "begin": 380, 708 | "end": 459, 709 | "name": "POP" 710 | }, 711 | { 712 | "begin": 380, 713 | "end": 459, 714 | "name": "PUSH", 715 | "value": "40" 716 | }, 717 | { 718 | "begin": 380, 719 | "end": 459, 720 | "name": "MLOAD" 721 | }, 722 | { 723 | "begin": 380, 724 | "end": 459, 725 | "name": "DUP1" 726 | }, 727 | { 728 | "begin": 380, 729 | "end": 459, 730 | "name": "SWAP2" 731 | }, 732 | { 733 | "begin": 380, 734 | "end": 459, 735 | "name": "SUB" 736 | }, 737 | { 738 | "begin": 380, 739 | "end": 459, 740 | "name": "SWAP1" 741 | }, 742 | { 743 | "begin": 380, 744 | "end": 459, 745 | "name": "RETURN" 746 | }, 747 | { 748 | "begin": 235, 749 | "end": 299, 750 | "name": "tag", 751 | "value": "7" 752 | }, 753 | { 754 | "begin": 235, 755 | "end": 299, 756 | "name": "JUMPDEST" 757 | }, 758 | { 759 | "begin": 289, 760 | "end": 292, 761 | "name": "DUP1" 762 | }, 763 | { 764 | "begin": 280, 765 | "end": 286, 766 | "name": "PUSH", 767 | "value": "0" 768 | }, 769 | { 770 | "begin": 280, 771 | "end": 292, 772 | "name": "DUP2" 773 | }, 774 | { 775 | "begin": 280, 776 | "end": 292, 777 | "name": "SWAP1" 778 | }, 779 | { 780 | "begin": 280, 781 | "end": 292, 782 | "name": "SSTORE" 783 | }, 784 | { 785 | "begin": 280, 786 | "end": 292, 787 | "name": "POP" 788 | }, 789 | { 790 | "begin": 235, 791 | "end": 299, 792 | "name": "POP" 793 | }, 794 | { 795 | "begin": 235, 796 | "end": 299, 797 | "name": "JUMP", 798 | "value": "[out]" 799 | }, 800 | { 801 | "begin": 380, 802 | "end": 459, 803 | "name": "tag", 804 | "value": "9" 805 | }, 806 | { 807 | "begin": 380, 808 | "end": 459, 809 | "name": "JUMPDEST" 810 | }, 811 | { 812 | "begin": 421, 813 | "end": 428, 814 | "name": "PUSH", 815 | "value": "0" 816 | }, 817 | { 818 | "begin": 446, 819 | "end": 452, 820 | "name": "DUP1" 821 | }, 822 | { 823 | "begin": 446, 824 | "end": 452, 825 | "name": "SLOAD" 826 | }, 827 | { 828 | "begin": 439, 829 | "end": 452, 830 | "name": "SWAP1" 831 | }, 832 | { 833 | "begin": 439, 834 | "end": 452, 835 | "name": "POP" 836 | }, 837 | { 838 | "begin": 380, 839 | "end": 459, 840 | "name": "SWAP1" 841 | }, 842 | { 843 | "begin": 380, 844 | "end": 459, 845 | "name": "JUMP", 846 | "value": "[out]" 847 | } 848 | ] 849 | } 850 | } 851 | }, 852 | "methodIdentifiers": { 853 | "retreive()": "b05784b8", 854 | "store(uint256)": "6057361d" 855 | } 856 | }, 857 | "metadata": getMetadataFor(compilerVersion), 858 | "userdoc": { 859 | "methods": {} 860 | } 861 | } 862 | } 863 | }, 864 | "sources": { 865 | "browser/1_Storage.sol": { 866 | "ast": { 867 | "absolutePath": "browser/1_Storage.sol", 868 | "exportedSymbols": { 869 | "Storage": [ 870 | 22 871 | ] 872 | }, 873 | "id": 23, 874 | "nodeType": "SourceUnit", 875 | "nodes": [ 876 | { 877 | "id": 1, 878 | "literals": [ 879 | "solidity", 880 | ">=", 881 | "0.4", 882 | ".22", 883 | "<", 884 | "0.7", 885 | ".0" 886 | ], 887 | "nodeType": "PragmaDirective", 888 | "src": "0:32:0" 889 | }, 890 | { 891 | "abstract": false, 892 | "baseContracts": [], 893 | "contractDependencies": [], 894 | "contractKind": "contract", 895 | "documentation": "@title Storage\n@dev Store & retreive value in a variable", 896 | "fullyImplemented": true, 897 | "id": 22, 898 | "linearizedBaseContracts": [ 899 | 22 900 | ], 901 | "name": "Storage", 902 | "nodeType": "ContractDefinition", 903 | "nodes": [ 904 | { 905 | "constant": false, 906 | "id": 3, 907 | "name": "number", 908 | "nodeType": "VariableDeclaration", 909 | "overrides": null, 910 | "scope": 22, 911 | "src": "129:14:0", 912 | "stateVariable": true, 913 | "storageLocation": "default", 914 | "typeDescriptions": { 915 | "typeIdentifier": "t_uint256", 916 | "typeString": "uint256" 917 | }, 918 | "typeName": { 919 | "id": 2, 920 | "name": "uint256", 921 | "nodeType": "ElementaryTypeName", 922 | "src": "129:7:0", 923 | "typeDescriptions": { 924 | "typeIdentifier": "t_uint256", 925 | "typeString": "uint256" 926 | } 927 | }, 928 | "value": null, 929 | "visibility": "internal" 930 | }, 931 | { 932 | "body": { 933 | "id": 12, 934 | "nodeType": "Block", 935 | "src": "270:29:0", 936 | "statements": [ 937 | { 938 | "expression": { 939 | "argumentTypes": null, 940 | "id": 10, 941 | "isConstant": false, 942 | "isLValue": false, 943 | "isPure": false, 944 | "lValueRequested": false, 945 | "leftHandSide": { 946 | "argumentTypes": null, 947 | "id": 8, 948 | "name": "number", 949 | "nodeType": "Identifier", 950 | "overloadedDeclarations": [], 951 | "referencedDeclaration": 3, 952 | "src": "280:6:0", 953 | "typeDescriptions": { 954 | "typeIdentifier": "t_uint256", 955 | "typeString": "uint256" 956 | } 957 | }, 958 | "nodeType": "Assignment", 959 | "operator": "=", 960 | "rightHandSide": { 961 | "argumentTypes": null, 962 | "id": 9, 963 | "name": "num", 964 | "nodeType": "Identifier", 965 | "overloadedDeclarations": [], 966 | "referencedDeclaration": 5, 967 | "src": "289:3:0", 968 | "typeDescriptions": { 969 | "typeIdentifier": "t_uint256", 970 | "typeString": "uint256" 971 | } 972 | }, 973 | "src": "280:12:0", 974 | "typeDescriptions": { 975 | "typeIdentifier": "t_uint256", 976 | "typeString": "uint256" 977 | } 978 | }, 979 | "id": 11, 980 | "nodeType": "ExpressionStatement", 981 | "src": "280:12:0" 982 | } 983 | ] 984 | }, 985 | "documentation": "@dev Store value in variable\n@param num value to store", 986 | "functionSelector": "6057361d", 987 | "id": 13, 988 | "implemented": true, 989 | "kind": "function", 990 | "modifiers": [], 991 | "name": "store", 992 | "nodeType": "FunctionDefinition", 993 | "overrides": null, 994 | "parameters": { 995 | "id": 6, 996 | "nodeType": "ParameterList", 997 | "parameters": [ 998 | { 999 | "constant": false, 1000 | "id": 5, 1001 | "name": "num", 1002 | "nodeType": "VariableDeclaration", 1003 | "overrides": null, 1004 | "scope": 13, 1005 | "src": "250:11:0", 1006 | "stateVariable": false, 1007 | "storageLocation": "default", 1008 | "typeDescriptions": { 1009 | "typeIdentifier": "t_uint256", 1010 | "typeString": "uint256" 1011 | }, 1012 | "typeName": { 1013 | "id": 4, 1014 | "name": "uint256", 1015 | "nodeType": "ElementaryTypeName", 1016 | "src": "250:7:0", 1017 | "typeDescriptions": { 1018 | "typeIdentifier": "t_uint256", 1019 | "typeString": "uint256" 1020 | } 1021 | }, 1022 | "value": null, 1023 | "visibility": "internal" 1024 | } 1025 | ], 1026 | "src": "249:13:0" 1027 | }, 1028 | "returnParameters": { 1029 | "id": 7, 1030 | "nodeType": "ParameterList", 1031 | "parameters": [], 1032 | "src": "270:0:0" 1033 | }, 1034 | "scope": 22, 1035 | "src": "235:64:0", 1036 | "stateMutability": "nonpayable", 1037 | "virtual": false, 1038 | "visibility": "public" 1039 | }, 1040 | { 1041 | "body": { 1042 | "id": 20, 1043 | "nodeType": "Block", 1044 | "src": "429:30:0", 1045 | "statements": [ 1046 | { 1047 | "expression": { 1048 | "argumentTypes": null, 1049 | "id": 18, 1050 | "name": "number", 1051 | "nodeType": "Identifier", 1052 | "overloadedDeclarations": [], 1053 | "referencedDeclaration": 3, 1054 | "src": "446:6:0", 1055 | "typeDescriptions": { 1056 | "typeIdentifier": "t_uint256", 1057 | "typeString": "uint256" 1058 | } 1059 | }, 1060 | "functionReturnParameters": 17, 1061 | "id": 19, 1062 | "nodeType": "Return", 1063 | "src": "439:13:0" 1064 | } 1065 | ] 1066 | }, 1067 | "documentation": "@dev Return value \n@return value of 'number'", 1068 | "functionSelector": "b05784b8", 1069 | "id": 21, 1070 | "implemented": true, 1071 | "kind": "function", 1072 | "modifiers": [], 1073 | "name": "retreive", 1074 | "nodeType": "FunctionDefinition", 1075 | "overrides": null, 1076 | "parameters": { 1077 | "id": 14, 1078 | "nodeType": "ParameterList", 1079 | "parameters": [], 1080 | "src": "397:2:0" 1081 | }, 1082 | "returnParameters": { 1083 | "id": 17, 1084 | "nodeType": "ParameterList", 1085 | "parameters": [ 1086 | { 1087 | "constant": false, 1088 | "id": 16, 1089 | "name": "", 1090 | "nodeType": "VariableDeclaration", 1091 | "overrides": null, 1092 | "scope": 21, 1093 | "src": "421:7:0", 1094 | "stateVariable": false, 1095 | "storageLocation": "default", 1096 | "typeDescriptions": { 1097 | "typeIdentifier": "t_uint256", 1098 | "typeString": "uint256" 1099 | }, 1100 | "typeName": { 1101 | "id": 15, 1102 | "name": "uint256", 1103 | "nodeType": "ElementaryTypeName", 1104 | "src": "421:7:0", 1105 | "typeDescriptions": { 1106 | "typeIdentifier": "t_uint256", 1107 | "typeString": "uint256" 1108 | } 1109 | }, 1110 | "value": null, 1111 | "visibility": "internal" 1112 | } 1113 | ], 1114 | "src": "420:9:0" 1115 | }, 1116 | "scope": 22, 1117 | "src": "380:79:0", 1118 | "stateMutability": "view", 1119 | "virtual": false, 1120 | "visibility": "public" 1121 | } 1122 | ], 1123 | "scope": 23, 1124 | "src": "105:356:0" 1125 | } 1126 | ], 1127 | "src": "0:461:0" 1128 | }, 1129 | "id": 0, 1130 | "legacyAST": { 1131 | "attributes": { 1132 | "absolutePath": "browser/1_Storage.sol", 1133 | "exportedSymbols": { 1134 | "Storage": [ 1135 | 22 1136 | ] 1137 | } 1138 | }, 1139 | "children": [ 1140 | { 1141 | "attributes": { 1142 | "literals": [ 1143 | "solidity", 1144 | ">=", 1145 | "0.4", 1146 | ".22", 1147 | "<", 1148 | "0.7", 1149 | ".0" 1150 | ] 1151 | }, 1152 | "id": 1, 1153 | "name": "PragmaDirective", 1154 | "src": "0:32:0" 1155 | }, 1156 | { 1157 | "attributes": { 1158 | "abstract": false, 1159 | "baseContracts": [ 1160 | null 1161 | ], 1162 | "contractDependencies": [ 1163 | null 1164 | ], 1165 | "contractKind": "contract", 1166 | "documentation": "@title Storage\n@dev Store & retreive value in a variable", 1167 | "fullyImplemented": true, 1168 | "linearizedBaseContracts": [ 1169 | 22 1170 | ], 1171 | "name": "Storage", 1172 | "scope": 23 1173 | }, 1174 | "children": [ 1175 | { 1176 | "attributes": { 1177 | "constant": false, 1178 | "name": "number", 1179 | "overrides": null, 1180 | "scope": 22, 1181 | "stateVariable": true, 1182 | "storageLocation": "default", 1183 | "type": "uint256", 1184 | "value": null, 1185 | "visibility": "internal" 1186 | }, 1187 | "children": [ 1188 | { 1189 | "attributes": { 1190 | "name": "uint256", 1191 | "type": "uint256" 1192 | }, 1193 | "id": 2, 1194 | "name": "ElementaryTypeName", 1195 | "src": "129:7:0" 1196 | } 1197 | ], 1198 | "id": 3, 1199 | "name": "VariableDeclaration", 1200 | "src": "129:14:0" 1201 | }, 1202 | { 1203 | "attributes": { 1204 | "documentation": "@dev Store value in variable\n@param num value to store", 1205 | "functionSelector": "6057361d", 1206 | "implemented": true, 1207 | "isConstructor": false, 1208 | "kind": "function", 1209 | "modifiers": [ 1210 | null 1211 | ], 1212 | "name": "store", 1213 | "overrides": null, 1214 | "scope": 22, 1215 | "stateMutability": "nonpayable", 1216 | "virtual": false, 1217 | "visibility": "public" 1218 | }, 1219 | "children": [ 1220 | { 1221 | "children": [ 1222 | { 1223 | "attributes": { 1224 | "constant": false, 1225 | "name": "num", 1226 | "overrides": null, 1227 | "scope": 13, 1228 | "stateVariable": false, 1229 | "storageLocation": "default", 1230 | "type": "uint256", 1231 | "value": null, 1232 | "visibility": "internal" 1233 | }, 1234 | "children": [ 1235 | { 1236 | "attributes": { 1237 | "name": "uint256", 1238 | "type": "uint256" 1239 | }, 1240 | "id": 4, 1241 | "name": "ElementaryTypeName", 1242 | "src": "250:7:0" 1243 | } 1244 | ], 1245 | "id": 5, 1246 | "name": "VariableDeclaration", 1247 | "src": "250:11:0" 1248 | } 1249 | ], 1250 | "id": 6, 1251 | "name": "ParameterList", 1252 | "src": "249:13:0" 1253 | }, 1254 | { 1255 | "attributes": { 1256 | "parameters": [ 1257 | null 1258 | ] 1259 | }, 1260 | "children": [], 1261 | "id": 7, 1262 | "name": "ParameterList", 1263 | "src": "270:0:0" 1264 | }, 1265 | { 1266 | "children": [ 1267 | { 1268 | "children": [ 1269 | { 1270 | "attributes": { 1271 | "argumentTypes": null, 1272 | "isConstant": false, 1273 | "isLValue": false, 1274 | "isPure": false, 1275 | "lValueRequested": false, 1276 | "operator": "=", 1277 | "type": "uint256" 1278 | }, 1279 | "children": [ 1280 | { 1281 | "attributes": { 1282 | "argumentTypes": null, 1283 | "overloadedDeclarations": [ 1284 | null 1285 | ], 1286 | "referencedDeclaration": 3, 1287 | "type": "uint256", 1288 | "value": "number" 1289 | }, 1290 | "id": 8, 1291 | "name": "Identifier", 1292 | "src": "280:6:0" 1293 | }, 1294 | { 1295 | "attributes": { 1296 | "argumentTypes": null, 1297 | "overloadedDeclarations": [ 1298 | null 1299 | ], 1300 | "referencedDeclaration": 5, 1301 | "type": "uint256", 1302 | "value": "num" 1303 | }, 1304 | "id": 9, 1305 | "name": "Identifier", 1306 | "src": "289:3:0" 1307 | } 1308 | ], 1309 | "id": 10, 1310 | "name": "Assignment", 1311 | "src": "280:12:0" 1312 | } 1313 | ], 1314 | "id": 11, 1315 | "name": "ExpressionStatement", 1316 | "src": "280:12:0" 1317 | } 1318 | ], 1319 | "id": 12, 1320 | "name": "Block", 1321 | "src": "270:29:0" 1322 | } 1323 | ], 1324 | "id": 13, 1325 | "name": "FunctionDefinition", 1326 | "src": "235:64:0" 1327 | }, 1328 | { 1329 | "attributes": { 1330 | "documentation": "@dev Return value \n@return value of 'number'", 1331 | "functionSelector": "b05784b8", 1332 | "implemented": true, 1333 | "isConstructor": false, 1334 | "kind": "function", 1335 | "modifiers": [ 1336 | null 1337 | ], 1338 | "name": "retreive", 1339 | "overrides": null, 1340 | "scope": 22, 1341 | "stateMutability": "view", 1342 | "virtual": false, 1343 | "visibility": "public" 1344 | }, 1345 | "children": [ 1346 | { 1347 | "attributes": { 1348 | "parameters": [ 1349 | null 1350 | ] 1351 | }, 1352 | "children": [], 1353 | "id": 14, 1354 | "name": "ParameterList", 1355 | "src": "397:2:0" 1356 | }, 1357 | { 1358 | "children": [ 1359 | { 1360 | "attributes": { 1361 | "constant": false, 1362 | "name": "", 1363 | "overrides": null, 1364 | "scope": 21, 1365 | "stateVariable": false, 1366 | "storageLocation": "default", 1367 | "type": "uint256", 1368 | "value": null, 1369 | "visibility": "internal" 1370 | }, 1371 | "children": [ 1372 | { 1373 | "attributes": { 1374 | "name": "uint256", 1375 | "type": "uint256" 1376 | }, 1377 | "id": 15, 1378 | "name": "ElementaryTypeName", 1379 | "src": "421:7:0" 1380 | } 1381 | ], 1382 | "id": 16, 1383 | "name": "VariableDeclaration", 1384 | "src": "421:7:0" 1385 | } 1386 | ], 1387 | "id": 17, 1388 | "name": "ParameterList", 1389 | "src": "420:9:0" 1390 | }, 1391 | { 1392 | "children": [ 1393 | { 1394 | "attributes": { 1395 | "functionReturnParameters": 17 1396 | }, 1397 | "children": [ 1398 | { 1399 | "attributes": { 1400 | "argumentTypes": null, 1401 | "overloadedDeclarations": [ 1402 | null 1403 | ], 1404 | "referencedDeclaration": 3, 1405 | "type": "uint256", 1406 | "value": "number" 1407 | }, 1408 | "id": 18, 1409 | "name": "Identifier", 1410 | "src": "446:6:0" 1411 | } 1412 | ], 1413 | "id": 19, 1414 | "name": "Return", 1415 | "src": "439:13:0" 1416 | } 1417 | ], 1418 | "id": 20, 1419 | "name": "Block", 1420 | "src": "429:30:0" 1421 | } 1422 | ], 1423 | "id": 21, 1424 | "name": "FunctionDefinition", 1425 | "src": "380:79:0" 1426 | } 1427 | ], 1428 | "id": 22, 1429 | "name": "ContractDefinition", 1430 | "src": "105:356:0" 1431 | } 1432 | ], 1433 | "id": 23, 1434 | "name": "SourceUnit", 1435 | "src": "0:461:0" 1436 | } 1437 | } 1438 | } 1439 | } as any 1440 | return result as CompilationResult 1441 | } 1442 | 1443 | const getMetadataFor = (version: CompilerVersion) => { 1444 | switch (version) { 1445 | case CompilerVersion.SOLIDITY_4: 1446 | return "{\"compiler\":{\"version\":\"0.4.26+commit.e6f7d5a4\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"retreive\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"num\",\"type\":\"uint256\"}],\"name\":\"store\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Store & retreive value in a variable\",\"methods\":{\"retreive()\":{\"details\":\"Return value \",\"returns\":{\"_0\":\"value of 'number'\"}},\"store(uint256)\":{\"details\":\"Store value in variable\",\"params\":{\"num\":\"value to store\"}}},\"title\":\"Storage\"},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"browser/1_Storage.sol\":\"Storage\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"browser/1_Storage.sol\":{\"keccak256\":\"0xaedc7086ad8503907209f50bac1e4dc6c2eca2ed41b15d03740fea748ea3f88e\",\"urls\":[\"bzz-raw://4bc331951c25951321cb29abbd689eb3af669530222c6bb2d45ff45334ee83a7\",\"dweb:/ipfs/QmWb1NQ6Pw8ZLMFX8uDjMyftgcEieT9iP2TvWisPhjN3U2\"]}},\"version\":1}" 1447 | case CompilerVersion.SOLIDITY_5: 1448 | return "{\"compiler\":{\"version\":\"0.5.1+commit.e6f7d5a4\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"retreive\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"num\",\"type\":\"uint256\"}],\"name\":\"store\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Store & retreive value in a variable\",\"methods\":{\"retreive()\":{\"details\":\"Return value \",\"returns\":{\"_0\":\"value of 'number'\"}},\"store(uint256)\":{\"details\":\"Store value in variable\",\"params\":{\"num\":\"value to store\"}}},\"title\":\"Storage\"},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"browser/1_Storage.sol\":\"Storage\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"browser/1_Storage.sol\":{\"keccak256\":\"0xaedc7086ad8503907209f50bac1e4dc6c2eca2ed41b15d03740fea748ea3f88e\",\"urls\":[\"bzz-raw://4bc331951c25951321cb29abbd689eb3af669530222c6bb2d45ff45334ee83a7\",\"dweb:/ipfs/QmWb1NQ6Pw8ZLMFX8uDjMyftgcEieT9iP2TvWisPhjN3U2\"]}},\"version\":1}" 1449 | case CompilerVersion.SOLIDITY_6: 1450 | return "{\"compiler\":{\"version\":\"0.6.1+commit.e6f7d5a4\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"retreive\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"num\",\"type\":\"uint256\"}],\"name\":\"store\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Store & retreive value in a variable\",\"methods\":{\"retreive()\":{\"details\":\"Return value \",\"returns\":{\"_0\":\"value of 'number'\"}},\"store(uint256)\":{\"details\":\"Store value in variable\",\"params\":{\"num\":\"value to store\"}}},\"title\":\"Storage\"},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"browser/1_Storage.sol\":\"Storage\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"browser/1_Storage.sol\":{\"keccak256\":\"0xaedc7086ad8503907209f50bac1e4dc6c2eca2ed41b15d03740fea748ea3f88e\",\"urls\":[\"bzz-raw://4bc331951c25951321cb29abbd689eb3af669530222c6bb2d45ff45334ee83a7\",\"dweb:/ipfs/QmWb1NQ6Pw8ZLMFX8uDjMyftgcEieT9iP2TvWisPhjN3U2\"]}},\"version\":1}" 1451 | } 1452 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 5 | "rootDir": "src", 6 | "moduleResolution": "node", 7 | "allowSyntheticDefaultImports": true, 8 | "esModuleInterop": true, 9 | "jsx": "react" 10 | }, 11 | "include": [ 12 | "src" 13 | ] 14 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "tslint:recommended", 4 | "tslint-config-prettier" 5 | ], 6 | "rules": { 7 | "no-unused-variable": false, 8 | "no-shadowed-variable": false, 9 | "interface-name": false, 10 | "member-access": false, 11 | "cyclomatic-complexity": [ 12 | true, 13 | 10 14 | ], 15 | "object-literal-sort-keys": [ 16 | false 17 | ], 18 | "no-console": [ 19 | false 20 | ], 21 | "no-implicit-dependencies": false, 22 | "ordered-imports": [ 23 | false, 24 | { 25 | "grouped-imports": true, 26 | "named-imports-order": "any" 27 | } 28 | ], 29 | "jsx-no-lambda": false 30 | }, 31 | "linterOptions": { 32 | "exclude": [ 33 | "node_modules/**/*.ts", 34 | "coverage/**/*.js", 35 | "src/**/*.json" 36 | ] 37 | } 38 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 2 | const path = require('path'); 3 | 4 | module.exports = { 5 | entry: './src/index.tsx', 6 | devtool: "source-map", 7 | resolve: { 8 | extensions: ['.ts', '.tsx', '.js'] 9 | }, 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.min.js' 13 | }, 14 | module: { 15 | rules: [ 16 | { 17 | test: /\.ts(x?)$/, 18 | exclude: /node_modules/, 19 | use: 'awesome-typescript-loader' 20 | }, 21 | { 22 | enforce: "pre", 23 | test: /\.js$/, 24 | loader: "source-map-loader" 25 | }, 26 | { 27 | test: /\.css$/i, 28 | use: ['style-loader', 'css-loader'], 29 | } 30 | ] 31 | }, 32 | devServer: { 33 | static: { 34 | directory: path.join(__dirname, 'dist'), 35 | }, 36 | port: 8000 37 | }, 38 | plugins: [ 39 | new HtmlWebpackPlugin({ template: './public/index.html' }) 40 | ] 41 | } -------------------------------------------------------------------------------- /webpack.config.production.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 2 | const path = require('path'); 3 | 4 | module.exports = { 5 | entry: './src/index.tsx', 6 | mode: 'production', 7 | resolve: { 8 | extensions: ['.ts', '.tsx', '.js'] 9 | }, 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.min.js' 13 | }, 14 | module: { 15 | rules: [ 16 | { 17 | test: /\.ts(x?)$/, 18 | exclude: /node_modules/, 19 | use: 'awesome-typescript-loader' 20 | }, 21 | { 22 | test: /\.css$/i, 23 | use: ['style-loader', 'css-loader'], 24 | } 25 | ] 26 | }, 27 | plugins: [ 28 | new HtmlWebpackPlugin({ template: './public/index.html' }) 29 | ] 30 | } --------------------------------------------------------------------------------