@morpho-org/evm-simulation 4.2.1 → 5.0.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.
Files changed (160) hide show
  1. package/README.md +109 -17
  2. package/lib/cjs/authorizations.d.ts +95 -0
  3. package/lib/cjs/authorizations.js +2 -0
  4. package/lib/cjs/errors.d.ts +199 -12
  5. package/lib/cjs/errors.js +190 -12
  6. package/lib/cjs/index.d.ts +10 -2
  7. package/lib/cjs/index.js +19 -3
  8. package/lib/cjs/limits.d.ts +112 -0
  9. package/lib/cjs/limits.js +50 -0
  10. package/lib/cjs/params.d.ts +26 -0
  11. package/lib/cjs/params.js +5 -0
  12. package/lib/cjs/requirements/index.d.ts +1 -0
  13. package/lib/cjs/requirements/index.js +5 -0
  14. package/lib/cjs/requirements/requirements.d.ts +64 -0
  15. package/lib/cjs/requirements/requirements.js +149 -0
  16. package/lib/cjs/result.d.ts +49 -0
  17. package/lib/cjs/result.js +2 -0
  18. package/lib/cjs/simulate/asset-changes.d.ts +7 -5
  19. package/lib/cjs/simulate/asset-changes.js +6 -5
  20. package/lib/cjs/simulate/backends/client.d.ts +16 -0
  21. package/lib/cjs/simulate/backends/client.js +27 -0
  22. package/lib/cjs/simulate/backends/eth-simulate-v1.d.ts +69 -20
  23. package/lib/cjs/simulate/backends/eth-simulate-v1.js +174 -98
  24. package/lib/cjs/simulate/backends/index.d.ts +1 -2
  25. package/lib/cjs/simulate/backends/index.js +3 -4
  26. package/lib/cjs/simulate/backends/parse-response.d.ts +69 -0
  27. package/lib/cjs/simulate/backends/parse-response.js +168 -0
  28. package/lib/cjs/simulate/backends/resolve-assets.d.ts +26 -0
  29. package/lib/cjs/simulate/backends/resolve-assets.js +111 -0
  30. package/lib/cjs/simulate/backends/resolve-pinned-block.d.ts +33 -0
  31. package/lib/cjs/simulate/backends/resolve-pinned-block.js +46 -0
  32. package/lib/cjs/simulate/context.d.ts +14 -0
  33. package/lib/cjs/simulate/context.js +2 -0
  34. package/lib/cjs/simulate/measurement-plan.d.ts +29 -0
  35. package/lib/cjs/simulate/measurement-plan.js +115 -0
  36. package/lib/cjs/simulate/parsing/transfers.d.ts +4 -3
  37. package/lib/cjs/simulate/parsing/transfers.js +4 -6
  38. package/lib/cjs/simulate/pipeline/bundles-retention.d.ts +7 -10
  39. package/lib/cjs/simulate/pipeline/bundles-retention.js +11 -14
  40. package/lib/cjs/simulate/pipeline/resolve-chain.d.ts +5 -11
  41. package/lib/cjs/simulate/pipeline/resolve-chain.js +5 -10
  42. package/lib/cjs/simulate/plan/plan-execution.d.ts +58 -0
  43. package/lib/cjs/simulate/plan/plan-execution.js +75 -0
  44. package/lib/cjs/simulate/prepare.d.ts +30 -0
  45. package/lib/cjs/simulate/prepare.js +80 -0
  46. package/lib/cjs/simulate/request/index.d.ts +1 -0
  47. package/lib/cjs/simulate/request/index.js +5 -0
  48. package/lib/cjs/simulate/request/parse-request.d.ts +44 -0
  49. package/lib/cjs/simulate/request/parse-request.js +759 -0
  50. package/lib/cjs/simulate/result.d.ts +19 -0
  51. package/lib/cjs/simulate/result.js +29 -0
  52. package/lib/cjs/simulate/run-simulation.d.ts +18 -0
  53. package/lib/cjs/simulate/run-simulation.js +156 -0
  54. package/lib/cjs/simulate/simulate.d.ts +102 -51
  55. package/lib/cjs/simulate/simulate.js +101 -82
  56. package/lib/cjs/simulate/slippage.d.ts +18 -0
  57. package/lib/cjs/simulate/slippage.js +41 -0
  58. package/lib/cjs/simulate/state/contract.d.ts +19 -0
  59. package/lib/cjs/simulate/state/contract.js +2 -0
  60. package/lib/cjs/simulate/state/read-state.d.ts +60 -0
  61. package/lib/cjs/simulate/state/read-state.js +148 -0
  62. package/lib/cjs/simulate/verify-slippage.d.ts +24 -0
  63. package/lib/cjs/simulate/verify-slippage.js +85 -0
  64. package/lib/cjs/types.d.ts +37 -96
  65. package/lib/esm/authorizations.d.ts +95 -0
  66. package/lib/esm/authorizations.js +1 -0
  67. package/lib/esm/errors.d.ts +199 -12
  68. package/lib/esm/errors.js +182 -11
  69. package/lib/esm/index.d.ts +10 -2
  70. package/lib/esm/index.js +4 -1
  71. package/lib/esm/limits.d.ts +112 -0
  72. package/lib/esm/limits.js +47 -0
  73. package/lib/esm/params.d.ts +26 -0
  74. package/lib/esm/params.js +2 -0
  75. package/lib/esm/requirements/index.d.ts +1 -0
  76. package/lib/esm/requirements/index.js +1 -0
  77. package/lib/esm/requirements/requirements.d.ts +64 -0
  78. package/lib/esm/requirements/requirements.js +146 -0
  79. package/lib/esm/result.d.ts +49 -0
  80. package/lib/esm/result.js +1 -0
  81. package/lib/esm/simulate/asset-changes.d.ts +7 -5
  82. package/lib/esm/simulate/asset-changes.js +6 -5
  83. package/lib/esm/simulate/backends/client.d.ts +16 -0
  84. package/lib/esm/simulate/backends/client.js +24 -0
  85. package/lib/esm/simulate/backends/eth-simulate-v1.d.ts +69 -20
  86. package/lib/esm/simulate/backends/eth-simulate-v1.js +172 -99
  87. package/lib/esm/simulate/backends/index.d.ts +1 -2
  88. package/lib/esm/simulate/backends/index.js +1 -2
  89. package/lib/esm/simulate/backends/parse-response.d.ts +69 -0
  90. package/lib/esm/simulate/backends/parse-response.js +165 -0
  91. package/lib/esm/simulate/backends/resolve-assets.d.ts +26 -0
  92. package/lib/esm/simulate/backends/resolve-assets.js +108 -0
  93. package/lib/esm/simulate/backends/resolve-pinned-block.d.ts +33 -0
  94. package/lib/esm/simulate/backends/resolve-pinned-block.js +43 -0
  95. package/lib/esm/simulate/context.d.ts +14 -0
  96. package/lib/esm/simulate/context.js +1 -0
  97. package/lib/esm/simulate/measurement-plan.d.ts +29 -0
  98. package/lib/esm/simulate/measurement-plan.js +112 -0
  99. package/lib/esm/simulate/parsing/transfers.d.ts +4 -3
  100. package/lib/esm/simulate/parsing/transfers.js +4 -6
  101. package/lib/esm/simulate/pipeline/bundles-retention.d.ts +7 -10
  102. package/lib/esm/simulate/pipeline/bundles-retention.js +11 -14
  103. package/lib/esm/simulate/pipeline/resolve-chain.d.ts +5 -11
  104. package/lib/esm/simulate/pipeline/resolve-chain.js +5 -10
  105. package/lib/esm/simulate/plan/plan-execution.d.ts +58 -0
  106. package/lib/esm/simulate/plan/plan-execution.js +72 -0
  107. package/lib/esm/simulate/prepare.d.ts +30 -0
  108. package/lib/esm/simulate/prepare.js +77 -0
  109. package/lib/esm/simulate/request/index.d.ts +1 -0
  110. package/lib/esm/simulate/request/index.js +1 -0
  111. package/lib/esm/simulate/request/parse-request.d.ts +44 -0
  112. package/lib/esm/simulate/request/parse-request.js +756 -0
  113. package/lib/esm/simulate/result.d.ts +19 -0
  114. package/lib/esm/simulate/result.js +26 -0
  115. package/lib/esm/simulate/run-simulation.d.ts +18 -0
  116. package/lib/esm/simulate/run-simulation.js +153 -0
  117. package/lib/esm/simulate/simulate.d.ts +102 -51
  118. package/lib/esm/simulate/simulate.js +101 -82
  119. package/lib/esm/simulate/slippage.d.ts +18 -0
  120. package/lib/esm/simulate/slippage.js +38 -0
  121. package/lib/esm/simulate/state/contract.d.ts +19 -0
  122. package/lib/esm/simulate/state/contract.js +1 -0
  123. package/lib/esm/simulate/state/read-state.d.ts +60 -0
  124. package/lib/esm/simulate/state/read-state.js +144 -0
  125. package/lib/esm/simulate/verify-slippage.d.ts +24 -0
  126. package/lib/esm/simulate/verify-slippage.js +82 -0
  127. package/lib/esm/types.d.ts +37 -96
  128. package/package.json +7 -6
  129. package/lib/cjs/simulate/authorizations/index.d.ts +0 -2
  130. package/lib/cjs/simulate/authorizations/index.js +0 -7
  131. package/lib/cjs/simulate/authorizations/resolve.d.ts +0 -9
  132. package/lib/cjs/simulate/authorizations/resolve.js +0 -29
  133. package/lib/cjs/simulate/authorizations/validate.d.ts +0 -6
  134. package/lib/cjs/simulate/authorizations/validate.js +0 -23
  135. package/lib/cjs/simulate/backends/tenderly-rpc.d.ts +0 -23
  136. package/lib/cjs/simulate/backends/tenderly-rpc.js +0 -234
  137. package/lib/cjs/simulate/pipeline/build-simulation-txs.d.ts +0 -17
  138. package/lib/cjs/simulate/pipeline/build-simulation-txs.js +0 -50
  139. package/lib/cjs/simulate/pipeline/execute-simulation.d.ts +0 -22
  140. package/lib/cjs/simulate/pipeline/execute-simulation.js +0 -82
  141. package/lib/cjs/simulate/pipeline/index.d.ts +0 -4
  142. package/lib/cjs/simulate/pipeline/index.js +0 -11
  143. package/lib/cjs/simulate/pipeline/validate-input.d.ts +0 -10
  144. package/lib/cjs/simulate/pipeline/validate-input.js +0 -55
  145. package/lib/esm/simulate/authorizations/index.d.ts +0 -2
  146. package/lib/esm/simulate/authorizations/index.js +0 -2
  147. package/lib/esm/simulate/authorizations/resolve.d.ts +0 -9
  148. package/lib/esm/simulate/authorizations/resolve.js +0 -26
  149. package/lib/esm/simulate/authorizations/validate.d.ts +0 -6
  150. package/lib/esm/simulate/authorizations/validate.js +0 -20
  151. package/lib/esm/simulate/backends/tenderly-rpc.d.ts +0 -23
  152. package/lib/esm/simulate/backends/tenderly-rpc.js +0 -231
  153. package/lib/esm/simulate/pipeline/build-simulation-txs.d.ts +0 -17
  154. package/lib/esm/simulate/pipeline/build-simulation-txs.js +0 -47
  155. package/lib/esm/simulate/pipeline/execute-simulation.d.ts +0 -22
  156. package/lib/esm/simulate/pipeline/execute-simulation.js +0 -79
  157. package/lib/esm/simulate/pipeline/index.d.ts +0 -4
  158. package/lib/esm/simulate/pipeline/index.js +0 -4
  159. package/lib/esm/simulate/pipeline/validate-input.d.ts +0 -10
  160. package/lib/esm/simulate/pipeline/validate-input.js +0 -52
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toSimulationAuthorizations = toSimulationAuthorizations;
4
+ const morpho_sdk_1 = require("@morpho-org/morpho-sdk");
5
+ const errors_js_1 = require("../errors.js");
6
+ const mismatch = (ctx) => (message, options) => {
7
+ throw new errors_js_1.AuthorizationRequestMismatchError(`${message}. Rebuild the wallet request from getRequirements()`, {
8
+ context: {
9
+ stage: "preparation",
10
+ chainId: ctx.chainId,
11
+ mode: ctx.mode,
12
+ blockNumber: ctx.blockNumber,
13
+ authorizationIndex: ctx.index,
14
+ },
15
+ ...options,
16
+ });
17
+ };
18
+ const unsupported = (ctx) => (message, options) => {
19
+ throw new errors_js_1.UnsupportedOperationError(message, {
20
+ context: {
21
+ stage: "preparation",
22
+ chainId: ctx.chainId,
23
+ mode: ctx.mode,
24
+ blockNumber: ctx.blockNumber,
25
+ authorizationIndex: ctx.index,
26
+ },
27
+ ...options,
28
+ });
29
+ };
30
+ const toErc2612Permit = (action, ctx) => {
31
+ if (action.typedData == null) {
32
+ mismatch(ctx)("Permit requirement carries no typedData payload");
33
+ }
34
+ return {
35
+ type: "erc2612Permit",
36
+ typedData: action.typedData,
37
+ };
38
+ };
39
+ const toPermit2SignatureTransfer = (action, ctx) => {
40
+ if (action.typedData == null) {
41
+ mismatch(ctx)("Permit2 requirement carries no typedData payload");
42
+ }
43
+ return {
44
+ type: "permit2SignatureTransfer",
45
+ owner: ctx.owner,
46
+ typedData: action.typedData,
47
+ };
48
+ };
49
+ const toBlueAuthorizationSignature = (action, ctx) => {
50
+ if (action.typedData == null) {
51
+ mismatch(ctx)("Authorization requirement carries no typedData payload");
52
+ }
53
+ return {
54
+ type: "blueAuthorizationSignature",
55
+ typedData: action.typedData,
56
+ };
57
+ };
58
+ const toErc20Approval = (requirement, ctx) => ({
59
+ type: "erc20Approval",
60
+ token: requirement.to,
61
+ owner: ctx.owner,
62
+ spender: requirement.action.args.spender,
63
+ amount: requirement.action.args.amount,
64
+ });
65
+ const toBlueAuthorization = (requirement, ctx) => ({
66
+ type: "blueAuthorization",
67
+ authorizer: ctx.owner,
68
+ authorized: requirement.action.args.authorized,
69
+ isAuthorized: requirement.action.args.isAuthorized,
70
+ });
71
+ /**
72
+ * Maps morpho-sdk action requirements, in order, onto simulation authorization descriptors.
73
+ *
74
+ * The adapter is a pure mapper — nothing is decoded or validated; `simulate()`'s request parser
75
+ * validates each authorization's shape and semantics when the request is parsed. Call requirements
76
+ * (`erc20Approval`, `blueAuthorization`) are mapped straight from `action.args` (the approval
77
+ * token is the requirement's `to`). Signature requirements (`permit`,
78
+ * `permit2SignatureTransfer`, `authorization`) carry their EIP-712 payload through unchanged; a
79
+ * missing payload throws {@link AuthorizationRequestMismatchError}. Any other requirement type
80
+ * throws {@link UnsupportedOperationError}.
81
+ *
82
+ * The function is pure and synchronous: no RPC reads, no clock, no signing.
83
+ *
84
+ * @param params - Mapping parameters.
85
+ * @param params.chainId - The chain the requirements were resolved on; carried into error contexts.
86
+ * @param params.mode - Simulation mode carried into error contexts (`"preview"` or `"final"`).
87
+ * @param params.blockNumber - Pinned block the simulation is verified against; carried into error contexts.
88
+ * @param params.owner - The account the requirements were resolved for (transaction sender).
89
+ * @param params.requirements - Requirements returned by `ActionOutput.getRequirements()`.
90
+ * @returns One {@link SimulationAuthorization} per input requirement, in the same order.
91
+ * @throws {AuthorizationRequestMismatchError} when a signature requirement carries no `typedData`.
92
+ * @throws {UnsupportedOperationError} when a requirement's action type is not a supported
93
+ * authorization.
94
+ * @example
95
+ * ```ts
96
+ * import { toSimulationAuthorizations } from "@morpho-org/evm-simulation";
97
+ * import { morphoViemExtension } from "@morpho-org/morpho-sdk";
98
+ * import { vaults } from "@morpho-org/morpho-test";
99
+ * import { createPublicClient, http, type Address } from "viem";
100
+ * import { mainnet } from "viem/chains";
101
+ *
102
+ * async function prepare(userAddress: Address, blockNumber: bigint) {
103
+ * const client = createPublicClient({ chain: mainnet, transport: http() })
104
+ * .extend(morphoViemExtension());
105
+ * const vault = client.morpho.vaultV1(
106
+ * vaults[mainnet.id].steakUsdc.address,
107
+ * mainnet.id,
108
+ * );
109
+ * const vaultData = await vault.getData();
110
+ * const requirements = await vault
111
+ * .deposit({ amount: 1_000_000n, userAddress, vaultData })
112
+ * .getRequirements();
113
+ * const authorizations = toSimulationAuthorizations({
114
+ * chainId: mainnet.id,
115
+ * mode: "final",
116
+ * blockNumber,
117
+ * owner: userAddress,
118
+ * requirements,
119
+ * });
120
+ * return authorizations; // readonly SimulationAuthorization[], one entry per requirement
121
+ * }
122
+ * ```
123
+ */
124
+ function toSimulationAuthorizations(params) {
125
+ const { chainId, mode, blockNumber, owner, requirements } = params;
126
+ return requirements.map((requirement, index) => {
127
+ const ctx = { chainId, mode, blockNumber, owner, index };
128
+ if ((0, morpho_sdk_1.isRequirementApproval)(requirement)) {
129
+ return toErc20Approval(requirement, ctx);
130
+ }
131
+ if ((0, morpho_sdk_1.isRequirementBlueAuthorization)(requirement)) {
132
+ return toBlueAuthorization(requirement, ctx);
133
+ }
134
+ if ((0, morpho_sdk_1.isRequirementSignature)(requirement)) {
135
+ const { action } = requirement;
136
+ switch (action.type) {
137
+ case "permit":
138
+ return toErc2612Permit(action, ctx);
139
+ case "permit2SignatureTransfer":
140
+ return toPermit2SignatureTransfer(action, ctx);
141
+ case "authorization":
142
+ return toBlueAuthorizationSignature(action, ctx);
143
+ default:
144
+ return unsupported(ctx)(`Signature requirement action type "${action.type}" is not supported. Only permit, permit2SignatureTransfer, and authorization signatures are supported`);
145
+ }
146
+ }
147
+ return unsupported(ctx)(`Requirement action type "${requirement.action.type}" is not supported. Only erc20Approval, blueAuthorization, permit, permit2SignatureTransfer, and authorization requirements are supported`);
148
+ });
149
+ }
@@ -0,0 +1,49 @@
1
+ import type { Address } from "viem";
2
+ import type { SimulationAuthorization } from "./authorizations.js";
3
+ import type { SimulationLimits, SimulationOperationSubject, SlippageLimits } from "./limits.js";
4
+ import type { SimulationMode } from "./params.js";
5
+ import type { SimulationCall, SimulationResult, SimulationTransaction } from "./types.js";
6
+ /** One operation described by the caller's `limits.operations`. */
7
+ export type SimulatedOperation = {
8
+ /** Quote and percentage tolerance checked against the named subject over the whole bundle. */
9
+ readonly checkedLimits: SlippageLimits;
10
+ /** Resolved selector from the limit; defaults to the transaction sender. */
11
+ readonly account: Address;
12
+ /** Resolved selector from the limit; defaults to the transaction sender. */
13
+ readonly receiver: Address;
14
+ } & SimulationOperationSubject;
15
+ /** How a pending authorization was modeled in preview. */
16
+ export interface AuthorizationPreparation {
17
+ readonly authorizationIndex: number;
18
+ readonly authorization: SimulationAuthorization;
19
+ /** Approval calls simulated before the user transactions. */
20
+ readonly calls: readonly {
21
+ readonly transaction: SimulationTransaction;
22
+ readonly result: SimulationCall;
23
+ }[];
24
+ }
25
+ /** Optional slippage checks; execution success does not imply economic verification. */
26
+ export interface SimulationVerification {
27
+ readonly mode: SimulationMode;
28
+ readonly chainId: number;
29
+ /**
30
+ * Block `eth_simulateV1` executed in: the pinned state block or its
31
+ * successor, depending on the node. Not a pin to pass back as
32
+ * `SimulateParams.blockNumber`.
33
+ */
34
+ readonly blockNumber: bigint;
35
+ /**
36
+ * Timestamp (seconds) of the block `eth_simulateV1` executed in: the
37
+ * pinned state block or its successor, depending on the node.
38
+ */
39
+ readonly blockTimestamp: bigint;
40
+ /** Caller-supplied quotes and tolerances only; omitted limits remain unchecked. */
41
+ readonly limits: Required<SimulationLimits>;
42
+ readonly operations: readonly SimulatedOperation[];
43
+ /** Preview only; always empty in final. */
44
+ readonly authorizations: readonly AuthorizationPreparation[];
45
+ }
46
+ /** `simulationTxs` equals the caller's `transactions`; `txIdx` indexes only those. */
47
+ export interface VerifiedSimulationResult extends SimulationResult {
48
+ readonly verification: SimulationVerification;
49
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -5,18 +5,20 @@ export interface AssetChangeEntry {
5
5
  account: Address;
6
6
  token: Address;
7
7
  diff: bigint;
8
+ /** Not populated by `eth_simulateV1`; kept for forward compatibility. */
8
9
  symbol?: string;
9
10
  decimals?: number;
10
11
  }
11
12
  /**
12
13
  * Collapse the native-ETH sentinel to viem's lowercase `ethAddress`, checksumming
13
14
  * any real token address. `eth_simulateV1` synthesizes native moves from the
14
- * sentinel `0xeee…eee`, and Tenderly may echo it — in checksummed or any other
15
- * case — as an asset change's `contractAddress`. Native ETH is keyed by the exact
16
- * `ethAddress` constant here and in the bundles-retention guard, so a checksummed
15
+ * sentinel `0xeee…eee`, possibly in checksummed or any other case. Native ETH
16
+ * is keyed by the exact `ethAddress` constant here and in the bundles-retention
17
+ * guard, so a checksummed
17
18
  * sentinel would land on a separate map key and silently escape retention checks.
18
- * This is the single source of truth for token normalization shared by the
19
- * transfer-log parser and the Tenderly asset-change mapper.
19
+ * This is the single source of truth for token normalization, applied by the
20
+ * transfer-log parser; asset-change aggregation and the bundler-retention guard
21
+ * rely on its `ethAddress` keying.
20
22
  *
21
23
  * @param address - Token address emitting a transfer or carried by an asset change.
22
24
  * @returns `ethAddress` for the native sentinel, else the checksummed address.
@@ -6,12 +6,13 @@ const viem_1 = require("viem");
6
6
  /**
7
7
  * Collapse the native-ETH sentinel to viem's lowercase `ethAddress`, checksumming
8
8
  * any real token address. `eth_simulateV1` synthesizes native moves from the
9
- * sentinel `0xeee…eee`, and Tenderly may echo it — in checksummed or any other
10
- * case — as an asset change's `contractAddress`. Native ETH is keyed by the exact
11
- * `ethAddress` constant here and in the bundles-retention guard, so a checksummed
9
+ * sentinel `0xeee…eee`, possibly in checksummed or any other case. Native ETH
10
+ * is keyed by the exact `ethAddress` constant here and in the bundles-retention
11
+ * guard, so a checksummed
12
12
  * sentinel would land on a separate map key and silently escape retention checks.
13
- * This is the single source of truth for token normalization shared by the
14
- * transfer-log parser and the Tenderly asset-change mapper.
13
+ * This is the single source of truth for token normalization, applied by the
14
+ * transfer-log parser; asset-change aggregation and the bundler-retention guard
15
+ * rely on its `ethAddress` keying.
15
16
  *
16
17
  * @param address - Token address emitting a transfer or carried by an asset change.
17
18
  * @returns `ethAddress` for the native sentinel, else the checksummed address.
@@ -0,0 +1,16 @@
1
+ import { type PublicClient } from "viem";
2
+ /**
3
+ * Create the viem public client shared by every simulation backend stage
4
+ * (pinned block resolution, binding/pinned reads, `eth_simulateV1`).
5
+ *
6
+ * A supplied abort signal is bound into the transport: a failed or aborted
7
+ * request must not consume another attempt or a fresh budget, and the pipeline
8
+ * abort signal owns the overall execution deadline, so the client sends zero
9
+ * retries and disables viem's own timeout when a signal is present.
10
+ *
11
+ * @param rpcUrl - Endpoint URL; each caller supplies the transport it trusts.
12
+ * @param signal - Optional pipeline abort signal shared by every request.
13
+ * @returns A viem {@link PublicClient} honoring the shared abort/timeout budget.
14
+ * @internal
15
+ */
16
+ export declare function createSimulationClient(rpcUrl: string, signal?: AbortSignal): PublicClient;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createSimulationClient = createSimulationClient;
4
+ const viem_1 = require("viem");
5
+ /**
6
+ * Create the viem public client shared by every simulation backend stage
7
+ * (pinned block resolution, binding/pinned reads, `eth_simulateV1`).
8
+ *
9
+ * A supplied abort signal is bound into the transport: a failed or aborted
10
+ * request must not consume another attempt or a fresh budget, and the pipeline
11
+ * abort signal owns the overall execution deadline, so the client sends zero
12
+ * retries and disables viem's own timeout when a signal is present.
13
+ *
14
+ * @param rpcUrl - Endpoint URL; each caller supplies the transport it trusts.
15
+ * @param signal - Optional pipeline abort signal shared by every request.
16
+ * @returns A viem {@link PublicClient} honoring the shared abort/timeout budget.
17
+ * @internal
18
+ */
19
+ function createSimulationClient(rpcUrl, signal) {
20
+ return (0, viem_1.createPublicClient)({
21
+ transport: (0, viem_1.http)(rpcUrl, {
22
+ fetchOptions: signal ? { signal } : undefined,
23
+ retryCount: 0,
24
+ timeout: signal ? 0 : undefined,
25
+ }),
26
+ });
27
+ }
@@ -1,24 +1,73 @@
1
- import { type Address, type BlockTag } from "viem";
2
- import type { RawSimulationResult, SimulationTransaction } from "../../types.js";
1
+ import { type Client, type PublicClient } from "viem";
2
+ import type { SimulationMode } from "../../params.js";
3
+ import type { ExecutionPlan } from "../plan/plan-execution.js";
4
+ import type { SimulationExecution } from "./parse-response.js";
5
+ import type { PinnedBlock } from "./resolve-pinned-block.js";
6
+ /** The JSON-RPC methods this boundary calls. */
7
+ type RpcLabel = "eth_getBlock" | "eth_chainId" | "eth_simulateV1";
8
+ /** Run one RPC call; anything thrown becomes a typed boundary error. @internal */
9
+ export declare const rpc: <T>(label: RpcLabel, call: () => Promise<T>) => Promise<T>;
10
+ /** Validate the endpoint identity through the same URL-safe RPC boundary. @internal */
11
+ export declare function assertEndpointChain(params: {
12
+ readonly client: Pick<PublicClient, "getChainId">;
13
+ readonly chainId: number;
14
+ readonly mode: SimulationMode;
15
+ readonly blockNumber?: bigint;
16
+ }): Promise<void>;
3
17
  /**
4
- * Simulate transactions using eth_simulateV1 (viem simulateCalls).
18
+ * Execute an {@link ExecutionPlan} through a single `eth_simulateV1` call and
19
+ * collect the pinned execution.
5
20
  *
6
- * Uses stateOverride to set the user's ETH balance high enough to avoid
7
- * false "insufficient balance for gas" reverts.
21
+ * The caller checks the endpoint chain identity and resolves the pinned state
22
+ * block before this boundary. This function uses that same block for the
23
+ * simulation and reorg check under the shared abort/timeout budget.
8
24
  *
9
- * Runs with `traceTransfers` enabled, so the node synthesizes native-ETH moves
10
- * (the top-level `value` *and* ETH moved through internal calls — e.g. a
11
- * `WETH.withdraw` refund or a swap that pays out ETH) as `Transfer` events from
12
- * the native sentinel. Derives `assetChanges` (net per-token deltas grouped by
13
- * account) entirely from the emitted transfer logs, with native ETH normalized
14
- * to viem's `ethAddress`. Top-level `value` is intentionally *not* added on top:
15
- * `traceTransfers` already logs it, so adding it would double-count.
25
+ * The boundary performs these steps:
26
+ *
27
+ * 1. **`eth_simulateV1`** — one `blockStateCalls` entry carrying the planned
28
+ * calls with their per-call `from`, `traceTransfers: true` so the node
29
+ * synthesizes native-ETH moves as transfer logs, and `validation: false`
30
+ * (`true` on Monad, whose nodes reject `false` and charge no gas in the
31
+ * simulated block). Validation-off means gas is not charged, which is how
32
+ * gas is separated from economic effects.
33
+ * **No balance override is
34
+ * applied** — `value` transfers are funded by the sender's real native
35
+ * balance.
36
+ * 2. **Response validation** — the response is parsed before the reorg
37
+ * re-fetch so revert/mismatch evidence already in hand surfaces instead
38
+ * of being downgraded to a bypassable {@link ExternalServiceError} by a
39
+ * failing re-fetch. The simulated block must be exactly
40
+ * `stateBlockNumber` or `stateBlockNumber + 1`: geth-style nodes report
41
+ * the former's successor while Anvil reports the pinned block itself.
42
+ * The result records whatever the node returns; consumers must read
43
+ * {@link ExecutionBlock.blockNumber} and never assume +1.
44
+ * 3. **Reorg check** — the pinned state block is re-fetched last to detect a reorg
45
+ * that swapped its hash mid-flight (`InvalidSimulationResponseError`).
46
+ *
47
+ * The endpoint must support `eth_simulateV1` with per-call `from`; there is
48
+ * no fallback backend.
49
+ *
50
+ * @param params - Shared simulation client, execution plan, already-pinned
51
+ * state block, and the `validation` flag to send.
52
+ * @returns Deep-frozen {@link SimulationExecution} — per-transaction call
53
+ * results and the resolved {@link ExecutionBlock}.
54
+ * @throws {ExternalServiceError} For transport failures, timeouts,
55
+ * or malformed JSON-RPC envelopes.
56
+ * @throws {InvalidSimulationResponseError} For a response that cannot be
57
+ * trusted (bad shape, call-count mismatch, block
58
+ * other than the pinned state block or its successor, a block timestamp
59
+ * earlier than the pinned block's, a per-call result that fails normalization,
60
+ * or a state-block hash that changed or is no longer served mid-flight).
61
+ * @throws {MissingVerificationEvidenceError} When a planned state read fails.
62
+ * @throws {SimulationRevertedError} When a preparation or user transaction
63
+ * reverts or the node reports a bundle-level revert (code 3 / insufficient
64
+ * funds).
65
+ * @internal
16
66
  */
17
- export declare function simulateV1(params: {
18
- rpcUrl: string;
19
- chainId: number;
20
- transactions: SimulationTransaction[];
21
- blockNumber?: bigint | BlockTag;
22
- wNative?: Address | null;
23
- signal?: AbortSignal;
24
- }): Promise<RawSimulationResult>;
67
+ export declare function executePlan(params: {
68
+ client: Client & Pick<PublicClient, "getBlock">;
69
+ plan: ExecutionPlan;
70
+ stateBlock: PinnedBlock;
71
+ validation: boolean;
72
+ }): Promise<SimulationExecution>;
73
+ export {};