viem-tx-sim 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +228 -0
- package/contracts/TxSimulator.sol +305 -0
- package/dist/constants.d.ts +15 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +15 -0
- package/dist/constants.js.map +1 -0
- package/dist/errors.d.ts +35 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +39 -0
- package/dist/errors.js.map +1 -0
- package/dist/generated/txSimulatorBytecode.d.ts +2 -0
- package/dist/generated/txSimulatorBytecode.d.ts.map +1 -0
- package/dist/generated/txSimulatorBytecode.js +3 -0
- package/dist/generated/txSimulatorBytecode.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/data.d.ts +8 -0
- package/dist/internal/data.d.ts.map +1 -0
- package/dist/internal/data.js +31 -0
- package/dist/internal/data.js.map +1 -0
- package/dist/internal/probes.d.ts +29 -0
- package/dist/internal/probes.d.ts.map +1 -0
- package/dist/internal/probes.js +159 -0
- package/dist/internal/probes.js.map +1 -0
- package/dist/internal/requirements.d.ts +5 -0
- package/dist/internal/requirements.d.ts.map +1 -0
- package/dist/internal/requirements.js +173 -0
- package/dist/internal/requirements.js.map +1 -0
- package/dist/internal/rpc.d.ts +36 -0
- package/dist/internal/rpc.d.ts.map +1 -0
- package/dist/internal/rpc.js +124 -0
- package/dist/internal/rpc.js.map +1 -0
- package/dist/internal/simulator.d.ts +33 -0
- package/dist/internal/simulator.d.ts.map +1 -0
- package/dist/internal/simulator.js +199 -0
- package/dist/internal/simulator.js.map +1 -0
- package/dist/internal/slots.d.ts +7 -0
- package/dist/internal/slots.d.ts.map +1 -0
- package/dist/internal/slots.js +129 -0
- package/dist/internal/slots.js.map +1 -0
- package/dist/txSimulator.d.ts +83 -0
- package/dist/txSimulator.d.ts.map +1 -0
- package/dist/txSimulator.js +75 -0
- package/dist/txSimulator.js.map +1 -0
- package/dist/types.d.ts +214 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +82 -0
- package/src/constants.ts +15 -0
- package/src/errors.ts +45 -0
- package/src/generated/txSimulatorBytecode.ts +5 -0
- package/src/index.ts +34 -0
- package/src/internal/data.ts +36 -0
- package/src/internal/probes.ts +221 -0
- package/src/internal/requirements.ts +240 -0
- package/src/internal/rpc.ts +207 -0
- package/src/internal/simulator.ts +306 -0
- package/src/internal/slots.ts +211 -0
- package/src/txSimulator.ts +176 -0
- package/src/types.ts +240 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { numberToHex } from "viem";
|
|
2
|
+
import { AccessListUnsupportedError } from "../errors.js";
|
|
3
|
+
/** Returns the block selector for RPC calls; `blockNumber` takes precedence over `blockTag`. */
|
|
4
|
+
export function blockOptionsSpread(args) {
|
|
5
|
+
return args.blockNumber !== undefined
|
|
6
|
+
? { blockNumber: args.blockNumber }
|
|
7
|
+
: args.blockTag !== undefined
|
|
8
|
+
? { blockTag: args.blockTag }
|
|
9
|
+
: {};
|
|
10
|
+
}
|
|
11
|
+
export function buildCallParameters(args) {
|
|
12
|
+
const base = {
|
|
13
|
+
account: args.account,
|
|
14
|
+
to: args.to,
|
|
15
|
+
data: args.data,
|
|
16
|
+
...(args.stateOverride !== undefined ? { stateOverride: args.stateOverride } : {}),
|
|
17
|
+
...(args.gas !== undefined ? { gas: args.gas } : {}),
|
|
18
|
+
};
|
|
19
|
+
return (args.blockNumber !== undefined
|
|
20
|
+
? { ...base, blockNumber: args.blockNumber }
|
|
21
|
+
: { ...base, ...(args.blockTag !== undefined ? { blockTag: args.blockTag } : {}) });
|
|
22
|
+
}
|
|
23
|
+
export async function createAccessList(args) {
|
|
24
|
+
const request = {
|
|
25
|
+
from: args.from,
|
|
26
|
+
to: args.to,
|
|
27
|
+
data: args.data,
|
|
28
|
+
...(args.value !== undefined ? { value: numberToHex(args.value) } : {}),
|
|
29
|
+
...(args.gas !== undefined ? { gas: numberToHex(args.gas) } : {}),
|
|
30
|
+
};
|
|
31
|
+
const block = args.blockNumber !== undefined ? numberToHex(args.blockNumber) : (args.blockTag ?? "latest");
|
|
32
|
+
try {
|
|
33
|
+
const result = await withRpcDebug(args.debug, {
|
|
34
|
+
method: "eth_createAccessList",
|
|
35
|
+
step: args.debugStep ?? "createAccessList",
|
|
36
|
+
details: {
|
|
37
|
+
from: args.from,
|
|
38
|
+
to: args.to,
|
|
39
|
+
hasValue: (args.value ?? 0n) > 0n,
|
|
40
|
+
hasGas: args.gas !== undefined,
|
|
41
|
+
},
|
|
42
|
+
}, () => requestAccessList(args.client, request, block));
|
|
43
|
+
if (result.accessList !== undefined)
|
|
44
|
+
return result.accessList;
|
|
45
|
+
if (isRpcExecutionRevert(result.error))
|
|
46
|
+
return [];
|
|
47
|
+
throw new Error(formatRpcError("eth_createAccessList returned no access list", result.error));
|
|
48
|
+
}
|
|
49
|
+
catch (cause) {
|
|
50
|
+
if (isExecutionRevert(cause))
|
|
51
|
+
return [];
|
|
52
|
+
throw new AccessListUnsupportedError(formatRpcError("eth_createAccessList failed", cause));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export function formatRpcError(prefix, cause) {
|
|
56
|
+
if (cause instanceof Error && cause.message)
|
|
57
|
+
return `${prefix}: ${cause.message}`;
|
|
58
|
+
return prefix;
|
|
59
|
+
}
|
|
60
|
+
function isExecutionRevert(cause) {
|
|
61
|
+
if (!(cause instanceof Error))
|
|
62
|
+
return false;
|
|
63
|
+
return /execution reverted|Execution reverted/i.test(cause.message);
|
|
64
|
+
}
|
|
65
|
+
function isRpcExecutionRevert(error) {
|
|
66
|
+
const message = typeof error === "string" ? error : error?.message;
|
|
67
|
+
return message !== undefined && /execution reverted|Execution reverted/i.test(message);
|
|
68
|
+
}
|
|
69
|
+
async function requestAccessList(client, request, block) {
|
|
70
|
+
return client.request({
|
|
71
|
+
method: "eth_createAccessList",
|
|
72
|
+
params: [request, block],
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
export function emitDebug(debug, event) {
|
|
76
|
+
if (typeof debug === "function") {
|
|
77
|
+
debug(event);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (debug === true || envDebugEnabled()) {
|
|
81
|
+
console.debug(formatDebugEvent(event));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
export async function withRpcDebug(debug, event, run) {
|
|
85
|
+
const startedAt = Date.now();
|
|
86
|
+
emitDebug(debug, { ...event, phase: "start" });
|
|
87
|
+
try {
|
|
88
|
+
const result = await run();
|
|
89
|
+
emitDebug(debug, { ...event, phase: "success", durationMs: Date.now() - startedAt });
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
emitDebug(debug, {
|
|
94
|
+
...event,
|
|
95
|
+
phase: "error",
|
|
96
|
+
durationMs: Date.now() - startedAt,
|
|
97
|
+
error: error instanceof Error ? error.message : String(error),
|
|
98
|
+
});
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function envDebugEnabled() {
|
|
103
|
+
const env = globalThis.process
|
|
104
|
+
?.env;
|
|
105
|
+
return env?.VIEM_TX_SIM_DEBUG_RPC === "1" || env?.DEBUG_RPC === "1";
|
|
106
|
+
}
|
|
107
|
+
function formatDebugEvent(event) {
|
|
108
|
+
const parts = [
|
|
109
|
+
`[viem-tx-sim] ${event.phase} ${event.method}`,
|
|
110
|
+
`step=${event.step}`,
|
|
111
|
+
...(event.durationMs === undefined ? [] : [`durationMs=${event.durationMs}`]),
|
|
112
|
+
...Object.entries(event.details ?? {}).map(([key, value]) => `${key}=${formatValue(value)}`),
|
|
113
|
+
...(event.error ? [`error=${event.error}`] : []),
|
|
114
|
+
];
|
|
115
|
+
return parts.join(" ");
|
|
116
|
+
}
|
|
117
|
+
function formatValue(value) {
|
|
118
|
+
if (typeof value === "bigint")
|
|
119
|
+
return value.toString();
|
|
120
|
+
if (Array.isArray(value))
|
|
121
|
+
return `[${value.map(formatValue).join(",")}]`;
|
|
122
|
+
return String(value);
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=rpc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../src/internal/rpc.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAEnC,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAmB1D,gGAAgG;AAChG,MAAM,UAAU,kBAAkB,CAAC,IAAkB;IACnD,OAAO,IAAI,CAAC,WAAW,KAAK,SAAS;QACnC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE;QACnC,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS;YAC3B,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE;YAC7B,CAAC,CAAC,EAAE,CAAC;AACX,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,IAMgB;IAEhB,MAAM,IAAI,GAAG;QACX,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,GAAG,CAAC,IAAI,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClF,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrD,CAAC;IACF,OAAO,CACL,IAAI,CAAC,WAAW,KAAK,SAAS;QAC5B,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE;QAC5C,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAC5D,CAAC;AAC7B,CAAC;AAkBD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAMC;IAED,MAAM,OAAO,GAAG;QACd,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACnC,CAAC;IACjC,MAAM,KAAK,GACT,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,CAAC;IAE/F,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAC/B,IAAI,CAAC,KAAK,EACV;YACE,MAAM,EAAE,sBAAsB;YAC9B,IAAI,EAAE,IAAI,CAAC,SAAS,IAAI,kBAAkB;YAC1C,OAAO,EAAE;gBACP,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,EAAE,EAAE,IAAI,CAAC,EAAE;gBACX,QAAQ,EAAE,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,EAAE;gBACjC,MAAM,EAAE,IAAI,CAAC,GAAG,KAAK,SAAS;aAC/B;SACF,EACD,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,CACrD,CAAC;QACF,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC,UAAU,CAAC;QAC9D,IAAI,oBAAoB,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,8CAA8C,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAChG,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,iBAAiB,CAAC,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QACxC,MAAM,IAAI,0BAA0B,CAAC,cAAc,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC,CAAC;IAC7F,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,KAAc;IAC3D,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO;QAAE,OAAO,GAAG,MAAM,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;IAClF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAc;IACvC,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5C,OAAO,wCAAwC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AACtE,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAmC;IAC/D,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC;IACnE,OAAO,OAAO,KAAK,SAAS,IAAI,wCAAwC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACzF,CAAC;AAED,KAAK,UAAU,iBAAiB,CAC9B,MAAoB,EACpB,OAA6B,EAC7B,KAAqB;IAErB,OAAO,MAAM,CAAC,OAAO,CAIlB;QACD,MAAM,EAAE,sBAAsB;QAC9B,MAAM,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC;KACzB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAkC,EAAE,KAA2B;IACvF,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;QAChC,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,OAAO;IACT,CAAC;IAED,IAAI,KAAK,KAAK,IAAI,IAAI,eAAe,EAAE,EAAE,CAAC;QACxC,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;IACzC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAkC,EAClC,KAA0C,EAC1C,GAAqB;IAErB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,SAAS,CAAC,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IAE/C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC;QAC3B,SAAS,CAAC,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC,CAAC;QACrF,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,SAAS,CAAC,KAAK,EAAE;YACf,GAAG,KAAK;YACR,KAAK,EAAE,OAAO;YACd,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;YAClC,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAC9D,CAAC,CAAC;QACH,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,eAAe;IACtB,MAAM,GAAG,GAAI,UAAyE,CAAC,OAAO;QAC5F,EAAE,GAAG,CAAC;IACR,OAAO,GAAG,EAAE,qBAAqB,KAAK,GAAG,IAAI,GAAG,EAAE,SAAS,KAAK,GAAG,CAAC;AACtE,CAAC;AAED,SAAS,gBAAgB,CAAC,KAA2B;IACnD,MAAM,KAAK,GAAG;QACZ,iBAAiB,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE;QAC9C,QAAQ,KAAK,CAAC,IAAI,EAAE;QACpB,GAAG,CAAC,KAAK,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,cAAc,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;QAC7E,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5F,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KACjD,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;IACvD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IACzE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Abi, Address, StateOverride } from "viem";
|
|
2
|
+
import type { SimulatedCall, SimulationResult, TokenSlotOverride } from "../types.js";
|
|
3
|
+
import type { RpcCallArgs } from "./rpc.js";
|
|
4
|
+
type ProbeData = {
|
|
5
|
+
observedTokens: Address[];
|
|
6
|
+
candidates: Address[];
|
|
7
|
+
maxTokenOutflows: readonly bigint[];
|
|
8
|
+
maxNativeOutflow: bigint;
|
|
9
|
+
allowanceCheckpoints: readonly bigint[];
|
|
10
|
+
};
|
|
11
|
+
export type SimulatorResult = SimulationResult & {
|
|
12
|
+
probeData: ProbeData;
|
|
13
|
+
};
|
|
14
|
+
export declare function runSimulator(args: RpcCallArgs & {
|
|
15
|
+
from: Address;
|
|
16
|
+
calls: readonly SimulatedCall[];
|
|
17
|
+
candidates: readonly Address[];
|
|
18
|
+
tokenSlotOverrides?: readonly TokenSlotOverride[];
|
|
19
|
+
extraStateOverrides?: readonly StateOverrideEntry[];
|
|
20
|
+
allowanceProbes?: readonly {
|
|
21
|
+
token: Address;
|
|
22
|
+
spender: Address;
|
|
23
|
+
}[];
|
|
24
|
+
debugStep?: string;
|
|
25
|
+
errorAbi?: Abi;
|
|
26
|
+
}): Promise<SimulatorResult>;
|
|
27
|
+
export declare function discoverCandidateAddresses(args: RpcCallArgs & {
|
|
28
|
+
from: Address;
|
|
29
|
+
calls: readonly SimulatedCall[];
|
|
30
|
+
}): Promise<Address[]>;
|
|
31
|
+
type StateOverrideEntry = StateOverride[number];
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=simulator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simulator.d.ts","sourceRoot":"","sources":["../../src/internal/simulator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAO,aAAa,EAAE,MAAM,MAAM,CAAC;AAU7D,OAAO,KAAK,EAEV,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAWrB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAS5C,KAAK,SAAS,GAAG;IACf,cAAc,EAAE,OAAO,EAAE,CAAC;IAC1B,UAAU,EAAE,OAAO,EAAE,CAAC;IACtB,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG;IAC/C,SAAS,EAAE,SAAS,CAAC;CACtB,CAAC;AAUF,wBAAsB,YAAY,CAChC,IAAI,EAAE,WAAW,GAAG;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IAChC,UAAU,EAAE,SAAS,OAAO,EAAE,CAAC;IAC/B,kBAAkB,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAClD,mBAAmB,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACpD,eAAe,CAAC,EAAE,SAAS;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,GAAG,CAAC;CAChB,GACA,OAAO,CAAC,eAAe,CAAC,CAmH1B;AAED,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,WAAW,GAAG;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;CACjC,GACA,OAAO,CAAC,OAAO,EAAE,CAAC,CAsBpB;AA8BD,KAAK,kBAAkB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { decodeErrorResult, decodeFunctionResult, encodeFunctionData, parseAbi, slice, size, } from "viem";
|
|
2
|
+
import { InvalidSimulationInputError, StateOverrideUnsupportedError } from "../errors.js";
|
|
3
|
+
import { txSimulatorRuntimeBytecode } from "../generated/txSimulatorBytecode.js";
|
|
4
|
+
import { MAX_UINT256, addressKey, getCallData, normalizeAddress, uint256Hex, uniqueAddresses, } from "./data.js";
|
|
5
|
+
import { blockOptionsSpread, buildCallParameters, createAccessList, formatRpcError, withRpcDebug, } from "./rpc.js";
|
|
6
|
+
const txSimulatorAbi = parseAbi([
|
|
7
|
+
"struct SimulatedCall { address to; uint256 value; bytes data; }",
|
|
8
|
+
"struct AllowanceProbe { address token; address spender; }",
|
|
9
|
+
"struct SimulationResult { bool success; uint256 failingCallIndex; bytes revertData; int256 nativeDelta; address[] observedTokens; address[] deltaTokens; int256[] tokenDeltas; uint256[] maxTokenOutflows; uint256 maxNativeOutflow; uint256[] allowanceCheckpoints; }",
|
|
10
|
+
"function simulate(SimulatedCall[] calls, address[] candidates, AllowanceProbe[] probes) returns (SimulationResult)",
|
|
11
|
+
"function isValidSignature(bytes32 hash, bytes signature) view returns (bytes4)",
|
|
12
|
+
]);
|
|
13
|
+
export async function runSimulator(args) {
|
|
14
|
+
const candidates = uniqueAddresses(args.candidates);
|
|
15
|
+
const data = encodeFunctionData({
|
|
16
|
+
abi: txSimulatorAbi,
|
|
17
|
+
functionName: "simulate",
|
|
18
|
+
args: [
|
|
19
|
+
args.calls.map((call) => ({
|
|
20
|
+
to: call.to,
|
|
21
|
+
value: call.value ?? 0n,
|
|
22
|
+
data: call.data,
|
|
23
|
+
})),
|
|
24
|
+
candidates,
|
|
25
|
+
args.allowanceProbes ?? [],
|
|
26
|
+
],
|
|
27
|
+
});
|
|
28
|
+
const stateOverride = buildStateOverride([
|
|
29
|
+
{ address: args.from, code: txSimulatorRuntimeBytecode },
|
|
30
|
+
...tokenSlotOverridesToStateDiff(args.tokenSlotOverrides ?? []),
|
|
31
|
+
...(args.extraStateOverrides ?? []),
|
|
32
|
+
]);
|
|
33
|
+
let callData;
|
|
34
|
+
try {
|
|
35
|
+
const result = await withRpcDebug(args.debug, {
|
|
36
|
+
method: "eth_call",
|
|
37
|
+
step: args.debugStep ?? "txSimulator.simulate",
|
|
38
|
+
details: {
|
|
39
|
+
from: args.from,
|
|
40
|
+
calls: args.calls.length,
|
|
41
|
+
candidates: candidates.length,
|
|
42
|
+
storageOverrides: args.tokenSlotOverrides?.length ?? 0,
|
|
43
|
+
stateOverrideAccounts: stateOverride.length,
|
|
44
|
+
},
|
|
45
|
+
}, () => args.client.call(buildCallParameters({
|
|
46
|
+
account: args.from,
|
|
47
|
+
to: args.from,
|
|
48
|
+
data,
|
|
49
|
+
gas: args.gas,
|
|
50
|
+
stateOverride,
|
|
51
|
+
...blockOptionsSpread(args),
|
|
52
|
+
})));
|
|
53
|
+
callData = getCallData(result);
|
|
54
|
+
}
|
|
55
|
+
catch (cause) {
|
|
56
|
+
throw new StateOverrideUnsupportedError(formatRpcError("eth_call with state override failed", cause));
|
|
57
|
+
}
|
|
58
|
+
let result;
|
|
59
|
+
try {
|
|
60
|
+
result = decodeFunctionResult({
|
|
61
|
+
abi: txSimulatorAbi,
|
|
62
|
+
functionName: "simulate",
|
|
63
|
+
data: callData,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
catch (cause) {
|
|
67
|
+
throw new StateOverrideUnsupportedError(formatRpcError("eth_call returned undecodable simulator output", cause));
|
|
68
|
+
}
|
|
69
|
+
const assetBalanceDeltas = [];
|
|
70
|
+
if (result.nativeDelta !== 0n) {
|
|
71
|
+
assetBalanceDeltas.push({ asset: "native", delta: result.nativeDelta });
|
|
72
|
+
}
|
|
73
|
+
for (let i = 0; i < result.deltaTokens.length; ++i) {
|
|
74
|
+
const token = result.deltaTokens[i];
|
|
75
|
+
const delta = result.tokenDeltas[i];
|
|
76
|
+
if (token && delta !== undefined && delta !== 0n) {
|
|
77
|
+
assetBalanceDeltas.push({ asset: token, delta });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const probeData = {
|
|
81
|
+
observedTokens: uniqueAddresses(result.observedTokens),
|
|
82
|
+
candidates,
|
|
83
|
+
maxTokenOutflows: result.maxTokenOutflows,
|
|
84
|
+
maxNativeOutflow: result.maxNativeOutflow,
|
|
85
|
+
allowanceCheckpoints: result.allowanceCheckpoints,
|
|
86
|
+
};
|
|
87
|
+
if (!result.success) {
|
|
88
|
+
const decodedRevert = decodeRevert(result.revertData, args.errorAbi);
|
|
89
|
+
return {
|
|
90
|
+
status: "reverted",
|
|
91
|
+
assetBalanceDeltas,
|
|
92
|
+
revertData: result.revertData,
|
|
93
|
+
...(decodedRevert.revertReason !== undefined
|
|
94
|
+
? { revertReason: decodedRevert.revertReason }
|
|
95
|
+
: {}),
|
|
96
|
+
...(decodedRevert.revertError !== undefined
|
|
97
|
+
? { revertError: decodedRevert.revertError }
|
|
98
|
+
: {}),
|
|
99
|
+
...(decodedRevert.revertSelector !== undefined
|
|
100
|
+
? { revertSelector: decodedRevert.revertSelector }
|
|
101
|
+
: {}),
|
|
102
|
+
failingCallIndex: Number(result.failingCallIndex),
|
|
103
|
+
probeData,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
status: "success",
|
|
108
|
+
assetBalanceDeltas,
|
|
109
|
+
probeData,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
export async function discoverCandidateAddresses(args) {
|
|
113
|
+
const accessLists = await Promise.all(args.calls.map((call) => createAccessList({
|
|
114
|
+
client: args.client,
|
|
115
|
+
from: args.from,
|
|
116
|
+
to: call.to,
|
|
117
|
+
data: call.data,
|
|
118
|
+
value: call.value ?? 0n,
|
|
119
|
+
gas: args.gas,
|
|
120
|
+
debug: args.debug,
|
|
121
|
+
debugStep: "candidateDiscovery.accessList",
|
|
122
|
+
...blockOptionsSpread(args),
|
|
123
|
+
})));
|
|
124
|
+
const candidates = args.calls.flatMap((call, index) => [
|
|
125
|
+
call.to,
|
|
126
|
+
...(accessLists[index] ?? []).map((entry) => entry.address),
|
|
127
|
+
]);
|
|
128
|
+
return uniqueAddresses(candidates);
|
|
129
|
+
}
|
|
130
|
+
function decodeRevert(data, errorAbi) {
|
|
131
|
+
if (!data || data === "0x")
|
|
132
|
+
return {};
|
|
133
|
+
const revertSelector = size(data) >= 4 ? slice(data, 0, 4) : undefined;
|
|
134
|
+
try {
|
|
135
|
+
const decoded = decodeErrorResult({ abi: errorAbi ?? [], data });
|
|
136
|
+
return {
|
|
137
|
+
revertReason: formatReason(decoded.errorName, decoded.args ?? []),
|
|
138
|
+
revertError: { name: decoded.errorName, args: decoded.args ?? [] },
|
|
139
|
+
...(revertSelector !== undefined ? { revertSelector } : {}),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return revertSelector !== undefined ? { revertSelector } : {};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function formatReason(name, args) {
|
|
147
|
+
if (name === "Error")
|
|
148
|
+
return String(args[0]);
|
|
149
|
+
if (name === "Panic")
|
|
150
|
+
return `Panic(${String(args[0])})`;
|
|
151
|
+
return `${name}(${args.map((arg) => String(arg)).join(", ")})`;
|
|
152
|
+
}
|
|
153
|
+
function buildStateOverride(entries) {
|
|
154
|
+
const merged = new Map();
|
|
155
|
+
for (const entry of entries) {
|
|
156
|
+
const normalized = normalizeAddress(entry.address);
|
|
157
|
+
const key = addressKey(normalized);
|
|
158
|
+
const existing = merged.get(key) ?? { address: normalized, stateDiff: [] };
|
|
159
|
+
if (entry.code)
|
|
160
|
+
existing.code = entry.code;
|
|
161
|
+
if (entry.balance !== undefined)
|
|
162
|
+
existing.balance = entry.balance;
|
|
163
|
+
if (entry.stateDiff) {
|
|
164
|
+
const bySlot = new Map((existing.stateDiff ?? []).map((item) => [item.slot.toLowerCase(), item]));
|
|
165
|
+
for (const diff of entry.stateDiff)
|
|
166
|
+
bySlot.set(diff.slot.toLowerCase(), diff);
|
|
167
|
+
existing.stateDiff = [...bySlot.values()];
|
|
168
|
+
}
|
|
169
|
+
merged.set(key, existing);
|
|
170
|
+
}
|
|
171
|
+
return [...merged.values()].map((entry) => {
|
|
172
|
+
if (entry.stateDiff?.length === 0) {
|
|
173
|
+
return {
|
|
174
|
+
address: entry.address,
|
|
175
|
+
code: entry.code,
|
|
176
|
+
balance: entry.balance,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return entry;
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
function tokenSlotOverridesToStateDiff(overrides) {
|
|
183
|
+
const byAddress = new Map();
|
|
184
|
+
for (const override of overrides) {
|
|
185
|
+
if (override.amount === MAX_UINT256) {
|
|
186
|
+
throw new InvalidSimulationInputError("tokenSlotOverrides amount must be below uint256 max: max-allowance skips ERC-20 decrements and max-balance overflows incoming transfers. Use OVERRIDE_TOKEN_AMOUNT.");
|
|
187
|
+
}
|
|
188
|
+
const normalized = normalizeAddress(override.token);
|
|
189
|
+
const key = addressKey(normalized);
|
|
190
|
+
const entry = byAddress.get(key) ?? { address: normalized, stateDiff: [] };
|
|
191
|
+
entry.stateDiff?.push({
|
|
192
|
+
slot: override.slot,
|
|
193
|
+
value: uint256Hex(override.amount),
|
|
194
|
+
});
|
|
195
|
+
byAddress.set(key, entry);
|
|
196
|
+
}
|
|
197
|
+
return [...byAddress.values()];
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=simulator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simulator.js","sourceRoot":"","sources":["../../src/internal/simulator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PreparedAllowanceOverrides, PreparedBalanceOverrides, PrepareAllowanceOverridesArgs, PrepareBalanceOverridesArgs } from "../types.js";
|
|
2
|
+
import type { ClientArgs } from "./rpc.js";
|
|
3
|
+
/** @internal Implements `TxSimulator.prepareBalanceOverrides`. Prefer the instance API from the package root. */
|
|
4
|
+
export declare function prepareBalanceOverrides(args: PrepareBalanceOverridesArgs & ClientArgs): Promise<PreparedBalanceOverrides>;
|
|
5
|
+
/** @internal Implements `TxSimulator.prepareAllowanceOverrides`. Prefer the instance API from the package root. */
|
|
6
|
+
export declare function prepareAllowanceOverrides(args: PrepareAllowanceOverridesArgs & ClientArgs): Promise<PreparedAllowanceOverrides>;
|
|
7
|
+
//# sourceMappingURL=slots.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slots.d.ts","sourceRoot":"","sources":["../../src/internal/slots.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,0BAA0B,EAC1B,wBAAwB,EACxB,6BAA6B,EAC7B,2BAA2B,EAE5B,MAAM,aAAa,CAAC;AAGrB,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,UAAU,CAAC;AAaxD,iHAAiH;AACjH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,2BAA2B,GAAG,UAAU,GAC7C,OAAO,CAAC,wBAAwB,CAAC,CAkBnC;AAED,mHAAmH;AACnH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,6BAA6B,GAAG,UAAU,GAC/C,OAAO,CAAC,0BAA0B,CAAC,CAcrC"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { encodeAbiParameters, keccak256 } from "viem";
|
|
2
|
+
import { OVERRIDE_TOKEN_AMOUNT } from "../constants.js";
|
|
3
|
+
import { addressKey, uint256Hex } from "./data.js";
|
|
4
|
+
import { discoverAllowanceSlot, discoverBalanceSlot, readAllowance } from "./probes.js";
|
|
5
|
+
import { blockOptionsSpread } from "./rpc.js";
|
|
6
|
+
// Orchestration
|
|
7
|
+
/** @internal Implements `TxSimulator.prepareBalanceOverrides`. Prefer the instance API from the package root. */
|
|
8
|
+
export async function prepareBalanceOverrides(args) {
|
|
9
|
+
const slots = await Promise.all(args.tokens.map((token) => discoverBalanceSlot({
|
|
10
|
+
client: args.client,
|
|
11
|
+
token,
|
|
12
|
+
owner: args.from,
|
|
13
|
+
sentinel: OVERRIDE_TOKEN_AMOUNT,
|
|
14
|
+
gas: args.gas,
|
|
15
|
+
debug: args.debug,
|
|
16
|
+
...blockOptionsSpread(args),
|
|
17
|
+
})));
|
|
18
|
+
return {
|
|
19
|
+
slots: slots.filter(isDefined).map(withOverrideAmount),
|
|
20
|
+
unresolved: args.tokens.filter((_, index) => slots[index] === undefined),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/** @internal Implements `TxSimulator.prepareAllowanceOverrides`. Prefer the instance API from the package root. */
|
|
24
|
+
export async function prepareAllowanceOverrides(args) {
|
|
25
|
+
const slots = await prepareAllowanceOverridesWithInference({
|
|
26
|
+
client: args.client,
|
|
27
|
+
from: args.from,
|
|
28
|
+
pairs: args.pairs,
|
|
29
|
+
sentinel: OVERRIDE_TOKEN_AMOUNT,
|
|
30
|
+
gas: args.gas,
|
|
31
|
+
debug: args.debug,
|
|
32
|
+
...blockOptionsSpread(args),
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
slots: slots.filter(isDefined).map(withOverrideAmount),
|
|
36
|
+
unresolved: args.pairs.filter((_, index) => slots[index] === undefined),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function isDefined(value) {
|
|
40
|
+
return value !== undefined;
|
|
41
|
+
}
|
|
42
|
+
function withOverrideAmount(slot) {
|
|
43
|
+
return { ...slot, amount: OVERRIDE_TOKEN_AMOUNT };
|
|
44
|
+
}
|
|
45
|
+
async function prepareAllowanceOverridesWithInference(args) {
|
|
46
|
+
const slots = Array.from({ length: args.pairs.length });
|
|
47
|
+
const groups = groupPairsByToken(args.pairs);
|
|
48
|
+
await Promise.all(groups.map(async (pairs) => {
|
|
49
|
+
const firstPair = pairs[0];
|
|
50
|
+
if (firstPair === undefined)
|
|
51
|
+
return;
|
|
52
|
+
const firstSlot = await probeAllowanceSlot({ ...args, ...firstPair });
|
|
53
|
+
slots[firstPair.index] = firstSlot;
|
|
54
|
+
const baseSlot = firstSlot === undefined
|
|
55
|
+
? undefined
|
|
56
|
+
: inferAllowanceBaseSlot({
|
|
57
|
+
probedSlot: firstSlot.slot,
|
|
58
|
+
owner: args.from,
|
|
59
|
+
spender: firstPair.spender,
|
|
60
|
+
});
|
|
61
|
+
await Promise.all(pairs.slice(1).map(async (pair) => {
|
|
62
|
+
slots[pair.index] =
|
|
63
|
+
baseSlot === undefined
|
|
64
|
+
? await probeAllowanceSlot({ ...args, ...pair })
|
|
65
|
+
: await computeAllowanceSlot({ ...args, ...pair, baseSlot });
|
|
66
|
+
}));
|
|
67
|
+
}));
|
|
68
|
+
return slots;
|
|
69
|
+
}
|
|
70
|
+
function groupPairsByToken(pairs) {
|
|
71
|
+
const groupsByToken = new Map();
|
|
72
|
+
for (let index = 0; index < pairs.length; ++index) {
|
|
73
|
+
const pair = pairs[index];
|
|
74
|
+
if (pair === undefined)
|
|
75
|
+
continue;
|
|
76
|
+
const key = addressKey(pair.token);
|
|
77
|
+
const group = groupsByToken.get(key) ?? [];
|
|
78
|
+
group.push({ ...pair, index });
|
|
79
|
+
groupsByToken.set(key, group);
|
|
80
|
+
}
|
|
81
|
+
return [...groupsByToken.values()];
|
|
82
|
+
}
|
|
83
|
+
async function probeAllowanceSlot(args) {
|
|
84
|
+
return discoverAllowanceSlot({
|
|
85
|
+
client: args.client,
|
|
86
|
+
token: args.token,
|
|
87
|
+
owner: args.from,
|
|
88
|
+
spender: args.spender,
|
|
89
|
+
sentinel: args.sentinel,
|
|
90
|
+
gas: args.gas,
|
|
91
|
+
debug: args.debug,
|
|
92
|
+
...blockOptionsSpread(args),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
async function computeAllowanceSlot(args) {
|
|
96
|
+
const slot = allowanceSlotFor(args.from, args.spender, args.baseSlot);
|
|
97
|
+
const allowance = await readAllowance({
|
|
98
|
+
client: args.client,
|
|
99
|
+
token: args.token,
|
|
100
|
+
owner: args.from,
|
|
101
|
+
spender: args.spender,
|
|
102
|
+
stateOverride: [
|
|
103
|
+
{ address: args.token, stateDiff: [{ slot, value: uint256Hex(args.sentinel) }] },
|
|
104
|
+
],
|
|
105
|
+
gas: args.gas,
|
|
106
|
+
debug: args.debug,
|
|
107
|
+
debugStep: "allowanceSlot.computedVerify",
|
|
108
|
+
...blockOptionsSpread(args),
|
|
109
|
+
});
|
|
110
|
+
if (allowance === args.sentinel)
|
|
111
|
+
return { token: args.token, spender: args.spender, slot };
|
|
112
|
+
return probeAllowanceSlot(args);
|
|
113
|
+
}
|
|
114
|
+
// Layout math
|
|
115
|
+
function mappingSlot(key, baseSlot) {
|
|
116
|
+
return keccak256(encodeAbiParameters([{ type: "address" }, { type: "uint256" }], [key, typeof baseSlot === "bigint" ? baseSlot : BigInt(baseSlot)]));
|
|
117
|
+
}
|
|
118
|
+
function allowanceSlotFor(owner, spender, base) {
|
|
119
|
+
return mappingSlot(spender, mappingSlot(owner, base));
|
|
120
|
+
}
|
|
121
|
+
function inferAllowanceBaseSlot(args) {
|
|
122
|
+
const target = args.probedSlot.toLowerCase();
|
|
123
|
+
for (let base = 0n; base <= 64n; ++base) {
|
|
124
|
+
if (allowanceSlotFor(args.owner, args.spender, base).toLowerCase() === target)
|
|
125
|
+
return base;
|
|
126
|
+
}
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=slots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slots.js","sourceRoot":"","sources":["../../src/internal/slots.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { PreparedAllowanceOverrides, PreparedBalanceOverrides, PrepareAllowanceOverridesArgs, PrepareBalanceOverridesArgs, EstimateAssetRequirementsArgs, EstimatedAssetRequirements, SimulateArgs, SimulationResult, TxSimulatorConfig } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Bound transaction simulator for one viem public client.
|
|
4
|
+
*
|
|
5
|
+
* Bind the RPC client once, then pass `from` per call so applications can switch accounts without
|
|
6
|
+
* rebuilding the simulator. Per-call `gas` and `debug` override defaults supplied to
|
|
7
|
+
* {@link TxSimulator.create}.
|
|
8
|
+
*/
|
|
9
|
+
export interface TxSimulator {
|
|
10
|
+
/**
|
|
11
|
+
* Simulates one call or sequential batch and returns raw native/token balance deltas.
|
|
12
|
+
*
|
|
13
|
+
* This uses `eth_createAccessList` for candidate discovery and one `eth_call` with state
|
|
14
|
+
* overrides that injects the simulator at `from`. It does not automatically forge balances or
|
|
15
|
+
* allowances; preparation methods return ready-to-use `tokenSlotOverrides` for view-only or
|
|
16
|
+
* unfunded accounts. Transaction reverts return `status: "reverted"` instead of throwing.
|
|
17
|
+
*
|
|
18
|
+
* @throws InvalidSimulationInputError when `calls` is empty.
|
|
19
|
+
* @throws AccessListUnsupportedError when the RPC endpoint cannot provide access lists.
|
|
20
|
+
* @throws StateOverrideUnsupportedError when the RPC endpoint cannot execute state overrides or
|
|
21
|
+
* returns undecodable simulator output.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* const sim = TxSimulator.create({ client });
|
|
26
|
+
* const result = await sim.simulate({
|
|
27
|
+
* from,
|
|
28
|
+
* calls: [{ to, data, value: 0n }],
|
|
29
|
+
* });
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
simulate: (args: SimulateArgs) => Promise<SimulationResult>;
|
|
33
|
+
/**
|
|
34
|
+
* Prepares ERC-20 balance overrides for `from`.
|
|
35
|
+
*
|
|
36
|
+
* Each token is probed with RPC-only access lists and sentinel state overrides. Tokens the
|
|
37
|
+
* simulator cannot `deal` by verified storage write are returned in `unresolved` rather than
|
|
38
|
+
* thrown.
|
|
39
|
+
*
|
|
40
|
+
* @throws StateOverrideUnsupportedError when the RPC endpoint cannot execute state overrides.
|
|
41
|
+
*/
|
|
42
|
+
prepareBalanceOverrides: (args: PrepareBalanceOverridesArgs) => Promise<PreparedBalanceOverrides>;
|
|
43
|
+
/**
|
|
44
|
+
* Prepares ERC-20 allowance overrides for `from` and the requested token/spender pairs.
|
|
45
|
+
*
|
|
46
|
+
* Standard Solidity allowance layouts are inferred after one verified probe per token where
|
|
47
|
+
* possible; non-standard layouts fall back to per-pair probing. Pairs the simulator cannot `deal`
|
|
48
|
+
* via verified storage write are returned in `unresolved` rather than thrown.
|
|
49
|
+
*
|
|
50
|
+
* @throws StateOverrideUnsupportedError when the RPC endpoint cannot execute state overrides.
|
|
51
|
+
*/
|
|
52
|
+
prepareAllowanceOverrides: (args: PrepareAllowanceOverridesArgs) => Promise<PreparedAllowanceOverrides>;
|
|
53
|
+
/**
|
|
54
|
+
* Estimates the balances and approvals needed to execute the observed path.
|
|
55
|
+
*
|
|
56
|
+
* Use this when the tokens or spenders are not known ahead of time. Returned amounts are estimated
|
|
57
|
+
* under forged balances/allowances and should be padded before display or transaction assembly;
|
|
58
|
+
* unreliable measurements are reported under `unresolved`.
|
|
59
|
+
*
|
|
60
|
+
* @throws InvalidSimulationInputError when `calls` is empty.
|
|
61
|
+
* @throws AccessListUnsupportedError when the RPC endpoint cannot provide access lists.
|
|
62
|
+
* @throws StateOverrideUnsupportedError when the RPC endpoint cannot execute state overrides or
|
|
63
|
+
* returns undecodable simulator output.
|
|
64
|
+
*/
|
|
65
|
+
estimateAssetRequirements: (args: EstimateAssetRequirementsArgs) => Promise<EstimatedAssetRequirements>;
|
|
66
|
+
}
|
|
67
|
+
/** Factory for {@link TxSimulator} instances bound to one viem public client. */
|
|
68
|
+
export declare const TxSimulator: {
|
|
69
|
+
/**
|
|
70
|
+
* Creates a simulator with optional default gas and debug settings.
|
|
71
|
+
*
|
|
72
|
+
* `gas` defaults to `DEFAULT_SIMULATION_GAS_LIMIT`; `debug` may be `true` for console logging or a
|
|
73
|
+
* callback for structured events. Per-call `gas` and `debug` take precedence over these defaults.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* const sim = TxSimulator.create({ client, debug: true });
|
|
78
|
+
* const result = await sim.simulate({ from, calls });
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
create(bound: TxSimulatorConfig): TxSimulator;
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=txSimulator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"txSimulator.d.ts","sourceRoot":"","sources":["../src/txSimulator.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,0BAA0B,EAC1B,wBAAwB,EACxB,6BAA6B,EAC7B,2BAA2B,EAC3B,6BAA6B,EAC7B,0BAA0B,EAC1B,YAAY,EAEZ,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAQpB;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAE5D;;;;;;;;OAQG;IACH,uBAAuB,EAAE,CAAC,IAAI,EAAE,2BAA2B,KAAK,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAElG;;;;;;;;OAQG;IACH,yBAAyB,EAAE,CACzB,IAAI,EAAE,6BAA6B,KAChC,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAEzC;;;;;;;;;;;OAWG;IACH,yBAAyB,EAAE,CACzB,IAAI,EAAE,6BAA6B,KAChC,OAAO,CAAC,0BAA0B,CAAC,CAAC;CAC1C;AAED,iFAAiF;AACjF,eAAO,MAAM,WAAW;IACtB;;;;;;;;;;;OAWG;kBACW,iBAAiB,GAAG,WAAW;CA6B9C,CAAC"}
|