bytecode-debugger
Advanced tools
Comparing version 0.1.8 to 0.1.9
{ | ||
"name": "bytecode-debugger", | ||
"version": "0.1.8", | ||
"version": "0.1.9", | ||
"main": "scripts/bytecode-debugger.ts", | ||
@@ -21,2 +21,3 @@ "bin": { | ||
"@types/lodash": "^4.14.172", | ||
"@types/prompts": "^2.0.14", | ||
"@types/table": "^6.3.2", | ||
@@ -26,3 +27,2 @@ "@types/yargs": "^17.0.2", | ||
"cli-table": "^0.3.6", | ||
"enquirer": "^2.3.6", | ||
"ethereumjs-util": "^7.1.0", | ||
@@ -35,2 +35,3 @@ "ethers": "^5.4.5", | ||
"prettier": "^2.3.2", | ||
"prompts": "^2.4.1", | ||
"ts-node": "^10.2.1", | ||
@@ -37,0 +38,0 @@ "typescript": "^4.3.5", |
@@ -1,3 +0,7 @@ | ||
# Quick Start | ||
# EVM Bytecode Debugger | ||
This utility allows you to take bytecode and abi output from `solc` and step through the byte code. | ||
## Quick Start | ||
```shell | ||
@@ -4,0 +8,0 @@ # Download the sample contract from github |
#!/usr/bin/env -S npx ts-node | ||
import { BN } from "ethereumjs-util"; | ||
import { OpcodeList } from "@ethereumjs/vm/dist/evm/opcodes"; | ||
@@ -17,8 +16,9 @@ import yargs from "yargs"; | ||
formatBuffer, | ||
addHexPrefix, | ||
} from "../src/utils"; | ||
import { prompt } from "enquirer"; | ||
// import { prompt } from "enquirer"; | ||
import fs from "fs"; | ||
import { utils } from "ethers"; | ||
import { utils, BigNumber } from "ethers"; | ||
import jsonfile from "jsonfile"; | ||
import prompts from "prompts"; | ||
debugBytecode(); | ||
@@ -47,5 +47,8 @@ | ||
const abi = new utils.Interface(abiFile); | ||
const choices = Object.keys(abi.functions); | ||
const choices = Object.keys(abi.functions).map((k) => ({ | ||
value: k, | ||
title: k, | ||
})); | ||
const { functionToCall } = (await prompt({ | ||
const { functionToCall } = await prompts({ | ||
type: "select", | ||
@@ -55,16 +58,7 @@ name: "functionToCall", | ||
message: "Which function do you want to call?'", | ||
})) as { functionToCall: string }; | ||
}); | ||
let inputValues = []; | ||
for (const input of abi.functions[functionToCall].inputs) { | ||
if (input.baseType === "array" || input.baseType === "tuple") { | ||
throw new Error(`Sorry, currently we don't support complex parameters`); | ||
} | ||
const { inputValue } = (await prompt({ | ||
type: "numeral", | ||
name: "inputValue", | ||
message: `Enter a value for argument ${input.name}`, | ||
})) as { inputValue: number }; | ||
inputValues.push(inputValue); | ||
inputValues.push(await getInputValue(input, input.name)); | ||
} | ||
@@ -76,7 +70,7 @@ const callData = abi.encodeFunctionData( | ||
const { callValue } = (await prompt({ | ||
type: "numeral", | ||
const { callValue } = await prompts({ | ||
type: "number", | ||
name: "callValue", | ||
message: `Enter the amount of wei to be sent to the function.`, | ||
})) as { callValue: number }; | ||
}); | ||
@@ -90,3 +84,3 @@ const code = Buffer.from( | ||
Buffer.from(callData.slice(2), "hex"), | ||
new BN(callValue), | ||
BigNumber.from(callValue), | ||
abi.functions[functionToCall] | ||
@@ -96,6 +90,97 @@ ); | ||
async function getInputValue( | ||
input: utils.ParamType, | ||
argumentName: string | ||
): Promise<any> { | ||
if (input.baseType === "tuple") { | ||
const tuple = []; | ||
for (const component of input.components) { | ||
tuple.push(await getInputValue(component, component.name)); | ||
} | ||
return tuple; | ||
} | ||
if (input.baseType === "array") { | ||
let { keepGoing } = await prompts({ | ||
type: "confirm", | ||
name: "keepGoing", | ||
message: `Add an item to the argument array for ${argumentName}`, | ||
}); | ||
const arrayValues = []; | ||
while (keepGoing) { | ||
arrayValues.push(await getInputValue(input.arrayChildren, "array")); | ||
keepGoing = ( | ||
await prompts({ | ||
type: "confirm", | ||
name: "keepGoing", | ||
message: `Add an item to the argument array for ${argumentName}`, | ||
}) | ||
).keepGoing; | ||
} | ||
return arrayValues; | ||
} | ||
if (input.baseType === "address") { | ||
const { inputValue } = await prompts({ | ||
type: "text", | ||
name: "inputValue", | ||
validate: (value) => | ||
utils.isAddress(addHexPrefix(value)) | ||
? true | ||
: "Please enter a valid address", | ||
message: `Enter an address for argument ${argumentName}`, | ||
}); | ||
return utils.getAddress(addHexPrefix(inputValue)); | ||
} | ||
if (input.baseType === "bool") { | ||
return ( | ||
await prompts({ | ||
type: "select", | ||
name: "inputValue", | ||
choices: [ | ||
{ title: "True", value: true }, | ||
{ title: "False", value: false }, | ||
], | ||
message: `Enter a boolean for argument ${argumentName}`, | ||
}) | ||
).inputValue; | ||
} | ||
if (input.baseType === "string") { | ||
return ( | ||
await prompts({ | ||
type: "text", | ||
name: "inputValue", | ||
message: `Enter a string for argument ${argumentName}`, | ||
}) | ||
).inputValue; | ||
} | ||
if (input.baseType.includes("bytes")) { | ||
const { inputValue } = await prompts({ | ||
type: "text", | ||
name: "inputValue", | ||
validate: (value) => | ||
utils.isHexString(addHexPrefix(value)) | ||
? true | ||
: "Please enter a valid hex string", | ||
message: `Enter a hex string for argument ${argumentName}`, | ||
}); | ||
return BigNumber.from(addHexPrefix(inputValue)); | ||
} | ||
if (input.baseType.includes("int")) { | ||
return ( | ||
await prompts({ | ||
type: "number", | ||
name: "inputValue", | ||
min: input.baseType.includes("uint") ? 0 : -Infinity, | ||
message: `Enter a number for argument ${argumentName}`, | ||
}) | ||
).inputValue; | ||
} | ||
} | ||
async function runCode( | ||
code: Buffer, | ||
callData: Buffer, | ||
callValue: BN, | ||
callValue: BigNumber, | ||
functionToCall: utils.FunctionFragment | ||
@@ -120,10 +205,10 @@ ) { | ||
if (executionManager.canStepForward) { | ||
choices.push("Step Forwards"); | ||
choices.push({ title: "Step Forwards", value: "stepForward" }); | ||
} | ||
if (executionManager.canStepBackward) { | ||
choices.push("Step Backwards"); | ||
choices.push({ title: "Step Backwards", value: "stepBackward" }); | ||
} | ||
choices.push("Quit"); | ||
choices.push({ title: "Quit", value: "quit" }); | ||
const response = (await prompt({ | ||
const response = await prompts({ | ||
type: "select", | ||
@@ -133,12 +218,11 @@ name: "action", | ||
message: "What do you want to do?", | ||
})) as { action: "Step Forwards" | "Step Backwards" | "Quit" }; | ||
}); | ||
switch (response.action) { | ||
case "Step Forwards": | ||
case "stepForward": | ||
execInfo = await executionManager.stepForwards(); | ||
break; | ||
case "Step Backwards": | ||
case "stepBackward": | ||
execInfo = await executionManager.stepBackwards(); | ||
break; | ||
case "Quit": | ||
case "quit": | ||
process.exit(0); | ||
@@ -153,3 +237,3 @@ } | ||
callData: Buffer, | ||
callValue: BN, | ||
callValue: BigNumber, | ||
opCodeList: OpcodeList, | ||
@@ -196,3 +280,3 @@ functionToCall: utils.FunctionFragment, | ||
console.log(chalk.bold("CALL VALUE")); | ||
console.log(`0x${callValue.toString("hex")}`); | ||
console.log(`0x${callValue.toHexString()}`); | ||
@@ -199,0 +283,0 @@ console.log(bytecodeOutput); |
@@ -1,5 +0,2 @@ | ||
import { Block } from "@ethereumjs/block"; | ||
import Common, { Chain } from "@ethereumjs/common"; | ||
import EEI from "@ethereumjs/vm/dist/evm/eei"; | ||
import EVM from "@ethereumjs/vm/dist/evm/evm"; | ||
import Common from "@ethereumjs/common"; | ||
import { RunState } from "@ethereumjs/vm/dist/evm/interpreter"; | ||
@@ -15,8 +12,6 @@ import Memory from "@ethereumjs/vm/dist/evm/memory"; | ||
import Stack from "@ethereumjs/vm/dist/evm/stack"; | ||
import { DefaultStateManager } from "@ethereumjs/vm/dist/state"; | ||
import { StorageDump } from "@ethereumjs/vm/dist/state/interface"; | ||
import level from "level"; | ||
import { BN, Address } from "ethereumjs-util"; | ||
import { Address, BN } from "ethereumjs-util"; | ||
import { BigNumber } from "ethers"; | ||
import _ from "lodash"; | ||
import { SecureTrie as Trie } from "merkle-patricia-tree"; | ||
import { evmSetup } from "./utils"; | ||
@@ -42,3 +37,3 @@ | ||
constructor(code: Buffer, callData: Buffer, callValue: BN) { | ||
constructor(code: Buffer, callData: Buffer, callValue: BigNumber) { | ||
const { runState, common } = evmSetup(callData, callValue, code); | ||
@@ -45,0 +40,0 @@ |
@@ -17,3 +17,3 @@ import { Block } from "@ethereumjs/block"; | ||
import { SecureTrie as Trie } from "merkle-patricia-tree"; | ||
import { utils } from "ethers"; | ||
import { BigNumber, utils } from "ethers"; | ||
import chalk from "chalk"; | ||
@@ -75,3 +75,3 @@ | ||
callData: Buffer, | ||
callValue: BN, | ||
callValue: BigNumber, | ||
code: Buffer | ||
@@ -90,3 +90,3 @@ ): { runState: RunState; opCodeList: OpcodeList; common: Common } { | ||
callData, | ||
callValue, | ||
callValue: new BN(callValue.toString()), | ||
code, | ||
@@ -133,2 +133,6 @@ isStatic: false, | ||
export function addHexPrefix(hexString: string) { | ||
return hexString.startsWith("0x") ? hexString : `0x${hexString}`; | ||
} | ||
export function incrementCounter( | ||
@@ -135,0 +139,0 @@ currentCounter: number, |
Sorry, the diff of this file is not supported yet
492792
673
17
26
+ Added@types/prompts@^2.0.14
+ Addedprompts@^2.4.1
+ Added@types/prompts@2.4.9(transitive)
+ Addedkleur@3.0.3(transitive)
+ Addedprompts@2.4.2(transitive)
+ Addedsisteransi@1.0.5(transitive)
- Removedenquirer@^2.3.6
- Removedansi-colors@4.1.3(transitive)
- Removedenquirer@2.4.1(transitive)