hardhat-tracer
Advanced tools
Comparing version 2.0.0-beta.6 to 2.0.0-beta.7
@@ -31,3 +31,2 @@ "use strict"; | ||
function checkEqual(tx, item, options) { | ||
// TODO add from check | ||
// console.log(item.params); | ||
@@ -34,0 +33,0 @@ // for contract creation, to is undefined, and note that undefined === undefined is true. |
@@ -33,3 +33,2 @@ "use strict"; | ||
printMode: "console", | ||
// @ts-ignore TODO remove, this has no place in "config" | ||
_internal: { | ||
@@ -36,0 +35,0 @@ printNameTagTip: undefined, |
@@ -29,3 +29,4 @@ "use strict"; | ||
} | ||
else if (Array.isArray(value)) { | ||
else if (Array.isArray(value) && | ||
(0, utils_1.removeNumericFromEthersResult)(value) === null) { | ||
return ("[" + value.map((v) => formatParam(v, dependencies)).join(", ") + "]"); | ||
@@ -37,6 +38,7 @@ } | ||
else if (typeof value === "object" && value !== null) { | ||
const _value = (0, utils_1.removeNumericFromEthersResult)(value); | ||
return ("{" + | ||
Object.entries(value) | ||
Object.entries(_value) | ||
.map((entry) => { | ||
return `${entry[0]}${constants_1.SEPARATOR}${formatParam(entry[1], dependencies)}`; | ||
return `${(0, utils_1.colorKey)(entry[0] + constants_1.SEPARATOR)}${formatParam(entry[1], dependencies)}`; | ||
}) | ||
@@ -43,0 +45,0 @@ .join(", ") + |
@@ -25,8 +25,2 @@ "use strict"; | ||
} | ||
else if (Array.isArray(param.components)) { | ||
value = | ||
"[" + | ||
formatResult(result[i], param.components, { decimals, shorten }, dependencies) + | ||
"]"; | ||
} | ||
else { | ||
@@ -33,0 +27,0 @@ value = (0, param_1.formatParam)(result[i], dependencies); |
import { TracerDependencies } from "../types"; | ||
import { Item } from "../types"; | ||
export interface CREATE2 { | ||
from: string; | ||
initCode: string; | ||
@@ -5,0 +6,0 @@ salt: string; |
@@ -10,2 +10,3 @@ "use strict"; | ||
.addParam("data", "Calldata or error data to decode") | ||
.addOptionalParam("returndata", "Return data if any") | ||
.setAction(async (args, hre) => { | ||
@@ -19,6 +20,8 @@ const td = { | ||
// see if the data is a call | ||
const formattedCallPromise = (0, call_1.formatCall)(ethers_1.ethers.constants.AddressZero, args.data, "0x", 0, 0, 0, true, td); | ||
const formattedCallPromise = (0, call_1.formatCall)(ethers_1.ethers.constants.AddressZero, args.data, args.returndata ?? "0x", 0, 0, 0, true, td); | ||
const formattedErrorPromise = (0, error_1.formatError)(args.data, td); | ||
const formattedCall = await formattedCallPromise; | ||
if (!(0, utils_1.removeColor)(formattedCall).includes("UnknownContractAndFunction(to=0x0000000000000000000000000000000000000000")) { | ||
const uncolored = (0, utils_1.removeColor)(formattedCall); | ||
if (!uncolored.startsWith("UnknownContractAndFunction(") && | ||
!uncolored.includes("<UnknownFunction>")) { | ||
console.log(formattedCall); | ||
@@ -34,2 +37,3 @@ } | ||
console.log("Failed to decode the data"); | ||
console.log(formattedCall); | ||
} | ||
@@ -36,0 +40,0 @@ } |
@@ -60,7 +60,9 @@ "use strict"; | ||
} | ||
args.rpc = url; | ||
if (args.rpc == undefined) { | ||
args.rpc = url; | ||
} | ||
} | ||
// try using current mainnet fork url as rpc url | ||
const mainnetForkUrl = hre.network.config.forking?.url; | ||
if (mainnetForkUrl) { | ||
if (mainnetForkUrl && args.rpc == undefined) { | ||
args.rpc = mainnetForkUrl; | ||
@@ -67,0 +69,0 @@ } |
@@ -23,3 +23,3 @@ "use strict"; | ||
const mainnetForkUrl = hre.network.config.forking?.url; | ||
if (mainnetForkUrl) { | ||
if (mainnetForkUrl && args.rpc == undefined) { | ||
args.rpc = mainnetForkUrl; | ||
@@ -26,0 +26,0 @@ } |
@@ -28,3 +28,2 @@ "use strict"; | ||
} | ||
// TODO see how to do this | ||
returnCurrentCall(returnData, executionGas, exception) { | ||
@@ -31,0 +30,0 @@ if (!this.parent) |
@@ -19,4 +19,8 @@ "use strict"; | ||
// alias | ||
.addFlag("traceError", "enable tracer with verbosity 1") | ||
.addFlag("fulltraceError", "enable tracer with verbosity 2") | ||
.addFlag("fullTraceError", "enable tracer with verbosity 2") | ||
.addFlag("trace", "enable tracer with verbosity 3") | ||
.addFlag("fulltrace", "enable tracer with verbosity 4")); | ||
.addFlag("fulltrace", "enable tracer with verbosity 4") | ||
.addFlag("fullTrace", "enable tracer with verbosity 4")); | ||
} | ||
@@ -36,3 +40,3 @@ exports.addCliParams = addCliParams; | ||
// setting verbosity | ||
if (args.vvvv || args.fulltrace) { | ||
if (args.vvvv || args.fulltrace || args.fullTrace) { | ||
hre.tracer.verbosity = 4; | ||
@@ -45,7 +49,7 @@ opcodesToActivate.push(...logOpcodes, ...storageOpcodes); | ||
} | ||
else if (args.vv) { | ||
else if (args.vv || args["fulltraceError"] || args["fullTraceError"]) { | ||
hre.tracer.verbosity = 2; | ||
opcodesToActivate.push(...logOpcodes, ...storageOpcodes); | ||
} | ||
else if (args.v) { | ||
else if (args.v || args["traceError"]) { | ||
opcodesToActivate.push(...logOpcodes); | ||
@@ -52,0 +56,0 @@ hre.tracer.verbosity = 1; |
@@ -5,2 +5,3 @@ export * from "./check-opcodes"; | ||
export * from "./compare-bytecode"; | ||
export * from "./ethers"; | ||
export * from "./hardhat"; | ||
@@ -7,0 +8,0 @@ export * from "./hex"; |
@@ -21,2 +21,3 @@ "use strict"; | ||
__exportStar(require("./compare-bytecode"), exports); | ||
__exportStar(require("./ethers"), exports); | ||
__exportStar(require("./hardhat"), exports); | ||
@@ -23,0 +24,0 @@ __exportStar(require("./hex"), exports); |
@@ -6,4 +6,4 @@ import { TracerDependencies } from "../types"; | ||
export declare function fetchContractDecimals(to: string, dependencies: TracerDependencies): Promise<number | undefined>; | ||
export declare function fetchContractNameUsingArtifacts(address: string, dependencies: TracerDependencies): Promise<string | undefined>; | ||
export declare function fetchContractNameUsingBytecodeComparison(address: string, dependencies: TracerDependencies): Promise<string | undefined>; | ||
export declare function getBetterContractName(address: string, dependencies: TracerDependencies): Promise<string | undefined>; | ||
//# sourceMappingURL=metadata.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getBetterContractName = exports.fetchContractNameUsingArtifacts = exports.fetchContractDecimals = exports.fetchContractNameFromMethodName = exports.fetchContractName = exports.getFromNameTags = void 0; | ||
exports.getBetterContractName = exports.fetchContractNameUsingBytecodeComparison = exports.fetchContractDecimals = exports.fetchContractNameFromMethodName = exports.fetchContractName = exports.getFromNameTags = void 0; | ||
const compare_bytecode_1 = require("./compare-bytecode"); | ||
@@ -85,3 +85,3 @@ const ethers_1 = require("ethers"); | ||
exports.fetchContractDecimals = fetchContractDecimals; | ||
async function fetchContractNameUsingArtifacts(address, dependencies) { | ||
async function fetchContractNameUsingBytecodeComparison(address, dependencies) { | ||
const toBytecode = await dependencies.provider.send("eth_getCode", [address]); | ||
@@ -92,4 +92,3 @@ const names = await dependencies.artifacts.getAllFullyQualifiedNames(); | ||
// try to find the contract name | ||
if ((0, compare_bytecode_1.compareBytecode)(_artifact.deployedBytecode, toBytecode) > 0.5 || | ||
(address === ethers_1.ethers.constants.AddressZero && toBytecode.length <= 2)) { | ||
if ((0, compare_bytecode_1.compareBytecode)(_artifact.deployedBytecode, toBytecode) > 0.5) { | ||
// if bytecode of "to" is the same as the deployed bytecode | ||
@@ -101,3 +100,3 @@ // we can use the artifact name | ||
} | ||
exports.fetchContractNameUsingArtifacts = fetchContractNameUsingArtifacts; | ||
exports.fetchContractNameUsingBytecodeComparison = fetchContractNameUsingBytecodeComparison; | ||
async function getBetterContractName(address, dependencies) { | ||
@@ -118,6 +117,6 @@ // 1. See if nameTag exists already | ||
// 3. Match bytecode | ||
const contractNameFromArtifacts = await fetchContractNameUsingArtifacts(address, dependencies); | ||
if (contractNameFromArtifacts) { | ||
dependencies.tracerEnv.nameTags[address] = contractNameFromArtifacts; | ||
return contractNameFromArtifacts; | ||
const contractNameFromBytecodeComparison = await fetchContractNameUsingBytecodeComparison(address, dependencies); | ||
if (contractNameFromBytecodeComparison) { | ||
dependencies.tracerEnv.nameTags[address] = contractNameFromBytecodeComparison; | ||
return contractNameFromBytecodeComparison; | ||
} | ||
@@ -124,0 +123,0 @@ } |
@@ -26,5 +26,3 @@ "use strict"; | ||
} | ||
// TODO take decision whether to print or not | ||
// if estimateGas fails then print it | ||
// sendTx should be printing it regardless of success or failure | ||
// take decision whether to print last trace or not | ||
const isSendTransaction = args.method === "eth_sendTransaction"; | ||
@@ -54,3 +52,3 @@ const isSendRawTransaction = args.method === "eth_sendRawTransaction"; | ||
isEthCall || | ||
isEstimateGas)); | ||
isEstimateGasFailed)); | ||
break; | ||
@@ -63,3 +61,3 @@ case 3: | ||
isEthCall || | ||
isEstimateGas; | ||
isEstimateGasFailed; | ||
break; | ||
@@ -75,5 +73,5 @@ default: | ||
else { | ||
this.dependencies.tracerEnv.printNext = false; | ||
const lastTrace = this.dependencies.tracerEnv.lastTrace(); | ||
if (lastTrace) { | ||
this.dependencies.tracerEnv.printNext = false; | ||
await (0, print_1.print)(lastTrace, this.dependencies); | ||
@@ -80,0 +78,0 @@ } |
{ | ||
"name": "hardhat-tracer", | ||
"version": "2.0.0-beta.6", | ||
"version": "2.0.0-beta.7", | ||
"description": "Hardhat Tracer plugin", | ||
@@ -5,0 +5,0 @@ "repository": "github:zemse/hardhat-tracer", |
@@ -15,2 +15,3 @@ # hardhat-tracer 🕵️ | ||
- [State overrides](#state-overrides) | ||
- [Chai util](#chai-util) | ||
@@ -22,3 +23,3 @@ ## Installation | ||
``` | ||
npm i hardhat-tracer | ||
npm i hardhat-tracer@beta | ||
``` | ||
@@ -71,3 +72,3 @@ | ||
If you are just looking for a quick decode of calldata or [Solidity"s Custom Error](https://blog.soliditylang.org/2021/04/21/custom-errors/): | ||
If you are just looking for a quick decode of calldata, return data or [Solidity"s Custom Error](https://blog.soliditylang.org/2021/04/21/custom-errors/): | ||
@@ -77,2 +78,7 @@ ``` | ||
ERC20.approve(spender=0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45, amount=115792089237316195423570985008687907853269984665640564039457584007913129639935) | ||
$ npx hardhat decode --data 0x3850c7bd --returndata 0x000000000000000000000000000000000000000000024d0fa9cd4ba6ff769172fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcdea1000000000000000000000000000000000000000000000000000000000000a244000000000000000000000000000000000000000000000000000000000000ff78000000000000000000000000000000000000000000000000000000000000ffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 | ||
IUniswapV3Pool(0x0000000000000000000000000000000000000000).slot0() => (sqrtPriceX96: 2781762795090269932261746, tick: -205151, observationIndex: 41540, observationCardinality: 65400, observationCardinalityNext: 65535, feeProtocol: 0, unlocked: true) | ||
``` | ||
@@ -118,1 +124,18 @@ | ||
``` | ||
### Chai util | ||
Allows to add a test case to check whether last tx did an internal message call. | ||
```ts | ||
expect(hre.tracer.lastTrace()).to.have.messageCall( | ||
await contract.populateTransaction.getData(), | ||
{ | ||
returnData: defaultAbiCoder.encode(["uint"], ["1234"]), | ||
from: otherContract.address, | ||
isDelegateCall: true, | ||
isStaticCall: true, | ||
isSuccess: true, | ||
} | ||
); | ||
``` |
@@ -56,3 +56,2 @@ import { Assertion } from "chai"; | ||
): { matchQuotient: number; error: Error | undefined } { | ||
// TODO add from check | ||
// console.log(item.params); | ||
@@ -59,0 +58,0 @@ |
@@ -51,3 +51,2 @@ import { DEFAULT_VERBOSITY } from "../constants"; | ||
printMode: "console", | ||
// @ts-ignore TODO remove, this has no place in "config" | ||
_internal: { | ||
@@ -54,0 +53,0 @@ printNameTagTip: undefined, |
import { BigNumber } from "ethers"; | ||
import { colorIndexed, colorNameTag } from "../utils"; | ||
import { | ||
colorIndexed, | ||
colorKey, | ||
colorNameTag, | ||
removeNumericFromEthersResult, | ||
} from "../utils"; | ||
import { getAddress } from "ethers/lib/utils"; | ||
@@ -29,3 +34,6 @@ import { getFromNameTags } from "../utils"; | ||
} | ||
} else if (Array.isArray(value)) { | ||
} else if ( | ||
Array.isArray(value) && | ||
removeNumericFromEthersResult(value) === null | ||
) { | ||
return ( | ||
@@ -40,7 +48,8 @@ "[" + value.map((v) => formatParam(v, dependencies)).join(", ") + "]" | ||
} else if (typeof value === "object" && value !== null) { | ||
const _value = removeNumericFromEthersResult(value); | ||
return ( | ||
"{" + | ||
Object.entries(value) | ||
Object.entries(_value) | ||
.map((entry) => { | ||
return `${entry[0]}${SEPARATOR}${formatParam( | ||
return `${colorKey(entry[0] + SEPARATOR)}${formatParam( | ||
entry[1], | ||
@@ -47,0 +56,0 @@ dependencies |
@@ -33,12 +33,2 @@ import { BigNumber } from "ethers"; | ||
value = formatUnits(result[i], decimals); | ||
} else if (Array.isArray(param.components)) { | ||
value = | ||
"[" + | ||
formatResult( | ||
result[i], | ||
param.components, | ||
{ decimals, shorten }, | ||
dependencies | ||
) + | ||
"]"; | ||
} else { | ||
@@ -45,0 +35,0 @@ value = formatParam(result[i], dependencies); |
@@ -6,2 +6,3 @@ import { formatContract } from "../format/contract"; | ||
export interface CREATE2 { | ||
from: string; | ||
initCode: string; | ||
@@ -8,0 +9,0 @@ salt: string; |
@@ -9,2 +9,3 @@ import { addCliParams, removeColor } from "../utils"; | ||
.addParam("data", "Calldata or error data to decode") | ||
.addOptionalParam("returndata", "Return data if any") | ||
.setAction(async (args, hre) => { | ||
@@ -22,3 +23,3 @@ const td = { | ||
args.data, | ||
"0x", | ||
args.returndata ?? "0x", | ||
0, | ||
@@ -34,6 +35,6 @@ 0, | ||
const formattedCall = await formattedCallPromise; | ||
const uncolored = removeColor(formattedCall); | ||
if ( | ||
!removeColor(formattedCall).includes( | ||
"UnknownContractAndFunction(to=0x0000000000000000000000000000000000000000" | ||
) | ||
!uncolored.startsWith("UnknownContractAndFunction(") && | ||
!uncolored.includes("<UnknownFunction>") | ||
) { | ||
@@ -44,3 +45,2 @@ console.log(formattedCall); | ||
const formattedError = await formattedErrorPromise; | ||
if (!removeColor(formattedError).includes("UnknownError(")) { | ||
@@ -50,4 +50,5 @@ console.log(formattedError); | ||
console.log("Failed to decode the data"); | ||
console.log(formattedCall); | ||
} | ||
} | ||
}); |
@@ -78,3 +78,5 @@ import { assert } from "console"; | ||
} | ||
args.rpc = url; | ||
if (args.rpc == undefined) { | ||
args.rpc = url; | ||
} | ||
} | ||
@@ -84,3 +86,3 @@ | ||
const mainnetForkUrl = (hre.network.config as any).forking?.url; | ||
if (mainnetForkUrl) { | ||
if (mainnetForkUrl && args.rpc == undefined) { | ||
args.rpc = mainnetForkUrl; | ||
@@ -87,0 +89,0 @@ } |
@@ -26,3 +26,3 @@ import { addCliParams, applyCliArgsToTracer } from "../utils"; | ||
const mainnetForkUrl = (hre.network.config as any).forking?.url; | ||
if (mainnetForkUrl) { | ||
if (mainnetForkUrl && args.rpc == undefined) { | ||
args.rpc = mainnetForkUrl; | ||
@@ -29,0 +29,0 @@ } |
@@ -35,3 +35,2 @@ import { CallItem, Item } from "./types"; | ||
// TODO see how to do this | ||
returnCurrentCall( | ||
@@ -38,0 +37,0 @@ returnData: string, |
@@ -36,3 +36,2 @@ import { Artifacts } from "hardhat/types"; | ||
printMode: PrintMode; | ||
// todo remove internal | ||
_internal: { | ||
@@ -39,0 +38,0 @@ cache: TracerCache; |
@@ -33,4 +33,8 @@ import { checkIfOpcodesAreValid } from "./check-opcodes"; | ||
// alias | ||
.addFlag("traceError", "enable tracer with verbosity 1") | ||
.addFlag("fulltraceError", "enable tracer with verbosity 2") | ||
.addFlag("fullTraceError", "enable tracer with verbosity 2") | ||
.addFlag("trace", "enable tracer with verbosity 3") | ||
.addFlag("fulltrace", "enable tracer with verbosity 4") | ||
.addFlag("fullTrace", "enable tracer with verbosity 4") | ||
); | ||
@@ -58,3 +62,3 @@ } | ||
// setting verbosity | ||
if (args.vvvv || args.fulltrace) { | ||
if (args.vvvv || args.fulltrace || args.fullTrace) { | ||
hre.tracer.verbosity = 4; | ||
@@ -65,6 +69,6 @@ opcodesToActivate.push(...logOpcodes, ...storageOpcodes); | ||
opcodesToActivate.push(...logOpcodes); | ||
} else if (args.vv) { | ||
} else if (args.vv || args["fulltraceError"] || args["fullTraceError"]) { | ||
hre.tracer.verbosity = 2; | ||
opcodesToActivate.push(...logOpcodes, ...storageOpcodes); | ||
} else if (args.v) { | ||
} else if (args.v || args["traceError"]) { | ||
opcodesToActivate.push(...logOpcodes); | ||
@@ -71,0 +75,0 @@ hre.tracer.verbosity = 1; |
@@ -5,2 +5,3 @@ export * from "./check-opcodes"; | ||
export * from "./compare-bytecode"; | ||
export * from "./ethers"; | ||
export * from "./hardhat"; | ||
@@ -7,0 +8,0 @@ export * from "./hex"; |
@@ -98,3 +98,3 @@ import { compareBytecode } from "./compare-bytecode"; | ||
export async function fetchContractNameUsingArtifacts( | ||
export async function fetchContractNameUsingBytecodeComparison( | ||
address: string, | ||
@@ -109,6 +109,3 @@ dependencies: TracerDependencies | ||
// try to find the contract name | ||
if ( | ||
compareBytecode(_artifact.deployedBytecode, toBytecode) > 0.5 || | ||
(address === ethers.constants.AddressZero && toBytecode.length <= 2) | ||
) { | ||
if (compareBytecode(_artifact.deployedBytecode, toBytecode) > 0.5) { | ||
// if bytecode of "to" is the same as the deployed bytecode | ||
@@ -145,10 +142,12 @@ // we can use the artifact name | ||
// 3. Match bytecode | ||
const contractNameFromArtifacts = await fetchContractNameUsingArtifacts( | ||
const contractNameFromBytecodeComparison = await fetchContractNameUsingBytecodeComparison( | ||
address, | ||
dependencies | ||
); | ||
if (contractNameFromArtifacts) { | ||
dependencies.tracerEnv.nameTags[address] = contractNameFromArtifacts; | ||
return contractNameFromArtifacts; | ||
if (contractNameFromBytecodeComparison) { | ||
dependencies.tracerEnv.nameTags[ | ||
address | ||
] = contractNameFromBytecodeComparison; | ||
return contractNameFromBytecodeComparison; | ||
} | ||
} |
@@ -38,5 +38,3 @@ import { BackwardsCompatibilityProviderAdapter } from "hardhat/internal/core/providers/backwards-compatibility"; | ||
// TODO take decision whether to print or not | ||
// if estimateGas fails then print it | ||
// sendTx should be printing it regardless of success or failure | ||
// take decision whether to print last trace or not | ||
const isSendTransaction = args.method === "eth_sendTransaction"; | ||
@@ -69,3 +67,3 @@ const isSendRawTransaction = args.method === "eth_sendRawTransaction"; | ||
isEthCall || | ||
isEstimateGas)); | ||
isEstimateGasFailed)); | ||
break; | ||
@@ -78,3 +76,3 @@ case 3: | ||
isEthCall || | ||
isEstimateGas; | ||
isEstimateGasFailed; | ||
break; | ||
@@ -92,5 +90,5 @@ default: | ||
} else { | ||
this.dependencies.tracerEnv.printNext = false; | ||
const lastTrace = this.dependencies.tracerEnv.lastTrace(); | ||
if (lastTrace) { | ||
this.dependencies.tracerEnv.printNext = false; | ||
await print(lastTrace, this.dependencies); | ||
@@ -97,0 +95,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
404259
301
7084
137