@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.
- package/README.md +109 -17
- package/lib/cjs/authorizations.d.ts +95 -0
- package/lib/cjs/authorizations.js +2 -0
- package/lib/cjs/errors.d.ts +199 -12
- package/lib/cjs/errors.js +190 -12
- package/lib/cjs/index.d.ts +10 -2
- package/lib/cjs/index.js +19 -3
- package/lib/cjs/limits.d.ts +112 -0
- package/lib/cjs/limits.js +50 -0
- package/lib/cjs/params.d.ts +26 -0
- package/lib/cjs/params.js +5 -0
- package/lib/cjs/requirements/index.d.ts +1 -0
- package/lib/cjs/requirements/index.js +5 -0
- package/lib/cjs/requirements/requirements.d.ts +64 -0
- package/lib/cjs/requirements/requirements.js +149 -0
- package/lib/cjs/result.d.ts +49 -0
- package/lib/cjs/result.js +2 -0
- package/lib/cjs/simulate/asset-changes.d.ts +7 -5
- package/lib/cjs/simulate/asset-changes.js +6 -5
- package/lib/cjs/simulate/backends/client.d.ts +16 -0
- package/lib/cjs/simulate/backends/client.js +27 -0
- package/lib/cjs/simulate/backends/eth-simulate-v1.d.ts +69 -20
- package/lib/cjs/simulate/backends/eth-simulate-v1.js +174 -98
- package/lib/cjs/simulate/backends/index.d.ts +1 -2
- package/lib/cjs/simulate/backends/index.js +3 -4
- package/lib/cjs/simulate/backends/parse-response.d.ts +69 -0
- package/lib/cjs/simulate/backends/parse-response.js +168 -0
- package/lib/cjs/simulate/backends/resolve-assets.d.ts +26 -0
- package/lib/cjs/simulate/backends/resolve-assets.js +111 -0
- package/lib/cjs/simulate/backends/resolve-pinned-block.d.ts +33 -0
- package/lib/cjs/simulate/backends/resolve-pinned-block.js +46 -0
- package/lib/cjs/simulate/context.d.ts +14 -0
- package/lib/cjs/simulate/context.js +2 -0
- package/lib/cjs/simulate/measurement-plan.d.ts +29 -0
- package/lib/cjs/simulate/measurement-plan.js +115 -0
- package/lib/cjs/simulate/parsing/transfers.d.ts +4 -3
- package/lib/cjs/simulate/parsing/transfers.js +4 -6
- package/lib/cjs/simulate/pipeline/bundles-retention.d.ts +7 -10
- package/lib/cjs/simulate/pipeline/bundles-retention.js +11 -14
- package/lib/cjs/simulate/pipeline/resolve-chain.d.ts +5 -11
- package/lib/cjs/simulate/pipeline/resolve-chain.js +5 -10
- package/lib/cjs/simulate/plan/plan-execution.d.ts +58 -0
- package/lib/cjs/simulate/plan/plan-execution.js +75 -0
- package/lib/cjs/simulate/prepare.d.ts +30 -0
- package/lib/cjs/simulate/prepare.js +80 -0
- package/lib/cjs/simulate/request/index.d.ts +1 -0
- package/lib/cjs/simulate/request/index.js +5 -0
- package/lib/cjs/simulate/request/parse-request.d.ts +44 -0
- package/lib/cjs/simulate/request/parse-request.js +759 -0
- package/lib/cjs/simulate/result.d.ts +19 -0
- package/lib/cjs/simulate/result.js +29 -0
- package/lib/cjs/simulate/run-simulation.d.ts +18 -0
- package/lib/cjs/simulate/run-simulation.js +156 -0
- package/lib/cjs/simulate/simulate.d.ts +102 -51
- package/lib/cjs/simulate/simulate.js +101 -82
- package/lib/cjs/simulate/slippage.d.ts +18 -0
- package/lib/cjs/simulate/slippage.js +41 -0
- package/lib/cjs/simulate/state/contract.d.ts +19 -0
- package/lib/cjs/simulate/state/contract.js +2 -0
- package/lib/cjs/simulate/state/read-state.d.ts +60 -0
- package/lib/cjs/simulate/state/read-state.js +148 -0
- package/lib/cjs/simulate/verify-slippage.d.ts +24 -0
- package/lib/cjs/simulate/verify-slippage.js +85 -0
- package/lib/cjs/types.d.ts +37 -96
- package/lib/esm/authorizations.d.ts +95 -0
- package/lib/esm/authorizations.js +1 -0
- package/lib/esm/errors.d.ts +199 -12
- package/lib/esm/errors.js +182 -11
- package/lib/esm/index.d.ts +10 -2
- package/lib/esm/index.js +4 -1
- package/lib/esm/limits.d.ts +112 -0
- package/lib/esm/limits.js +47 -0
- package/lib/esm/params.d.ts +26 -0
- package/lib/esm/params.js +2 -0
- package/lib/esm/requirements/index.d.ts +1 -0
- package/lib/esm/requirements/index.js +1 -0
- package/lib/esm/requirements/requirements.d.ts +64 -0
- package/lib/esm/requirements/requirements.js +146 -0
- package/lib/esm/result.d.ts +49 -0
- package/lib/esm/result.js +1 -0
- package/lib/esm/simulate/asset-changes.d.ts +7 -5
- package/lib/esm/simulate/asset-changes.js +6 -5
- package/lib/esm/simulate/backends/client.d.ts +16 -0
- package/lib/esm/simulate/backends/client.js +24 -0
- package/lib/esm/simulate/backends/eth-simulate-v1.d.ts +69 -20
- package/lib/esm/simulate/backends/eth-simulate-v1.js +172 -99
- package/lib/esm/simulate/backends/index.d.ts +1 -2
- package/lib/esm/simulate/backends/index.js +1 -2
- package/lib/esm/simulate/backends/parse-response.d.ts +69 -0
- package/lib/esm/simulate/backends/parse-response.js +165 -0
- package/lib/esm/simulate/backends/resolve-assets.d.ts +26 -0
- package/lib/esm/simulate/backends/resolve-assets.js +108 -0
- package/lib/esm/simulate/backends/resolve-pinned-block.d.ts +33 -0
- package/lib/esm/simulate/backends/resolve-pinned-block.js +43 -0
- package/lib/esm/simulate/context.d.ts +14 -0
- package/lib/esm/simulate/context.js +1 -0
- package/lib/esm/simulate/measurement-plan.d.ts +29 -0
- package/lib/esm/simulate/measurement-plan.js +112 -0
- package/lib/esm/simulate/parsing/transfers.d.ts +4 -3
- package/lib/esm/simulate/parsing/transfers.js +4 -6
- package/lib/esm/simulate/pipeline/bundles-retention.d.ts +7 -10
- package/lib/esm/simulate/pipeline/bundles-retention.js +11 -14
- package/lib/esm/simulate/pipeline/resolve-chain.d.ts +5 -11
- package/lib/esm/simulate/pipeline/resolve-chain.js +5 -10
- package/lib/esm/simulate/plan/plan-execution.d.ts +58 -0
- package/lib/esm/simulate/plan/plan-execution.js +72 -0
- package/lib/esm/simulate/prepare.d.ts +30 -0
- package/lib/esm/simulate/prepare.js +77 -0
- package/lib/esm/simulate/request/index.d.ts +1 -0
- package/lib/esm/simulate/request/index.js +1 -0
- package/lib/esm/simulate/request/parse-request.d.ts +44 -0
- package/lib/esm/simulate/request/parse-request.js +756 -0
- package/lib/esm/simulate/result.d.ts +19 -0
- package/lib/esm/simulate/result.js +26 -0
- package/lib/esm/simulate/run-simulation.d.ts +18 -0
- package/lib/esm/simulate/run-simulation.js +153 -0
- package/lib/esm/simulate/simulate.d.ts +102 -51
- package/lib/esm/simulate/simulate.js +101 -82
- package/lib/esm/simulate/slippage.d.ts +18 -0
- package/lib/esm/simulate/slippage.js +38 -0
- package/lib/esm/simulate/state/contract.d.ts +19 -0
- package/lib/esm/simulate/state/contract.js +1 -0
- package/lib/esm/simulate/state/read-state.d.ts +60 -0
- package/lib/esm/simulate/state/read-state.js +144 -0
- package/lib/esm/simulate/verify-slippage.d.ts +24 -0
- package/lib/esm/simulate/verify-slippage.js +82 -0
- package/lib/esm/types.d.ts +37 -96
- package/package.json +7 -6
- package/lib/cjs/simulate/authorizations/index.d.ts +0 -2
- package/lib/cjs/simulate/authorizations/index.js +0 -7
- package/lib/cjs/simulate/authorizations/resolve.d.ts +0 -9
- package/lib/cjs/simulate/authorizations/resolve.js +0 -29
- package/lib/cjs/simulate/authorizations/validate.d.ts +0 -6
- package/lib/cjs/simulate/authorizations/validate.js +0 -23
- package/lib/cjs/simulate/backends/tenderly-rpc.d.ts +0 -23
- package/lib/cjs/simulate/backends/tenderly-rpc.js +0 -234
- package/lib/cjs/simulate/pipeline/build-simulation-txs.d.ts +0 -17
- package/lib/cjs/simulate/pipeline/build-simulation-txs.js +0 -50
- package/lib/cjs/simulate/pipeline/execute-simulation.d.ts +0 -22
- package/lib/cjs/simulate/pipeline/execute-simulation.js +0 -82
- package/lib/cjs/simulate/pipeline/index.d.ts +0 -4
- package/lib/cjs/simulate/pipeline/index.js +0 -11
- package/lib/cjs/simulate/pipeline/validate-input.d.ts +0 -10
- package/lib/cjs/simulate/pipeline/validate-input.js +0 -55
- package/lib/esm/simulate/authorizations/index.d.ts +0 -2
- package/lib/esm/simulate/authorizations/index.js +0 -2
- package/lib/esm/simulate/authorizations/resolve.d.ts +0 -9
- package/lib/esm/simulate/authorizations/resolve.js +0 -26
- package/lib/esm/simulate/authorizations/validate.d.ts +0 -6
- package/lib/esm/simulate/authorizations/validate.js +0 -20
- package/lib/esm/simulate/backends/tenderly-rpc.d.ts +0 -23
- package/lib/esm/simulate/backends/tenderly-rpc.js +0 -231
- package/lib/esm/simulate/pipeline/build-simulation-txs.d.ts +0 -17
- package/lib/esm/simulate/pipeline/build-simulation-txs.js +0 -47
- package/lib/esm/simulate/pipeline/execute-simulation.d.ts +0 -22
- package/lib/esm/simulate/pipeline/execute-simulation.js +0 -79
- package/lib/esm/simulate/pipeline/index.d.ts +0 -4
- package/lib/esm/simulate/pipeline/index.js +0 -4
- package/lib/esm/simulate/pipeline/validate-input.d.ts +0 -10
- 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
|
+
}
|
|
@@ -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`,
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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
|
|
19
|
-
* transfer-log parser and the
|
|
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`,
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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
|
|
14
|
-
* transfer-log parser and the
|
|
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
|
|
2
|
-
import type {
|
|
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
|
-
*
|
|
18
|
+
* Execute an {@link ExecutionPlan} through a single `eth_simulateV1` call and
|
|
19
|
+
* collect the pinned execution.
|
|
5
20
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
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
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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 {};
|