@matterlabs/zksync-js 0.0.1 → 0.0.2
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 +12 -12
- package/dist/adapters/ethers/client.cjs +642 -1
- package/dist/adapters/ethers/client.cjs.map +1 -1
- package/dist/adapters/ethers/client.js +6 -5
- package/dist/adapters/ethers/estimator.d.ts +4 -0
- package/dist/adapters/ethers/index.cjs +934 -801
- package/dist/adapters/ethers/index.cjs.map +1 -1
- package/dist/adapters/ethers/index.js +9 -8
- package/dist/adapters/ethers/resources/deposits/context.d.ts +5 -5
- package/dist/adapters/ethers/resources/deposits/routes/types.d.ts +2 -6
- package/dist/adapters/ethers/resources/deposits/services/fee.d.ts +6 -0
- package/dist/adapters/ethers/resources/deposits/services/gas.d.ts +40 -0
- package/dist/adapters/ethers/resources/utils.d.ts +4 -15
- package/dist/adapters/ethers/resources/withdrawals/context.d.ts +4 -4
- package/dist/adapters/ethers/resources/withdrawals/routes/types.d.ts +2 -2
- package/dist/adapters/ethers/resources/withdrawals/services/fees.d.ts +14 -0
- package/dist/adapters/ethers/resources/withdrawals/services/gas.d.ts +12 -0
- package/dist/adapters/ethers/sdk.cjs +947 -1292
- package/dist/adapters/ethers/sdk.cjs.map +1 -1
- package/dist/adapters/ethers/sdk.js +7 -6
- package/dist/adapters/viem/client.cjs.map +1 -1
- package/dist/adapters/viem/client.d.ts +1 -1
- package/dist/adapters/viem/client.js +4 -5
- package/dist/adapters/viem/estimator.d.ts +4 -0
- package/dist/adapters/viem/index.cjs +944 -662
- package/dist/adapters/viem/index.cjs.map +1 -1
- package/dist/adapters/viem/index.js +8 -8
- package/dist/adapters/viem/resources/deposits/context.d.ts +5 -5
- package/dist/adapters/viem/resources/deposits/routes/types.d.ts +2 -6
- package/dist/adapters/viem/resources/deposits/services/fee.d.ts +6 -0
- package/dist/adapters/viem/resources/deposits/services/gas.d.ts +36 -0
- package/dist/adapters/viem/resources/utils.d.ts +3 -16
- package/dist/adapters/viem/resources/withdrawals/context.d.ts +3 -6
- package/dist/adapters/viem/resources/withdrawals/routes/types.d.ts +12 -2
- package/dist/adapters/viem/resources/withdrawals/services/fee.d.ts +17 -0
- package/dist/adapters/viem/resources/withdrawals/services/gas.d.ts +12 -0
- package/dist/adapters/viem/sdk.cjs +877 -563
- package/dist/adapters/viem/sdk.cjs.map +1 -1
- package/dist/adapters/viem/sdk.d.ts +1 -1
- package/dist/adapters/viem/sdk.js +6 -6
- package/dist/{chunk-3LALBFFE.js → chunk-3MRGU4HV.js} +9 -5
- package/dist/{chunk-4HLJJKIY.js → chunk-6K6VJQAL.js} +2 -2
- package/dist/{chunk-CGO27P7F.js → chunk-BCCKWWOX.js} +540 -741
- package/dist/{chunk-6GCT6TLS.js → chunk-F2ENUV3A.js} +13 -1
- package/dist/{chunk-DI2CJDPZ.js → chunk-HLUANWGN.js} +2 -2
- package/dist/{chunk-Y75OMFK6.js → chunk-M5J2MM2U.js} +351 -1
- package/dist/{chunk-263G6636.js → chunk-NCAIVYBR.js} +1 -14
- package/dist/{chunk-7M4V3FMT.js → chunk-OC6ZVLSP.js} +669 -559
- package/dist/chunk-QJS6ETEE.js +217 -0
- package/dist/chunk-XRE7H466.js +157 -0
- package/dist/{chunk-BD2LUO5T.js → chunk-YUK547UF.js} +3 -3
- package/dist/core/abi.d.ts +9 -0
- package/dist/core/adapters/interfaces.d.ts +25 -0
- package/dist/core/constants.cjs +12 -0
- package/dist/core/constants.cjs.map +1 -1
- package/dist/core/constants.d.ts +6 -0
- package/dist/core/constants.js +1 -1
- package/dist/core/index.cjs +4504 -1
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +4 -4
- package/dist/core/resources/deposits/fee.d.ts +15 -0
- package/dist/core/resources/deposits/gas.d.ts +38 -0
- package/dist/core/resources/withdrawals/gas.d.ts +14 -0
- package/dist/core/types/errors.d.ts +1 -1
- package/dist/core/types/fees.d.ts +40 -0
- package/dist/core/types/flows/base.d.ts +0 -10
- package/dist/core/types/flows/deposits.d.ts +20 -6
- package/dist/core/types/flows/route.d.ts +2 -3
- package/dist/core/types/flows/withdrawals.d.ts +12 -6
- package/dist/index.cjs +4516 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -4
- package/package.json +5 -1
- package/dist/adapters/ethers/resources/withdrawals/routes/eth-nonbase.d.ts +0 -2
- package/dist/adapters/viem/resources/withdrawals/routes/eth-nonbase.d.ts +0 -2
- package/dist/chunk-B77GWPO5.js +0 -339
- package/dist/core/internal/abi-registry.d.ts +0 -9
- package/dist/core/utils/gas.d.ts +0 -13
|
@@ -223,35 +223,17 @@ var OP_DEPOSITS = {
|
|
|
223
223
|
assertErc20Asset: "deposits.erc20-base:assertErc20Asset",
|
|
224
224
|
assertMatchesBase: "deposits.erc20-base:assertMatchesBase",
|
|
225
225
|
baseToken: "deposits.erc20-base:baseToken",
|
|
226
|
-
allowance: "deposits.erc20-base:allowance",
|
|
227
|
-
baseCost: "deposits.erc20-base:l2TransactionBaseCost",
|
|
228
|
-
estGas: "deposits.erc20-base:estimateGas"
|
|
229
|
-
},
|
|
226
|
+
allowance: "deposits.erc20-base:allowance"},
|
|
230
227
|
nonbase: {
|
|
231
|
-
baseToken: "deposits.erc20-nonbase:baseToken",
|
|
232
|
-
assertNotEthAsset: "deposits.erc20-nonbase:assertNotEthAsset",
|
|
233
|
-
allowance: "deposits.erc20-nonbase:allowance",
|
|
234
|
-
allowanceFees: "deposits.erc20-nonbase:allowanceFeesBaseToken",
|
|
235
|
-
baseCost: "deposits.erc20-nonbase:l2TransactionBaseCost",
|
|
236
228
|
encodeCalldata: "deposits.erc20-nonbase:encodeSecondBridgeErc20Args",
|
|
237
|
-
estGas: "deposits.erc20-nonbase:estimateGas",
|
|
238
|
-
assertBaseIsEth: "deposits.erc20-nonbase:assertBaseIsEth",
|
|
239
|
-
assertBaseIsErc20: "deposits.erc20-nonbase:assertBaseIsErc20",
|
|
240
229
|
assertNonBaseToken: "deposits.erc20-nonbase:assertNonBaseToken",
|
|
241
230
|
allowanceToken: "deposits.erc20-nonbase:allowanceToken",
|
|
242
231
|
allowanceBase: "deposits.erc20-nonbase:allowanceBase"
|
|
243
232
|
},
|
|
244
|
-
eth: {
|
|
245
|
-
baseCost: "deposits.eth:l2TransactionBaseCost",
|
|
246
|
-
estGas: "deposits.eth:estimateGas"
|
|
247
|
-
},
|
|
248
233
|
ethNonBase: {
|
|
249
|
-
baseToken: "deposits.eth-nonbase:baseToken",
|
|
250
|
-
baseCost: "deposits.eth-nonbase:l2TransactionBaseCost",
|
|
251
234
|
allowanceBase: "deposits.eth-nonbase:allowanceBaseToken",
|
|
252
235
|
ethBalance: "deposits.eth-nonbase:getEthBalance",
|
|
253
236
|
encodeCalldata: "deposits.eth-nonbase:encodeSecondBridgeEthArgs",
|
|
254
|
-
estGas: "deposits.eth-nonbase:estimateGas",
|
|
255
237
|
assertEthAsset: "deposits.eth-nonbase:assertEthAsset",
|
|
256
238
|
assertNonEthBase: "deposits.eth-nonbase:assertNonEthBase",
|
|
257
239
|
assertEthBalance: "deposits.eth-nonbase:assertEthBalance"
|
|
@@ -603,8 +585,12 @@ var TOPIC_L1_MESSAGE_SENT_NEW = k256hex("L1MessageSent(uint256,bytes32,bytes)");
|
|
|
603
585
|
var TOPIC_L1_MESSAGE_SENT_LEG = k256hex("L1MessageSent(address,bytes32,bytes)");
|
|
604
586
|
var TOPIC_CANONICAL_ASSIGNED = "0x779f441679936c5441b671969f37400b8c3ed0071cb47444431bf985754560df";
|
|
605
587
|
var TOPIC_CANONICAL_SUCCESS = "0xe4def01b981193a97a9e81230d7b9f31812ceaf23f864a828a82c687911cb2df";
|
|
606
|
-
var
|
|
607
|
-
var
|
|
588
|
+
var BUFFER = 20n;
|
|
589
|
+
var TX_OVERHEAD_GAS = 10000n;
|
|
590
|
+
var TX_MEMORY_OVERHEAD_GAS = 10n;
|
|
591
|
+
var DEFAULT_PUBDATA_BYTES = 155n;
|
|
592
|
+
var DEFAULT_ABI_BYTES = 400n;
|
|
593
|
+
var SAFE_L1_BRIDGE_GAS = 600000n;
|
|
608
594
|
|
|
609
595
|
// src/core/internal/abis/IBridgehub.ts
|
|
610
596
|
var IBridgehubABI = [
|
|
@@ -5094,7 +5080,183 @@ var MailboxABI = [
|
|
|
5094
5080
|
];
|
|
5095
5081
|
var Mailbox_default = MailboxABI;
|
|
5096
5082
|
|
|
5083
|
+
// src/core/errors/withdrawal-revert-map.ts
|
|
5084
|
+
var REVERT_TO_READINESS = {
|
|
5085
|
+
// Already done
|
|
5086
|
+
WithdrawalAlreadyFinalized: { kind: "FINALIZED" },
|
|
5087
|
+
// Temporary — try later
|
|
5088
|
+
BatchNotExecuted: { kind: "NOT_READY", reason: "batch-not-executed" },
|
|
5089
|
+
LocalRootIsZero: { kind: "NOT_READY", reason: "root-missing" },
|
|
5090
|
+
// Permanent — won’t become ready for this tx
|
|
5091
|
+
WrongL2Sender: { kind: "UNFINALIZABLE", reason: "message-invalid" },
|
|
5092
|
+
InvalidSelector: { kind: "UNFINALIZABLE", reason: "message-invalid" },
|
|
5093
|
+
L2WithdrawalMessageWrongLength: { kind: "UNFINALIZABLE", reason: "message-invalid" },
|
|
5094
|
+
WrongMsgLength: { kind: "UNFINALIZABLE", reason: "message-invalid" },
|
|
5095
|
+
TokenNotLegacy: { kind: "UNFINALIZABLE", reason: "message-invalid" },
|
|
5096
|
+
TokenIsLegacy: { kind: "UNFINALIZABLE", reason: "message-invalid" },
|
|
5097
|
+
InvalidProof: { kind: "UNFINALIZABLE", reason: "message-invalid" },
|
|
5098
|
+
InvalidChainId: { kind: "UNFINALIZABLE", reason: "invalid-chain" },
|
|
5099
|
+
NotSettlementLayer: { kind: "UNFINALIZABLE", reason: "settlement-layer" },
|
|
5100
|
+
// Likely environment mismatch — treat as permanent for this tx
|
|
5101
|
+
OnlyEraSupported: { kind: "UNFINALIZABLE", reason: "unsupported" },
|
|
5102
|
+
LocalRootMustBeZero: { kind: "UNFINALIZABLE", reason: "unsupported" }
|
|
5103
|
+
};
|
|
5104
|
+
|
|
5105
|
+
// src/adapters/ethers/errors/revert.ts
|
|
5106
|
+
var ERROR_IFACES = [];
|
|
5107
|
+
var IFACE_ERROR_STRING = new ethers.Interface(["error Error(string)"]);
|
|
5108
|
+
var IFACE_PANIC = new ethers.Interface(["error Panic(uint256)"]);
|
|
5109
|
+
(function bootstrapDefaultIfaces() {
|
|
5110
|
+
try {
|
|
5111
|
+
ERROR_IFACES.push({
|
|
5112
|
+
name: "IL1Nullifier",
|
|
5113
|
+
iface: new ethers.Interface(IL1Nullifier_default)
|
|
5114
|
+
});
|
|
5115
|
+
} catch {
|
|
5116
|
+
}
|
|
5117
|
+
try {
|
|
5118
|
+
ERROR_IFACES.push({ name: "IERC20", iface: new ethers.Interface(IERC20_default) });
|
|
5119
|
+
} catch {
|
|
5120
|
+
}
|
|
5121
|
+
try {
|
|
5122
|
+
ERROR_IFACES.push({
|
|
5123
|
+
name: "IL1NativeTokenVault",
|
|
5124
|
+
iface: new ethers.Interface(L1NativeTokenVault_default)
|
|
5125
|
+
});
|
|
5126
|
+
} catch {
|
|
5127
|
+
}
|
|
5128
|
+
try {
|
|
5129
|
+
ERROR_IFACES.push({
|
|
5130
|
+
name: "IL2NativeTokenVault",
|
|
5131
|
+
iface: new ethers.Interface(L2NativeTokenVault_default)
|
|
5132
|
+
});
|
|
5133
|
+
} catch {
|
|
5134
|
+
}
|
|
5135
|
+
try {
|
|
5136
|
+
ERROR_IFACES.push({ name: "Mailbox", iface: new ethers.Interface(Mailbox_default) });
|
|
5137
|
+
} catch {
|
|
5138
|
+
}
|
|
5139
|
+
})();
|
|
5140
|
+
function registerErrorAbi(name, abi) {
|
|
5141
|
+
const existing = ERROR_IFACES.findIndex((x) => x.name === name);
|
|
5142
|
+
const entry = { name, iface: new ethers.Interface(abi) };
|
|
5143
|
+
if (existing >= 0) ERROR_IFACES[existing] = entry;
|
|
5144
|
+
else ERROR_IFACES.push(entry);
|
|
5145
|
+
}
|
|
5146
|
+
function extractRevertData(e) {
|
|
5147
|
+
const maybe = (
|
|
5148
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
5149
|
+
e?.data?.data ?? e?.error?.data ?? e?.data ?? e?.error?.error?.data ?? e?.info?.error?.data
|
|
5150
|
+
);
|
|
5151
|
+
if (typeof maybe === "string" && maybe.startsWith("0x") && maybe.length >= 10) {
|
|
5152
|
+
return maybe;
|
|
5153
|
+
}
|
|
5154
|
+
return void 0;
|
|
5155
|
+
}
|
|
5156
|
+
function decodeRevert(e) {
|
|
5157
|
+
const data = extractRevertData(e);
|
|
5158
|
+
if (!data) return;
|
|
5159
|
+
const selector = `0x${data.slice(2, 10)}`;
|
|
5160
|
+
try {
|
|
5161
|
+
const parsed = IFACE_ERROR_STRING.parseError(data);
|
|
5162
|
+
if (parsed?.name === "Error") {
|
|
5163
|
+
const args = parsed.args ? Array.from(parsed.args) : void 0;
|
|
5164
|
+
return { selector, name: "Error", args };
|
|
5165
|
+
}
|
|
5166
|
+
} catch {
|
|
5167
|
+
}
|
|
5168
|
+
try {
|
|
5169
|
+
const parsed = IFACE_PANIC.parseError(data);
|
|
5170
|
+
if (parsed?.name === "Panic") {
|
|
5171
|
+
const args = parsed.args ? Array.from(parsed.args) : void 0;
|
|
5172
|
+
return { selector, name: "Panic", args };
|
|
5173
|
+
}
|
|
5174
|
+
} catch {
|
|
5175
|
+
}
|
|
5176
|
+
for (const { name, iface } of ERROR_IFACES) {
|
|
5177
|
+
try {
|
|
5178
|
+
const parsed = iface.parseError(data);
|
|
5179
|
+
if (parsed) {
|
|
5180
|
+
const args = parsed.args ? Array.from(parsed.args) : void 0;
|
|
5181
|
+
return {
|
|
5182
|
+
selector,
|
|
5183
|
+
name: parsed.name,
|
|
5184
|
+
args,
|
|
5185
|
+
contract: name
|
|
5186
|
+
};
|
|
5187
|
+
}
|
|
5188
|
+
} catch {
|
|
5189
|
+
}
|
|
5190
|
+
}
|
|
5191
|
+
return { selector };
|
|
5192
|
+
}
|
|
5193
|
+
function classifyReadinessFromRevert(e) {
|
|
5194
|
+
const r = decodeRevert(e);
|
|
5195
|
+
const name = r?.name;
|
|
5196
|
+
if (name && REVERT_TO_READINESS[name]) return REVERT_TO_READINESS[name];
|
|
5197
|
+
const msg = (() => {
|
|
5198
|
+
if (typeof e !== "object" || e === null) return "";
|
|
5199
|
+
const obj = e;
|
|
5200
|
+
const maybeMsg = obj["shortMessage"] ?? obj["message"];
|
|
5201
|
+
return typeof maybeMsg === "string" ? maybeMsg : "";
|
|
5202
|
+
})();
|
|
5203
|
+
const lower = String(msg).toLowerCase();
|
|
5204
|
+
if (lower.includes("paused")) return { kind: "NOT_READY", reason: "paused" };
|
|
5205
|
+
if (name || r?.selector) {
|
|
5206
|
+
return { kind: "UNFINALIZABLE", reason: "unsupported", detail: name ?? r?.selector };
|
|
5207
|
+
}
|
|
5208
|
+
return { kind: "NOT_READY", reason: "unknown", detail: lower || void 0 };
|
|
5209
|
+
}
|
|
5210
|
+
|
|
5211
|
+
// src/adapters/ethers/errors/error-ops.ts
|
|
5212
|
+
function toZKsyncError(type, base, err) {
|
|
5213
|
+
if (isZKsyncError(err)) return err;
|
|
5214
|
+
const revert = decodeRevert(err);
|
|
5215
|
+
return createError(type, { ...base, ...revert ? { revert } : {}, cause: shapeCause(err) });
|
|
5216
|
+
}
|
|
5217
|
+
function resolveMessage(op, msg) {
|
|
5218
|
+
if (!msg) return `Error during ${op}.`;
|
|
5219
|
+
return typeof msg === "function" ? msg() : msg;
|
|
5220
|
+
}
|
|
5221
|
+
function createErrorHandlers(resource) {
|
|
5222
|
+
async function run(kind, operation, fn, opts) {
|
|
5223
|
+
try {
|
|
5224
|
+
return await fn();
|
|
5225
|
+
} catch (e) {
|
|
5226
|
+
if (isZKsyncError(e)) throw e;
|
|
5227
|
+
const message = resolveMessage(operation, opts?.message);
|
|
5228
|
+
throw toZKsyncError(kind, { resource, operation, context: opts?.ctx ?? {}, message }, e);
|
|
5229
|
+
}
|
|
5230
|
+
}
|
|
5231
|
+
function wrap2(operation, fn, opts) {
|
|
5232
|
+
return run("INTERNAL", operation, fn, opts);
|
|
5233
|
+
}
|
|
5234
|
+
function wrapAs9(kind, operation, fn, opts) {
|
|
5235
|
+
return run(kind, operation, fn, opts);
|
|
5236
|
+
}
|
|
5237
|
+
async function toResult2(operation, fn, opts) {
|
|
5238
|
+
try {
|
|
5239
|
+
const value = await wrap2(operation, fn, opts);
|
|
5240
|
+
return { ok: true, value };
|
|
5241
|
+
} catch (e) {
|
|
5242
|
+
const shaped = isZKsyncError(e) ? e : toZKsyncError(
|
|
5243
|
+
"INTERNAL",
|
|
5244
|
+
{
|
|
5245
|
+
resource,
|
|
5246
|
+
operation,
|
|
5247
|
+
context: opts?.ctx ?? {},
|
|
5248
|
+
message: resolveMessage(operation, opts?.message)
|
|
5249
|
+
},
|
|
5250
|
+
e
|
|
5251
|
+
);
|
|
5252
|
+
return { ok: false, error: shaped };
|
|
5253
|
+
}
|
|
5254
|
+
}
|
|
5255
|
+
return { wrap: wrap2, wrapAs: wrapAs9, toResult: toResult2 };
|
|
5256
|
+
}
|
|
5257
|
+
|
|
5097
5258
|
// src/adapters/ethers/client.ts
|
|
5259
|
+
var { wrapAs } = createErrorHandlers("client");
|
|
5098
5260
|
function createEthersClient(args) {
|
|
5099
5261
|
const { l1, l2, signer } = args;
|
|
5100
5262
|
let boundSigner = signer;
|
|
@@ -5192,7 +5354,10 @@ function createEthersClient(args) {
|
|
|
5192
5354
|
async function baseToken(chainId) {
|
|
5193
5355
|
const { bridgehub } = await ensureAddresses();
|
|
5194
5356
|
const bh = new ethers.Contract(bridgehub, IBridgehub_default, l1);
|
|
5195
|
-
return await bh.baseToken(chainId)
|
|
5357
|
+
return await wrapAs("CONTRACT", OP_DEPOSITS.base.baseToken, () => bh.baseToken(chainId), {
|
|
5358
|
+
ctx: { where: "bridgehub.baseToken", chainIdL2: chainId },
|
|
5359
|
+
message: "Failed to read base token."
|
|
5360
|
+
});
|
|
5196
5361
|
}
|
|
5197
5362
|
const client = {
|
|
5198
5363
|
kind: "ethers",
|
|
@@ -5297,22 +5462,38 @@ async function waitForL2ExecutionFromL1Tx(l1, l2, l1TxHash) {
|
|
|
5297
5462
|
return { l2Receipt, l2TxHash };
|
|
5298
5463
|
}
|
|
5299
5464
|
|
|
5300
|
-
// src/core/
|
|
5301
|
-
function
|
|
5302
|
-
if (
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
}
|
|
5306
|
-
}
|
|
5307
|
-
function assertPriorityFeeBounds(fees) {
|
|
5308
|
-
if (fees.maxPriorityFeePerGas > fees.maxFeePerGas) {
|
|
5309
|
-
throw new Error("maxPriorityFeePerGas cannot exceed maxFeePerGas.");
|
|
5465
|
+
// src/core/resources/deposits/route.ts
|
|
5466
|
+
async function pickDepositRoute(client, chainIdL2, token) {
|
|
5467
|
+
if (isETH(token)) {
|
|
5468
|
+
const base2 = await client.baseToken(chainIdL2);
|
|
5469
|
+
return isETH(base2) ? "eth-base" : "eth-nonbase";
|
|
5310
5470
|
}
|
|
5471
|
+
const base = await client.baseToken(chainIdL2);
|
|
5472
|
+
return normalizeAddrEq(token, base) ? "erc20-base" : "erc20-nonbase";
|
|
5311
5473
|
}
|
|
5312
5474
|
|
|
5313
|
-
// src/adapters/ethers/resources/
|
|
5314
|
-
function
|
|
5315
|
-
|
|
5475
|
+
// src/adapters/ethers/resources/deposits/context.ts
|
|
5476
|
+
async function commonCtx(p, client) {
|
|
5477
|
+
const { bridgehub, l1AssetRouter } = await client.ensureAddresses();
|
|
5478
|
+
const { chainId } = await client.l2.getNetwork();
|
|
5479
|
+
const sender = await client.signer.getAddress();
|
|
5480
|
+
const gasPerPubdata = p.gasPerPubdata ?? 800n;
|
|
5481
|
+
const operatorTip = p.operatorTip ?? 0n;
|
|
5482
|
+
const refundRecipient = p.refundRecipient ?? sender;
|
|
5483
|
+
const route = await pickDepositRoute(client, BigInt(chainId), p.token);
|
|
5484
|
+
return {
|
|
5485
|
+
client,
|
|
5486
|
+
l1AssetRouter,
|
|
5487
|
+
route,
|
|
5488
|
+
bridgehub,
|
|
5489
|
+
chainIdL2: BigInt(chainId),
|
|
5490
|
+
sender,
|
|
5491
|
+
gasOverrides: p.l1TxOverrides,
|
|
5492
|
+
l2GasLimit: p.l2GasLimit,
|
|
5493
|
+
gasPerPubdata,
|
|
5494
|
+
operatorTip,
|
|
5495
|
+
refundRecipient
|
|
5496
|
+
};
|
|
5316
5497
|
}
|
|
5317
5498
|
function encodeNativeTokenVaultAssetId(chainId, address) {
|
|
5318
5499
|
const abi = new ethers.AbiCoder();
|
|
@@ -5338,78 +5519,18 @@ function encodeNTVAssetId(chainId, address) {
|
|
|
5338
5519
|
);
|
|
5339
5520
|
return ethers.ethers.keccak256(hex);
|
|
5340
5521
|
}
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
async function checkBaseCost(baseCost, value) {
|
|
5348
|
-
const resolvedValue = await value;
|
|
5349
|
-
if (baseCost > resolvedValue) {
|
|
5350
|
-
throw new Error(
|
|
5351
|
-
`The base cost of performing the priority operation is higher than the provided value parameter for the transaction: baseCost: ${String(baseCost)}, provided value: ${String(resolvedValue)}!`
|
|
5352
|
-
);
|
|
5353
|
-
}
|
|
5354
|
-
}
|
|
5355
|
-
async function getFeeOverrides(client, overrides) {
|
|
5356
|
-
assertNoLegacyGas(overrides);
|
|
5357
|
-
const fd = await client.l1.getFeeData();
|
|
5358
|
-
const maxFeeFromProvider = fd.maxFeePerGas ?? void 0;
|
|
5359
|
-
const maxPriorityFromProvider = fd.maxPriorityFeePerGas ?? void 0;
|
|
5360
|
-
const gasPriceFallback = fd.gasPrice ?? void 0;
|
|
5361
|
-
const maxFeePerGas = overrides?.maxFeePerGas ?? maxFeeFromProvider ?? gasPriceFallback;
|
|
5362
|
-
if (maxFeePerGas == null) throw new Error("provider returned no gas price data");
|
|
5363
|
-
const maxPriorityFeePerGas = overrides?.maxPriorityFeePerGas ?? maxPriorityFromProvider ?? maxFeePerGas;
|
|
5364
|
-
assertPriorityFeeBounds({ maxFeePerGas, maxPriorityFeePerGas });
|
|
5365
|
-
const gasPriceForBaseCost = overrides?.maxFeePerGas ?? maxFeeFromProvider ?? gasPriceFallback ?? maxFeePerGas;
|
|
5366
|
-
return {
|
|
5367
|
-
gasLimit: overrides?.gasLimit,
|
|
5368
|
-
maxFeePerGas,
|
|
5369
|
-
maxPriorityFeePerGas,
|
|
5370
|
-
gasPriceForBaseCost
|
|
5371
|
-
};
|
|
5522
|
+
var encodeNTVTransferData = encodeNativeTokenVaultTransferData;
|
|
5523
|
+
function encodeSecondBridgeArgs(token, amount, l2Receiver) {
|
|
5524
|
+
return ethers.AbiCoder.defaultAbiCoder().encode(
|
|
5525
|
+
["address", "uint256", "address"],
|
|
5526
|
+
[token, amount, l2Receiver]
|
|
5527
|
+
);
|
|
5372
5528
|
}
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
let maxFeeFromProvider;
|
|
5376
|
-
let maxPriorityFromProvider;
|
|
5377
|
-
let gasPriceFallback;
|
|
5378
|
-
try {
|
|
5379
|
-
const fd = await client.l2.getFeeData();
|
|
5380
|
-
if (fd?.maxFeePerGas != null) maxFeeFromProvider = fd.maxFeePerGas;
|
|
5381
|
-
if (fd?.maxPriorityFeePerGas != null) {
|
|
5382
|
-
maxPriorityFromProvider = fd.maxPriorityFeePerGas;
|
|
5383
|
-
}
|
|
5384
|
-
if (fd?.gasPrice != null) gasPriceFallback = fd.gasPrice;
|
|
5385
|
-
} catch {
|
|
5386
|
-
}
|
|
5387
|
-
if (gasPriceFallback == null) {
|
|
5388
|
-
try {
|
|
5389
|
-
if (supportsGetGasPrice(client.l2)) {
|
|
5390
|
-
const gp = await client.l2.getGasPrice();
|
|
5391
|
-
gasPriceFallback = typeof gp === "bigint" ? gp : BigInt(gp.toString());
|
|
5392
|
-
}
|
|
5393
|
-
} catch {
|
|
5394
|
-
}
|
|
5395
|
-
}
|
|
5396
|
-
const maxFeePerGas = overrides?.maxFeePerGas ?? maxFeeFromProvider ?? gasPriceFallback;
|
|
5397
|
-
if (maxFeePerGas == null) {
|
|
5398
|
-
throw new Error("L2 provider returned no gas price data");
|
|
5399
|
-
}
|
|
5400
|
-
const maxPriorityFeePerGas = overrides?.maxPriorityFeePerGas ?? maxPriorityFromProvider ?? maxFeePerGas;
|
|
5401
|
-
assertPriorityFeeBounds({ maxFeePerGas, maxPriorityFeePerGas });
|
|
5402
|
-
return {
|
|
5403
|
-
gasLimit: overrides?.gasLimit,
|
|
5404
|
-
maxFeePerGas,
|
|
5405
|
-
maxPriorityFeePerGas
|
|
5406
|
-
};
|
|
5529
|
+
function encodeSecondBridgeErc20Args(token, amount, l2Receiver) {
|
|
5530
|
+
return encodeSecondBridgeArgs(token, amount, l2Receiver);
|
|
5407
5531
|
}
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
if (fd.gasPrice != null) return fd.gasPrice;
|
|
5411
|
-
if (fd.maxFeePerGas != null) return fd.maxFeePerGas;
|
|
5412
|
-
throw new Error("provider returned no gas price data");
|
|
5532
|
+
function encodeSecondBridgeEthArgs(amount, l2Receiver, ethToken = ETH_ADDRESS) {
|
|
5533
|
+
return encodeSecondBridgeArgs(ethToken, amount, l2Receiver);
|
|
5413
5534
|
}
|
|
5414
5535
|
function buildDirectRequestStruct(args) {
|
|
5415
5536
|
return {
|
|
@@ -5424,331 +5545,409 @@ function buildDirectRequestStruct(args) {
|
|
|
5424
5545
|
refundRecipient: args.refundRecipient
|
|
5425
5546
|
};
|
|
5426
5547
|
}
|
|
5427
|
-
function encodeSecondBridgeArgs(token, amount, l2Receiver) {
|
|
5428
|
-
return ethers.AbiCoder.defaultAbiCoder().encode(
|
|
5429
|
-
["address", "uint256", "address"],
|
|
5430
|
-
[token, amount, l2Receiver]
|
|
5431
|
-
);
|
|
5432
|
-
}
|
|
5433
|
-
function encodeSecondBridgeErc20Args(token, amount, l2Receiver) {
|
|
5434
|
-
return encodeSecondBridgeArgs(token, amount, l2Receiver);
|
|
5435
|
-
}
|
|
5436
|
-
function encodeSecondBridgeEthArgs(amount, l2Receiver, ethToken = ETH_ADDRESS) {
|
|
5437
|
-
return encodeSecondBridgeArgs(ethToken, amount, l2Receiver);
|
|
5438
|
-
}
|
|
5439
5548
|
|
|
5440
|
-
// src/core/resources/deposits/
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
const base2 = await client.baseToken(chainIdL2);
|
|
5444
|
-
return isETH(base2) ? "eth-base" : "eth-nonbase";
|
|
5445
|
-
}
|
|
5446
|
-
const base = await client.baseToken(chainIdL2);
|
|
5447
|
-
return normalizeAddrEq(token, base) ? "erc20-base" : "erc20-nonbase";
|
|
5448
|
-
}
|
|
5449
|
-
|
|
5450
|
-
// src/adapters/ethers/resources/deposits/context.ts
|
|
5451
|
-
async function commonCtx(p, client) {
|
|
5452
|
-
const { bridgehub, l1AssetRouter } = await client.ensureAddresses();
|
|
5453
|
-
const { chainId } = await client.l2.getNetwork();
|
|
5454
|
-
const sender = await client.signer.getAddress();
|
|
5455
|
-
const fee = await getFeeOverrides(client, p.l1TxOverrides);
|
|
5456
|
-
const l2GasLimit = p.l2GasLimit ?? 300000n;
|
|
5457
|
-
const gasPerPubdata = p.gasPerPubdata ?? 800n;
|
|
5458
|
-
const operatorTip = p.operatorTip ?? 0n;
|
|
5459
|
-
const refundRecipient = p.refundRecipient ?? sender;
|
|
5460
|
-
const route = await pickDepositRoute(client, BigInt(chainId), p.token);
|
|
5549
|
+
// src/core/resources/deposits/gas.ts
|
|
5550
|
+
function makeGasQuote(p) {
|
|
5551
|
+
const maxPriorityFeePerGas = p.maxPriorityFeePerGas ?? 0n;
|
|
5461
5552
|
return {
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
sender,
|
|
5468
|
-
fee,
|
|
5469
|
-
l2GasLimit,
|
|
5470
|
-
gasPerPubdata,
|
|
5471
|
-
operatorTip,
|
|
5472
|
-
refundRecipient
|
|
5553
|
+
gasLimit: p.gasLimit,
|
|
5554
|
+
maxFeePerGas: p.maxFeePerGas,
|
|
5555
|
+
maxPriorityFeePerGas,
|
|
5556
|
+
gasPerPubdata: p.gasPerPubdata,
|
|
5557
|
+
maxCost: p.gasLimit * p.maxFeePerGas
|
|
5473
5558
|
};
|
|
5474
5559
|
}
|
|
5475
|
-
|
|
5476
|
-
// src/core/errors/withdrawal-revert-map.ts
|
|
5477
|
-
var REVERT_TO_READINESS = {
|
|
5478
|
-
// Already done
|
|
5479
|
-
WithdrawalAlreadyFinalized: { kind: "FINALIZED" },
|
|
5480
|
-
// Temporary — try later
|
|
5481
|
-
BatchNotExecuted: { kind: "NOT_READY", reason: "batch-not-executed" },
|
|
5482
|
-
LocalRootIsZero: { kind: "NOT_READY", reason: "root-missing" },
|
|
5483
|
-
// Permanent — won’t become ready for this tx
|
|
5484
|
-
WrongL2Sender: { kind: "UNFINALIZABLE", reason: "message-invalid" },
|
|
5485
|
-
InvalidSelector: { kind: "UNFINALIZABLE", reason: "message-invalid" },
|
|
5486
|
-
L2WithdrawalMessageWrongLength: { kind: "UNFINALIZABLE", reason: "message-invalid" },
|
|
5487
|
-
WrongMsgLength: { kind: "UNFINALIZABLE", reason: "message-invalid" },
|
|
5488
|
-
TokenNotLegacy: { kind: "UNFINALIZABLE", reason: "message-invalid" },
|
|
5489
|
-
TokenIsLegacy: { kind: "UNFINALIZABLE", reason: "message-invalid" },
|
|
5490
|
-
InvalidProof: { kind: "UNFINALIZABLE", reason: "message-invalid" },
|
|
5491
|
-
InvalidChainId: { kind: "UNFINALIZABLE", reason: "invalid-chain" },
|
|
5492
|
-
NotSettlementLayer: { kind: "UNFINALIZABLE", reason: "settlement-layer" },
|
|
5493
|
-
// Likely environment mismatch — treat as permanent for this tx
|
|
5494
|
-
OnlyEraSupported: { kind: "UNFINALIZABLE", reason: "unsupported" },
|
|
5495
|
-
LocalRootMustBeZero: { kind: "UNFINALIZABLE", reason: "unsupported" }
|
|
5496
|
-
};
|
|
5497
|
-
|
|
5498
|
-
// src/adapters/ethers/errors/revert.ts
|
|
5499
|
-
var ERROR_IFACES = [];
|
|
5500
|
-
var IFACE_ERROR_STRING = new ethers.Interface(["error Error(string)"]);
|
|
5501
|
-
var IFACE_PANIC = new ethers.Interface(["error Panic(uint256)"]);
|
|
5502
|
-
(function bootstrapDefaultIfaces() {
|
|
5560
|
+
async function fetchFees(estimator) {
|
|
5503
5561
|
try {
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5562
|
+
const fees = await estimator.estimateFeesPerGas();
|
|
5563
|
+
if (fees.maxFeePerGas != null) {
|
|
5564
|
+
return {
|
|
5565
|
+
maxFeePerGas: fees.maxFeePerGas,
|
|
5566
|
+
maxPriorityFeePerGas: fees.maxPriorityFeePerGas ?? 0n
|
|
5567
|
+
};
|
|
5568
|
+
}
|
|
5569
|
+
if (fees.gasPrice != null) {
|
|
5570
|
+
return {
|
|
5571
|
+
maxFeePerGas: fees.gasPrice,
|
|
5572
|
+
maxPriorityFeePerGas: 0n
|
|
5573
|
+
};
|
|
5574
|
+
}
|
|
5508
5575
|
} catch {
|
|
5509
5576
|
}
|
|
5510
5577
|
try {
|
|
5511
|
-
|
|
5578
|
+
const gp = await estimator.getGasPrice();
|
|
5579
|
+
return { maxFeePerGas: gp, maxPriorityFeePerGas: 0n };
|
|
5512
5580
|
} catch {
|
|
5581
|
+
return { maxFeePerGas: 0n, maxPriorityFeePerGas: 0n };
|
|
5582
|
+
}
|
|
5583
|
+
}
|
|
5584
|
+
async function quoteL1Gas(input) {
|
|
5585
|
+
const { estimator, tx, overrides, fallbackGasLimit } = input;
|
|
5586
|
+
let market;
|
|
5587
|
+
const getMarket = async () => {
|
|
5588
|
+
if (market) return market;
|
|
5589
|
+
market = await fetchFees(estimator);
|
|
5590
|
+
return market;
|
|
5591
|
+
};
|
|
5592
|
+
const maxFeePerGas = overrides?.maxFeePerGas ?? (tx.maxFeePerGas != null ? BigInt(tx.maxFeePerGas) : (await getMarket()).maxFeePerGas);
|
|
5593
|
+
const maxPriorityFeePerGas = overrides?.maxPriorityFeePerGas ?? (tx.maxPriorityFeePerGas != null ? BigInt(tx.maxPriorityFeePerGas) : (await getMarket()).maxPriorityFeePerGas);
|
|
5594
|
+
const explicitGasLimit = overrides?.gasLimit ?? (tx.gasLimit != null ? BigInt(tx.gasLimit) : void 0);
|
|
5595
|
+
if (explicitGasLimit != null) {
|
|
5596
|
+
return makeGasQuote({ gasLimit: explicitGasLimit, maxFeePerGas, maxPriorityFeePerGas });
|
|
5513
5597
|
}
|
|
5514
5598
|
try {
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5599
|
+
const est = await estimator.estimateGas(tx);
|
|
5600
|
+
const buffered = BigInt(est) * (100n + BUFFER) / 100n;
|
|
5601
|
+
return makeGasQuote({ gasLimit: buffered, maxFeePerGas, maxPriorityFeePerGas });
|
|
5602
|
+
} catch (err) {
|
|
5603
|
+
if (fallbackGasLimit != null) {
|
|
5604
|
+
return makeGasQuote({ gasLimit: fallbackGasLimit, maxFeePerGas, maxPriorityFeePerGas });
|
|
5605
|
+
}
|
|
5606
|
+
console.warn("L1 gas estimation failed", err);
|
|
5607
|
+
return void 0;
|
|
5608
|
+
}
|
|
5609
|
+
}
|
|
5610
|
+
async function quoteL2Gas(input) {
|
|
5611
|
+
const { estimator, route, tx, gasPerPubdata, l2GasLimit, overrideGasLimit, stateOverrides } = input;
|
|
5612
|
+
const market = await fetchFees(estimator);
|
|
5613
|
+
const maxFeePerGas = market.maxFeePerGas || market.maxPriorityFeePerGas || 0n;
|
|
5614
|
+
const txGasLimit = tx?.gasLimit != null ? BigInt(tx.gasLimit) : void 0;
|
|
5615
|
+
const explicit = overrideGasLimit ?? txGasLimit;
|
|
5616
|
+
if (explicit != null) {
|
|
5617
|
+
return makeGasQuote({
|
|
5618
|
+
gasLimit: explicit,
|
|
5619
|
+
maxFeePerGas,
|
|
5620
|
+
gasPerPubdata
|
|
5518
5621
|
});
|
|
5519
|
-
} catch {
|
|
5520
5622
|
}
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5623
|
+
if (!tx) {
|
|
5624
|
+
return makeGasQuote({
|
|
5625
|
+
gasLimit: l2GasLimit ?? 0n,
|
|
5626
|
+
maxFeePerGas,
|
|
5627
|
+
gasPerPubdata
|
|
5525
5628
|
});
|
|
5526
|
-
} catch {
|
|
5527
5629
|
}
|
|
5528
5630
|
try {
|
|
5529
|
-
|
|
5530
|
-
|
|
5631
|
+
const execEstimate = await estimator.estimateGas(tx, stateOverrides);
|
|
5632
|
+
const memoryBytes = route === "erc20-nonbase" ? 500n : DEFAULT_ABI_BYTES;
|
|
5633
|
+
const pubdataBytes = route === "erc20-nonbase" ? 200n : DEFAULT_PUBDATA_BYTES;
|
|
5634
|
+
const pp = gasPerPubdata ?? 800n;
|
|
5635
|
+
const memoryOverhead = memoryBytes * TX_MEMORY_OVERHEAD_GAS;
|
|
5636
|
+
const pubdataOverhead = pubdataBytes * pp;
|
|
5637
|
+
let total = BigInt(execEstimate) + TX_OVERHEAD_GAS + memoryOverhead + pubdataOverhead;
|
|
5638
|
+
total = total * (100n + BUFFER) / 100n;
|
|
5639
|
+
return makeGasQuote({
|
|
5640
|
+
gasLimit: total,
|
|
5641
|
+
maxFeePerGas,
|
|
5642
|
+
gasPerPubdata: pp
|
|
5643
|
+
});
|
|
5644
|
+
} catch (err) {
|
|
5645
|
+
console.warn("L2 gas estimation failed", err);
|
|
5646
|
+
return makeGasQuote({
|
|
5647
|
+
gasLimit: l2GasLimit ?? 0n,
|
|
5648
|
+
maxFeePerGas,
|
|
5649
|
+
gasPerPubdata
|
|
5650
|
+
});
|
|
5531
5651
|
}
|
|
5532
|
-
})();
|
|
5533
|
-
function registerErrorAbi(name, abi) {
|
|
5534
|
-
const existing = ERROR_IFACES.findIndex((x) => x.name === name);
|
|
5535
|
-
const entry = { name, iface: new ethers.Interface(abi) };
|
|
5536
|
-
if (existing >= 0) ERROR_IFACES[existing] = entry;
|
|
5537
|
-
else ERROR_IFACES.push(entry);
|
|
5538
5652
|
}
|
|
5539
|
-
function
|
|
5540
|
-
const
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
)
|
|
5544
|
-
|
|
5545
|
-
return maybe;
|
|
5653
|
+
async function quoteL2BaseCost(input) {
|
|
5654
|
+
const { estimator, encode: encode2, bridgehub, chainIdL2, l2GasLimit, gasPerPubdata } = input;
|
|
5655
|
+
const market = await fetchFees(estimator);
|
|
5656
|
+
const l1GasPrice = market.maxFeePerGas || market.maxPriorityFeePerGas || 0n;
|
|
5657
|
+
if (l1GasPrice === 0n) {
|
|
5658
|
+
throw new Error("Could not fetch L1 gas price for Bridgehub base cost calculation.");
|
|
5546
5659
|
}
|
|
5547
|
-
|
|
5660
|
+
const data = encode2(IBridgehub_default, "l2TransactionBaseCost", [
|
|
5661
|
+
chainIdL2,
|
|
5662
|
+
l1GasPrice,
|
|
5663
|
+
l2GasLimit,
|
|
5664
|
+
gasPerPubdata
|
|
5665
|
+
]);
|
|
5666
|
+
const raw = await estimator.call({
|
|
5667
|
+
to: bridgehub,
|
|
5668
|
+
data
|
|
5669
|
+
});
|
|
5670
|
+
return BigInt(raw);
|
|
5548
5671
|
}
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
}
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5672
|
+
|
|
5673
|
+
// src/adapters/ethers/estimator.ts
|
|
5674
|
+
function toCoreTx(tx) {
|
|
5675
|
+
return {
|
|
5676
|
+
to: tx.to,
|
|
5677
|
+
from: tx.from,
|
|
5678
|
+
data: tx.data,
|
|
5679
|
+
value: tx.value ? BigInt(tx.value) : void 0,
|
|
5680
|
+
gasLimit: tx.gasLimit ? BigInt(tx.gasLimit) : void 0,
|
|
5681
|
+
maxFeePerGas: tx.maxFeePerGas ? BigInt(tx.maxFeePerGas) : void 0,
|
|
5682
|
+
maxPriorityFeePerGas: tx.maxPriorityFeePerGas ? BigInt(tx.maxPriorityFeePerGas) : void 0
|
|
5683
|
+
};
|
|
5684
|
+
}
|
|
5685
|
+
function ethersToGasEstimator(provider) {
|
|
5686
|
+
return {
|
|
5687
|
+
async estimateGas(tx, stateOverrides) {
|
|
5688
|
+
const ethTx = {
|
|
5689
|
+
to: tx.to,
|
|
5690
|
+
from: tx.from,
|
|
5691
|
+
data: tx.data,
|
|
5692
|
+
value: tx.value,
|
|
5693
|
+
gasLimit: tx.gasLimit,
|
|
5694
|
+
maxFeePerGas: tx.maxFeePerGas,
|
|
5695
|
+
maxPriorityFeePerGas: tx.maxPriorityFeePerGas
|
|
5696
|
+
};
|
|
5697
|
+
if (stateOverrides && "send" in provider) {
|
|
5698
|
+
try {
|
|
5699
|
+
const jsonRpcProvider = provider;
|
|
5700
|
+
const result = await jsonRpcProvider.send("eth_estimateGas", [
|
|
5701
|
+
ethTx,
|
|
5702
|
+
"latest",
|
|
5703
|
+
stateOverrides
|
|
5704
|
+
]);
|
|
5705
|
+
return BigInt(result);
|
|
5706
|
+
} catch (error) {
|
|
5707
|
+
console.warn(
|
|
5708
|
+
"Failed to estimate gas with state overrides, falling back to standard estimation:",
|
|
5709
|
+
error
|
|
5710
|
+
);
|
|
5711
|
+
}
|
|
5712
|
+
} else if (stateOverrides) {
|
|
5713
|
+
console.warn('Provider does not support "send", skipping state overrides estimation.');
|
|
5580
5714
|
}
|
|
5581
|
-
|
|
5715
|
+
return await provider.estimateGas(ethTx);
|
|
5716
|
+
},
|
|
5717
|
+
async estimateFeesPerGas() {
|
|
5718
|
+
const fd = await provider.getFeeData();
|
|
5719
|
+
return {
|
|
5720
|
+
maxFeePerGas: fd.maxFeePerGas != null ? BigInt(fd.maxFeePerGas) : void 0,
|
|
5721
|
+
maxPriorityFeePerGas: fd.maxPriorityFeePerGas != null ? BigInt(fd.maxPriorityFeePerGas) : void 0,
|
|
5722
|
+
gasPrice: fd.gasPrice != null ? BigInt(fd.gasPrice) : void 0
|
|
5723
|
+
};
|
|
5724
|
+
},
|
|
5725
|
+
async getGasPrice() {
|
|
5726
|
+
const fd = await provider.getFeeData();
|
|
5727
|
+
if (fd.gasPrice != null) return BigInt(fd.gasPrice);
|
|
5728
|
+
throw new Error("Could not fetch gas price");
|
|
5729
|
+
},
|
|
5730
|
+
async call(tx) {
|
|
5731
|
+
const ethTx = {
|
|
5732
|
+
to: tx.to,
|
|
5733
|
+
data: tx.data,
|
|
5734
|
+
value: tx.value,
|
|
5735
|
+
from: tx.from
|
|
5736
|
+
};
|
|
5737
|
+
return await provider.call(ethTx);
|
|
5582
5738
|
}
|
|
5583
|
-
}
|
|
5584
|
-
return { selector };
|
|
5739
|
+
};
|
|
5585
5740
|
}
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5741
|
+
|
|
5742
|
+
// src/adapters/ethers/resources/deposits/services/fee.ts
|
|
5743
|
+
var { wrapAs: wrapAs2 } = createErrorHandlers("deposits");
|
|
5744
|
+
var encode = (abi, fn, args) => {
|
|
5745
|
+
return new ethers.Interface(abi).encodeFunctionData(fn, args);
|
|
5746
|
+
};
|
|
5747
|
+
async function quoteL2BaseCost2(input) {
|
|
5748
|
+
const { ctx, l2GasLimit } = input;
|
|
5749
|
+
const estimator = ethersToGasEstimator(ctx.client.l1);
|
|
5750
|
+
return wrapAs2(
|
|
5751
|
+
"RPC",
|
|
5752
|
+
"deposits.fees.l2BaseCost",
|
|
5753
|
+
() => quoteL2BaseCost({
|
|
5754
|
+
estimator,
|
|
5755
|
+
encode,
|
|
5756
|
+
bridgehub: ctx.bridgehub,
|
|
5757
|
+
chainIdL2: ctx.chainIdL2,
|
|
5758
|
+
l2GasLimit,
|
|
5759
|
+
gasPerPubdata: ctx.gasPerPubdata
|
|
5760
|
+
}),
|
|
5761
|
+
{ ctx: { chainIdL2: ctx.chainIdL2 } }
|
|
5762
|
+
);
|
|
5602
5763
|
}
|
|
5603
5764
|
|
|
5604
|
-
// src/adapters/ethers/
|
|
5605
|
-
function
|
|
5606
|
-
|
|
5607
|
-
const
|
|
5608
|
-
return
|
|
5765
|
+
// src/adapters/ethers/resources/deposits/services/gas.ts
|
|
5766
|
+
async function quoteL1Gas2(input) {
|
|
5767
|
+
const { ctx, tx, overrides, fallbackGasLimit } = input;
|
|
5768
|
+
const estimator = ethersToGasEstimator(ctx.client.l1);
|
|
5769
|
+
return quoteL1Gas({
|
|
5770
|
+
estimator,
|
|
5771
|
+
tx: toCoreTx(tx),
|
|
5772
|
+
overrides,
|
|
5773
|
+
fallbackGasLimit
|
|
5774
|
+
});
|
|
5609
5775
|
}
|
|
5610
|
-
function
|
|
5611
|
-
|
|
5612
|
-
|
|
5776
|
+
async function quoteL2Gas2(input) {
|
|
5777
|
+
const { ctx, route, l2TxForModeling, overrideGasLimit } = input;
|
|
5778
|
+
const estimator = ethersToGasEstimator(ctx.client.l2);
|
|
5779
|
+
return quoteL2Gas({
|
|
5780
|
+
estimator,
|
|
5781
|
+
route,
|
|
5782
|
+
tx: l2TxForModeling ? toCoreTx(l2TxForModeling) : void 0,
|
|
5783
|
+
gasPerPubdata: ctx.gasPerPubdata,
|
|
5784
|
+
l2GasLimit: ctx.l2GasLimit,
|
|
5785
|
+
overrideGasLimit,
|
|
5786
|
+
stateOverrides: input.stateOverrides
|
|
5787
|
+
});
|
|
5613
5788
|
}
|
|
5614
|
-
function
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
}
|
|
5623
|
-
}
|
|
5624
|
-
function wrap2(operation, fn, opts) {
|
|
5625
|
-
return run("INTERNAL", operation, fn, opts);
|
|
5626
|
-
}
|
|
5627
|
-
function wrapAs9(kind, operation, fn, opts) {
|
|
5628
|
-
return run(kind, operation, fn, opts);
|
|
5789
|
+
async function determineErc20L2Gas(input) {
|
|
5790
|
+
const { ctx, l1Token } = input;
|
|
5791
|
+
const DEFAULT_SAFE_L2_GAS_LIMIT = 3000000n;
|
|
5792
|
+
if (ctx.l2GasLimit != null) {
|
|
5793
|
+
return quoteL2Gas2({
|
|
5794
|
+
ctx,
|
|
5795
|
+
route: "erc20-nonbase",
|
|
5796
|
+
overrideGasLimit: ctx.l2GasLimit
|
|
5797
|
+
});
|
|
5629
5798
|
}
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
"
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5799
|
+
try {
|
|
5800
|
+
const { l2NativeTokenVault } = await ctx.client.contracts();
|
|
5801
|
+
const l2TokenAddress = await l2NativeTokenVault.l2TokenAddress(l1Token);
|
|
5802
|
+
if (l2TokenAddress === "0x0000000000000000000000000000000000000000") {
|
|
5803
|
+
return quoteL2Gas2({
|
|
5804
|
+
ctx,
|
|
5805
|
+
route: "erc20-nonbase",
|
|
5806
|
+
overrideGasLimit: DEFAULT_SAFE_L2_GAS_LIMIT
|
|
5807
|
+
});
|
|
5808
|
+
}
|
|
5809
|
+
const modelTx = {
|
|
5810
|
+
to: input.modelTx?.to ?? ctx.sender,
|
|
5811
|
+
from: input.modelTx?.from ?? ctx.sender,
|
|
5812
|
+
data: input.modelTx?.data ?? "0x",
|
|
5813
|
+
value: input.modelTx?.value ?? 0n
|
|
5814
|
+
};
|
|
5815
|
+
const gas = await quoteL2Gas2({
|
|
5816
|
+
ctx,
|
|
5817
|
+
route: "erc20-nonbase",
|
|
5818
|
+
l2TxForModeling: modelTx
|
|
5819
|
+
});
|
|
5820
|
+
if (!gas) {
|
|
5821
|
+
return quoteL2Gas2({
|
|
5822
|
+
ctx,
|
|
5823
|
+
route: "erc20-nonbase",
|
|
5824
|
+
overrideGasLimit: DEFAULT_SAFE_L2_GAS_LIMIT
|
|
5825
|
+
});
|
|
5646
5826
|
}
|
|
5827
|
+
return gas;
|
|
5828
|
+
} catch (err) {
|
|
5829
|
+
console.warn("Failed to determine ERC20 L2 gas; defaulting to safe gas limit.", err);
|
|
5830
|
+
return quoteL2Gas2({
|
|
5831
|
+
ctx,
|
|
5832
|
+
route: "erc20-nonbase",
|
|
5833
|
+
overrideGasLimit: DEFAULT_SAFE_L2_GAS_LIMIT
|
|
5834
|
+
});
|
|
5647
5835
|
}
|
|
5648
|
-
|
|
5836
|
+
}
|
|
5837
|
+
|
|
5838
|
+
// src/core/resources/deposits/fee.ts
|
|
5839
|
+
function buildFeeBreakdown(p) {
|
|
5840
|
+
const l1MaxTotal = p.l1Gas?.maxCost ?? 0n;
|
|
5841
|
+
const l2Total = p.l2BaseCost + p.operatorTip;
|
|
5842
|
+
const l1 = {
|
|
5843
|
+
gasLimit: p.l1Gas?.gasLimit ?? 0n,
|
|
5844
|
+
maxFeePerGas: p.l1Gas?.maxFeePerGas ?? 0n,
|
|
5845
|
+
maxPriorityFeePerGas: p.l1Gas?.maxPriorityFeePerGas,
|
|
5846
|
+
maxTotal: l1MaxTotal
|
|
5847
|
+
};
|
|
5848
|
+
const l2 = {
|
|
5849
|
+
total: l2Total,
|
|
5850
|
+
baseCost: p.l2BaseCost,
|
|
5851
|
+
operatorTip: p.operatorTip,
|
|
5852
|
+
gasLimit: p.l2Gas?.gasLimit ?? 0n,
|
|
5853
|
+
maxFeePerGas: p.l2Gas?.maxFeePerGas ?? 0n,
|
|
5854
|
+
maxPriorityFeePerGas: p.l2Gas?.maxPriorityFeePerGas,
|
|
5855
|
+
gasPerPubdata: p.l2Gas?.gasPerPubdata ?? 0n
|
|
5856
|
+
};
|
|
5857
|
+
return {
|
|
5858
|
+
token: p.feeToken,
|
|
5859
|
+
maxTotal: l1MaxTotal + l2Total,
|
|
5860
|
+
mintValue: p.mintValue,
|
|
5861
|
+
l1,
|
|
5862
|
+
l2
|
|
5863
|
+
};
|
|
5649
5864
|
}
|
|
5650
5865
|
|
|
5651
5866
|
// src/adapters/ethers/resources/deposits/routes/eth.ts
|
|
5652
|
-
var { wrapAs } = createErrorHandlers("deposits");
|
|
5653
5867
|
function routeEthDirect() {
|
|
5654
5868
|
return {
|
|
5655
5869
|
async build(p, ctx) {
|
|
5656
5870
|
const bh = new ethers.Contract(ctx.bridgehub, IBridgehub_default, ctx.client.l1);
|
|
5657
|
-
const
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5871
|
+
const l2TxModel = {
|
|
5872
|
+
to: p.to ?? ctx.sender,
|
|
5873
|
+
from: ctx.sender,
|
|
5874
|
+
data: "0x",
|
|
5875
|
+
value: 0n
|
|
5876
|
+
};
|
|
5877
|
+
const l2GasParams = await quoteL2Gas2({
|
|
5878
|
+
ctx,
|
|
5879
|
+
route: "eth-base",
|
|
5880
|
+
l2TxForModeling: l2TxModel,
|
|
5881
|
+
overrideGasLimit: ctx.l2GasLimit,
|
|
5882
|
+
stateOverrides: {
|
|
5883
|
+
[ctx.sender]: {
|
|
5884
|
+
balance: "0xffffffffffffffffffff"
|
|
5885
|
+
}
|
|
5670
5886
|
}
|
|
5671
|
-
);
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
const
|
|
5887
|
+
});
|
|
5888
|
+
if (!l2GasParams) {
|
|
5889
|
+
throw new Error("Failed to estimate L2 gas for deposit.");
|
|
5890
|
+
}
|
|
5891
|
+
const baseCost = await quoteL2BaseCost2({ ctx, l2GasLimit: l2GasParams.gasLimit });
|
|
5892
|
+
const mintValue = baseCost + ctx.operatorTip + p.amount;
|
|
5676
5893
|
const req = buildDirectRequestStruct({
|
|
5677
5894
|
chainId: ctx.chainIdL2,
|
|
5678
5895
|
mintValue,
|
|
5679
|
-
l2GasLimit:
|
|
5896
|
+
l2GasLimit: l2GasParams.gasLimit,
|
|
5680
5897
|
gasPerPubdata: ctx.gasPerPubdata,
|
|
5681
5898
|
refundRecipient: ctx.refundRecipient,
|
|
5682
|
-
l2Contract,
|
|
5683
|
-
l2Value
|
|
5899
|
+
l2Contract: p.to ?? ctx.sender,
|
|
5900
|
+
l2Value: p.amount
|
|
5684
5901
|
});
|
|
5685
5902
|
const data = bh.interface.encodeFunctionData("requestL2TransactionDirect", [req]);
|
|
5686
|
-
|
|
5687
|
-
const tx = {
|
|
5903
|
+
const l1TxCandidate = {
|
|
5688
5904
|
to: ctx.bridgehub,
|
|
5689
5905
|
data,
|
|
5690
5906
|
value: mintValue,
|
|
5691
5907
|
from: ctx.sender,
|
|
5692
|
-
...
|
|
5908
|
+
...ctx.gasOverrides
|
|
5693
5909
|
};
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
{
|
|
5704
|
-
ctx: { where: "l1.estimateGas", to: ctx.bridgehub },
|
|
5705
|
-
message: "Failed to estimate gas for Bridgehub request."
|
|
5706
|
-
}
|
|
5707
|
-
);
|
|
5708
|
-
const buffered = BigInt(est) * 115n / 100n;
|
|
5709
|
-
tx.gasLimit = buffered;
|
|
5710
|
-
resolvedL1GasLimit = buffered;
|
|
5711
|
-
} catch {
|
|
5712
|
-
}
|
|
5910
|
+
const l1GasParams = await quoteL1Gas2({
|
|
5911
|
+
ctx,
|
|
5912
|
+
tx: l1TxCandidate,
|
|
5913
|
+
overrides: ctx.gasOverrides
|
|
5914
|
+
});
|
|
5915
|
+
if (l1GasParams) {
|
|
5916
|
+
l1TxCandidate.gasLimit = l1GasParams.gasLimit;
|
|
5917
|
+
l1TxCandidate.maxFeePerGas = l1GasParams.maxFeePerGas;
|
|
5918
|
+
l1TxCandidate.maxPriorityFeePerGas = l1GasParams.maxPriorityFeePerGas;
|
|
5713
5919
|
}
|
|
5714
5920
|
const steps = [
|
|
5715
5921
|
{
|
|
5716
5922
|
key: "bridgehub:direct",
|
|
5717
5923
|
kind: "bridgehub:direct",
|
|
5718
5924
|
description: "Bridge ETH via Bridgehub.requestL2TransactionDirect",
|
|
5719
|
-
tx
|
|
5925
|
+
tx: l1TxCandidate
|
|
5720
5926
|
}
|
|
5721
5927
|
];
|
|
5928
|
+
const fees = buildFeeBreakdown({
|
|
5929
|
+
feeToken: ETH_ADDRESS,
|
|
5930
|
+
l1Gas: l1GasParams,
|
|
5931
|
+
l2Gas: l2GasParams,
|
|
5932
|
+
l2BaseCost: baseCost,
|
|
5933
|
+
operatorTip: ctx.operatorTip,
|
|
5934
|
+
mintValue
|
|
5935
|
+
});
|
|
5722
5936
|
return {
|
|
5723
5937
|
steps,
|
|
5724
5938
|
approvals: [],
|
|
5725
|
-
|
|
5939
|
+
fees
|
|
5726
5940
|
};
|
|
5727
5941
|
}
|
|
5728
5942
|
};
|
|
5729
|
-
}
|
|
5730
|
-
var { wrapAs:
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
async preflight() {
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
const bh = new ethers.Contract(ctx.bridgehub, IBridgehub_default, ctx.client.l1);
|
|
5738
|
-
const assetRouter = ctx.l1AssetRouter;
|
|
5739
|
-
const { gasPriceForBaseCost, gasLimit: overrideGasLimit, ...txFeeOverrides } = ctx.fee;
|
|
5740
|
-
const txOverrides = overrideGasLimit != null ? { ...txFeeOverrides, gasLimit: overrideGasLimit } : txFeeOverrides;
|
|
5741
|
-
let resolvedL1GasLimit = overrideGasLimit ?? ctx.l2GasLimit;
|
|
5742
|
-
const baseToken = await wrapAs2(
|
|
5743
|
-
"CONTRACT",
|
|
5744
|
-
OP_DEPOSITS.nonbase.baseToken,
|
|
5745
|
-
() => bh.baseToken(ctx.chainIdL2),
|
|
5746
|
-
{
|
|
5747
|
-
ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 },
|
|
5748
|
-
message: "Failed to read base token."
|
|
5749
|
-
}
|
|
5750
|
-
);
|
|
5751
|
-
await wrapAs2(
|
|
5943
|
+
}
|
|
5944
|
+
var { wrapAs: wrapAs3 } = createErrorHandlers("deposits");
|
|
5945
|
+
function routeErc20NonBase() {
|
|
5946
|
+
return {
|
|
5947
|
+
// TODO: do we even need these validations?
|
|
5948
|
+
async preflight(p, ctx) {
|
|
5949
|
+
const baseToken = await ctx.client.baseToken(ctx.chainIdL2);
|
|
5950
|
+
await wrapAs3(
|
|
5752
5951
|
"VALIDATION",
|
|
5753
5952
|
OP_DEPOSITS.nonbase.assertNonBaseToken,
|
|
5754
5953
|
() => {
|
|
@@ -5758,55 +5957,54 @@ function routeErc20NonBase() {
|
|
|
5758
5957
|
},
|
|
5759
5958
|
{ ctx: { depositToken: p.token, baseToken } }
|
|
5760
5959
|
);
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5960
|
+
},
|
|
5961
|
+
async build(p, ctx) {
|
|
5962
|
+
const l1Signer = ctx.client.getL1Signer();
|
|
5963
|
+
const baseToken = await ctx.client.baseToken(ctx.chainIdL2);
|
|
5964
|
+
const baseIsEth = isETH(baseToken);
|
|
5965
|
+
const l2GasParams = await determineErc20L2Gas({
|
|
5966
|
+
ctx,
|
|
5967
|
+
l1Token: p.token,
|
|
5968
|
+
modelTx: {
|
|
5969
|
+
to: p.to ?? ctx.sender,
|
|
5970
|
+
from: ctx.sender,
|
|
5971
|
+
data: "0x",
|
|
5972
|
+
value: 0n
|
|
5774
5973
|
}
|
|
5775
|
-
);
|
|
5776
|
-
|
|
5974
|
+
});
|
|
5975
|
+
if (!l2GasParams) throw new Error("Failed to establish L2 gas parameters.");
|
|
5976
|
+
const baseCost = await quoteL2BaseCost2({ ctx, l2GasLimit: l2GasParams.gasLimit });
|
|
5777
5977
|
const mintValue = baseCost + ctx.operatorTip;
|
|
5778
5978
|
const approvals = [];
|
|
5779
5979
|
const steps = [];
|
|
5780
|
-
const
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
{
|
|
5788
|
-
|
|
5789
|
-
message: "Failed to read deposit-token allowance."
|
|
5790
|
-
}
|
|
5791
|
-
);
|
|
5792
|
-
if (allowanceToken < p.amount) {
|
|
5793
|
-
approvals.push({ token: p.token, spender: assetRouter, amount: p.amount });
|
|
5794
|
-
const data = erc20Deposit.interface.encodeFunctionData("approve", [
|
|
5795
|
-
assetRouter,
|
|
5796
|
-
p.amount
|
|
5797
|
-
]);
|
|
5798
|
-
steps.push({
|
|
5799
|
-
key: `approve:${p.token}:${assetRouter}`,
|
|
5800
|
-
kind: "approve",
|
|
5801
|
-
description: `Approve ${p.amount} for router (deposit token)`,
|
|
5802
|
-
tx: { to: p.token, data, from: ctx.sender, ...txOverrides }
|
|
5803
|
-
});
|
|
5980
|
+
const assetRouter = ctx.l1AssetRouter;
|
|
5981
|
+
const erc20Deposit = new ethers.Contract(p.token, IERC20_default, l1Signer);
|
|
5982
|
+
const allowanceToken = await wrapAs3(
|
|
5983
|
+
"RPC",
|
|
5984
|
+
OP_DEPOSITS.nonbase.allowanceToken,
|
|
5985
|
+
() => erc20Deposit.allowance(ctx.sender, assetRouter),
|
|
5986
|
+
{
|
|
5987
|
+
ctx: { where: "erc20.allowance", token: p.token, spender: assetRouter },
|
|
5988
|
+
message: "Failed to read deposit-token allowance."
|
|
5804
5989
|
}
|
|
5990
|
+
);
|
|
5991
|
+
if (allowanceToken < p.amount) {
|
|
5992
|
+
approvals.push({ token: p.token, spender: assetRouter, amount: p.amount });
|
|
5993
|
+
steps.push({
|
|
5994
|
+
key: `approve:${p.token}:${assetRouter}`,
|
|
5995
|
+
kind: "approve",
|
|
5996
|
+
description: `Approve ${p.amount} for router (deposit token)`,
|
|
5997
|
+
tx: {
|
|
5998
|
+
to: p.token,
|
|
5999
|
+
data: erc20Deposit.interface.encodeFunctionData("approve", [assetRouter, p.amount]),
|
|
6000
|
+
from: ctx.sender,
|
|
6001
|
+
...ctx.gasOverrides
|
|
6002
|
+
}
|
|
6003
|
+
});
|
|
5805
6004
|
}
|
|
5806
|
-
const baseIsEth = isETH(baseToken);
|
|
5807
6005
|
if (!baseIsEth) {
|
|
5808
6006
|
const erc20Base = new ethers.Contract(baseToken, IERC20_default, l1Signer);
|
|
5809
|
-
const allowanceBase = await
|
|
6007
|
+
const allowanceBase = await wrapAs3(
|
|
5810
6008
|
"RPC",
|
|
5811
6009
|
OP_DEPOSITS.nonbase.allowanceBase,
|
|
5812
6010
|
() => erc20Base.allowance(ctx.sender, assetRouter),
|
|
@@ -5817,16 +6015,20 @@ function routeErc20NonBase() {
|
|
|
5817
6015
|
);
|
|
5818
6016
|
if (allowanceBase < mintValue) {
|
|
5819
6017
|
approvals.push({ token: baseToken, spender: assetRouter, amount: mintValue });
|
|
5820
|
-
const data = erc20Base.interface.encodeFunctionData("approve", [assetRouter, mintValue]);
|
|
5821
6018
|
steps.push({
|
|
5822
6019
|
key: `approve:${baseToken}:${assetRouter}`,
|
|
5823
6020
|
kind: "approve",
|
|
5824
6021
|
description: `Approve base token for mintValue`,
|
|
5825
|
-
tx: {
|
|
6022
|
+
tx: {
|
|
6023
|
+
to: baseToken,
|
|
6024
|
+
data: erc20Base.interface.encodeFunctionData("approve", [assetRouter, mintValue]),
|
|
6025
|
+
from: ctx.sender,
|
|
6026
|
+
...ctx.gasOverrides
|
|
6027
|
+
}
|
|
5826
6028
|
});
|
|
5827
6029
|
}
|
|
5828
6030
|
}
|
|
5829
|
-
const secondBridgeCalldata = await
|
|
6031
|
+
const secondBridgeCalldata = await wrapAs3(
|
|
5830
6032
|
"INTERNAL",
|
|
5831
6033
|
OP_DEPOSITS.nonbase.encodeCalldata,
|
|
5832
6034
|
() => Promise.resolve(encodeSecondBridgeErc20Args(p.token, p.amount, p.to ?? ctx.sender)),
|
|
@@ -5835,68 +6037,67 @@ function routeErc20NonBase() {
|
|
|
5835
6037
|
message: "Failed to encode bridging calldata."
|
|
5836
6038
|
}
|
|
5837
6039
|
);
|
|
5838
|
-
const
|
|
6040
|
+
const requestStruct = {
|
|
5839
6041
|
chainId: ctx.chainIdL2,
|
|
5840
6042
|
mintValue,
|
|
5841
|
-
// fees (in ETH if base=ETH, else pulled as base ERC-20)
|
|
5842
6043
|
l2Value: 0n,
|
|
5843
|
-
l2GasLimit:
|
|
6044
|
+
l2GasLimit: l2GasParams.gasLimit,
|
|
5844
6045
|
l2GasPerPubdataByteLimit: ctx.gasPerPubdata,
|
|
5845
6046
|
refundRecipient: ctx.refundRecipient,
|
|
5846
6047
|
secondBridgeAddress: assetRouter,
|
|
5847
6048
|
secondBridgeValue: 0n,
|
|
5848
6049
|
secondBridgeCalldata
|
|
5849
6050
|
};
|
|
5850
|
-
const
|
|
5851
|
-
const
|
|
6051
|
+
const bh = (await ctx.client.contracts()).bridgehub;
|
|
6052
|
+
const data = bh.interface.encodeFunctionData("requestL2TransactionTwoBridges", [
|
|
6053
|
+
requestStruct
|
|
6054
|
+
]);
|
|
6055
|
+
const txValue = baseIsEth ? mintValue : 0n;
|
|
6056
|
+
const l1TxCandidate = {
|
|
5852
6057
|
to: ctx.bridgehub,
|
|
5853
|
-
data
|
|
5854
|
-
value:
|
|
6058
|
+
data,
|
|
6059
|
+
value: txValue,
|
|
5855
6060
|
from: ctx.sender,
|
|
5856
|
-
...
|
|
6061
|
+
...ctx.gasOverrides
|
|
5857
6062
|
};
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
ctx: { where: "l1.estimateGas", to: ctx.bridgehub, baseIsEth },
|
|
5869
|
-
message: "Failed to estimate gas for Bridgehub request."
|
|
5870
|
-
}
|
|
5871
|
-
);
|
|
5872
|
-
const buffered = BigInt(est) * 125n / 100n;
|
|
5873
|
-
bridgeTx.gasLimit = buffered;
|
|
5874
|
-
resolvedL1GasLimit = buffered;
|
|
5875
|
-
} catch {
|
|
5876
|
-
}
|
|
6063
|
+
const l1GasParams = await quoteL1Gas2({
|
|
6064
|
+
ctx,
|
|
6065
|
+
tx: l1TxCandidate,
|
|
6066
|
+
overrides: ctx.gasOverrides,
|
|
6067
|
+
fallbackGasLimit: SAFE_L1_BRIDGE_GAS
|
|
6068
|
+
});
|
|
6069
|
+
if (l1GasParams) {
|
|
6070
|
+
l1TxCandidate.gasLimit = l1GasParams.gasLimit;
|
|
6071
|
+
l1TxCandidate.maxFeePerGas = l1GasParams.maxFeePerGas;
|
|
6072
|
+
l1TxCandidate.maxPriorityFeePerGas = l1GasParams.maxPriorityFeePerGas;
|
|
5877
6073
|
}
|
|
5878
6074
|
steps.push({
|
|
5879
|
-
key: "bridgehub:two-bridges
|
|
6075
|
+
key: "bridgehub:two-bridges",
|
|
5880
6076
|
kind: "bridgehub:two-bridges",
|
|
5881
|
-
description: baseIsEth ? "Bridge ERC-20 (
|
|
5882
|
-
tx:
|
|
6077
|
+
description: baseIsEth ? "Bridge ERC-20 (Fees paid in ETH)" : "Bridge ERC-20 (Fees paid in Base Token)",
|
|
6078
|
+
tx: l1TxCandidate
|
|
6079
|
+
});
|
|
6080
|
+
const fees = buildFeeBreakdown({
|
|
6081
|
+
feeToken: baseToken,
|
|
6082
|
+
l1Gas: l1GasParams,
|
|
6083
|
+
l2Gas: l2GasParams,
|
|
6084
|
+
l2BaseCost: baseCost,
|
|
6085
|
+
operatorTip: ctx.operatorTip,
|
|
6086
|
+
mintValue
|
|
5883
6087
|
});
|
|
5884
6088
|
return {
|
|
5885
6089
|
steps,
|
|
5886
6090
|
approvals,
|
|
5887
|
-
|
|
6091
|
+
fees
|
|
5888
6092
|
};
|
|
5889
6093
|
}
|
|
5890
6094
|
};
|
|
5891
6095
|
}
|
|
5892
|
-
var { wrapAs:
|
|
5893
|
-
var BASE_COST_BUFFER_BPS = 100n;
|
|
5894
|
-
var BPS = 10000n;
|
|
5895
|
-
var withBuffer = (x) => x * (BPS + BASE_COST_BUFFER_BPS) / BPS;
|
|
6096
|
+
var { wrapAs: wrapAs4 } = createErrorHandlers("deposits");
|
|
5896
6097
|
function routeEthNonBase() {
|
|
5897
6098
|
return {
|
|
5898
6099
|
async preflight(p, ctx) {
|
|
5899
|
-
await
|
|
6100
|
+
await wrapAs4(
|
|
5900
6101
|
"VALIDATION",
|
|
5901
6102
|
OP_DEPOSITS.ethNonBase.assertEthAsset,
|
|
5902
6103
|
() => {
|
|
@@ -5906,17 +6107,8 @@ function routeEthNonBase() {
|
|
|
5906
6107
|
},
|
|
5907
6108
|
{ ctx: { token: p.token } }
|
|
5908
6109
|
);
|
|
5909
|
-
const
|
|
5910
|
-
|
|
5911
|
-
"CONTRACT",
|
|
5912
|
-
OP_DEPOSITS.ethNonBase.baseToken,
|
|
5913
|
-
() => bh.baseToken(ctx.chainIdL2),
|
|
5914
|
-
{
|
|
5915
|
-
ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 },
|
|
5916
|
-
message: "Failed to read base token."
|
|
5917
|
-
}
|
|
5918
|
-
);
|
|
5919
|
-
await wrapAs3(
|
|
6110
|
+
const baseToken = await ctx.client.baseToken(ctx.chainIdL2);
|
|
6111
|
+
await wrapAs4(
|
|
5920
6112
|
"VALIDATION",
|
|
5921
6113
|
OP_DEPOSITS.ethNonBase.assertNonEthBase,
|
|
5922
6114
|
() => {
|
|
@@ -5926,7 +6118,7 @@ function routeEthNonBase() {
|
|
|
5926
6118
|
},
|
|
5927
6119
|
{ ctx: { baseToken, chainIdL2: ctx.chainIdL2 } }
|
|
5928
6120
|
);
|
|
5929
|
-
const ethBal = await
|
|
6121
|
+
const ethBal = await wrapAs4(
|
|
5930
6122
|
"RPC",
|
|
5931
6123
|
OP_DEPOSITS.ethNonBase.ethBalance,
|
|
5932
6124
|
() => ctx.client.l1.getBalance(ctx.sender),
|
|
@@ -5935,7 +6127,7 @@ function routeEthNonBase() {
|
|
|
5935
6127
|
message: "Failed to read L1 ETH balance."
|
|
5936
6128
|
}
|
|
5937
6129
|
);
|
|
5938
|
-
await
|
|
6130
|
+
await wrapAs4(
|
|
5939
6131
|
"VALIDATION",
|
|
5940
6132
|
OP_DEPOSITS.ethNonBase.assertEthBalance,
|
|
5941
6133
|
() => {
|
|
@@ -5948,63 +6140,50 @@ function routeEthNonBase() {
|
|
|
5948
6140
|
return;
|
|
5949
6141
|
},
|
|
5950
6142
|
async build(p, ctx) {
|
|
5951
|
-
const
|
|
5952
|
-
const
|
|
5953
|
-
const
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
6143
|
+
const l1Signer = ctx.client.getL1Signer();
|
|
6144
|
+
const baseToken = await ctx.client.baseToken(ctx.chainIdL2);
|
|
6145
|
+
const l2TxModel = {
|
|
6146
|
+
to: p.to ?? ctx.sender,
|
|
6147
|
+
from: ctx.sender,
|
|
6148
|
+
data: "0x",
|
|
6149
|
+
value: 0n
|
|
6150
|
+
};
|
|
6151
|
+
const l2GasParams = await quoteL2Gas2({
|
|
6152
|
+
ctx,
|
|
6153
|
+
route: "eth-nonbase",
|
|
6154
|
+
l2TxForModeling: l2TxModel,
|
|
6155
|
+
overrideGasLimit: ctx.l2GasLimit
|
|
6156
|
+
});
|
|
6157
|
+
if (!l2GasParams) throw new Error("Failed to estimate L2 gas parameters.");
|
|
6158
|
+
const baseCost = await quoteL2BaseCost2({ ctx, l2GasLimit: l2GasParams.gasLimit });
|
|
6159
|
+
const mintValue = baseCost + ctx.operatorTip;
|
|
6160
|
+
const approvals = [];
|
|
6161
|
+
const steps = [];
|
|
6162
|
+
const erc20Base = new ethers.Contract(baseToken, IERC20_default, l1Signer);
|
|
6163
|
+
const allowance = await wrapAs4(
|
|
5964
6164
|
"RPC",
|
|
5965
|
-
OP_DEPOSITS.ethNonBase.
|
|
5966
|
-
() =>
|
|
5967
|
-
ctx.chainIdL2,
|
|
5968
|
-
gasPriceForBaseCost,
|
|
5969
|
-
ctx.l2GasLimit,
|
|
5970
|
-
ctx.gasPerPubdata
|
|
5971
|
-
),
|
|
6165
|
+
OP_DEPOSITS.ethNonBase.allowanceBase,
|
|
6166
|
+
() => erc20Base.allowance(ctx.sender, ctx.l1AssetRouter),
|
|
5972
6167
|
{
|
|
5973
|
-
ctx: { where: "
|
|
5974
|
-
message: "
|
|
6168
|
+
ctx: { where: "erc20.allowance", token: baseToken, spender: ctx.l1AssetRouter },
|
|
6169
|
+
message: "Failed to read base-token allowance."
|
|
5975
6170
|
}
|
|
5976
6171
|
);
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
{
|
|
5989
|
-
ctx: { where: "erc20.allowance", token: baseToken, spender: ctx.l1AssetRouter },
|
|
5990
|
-
message: "Failed to read base-token allowance."
|
|
6172
|
+
if (allowance < mintValue) {
|
|
6173
|
+
approvals.push({ token: baseToken, spender: ctx.l1AssetRouter, amount: mintValue });
|
|
6174
|
+
steps.push({
|
|
6175
|
+
key: `approve:${baseToken}`,
|
|
6176
|
+
kind: "approve",
|
|
6177
|
+
description: `Approve base token for fees (mintValue)`,
|
|
6178
|
+
tx: {
|
|
6179
|
+
to: baseToken,
|
|
6180
|
+
data: erc20Base.interface.encodeFunctionData("approve", [ctx.l1AssetRouter, mintValue]),
|
|
6181
|
+
from: ctx.sender,
|
|
6182
|
+
...ctx.gasOverrides
|
|
5991
6183
|
}
|
|
5992
|
-
);
|
|
5993
|
-
if (allowance < mintValue) {
|
|
5994
|
-
approvals.push({ token: baseToken, spender: ctx.l1AssetRouter, amount: mintValue });
|
|
5995
|
-
const data = erc20.interface.encodeFunctionData("approve", [
|
|
5996
|
-
ctx.l1AssetRouter,
|
|
5997
|
-
mintValue
|
|
5998
|
-
]);
|
|
5999
|
-
steps.push({
|
|
6000
|
-
key: `approve:${baseToken}:${ctx.l1AssetRouter}`,
|
|
6001
|
-
kind: "approve",
|
|
6002
|
-
description: `Approve base token for mintValue`,
|
|
6003
|
-
tx: { to: baseToken, data, from: ctx.sender, ...txOverrides }
|
|
6004
|
-
});
|
|
6005
|
-
}
|
|
6184
|
+
});
|
|
6006
6185
|
}
|
|
6007
|
-
const secondBridgeCalldata = await
|
|
6186
|
+
const secondBridgeCalldata = await wrapAs4(
|
|
6008
6187
|
"INTERNAL",
|
|
6009
6188
|
OP_DEPOSITS.ethNonBase.encodeCalldata,
|
|
6010
6189
|
() => Promise.resolve(encodeSecondBridgeEthArgs(p.amount, p.to ?? ctx.sender)),
|
|
@@ -6016,73 +6195,68 @@ function routeEthNonBase() {
|
|
|
6016
6195
|
}
|
|
6017
6196
|
}
|
|
6018
6197
|
);
|
|
6019
|
-
const
|
|
6198
|
+
const requestStruct = {
|
|
6020
6199
|
chainId: ctx.chainIdL2,
|
|
6021
6200
|
mintValue,
|
|
6022
|
-
l2Value:
|
|
6023
|
-
l2GasLimit:
|
|
6201
|
+
l2Value: p.amount,
|
|
6202
|
+
l2GasLimit: l2GasParams.gasLimit,
|
|
6024
6203
|
l2GasPerPubdataByteLimit: ctx.gasPerPubdata,
|
|
6025
6204
|
refundRecipient: ctx.refundRecipient,
|
|
6026
6205
|
secondBridgeAddress: ctx.l1AssetRouter,
|
|
6027
6206
|
secondBridgeValue: p.amount,
|
|
6028
6207
|
secondBridgeCalldata
|
|
6029
6208
|
};
|
|
6030
|
-
const
|
|
6209
|
+
const data = new ethers.Contract(
|
|
6031
6210
|
ctx.bridgehub,
|
|
6032
6211
|
IBridgehub_default,
|
|
6033
6212
|
ctx.client.l1
|
|
6034
|
-
).interface.encodeFunctionData("requestL2TransactionTwoBridges", [
|
|
6035
|
-
|
|
6036
|
-
const bridgeTx = {
|
|
6213
|
+
).interface.encodeFunctionData("requestL2TransactionTwoBridges", [requestStruct]);
|
|
6214
|
+
const l1TxCandidate = {
|
|
6037
6215
|
to: ctx.bridgehub,
|
|
6038
|
-
data
|
|
6216
|
+
data,
|
|
6039
6217
|
value: p.amount,
|
|
6040
6218
|
// base ≠ ETH ⇒ msg.value == secondBridgeValue
|
|
6041
6219
|
from: ctx.sender,
|
|
6042
|
-
...
|
|
6220
|
+
...ctx.gasOverrides
|
|
6043
6221
|
};
|
|
6044
|
-
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
ctx: { where: "l1.estimateGas", to: ctx.bridgehub },
|
|
6055
|
-
message: "Failed to estimate gas for Bridgehub request."
|
|
6056
|
-
}
|
|
6057
|
-
);
|
|
6058
|
-
const buffered = BigInt(est) * 115n / 100n;
|
|
6059
|
-
bridgeTx.gasLimit = buffered;
|
|
6060
|
-
resolvedL1GasLimit = buffered;
|
|
6061
|
-
} catch {
|
|
6062
|
-
}
|
|
6222
|
+
const l1GasParams = await quoteL1Gas2({
|
|
6223
|
+
ctx,
|
|
6224
|
+
tx: l1TxCandidate,
|
|
6225
|
+
overrides: ctx.gasOverrides,
|
|
6226
|
+
fallbackGasLimit: SAFE_L1_BRIDGE_GAS
|
|
6227
|
+
});
|
|
6228
|
+
if (l1GasParams) {
|
|
6229
|
+
l1TxCandidate.gasLimit = l1GasParams.gasLimit;
|
|
6230
|
+
l1TxCandidate.maxFeePerGas = l1GasParams.maxFeePerGas;
|
|
6231
|
+
l1TxCandidate.maxPriorityFeePerGas = l1GasParams.maxPriorityFeePerGas;
|
|
6063
6232
|
}
|
|
6064
6233
|
steps.push({
|
|
6065
6234
|
key: "bridgehub:two-bridges:eth-nonbase",
|
|
6066
6235
|
kind: "bridgehub:two-bridges",
|
|
6067
6236
|
description: "Bridge ETH (fees in base ERC-20) via Bridgehub.requestL2TransactionTwoBridges",
|
|
6068
|
-
tx:
|
|
6237
|
+
tx: l1TxCandidate
|
|
6238
|
+
});
|
|
6239
|
+
const fees = buildFeeBreakdown({
|
|
6240
|
+
feeToken: baseToken,
|
|
6241
|
+
l1Gas: l1GasParams,
|
|
6242
|
+
l2Gas: l2GasParams,
|
|
6243
|
+
l2BaseCost: baseCost,
|
|
6244
|
+
operatorTip: ctx.operatorTip,
|
|
6245
|
+
mintValue
|
|
6069
6246
|
});
|
|
6070
6247
|
return {
|
|
6071
6248
|
steps,
|
|
6072
6249
|
approvals,
|
|
6073
|
-
|
|
6250
|
+
fees
|
|
6074
6251
|
};
|
|
6075
6252
|
}
|
|
6076
6253
|
};
|
|
6077
6254
|
}
|
|
6078
|
-
var { wrapAs:
|
|
6079
|
-
var BASE_COST_BUFFER_BPS2 = 100n;
|
|
6080
|
-
var BPS2 = 10000n;
|
|
6081
|
-
var withBuffer2 = (x) => x * (BPS2 + BASE_COST_BUFFER_BPS2) / BPS2;
|
|
6255
|
+
var { wrapAs: wrapAs5 } = createErrorHandlers("deposits");
|
|
6082
6256
|
function routeErc20Base() {
|
|
6083
6257
|
return {
|
|
6084
6258
|
async preflight(p, ctx) {
|
|
6085
|
-
await
|
|
6259
|
+
await wrapAs5(
|
|
6086
6260
|
"VALIDATION",
|
|
6087
6261
|
OP_DEPOSITS.base.assertErc20Asset,
|
|
6088
6262
|
() => {
|
|
@@ -6092,17 +6266,8 @@ function routeErc20Base() {
|
|
|
6092
6266
|
},
|
|
6093
6267
|
{ ctx: { token: p.token } }
|
|
6094
6268
|
);
|
|
6095
|
-
const
|
|
6096
|
-
|
|
6097
|
-
"CONTRACT",
|
|
6098
|
-
OP_DEPOSITS.base.baseToken,
|
|
6099
|
-
() => bh.baseToken(ctx.chainIdL2),
|
|
6100
|
-
{
|
|
6101
|
-
ctx: { where: "bridgehub.baseToken", chainIdL2: ctx.chainIdL2 },
|
|
6102
|
-
message: "Failed to read base token."
|
|
6103
|
-
}
|
|
6104
|
-
);
|
|
6105
|
-
await wrapAs4(
|
|
6269
|
+
const baseToken = await ctx.client.baseToken(ctx.chainIdL2);
|
|
6270
|
+
await wrapAs5(
|
|
6106
6271
|
"VALIDATION",
|
|
6107
6272
|
OP_DEPOSITS.base.assertMatchesBase,
|
|
6108
6273
|
() => {
|
|
@@ -6115,42 +6280,28 @@ function routeErc20Base() {
|
|
|
6115
6280
|
return;
|
|
6116
6281
|
},
|
|
6117
6282
|
async build(p, ctx) {
|
|
6118
|
-
const
|
|
6119
|
-
const
|
|
6120
|
-
const
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
"
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
ctx.chainIdL2,
|
|
6136
|
-
gasPriceForBaseCost,
|
|
6137
|
-
ctx.l2GasLimit,
|
|
6138
|
-
ctx.gasPerPubdata
|
|
6139
|
-
),
|
|
6140
|
-
{
|
|
6141
|
-
ctx: { where: "l2TransactionBaseCost", chainIdL2: ctx.chainIdL2 },
|
|
6142
|
-
message: "Could not fetch L2 base cost from Bridgehub."
|
|
6143
|
-
}
|
|
6144
|
-
);
|
|
6145
|
-
const baseCost = BigInt(rawBaseCost);
|
|
6146
|
-
const l2Value = p.amount;
|
|
6147
|
-
const rawMintValue = baseCost + ctx.operatorTip + l2Value;
|
|
6148
|
-
const mintValue = withBuffer2(rawMintValue);
|
|
6283
|
+
const l1Signer = ctx.client.getL1Signer();
|
|
6284
|
+
const baseToken = await ctx.client.baseToken(ctx.chainIdL2);
|
|
6285
|
+
const l2TxModel = {
|
|
6286
|
+
to: p.to ?? ctx.sender,
|
|
6287
|
+
from: ctx.sender,
|
|
6288
|
+
data: "0x",
|
|
6289
|
+
value: 0n
|
|
6290
|
+
};
|
|
6291
|
+
const l2GasParams = await quoteL2Gas2({
|
|
6292
|
+
ctx,
|
|
6293
|
+
route: "erc20-base",
|
|
6294
|
+
l2TxForModeling: l2TxModel,
|
|
6295
|
+
overrideGasLimit: ctx.l2GasLimit
|
|
6296
|
+
});
|
|
6297
|
+
if (!l2GasParams) throw new Error("Failed to estimate L2 gas parameters.");
|
|
6298
|
+
const baseCost = await quoteL2BaseCost2({ ctx, l2GasLimit: l2GasParams.gasLimit });
|
|
6299
|
+
const mintValue = baseCost + ctx.operatorTip + p.amount;
|
|
6149
6300
|
const approvals = [];
|
|
6150
6301
|
const steps = [];
|
|
6151
6302
|
{
|
|
6152
|
-
const erc20 = new ethers.Contract(baseToken, IERC20_default,
|
|
6153
|
-
const allowance = await
|
|
6303
|
+
const erc20 = new ethers.Contract(baseToken, IERC20_default, l1Signer);
|
|
6304
|
+
const allowance = await wrapAs5(
|
|
6154
6305
|
"RPC",
|
|
6155
6306
|
OP_DEPOSITS.base.allowance,
|
|
6156
6307
|
() => erc20.allowance(ctx.sender, ctx.l1AssetRouter),
|
|
@@ -6161,70 +6312,70 @@ function routeErc20Base() {
|
|
|
6161
6312
|
);
|
|
6162
6313
|
if (allowance < mintValue) {
|
|
6163
6314
|
approvals.push({ token: baseToken, spender: ctx.l1AssetRouter, amount: mintValue });
|
|
6164
|
-
const data2 = erc20.interface.encodeFunctionData("approve", [
|
|
6165
|
-
ctx.l1AssetRouter,
|
|
6166
|
-
mintValue
|
|
6167
|
-
]);
|
|
6168
6315
|
steps.push({
|
|
6169
6316
|
key: `approve:${baseToken}:${ctx.l1AssetRouter}`,
|
|
6170
6317
|
kind: "approve",
|
|
6171
6318
|
description: "Approve base token for mintValue",
|
|
6172
|
-
tx: {
|
|
6319
|
+
tx: {
|
|
6320
|
+
to: baseToken,
|
|
6321
|
+
data: erc20.interface.encodeFunctionData("approve", [ctx.l1AssetRouter, mintValue]),
|
|
6322
|
+
from: ctx.sender,
|
|
6323
|
+
...ctx.gasOverrides
|
|
6324
|
+
}
|
|
6173
6325
|
});
|
|
6174
6326
|
}
|
|
6175
6327
|
}
|
|
6176
|
-
const
|
|
6328
|
+
const requestStruct = buildDirectRequestStruct({
|
|
6177
6329
|
chainId: ctx.chainIdL2,
|
|
6178
6330
|
mintValue,
|
|
6179
|
-
l2GasLimit:
|
|
6331
|
+
l2GasLimit: l2GasParams.gasLimit,
|
|
6180
6332
|
gasPerPubdata: ctx.gasPerPubdata,
|
|
6181
6333
|
refundRecipient: ctx.refundRecipient,
|
|
6182
6334
|
l2Contract: p.to ?? ctx.sender,
|
|
6183
|
-
l2Value
|
|
6335
|
+
l2Value: p.amount
|
|
6184
6336
|
});
|
|
6185
6337
|
const data = new ethers.Contract(
|
|
6186
6338
|
ctx.bridgehub,
|
|
6187
6339
|
IBridgehub_default,
|
|
6188
6340
|
ctx.client.l1
|
|
6189
|
-
).interface.encodeFunctionData("requestL2TransactionDirect", [
|
|
6190
|
-
const
|
|
6341
|
+
).interface.encodeFunctionData("requestL2TransactionDirect", [requestStruct]);
|
|
6342
|
+
const l1TxCandidate = {
|
|
6191
6343
|
to: ctx.bridgehub,
|
|
6192
6344
|
data,
|
|
6193
6345
|
value: 0n,
|
|
6194
6346
|
// base token is ERC-20 ⇒ msg.value MUST be 0
|
|
6195
6347
|
from: ctx.sender,
|
|
6196
|
-
...
|
|
6348
|
+
...ctx.gasOverrides
|
|
6197
6349
|
};
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
ctx: { where: "l1.estimateGas", to: ctx.bridgehub },
|
|
6209
|
-
message: "Failed to estimate gas for Bridgehub request."
|
|
6210
|
-
}
|
|
6211
|
-
);
|
|
6212
|
-
const buffered = BigInt(est) * 115n / 100n;
|
|
6213
|
-
tx.gasLimit = buffered;
|
|
6214
|
-
resolvedL1GasLimit = buffered;
|
|
6215
|
-
} catch {
|
|
6216
|
-
}
|
|
6350
|
+
const l1GasParams = await quoteL1Gas2({
|
|
6351
|
+
ctx,
|
|
6352
|
+
tx: l1TxCandidate,
|
|
6353
|
+
overrides: ctx.gasOverrides,
|
|
6354
|
+
fallbackGasLimit: SAFE_L1_BRIDGE_GAS
|
|
6355
|
+
});
|
|
6356
|
+
if (l1GasParams) {
|
|
6357
|
+
l1TxCandidate.gasLimit = l1GasParams.gasLimit;
|
|
6358
|
+
l1TxCandidate.maxFeePerGas = l1GasParams.maxFeePerGas;
|
|
6359
|
+
l1TxCandidate.maxPriorityFeePerGas = l1GasParams.maxPriorityFeePerGas;
|
|
6217
6360
|
}
|
|
6218
6361
|
steps.push({
|
|
6219
6362
|
key: "bridgehub:direct:erc20-base",
|
|
6220
6363
|
kind: "bridgehub:direct",
|
|
6221
6364
|
description: "Bridge base ERC-20 via Bridgehub.requestL2TransactionDirect",
|
|
6222
|
-
tx
|
|
6365
|
+
tx: l1TxCandidate
|
|
6366
|
+
});
|
|
6367
|
+
const fees = buildFeeBreakdown({
|
|
6368
|
+
feeToken: baseToken,
|
|
6369
|
+
l1Gas: l1GasParams,
|
|
6370
|
+
l2Gas: l2GasParams,
|
|
6371
|
+
l2BaseCost: baseCost,
|
|
6372
|
+
operatorTip: ctx.operatorTip,
|
|
6373
|
+
mintValue
|
|
6223
6374
|
});
|
|
6224
6375
|
return {
|
|
6225
6376
|
steps,
|
|
6226
6377
|
approvals,
|
|
6227
|
-
|
|
6378
|
+
fees
|
|
6228
6379
|
};
|
|
6229
6380
|
}
|
|
6230
6381
|
};
|
|
@@ -6243,37 +6394,19 @@ function createDepositsResource(client) {
|
|
|
6243
6394
|
const ctx = await commonCtx(p, client);
|
|
6244
6395
|
const route = ctx.route;
|
|
6245
6396
|
await ROUTES[route].preflight?.(p, ctx);
|
|
6246
|
-
const { steps, approvals,
|
|
6247
|
-
const { baseCost, mintValue } = quoteExtras;
|
|
6248
|
-
const fallbackGasLimit = quoteExtras.l1GasLimit;
|
|
6249
|
-
const resolveGasLimit = () => {
|
|
6250
|
-
if (ctx.fee.gasLimit != null) return ctx.fee.gasLimit;
|
|
6251
|
-
for (let i = steps.length - 1; i >= 0; i--) {
|
|
6252
|
-
const candidate = steps[i].tx.gasLimit;
|
|
6253
|
-
if (candidate == null) continue;
|
|
6254
|
-
if (typeof candidate === "bigint") return candidate;
|
|
6255
|
-
try {
|
|
6256
|
-
return BigInt(candidate.toString());
|
|
6257
|
-
} catch {
|
|
6258
|
-
}
|
|
6259
|
-
}
|
|
6260
|
-
if (fallbackGasLimit != null) return fallbackGasLimit;
|
|
6261
|
-
return ctx.l2GasLimit;
|
|
6262
|
-
};
|
|
6263
|
-
const gasLimit = resolveGasLimit();
|
|
6397
|
+
const { steps, approvals, fees } = await ROUTES[route].build(p, ctx);
|
|
6264
6398
|
return {
|
|
6265
6399
|
route: ctx.route,
|
|
6266
6400
|
summary: {
|
|
6267
6401
|
route: ctx.route,
|
|
6268
6402
|
approvalsNeeded: approvals,
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
fees
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
}
|
|
6403
|
+
amounts: {
|
|
6404
|
+
transfer: { token: p.token, amount: p.amount }
|
|
6405
|
+
},
|
|
6406
|
+
fees,
|
|
6407
|
+
// Legacy fields (maintained for backward compatibility)
|
|
6408
|
+
baseCost: fees.l2?.baseCost,
|
|
6409
|
+
mintValue: fees.mintValue
|
|
6277
6410
|
},
|
|
6278
6411
|
steps
|
|
6279
6412
|
};
|
|
@@ -6342,7 +6475,7 @@ function createDepositsResource(client) {
|
|
|
6342
6475
|
step.tx.maxPriorityFeePerGas = overrides.maxPriorityFeePerGas;
|
|
6343
6476
|
}
|
|
6344
6477
|
}
|
|
6345
|
-
if (!
|
|
6478
|
+
if (!p.l1TxOverrides?.gasLimit) {
|
|
6346
6479
|
try {
|
|
6347
6480
|
const est = await client.l1.estimateGas(step.tx);
|
|
6348
6481
|
step.tx.gasLimit = BigInt(est) * 115n / 100n;
|
|
@@ -6533,7 +6666,7 @@ function normalizeTokenForRouting(token) {
|
|
|
6533
6666
|
function pickWithdrawRoute(args) {
|
|
6534
6667
|
const tokenNorm = normalizeTokenForRouting(args.token);
|
|
6535
6668
|
const isL2BaseAlias = tokenNorm.toLowerCase() === L2_BASE_TOKEN_ADDRESS.toLowerCase();
|
|
6536
|
-
if (isL2BaseAlias) return
|
|
6669
|
+
if (isL2BaseAlias) return "base";
|
|
6537
6670
|
return "erc20-nonbase";
|
|
6538
6671
|
}
|
|
6539
6672
|
async function ntvBaseAssetId(l2, ntv) {
|
|
@@ -6567,10 +6700,7 @@ async function commonCtx2(p, client) {
|
|
|
6567
6700
|
const { chainId } = await client.l2.getNetwork();
|
|
6568
6701
|
const chainIdL2 = BigInt(chainId);
|
|
6569
6702
|
const baseIsEth = await isEthBasedChain(client.l2, l2NativeTokenVault);
|
|
6570
|
-
const
|
|
6571
|
-
const route = pickWithdrawRoute({ token: p.token, baseIsEth });
|
|
6572
|
-
const l2GasLimit = p.l2GasLimit ?? 300000n;
|
|
6573
|
-
const gasBufferPct = 15;
|
|
6703
|
+
const route = pickWithdrawRoute({ token: p.token});
|
|
6574
6704
|
return {
|
|
6575
6705
|
client,
|
|
6576
6706
|
bridgehub,
|
|
@@ -6583,29 +6713,111 @@ async function commonCtx2(p, client) {
|
|
|
6583
6713
|
l2NativeTokenVault,
|
|
6584
6714
|
l2BaseTokenSystem,
|
|
6585
6715
|
baseIsEth,
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6716
|
+
gasOverrides: p.l2TxOverrides
|
|
6717
|
+
};
|
|
6718
|
+
}
|
|
6719
|
+
|
|
6720
|
+
// src/core/resources/withdrawals/gas.ts
|
|
6721
|
+
function makeGasQuote2(p) {
|
|
6722
|
+
return {
|
|
6723
|
+
gasLimit: p.gasLimit,
|
|
6724
|
+
maxFeePerGas: p.maxFeePerGas,
|
|
6725
|
+
maxPriorityFeePerGas: p.maxPriorityFeePerGas,
|
|
6726
|
+
maxCost: p.gasLimit * p.maxFeePerGas
|
|
6727
|
+
};
|
|
6728
|
+
}
|
|
6729
|
+
async function fetchFees2(estimator) {
|
|
6730
|
+
try {
|
|
6731
|
+
const fees = await estimator.estimateFeesPerGas();
|
|
6732
|
+
if (fees.maxFeePerGas != null) {
|
|
6733
|
+
return {
|
|
6734
|
+
maxFeePerGas: fees.maxFeePerGas,
|
|
6735
|
+
maxPriorityFeePerGas: fees.maxPriorityFeePerGas ?? 0n
|
|
6736
|
+
};
|
|
6737
|
+
}
|
|
6738
|
+
if (fees.gasPrice != null) {
|
|
6739
|
+
return {
|
|
6740
|
+
maxFeePerGas: fees.gasPrice,
|
|
6741
|
+
maxPriorityFeePerGas: 0n
|
|
6742
|
+
};
|
|
6743
|
+
}
|
|
6744
|
+
} catch {
|
|
6745
|
+
}
|
|
6746
|
+
try {
|
|
6747
|
+
const gp = await estimator.getGasPrice();
|
|
6748
|
+
return { maxFeePerGas: gp, maxPriorityFeePerGas: 0n };
|
|
6749
|
+
} catch {
|
|
6750
|
+
return { maxFeePerGas: 0n, maxPriorityFeePerGas: 0n };
|
|
6751
|
+
}
|
|
6752
|
+
}
|
|
6753
|
+
async function quoteL2Gas3(input) {
|
|
6754
|
+
const { estimator, tx, overrides } = input;
|
|
6755
|
+
const market = await fetchFees2(estimator);
|
|
6756
|
+
const o = overrides;
|
|
6757
|
+
const maxFeePerGas = o?.maxFeePerGas ?? (tx.maxFeePerGas != null ? BigInt(tx.maxFeePerGas) : market.maxFeePerGas);
|
|
6758
|
+
const maxPriorityFeePerGas = o?.maxPriorityFeePerGas ?? (tx.maxPriorityFeePerGas != null ? BigInt(tx.maxPriorityFeePerGas) : market.maxPriorityFeePerGas);
|
|
6759
|
+
const explicitGasLimit = o?.gasLimit ?? (tx.gasLimit != null ? BigInt(tx.gasLimit) : void 0);
|
|
6760
|
+
if (explicitGasLimit != null) {
|
|
6761
|
+
return makeGasQuote2({
|
|
6762
|
+
gasLimit: explicitGasLimit,
|
|
6763
|
+
maxFeePerGas,
|
|
6764
|
+
maxPriorityFeePerGas
|
|
6765
|
+
});
|
|
6766
|
+
}
|
|
6767
|
+
try {
|
|
6768
|
+
const est = await estimator.estimateGas(tx);
|
|
6769
|
+
const buffered = BigInt(est) * (100n + BUFFER) / 100n;
|
|
6770
|
+
return makeGasQuote2({
|
|
6771
|
+
gasLimit: buffered,
|
|
6772
|
+
maxFeePerGas,
|
|
6773
|
+
maxPriorityFeePerGas
|
|
6774
|
+
});
|
|
6775
|
+
} catch (err) {
|
|
6776
|
+
console.warn("Failed to estimate L2 gas for withdrawal.", err);
|
|
6777
|
+
return void 0;
|
|
6778
|
+
}
|
|
6779
|
+
}
|
|
6780
|
+
|
|
6781
|
+
// src/adapters/ethers/resources/withdrawals/services/gas.ts
|
|
6782
|
+
async function quoteL2Gas4(input) {
|
|
6783
|
+
const { ctx, tx } = input;
|
|
6784
|
+
const estimator = ethersToGasEstimator(ctx.client.l2);
|
|
6785
|
+
return quoteL2Gas3({
|
|
6786
|
+
estimator,
|
|
6787
|
+
tx: toCoreTx(tx),
|
|
6788
|
+
overrides: ctx.gasOverrides
|
|
6789
|
+
});
|
|
6790
|
+
}
|
|
6791
|
+
|
|
6792
|
+
// src/adapters/ethers/resources/withdrawals/services/fees.ts
|
|
6793
|
+
function buildFeeBreakdown2(p) {
|
|
6794
|
+
const l2Total = p.l2Gas?.maxCost ?? 0n;
|
|
6795
|
+
const l2 = {
|
|
6796
|
+
total: l2Total,
|
|
6797
|
+
gasLimit: p.l2Gas?.gasLimit ?? 0n,
|
|
6798
|
+
maxFeePerGas: p.l2Gas?.maxFeePerGas ?? 0n,
|
|
6799
|
+
maxPriorityFeePerGas: p.l2Gas?.maxPriorityFeePerGas
|
|
6800
|
+
};
|
|
6801
|
+
return {
|
|
6802
|
+
token: p.feeToken,
|
|
6803
|
+
maxTotal: l2Total,
|
|
6804
|
+
l2
|
|
6589
6805
|
};
|
|
6590
6806
|
}
|
|
6591
|
-
|
|
6807
|
+
|
|
6808
|
+
// src/adapters/ethers/resources/withdrawals/routes/eth.ts
|
|
6809
|
+
var { wrapAs: wrapAs6 } = createErrorHandlers("withdrawals");
|
|
6592
6810
|
function routeEthBase() {
|
|
6593
6811
|
return {
|
|
6594
6812
|
async build(p, ctx) {
|
|
6595
6813
|
const steps = [];
|
|
6596
|
-
const
|
|
6597
|
-
const
|
|
6598
|
-
L2_BASE_TOKEN_ADDRESS,
|
|
6599
|
-
new ethers.Interface(IBaseToken_default),
|
|
6600
|
-
ctx.client.l2
|
|
6601
|
-
);
|
|
6602
|
-
const toL1 = p.to ?? ctx.sender;
|
|
6603
|
-
const data = await wrapAs5(
|
|
6814
|
+
const base = (await ctx.client.contracts()).l2BaseTokenSystem;
|
|
6815
|
+
const data = await wrapAs6(
|
|
6604
6816
|
"INTERNAL",
|
|
6605
6817
|
OP_WITHDRAWALS.eth.encodeWithdraw,
|
|
6606
|
-
() => Promise.resolve(base.interface.encodeFunctionData("withdraw", [
|
|
6818
|
+
() => Promise.resolve(base.interface.encodeFunctionData("withdraw", [p.to ?? ctx.sender])),
|
|
6607
6819
|
{
|
|
6608
|
-
ctx: { where: "L2BaseToken.withdraw", to:
|
|
6820
|
+
ctx: { where: "L2BaseToken.withdraw", to: p.to ?? ctx.sender },
|
|
6609
6821
|
message: "Failed to encode ETH withdraw calldata."
|
|
6610
6822
|
}
|
|
6611
6823
|
);
|
|
@@ -6613,38 +6825,29 @@ function routeEthBase() {
|
|
|
6613
6825
|
to: L2_BASE_TOKEN_ADDRESS,
|
|
6614
6826
|
data,
|
|
6615
6827
|
from: ctx.sender,
|
|
6616
|
-
value: p.amount
|
|
6617
|
-
maxFeePerGas,
|
|
6618
|
-
maxPriorityFeePerGas
|
|
6828
|
+
value: p.amount
|
|
6619
6829
|
};
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
message: "Failed to estimate gas for L2 ETH withdraw."
|
|
6631
|
-
}
|
|
6632
|
-
);
|
|
6633
|
-
tx.gasLimit = BigInt(est) * 115n / 100n;
|
|
6634
|
-
} catch {
|
|
6635
|
-
}
|
|
6636
|
-
}
|
|
6830
|
+
const gas = await quoteL2Gas4({ ctx, tx });
|
|
6831
|
+
if (gas) {
|
|
6832
|
+
tx.gasLimit = gas.gasLimit;
|
|
6833
|
+
tx.maxFeePerGas = gas.maxFeePerGas;
|
|
6834
|
+
tx.maxPriorityFeePerGas = gas.maxPriorityFeePerGas;
|
|
6835
|
+
}
|
|
6836
|
+
const fees = buildFeeBreakdown2({
|
|
6837
|
+
feeToken: L2_BASE_TOKEN_ADDRESS,
|
|
6838
|
+
l2Gas: gas
|
|
6839
|
+
});
|
|
6637
6840
|
steps.push({
|
|
6638
6841
|
key: "l2-base-token:withdraw",
|
|
6639
6842
|
kind: "l2-base-token:withdraw",
|
|
6640
6843
|
description: "Withdraw ETH via L2 Base Token System",
|
|
6641
6844
|
tx
|
|
6642
6845
|
});
|
|
6643
|
-
return { steps, approvals: [],
|
|
6846
|
+
return { steps, approvals: [], fees };
|
|
6644
6847
|
}
|
|
6645
6848
|
};
|
|
6646
6849
|
}
|
|
6647
|
-
var { wrapAs:
|
|
6850
|
+
var { wrapAs: wrapAs7 } = createErrorHandlers("withdrawals");
|
|
6648
6851
|
var SIG = {
|
|
6649
6852
|
withdraw: "withdraw(bytes32,bytes)"
|
|
6650
6853
|
};
|
|
@@ -6653,10 +6856,8 @@ function routeErc20NonBase2() {
|
|
|
6653
6856
|
async build(p, ctx) {
|
|
6654
6857
|
const steps = [];
|
|
6655
6858
|
const approvals = [];
|
|
6656
|
-
const { gasLimit: overrideGasLimit, maxFeePerGas, maxPriorityFeePerGas } = ctx.fee;
|
|
6657
|
-
const txOverrides = overrideGasLimit != null ? { maxFeePerGas, maxPriorityFeePerGas, gasLimit: overrideGasLimit } : { maxFeePerGas, maxPriorityFeePerGas };
|
|
6658
6859
|
const erc20 = new ethers.Contract(p.token, IERC20_default, ctx.client.getL2Signer());
|
|
6659
|
-
const current = await
|
|
6860
|
+
const current = await wrapAs7(
|
|
6660
6861
|
"CONTRACT",
|
|
6661
6862
|
OP_WITHDRAWALS.erc20.allowance,
|
|
6662
6863
|
() => erc20.allowance(ctx.sender, ctx.l2NativeTokenVault),
|
|
@@ -6676,15 +6877,26 @@ function routeErc20NonBase2() {
|
|
|
6676
6877
|
ctx.l2NativeTokenVault,
|
|
6677
6878
|
p.amount
|
|
6678
6879
|
]);
|
|
6880
|
+
const approveTx = {
|
|
6881
|
+
to: p.token,
|
|
6882
|
+
data,
|
|
6883
|
+
from: ctx.sender
|
|
6884
|
+
};
|
|
6885
|
+
const approveGas = await quoteL2Gas4({ ctx, tx: approveTx });
|
|
6886
|
+
if (approveGas) {
|
|
6887
|
+
approveTx.gasLimit = approveGas.gasLimit;
|
|
6888
|
+
approveTx.maxFeePerGas = approveGas.maxFeePerGas;
|
|
6889
|
+
approveTx.maxPriorityFeePerGas = approveGas.maxPriorityFeePerGas;
|
|
6890
|
+
}
|
|
6679
6891
|
steps.push({
|
|
6680
6892
|
key: `approve:l2:${p.token}:${ctx.l2NativeTokenVault}`,
|
|
6681
6893
|
kind: "approve:l2",
|
|
6682
6894
|
description: `Approve ${p.amount} to NativeTokenVault`,
|
|
6683
|
-
tx:
|
|
6895
|
+
tx: approveTx
|
|
6684
6896
|
});
|
|
6685
6897
|
}
|
|
6686
|
-
const ntv =
|
|
6687
|
-
const assetId = await
|
|
6898
|
+
const ntv = (await ctx.client.contracts()).l2NativeTokenVault;
|
|
6899
|
+
const assetId = await wrapAs7(
|
|
6688
6900
|
"CONTRACT",
|
|
6689
6901
|
OP_WITHDRAWALS.erc20.ensureRegistered,
|
|
6690
6902
|
() => ntv.getFunction("ensureTokenIsRegistered").staticCall(p.token),
|
|
@@ -6693,22 +6905,19 @@ function routeErc20NonBase2() {
|
|
|
6693
6905
|
message: "Failed to ensure token is registered in L2NativeTokenVault."
|
|
6694
6906
|
}
|
|
6695
6907
|
);
|
|
6696
|
-
const assetData = await
|
|
6908
|
+
const assetData = await wrapAs7(
|
|
6697
6909
|
"INTERNAL",
|
|
6698
6910
|
OP_WITHDRAWALS.erc20.encodeAssetData,
|
|
6699
6911
|
() => Promise.resolve(
|
|
6700
|
-
|
|
6701
|
-
["uint256", "address", "address"],
|
|
6702
|
-
[p.amount, p.to ?? ctx.sender, p.token]
|
|
6703
|
-
)
|
|
6912
|
+
encodeNativeTokenVaultTransferData(p.amount, p.to ?? ctx.sender, p.token)
|
|
6704
6913
|
),
|
|
6705
6914
|
{
|
|
6706
6915
|
ctx: { where: "AbiCoder.encode", token: p.token, to: p.to ?? ctx.sender },
|
|
6707
6916
|
message: "Failed to encode burn/withdraw asset data."
|
|
6708
6917
|
}
|
|
6709
6918
|
);
|
|
6710
|
-
const l2ar =
|
|
6711
|
-
const dataWithdraw = await
|
|
6919
|
+
const l2ar = (await ctx.client.contracts()).l2AssetRouter;
|
|
6920
|
+
const dataWithdraw = await wrapAs7(
|
|
6712
6921
|
"INTERNAL",
|
|
6713
6922
|
OP_WITHDRAWALS.erc20.encodeWithdraw,
|
|
6714
6923
|
() => Promise.resolve(l2ar.interface.encodeFunctionData(SIG.withdraw, [assetId, assetData])),
|
|
@@ -6720,81 +6929,25 @@ function routeErc20NonBase2() {
|
|
|
6720
6929
|
const withdrawTx = {
|
|
6721
6930
|
to: ctx.l2AssetRouter,
|
|
6722
6931
|
data: dataWithdraw,
|
|
6723
|
-
from: ctx.sender
|
|
6724
|
-
...txOverrides
|
|
6932
|
+
from: ctx.sender
|
|
6725
6933
|
};
|
|
6934
|
+
const withdrawGas = await quoteL2Gas4({ ctx, tx: withdrawTx });
|
|
6935
|
+
if (withdrawGas) {
|
|
6936
|
+
withdrawTx.gasLimit = withdrawGas.gasLimit;
|
|
6937
|
+
withdrawTx.maxFeePerGas = withdrawGas.maxFeePerGas;
|
|
6938
|
+
withdrawTx.maxPriorityFeePerGas = withdrawGas.maxPriorityFeePerGas;
|
|
6939
|
+
}
|
|
6726
6940
|
steps.push({
|
|
6727
6941
|
key: "l2-asset-router:withdraw",
|
|
6728
6942
|
kind: "l2-asset-router:withdraw",
|
|
6729
6943
|
description: "Burn on L2 & send L2\u2192L1 message",
|
|
6730
6944
|
tx: withdrawTx
|
|
6731
6945
|
});
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
}
|
|
6736
|
-
var { wrapAs: wrapAs7 } = createErrorHandlers("withdrawals");
|
|
6737
|
-
function routeEthNonBase2() {
|
|
6738
|
-
return {
|
|
6739
|
-
async preflight(p, ctx) {
|
|
6740
|
-
await wrapAs7(
|
|
6741
|
-
"VALIDATION",
|
|
6742
|
-
OP_WITHDRAWALS.ethNonBase.assertNonEthBase,
|
|
6743
|
-
() => {
|
|
6744
|
-
if (p.token.toLowerCase() !== L2_BASE_TOKEN_ADDRESS.toLowerCase()) {
|
|
6745
|
-
throw new Error("eth-nonbase route requires the L2 base-token alias (0x\u2026800A).");
|
|
6746
|
-
}
|
|
6747
|
-
if (ctx.baseIsEth) {
|
|
6748
|
-
throw new Error("eth-nonbase route requires chain base \u2260 ETH.");
|
|
6749
|
-
}
|
|
6750
|
-
},
|
|
6751
|
-
{ ctx: { token: p.token, baseIsEth: ctx.baseIsEth } }
|
|
6752
|
-
);
|
|
6753
|
-
},
|
|
6754
|
-
async build(p, ctx) {
|
|
6755
|
-
const steps = [];
|
|
6756
|
-
const { gasLimit: overrideGasLimit, maxFeePerGas, maxPriorityFeePerGas } = ctx.fee;
|
|
6757
|
-
const toL1 = p.to ?? ctx.sender;
|
|
6758
|
-
const iface = new ethers.Interface(IBaseToken_default);
|
|
6759
|
-
const data = await wrapAs7(
|
|
6760
|
-
"INTERNAL",
|
|
6761
|
-
OP_WITHDRAWALS.eth.encodeWithdraw,
|
|
6762
|
-
// reuse label for base-token system call
|
|
6763
|
-
() => Promise.resolve(iface.encodeFunctionData("withdraw", [toL1])),
|
|
6764
|
-
{ ctx: { where: "L2BaseToken.withdraw", to: toL1 } }
|
|
6765
|
-
);
|
|
6766
|
-
const tx = {
|
|
6767
|
-
to: L2_BASE_TOKEN_ADDRESS,
|
|
6768
|
-
data,
|
|
6769
|
-
from: ctx.sender,
|
|
6770
|
-
value: p.amount,
|
|
6771
|
-
maxFeePerGas,
|
|
6772
|
-
maxPriorityFeePerGas
|
|
6773
|
-
};
|
|
6774
|
-
if (overrideGasLimit != null) {
|
|
6775
|
-
tx.gasLimit = overrideGasLimit;
|
|
6776
|
-
} else {
|
|
6777
|
-
try {
|
|
6778
|
-
const est = await wrapAs7(
|
|
6779
|
-
"RPC",
|
|
6780
|
-
OP_WITHDRAWALS.eth.estGas,
|
|
6781
|
-
() => ctx.client.l2.estimateGas(tx),
|
|
6782
|
-
{
|
|
6783
|
-
ctx: { where: "l2.estimateGas", to: L2_BASE_TOKEN_ADDRESS },
|
|
6784
|
-
message: "Failed to estimate gas for L2 base-token withdraw."
|
|
6785
|
-
}
|
|
6786
|
-
);
|
|
6787
|
-
tx.gasLimit = BigInt(est) * 115n / 100n;
|
|
6788
|
-
} catch {
|
|
6789
|
-
}
|
|
6790
|
-
}
|
|
6791
|
-
steps.push({
|
|
6792
|
-
key: "l2-base-token:withdraw",
|
|
6793
|
-
kind: "l2-base-token:withdraw",
|
|
6794
|
-
description: "Withdraw base token via L2 Base Token System (base \u2260 ETH)",
|
|
6795
|
-
tx
|
|
6946
|
+
const fees = buildFeeBreakdown2({
|
|
6947
|
+
feeToken: await ctx.client.baseToken(ctx.chainIdL2),
|
|
6948
|
+
l2Gas: withdrawGas
|
|
6796
6949
|
});
|
|
6797
|
-
return { steps, approvals
|
|
6950
|
+
return { steps, approvals, fees };
|
|
6798
6951
|
}
|
|
6799
6952
|
};
|
|
6800
6953
|
}
|
|
@@ -7106,10 +7259,8 @@ function createFinalizationServices(client) {
|
|
|
7106
7259
|
|
|
7107
7260
|
// src/adapters/ethers/resources/withdrawals/index.ts
|
|
7108
7261
|
var ROUTES2 = {
|
|
7109
|
-
|
|
7262
|
+
base: routeEthBase(),
|
|
7110
7263
|
// BaseTokenSystem.withdraw, chain base = ETH
|
|
7111
|
-
"eth-nonbase": routeEthNonBase2(),
|
|
7112
|
-
// BaseTokenSystem.withdraw, chain base ≠ ETH
|
|
7113
7264
|
"erc20-nonbase": routeErc20NonBase2()
|
|
7114
7265
|
// AssetRouter.withdraw for non-base ERC-20s
|
|
7115
7266
|
};
|
|
@@ -7119,32 +7270,19 @@ function createWithdrawalsResource(client) {
|
|
|
7119
7270
|
async function buildPlan(p) {
|
|
7120
7271
|
const ctx = await commonCtx2(p, client);
|
|
7121
7272
|
await ROUTES2[ctx.route].preflight?.(p, ctx);
|
|
7122
|
-
const { steps, approvals } = await ROUTES2[ctx.route].build(p, ctx);
|
|
7123
|
-
|
|
7124
|
-
if (ctx.fee.gasLimit != null) return ctx.fee.gasLimit;
|
|
7125
|
-
for (let i = steps.length - 1; i >= 0; i--) {
|
|
7126
|
-
const candidate = steps[i].tx.gasLimit;
|
|
7127
|
-
if (candidate == null) continue;
|
|
7128
|
-
if (typeof candidate === "bigint") return candidate;
|
|
7129
|
-
try {
|
|
7130
|
-
return BigInt(candidate.toString());
|
|
7131
|
-
} catch {
|
|
7132
|
-
}
|
|
7133
|
-
}
|
|
7134
|
-
return void 0;
|
|
7135
|
-
};
|
|
7136
|
-
const gasLimit = resolveGasLimit();
|
|
7137
|
-
const summary = {
|
|
7273
|
+
const { steps, approvals, fees } = await ROUTES2[ctx.route].build(p, ctx);
|
|
7274
|
+
return {
|
|
7138
7275
|
route: ctx.route,
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7276
|
+
summary: {
|
|
7277
|
+
route: ctx.route,
|
|
7278
|
+
approvalsNeeded: approvals,
|
|
7279
|
+
amounts: {
|
|
7280
|
+
transfer: { token: p.token, amount: p.amount }
|
|
7281
|
+
},
|
|
7282
|
+
fees
|
|
7283
|
+
},
|
|
7284
|
+
steps
|
|
7146
7285
|
};
|
|
7147
|
-
return { route: ctx.route, summary, steps };
|
|
7148
7286
|
}
|
|
7149
7287
|
const finalizeCache = /* @__PURE__ */ new Map();
|
|
7150
7288
|
const quote = (p) => wrap2(
|
|
@@ -7509,7 +7647,6 @@ function createEthersSdk(client) {
|
|
|
7509
7647
|
}
|
|
7510
7648
|
|
|
7511
7649
|
exports.buildDirectRequestStruct = buildDirectRequestStruct;
|
|
7512
|
-
exports.checkBaseCost = checkBaseCost;
|
|
7513
7650
|
exports.classifyReadinessFromRevert = classifyReadinessFromRevert;
|
|
7514
7651
|
exports.createClient = createEthersClient;
|
|
7515
7652
|
exports.createDepositsResource = createDepositsResource;
|
|
@@ -7527,11 +7664,7 @@ exports.encodeSecondBridgeArgs = encodeSecondBridgeArgs;
|
|
|
7527
7664
|
exports.encodeSecondBridgeDataV1 = encodeSecondBridgeDataV1;
|
|
7528
7665
|
exports.encodeSecondBridgeErc20Args = encodeSecondBridgeErc20Args;
|
|
7529
7666
|
exports.encodeSecondBridgeEthArgs = encodeSecondBridgeEthArgs;
|
|
7530
|
-
exports.getFeeOverrides = getFeeOverrides;
|
|
7531
|
-
exports.getGasPriceWei = getGasPriceWei;
|
|
7532
|
-
exports.getL2FeeOverrides = getL2FeeOverrides;
|
|
7533
7667
|
exports.registerErrorAbi = registerErrorAbi;
|
|
7534
|
-
exports.scaleGasLimit = scaleGasLimit;
|
|
7535
7668
|
exports.toZKsyncError = toZKsyncError;
|
|
7536
7669
|
//# sourceMappingURL=index.cjs.map
|
|
7537
7670
|
//# sourceMappingURL=index.cjs.map
|