viem-tracer
Version:
[![npm package][npm-img]][npm-url] [![Build Status][build-img]][build-url] [![Downloads][downloads-img]][downloads-url] [![Issues][issues-img]][issues-url] [![Commitizen Friendly][commitizen-img]][commitizen-url] [![Semantic Release][semantic-release-img]
113 lines (112 loc) • 4.87 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExecutionRevertedTraceError = void 0;
exports.traced = traced;
const viem_1 = require("viem");
const format_1 = require("./format");
class ExecutionRevertedTraceError extends viem_1.BaseError {
static code = 3;
static nodeMessage = /execution reverted/;
constructor(trace, message = "execution reverted for an unknown reason.") {
super(message, {
name: "ExecutionRevertedError",
metaMessages: [trace],
});
}
}
exports.ExecutionRevertedTraceError = ExecutionRevertedTraceError;
/**
* @description Overloads a transport intended to be used with a test client, to trace and debug transactions.
*/
function traced(transport, { all = false, next, failed = true, gas, raw } = {}) {
// @ts-ignore: complex overload
return (...config) => {
const instance = transport(...config);
instance.value = {
...instance.value,
tracer: { all, next, failed, gas, raw },
};
return {
...instance,
async request(args, options) {
const { method, params } = args;
if (method !== "eth_estimateGas" &&
method !== "eth_sendTransaction" &&
method !== "wallet_sendTransaction")
return instance.request(args, options);
const { tracer } = instance.value;
// @ts-expect-error: params[0] is the rpc transaction request
const tx = params[0];
const traceCall = async (message) => {
const trace = await instance.request({
method: "debug_traceCall",
params: [
tx,
// @ts-expect-error: params[1] is either undefined or the block identifier
params[1] || "latest",
{
// @ts-expect-error: params[2] may contain state and block overrides
...params[2],
tracer: "callTracer",
tracerConfig: {
onlyTopCall: false,
withLog: true,
},
},
],
}, { retryCount: 0 });
return new ExecutionRevertedTraceError(await (0, format_1.formatFullTrace)(trace, tracer), message || trace.revertReason || trace.error);
};
if (tracer.next || (tracer.next == null && tracer.all)) {
try {
console.log((await traceCall()).metaMessages[0]);
}
catch (error) {
console.warn("Failed to trace transaction:");
console.trace(error);
}
}
const res = await instance
.request(args, options)
.catch(async (error) => {
if (tracer.next || (tracer.next == null && tracer.failed)) {
const trace = await traceCall(error.details);
trace.stack = error.stack;
throw trace;
}
throw error;
})
.finally(() => {
tracer.next = undefined;
});
if (method !== "eth_estimateGas") {
let receipt = null;
try {
for (let i = 0; i < 720; i++) {
receipt = await instance.request({
method: "eth_getTransactionReceipt",
params: [res],
});
if (receipt)
break;
await new Promise((resolve) => setTimeout(resolve, 250));
}
if (!receipt)
throw new viem_1.WaitForTransactionReceiptTimeoutError({
hash: res,
});
if (receipt.status === "0x0")
throw await traceCall();
}
catch (error) {
if (error instanceof ExecutionRevertedTraceError)
throw error;
console.warn("Failed to trace transaction:");
console.trace(error);
}
}
return res;
},
};
};
}