@matterlabs/zksync-js 0.0.13 → 0.0.15
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/dist/adapters/ethers/client.cjs +13 -4
- package/dist/adapters/ethers/client.cjs.map +1 -1
- package/dist/adapters/ethers/client.d.ts +1 -2
- package/dist/adapters/ethers/client.js +6 -6
- package/dist/adapters/ethers/index.cjs +607 -259
- package/dist/adapters/ethers/index.cjs.map +1 -1
- package/dist/adapters/ethers/index.js +9 -9
- package/dist/adapters/ethers/resources/deposits/routes/priority.d.ts +12 -0
- package/dist/adapters/ethers/resources/deposits/services/gas.d.ts +4 -0
- package/dist/adapters/ethers/resources/interop/index.d.ts +14 -14
- package/dist/adapters/ethers/resources/interop/resolvers.d.ts +3 -8
- package/dist/adapters/ethers/resources/interop/routes/types.d.ts +2 -1
- package/dist/adapters/ethers/resources/interop/services/erc20.d.ts +10 -0
- package/dist/adapters/ethers/resources/interop/services/fee.d.ts +12 -0
- package/dist/adapters/ethers/resources/interop/services/finalization/index.d.ts +1 -1
- package/dist/adapters/ethers/resources/interop/services/finalization/polling.d.ts +1 -1
- package/dist/adapters/ethers/resources/interop/services/gas.d.ts +12 -0
- package/dist/adapters/ethers/resources/interop/types.d.ts +6 -14
- package/dist/adapters/ethers/sdk.cjs +1008 -259
- package/dist/adapters/ethers/sdk.cjs.map +1 -1
- package/dist/adapters/ethers/sdk.d.ts +6 -1
- package/dist/adapters/ethers/sdk.js +7 -7
- package/dist/adapters/viem/client.cjs +795 -7
- package/dist/adapters/viem/client.cjs.map +1 -1
- package/dist/adapters/viem/client.d.ts +6 -1
- package/dist/adapters/viem/client.js +6 -6
- package/dist/adapters/viem/index.cjs +6490 -2799
- package/dist/adapters/viem/index.cjs.map +1 -1
- package/dist/adapters/viem/index.d.ts +5 -0
- package/dist/adapters/viem/index.js +9 -9
- package/dist/adapters/viem/resources/deposits/routes/priority.d.ts +13 -0
- package/dist/adapters/viem/resources/deposits/services/gas.d.ts +4 -0
- package/dist/adapters/viem/resources/interop/address.d.ts +18 -0
- package/dist/adapters/viem/resources/interop/attributes/resource.d.ts +6 -0
- package/dist/adapters/viem/resources/interop/context.d.ts +31 -0
- package/dist/adapters/viem/resources/interop/index.d.ts +62 -0
- package/dist/adapters/viem/resources/interop/resolvers.d.ts +4 -0
- package/dist/adapters/viem/resources/interop/routes/direct.d.ts +2 -0
- package/dist/adapters/viem/resources/interop/routes/indirect.d.ts +2 -0
- package/dist/adapters/viem/resources/interop/routes/types.d.ts +23 -0
- package/dist/adapters/viem/resources/interop/services/erc20.d.ts +25 -0
- package/dist/adapters/viem/resources/interop/services/fee.d.ts +12 -0
- package/dist/adapters/viem/resources/interop/services/finalization/bundle.d.ts +15 -0
- package/dist/adapters/viem/resources/interop/services/finalization/data-fetchers.d.ts +17 -0
- package/dist/adapters/viem/resources/interop/services/finalization/decoders.d.ts +11 -0
- package/dist/adapters/viem/resources/interop/services/finalization/index.d.ts +13 -0
- package/dist/adapters/viem/resources/interop/services/finalization/polling.d.ts +7 -0
- package/dist/adapters/viem/resources/interop/services/finalization/status.d.ts +5 -0
- package/dist/adapters/viem/resources/interop/services/finalization/topics.d.ts +4 -0
- package/dist/adapters/viem/resources/interop/services/gas.d.ts +12 -0
- package/dist/adapters/viem/resources/interop/services/starter-data.d.ts +6 -0
- package/dist/adapters/viem/resources/interop/types.d.ts +8 -0
- package/dist/adapters/viem/sdk.cjs +6401 -2758
- package/dist/adapters/viem/sdk.cjs.map +1 -1
- package/dist/adapters/viem/sdk.d.ts +8 -1
- package/dist/adapters/viem/sdk.js +7 -7
- package/dist/{chunk-E3KP7XCG.js → chunk-3HHUZXSV.js} +1 -1
- package/dist/{chunk-EDWBCPO3.js → chunk-4PZCNTQ3.js} +1387 -71
- package/dist/{chunk-UDBRUBEK.js → chunk-65HAYKVL.js} +2 -2
- package/dist/chunk-BWKWWLY4.js +9 -0
- package/dist/{chunk-JHO2UQ5F.js → chunk-HGB3DOV2.js} +445 -554
- package/dist/{chunk-HI64OOAR.js → chunk-HVHMLAYH.js} +1 -1
- package/dist/{chunk-2RIARDXZ.js → chunk-JHRYNLZG.js} +65 -7
- package/dist/{chunk-RI73VJSH.js → chunk-JXR5V5YK.js} +463 -27
- package/dist/chunk-K2UVKMLN.js +658 -0
- package/dist/{chunk-53MC5BR2.js → chunk-MDPX5LNW.js} +1 -1
- package/dist/{chunk-QQ2OR434.js → chunk-MT4X5FEO.js} +18 -2
- package/dist/{chunk-R5WRFPK2.js → chunk-MZBKM3GH.js} +4 -4
- package/dist/{chunk-5R7L5NM5.js → chunk-YIWXIP2M.js} +10 -2
- package/dist/core/constants.cjs +17 -1
- package/dist/core/constants.cjs.map +1 -1
- package/dist/core/constants.d.ts +9 -1
- package/dist/core/constants.js +1 -1
- package/dist/core/index.cjs +52 -24
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.js +5 -5
- package/dist/core/internal/abis/IERC7786Attributes.d.ts +21 -11
- package/dist/core/internal/abis/IInteropCenter.d.ts +4 -0
- package/dist/core/resources/deposits/chains.d.ts +1 -0
- package/dist/core/resources/deposits/gas.d.ts +7 -0
- package/dist/core/resources/deposits/priority.d.ts +41 -0
- package/dist/core/resources/interop/attributes/bundle.d.ts +1 -0
- package/dist/core/resources/interop/attributes/resource.d.ts +1 -0
- package/dist/core/resources/interop/plan.d.ts +11 -3
- package/dist/core/resources/interop/protocol.d.ts +3 -0
- package/dist/core/rpc/types.d.ts +1 -0
- package/dist/core/rpc/zks.d.ts +5 -1
- package/dist/core/types/errors.d.ts +5 -0
- package/dist/core/types/flows/interop.d.ts +11 -20
- package/dist/core/types/primitives.d.ts +2 -0
- package/dist/index.cjs +69 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -5
- package/package.json +1 -1
- package/dist/chunk-4S4XDA4N.js +0 -415
- package/dist/chunk-5L6EYUJB.js +0 -237
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
import { isL1MessageSentLog } from './chunk-3HHUZXSV.js';
|
|
2
|
+
import { IBridgehub_default, isHash66, isBigint, isHash, assertNever, createError, OP_INTEROP, isNumber, isAddress, isHash66Array } from './chunk-JXR5V5YK.js';
|
|
3
|
+
import { BUFFER, DEFAULT_ABI_BYTES, DEFAULT_PUBDATA_BYTES, TX_MEMORY_OVERHEAD_GAS, TX_OVERHEAD_GAS, L1_TX_MIN_L2_GAS_BASE, L1_TX_INTRINSIC_L2_GAS, L1_TX_DELTA_544_ENCODING_BYTES, L1_TX_DELTA_FACTORY_DEPS_L2_GAS, L1_TX_INTRINSIC_PUBDATA, L1_TX_DELTA_FACTORY_DEPS_PUBDATA, TX_SLOT_OVERHEAD_L2_GAS, PRIORITY_TX_MAX_GAS_LIMIT, L2_INTEROP_CENTER_ADDRESS, BUNDLE_IDENTIFIER } from './chunk-MT4X5FEO.js';
|
|
4
|
+
|
|
5
|
+
// src/core/resources/deposits/chains.ts
|
|
6
|
+
var ERAVM_CHAIN_IDS = /* @__PURE__ */ new Set([324n, 2741n, 11124n, 300n]);
|
|
7
|
+
function isEraVmChain(chainIdL2) {
|
|
8
|
+
return ERAVM_CHAIN_IDS.has(chainIdL2);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// src/core/resources/deposits/gas.ts
|
|
12
|
+
var CREATE_REESTIMATE_BUFFER = 15n;
|
|
13
|
+
var maxBigInt = (a, b) => a > b ? a : b;
|
|
14
|
+
function applyGasBuffer(gasLimit, bufferPct = BUFFER) {
|
|
15
|
+
return gasLimit * (100n + bufferPct) / 100n;
|
|
16
|
+
}
|
|
17
|
+
function resolveCreateDepositL1GasLimit(input) {
|
|
18
|
+
const { chainIdL2, stepKey, preparedGasLimit, estimatedGasLimit } = input;
|
|
19
|
+
if (estimatedGasLimit == null) {
|
|
20
|
+
return preparedGasLimit;
|
|
21
|
+
}
|
|
22
|
+
const isEraVmBridgeStep = isEraVmChain(chainIdL2) && stepKey.startsWith("bridgehub:");
|
|
23
|
+
const reestimatedGasLimit = applyGasBuffer(
|
|
24
|
+
estimatedGasLimit,
|
|
25
|
+
isEraVmBridgeStep ? BUFFER : CREATE_REESTIMATE_BUFFER
|
|
26
|
+
);
|
|
27
|
+
if (isEraVmBridgeStep && preparedGasLimit != null) {
|
|
28
|
+
return maxBigInt(preparedGasLimit, reestimatedGasLimit);
|
|
29
|
+
}
|
|
30
|
+
return reestimatedGasLimit;
|
|
31
|
+
}
|
|
32
|
+
function makeGasQuote(p) {
|
|
33
|
+
const maxPriorityFeePerGas = p.maxPriorityFeePerGas ?? 0n;
|
|
34
|
+
return {
|
|
35
|
+
gasLimit: p.gasLimit,
|
|
36
|
+
maxFeePerGas: p.maxFeePerGas,
|
|
37
|
+
maxPriorityFeePerGas,
|
|
38
|
+
gasPerPubdata: p.gasPerPubdata,
|
|
39
|
+
maxCost: p.gasLimit * p.maxFeePerGas
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
async function fetchFees(estimator) {
|
|
43
|
+
try {
|
|
44
|
+
const fees = await estimator.estimateFeesPerGas();
|
|
45
|
+
if (fees.maxFeePerGas != null) {
|
|
46
|
+
return {
|
|
47
|
+
maxFeePerGas: fees.maxFeePerGas,
|
|
48
|
+
maxPriorityFeePerGas: fees.maxPriorityFeePerGas ?? 0n
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (fees.gasPrice != null) {
|
|
52
|
+
return {
|
|
53
|
+
maxFeePerGas: fees.gasPrice,
|
|
54
|
+
maxPriorityFeePerGas: 0n
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
} catch {
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
const gp = await estimator.getGasPrice();
|
|
61
|
+
return { maxFeePerGas: gp, maxPriorityFeePerGas: 0n };
|
|
62
|
+
} catch {
|
|
63
|
+
return { maxFeePerGas: 0n, maxPriorityFeePerGas: 0n };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function quoteL1Gas(input) {
|
|
67
|
+
const { estimator, tx, overrides, fallbackGasLimit } = input;
|
|
68
|
+
let market;
|
|
69
|
+
const getMarket = async () => {
|
|
70
|
+
if (market) return market;
|
|
71
|
+
market = await fetchFees(estimator);
|
|
72
|
+
return market;
|
|
73
|
+
};
|
|
74
|
+
const maxFeePerGas = overrides?.maxFeePerGas ?? (tx.maxFeePerGas != null ? BigInt(tx.maxFeePerGas) : (await getMarket()).maxFeePerGas);
|
|
75
|
+
const maxPriorityFeePerGas = overrides?.maxPriorityFeePerGas ?? (tx.maxPriorityFeePerGas != null ? BigInt(tx.maxPriorityFeePerGas) : (await getMarket()).maxPriorityFeePerGas);
|
|
76
|
+
const explicitGasLimit = overrides?.gasLimit ?? (tx.gasLimit != null ? BigInt(tx.gasLimit) : void 0);
|
|
77
|
+
if (explicitGasLimit != null) {
|
|
78
|
+
return makeGasQuote({ gasLimit: explicitGasLimit, maxFeePerGas, maxPriorityFeePerGas });
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const est = await estimator.estimateGas(tx);
|
|
82
|
+
const buffered = applyGasBuffer(BigInt(est));
|
|
83
|
+
return makeGasQuote({ gasLimit: buffered, maxFeePerGas, maxPriorityFeePerGas });
|
|
84
|
+
} catch {
|
|
85
|
+
if (fallbackGasLimit != null) {
|
|
86
|
+
return makeGasQuote({ gasLimit: fallbackGasLimit, maxFeePerGas, maxPriorityFeePerGas });
|
|
87
|
+
}
|
|
88
|
+
return void 0;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function quoteL2Gas(input) {
|
|
92
|
+
const { estimator, route, tx, gasPerPubdata, l2GasLimit, overrideGasLimit, stateOverrides } = input;
|
|
93
|
+
const market = await fetchFees(estimator);
|
|
94
|
+
const maxFeePerGas = market.maxFeePerGas || market.maxPriorityFeePerGas || 0n;
|
|
95
|
+
const txGasLimit = tx?.gasLimit != null ? BigInt(tx.gasLimit) : void 0;
|
|
96
|
+
const explicit = overrideGasLimit ?? txGasLimit;
|
|
97
|
+
if (explicit != null) {
|
|
98
|
+
return makeGasQuote({
|
|
99
|
+
gasLimit: explicit,
|
|
100
|
+
maxFeePerGas,
|
|
101
|
+
gasPerPubdata
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (!tx) {
|
|
105
|
+
return makeGasQuote({
|
|
106
|
+
gasLimit: l2GasLimit ?? 0n,
|
|
107
|
+
maxFeePerGas,
|
|
108
|
+
gasPerPubdata
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const execEstimate = await estimator.estimateGas(tx, stateOverrides);
|
|
113
|
+
const memoryBytes = route === "erc20-nonbase" ? 500n : DEFAULT_ABI_BYTES;
|
|
114
|
+
const pubdataBytes = route === "erc20-nonbase" ? 200n : DEFAULT_PUBDATA_BYTES;
|
|
115
|
+
const pp = gasPerPubdata ?? 800n;
|
|
116
|
+
const memoryOverhead = memoryBytes * TX_MEMORY_OVERHEAD_GAS;
|
|
117
|
+
const pubdataOverhead = pubdataBytes * pp;
|
|
118
|
+
let total = BigInt(execEstimate) + TX_OVERHEAD_GAS + memoryOverhead + pubdataOverhead;
|
|
119
|
+
total = applyGasBuffer(total);
|
|
120
|
+
return makeGasQuote({
|
|
121
|
+
gasLimit: total,
|
|
122
|
+
maxFeePerGas,
|
|
123
|
+
gasPerPubdata: pp
|
|
124
|
+
});
|
|
125
|
+
} catch {
|
|
126
|
+
return makeGasQuote({
|
|
127
|
+
gasLimit: l2GasLimit ?? 0n,
|
|
128
|
+
maxFeePerGas,
|
|
129
|
+
gasPerPubdata
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async function quoteL2BaseCost(input) {
|
|
134
|
+
const { estimator, encode, bridgehub, chainIdL2, l2GasLimit, gasPerPubdata } = input;
|
|
135
|
+
const market = await fetchFees(estimator);
|
|
136
|
+
const l1GasPrice = market.maxFeePerGas || market.maxPriorityFeePerGas || 0n;
|
|
137
|
+
if (l1GasPrice === 0n) {
|
|
138
|
+
throw new Error("Could not fetch L1 gas price for Bridgehub base cost calculation.");
|
|
139
|
+
}
|
|
140
|
+
const data = encode(IBridgehub_default, "l2TransactionBaseCost", [
|
|
141
|
+
chainIdL2,
|
|
142
|
+
l1GasPrice,
|
|
143
|
+
l2GasLimit,
|
|
144
|
+
gasPerPubdata
|
|
145
|
+
]);
|
|
146
|
+
const raw = await estimator.call({
|
|
147
|
+
to: bridgehub,
|
|
148
|
+
data
|
|
149
|
+
});
|
|
150
|
+
return BigInt(raw);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// src/core/codec/ntv.ts
|
|
154
|
+
function createNTVCodec(deps) {
|
|
155
|
+
function encodeAssetId(originChainId, ntvAddress, tokenAddress) {
|
|
156
|
+
const encoded = deps.encode(
|
|
157
|
+
["uint256", "address", "address"],
|
|
158
|
+
[originChainId, ntvAddress, tokenAddress]
|
|
159
|
+
);
|
|
160
|
+
return deps.keccak256(encoded);
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
encodeAssetId
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// src/core/types/flows/interop.ts
|
|
168
|
+
function isInteropMessageProof(obj) {
|
|
169
|
+
if (typeof obj !== "object" || obj === null) return false;
|
|
170
|
+
const proof = obj;
|
|
171
|
+
return isBigint(proof.chainId) && isBigint(proof.l1BatchNumber) && isBigint(proof.l2MessageIndex) && typeof proof.message === "object" && proof.message !== null && isNumber(proof.message.txNumberInBatch) && isAddress(proof.message.sender) && isHash(proof.message.data) && isHash66Array(proof.proof);
|
|
172
|
+
}
|
|
173
|
+
function isInteropFinalizationInfo(obj) {
|
|
174
|
+
if (typeof obj !== "object" || obj === null) return false;
|
|
175
|
+
const info = obj;
|
|
176
|
+
return isHash66(info.l2SrcTxHash) && isHash66(info.bundleHash) && isBigint(info.dstChainId) && isHash(info.encodedData) && isInteropMessageProof(info.proof);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// src/core/resources/interop/route.ts
|
|
180
|
+
function sumActionMsgValue(actions) {
|
|
181
|
+
let sum = 0n;
|
|
182
|
+
for (const a of actions) {
|
|
183
|
+
if (a.type === "sendNative") sum += a.amount;
|
|
184
|
+
else if (a.type === "call" && a.value) sum += a.value;
|
|
185
|
+
}
|
|
186
|
+
return sum;
|
|
187
|
+
}
|
|
188
|
+
function sumErc20Amounts(actions) {
|
|
189
|
+
let sum = 0n;
|
|
190
|
+
for (const a of actions) if (a.type === "sendErc20") sum += a.amount;
|
|
191
|
+
return sum;
|
|
192
|
+
}
|
|
193
|
+
function pickInteropRoute(args) {
|
|
194
|
+
const hasErc20 = args.actions.some((a) => a.type === "sendErc20");
|
|
195
|
+
const baseMatches = args.ctx.baseTokenSrc.toLowerCase() === args.ctx.baseTokenDst.toLowerCase();
|
|
196
|
+
if (hasErc20) return "indirect";
|
|
197
|
+
if (!baseMatches) return "indirect";
|
|
198
|
+
return "direct";
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// src/core/types/primitives.ts
|
|
202
|
+
var ZERO_HASH = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
203
|
+
|
|
204
|
+
// src/core/types/fees.ts
|
|
205
|
+
function toGasOverrides(overrides) {
|
|
206
|
+
const { nonce: _, ...gas } = overrides;
|
|
207
|
+
return gas;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// src/core/resources/deposits/fee.ts
|
|
211
|
+
function buildFeeBreakdown(p) {
|
|
212
|
+
const l1MaxTotal = p.l1Gas?.maxCost ?? 0n;
|
|
213
|
+
const l2Total = p.l2BaseCost + p.operatorTip;
|
|
214
|
+
const l1 = {
|
|
215
|
+
gasLimit: p.l1Gas?.gasLimit ?? 0n,
|
|
216
|
+
maxFeePerGas: p.l1Gas?.maxFeePerGas ?? 0n,
|
|
217
|
+
maxPriorityFeePerGas: p.l1Gas?.maxPriorityFeePerGas,
|
|
218
|
+
maxTotal: l1MaxTotal
|
|
219
|
+
};
|
|
220
|
+
const l2 = {
|
|
221
|
+
total: l2Total,
|
|
222
|
+
baseCost: p.l2BaseCost,
|
|
223
|
+
operatorTip: p.operatorTip,
|
|
224
|
+
gasLimit: p.l2Gas?.gasLimit ?? 0n,
|
|
225
|
+
maxFeePerGas: p.l2Gas?.maxFeePerGas ?? 0n,
|
|
226
|
+
maxPriorityFeePerGas: p.l2Gas?.maxPriorityFeePerGas,
|
|
227
|
+
gasPerPubdata: p.l2Gas?.gasPerPubdata ?? 0n
|
|
228
|
+
};
|
|
229
|
+
return {
|
|
230
|
+
token: p.feeToken,
|
|
231
|
+
maxTotal: l1MaxTotal + l2Total,
|
|
232
|
+
mintValue: p.mintValue,
|
|
233
|
+
l1,
|
|
234
|
+
l2
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// src/core/resources/deposits/priority.ts
|
|
239
|
+
var PRIORITY_TX_ENCODING_STEP_BYTES = 544n;
|
|
240
|
+
var DEFAULT_PRIORITY_BODY_GAS_ESTIMATE_MULTIPLIER = 6n;
|
|
241
|
+
var ERAVM_PRIORITY_L2_GAS_BUFFER = 30n;
|
|
242
|
+
var maxBigInt2 = (a, b) => a > b ? a : b;
|
|
243
|
+
var ceilDiv = (a, b) => (a + b - 1n) / b;
|
|
244
|
+
function derivePriorityTxGasBreakdown(input) {
|
|
245
|
+
const factoryDepsCount = input.factoryDepsCount ?? 0n;
|
|
246
|
+
const minBodyGas = maxBigInt2(
|
|
247
|
+
L1_TX_INTRINSIC_L2_GAS + ceilDiv(
|
|
248
|
+
input.encodedLength * L1_TX_DELTA_544_ENCODING_BYTES,
|
|
249
|
+
PRIORITY_TX_ENCODING_STEP_BYTES
|
|
250
|
+
) + factoryDepsCount * L1_TX_DELTA_FACTORY_DEPS_L2_GAS,
|
|
251
|
+
L1_TX_MIN_L2_GAS_BASE
|
|
252
|
+
) + L1_TX_INTRINSIC_PUBDATA * input.gasPerPubdata + factoryDepsCount * L1_TX_DELTA_FACTORY_DEPS_PUBDATA * input.gasPerPubdata;
|
|
253
|
+
const overhead = maxBigInt2(TX_SLOT_OVERHEAD_L2_GAS, TX_MEMORY_OVERHEAD_GAS * input.encodedLength);
|
|
254
|
+
const derivedBodyGas = minBodyGas;
|
|
255
|
+
return {
|
|
256
|
+
encodedLength: input.encodedLength,
|
|
257
|
+
minBodyGas,
|
|
258
|
+
overhead,
|
|
259
|
+
derivedBodyGas,
|
|
260
|
+
derivedL2GasLimit: derivedBodyGas + overhead,
|
|
261
|
+
priorityTxMaxGasLimit: PRIORITY_TX_MAX_GAS_LIMIT,
|
|
262
|
+
priorityTxMaxGasLimitExceeded: derivedBodyGas > PRIORITY_TX_MAX_GAS_LIMIT
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
function derivePriorityBodyGasEstimateCap(input) {
|
|
266
|
+
return input.minBodyGas * (input.multiplier ?? DEFAULT_PRIORITY_BODY_GAS_ESTIMATE_MULTIPLIER);
|
|
267
|
+
}
|
|
268
|
+
function applyPriorityL2GasLimitBuffer(input) {
|
|
269
|
+
if (!isEraVmChain(input.chainIdL2)) {
|
|
270
|
+
return input.gasLimit;
|
|
271
|
+
}
|
|
272
|
+
return input.gasLimit * (100n + ERAVM_PRIORITY_L2_GAS_BUFFER) / 100n;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// src/core/resources/interop/attributes/call.ts
|
|
276
|
+
function createCallAttributes(codec) {
|
|
277
|
+
const indirectCall = (messageValue) => codec.encode("indirectCall", [messageValue]);
|
|
278
|
+
const interopCallValue = (bridgedAmount) => codec.encode("interopCallValue", [bridgedAmount]);
|
|
279
|
+
return {
|
|
280
|
+
indirectCall,
|
|
281
|
+
interopCallValue
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// src/core/resources/interop/attributes/bundle.ts
|
|
286
|
+
function createBundleAttributes(codec) {
|
|
287
|
+
const executionAddress = (executor) => codec.encode("executionAddress", [executor]);
|
|
288
|
+
const unbundlerAddress = (addr) => codec.encode("unbundlerAddress", [addr]);
|
|
289
|
+
const useFixedFee = (enabled) => codec.encode("useFixedFee", [enabled]);
|
|
290
|
+
return {
|
|
291
|
+
executionAddress,
|
|
292
|
+
unbundlerAddress,
|
|
293
|
+
useFixedFee
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// src/core/resources/interop/attributes/resource.ts
|
|
298
|
+
function createAttributesResource(codec) {
|
|
299
|
+
return {
|
|
300
|
+
call: createCallAttributes(codec),
|
|
301
|
+
bundle: createBundleAttributes(codec)
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// src/core/resources/interop/plan.ts
|
|
306
|
+
function preflightDirect(params, ctx) {
|
|
307
|
+
if (!params.actions?.length) {
|
|
308
|
+
throw new Error('route "direct" requires at least one action.');
|
|
309
|
+
}
|
|
310
|
+
const baseMatch = ctx.baseTokens.src.toLowerCase() === ctx.baseTokens.dst.toLowerCase();
|
|
311
|
+
if (!baseMatch) {
|
|
312
|
+
throw new Error('route "direct" requires matching base tokens between source and destination.');
|
|
313
|
+
}
|
|
314
|
+
for (const action of params.actions) {
|
|
315
|
+
switch (action.type) {
|
|
316
|
+
case "sendNative":
|
|
317
|
+
if (action.amount < 0n) {
|
|
318
|
+
throw new Error("sendNative.amount must be >= 0.");
|
|
319
|
+
}
|
|
320
|
+
break;
|
|
321
|
+
case "call":
|
|
322
|
+
if (action.value != null && action.value < 0n) {
|
|
323
|
+
throw new Error("call.value must be >= 0 when provided.");
|
|
324
|
+
}
|
|
325
|
+
break;
|
|
326
|
+
default:
|
|
327
|
+
throw new Error(
|
|
328
|
+
`route "direct" does not support ${action.type} actions; use the indirect route.`
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
function buildDirectBundle(params, ctx, attrs, interopFeeInfo) {
|
|
334
|
+
const totalActionValue = sumActionMsgValue(params.actions);
|
|
335
|
+
const starters = params.actions.map((action, index) => {
|
|
336
|
+
const to = ctx.codec.formatAddress(action.to);
|
|
337
|
+
const callAttributes = attrs.callAttributes[index] ?? [];
|
|
338
|
+
switch (action.type) {
|
|
339
|
+
case "sendNative":
|
|
340
|
+
return [to, "0x", callAttributes];
|
|
341
|
+
case "call":
|
|
342
|
+
return [to, action.data ?? "0x", callAttributes];
|
|
343
|
+
default:
|
|
344
|
+
throw new Error(`buildDirectBundle: unsupported action type "${action.type}".`);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
return {
|
|
348
|
+
dstChain: ctx.codec.formatChain(ctx.dstChainId),
|
|
349
|
+
starters,
|
|
350
|
+
bundleAttributes: attrs.bundleAttributes,
|
|
351
|
+
approvals: interopFeeInfo.approval ? [interopFeeInfo.approval] : [],
|
|
352
|
+
interopFee: interopFeeInfo.fee,
|
|
353
|
+
quoteExtras: {
|
|
354
|
+
totalActionValue,
|
|
355
|
+
bridgedTokenTotal: 0n
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
function preflightIndirect(params, ctx) {
|
|
360
|
+
if (!params.actions?.length) {
|
|
361
|
+
throw new Error('route "indirect" requires at least one action.');
|
|
362
|
+
}
|
|
363
|
+
const hasErc20 = params.actions.some((a) => a.type === "sendErc20");
|
|
364
|
+
const baseMatches = ctx.baseTokens.src.toLowerCase() === ctx.baseTokens.dst.toLowerCase();
|
|
365
|
+
if (!hasErc20 && baseMatches) {
|
|
366
|
+
throw new Error(
|
|
367
|
+
'route "indirect" requires ERC-20 actions or mismatched base tokens; use the direct route instead.'
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
for (const action of params.actions) {
|
|
371
|
+
switch (action.type) {
|
|
372
|
+
case "sendNative":
|
|
373
|
+
if (action.amount < 0n) {
|
|
374
|
+
throw new Error("sendNative.amount must be >= 0.");
|
|
375
|
+
}
|
|
376
|
+
break;
|
|
377
|
+
case "sendErc20":
|
|
378
|
+
if (action.amount < 0n) {
|
|
379
|
+
throw new Error("sendErc20.amount must be >= 0.");
|
|
380
|
+
}
|
|
381
|
+
break;
|
|
382
|
+
case "call":
|
|
383
|
+
if (action.value != null) {
|
|
384
|
+
if (action.value < 0n) {
|
|
385
|
+
throw new Error("call.value must be >= 0 when provided.");
|
|
386
|
+
}
|
|
387
|
+
if (action.value > 0n && !baseMatches) {
|
|
388
|
+
throw new Error("indirect route does not support call.value when base tokens differ.");
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
break;
|
|
392
|
+
default:
|
|
393
|
+
assertNever(action);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
function buildIndirectBundle(params, ctx, attrs, starterData, interopFeeInfo) {
|
|
398
|
+
const totalActionValue = sumActionMsgValue(params.actions);
|
|
399
|
+
const bridgedTokenTotal = sumErc20Amounts(params.actions);
|
|
400
|
+
const approvalMap = /* @__PURE__ */ new Map();
|
|
401
|
+
for (const action of params.actions) {
|
|
402
|
+
if (action.type !== "sendErc20") continue;
|
|
403
|
+
const key = action.token.toLowerCase();
|
|
404
|
+
const existing = approvalMap.get(key);
|
|
405
|
+
if (existing) {
|
|
406
|
+
existing.amount += action.amount;
|
|
407
|
+
} else {
|
|
408
|
+
approvalMap.set(key, {
|
|
409
|
+
token: action.token,
|
|
410
|
+
spender: ctx.l2NativeTokenVault,
|
|
411
|
+
amount: action.amount
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
const approvals = Array.from(approvalMap.values());
|
|
416
|
+
if (interopFeeInfo.approval) approvals.push(interopFeeInfo.approval);
|
|
417
|
+
const starters = params.actions.map((action, index) => {
|
|
418
|
+
const callAttributes = attrs.callAttributes[index] ?? [];
|
|
419
|
+
if (starterData[index]?.assetRouterPayload) {
|
|
420
|
+
const l2AssetRouter = ctx.codec.formatAddress(ctx.l2AssetRouter);
|
|
421
|
+
return [l2AssetRouter, starterData[index].assetRouterPayload, callAttributes];
|
|
422
|
+
}
|
|
423
|
+
const directTo = ctx.codec.formatAddress(action.to);
|
|
424
|
+
switch (action.type) {
|
|
425
|
+
case "sendNative":
|
|
426
|
+
return [directTo, "0x", callAttributes];
|
|
427
|
+
case "call":
|
|
428
|
+
return [directTo, action.data ?? "0x", callAttributes];
|
|
429
|
+
case "sendErc20":
|
|
430
|
+
throw new Error("buildIndirectBundle: missing assetRouterPayload for sendErc20 action.");
|
|
431
|
+
default:
|
|
432
|
+
return assertNever(action);
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
return {
|
|
436
|
+
dstChain: ctx.codec.formatChain(ctx.dstChainId),
|
|
437
|
+
starters,
|
|
438
|
+
bundleAttributes: attrs.bundleAttributes,
|
|
439
|
+
approvals,
|
|
440
|
+
interopFee: interopFeeInfo.fee,
|
|
441
|
+
quoteExtras: {
|
|
442
|
+
totalActionValue,
|
|
443
|
+
bridgedTokenTotal
|
|
444
|
+
}
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// src/core/resources/interop/protocol.ts
|
|
449
|
+
var MIN_INTEROP_PROTOCOL = 31;
|
|
450
|
+
function assertProtocolVersion(chainId, protocolVersion) {
|
|
451
|
+
if (protocolVersion[1] < MIN_INTEROP_PROTOCOL) {
|
|
452
|
+
throw createError("VALIDATION", {
|
|
453
|
+
resource: "interop",
|
|
454
|
+
operation: OP_INTEROP.context.protocolVersion,
|
|
455
|
+
message: `Interop requires protocol version 31.0+. Found: ${protocolVersion[1]}.${protocolVersion[2]} for chain: ${chainId}.`,
|
|
456
|
+
context: {
|
|
457
|
+
chainId,
|
|
458
|
+
requiredMinor: MIN_INTEROP_PROTOCOL,
|
|
459
|
+
semver: protocolVersion
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// src/core/resources/interop/finalization.ts
|
|
466
|
+
var DEFAULT_POLL_MS = 1e3;
|
|
467
|
+
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
468
|
+
function resolveIdsFromWaitable(input) {
|
|
469
|
+
if (typeof input === "string") {
|
|
470
|
+
return { l2SrcTxHash: input };
|
|
471
|
+
}
|
|
472
|
+
return {
|
|
473
|
+
l2SrcTxHash: input.l2SrcTxHash,
|
|
474
|
+
bundleHash: input.bundleHash,
|
|
475
|
+
dstExecTxHash: input.dstExecTxHash
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
function parseBundleSentFromReceipt(input) {
|
|
479
|
+
const { receipt, interopCenter, interopBundleSentTopic, decodeInteropBundleSent } = input;
|
|
480
|
+
const bundleSentLog = receipt.logs.find(
|
|
481
|
+
(log) => log.address.toLowerCase() === interopCenter.toLowerCase() && log.topics[0].toLowerCase() === interopBundleSentTopic.toLowerCase()
|
|
482
|
+
);
|
|
483
|
+
if (!bundleSentLog) {
|
|
484
|
+
throw createError("STATE", {
|
|
485
|
+
resource: "interop",
|
|
486
|
+
operation: OP_INTEROP.svc.status.parseSentLog,
|
|
487
|
+
message: "Failed to locate InteropBundleSent event in source receipt.",
|
|
488
|
+
context: { receipt, interopCenter }
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
const decoded = decodeInteropBundleSent({
|
|
492
|
+
data: bundleSentLog.data,
|
|
493
|
+
topics: bundleSentLog.topics
|
|
494
|
+
});
|
|
495
|
+
return { bundleHash: decoded.bundleHash, dstChainId: decoded.destinationChainId };
|
|
496
|
+
}
|
|
497
|
+
function parseBundleReceiptInfo(params) {
|
|
498
|
+
const {
|
|
499
|
+
rawReceipt,
|
|
500
|
+
interopCenter,
|
|
501
|
+
interopBundleSentTopic,
|
|
502
|
+
decodeInteropBundleSent,
|
|
503
|
+
decodeL1MessageData,
|
|
504
|
+
l2SrcTxHash
|
|
505
|
+
} = params;
|
|
506
|
+
let l2ToL1LogIndex = -1;
|
|
507
|
+
let l1MessageData = null;
|
|
508
|
+
let found;
|
|
509
|
+
for (const log of rawReceipt.logs) {
|
|
510
|
+
if (isL1MessageSentLog(log)) {
|
|
511
|
+
l2ToL1LogIndex += 1;
|
|
512
|
+
try {
|
|
513
|
+
l1MessageData = decodeL1MessageData(log);
|
|
514
|
+
} catch (e) {
|
|
515
|
+
throw createError("STATE", {
|
|
516
|
+
resource: "interop",
|
|
517
|
+
operation: OP_INTEROP.svc.status.parseSentLog,
|
|
518
|
+
message: "Failed to decode L1MessageSent log data for interop bundle.",
|
|
519
|
+
context: { l2SrcTxHash, l2ToL1LogIndex },
|
|
520
|
+
cause: e
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
if (log.address.toLowerCase() !== interopCenter.toLowerCase() || log.topics[0].toLowerCase() !== interopBundleSentTopic.toLowerCase())
|
|
526
|
+
continue;
|
|
527
|
+
const decoded = decodeInteropBundleSent({
|
|
528
|
+
data: log.data,
|
|
529
|
+
topics: log.topics
|
|
530
|
+
});
|
|
531
|
+
found = {
|
|
532
|
+
bundleHash: decoded.bundleHash,
|
|
533
|
+
dstChainId: decoded.destinationChainId,
|
|
534
|
+
sourceChainId: decoded.sourceChainId
|
|
535
|
+
};
|
|
536
|
+
break;
|
|
537
|
+
}
|
|
538
|
+
if (!found) {
|
|
539
|
+
throw createError("STATE", {
|
|
540
|
+
resource: "interop",
|
|
541
|
+
operation: OP_INTEROP.svc.status.parseSentLog,
|
|
542
|
+
message: "Failed to locate InteropBundleSent event in source receipt.",
|
|
543
|
+
context: { l2SrcTxHash, interopCenter }
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
if (!l1MessageData) {
|
|
547
|
+
throw createError("STATE", {
|
|
548
|
+
resource: "interop",
|
|
549
|
+
operation: OP_INTEROP.svc.status.parseSentLog,
|
|
550
|
+
message: "Failed to locate L1MessageSent log data for interop bundle.",
|
|
551
|
+
context: { l2SrcTxHash, interopCenter }
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
return {
|
|
555
|
+
bundleHash: found.bundleHash,
|
|
556
|
+
dstChainId: found.dstChainId,
|
|
557
|
+
sourceChainId: found.sourceChainId,
|
|
558
|
+
l1MessageData,
|
|
559
|
+
l2ToL1LogIndex,
|
|
560
|
+
txNumberInBatch: Number(rawReceipt.transactionIndex),
|
|
561
|
+
rawReceipt
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
function getBundleEncodedData(messageData) {
|
|
565
|
+
const prefix = `0x${messageData.slice(2, 4)}`;
|
|
566
|
+
if (prefix !== BUNDLE_IDENTIFIER) {
|
|
567
|
+
throw createError("STATE", {
|
|
568
|
+
resource: "interop",
|
|
569
|
+
operation: OP_INTEROP.wait,
|
|
570
|
+
message: "Unexpected bundle prefix in L1MessageSent data.",
|
|
571
|
+
context: { prefix, expected: BUNDLE_IDENTIFIER }
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
return `0x${messageData.slice(4)}`;
|
|
575
|
+
}
|
|
576
|
+
function buildFinalizationInfo(ids, bundleInfo, proof, messageData) {
|
|
577
|
+
const messageProof = {
|
|
578
|
+
chainId: bundleInfo.sourceChainId,
|
|
579
|
+
l1BatchNumber: proof.batchNumber,
|
|
580
|
+
l2MessageIndex: proof.id,
|
|
581
|
+
message: {
|
|
582
|
+
txNumberInBatch: bundleInfo.txNumberInBatch,
|
|
583
|
+
sender: L2_INTEROP_CENTER_ADDRESS,
|
|
584
|
+
data: messageData
|
|
585
|
+
},
|
|
586
|
+
proof: proof.proof
|
|
587
|
+
};
|
|
588
|
+
return {
|
|
589
|
+
l2SrcTxHash: ids.l2SrcTxHash,
|
|
590
|
+
bundleHash: bundleInfo.bundleHash,
|
|
591
|
+
dstChainId: bundleInfo.dstChainId,
|
|
592
|
+
proof: messageProof,
|
|
593
|
+
encodedData: getBundleEncodedData(messageData)
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// src/core/resources/withdrawals/gas.ts
|
|
598
|
+
function makeGasQuote2(p) {
|
|
599
|
+
return {
|
|
600
|
+
gasLimit: p.gasLimit,
|
|
601
|
+
maxFeePerGas: p.maxFeePerGas,
|
|
602
|
+
maxPriorityFeePerGas: p.maxPriorityFeePerGas,
|
|
603
|
+
maxCost: p.gasLimit * p.maxFeePerGas
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
async function fetchFees2(estimator) {
|
|
607
|
+
try {
|
|
608
|
+
const fees = await estimator.estimateFeesPerGas();
|
|
609
|
+
if (fees.maxFeePerGas != null) {
|
|
610
|
+
return {
|
|
611
|
+
maxFeePerGas: fees.maxFeePerGas,
|
|
612
|
+
maxPriorityFeePerGas: fees.maxPriorityFeePerGas ?? 0n
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
if (fees.gasPrice != null) {
|
|
616
|
+
return {
|
|
617
|
+
maxFeePerGas: fees.gasPrice,
|
|
618
|
+
maxPriorityFeePerGas: 0n
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
} catch {
|
|
622
|
+
}
|
|
623
|
+
try {
|
|
624
|
+
const gp = await estimator.getGasPrice();
|
|
625
|
+
return { maxFeePerGas: gp, maxPriorityFeePerGas: 0n };
|
|
626
|
+
} catch {
|
|
627
|
+
return { maxFeePerGas: 0n, maxPriorityFeePerGas: 0n };
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
async function quoteL2Gas2(input) {
|
|
631
|
+
const { estimator, tx, overrides } = input;
|
|
632
|
+
const market = await fetchFees2(estimator);
|
|
633
|
+
const o = overrides;
|
|
634
|
+
const maxFeePerGas = o?.maxFeePerGas ?? (tx.maxFeePerGas != null ? BigInt(tx.maxFeePerGas) : market.maxFeePerGas);
|
|
635
|
+
const maxPriorityFeePerGas = o?.maxPriorityFeePerGas ?? (tx.maxPriorityFeePerGas != null ? BigInt(tx.maxPriorityFeePerGas) : market.maxPriorityFeePerGas);
|
|
636
|
+
const explicitGasLimit = o?.gasLimit ?? (tx.gasLimit != null ? BigInt(tx.gasLimit) : void 0);
|
|
637
|
+
if (explicitGasLimit != null) {
|
|
638
|
+
return makeGasQuote2({
|
|
639
|
+
gasLimit: explicitGasLimit,
|
|
640
|
+
maxFeePerGas,
|
|
641
|
+
maxPriorityFeePerGas
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
try {
|
|
645
|
+
const est = await estimator.estimateGas(tx);
|
|
646
|
+
const buffered = BigInt(est) * (100n + BUFFER) / 100n;
|
|
647
|
+
return makeGasQuote2({
|
|
648
|
+
gasLimit: buffered,
|
|
649
|
+
maxFeePerGas,
|
|
650
|
+
maxPriorityFeePerGas
|
|
651
|
+
});
|
|
652
|
+
} catch (err) {
|
|
653
|
+
console.warn("Failed to estimate L2 gas for withdrawal.", err);
|
|
654
|
+
return void 0;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
export { DEFAULT_POLL_MS, DEFAULT_TIMEOUT_MS, ZERO_HASH, applyPriorityL2GasLimitBuffer, assertProtocolVersion, buildDirectBundle, buildFeeBreakdown, buildFinalizationInfo, buildIndirectBundle, createAttributesResource, createNTVCodec, derivePriorityBodyGasEstimateCap, derivePriorityTxGasBreakdown, isInteropFinalizationInfo, parseBundleReceiptInfo, parseBundleSentFromReceipt, pickInteropRoute, preflightDirect, preflightIndirect, quoteL1Gas, quoteL2BaseCost, quoteL2Gas, quoteL2Gas2, resolveCreateDepositL1GasLimit, resolveIdsFromWaitable, toGasOverrides };
|