viem-tx-sim 0.1.1 → 0.2.1
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/README.md +115 -34
- package/contracts/TxSimulator.sol +83 -20
- package/dist/generated/txSimulatorBytecode.d.ts +1 -1
- package/dist/generated/txSimulatorBytecode.d.ts.map +1 -1
- package/dist/generated/txSimulatorBytecode.js +1 -1
- package/dist/generated/txSimulatorBytecode.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/internal/queryDiscovery.d.ts +8 -0
- package/dist/internal/queryDiscovery.d.ts.map +1 -0
- package/dist/internal/queryDiscovery.js +38 -0
- package/dist/internal/queryDiscovery.js.map +1 -0
- package/dist/internal/requirements.d.ts +2 -1
- package/dist/internal/requirements.d.ts.map +1 -1
- package/dist/internal/requirements.js +23 -9
- package/dist/internal/requirements.js.map +1 -1
- package/dist/internal/simulator.d.ts +19 -3
- package/dist/internal/simulator.d.ts.map +1 -1
- package/dist/internal/simulator.js +12 -16
- package/dist/internal/simulator.js.map +1 -1
- package/dist/internal/slots.d.ts +4 -2
- package/dist/internal/slots.d.ts.map +1 -1
- package/dist/internal/slots.js +4 -2
- package/dist/internal/slots.js.map +1 -1
- package/dist/txSimulator.d.ts +64 -40
- package/dist/txSimulator.d.ts.map +1 -1
- package/dist/txSimulator.js +68 -16
- package/dist/txSimulator.js.map +1 -1
- package/dist/types.d.ts +59 -16
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/generated/txSimulatorBytecode.ts +1 -1
- package/src/index.ts +4 -1
- package/src/internal/queryDiscovery.ts +49 -0
- package/src/internal/requirements.ts +23 -9
- package/src/internal/simulator.ts +28 -24
- package/src/internal/slots.ts +5 -2
- package/src/txSimulator.ts +164 -63
- package/src/types.ts +63 -17
package/src/txSimulator.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
+
import type { Address } from "viem";
|
|
2
|
+
|
|
1
3
|
import { DEFAULT_SIMULATION_GAS_LIMIT } from "./constants.js";
|
|
2
4
|
import { InvalidSimulationInputError } from "./errors.js";
|
|
3
|
-
import {
|
|
5
|
+
import { discoverErc20s, forUserBalanceQueries } from "./internal/queryDiscovery.js";
|
|
6
|
+
import { estimateTokenOverrideRequirements } from "./internal/requirements.js";
|
|
4
7
|
import { blockOptionsSpread, type ClientArgs } from "./internal/rpc.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
8
|
+
import { runSimulator } from "./internal/simulator.js";
|
|
9
|
+
import { prepareAllowanceTokenOverrides, prepareBalanceTokenOverrides } from "./internal/slots.js";
|
|
7
10
|
import type {
|
|
11
|
+
BalanceDelta,
|
|
12
|
+
BalanceQuery,
|
|
13
|
+
ForUserBalanceQueriesArgs,
|
|
8
14
|
PreparedAllowanceOverrides,
|
|
9
15
|
PreparedBalanceOverrides,
|
|
10
16
|
PrepareAllowanceOverridesArgs,
|
|
@@ -32,15 +38,13 @@ type BoundCallDefaults = {
|
|
|
32
38
|
*/
|
|
33
39
|
export interface TxSimulator {
|
|
34
40
|
/**
|
|
35
|
-
* Simulates one call or sequential batch and returns
|
|
41
|
+
* Simulates one call or sequential batch and returns requested balance deltas.
|
|
36
42
|
*
|
|
37
|
-
* This
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* unfunded accounts. Transaction reverts return `status: "reverted"` instead of throwing.
|
|
43
|
+
* This performs one `eth_call` with state overrides that inject the simulator at `from`.
|
|
44
|
+
* Balances are observed only for `balanceQueries`; query the tokens you forge if you want to
|
|
45
|
+
* observe them. Transaction reverts return `status: "reverted"` instead of throwing.
|
|
41
46
|
*
|
|
42
47
|
* @throws InvalidSimulationInputError when `calls` is empty.
|
|
43
|
-
* @throws AccessListUnsupportedError when the RPC endpoint cannot provide access lists.
|
|
44
48
|
* @throws StateOverrideUnsupportedError when the RPC endpoint cannot execute state overrides or
|
|
45
49
|
* returns undecodable simulator output.
|
|
46
50
|
*
|
|
@@ -50,50 +54,75 @@ export interface TxSimulator {
|
|
|
50
54
|
* const result = await sim.simulate({
|
|
51
55
|
* from,
|
|
52
56
|
* calls: [{ to, data, value: 0n }],
|
|
57
|
+
* balanceQueries: [{ asset: "native", account: from }],
|
|
53
58
|
* });
|
|
54
59
|
* ```
|
|
55
60
|
*/
|
|
56
61
|
simulate: (args: SimulateArgs) => Promise<SimulationResult>;
|
|
57
62
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
readonly balanceQueries: {
|
|
64
|
+
/**
|
|
65
|
+
* Discovers wallet-style balance queries for `from`.
|
|
66
|
+
*
|
|
67
|
+
* This runs access-list candidate discovery, then one token-filter `eth_call`, and returns
|
|
68
|
+
* native plus token balance queries for `from`. Pass the result to `simulate`.
|
|
69
|
+
*
|
|
70
|
+
* @throws AccessListUnsupportedError when the RPC endpoint cannot provide access lists.
|
|
71
|
+
* @throws StateOverrideUnsupportedError when the RPC endpoint cannot execute state overrides.
|
|
72
|
+
*/
|
|
73
|
+
forUser: (args: ForUserBalanceQueriesArgs) => Promise<BalanceQuery[]>;
|
|
68
74
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
) => Promise<PreparedAllowanceOverrides>;
|
|
75
|
+
/**
|
|
76
|
+
* Discovers ERC-20 contracts touched by the calls that answer `balanceOf(from)`.
|
|
77
|
+
*
|
|
78
|
+
* This is the discovery half of `forUser`; map the returned addresses yourself when observing a
|
|
79
|
+
* different account.
|
|
80
|
+
*
|
|
81
|
+
* @throws AccessListUnsupportedError when the RPC endpoint cannot provide access lists.
|
|
82
|
+
* @throws StateOverrideUnsupportedError when the RPC endpoint cannot execute state overrides.
|
|
83
|
+
*/
|
|
84
|
+
discoverErc20s: (args: ForUserBalanceQueriesArgs) => Promise<Address[]>;
|
|
85
|
+
};
|
|
81
86
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
87
|
+
readonly tokenOverrides: {
|
|
88
|
+
/**
|
|
89
|
+
* Prepares ERC-20 balance overrides for `from`.
|
|
90
|
+
*
|
|
91
|
+
* Each token is probed with RPC-only access lists and sentinel state overrides. Tokens the
|
|
92
|
+
* simulator cannot `deal` by verified storage write are returned in `unresolved` rather than
|
|
93
|
+
* thrown.
|
|
94
|
+
*
|
|
95
|
+
* @throws StateOverrideUnsupportedError when the RPC endpoint cannot execute state overrides.
|
|
96
|
+
*/
|
|
97
|
+
forBalances: (args: PrepareBalanceOverridesArgs) => Promise<PreparedBalanceOverrides>;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Prepares ERC-20 allowance overrides for `from` and the requested token/spender pairs.
|
|
101
|
+
*
|
|
102
|
+
* Standard Solidity allowance layouts are inferred after one verified probe per token where
|
|
103
|
+
* possible; non-standard layouts fall back to per-pair probing. Pairs the simulator cannot
|
|
104
|
+
* `deal` via verified storage write are returned in `unresolved` rather than thrown.
|
|
105
|
+
*
|
|
106
|
+
* @throws StateOverrideUnsupportedError when the RPC endpoint cannot execute state overrides.
|
|
107
|
+
*/
|
|
108
|
+
forAllowances: (args: PrepareAllowanceOverridesArgs) => Promise<PreparedAllowanceOverrides>;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Estimates the balances and approvals needed to execute the observed path.
|
|
112
|
+
*
|
|
113
|
+
* Use this when the tokens or spenders are not known ahead of time. Returned amounts are
|
|
114
|
+
* estimated under forged balances/allowances and should be padded before display or transaction
|
|
115
|
+
* assembly; unreliable measurements are reported under `unresolved`.
|
|
116
|
+
*
|
|
117
|
+
* @throws InvalidSimulationInputError when `calls` is empty.
|
|
118
|
+
* @throws AccessListUnsupportedError when the RPC endpoint cannot provide access lists.
|
|
119
|
+
* @throws StateOverrideUnsupportedError when the RPC endpoint cannot execute state overrides or
|
|
120
|
+
* returns undecodable simulator output.
|
|
121
|
+
*/
|
|
122
|
+
estimateRequirements: (
|
|
123
|
+
args: EstimateAssetRequirementsArgs,
|
|
124
|
+
) => Promise<EstimatedAssetRequirements>;
|
|
125
|
+
};
|
|
97
126
|
}
|
|
98
127
|
|
|
99
128
|
/** Factory for {@link TxSimulator} instances bound to one viem public client. */
|
|
@@ -131,12 +160,24 @@ export const TxSimulator = {
|
|
|
131
160
|
|
|
132
161
|
return {
|
|
133
162
|
simulate: (args) => runSimulate({ ...args, ...revertDefaults(args), client: bound.client }),
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
163
|
+
balanceQueries: {
|
|
164
|
+
forUser: (args) =>
|
|
165
|
+
forUserBalanceQueries({ ...args, ...defaults(args), client: bound.client }),
|
|
166
|
+
discoverErc20s: (args) =>
|
|
167
|
+
discoverErc20s({ ...args, ...defaults(args), client: bound.client }),
|
|
168
|
+
},
|
|
169
|
+
tokenOverrides: {
|
|
170
|
+
forBalances: (args) =>
|
|
171
|
+
prepareBalanceTokenOverrides({ ...args, ...defaults(args), client: bound.client }),
|
|
172
|
+
forAllowances: (args) =>
|
|
173
|
+
prepareAllowanceTokenOverrides({ ...args, ...defaults(args), client: bound.client }),
|
|
174
|
+
estimateRequirements: (args) =>
|
|
175
|
+
estimateTokenOverrideRequirements({
|
|
176
|
+
...args,
|
|
177
|
+
...revertDefaults(args),
|
|
178
|
+
client: bound.client,
|
|
179
|
+
}),
|
|
180
|
+
},
|
|
140
181
|
};
|
|
141
182
|
},
|
|
142
183
|
};
|
|
@@ -151,26 +192,86 @@ async function runSimulate(args: SimulateArgs & ClientArgs): Promise<SimulationR
|
|
|
151
192
|
data: call.data,
|
|
152
193
|
value: call.value ?? 0n,
|
|
153
194
|
})) satisfies SimulatedCall[];
|
|
154
|
-
const candidateAddresses = await discoverCandidateAddresses({
|
|
155
|
-
client: args.client,
|
|
156
|
-
from: args.from,
|
|
157
|
-
calls,
|
|
158
|
-
...blockOptionsSpread(args),
|
|
159
|
-
gas: args.gas,
|
|
160
|
-
...(args.debug !== undefined ? { debug: args.debug } : {}),
|
|
161
|
-
});
|
|
162
|
-
|
|
163
195
|
const tokenSlotOverrides = args.tokenSlotOverrides ?? [];
|
|
164
196
|
|
|
165
|
-
|
|
197
|
+
const result = await runSimulator({
|
|
166
198
|
client: args.client,
|
|
167
199
|
from: args.from,
|
|
168
200
|
calls,
|
|
169
|
-
candidates: [
|
|
201
|
+
candidates: [],
|
|
170
202
|
tokenSlotOverrides,
|
|
203
|
+
extraStateOverrides: (args.nativeBalanceOverrides ?? []).map((override) => ({
|
|
204
|
+
address: override.account,
|
|
205
|
+
balance: override.amount,
|
|
206
|
+
})),
|
|
207
|
+
balanceProbes: args.balanceQueries.map((query) => ({
|
|
208
|
+
token: query.asset,
|
|
209
|
+
account: query.account,
|
|
210
|
+
})),
|
|
171
211
|
debug: args.debug,
|
|
172
212
|
...blockOptionsSpread(args),
|
|
173
213
|
gas: args.gas,
|
|
174
214
|
...(args.errorAbi !== undefined ? { errorAbi: args.errorAbi } : {}),
|
|
175
215
|
});
|
|
216
|
+
const balances = buildBalanceResults(args.balanceQueries, result.probeData, calls.length);
|
|
217
|
+
|
|
218
|
+
if (result.status === "reverted") {
|
|
219
|
+
return {
|
|
220
|
+
status: "reverted",
|
|
221
|
+
...balances,
|
|
222
|
+
revertData: result.revertData,
|
|
223
|
+
...(result.revertReason !== undefined ? { revertReason: result.revertReason } : {}),
|
|
224
|
+
...(result.revertError !== undefined ? { revertError: result.revertError } : {}),
|
|
225
|
+
...(result.revertSelector !== undefined ? { revertSelector: result.revertSelector } : {}),
|
|
226
|
+
failingCallIndex: result.failingCallIndex,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return { status: "success", ...balances };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
type BalanceResultFields = {
|
|
234
|
+
balanceDeltas: BalanceDelta[];
|
|
235
|
+
unresolved: BalanceQuery[];
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
function buildBalanceResults(
|
|
239
|
+
queries: readonly BalanceQuery[],
|
|
240
|
+
probeData: {
|
|
241
|
+
balanceCheckpoints: readonly bigint[];
|
|
242
|
+
balanceProbeOk: readonly boolean[];
|
|
243
|
+
},
|
|
244
|
+
callsLength: number,
|
|
245
|
+
): BalanceResultFields {
|
|
246
|
+
const balanceDeltas: BalanceDelta[] = [];
|
|
247
|
+
const unresolved: BalanceQuery[] = [];
|
|
248
|
+
const stride = callsLength + 1;
|
|
249
|
+
|
|
250
|
+
for (let i = 0; i < queries.length; ++i) {
|
|
251
|
+
const query = queries[i];
|
|
252
|
+
if (query === undefined) continue;
|
|
253
|
+
if (probeData.balanceProbeOk[i] !== true) {
|
|
254
|
+
unresolved.push(query);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
const base = i * stride;
|
|
258
|
+
const before = probeData.balanceCheckpoints[base] ?? 0n;
|
|
259
|
+
const after = probeData.balanceCheckpoints[base + callsLength] ?? 0n;
|
|
260
|
+
const byCall = Array.from(
|
|
261
|
+
{ length: callsLength },
|
|
262
|
+
(_, callIndex) =>
|
|
263
|
+
(probeData.balanceCheckpoints[base + callIndex + 1] ?? 0n) -
|
|
264
|
+
(probeData.balanceCheckpoints[base + callIndex] ?? 0n),
|
|
265
|
+
);
|
|
266
|
+
balanceDeltas.push({
|
|
267
|
+
asset: query.asset,
|
|
268
|
+
account: query.account,
|
|
269
|
+
before,
|
|
270
|
+
after,
|
|
271
|
+
delta: after - before,
|
|
272
|
+
byCall,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return { balanceDeltas, unresolved };
|
|
176
277
|
}
|
package/src/types.ts
CHANGED
|
@@ -10,6 +10,38 @@ export type SimulatedCall = {
|
|
|
10
10
|
value?: bigint;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
+
/** One balance to observe during simulation. `asset` is `"native"` or an ERC-20 address. */
|
|
14
|
+
export type BalanceQuery = {
|
|
15
|
+
asset: "native" | Address;
|
|
16
|
+
/** Account whose balance is observed; this can be any address, not just `from`. */
|
|
17
|
+
account: Address;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/** Protocol-level native balance to set before simulating; no slot discovery needed. */
|
|
21
|
+
export type NativeBalanceOverride = {
|
|
22
|
+
/** Account to fund: `from` or any other address such as a plugin or router. */
|
|
23
|
+
account: Address;
|
|
24
|
+
/** Balance in wei to set. */
|
|
25
|
+
amount: bigint;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Balance observation for one query. `before` is after `tokenSlotOverrides` are applied, so deltas
|
|
30
|
+
* describe simulated changes under the supplied state assumptions.
|
|
31
|
+
*/
|
|
32
|
+
export type BalanceDelta = {
|
|
33
|
+
asset: "native" | Address;
|
|
34
|
+
account: Address;
|
|
35
|
+
before: bigint;
|
|
36
|
+
after: bigint;
|
|
37
|
+
delta: bigint;
|
|
38
|
+
/**
|
|
39
|
+
* Signed change per call, index-aligned with `calls`. Sums to `delta`; on a
|
|
40
|
+
* revert, entries from the failing call onward are 0n.
|
|
41
|
+
*/
|
|
42
|
+
byCall: readonly bigint[];
|
|
43
|
+
};
|
|
44
|
+
|
|
13
45
|
/** Structured event emitted before and after each RPC call when debug logging is enabled. */
|
|
14
46
|
export type SimulationDebugEvent = {
|
|
15
47
|
/** Lifecycle phase for the RPC operation. */
|
|
@@ -51,7 +83,7 @@ type SimulationOptions = {
|
|
|
51
83
|
export type TokenSlotOverride = {
|
|
52
84
|
/** Token contract whose storage should be overridden. */
|
|
53
85
|
token: Address;
|
|
54
|
-
/** Storage slot to write. Usually prepared by `
|
|
86
|
+
/** Storage slot to write. Usually prepared by `tokenOverrides.forBalances` or `tokenOverrides.forAllowances`. */
|
|
55
87
|
slot: Hex;
|
|
56
88
|
/** Value written to the slot. Must be below uint256 max. */
|
|
57
89
|
amount: bigint;
|
|
@@ -100,13 +132,31 @@ export type SimulateArgs = SimulationOptions & {
|
|
|
100
132
|
from: Address;
|
|
101
133
|
/** One call or an ERC-5792-style sequential batch. Must contain at least one call. */
|
|
102
134
|
calls: readonly SimulatedCall[];
|
|
103
|
-
/**
|
|
135
|
+
/** Balances to observe. Use `[]` to execute without balance observations. */
|
|
136
|
+
balanceQueries: readonly BalanceQuery[];
|
|
137
|
+
/**
|
|
138
|
+
* Storage-slot overrides applied before simulating. Query the tokens you forge if you want to
|
|
139
|
+
* observe them.
|
|
140
|
+
*/
|
|
104
141
|
tokenSlotOverrides?: readonly TokenSlotOverride[];
|
|
142
|
+
/**
|
|
143
|
+
* Native balance overrides applied before simulating. Duplicate accounts use the last amount.
|
|
144
|
+
* Query forged accounts if you want to observe them.
|
|
145
|
+
*/
|
|
146
|
+
nativeBalanceOverrides?: readonly NativeBalanceOverride[];
|
|
105
147
|
/** Additional error definitions for decoding this call's reverts; merged after the bound errorAbi. */
|
|
106
148
|
errorAbi?: Abi;
|
|
107
149
|
};
|
|
108
150
|
|
|
109
|
-
/** Arguments for `TxSimulator.
|
|
151
|
+
/** Arguments for `TxSimulator.balanceQueries.forUser`. */
|
|
152
|
+
export type ForUserBalanceQueriesArgs = SimulationOptions & {
|
|
153
|
+
/** Account whose wallet-style balance queries should be discovered. */
|
|
154
|
+
from: Address;
|
|
155
|
+
/** Calls whose access lists should be searched for token candidates. */
|
|
156
|
+
calls: readonly SimulatedCall[];
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
/** Arguments for `TxSimulator.tokenOverrides.forBalances`. */
|
|
110
160
|
export type PrepareBalanceOverridesArgs = SimulationOptions & {
|
|
111
161
|
/** Account whose token balance overrides should be prepared. */
|
|
112
162
|
from: Address;
|
|
@@ -114,7 +164,7 @@ export type PrepareBalanceOverridesArgs = SimulationOptions & {
|
|
|
114
164
|
tokens: readonly Address[];
|
|
115
165
|
};
|
|
116
166
|
|
|
117
|
-
/** Arguments for `TxSimulator.
|
|
167
|
+
/** Arguments for `TxSimulator.tokenOverrides.forAllowances`. */
|
|
118
168
|
export type PrepareAllowanceOverridesArgs = SimulationOptions & {
|
|
119
169
|
/** Account whose allowance overrides should be prepared. */
|
|
120
170
|
from: Address;
|
|
@@ -122,7 +172,7 @@ export type PrepareAllowanceOverridesArgs = SimulationOptions & {
|
|
|
122
172
|
pairs: readonly AllowanceSlotPair[];
|
|
123
173
|
};
|
|
124
174
|
|
|
125
|
-
/** Arguments for `TxSimulator.
|
|
175
|
+
/** Arguments for `TxSimulator.tokenOverrides.estimateRequirements`. */
|
|
126
176
|
export type EstimateAssetRequirementsArgs = SimulationOptions & {
|
|
127
177
|
/** Account whose balance and approval needs should be estimated. */
|
|
128
178
|
from: Address;
|
|
@@ -204,26 +254,22 @@ export type EstimatedAssetRequirements =
|
|
|
204
254
|
| EstimatedAssetRequirementsSuccess
|
|
205
255
|
| EstimatedAssetRequirementsReverted;
|
|
206
256
|
|
|
207
|
-
/** Raw balance delta for native ETH or an ERC-20-style `balanceOf(address)` asset. */
|
|
208
|
-
export type AssetBalanceDelta = {
|
|
209
|
-
/** `"native"` for ETH, otherwise the token contract address. */
|
|
210
|
-
asset: "native" | Address;
|
|
211
|
-
/** Signed raw-unit balance change for `from`; negative means the account lost assets. */
|
|
212
|
-
delta: bigint;
|
|
213
|
-
};
|
|
214
|
-
|
|
215
257
|
/** Successful simulation result. */
|
|
216
258
|
export type SimulationSuccess = {
|
|
217
259
|
status: "success";
|
|
218
|
-
/**
|
|
219
|
-
|
|
260
|
+
/** Balance observations mirrored 1:1 from successful queries, including zero deltas. */
|
|
261
|
+
balanceDeltas: BalanceDelta[];
|
|
262
|
+
/** Queries that could not be read, usually because an ERC-20 `balanceOf` staticcall failed. */
|
|
263
|
+
unresolved: BalanceQuery[];
|
|
220
264
|
};
|
|
221
265
|
|
|
222
266
|
/** Simulation result for a transaction revert; infrastructure failures throw typed errors instead. */
|
|
223
267
|
export type SimulationReverted = {
|
|
224
268
|
status: "reverted";
|
|
225
|
-
/**
|
|
226
|
-
|
|
269
|
+
/** Balance observations mirrored 1:1 from successful queries, including zero deltas. */
|
|
270
|
+
balanceDeltas: BalanceDelta[];
|
|
271
|
+
/** Queries that could not be read, usually because an ERC-20 `balanceOf` staticcall failed. */
|
|
272
|
+
unresolved: BalanceQuery[];
|
|
227
273
|
/** Raw EVM revert data from the failing simulated call. */
|
|
228
274
|
revertData: Hex;
|
|
229
275
|
/** Human-readable decoded revert; present when revertData decodes via supplied error definitions or as built-in Error/Panic. */
|