Socket
Socket
Sign inDemoInstall

hardhat-tracer

Package Overview
Dependencies
298
Maintainers
1
Versions
52
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.0.0-beta.4 to 2.0.0-beta.5

dist/src/chai/index.d.ts

6

dist/src/cache.js

@@ -7,4 +7,4 @@ "use strict";

exports.TracerCache = void 0;
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const fs_extra_1 = __importDefault(require("fs-extra"));
// To locally cache contract name, decimals, and ABI to prevent async API calls

@@ -39,7 +39,7 @@ class TracerCache {

fourByteDir: Array.from(this.fourByteDir.entries()),
});
}, { spaces: 2 });
}
getTracerCachePath() {
if (!this.cachePath) {
throw new Error("cachePath not set");
throw new Error("[hardhat-tracer]: cachePath not set");
}

@@ -46,0 +46,0 @@ return path_1.default.join(this.cachePath, "hardhat-tracer-cache", `data.json`);

export declare const DEPTH_INDENTATION = " ";
export declare const SEPARATOR = ": ";
export declare const DEFAULT_VERBOSITY = 0;
//# sourceMappingURL=constants.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DEPTH_INDENTATION = void 0;
exports.DEFAULT_VERBOSITY = exports.SEPARATOR = exports.DEPTH_INDENTATION = void 0;
exports.DEPTH_INDENTATION = " ";
exports.SEPARATOR = ": ";
exports.DEFAULT_VERBOSITY = 0;
//# sourceMappingURL=constants.js.map

@@ -1,4 +0,4 @@

import { ErrorFragment, EventFragment, Fragment, FunctionFragment, Result } from "ethers/lib/utils";
import { Artifacts } from "hardhat/types";
import { TracerCache } from "./cache";
import { ErrorFragment, EventFragment, Fragment, FunctionFragment, Result } from "ethers/lib/utils";
declare type Mapping<FragmentType> = Map<string, Array<{

@@ -5,0 +5,0 @@ contractName: string;

@@ -54,3 +54,3 @@ "use strict";

if (topics.length === 0) {
throw new Error("No topics, cannot decode");
throw new Error("[hardhat-tracer]: No topics, cannot decode");
}

@@ -57,0 +57,0 @@ const topic0 = topics[0];

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const constants_1 = require("../constants");
const config_1 = require("hardhat/config");
const cache_1 = require("../cache");
const utils_1 = require("../utils");
(0, config_1.extendConfig)((config, userConfig) => {

@@ -13,3 +13,3 @@ // config.tracer = getTracerEnvFromUserInput(userConfig.tracer);

if (!Array.isArray(userConfig.tracer.opcodes)) {
throw new Error("tracer.opcodes in hardhat user config should be array");
throw new Error("[hardhat-tracer]: tracer.opcodes in hardhat user config should be array");
}

@@ -28,7 +28,8 @@ opcodesToActivate.push(...userConfig.tracer.opcodes);

printNext: false,
verbosity: userConfig.tracer?.defaultVerbosity ?? utils_1.DEFAULT_VERBOSITY,
showAddresses: userConfig.tracer?.showAddresses ?? false,
verbosity: userConfig.tracer?.defaultVerbosity ?? constants_1.DEFAULT_VERBOSITY,
showAddresses: userConfig.tracer?.showAddresses ?? true,
gasCost: userConfig.tracer?.gasCost ?? false,
opcodes,
nameTags: userConfig.tracer?.nameTags ?? {},
printMode: "console",
// @ts-ignore TODO remove, this has no place in "config"

@@ -39,2 +40,7 @@ _internal: {

},
lastTrace: function () {
if (this.recorder) {
return this.recorder.previousTraces[this.recorder.previousTraces.length - 1];
}
},
stateOverrides: userConfig.tracer?.stateOverrides,

@@ -41,0 +47,0 @@ };

@@ -0,4 +1,4 @@

import { TracerEnv } from "../types";
import "hardhat/types/config";
import "hardhat/types/runtime";
import { TracerEnv } from "../types";
declare module "hardhat/types/runtime" {

@@ -5,0 +5,0 @@ interface HardhatRuntimeEnvironment {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const decoder_1 = require("../decoder");
const config_1 = require("hardhat/config");
const trace_recorder_1 = require("../trace-recorder");
require("hardhat/types/config");
require("hardhat/types/runtime");
const get_vm_1 = require("../get-vm");
const recorder_1 = require("../trace/recorder");
const decoder_1 = require("../decoder");
(0, config_1.extendEnvironment)((hre) => {

@@ -18,5 +18,11 @@ // copy reference of config.tracer to tracer

global.hreArtifacts = hre.artifacts;
(0, get_vm_1.getVM)(hre)
.then((vm) => {
hre.tracer.recorder = new recorder_1.TraceRecorder(vm, hre.tracer, hre.artifacts);
(0, utils_1.getVM)(hre)
.then(async (vm) => {
hre.tracer.recorder = new trace_recorder_1.TraceRecorder(vm, hre.tracer);
if (hre.tracer.stateOverrides) {
try {
await (0, utils_1.applyStateOverrides)(hre.tracer.stateOverrides, vm, hre.artifacts);
}
catch { }
}
})

@@ -23,0 +29,0 @@ .catch(() => {

import { BigNumberish } from "ethers";
import { TracerDependencies } from "../types";
export declare function formatCall(to: string, input: string, ret: string, value: BigNumberish, gas: BigNumberish, success: boolean, dependencies: TracerDependencies): Promise<string>;
export declare function formatCall(to: string, input: string, ret: string, value: BigNumberish, gasUsed: BigNumberish, gasLimit: BigNumberish, success: boolean, dependencies: TracerDependencies): Promise<string>;
//# sourceMappingURL=call.d.ts.map

@@ -5,9 +5,9 @@ "use strict";

const ethers_1 = require("ethers");
const colors_1 = require("../colors");
const utils_1 = require("../utils");
const param_1 = require("./param");
const result_1 = require("./result");
const constants_1 = require("../constants");
const colors_1 = require("../utils/colors");
const utils_2 = require("ethers/lib/utils");
const separator_1 = require("./separator");
async function formatCall(to, input, ret, value, gas, success, dependencies) {
async function formatCall(to, input, ret, value, gasUsed, gasLimit, success, dependencies) {
let contractName;

@@ -51,3 +51,3 @@ let contractDecimals;

// otherwise fetch it
contractDecimals = await (0, utils_1.fetchContractDecimals)(to, dependencies.provider);
contractDecimals = await (0, utils_1.fetchContractDecimals)(to, dependencies);
// and cache it

@@ -65,7 +65,11 @@ if (contractDecimals !== undefined) {

if ((value = ethers_1.BigNumber.from(value)).gt(0)) {
extra.push(`value${separator_1.SEPARATOR}${(0, utils_2.formatEther)(value)}`);
extra.push(`value${constants_1.SEPARATOR}${(0, utils_2.formatEther)(value)}`);
}
if ((gas = ethers_1.BigNumber.from(gas)).gt(0) && dependencies.tracerEnv.gasCost) {
extra.push(`gas${separator_1.SEPARATOR}${(0, param_1.formatParam)(gas, dependencies)}`);
if ((gasLimit = ethers_1.BigNumber.from(gasLimit)).gt(0) &&
(gasUsed = ethers_1.BigNumber.from(gasUsed)).gt(0) &&
dependencies.tracerEnv.gasCost) {
extra.push(`gasLimit${constants_1.SEPARATOR}${(0, param_1.formatParam)(gasLimit, dependencies)}`);
extra.push(`gasUsed${constants_1.SEPARATOR}${(0, param_1.formatParam)(gasUsed, dependencies)}`);
}
const colorFunction = success ? colors_1.colorFunctionSuccess : colors_1.colorFunctioFail;
if (inputResult && fragment) {

@@ -82,3 +86,3 @@ const inputArgs = (0, result_1.formatResult)(inputResult, fragment.inputs, { decimals: contractDecimals, shorten: false }, dependencies);

? `${(0, colors_1.colorContract)(nameToPrint)}(${to})`
: (0, colors_1.colorContract)(nameToPrint)}.${(0, colors_1.colorFunction)(fragment.name)}${extra.length !== 0 ? `{${extra.join(",")}}` : ""}(${inputArgs})${outputArgs ? ` => (${outputArgs})` : ""}`;
: (0, colors_1.colorContract)(nameToPrint)}.${colorFunction(fragment.name)}${extra.length !== 0 ? `{${extra.join(", ")}}` : ""}(${inputArgs})${outputArgs ? ` => (${outputArgs})` : ""}`;
}

@@ -89,6 +93,6 @@ // TODO add flag to hide unrecognized stuff

? `${(0, colors_1.colorContract)(contractName)}(${to})`
: (0, colors_1.colorContract)(contractName)}.<${(0, colors_1.colorFunction)("UnknownFunction")}>${extra.length !== 0 ? `{${extra.join(",")}}` : ""}(${(0, colors_1.colorKey)("input" + separator_1.SEPARATOR)}${input}, ${(0, colors_1.colorKey)("ret" + separator_1.SEPARATOR)}${ret})`;
: (0, colors_1.colorContract)(contractName)}.<${colorFunction("UnknownFunction")}>${extra.length !== 0 ? `{${extra.join(", ")}}` : ""}(${(0, colors_1.colorKey)("input" + constants_1.SEPARATOR)}${input}, ${(0, colors_1.colorKey)("ret" + constants_1.SEPARATOR)}${ret})`;
}
else {
return `${(0, colors_1.colorFunction)("UnknownContractAndFunction")}${extra.length !== 0 ? `{${extra.join(",")}}` : ""}(${(0, colors_1.colorKey)("to" + separator_1.SEPARATOR)}${to}, ${(0, colors_1.colorKey)("input" + separator_1.SEPARATOR)}${input}, ${(0, colors_1.colorKey)("ret" + separator_1.SEPARATOR)}${ret || "0x"})`;
return `${colorFunction("UnknownContractAndFunction")}${extra.length !== 0 ? `{${extra.join(", ")}}` : ""}(${(0, colors_1.colorKey)("to" + constants_1.SEPARATOR)}${to}, ${(0, colors_1.colorKey)("input" + constants_1.SEPARATOR)}${input}, ${(0, colors_1.colorKey)("ret" + constants_1.SEPARATOR)}${ret || "0x"})`;
}

@@ -95,0 +99,0 @@ }

@@ -7,5 +7,5 @@ "use strict";

exports.formatConsoleLog = exports.CONSOLE_LOG_ADDRESS = void 0;
const console_log_methods_json_1 = __importDefault(require("./console-log-methods.json"));
const ethers_1 = require("ethers");
const result_1 = require("./result");
const console_log_methods_json_1 = __importDefault(require("./console-log-methods.json"));
// TODO try to import this from somewhere in hardhat

@@ -12,0 +12,0 @@ exports.CONSOLE_LOG_ADDRESS = "0x000000000000000000636f6e736f6c652e6c6f67";

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatContract = void 0;
const utils_1 = require("ethers/lib/utils");
const ethers_1 = require("ethers");
const utils_1 = require("ethers/lib/utils");
const colors_1 = require("../colors");
const colors_1 = require("../utils/colors");
const utils_2 = require("../utils");

@@ -32,3 +32,3 @@ const param_1 = require("./param");

}
return `${(0, colors_1.colorContract)(artifact.contractName)}.${(0, colors_1.colorFunction)("constructor")}${extra.length !== 0 ? `{${extra.join(",")}}` : ""}(${inputArgs})${deployedAddress
return `${(0, colors_1.colorContract)(artifact.contractName)}.${(0, colors_1.colorFunctionSuccess)("constructor")}${extra.length !== 0 ? `{${extra.join(",")}}` : ""}(${inputArgs})${deployedAddress
? ` => (${(0, param_1.formatParam)(deployedAddress, dependencies)})`

@@ -35,0 +35,0 @@ : ""}`;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatError = void 0;
const colors_1 = require("../colors");
const colors_1 = require("../utils/colors");
const object_1 = require("./object");

@@ -6,0 +6,0 @@ const param_1 = require("./param");

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatLog = void 0;
const colors_1 = require("../colors");
const colors_1 = require("../utils/colors");
const param_1 = require("./param");

@@ -6,0 +6,0 @@ const result_1 = require("./result");

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatObject = void 0;
const colors_1 = require("../colors");
const separator_1 = require("./separator");
const utils_1 = require("../utils");
const constants_1 = require("../constants");
function formatObject(obj) {

@@ -19,3 +19,3 @@ return Object.entries(obj)

}
return `${(0, colors_1.colorKey)(key + separator_1.SEPARATOR)}${value}`;
return `${(0, utils_1.colorKey)(key + constants_1.SEPARATOR)}${value}`;
})

@@ -22,0 +22,0 @@ .join(", ");

@@ -5,6 +5,6 @@ "use strict";

const ethers_1 = require("ethers");
const utils_1 = require("ethers/lib/utils");
const colors_1 = require("../colors");
const utils_2 = require("../utils");
const separator_1 = require("./separator");
const utils_1 = require("../utils");
const utils_2 = require("ethers/lib/utils");
const utils_3 = require("../utils");
const constants_1 = require("../constants");
function formatParam(value, dependencies) {

@@ -20,4 +20,4 @@ if (value?._isBigNumber) {

value.length === 42) {
if ((0, utils_2.getFromNameTags)(value, dependencies)) {
return (0, colors_1.colorNameTag)(`[${(0, utils_2.getFromNameTags)(value, dependencies)}]`);
if ((0, utils_3.getFromNameTags)(value, dependencies)) {
return (0, utils_1.colorNameTag)(`[${(0, utils_3.getFromNameTags)(value, dependencies)}]`);
}

@@ -28,3 +28,3 @@ else {

}
return (0, utils_1.getAddress)(value);
return (0, utils_2.getAddress)(value);
}

@@ -36,3 +36,3 @@ }

else if (value?._isIndexed) {
return `${(0, colors_1.colorIndexed)("[Indexed]")}${formatParam(value.hash, dependencies)}`;
return `${(0, utils_1.colorIndexed)("[Indexed]")}${formatParam(value.hash, dependencies)}`;
}

@@ -43,3 +43,3 @@ else if (typeof value === "object" && value !== null) {

.map((entry) => {
return `${entry[0]}${separator_1.SEPARATOR}${formatParam(entry[1], dependencies)}`;
return `${entry[0]}${constants_1.SEPARATOR}${formatParam(entry[1], dependencies)}`;
})

@@ -46,0 +46,0 @@ .join(", ") +

@@ -5,5 +5,5 @@ "use strict";

const ethers_1 = require("ethers");
const colors_1 = require("../utils/colors");
const param_1 = require("./param");
const utils_1 = require("ethers/lib/utils");
const colors_1 = require("../colors");
const param_1 = require("./param");
function formatResult(result, params, { decimals, shorten }, dependencies) {

@@ -10,0 +10,0 @@ decimals = decimals ?? -1;

import "./extend";
import "./tasks";
import "./chai";
export * from "./types";
export * from "./wrapper";
//# sourceMappingURL=index.d.ts.map

@@ -19,4 +19,5 @@ "use strict";

require("./tasks");
require("./chai");
__exportStar(require("./types"), exports);
__exportStar(require("./wrapper"), exports);
//# sourceMappingURL=index.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const config_1 = require("hardhat/config");
const task_names_1 = require("hardhat/builtin-tasks/task-names");
const config_1 = require("hardhat/config");
(0, config_1.task)(task_names_1.TASK_COMPILE_SOLIDITY_EMIT_ARTIFACTS).setAction(async (args, hre, runSuper) => {

@@ -11,4 +12,8 @@ const result = await runSuper(args);

}
// if state overrides are provided, then apply them after compilation
if (hre.tracer.stateOverrides && hre.tracer.recorder?.vm) {
(0, utils_1.applyStateOverrides)(hre.tracer.stateOverrides, hre.tracer.recorder?.vm, hre.artifacts);
}
return result;
});
//# sourceMappingURL=compile.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ethers_1 = require("ethers");
const config_1 = require("hardhat/config");
const call_1 = require("../format/call");
const error_1 = require("../format/error");
const utils_1 = require("../utils");
const config_1 = require("hardhat/config");
(0, utils_1.addCliParams)((0, config_1.task)("decode", "Decodes calldata or error data"))

@@ -18,3 +18,3 @@ .addParam("data", "Calldata or error data to decode")

// see if the data is a call
const formattedCallPromise = (0, call_1.formatCall)(ethers_1.ethers.constants.AddressZero, args.data, "0x", 0, 0, true, td);
const formattedCallPromise = (0, call_1.formatCall)(ethers_1.ethers.constants.AddressZero, args.data, "0x", 0, 0, 0, true, td);
const formattedErrorPromise = (0, error_1.formatError)(args.data, td);

@@ -21,0 +21,0 @@ const formattedCall = await formattedCallPromise;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const config_1 = require("hardhat/config");
const task_names_1 = require("hardhat/builtin-tasks/task-names");
const config_1 = require("hardhat/config");
const utils_1 = require("../utils");
const wrapper_1 = require("../wrapper");

@@ -7,0 +7,0 @@ (0, utils_1.addCliParams)((0, config_1.task)(task_names_1.TASK_TEST, "Runs mocha tests")).setAction(async (args, hre, runSuper) => {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const console_1 = require("console");
const ethers_1 = require("ethers");
const FakeSenderAccessListEIP2930Transaction_1 = require("hardhat/internal/hardhat-network/provider/transactions/FakeSenderAccessListEIP2930Transaction");
const FakeSenderEIP1559Transaction_1 = require("hardhat/internal/hardhat-network/provider/transactions/FakeSenderEIP1559Transaction");
const FakeSenderTransaction_1 = require("hardhat/internal/hardhat-network/provider/transactions/FakeSenderTransaction");
const ForkBlockchain_1 = require("hardhat/internal/hardhat-network/provider/fork/ForkBlockchain");
const hardhat_1 = require("../utils/hardhat");
const config_1 = require("hardhat/config");
const get_vm_1 = require("../get-vm");
const trace_recorder_1 = require("../trace-recorder");
const ethereumjs_vm_1 = require("@nomicfoundation/ethereumjs-vm");
const utils_1 = require("../utils");
const ethereumjs_vm_1 = require("@nomicfoundation/ethereumjs-vm");
const recorder_1 = require("../trace/recorder");
const print_1 = require("../print");
const originalCreate = ethereumjs_vm_1.VM.create;

@@ -16,3 +22,9 @@ ethereumjs_vm_1.VM.create = async function (...args) {

const hreArtifacts = global.hreArtifacts;
const recorder = new recorder_1.TraceRecorder(vm, tracerEnv, hreArtifacts);
const recorder = new trace_recorder_1.TraceRecorder(vm, tracerEnv);
if (tracerEnv.stateOverrides) {
try {
await (0, utils_1.applyStateOverrides)(tracerEnv.stateOverrides, vm, hreArtifacts);
}
catch { }
}
tracerEnv.recorder = recorder;

@@ -28,2 +40,5 @@ // @ts-ignore

(0, utils_1.applyCliArgsToTracer)(args, hre);
if (!args["nocompile"]) {
await hre.run("compile");
}
const tx = await hre.network.provider.send("eth_getTransactionByHash", [

@@ -38,10 +53,10 @@ args.hash,

if (userNetworks === undefined) {
throw new Error("No networks found in hardhat config");
throw new Error("[hardhat-tracer]: No networks found in hardhat config");
}
if (userNetworks[args.network] === undefined) {
throw new Error(`Network ${args.network} not found in hardhat config`);
throw new Error(`[hardhat-tracer]: Network ${args.network} not found in hardhat config`);
}
const url = userNetworks[args.network].url;
if (url === undefined) {
throw new Error(`Url not found in hardhat-config->networks->${args.network}`);
throw new Error(`[hardhat-tracer]: Url not found in hardhat-config->networks->${args.network}`);
}

@@ -57,3 +72,3 @@ args.rpc = url;

// TODO add auto-detect network
throw new Error("rpc url not provided, please either use --network <network-name> or --rpc <rpc-url>");
throw new Error("[hardhat-tracer]: rpc url not provided, please either use --network <network-name> or --rpc <rpc-url>");
}

@@ -63,6 +78,6 @@ const provider = new ethers_1.ethers.providers.StaticJsonRpcProvider(args.rpc);

if (txFromRpc == null) {
throw new Error("Transaction not found on rpc. Are you sure the transaction is confirmed on this network?");
throw new Error("[hardhat-tracer]: Transaction not found on rpc. Are you sure the transaction is confirmed on this network?");
}
if (!txFromRpc.blockNumber) {
throw new Error("Transaction is not mined yet, please wait for it to be mined");
throw new Error("[hardhat-tracer]: Transaction is not mined yet, please wait for it to be mined");
}

@@ -86,13 +101,14 @@ // TODO add support for decoding using debug_tt on the RPC if present, otherwise use hardhat mainnet fork

}
const node = await (0, get_vm_1.getNode)(hre);
const node = await (0, hardhat_1.getNode)(hre);
// we cant use this resp because stack and memory is not there (takes up lot of memory if enabled)
await node.traceTransaction(Buffer.from(args.hash.slice(2), "hex"), {
disableStorage: true,
disableMemory: true,
disableStack: true,
});
// await node.traceTransaction(Buffer.from(args.hash.slice(2), "hex"), {
// disableStorage: true,
// disableMemory: true,
// disableStack: true,
// });
await traceTransctionWithProgress(node, args.hash);
// TODO try to do this properly
// @ts-ignore
const recorder = global?._hardhat_tracer_recorder;
await recorder.previousTraces[recorder.previousTraces.length - 1].print({
await (0, print_1.print)(recorder.previousTraces[recorder.previousTraces.length - 1], {
artifacts: hre.artifacts,

@@ -105,2 +121,88 @@ tracerEnv: hre.tracer,

});
async function traceTransctionWithProgress(node, hash) {
const hashBuffer = Buffer.from(hash.slice(2), "hex");
const block = await node.getBlockByTransactionHash(hashBuffer);
if (block === undefined) {
throw new Error(`Unable to find a block containing transaction ${hash}`);
}
// @ts-ignore
return node._runInBlockContext(block.header.number - 1n, async () => {
const blockNumber = block.header.number;
// @ts-ignore
const blockchain = node._blockchain;
// @ts-ignore
let vm = node._vm;
if (blockchain instanceof ForkBlockchain_1.ForkBlockchain &&
blockNumber <= blockchain.getForkBlockNumber()) {
(0, console_1.assert)(
// @ts-ignore
node._forkNetworkId !== undefined, "this._forkNetworkId should exist if the blockchain is an instance of ForkBlockchain");
// @ts-ignore
const common = node._getCommonForTracing(
// @ts-ignore
node._forkNetworkId, blockNumber);
vm = await ethereumjs_vm_1.VM.create({
common,
activatePrecompiles: true,
// @ts-ignore
stateManager: node._vm.stateManager,
// @ts-ignore
blockchain: node._vm.blockchain,
});
}
// We don't support tracing transactions before the spuriousDragon fork
// to avoid having to distinguish between empty and non-existing accounts.
// We *could* do it during the non-forked mode, but for simplicity we just
// don't support it at all.
const isPreSpuriousDragon = !vm._common.gteHardfork("spuriousDragon");
if (isPreSpuriousDragon) {
throw new Error("Tracing is not supported for transactions using hardforks older than Spurious Dragon. ");
}
let currentProgress = 0;
let totalProgress = 0;
let progressPrinted = Date.now();
for (const tx of block.transactions) {
totalProgress += Number(tx.gasLimit.toString());
if (tx.hash().equals(hashBuffer)) {
break;
}
}
for (const tx of block.transactions) {
let txWithCommon;
const sender = tx.getSenderAddress();
if (tx.type === 0) {
txWithCommon = new FakeSenderTransaction_1.FakeSenderTransaction(sender, tx, {
common: vm._common,
});
}
else if (tx.type === 1) {
txWithCommon = new FakeSenderAccessListEIP2930Transaction_1.FakeSenderAccessListEIP2930Transaction(sender, tx, {
common: vm._common,
});
}
else if (tx.type === 2) {
txWithCommon = new FakeSenderEIP1559Transaction_1.FakeSenderEIP1559Transaction(sender, { ...tx, gasPrice: undefined }, {
common: vm._common,
});
}
else {
// throw new Error("Only legacy, EIP2930, and EIP1559 txs are supported");
continue;
}
const txHash = txWithCommon.hash();
// console.log(txHash.toString("hex"));
if (txHash.equals(hashBuffer)) {
await vm.runTx({ tx: txWithCommon, block });
return; // stop here and print last trace
}
await vm.runTx({ tx: txWithCommon, block });
currentProgress += Number(tx.gasLimit.toString());
if (Date.now() - progressPrinted > 1000) {
console.warn("current progress", Math.floor((currentProgress / totalProgress) * 10000) / 100);
progressPrinted = Date.now();
}
}
throw new Error(`Unable to find a transaction in a block that contains that transaction, this should never happen`);
});
}
//# sourceMappingURL=trace.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ethers_1 = require("ethers");
const config_1 = require("hardhat/config");
const ethers_1 = require("ethers");
const print_1 = require("../print");
(0, utils_1.addCliParams)((0, config_1.task)("tracecall", "Traces a call"))

@@ -13,5 +14,9 @@ .addParam("to", "destination address")

.addOptionalParam("blocknumber", "block number")
.addOptionalParam("from", "from address")
.addOptionalParam("rpc", "archive node")
.setAction(async (args, hre, runSuper) => {
(0, utils_1.applyCliArgsToTracer)(args, hre);
if (!args["nocompile"]) {
await hre.run("compile");
}
// try using current mainnet fork url as rpc url

@@ -26,10 +31,10 @@ const mainnetForkUrl = hre.network.config.forking?.url;

if (userNetworks === undefined) {
throw new Error("No networks found in hardhat config");
throw new Error("[hardhat-tracer]: No networks found in hardhat config");
}
if (userNetworks[args.network] === undefined) {
throw new Error(`Network ${args.network} not found in hardhat config`);
throw new Error(`[hardhat-tracer]: Network ${args.network} not found in hardhat config`);
}
const url = userNetworks[args.network].url;
if (url === undefined) {
throw new Error(`Url not found in hardhat-config->networks->${args.network}`);
throw new Error(`[hardhat-tracer]: Url not found in hardhat-config->networks->${args.network}`);
}

@@ -40,3 +45,3 @@ args.rpc = url;

// TODO add auto-detect network
throw new Error("rpc url not provided, please either use --network <network-name> or --rpc <rpc-url>");
throw new Error("[hardhat-tracer]: rpc url not provided, please either use --network <network-name> or --rpc <rpc-url>");
}

@@ -63,2 +68,3 @@ const provider = new ethers_1.ethers.providers.StaticJsonRpcProvider(args.rpc);

gasPrice: args.gasPrice,
from: args.from,
});

@@ -71,3 +77,3 @@ console.log("result:", result);

const recorder = global?._hardhat_tracer_recorder;
await recorder.previousTraces[recorder.previousTraces.length - 1].print({
await (0, print_1.print)(recorder.previousTraces[recorder.previousTraces.length - 1], {
artifacts: hre.artifacts,

@@ -74,0 +80,0 @@ tracerEnv: hre.tracer,

import { Artifacts } from "hardhat/types";
import { TraceRecorder } from "./trace/recorder";
import { BigNumberish, PopulatedTransaction } from "ethers";
import { CALL } from "./opcodes/call";
import { Decoder } from "./decoder";
import { BigNumberish } from "ethers";
import { InterpreterStep } from "@nomicfoundation/ethereumjs-evm";
import { TracerCache } from "./cache";
import { TraceRecorder } from "./trace-recorder";
import { TransactionTrace } from "./transaction-trace";
declare type PrintMode = "console" | "json";
export interface NameTags {

@@ -27,2 +31,3 @@ [address: string]: string;

nameTags: NameTags;
printMode: PrintMode;
_internal: {

@@ -33,2 +38,3 @@ cache: TracerCache;

recorder?: TraceRecorder;
lastTrace: () => TransactionTrace | undefined;
decoder?: Decoder;

@@ -75,2 +81,34 @@ stateOverrides?: StateOverrides;

};
export interface Item<Params> {
opcode: string;
params: Params;
parent?: Item<Params>;
children?: Item<Params>[];
format?: () => string;
}
export declare type AwaitedItem<T> = {
isAwaitedItem: true;
next: number;
parse: (step: InterpreterStep, currentAddress?: string) => Item<T>;
};
export interface CallItem extends Item<CALL> {
opcode: CALL_OPCODES;
children: Item<any>[];
}
export declare type CALL_OPCODES = "CALL" | "STATICCALL" | "DELEGATECALL" | "CALLCODE" | "CREATE" | "CREATE2";
export interface ChaiMessageCallOptions {
isStaticCall?: boolean;
isDelegateCall?: boolean;
isSuccess?: boolean;
returnData?: string;
from?: string;
}
declare global {
export namespace Chai {
interface Assertion {
messageCall(tx: PopulatedTransaction, options?: ChaiMessageCallOptions): Assertion;
}
}
}
export {};
//# sourceMappingURL=types.d.ts.map

@@ -1,4 +0,2 @@

import { ethers } from "ethers";
import { Artifacts, HardhatRuntimeEnvironment } from "hardhat/types";
import { ProviderLike, TracerEnv } from "./types";
import { HardhatRuntimeEnvironment } from "hardhat/types";
/**

@@ -9,10 +7,2 @@ * Add hardhat-tracer to your environment

export declare function wrapHardhatProvider(hre: HardhatRuntimeEnvironment): void;
/**
* Wrap hardhat-tracer over an ethers provider
* @param provider an ethers provider to attach hardhat-tracer logic
* @param artifacts hre.artifacts
* @param tracerEnv hre.tracer
* @returns
*/
export declare function wrapEthersProvider(provider: ProviderLike, artifacts: Artifacts, tracerEnv?: TracerEnv): ethers.providers.Provider;
//# sourceMappingURL=wrapper.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.wrapEthersProvider = exports.wrapHardhatProvider = void 0;
const ethers_1 = require("ethers");
exports.wrapHardhatProvider = void 0;
const backwards_compatibility_1 = require("hardhat/internal/core/providers/backwards-compatibility");
const wrapper_1 = require("hardhat/internal/core/providers/wrapper");
const cache_1 = require("./cache");
const decoder_1 = require("./decoder");
const utils_1 = require("./utils");
const print_1 = require("./print");
/**

@@ -54,6 +51,7 @@ * Wrapped provider which extends requests

case 4:
shouldPrint = true;
shouldPrint = isSendTransaction || isEthCall || isEstimateGas;
break;
default:
throw new Error("Invalid verbosity value: " + this.dependencies.tracerEnv.verbosity);
throw new Error("[hardhat-tracer]: Invalid verbosity value: " +
this.dependencies.tracerEnv.verbosity);
}

@@ -66,3 +64,6 @@ if (this.dependencies.tracerEnv.enabled && shouldPrint) {

this.dependencies.tracerEnv.printNext = false;
await this.dependencies.tracerEnv.recorder?.previousTraces?.[this.dependencies.tracerEnv.recorder?.previousTraces.length - 1]?.print?.(this.dependencies);
const lastTrace = this.dependencies.tracerEnv.lastTrace();
if (lastTrace) {
await (0, print_1.print)(lastTrace, this.dependencies);
}
}

@@ -92,38 +93,2 @@ }

exports.wrapHardhatProvider = wrapHardhatProvider;
/**
* Wrap hardhat-tracer over an ethers provider
* @param provider an ethers provider to attach hardhat-tracer logic
* @param artifacts hre.artifacts
* @param tracerEnv hre.tracer
* @returns
*/
function wrapEthersProvider(provider, artifacts, tracerEnv) {
// ensure env is present
// const tracerEnv = getTracerEnvFromUserInput(tracerEnvUser);
const cache = new cache_1.TracerCache();
const decoder = new decoder_1.Decoder(artifacts, cache);
if (!tracerEnv) {
tracerEnv = {
enabled: false,
ignoreNext: false,
printNext: false,
verbosity: utils_1.DEFAULT_VERBOSITY,
showAddresses: false,
gasCost: false,
opcodes: new Map(),
nameTags: {},
// @ts-ignore TODO remove, this has no place in "config"
_internal: {
printNameTagTip: undefined,
// tokenDecimalsCache: new Map(),
cache,
},
decoder,
};
}
const tracerProvider = new TracerWrapper({ provider, artifacts, tracerEnv });
const compatibleProvider = new backwards_compatibility_1.BackwardsCompatibilityProviderAdapter(tracerProvider);
return new ethers_1.ethers.providers.Web3Provider(compatibleProvider);
}
exports.wrapEthersProvider = wrapEthersProvider;
//# sourceMappingURL=wrapper.js.map
{
"name": "hardhat-tracer",
"version": "2.0.0-beta.4",
"version": "2.0.0-beta.5",
"description": "Hardhat Tracer plugin",

@@ -40,5 +40,5 @@ "repository": "github:zemse/hardhat-tracer",

"@types/mocha": "^5.2.6",
"@types/node": "^8.10.38",
"@types/node": "^16.0.0",
"@types/readable-stream": "^2.3.14",
"chai": "^4.2.0",
"chai": "^4.3.7",
"hardhat": "^2.12.2",

@@ -55,2 +55,3 @@ "hardhat-deploy": "^0.11.20",

"peerDependencies": {
"chai": "4.x",
"chalk": "4.x",

@@ -57,0 +58,0 @@ "ethers": "5.x",

@@ -0,3 +1,3 @@

import fs from "fs-extra";
import path from "path";
import fs from "fs-extra";

@@ -32,7 +32,11 @@ // To locally cache contract name, decimals, and ABI to prevent async API calls

fs.writeJSONSync(this.getTracerCachePath(), {
tokenDecimals: Array.from(this.tokenDecimals.entries()),
contractNames: Array.from(this.contractNames.entries()),
fourByteDir: Array.from(this.fourByteDir.entries()),
});
fs.writeJSONSync(
this.getTracerCachePath(),
{
tokenDecimals: Array.from(this.tokenDecimals.entries()),
contractNames: Array.from(this.contractNames.entries()),
fourByteDir: Array.from(this.fourByteDir.entries()),
},
{ spaces: 2 }
);
}

@@ -42,3 +46,3 @@

if (!this.cachePath) {
throw new Error("cachePath not set");
throw new Error("[hardhat-tracer]: cachePath not set");
}

@@ -45,0 +49,0 @@ return path.join(this.cachePath, "hardhat-tracer-cache", `data.json`);

export const DEPTH_INDENTATION = " ";
export const SEPARATOR = ": ";
export const DEFAULT_VERBOSITY = 0;

@@ -0,2 +1,4 @@

import { Artifacts } from "hardhat/types";
import { ethers } from "ethers";
import { TracerCache } from "./cache";
import {

@@ -11,4 +13,2 @@ ErrorFragment,

} from "ethers/lib/utils";
import { Artifacts } from "hardhat/types";
import { TracerCache } from "./cache";

@@ -139,3 +139,3 @@ type Mapping<FragmentType> = Map<

if (topics.length === 0) {
throw new Error("No topics, cannot decode");
throw new Error("[hardhat-tracer]: No topics, cannot decode");
}

@@ -142,0 +142,0 @@

@@ -0,8 +1,6 @@

import { DEFAULT_VERBOSITY } from "../constants";
import { extendConfig } from "hardhat/config";
import { HardhatConfig, HardhatUserConfig } from "hardhat/types";
import { TracerCache } from "../cache";
import { TracerEnv, TracerEnvUser } from "../types";
import { DEFAULT_VERBOSITY } from "../utils";

@@ -30,3 +28,3 @@ declare module "hardhat/types/config" {

throw new Error(
"tracer.opcodes in hardhat user config should be array"
"[hardhat-tracer]: tracer.opcodes in hardhat user config should be array"
);

@@ -49,6 +47,7 @@ }

verbosity: userConfig.tracer?.defaultVerbosity ?? DEFAULT_VERBOSITY,
showAddresses: userConfig.tracer?.showAddresses ?? false,
showAddresses: userConfig.tracer?.showAddresses ?? true,
gasCost: userConfig.tracer?.gasCost ?? false,
opcodes,
nameTags: userConfig.tracer?.nameTags ?? {},
printMode: "console",
// @ts-ignore TODO remove, this has no place in "config"

@@ -59,2 +58,9 @@ _internal: {

},
lastTrace: function () {
if (this.recorder) {
return this.recorder.previousTraces[
this.recorder.previousTraces.length - 1
];
}
},
stateOverrides: userConfig.tracer?.stateOverrides,

@@ -61,0 +67,0 @@ };

@@ -0,9 +1,8 @@

import { applyStateOverrides, getVM } from "../utils";
import { Decoder } from "../decoder";
import { extendEnvironment } from "hardhat/config";
import { TraceRecorder } from "../trace-recorder";
import { TracerEnv } from "../types";
import "hardhat/types/config";
import "hardhat/types/runtime";
import { getVM } from "../get-vm";
import { TracerEnv } from "../types";
import { TraceRecorder } from "../trace/recorder";
import { Decoder } from "../decoder";
import { hardhatArguments } from "hardhat";

@@ -28,4 +27,13 @@ declare module "hardhat/types/runtime" {

getVM(hre)
.then((vm) => {
hre.tracer.recorder = new TraceRecorder(vm, hre.tracer, hre.artifacts);
.then(async (vm) => {
hre.tracer.recorder = new TraceRecorder(vm, hre.tracer);
if (hre.tracer.stateOverrides) {
try {
await applyStateOverrides(
hre.tracer.stateOverrides,
vm,
hre.artifacts
);
} catch {}
}
})

@@ -32,0 +40,0 @@ .catch(() => {

import { BigNumber, BigNumberish } from "ethers";
import { colorContract, colorFunction, colorKey } from "../colors";
import { fetchContractDecimals, getBetterContractName } from "../utils";
import { formatParam } from "./param";
import { formatResult } from "./result";
import { SEPARATOR } from "../constants";
import { TracerDependencies } from "../types";
import {
colorContract,
colorFunctionSuccess,
colorFunctioFail,
colorKey,
} from "../utils/colors";
import {
formatEther,

@@ -12,4 +19,2 @@ Fragment,

} from "ethers/lib/utils";
import { SEPARATOR } from "./separator";
import { TracerDependencies } from "../types";

@@ -21,3 +26,4 @@ export async function formatCall(

value: BigNumberish,
gas: BigNumberish,
gasUsed: BigNumberish,
gasLimit: BigNumberish,
success: boolean,

@@ -66,3 +72,3 @@ dependencies: TracerDependencies

// otherwise fetch it
contractDecimals = await fetchContractDecimals(to, dependencies.provider);
contractDecimals = await fetchContractDecimals(to, dependencies);
// and cache it

@@ -82,6 +88,13 @@ if (contractDecimals !== undefined) {

}
if ((gas = BigNumber.from(gas)).gt(0) && dependencies.tracerEnv.gasCost) {
extra.push(`gas${SEPARATOR}${formatParam(gas, dependencies)}`);
if (
(gasLimit = BigNumber.from(gasLimit)).gt(0) &&
(gasUsed = BigNumber.from(gasUsed)).gt(0) &&
dependencies.tracerEnv.gasCost
) {
extra.push(`gasLimit${SEPARATOR}${formatParam(gasLimit, dependencies)}`);
extra.push(`gasUsed${SEPARATOR}${formatParam(gasUsed, dependencies)}`);
}
const colorFunction = success ? colorFunctionSuccess : colorFunctioFail;
if (inputResult && fragment) {

@@ -113,3 +126,3 @@ const inputArgs = formatResult(

}.${colorFunction(fragment.name)}${
extra.length !== 0 ? `{${extra.join(",")}}` : ""
extra.length !== 0 ? `{${extra.join(", ")}}` : ""
}(${inputArgs})${outputArgs ? ` => (${outputArgs})` : ""}`;

@@ -125,3 +138,3 @@ }

}.<${colorFunction("UnknownFunction")}>${
extra.length !== 0 ? `{${extra.join(",")}}` : ""
extra.length !== 0 ? `{${extra.join(", ")}}` : ""
}(${colorKey("input" + SEPARATOR)}${input}, ${colorKey(

@@ -132,3 +145,3 @@ "ret" + SEPARATOR

return `${colorFunction("UnknownContractAndFunction")}${
extra.length !== 0 ? `{${extra.join(",")}}` : ""
extra.length !== 0 ? `{${extra.join(", ")}}` : ""
}(${colorKey("to" + SEPARATOR)}${to}, ${colorKey(

@@ -135,0 +148,0 @@ "input" + SEPARATOR

@@ -0,5 +1,5 @@

import consoleLogMethods from "./console-log-methods.json";
import { ethers } from "ethers";
import { formatResult } from "./result";
import { TracerDependencies } from "../types";
import { formatResult } from "./result";
import consoleLogMethods from "./console-log-methods.json";

@@ -6,0 +6,0 @@ // TODO try to import this from somewhere in hardhat

@@ -0,10 +1,8 @@

import { arrayify, Interface } from "ethers/lib/utils";
import { BigNumber, BigNumberish } from "ethers";
import { arrayify, Interface } from "ethers/lib/utils";
import { colorContract, colorFunction, colorKey } from "../colors";
import { TracerDependencies } from "../types";
import { colorContract, colorFunctionSuccess, colorKey } from "../utils/colors";
import { compareBytecode } from "../utils";
import { formatParam } from "./param";
import { formatResult } from "./result";
import { TracerDependencies } from "../types";

@@ -55,3 +53,3 @@ export async function formatContract(

}
return `${colorContract(artifact.contractName)}.${colorFunction(
return `${colorContract(artifact.contractName)}.${colorFunctionSuccess(
"constructor"

@@ -58,0 +56,0 @@ )}${extra.length !== 0 ? `{${extra.join(",")}}` : ""}(${inputArgs})${

@@ -1,9 +0,6 @@

import { Interface } from "ethers/lib/utils";
import { colorError } from "../colors";
import { TracerDependencies } from "../types";
import { colorError } from "../utils/colors";
import { formatObject } from "./object";
import { formatParam } from "./param";
import { formatResult } from "./result";
import { TracerDependencies } from "../types";

@@ -10,0 +7,0 @@ export async function formatError(

@@ -1,2 +0,2 @@

import { colorContract, colorEvent } from "../colors";
import { colorContract, colorEvent } from "../utils/colors";
import { EventFragment, Result } from "ethers/lib/utils";

@@ -3,0 +3,0 @@ import { formatParam } from "./param";

@@ -1,3 +0,3 @@

import { colorKey } from "../colors";
import { SEPARATOR } from "./separator";
import { colorKey } from "../utils";
import { SEPARATOR } from "../constants";

@@ -4,0 +4,0 @@ export function formatObject(obj: any) {

import { BigNumber } from "ethers";
import { colorIndexed, colorNameTag } from "../utils";
import { getAddress } from "ethers/lib/utils";
import { colorIndexed, colorNameTag } from "../colors";
import { getFromNameTags } from "../utils";
import { SEPARATOR } from "../constants";
import { TracerDependencies } from "../types";
import { getFromNameTags } from "../utils";
import { SEPARATOR } from "./separator";

@@ -9,0 +8,0 @@ export function formatParam(

import { BigNumber } from "ethers";
import {
formatUnits,
Fragment,
FunctionFragment,
ParamType,
Result,
} from "ethers/lib/utils";
import { colorKey } from "../colors";
import { colorKey } from "../utils/colors";
import { formatParam } from "./param";
import { formatUnits, ParamType, Result } from "ethers/lib/utils";
import { TracerDependencies } from "../types";
import { formatParam } from "./param";
interface FormatOptions {

@@ -16,0 +8,0 @@ decimals?: number;

import "./extend";
import "./tasks";
import "./chai";
export * from "./types";
export * from "./wrapper";

@@ -0,3 +1,4 @@

import { applyStateOverrides } from "../utils";
import { task } from "hardhat/config";
import { TASK_COMPILE_SOLIDITY_EMIT_ARTIFACTS } from "hardhat/builtin-tasks/task-names";
import { task } from "hardhat/config";

@@ -13,4 +14,13 @@ task(TASK_COMPILE_SOLIDITY_EMIT_ARTIFACTS).setAction(

// if state overrides are provided, then apply them after compilation
if (hre.tracer.stateOverrides && hre.tracer.recorder?.vm) {
applyStateOverrides(
hre.tracer.stateOverrides,
hre.tracer.recorder?.vm,
hre.artifacts
);
}
return result;
}
);

@@ -0,6 +1,6 @@

import { addCliParams, removeColor } from "../utils";
import { ethers } from "ethers";
import { task } from "hardhat/config";
import { formatCall } from "../format/call";
import { formatError } from "../format/error";
import { addCliParams, removeColor } from "../utils";
import { task } from "hardhat/config";

@@ -24,2 +24,3 @@ addCliParams(task("decode", "Decodes calldata or error data"))

0,
0,
true,

@@ -26,0 +27,0 @@ td

@@ -0,5 +1,4 @@

import { addCliParams, applyCliArgsToTracer } from "../utils";
import { task } from "hardhat/config";
import { TASK_TEST } from "hardhat/builtin-tasks/task-names";
import { task } from "hardhat/config";
import { addCliParams, applyCliArgsToTracer } from "../utils";
import { wrapHardhatProvider } from "../wrapper";

@@ -6,0 +5,0 @@

@@ -0,10 +1,20 @@

import { assert } from "console";
import { ethers } from "ethers";
import { FakeSenderAccessListEIP2930Transaction } from "hardhat/internal/hardhat-network/provider/transactions/FakeSenderAccessListEIP2930Transaction";
import { FakeSenderEIP1559Transaction } from "hardhat/internal/hardhat-network/provider/transactions/FakeSenderEIP1559Transaction";
import { FakeSenderTransaction } from "hardhat/internal/hardhat-network/provider/transactions/FakeSenderTransaction";
import { ForkBlockchain } from "hardhat/internal/hardhat-network/provider/fork/ForkBlockchain";
import { getNode } from "../utils/hardhat";
import { HardhatNode } from "hardhat/internal/hardhat-network/provider/node";
import { HttpNetworkUserConfig } from "hardhat/types";
import { task } from "hardhat/config";
import { getNode } from "../get-vm";
import { addCliParams, applyCliArgsToTracer } from "../utils";
import { TraceRecorder } from "../trace-recorder";
import { TypedTransaction } from "@nomicfoundation/ethereumjs-tx";
import { VM } from "@nomicfoundation/ethereumjs-vm";
import { TraceRecorder } from "../trace/recorder";
import { HttpNetworkUserConfig } from "hardhat/types";
import {
addCliParams,
applyCliArgsToTracer,
applyStateOverrides,
} from "../utils";
import { print } from "../print";

@@ -20,3 +30,8 @@ const originalCreate = VM.create;

const hreArtifacts = global.hreArtifacts;
const recorder = new TraceRecorder(vm, tracerEnv, hreArtifacts);
const recorder = new TraceRecorder(vm, tracerEnv);
if (tracerEnv.stateOverrides) {
try {
await applyStateOverrides(tracerEnv.stateOverrides, vm, hreArtifacts);
} catch {}
}
tracerEnv.recorder = recorder;

@@ -35,2 +50,6 @@ // @ts-ignore

if (!args["nocompile"]) {
await hre.run("compile");
}
const tx = await hre.network.provider.send("eth_getTransactionByHash", [

@@ -46,7 +65,9 @@ args.hash,

if (userNetworks === undefined) {
throw new Error("No networks found in hardhat config");
throw new Error(
"[hardhat-tracer]: No networks found in hardhat config"
);
}
if (userNetworks[args.network] === undefined) {
throw new Error(
`Network ${args.network} not found in hardhat config`
`[hardhat-tracer]: Network ${args.network} not found in hardhat config`
);

@@ -57,3 +78,3 @@ }

throw new Error(
`Url not found in hardhat-config->networks->${args.network}`
`[hardhat-tracer]: Url not found in hardhat-config->networks->${args.network}`
);

@@ -73,3 +94,3 @@ }

throw new Error(
"rpc url not provided, please either use --network <network-name> or --rpc <rpc-url>"
"[hardhat-tracer]: rpc url not provided, please either use --network <network-name> or --rpc <rpc-url>"
);

@@ -82,3 +103,3 @@ }

throw new Error(
"Transaction not found on rpc. Are you sure the transaction is confirmed on this network?"
"[hardhat-tracer]: Transaction not found on rpc. Are you sure the transaction is confirmed on this network?"
);

@@ -89,3 +110,3 @@ }

throw new Error(
"Transaction is not mined yet, please wait for it to be mined"
"[hardhat-tracer]: Transaction is not mined yet, please wait for it to be mined"
);

@@ -117,7 +138,8 @@ }

// we cant use this resp because stack and memory is not there (takes up lot of memory if enabled)
await node.traceTransaction(Buffer.from(args.hash.slice(2), "hex"), {
disableStorage: true,
disableMemory: true,
disableStack: true,
});
// await node.traceTransaction(Buffer.from(args.hash.slice(2), "hex"), {
// disableStorage: true,
// disableMemory: true,
// disableStack: true,
// });
await traceTransctionWithProgress(node, args.hash);

@@ -128,3 +150,3 @@ // TODO try to do this properly

await recorder.previousTraces[recorder.previousTraces.length - 1].print({
await print(recorder.previousTraces[recorder.previousTraces.length - 1], {
artifacts: hre.artifacts,

@@ -138,1 +160,110 @@ tracerEnv: hre.tracer,

});
async function traceTransctionWithProgress(node: HardhatNode, hash: string) {
const hashBuffer = Buffer.from(hash.slice(2), "hex");
const block = await node.getBlockByTransactionHash(hashBuffer);
if (block === undefined) {
throw new Error(`Unable to find a block containing transaction ${hash}`);
}
// @ts-ignore
return node._runInBlockContext(block.header.number - 1n, async () => {
const blockNumber = block.header.number;
// @ts-ignore
const blockchain = node._blockchain;
// @ts-ignore
let vm = node._vm;
if (
blockchain instanceof ForkBlockchain &&
blockNumber <= blockchain.getForkBlockNumber()
) {
assert(
// @ts-ignore
node._forkNetworkId !== undefined,
"this._forkNetworkId should exist if the blockchain is an instance of ForkBlockchain"
);
// @ts-ignore
const common = node._getCommonForTracing(
// @ts-ignore
node._forkNetworkId,
blockNumber
);
vm = await VM.create({
common,
activatePrecompiles: true,
// @ts-ignore
stateManager: node._vm.stateManager,
// @ts-ignore
blockchain: node._vm.blockchain,
});
}
// We don't support tracing transactions before the spuriousDragon fork
// to avoid having to distinguish between empty and non-existing accounts.
// We *could* do it during the non-forked mode, but for simplicity we just
// don't support it at all.
const isPreSpuriousDragon = !vm._common.gteHardfork("spuriousDragon");
if (isPreSpuriousDragon) {
throw new Error(
"Tracing is not supported for transactions using hardforks older than Spurious Dragon. "
);
}
let currentProgress = 0;
let totalProgress = 0;
let progressPrinted = Date.now();
for (const tx of block.transactions) {
totalProgress += Number(tx.gasLimit.toString());
if (tx.hash().equals(hashBuffer)) {
break;
}
}
for (const tx of block.transactions) {
let txWithCommon: TypedTransaction;
const sender = tx.getSenderAddress();
if (tx.type === 0) {
txWithCommon = new FakeSenderTransaction(sender, tx, {
common: vm._common,
});
} else if (tx.type === 1) {
txWithCommon = new FakeSenderAccessListEIP2930Transaction(sender, tx, {
common: vm._common,
});
} else if (tx.type === 2) {
txWithCommon = new FakeSenderEIP1559Transaction(
sender,
{ ...tx, gasPrice: undefined },
{
common: vm._common,
}
);
} else {
// throw new Error("Only legacy, EIP2930, and EIP1559 txs are supported");
continue;
}
const txHash = txWithCommon.hash();
// console.log(txHash.toString("hex"));
if (txHash.equals(hashBuffer)) {
await vm.runTx({ tx: txWithCommon, block });
return; // stop here and print last trace
}
await vm.runTx({ tx: txWithCommon, block });
currentProgress += Number(tx.gasLimit.toString());
if (Date.now() - progressPrinted > 1000) {
console.warn(
"current progress",
Math.floor((currentProgress / totalProgress) * 10000) / 100
);
progressPrinted = Date.now();
}
}
throw new Error(
`Unable to find a transaction in a block that contains that transaction, this should never happen`
);
});
}
import { addCliParams, applyCliArgsToTracer } from "../utils";
import { ethers } from "ethers";
import { HttpNetworkUserConfig } from "hardhat/types";
import { task } from "hardhat/config";
import { TraceRecorder } from "../trace/recorder";
import { ethers } from "ethers";
import { TraceRecorder } from "../trace-recorder";
import { print } from "../print";

@@ -14,2 +15,3 @@ addCliParams(task("tracecall", "Traces a call"))

.addOptionalParam("blocknumber", "block number")
.addOptionalParam("from", "from address")
.addOptionalParam("rpc", "archive node")

@@ -19,2 +21,6 @@ .setAction(async (args, hre, runSuper) => {

if (!args["nocompile"]) {
await hre.run("compile");
}
// try using current mainnet fork url as rpc url

@@ -30,6 +36,10 @@ const mainnetForkUrl = (hre.network.config as any).forking?.url;

if (userNetworks === undefined) {
throw new Error("No networks found in hardhat config");
throw new Error(
"[hardhat-tracer]: No networks found in hardhat config"
);
}
if (userNetworks[args.network] === undefined) {
throw new Error(`Network ${args.network} not found in hardhat config`);
throw new Error(
`[hardhat-tracer]: Network ${args.network} not found in hardhat config`
);
}

@@ -39,3 +49,3 @@ const url = (userNetworks[args.network] as HttpNetworkUserConfig).url;

throw new Error(
`Url not found in hardhat-config->networks->${args.network}`
`[hardhat-tracer]: Url not found in hardhat-config->networks->${args.network}`
);

@@ -49,3 +59,3 @@ }

throw new Error(
"rpc url not provided, please either use --network <network-name> or --rpc <rpc-url>"
"[hardhat-tracer]: rpc url not provided, please either use --network <network-name> or --rpc <rpc-url>"
);

@@ -76,2 +86,3 @@ }

gasPrice: args.gasPrice,
from: args.from,
});

@@ -84,3 +95,3 @@ console.log("result:", result);

await recorder.previousTraces[recorder.previousTraces.length - 1].print({
await print(recorder.previousTraces[recorder.previousTraces.length - 1], {
artifacts: hre.artifacts,

@@ -87,0 +98,0 @@ tracerEnv: hre.tracer,

import { Artifacts } from "hardhat/types";
import { TraceRecorder } from "./trace/recorder";
import { BigNumberish, PopulatedTransaction } from "ethers";
import { CALL } from "./opcodes/call";
import { Decoder } from "./decoder";
import { BigNumberish } from "ethers";
import { InterpreterStep } from "@nomicfoundation/ethereumjs-evm";
import { TracerCache } from "./cache";
import { TraceRecorder } from "./trace-recorder";
import { TransactionTrace } from "./transaction-trace";
type PrintMode = "console" | "json";
export interface NameTags {

@@ -30,2 +35,3 @@ [address: string]: string;

nameTags: NameTags;
printMode: PrintMode;
// todo remove internal

@@ -40,2 +46,3 @@ _internal: {

recorder?: TraceRecorder;
lastTrace: () => TransactionTrace | undefined;
decoder?: Decoder;

@@ -90,1 +97,47 @@ stateOverrides?: StateOverrides;

};
export interface Item<Params> {
opcode: string;
params: Params;
parent?: Item<Params>;
children?: Item<Params>[];
format?: () => string;
}
export type AwaitedItem<T> = {
isAwaitedItem: true;
next: number;
parse: (step: InterpreterStep, currentAddress?: string) => Item<T>;
};
export interface CallItem extends Item<CALL> {
opcode: CALL_OPCODES;
children: Item<any>[];
}
export type CALL_OPCODES =
| "CALL"
| "STATICCALL"
| "DELEGATECALL"
| "CALLCODE"
| "CREATE"
| "CREATE2";
export interface ChaiMessageCallOptions {
isStaticCall?: boolean;
isDelegateCall?: boolean;
isSuccess?: boolean;
returnData?: string;
from?: string;
}
declare global {
export namespace Chai {
interface Assertion {
messageCall(
tx: PopulatedTransaction,
options?: ChaiMessageCallOptions
): Assertion;
}
}
}

@@ -1,6 +0,6 @@

import { ethers } from "ethers";
import { BackwardsCompatibilityProviderAdapter } from "hardhat/internal/core/providers/backwards-compatibility";
import { ProviderWrapper } from "hardhat/internal/core/providers/wrapper";
import { TracerDependencies } from "./types";
import {
Artifacts,
EIP1193Provider,

@@ -10,8 +10,4 @@ HardhatRuntimeEnvironment,

} from "hardhat/types";
import { TracerCache } from "./cache";
import { Decoder } from "./decoder";
import { print } from "./print";
import { ProviderLike, TracerDependencies, TracerEnv } from "./types";
import { DEFAULT_VERBOSITY } from "./utils";
/**

@@ -71,7 +67,8 @@ * Wrapped provider which extends requests

case 4:
shouldPrint = true;
shouldPrint = isSendTransaction || isEthCall || isEstimateGas;
break;
default:
throw new Error(
"Invalid verbosity value: " + this.dependencies.tracerEnv.verbosity
"[hardhat-tracer]: Invalid verbosity value: " +
this.dependencies.tracerEnv.verbosity
);

@@ -85,5 +82,6 @@ }

this.dependencies.tracerEnv.printNext = false;
await this.dependencies.tracerEnv.recorder?.previousTraces?.[
this.dependencies.tracerEnv.recorder?.previousTraces.length - 1
]?.print?.(this.dependencies);
const lastTrace = this.dependencies.tracerEnv.lastTrace();
if (lastTrace) {
await print(lastTrace, this.dependencies);
}
}

@@ -117,45 +115,1 @@ }

}
/**
* Wrap hardhat-tracer over an ethers provider
* @param provider an ethers provider to attach hardhat-tracer logic
* @param artifacts hre.artifacts
* @param tracerEnv hre.tracer
* @returns
*/
export function wrapEthersProvider(
provider: ProviderLike,
artifacts: Artifacts,
tracerEnv?: TracerEnv
): ethers.providers.Provider {
// ensure env is present
// const tracerEnv = getTracerEnvFromUserInput(tracerEnvUser);
const cache = new TracerCache();
const decoder = new Decoder(artifacts, cache);
if (!tracerEnv) {
tracerEnv = {
enabled: false,
ignoreNext: false,
printNext: false,
verbosity: DEFAULT_VERBOSITY,
showAddresses: false,
gasCost: false,
opcodes: new Map(),
nameTags: {},
// @ts-ignore TODO remove, this has no place in "config"
_internal: {
printNameTagTip: undefined,
// tokenDecimalsCache: new Map(),
cache,
},
decoder,
};
}
const tracerProvider = new TracerWrapper({ provider, artifacts, tracerEnv });
const compatibleProvider = new BackwardsCompatibilityProviderAdapter(
tracerProvider
);
return new ethers.providers.Web3Provider(compatibleProvider as any);
}

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

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc