@veil-cash/sdk 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ethers } from 'ethers';
2
- import { privateKeyToAccount } from 'viem/accounts';
2
+ import { privateKeyToAccount, privateKeyToAddress } from 'viem/accounts';
3
3
  import * as crypto from 'crypto';
4
- import { encodeFunctionData, parseEther, parseUnits, createPublicClient, http, formatUnits } from 'viem';
4
+ import { encodeFunctionData, parseEther, parseUnits, createPublicClient, http, formatUnits, keccak256, encodePacked, isAddress, formatEther } from 'viem';
5
5
  import { base } from 'viem/chains';
6
6
  import MerkleTree from 'fixed-merkle-tree-legacy';
7
7
  import { groth16 } from 'snarkjs';
@@ -347,9 +347,11 @@ var ADDRESSES = {
347
347
  usdcPool: "0x5c50d58E49C59d112680c187De2Bf989d2a91242",
348
348
  usdcQueue: "0x5530241b24504bF05C9a22e95A1F5458888e6a9B",
349
349
  usdcToken: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
350
+ forwarderFactory: "0x2848Fd62293A1ff3b4a897E9FcD0e5962dcc8101",
350
351
  chainId: 8453,
351
352
  relayUrl: "https://veil-relay.up.railway.app"
352
353
  };
354
+ var FORWARDER_CONTRACT_VERSION = "1";
353
355
  var POOL_CONFIG = {
354
356
  eth: {
355
357
  decimals: 18,
@@ -389,6 +391,9 @@ function getQueueAddress(pool) {
389
391
  throw new Error(`Unknown pool: ${pool}`);
390
392
  }
391
393
  }
394
+ function getForwarderFactoryAddress() {
395
+ return getAddresses().forwarderFactory;
396
+ }
392
397
  function getRelayUrl() {
393
398
  return ADDRESSES.relayUrl;
394
399
  }
@@ -1009,6 +1014,170 @@ var ERC20_ABI = [
1009
1014
  type: "function"
1010
1015
  }
1011
1016
  ];
1017
+ var FORWARDER_FACTORY_ABI = [
1018
+ {
1019
+ inputs: [],
1020
+ name: "CONTRACT_VERSION",
1021
+ outputs: [{ internalType: "string", name: "", type: "string" }],
1022
+ stateMutability: "view",
1023
+ type: "function"
1024
+ },
1025
+ {
1026
+ inputs: [
1027
+ { internalType: "bytes32", name: "_salt", type: "bytes32" },
1028
+ { internalType: "bytes", name: "_childDepositKey", type: "bytes" },
1029
+ { internalType: "address", name: "_owner", type: "address" }
1030
+ ],
1031
+ name: "computeAddress",
1032
+ outputs: [{ internalType: "address", name: "", type: "address" }],
1033
+ stateMutability: "view",
1034
+ type: "function"
1035
+ },
1036
+ {
1037
+ inputs: [
1038
+ { internalType: "bytes32", name: "_salt", type: "bytes32" },
1039
+ { internalType: "bytes", name: "_childDepositKey", type: "bytes" },
1040
+ { internalType: "address", name: "_owner", type: "address" }
1041
+ ],
1042
+ name: "deploy",
1043
+ outputs: [{ internalType: "address", name: "forwarder", type: "address" }],
1044
+ stateMutability: "nonpayable",
1045
+ type: "function"
1046
+ },
1047
+ {
1048
+ inputs: [],
1049
+ name: "relayer",
1050
+ outputs: [{ internalType: "address", name: "", type: "address" }],
1051
+ stateMutability: "view",
1052
+ type: "function"
1053
+ },
1054
+ {
1055
+ inputs: [],
1056
+ name: "veilEntry",
1057
+ outputs: [{ internalType: "address payable", name: "", type: "address" }],
1058
+ stateMutability: "view",
1059
+ type: "function"
1060
+ },
1061
+ {
1062
+ inputs: [],
1063
+ name: "usdc",
1064
+ outputs: [{ internalType: "address", name: "", type: "address" }],
1065
+ stateMutability: "view",
1066
+ type: "function"
1067
+ },
1068
+ {
1069
+ inputs: [],
1070
+ name: "owner",
1071
+ outputs: [{ internalType: "address", name: "", type: "address" }],
1072
+ stateMutability: "view",
1073
+ type: "function"
1074
+ }
1075
+ ];
1076
+ var FORWARDER_ABI = [
1077
+ {
1078
+ inputs: [],
1079
+ name: "CONTRACT_VERSION",
1080
+ outputs: [{ internalType: "string", name: "", type: "string" }],
1081
+ stateMutability: "view",
1082
+ type: "function"
1083
+ },
1084
+ {
1085
+ inputs: [
1086
+ { internalType: "address", name: "_token", type: "address" },
1087
+ { internalType: "address", name: "_to", type: "address" },
1088
+ { internalType: "uint256", name: "_amount", type: "uint256" },
1089
+ { internalType: "uint256", name: "_nonce", type: "uint256" },
1090
+ { internalType: "uint256", name: "_deadline", type: "uint256" },
1091
+ { internalType: "bytes", name: "_signature", type: "bytes" }
1092
+ ],
1093
+ name: "withdraw",
1094
+ outputs: [],
1095
+ stateMutability: "nonpayable",
1096
+ type: "function"
1097
+ },
1098
+ {
1099
+ inputs: [{ internalType: "uint256", name: "", type: "uint256" }],
1100
+ name: "usedNonces",
1101
+ outputs: [{ internalType: "bool", name: "", type: "bool" }],
1102
+ stateMutability: "view",
1103
+ type: "function"
1104
+ },
1105
+ {
1106
+ inputs: [],
1107
+ name: "owner",
1108
+ outputs: [{ internalType: "address", name: "", type: "address" }],
1109
+ stateMutability: "view",
1110
+ type: "function"
1111
+ },
1112
+ {
1113
+ inputs: [],
1114
+ name: "factory",
1115
+ outputs: [{ internalType: "address", name: "", type: "address" }],
1116
+ stateMutability: "view",
1117
+ type: "function"
1118
+ },
1119
+ {
1120
+ inputs: [],
1121
+ name: "childDepositKey",
1122
+ outputs: [{ internalType: "bytes", name: "", type: "bytes" }],
1123
+ stateMutability: "view",
1124
+ type: "function"
1125
+ },
1126
+ {
1127
+ inputs: [],
1128
+ name: "entry",
1129
+ outputs: [{ internalType: "address", name: "", type: "address" }],
1130
+ stateMutability: "view",
1131
+ type: "function"
1132
+ },
1133
+ {
1134
+ inputs: [],
1135
+ name: "usdc",
1136
+ outputs: [{ internalType: "address", name: "", type: "address" }],
1137
+ stateMutability: "view",
1138
+ type: "function"
1139
+ },
1140
+ {
1141
+ inputs: [],
1142
+ name: "sweepETH",
1143
+ outputs: [],
1144
+ stateMutability: "nonpayable",
1145
+ type: "function"
1146
+ },
1147
+ {
1148
+ inputs: [],
1149
+ name: "sweepUSDC",
1150
+ outputs: [],
1151
+ stateMutability: "nonpayable",
1152
+ type: "function"
1153
+ },
1154
+ {
1155
+ inputs: [],
1156
+ name: "eip712Domain",
1157
+ outputs: [
1158
+ { internalType: "bytes1", name: "fields", type: "bytes1" },
1159
+ { internalType: "string", name: "name", type: "string" },
1160
+ { internalType: "string", name: "version", type: "string" },
1161
+ { internalType: "uint256", name: "chainId", type: "uint256" },
1162
+ { internalType: "address", name: "verifyingContract", type: "address" },
1163
+ { internalType: "bytes32", name: "salt", type: "bytes32" },
1164
+ { internalType: "uint256[]", name: "extensions", type: "uint256[]" }
1165
+ ],
1166
+ stateMutability: "view",
1167
+ type: "function"
1168
+ },
1169
+ { type: "error", name: "ZeroAddress", inputs: [] },
1170
+ { type: "error", name: "ZeroAmount", inputs: [] },
1171
+ { type: "error", name: "InvalidDepositKey", inputs: [] },
1172
+ { type: "error", name: "NotRelayer", inputs: [] },
1173
+ { type: "error", name: "NoETHBalance", inputs: [] },
1174
+ { type: "error", name: "NoTokenBalance", inputs: [] },
1175
+ { type: "error", name: "TokenApproveFailed", inputs: [] },
1176
+ { type: "error", name: "ETHTransferFailed", inputs: [] },
1177
+ { type: "error", name: "NonceUsed", inputs: [] },
1178
+ { type: "error", name: "Unauthorized", inputs: [] },
1179
+ { type: "error", name: "DeadlineExpired", inputs: [] }
1180
+ ];
1012
1181
 
1013
1182
  // src/deposit.ts
1014
1183
  function buildRegisterTx(depositKey, ownerAddress) {
@@ -1463,6 +1632,27 @@ var RelayError = class extends Error {
1463
1632
  this.network = network;
1464
1633
  }
1465
1634
  };
1635
+ async function postRelayJson(endpoint, body, relayUrl) {
1636
+ const url = relayUrl || getRelayUrl();
1637
+ const response = await fetch(`${url}${endpoint}`, {
1638
+ method: "POST",
1639
+ headers: {
1640
+ "Content-Type": "application/json"
1641
+ },
1642
+ body: JSON.stringify(body)
1643
+ });
1644
+ const data = await response.json();
1645
+ if (!response.ok) {
1646
+ const errorData = data;
1647
+ throw new RelayError(
1648
+ errorData.error || errorData.message || "Relay request failed",
1649
+ response.status,
1650
+ errorData.retryAfter,
1651
+ errorData.network
1652
+ );
1653
+ }
1654
+ return data;
1655
+ }
1466
1656
  async function submitRelay(options) {
1467
1657
  const {
1468
1658
  type,
@@ -1482,30 +1672,17 @@ async function submitRelay(options) {
1482
1672
  throw new RelayError("Missing proofArgs or extData", 400);
1483
1673
  }
1484
1674
  const relayUrl = customRelayUrl || getRelayUrl();
1485
- const endpoint = `${relayUrl}/relay/${pool}`;
1486
- const response = await fetch(endpoint, {
1487
- method: "POST",
1488
- headers: {
1489
- "Content-Type": "application/json"
1490
- },
1491
- body: JSON.stringify({
1675
+ const endpoint = `/relay/${pool}`;
1676
+ return postRelayJson(
1677
+ endpoint,
1678
+ {
1492
1679
  type,
1493
1680
  proofArgs,
1494
1681
  extData,
1495
1682
  metadata
1496
- })
1497
- });
1498
- const data = await response.json();
1499
- if (!response.ok) {
1500
- const errorData = data;
1501
- throw new RelayError(
1502
- errorData.error || errorData.message || "Relay request failed",
1503
- response.status,
1504
- errorData.retryAfter,
1505
- errorData.network
1506
- );
1507
- }
1508
- return data;
1683
+ },
1684
+ relayUrl
1685
+ );
1509
1686
  }
1510
1687
  async function checkRelayHealth(relayUrl) {
1511
1688
  const url = relayUrl || getRelayUrl();
@@ -1960,7 +2137,344 @@ async function mergeUtxos(options) {
1960
2137
  recipient: "self"
1961
2138
  };
1962
2139
  }
2140
+ var SUBACCOUNT_CHILD_DOMAIN = "veil-sua-child";
2141
+ var SUBACCOUNT_SALT_DOMAIN = "veil-sua-salt";
2142
+ var ETH_ADDRESS = "0x0000000000000000000000000000000000000000";
2143
+ var DEFAULT_WITHDRAW_DEADLINE_SECONDS = 3600n;
2144
+ var DEFAULT_MAX_NONCE_SCAN = 100n;
2145
+ var MAX_SUBACCOUNT_SLOTS = 3;
2146
+ function createBaseClient(rpcUrl) {
2147
+ return createPublicClient({
2148
+ chain: base,
2149
+ transport: http(rpcUrl)
2150
+ });
2151
+ }
2152
+ function assertPrivateKey(value, label) {
2153
+ if (!/^0x[a-fA-F0-9]{64}$/.test(value)) {
2154
+ throw new Error(`${label} must be a 0x-prefixed 32-byte hex string`);
2155
+ }
2156
+ }
2157
+ function normalizeSlot(slot) {
2158
+ if (!Number.isInteger(slot) || slot < 0) {
2159
+ throw new Error("slot must be a non-negative integer");
2160
+ }
2161
+ if (slot >= MAX_SUBACCOUNT_SLOTS) {
2162
+ throw new Error(`slot must be less than ${MAX_SUBACCOUNT_SLOTS} (supported slots: 0-${MAX_SUBACCOUNT_SLOTS - 1})`);
2163
+ }
2164
+ return slot;
2165
+ }
2166
+ function normalizeAsset(asset) {
2167
+ if (asset !== "eth" && asset !== "usdc") {
2168
+ throw new Error('asset must be "eth" or "usdc"');
2169
+ }
2170
+ return asset;
2171
+ }
2172
+ function normalizeNonce(value) {
2173
+ const nonce = typeof value === "bigint" ? value : BigInt(value);
2174
+ if (nonce < 0n) {
2175
+ throw new Error("nonce must be non-negative");
2176
+ }
2177
+ return nonce;
2178
+ }
2179
+ function normalizeDeadline(deadline) {
2180
+ const nextDeadline = deadline === void 0 ? BigInt(Math.floor(Date.now() / 1e3)) + DEFAULT_WITHDRAW_DEADLINE_SECONDS : typeof deadline === "bigint" ? deadline : BigInt(deadline);
2181
+ if (nextDeadline <= 0n) {
2182
+ throw new Error("deadline must be greater than 0");
2183
+ }
2184
+ return nextDeadline;
2185
+ }
2186
+ function deriveSubaccountChildPrivateKey(rootPrivateKey, slot) {
2187
+ assertPrivateKey(rootPrivateKey, "rootPrivateKey");
2188
+ const normalizedSlot = normalizeSlot(slot);
2189
+ return keccak256(
2190
+ encodePacked(
2191
+ ["bytes32", "string", "uint256"],
2192
+ [rootPrivateKey, SUBACCOUNT_CHILD_DOMAIN, BigInt(normalizedSlot)]
2193
+ )
2194
+ );
2195
+ }
2196
+ function deriveSubaccountSalt(rootPrivateKey, slot) {
2197
+ assertPrivateKey(rootPrivateKey, "rootPrivateKey");
2198
+ const normalizedSlot = normalizeSlot(slot);
2199
+ return keccak256(
2200
+ encodePacked(
2201
+ ["bytes32", "string", "uint256"],
2202
+ [rootPrivateKey, SUBACCOUNT_SALT_DOMAIN, BigInt(normalizedSlot)]
2203
+ )
2204
+ );
2205
+ }
2206
+ function deriveSubaccountChildOwner(childPrivateKey) {
2207
+ assertPrivateKey(childPrivateKey, "childPrivateKey");
2208
+ return privateKeyToAddress(childPrivateKey);
2209
+ }
2210
+ function deriveSubaccountChildDepositKey(childPrivateKey) {
2211
+ assertPrivateKey(childPrivateKey, "childPrivateKey");
2212
+ return new Keypair(childPrivateKey).depositKey();
2213
+ }
2214
+ async function predictSubaccountForwarder(options) {
2215
+ const publicClient = createBaseClient(options.rpcUrl);
2216
+ return publicClient.readContract({
2217
+ abi: FORWARDER_FACTORY_ABI,
2218
+ address: getForwarderFactoryAddress(),
2219
+ functionName: "computeAddress",
2220
+ args: [options.salt, options.childDepositKey, options.childOwner]
2221
+ });
2222
+ }
2223
+ async function deriveSubaccountSlot(options) {
2224
+ const normalizedSlot = normalizeSlot(options.slot);
2225
+ const childPrivateKey = deriveSubaccountChildPrivateKey(options.rootPrivateKey, normalizedSlot);
2226
+ const salt = deriveSubaccountSalt(options.rootPrivateKey, normalizedSlot);
2227
+ const childOwner = deriveSubaccountChildOwner(childPrivateKey);
2228
+ const childDepositKey = deriveSubaccountChildDepositKey(childPrivateKey);
2229
+ const forwarderAddress = await predictSubaccountForwarder({
2230
+ salt,
2231
+ childDepositKey,
2232
+ childOwner,
2233
+ rpcUrl: options.rpcUrl
2234
+ });
2235
+ return {
2236
+ slot: normalizedSlot,
2237
+ childOwner,
2238
+ childDepositKey,
2239
+ salt,
2240
+ forwarderAddress
2241
+ };
2242
+ }
2243
+ async function isSubaccountForwarderDeployed(options) {
2244
+ if (!isAddress(options.forwarderAddress)) {
2245
+ throw new Error("forwarderAddress must be a valid Ethereum address");
2246
+ }
2247
+ const publicClient = createBaseClient(options.rpcUrl);
2248
+ const code = await publicClient.getCode({ address: options.forwarderAddress });
2249
+ return !!code && code !== "0x";
2250
+ }
2251
+ async function deploySubaccountForwarder(options) {
2252
+ const slot = await deriveSubaccountSlot({
2253
+ rootPrivateKey: options.rootPrivateKey,
2254
+ slot: options.slot,
2255
+ rpcUrl: options.rpcUrl
2256
+ });
2257
+ return postRelayJson(
2258
+ "/stealth/deploy",
2259
+ {
2260
+ salt: slot.salt,
2261
+ childDepositKey: slot.childDepositKey,
2262
+ childOwner: slot.childOwner,
2263
+ expectedForwarder: slot.forwarderAddress
2264
+ },
2265
+ options.relayUrl
2266
+ );
2267
+ }
2268
+ async function sweepSubaccountForwarder(options) {
2269
+ const asset = normalizeAsset(options.asset);
2270
+ if (!isAddress(options.forwarderAddress)) {
2271
+ throw new Error("forwarderAddress must be a valid Ethereum address");
2272
+ }
2273
+ return postRelayJson(
2274
+ "/stealth/sweep",
2275
+ {
2276
+ forwarder: options.forwarderAddress,
2277
+ asset
2278
+ },
2279
+ options.relayUrl
2280
+ );
2281
+ }
2282
+ function toQueueStatus(asset, result) {
2283
+ return {
2284
+ asset,
2285
+ queueBalance: result.queueBalance,
2286
+ queueBalanceWei: result.queueBalanceWei,
2287
+ pendingCount: result.pendingCount,
2288
+ pendingDeposits: result.pendingDeposits
2289
+ };
2290
+ }
2291
+ async function getSubaccountStatus(options) {
2292
+ const slot = await deriveSubaccountSlot(options);
2293
+ const publicClient = createBaseClient(options.rpcUrl);
2294
+ const addresses = getAddresses();
2295
+ const [deployed, ethWei, usdcWei, ethQueue, usdcQueue] = await Promise.all([
2296
+ isSubaccountForwarderDeployed({
2297
+ forwarderAddress: slot.forwarderAddress,
2298
+ rpcUrl: options.rpcUrl
2299
+ }),
2300
+ publicClient.getBalance({ address: slot.forwarderAddress }),
2301
+ publicClient.readContract({
2302
+ address: addresses.usdcToken,
2303
+ abi: ERC20_ABI,
2304
+ functionName: "balanceOf",
2305
+ args: [slot.forwarderAddress]
2306
+ }),
2307
+ getQueueBalance({
2308
+ address: slot.forwarderAddress,
2309
+ pool: "eth",
2310
+ rpcUrl: options.rpcUrl
2311
+ }),
2312
+ getQueueBalance({
2313
+ address: slot.forwarderAddress,
2314
+ pool: "usdc",
2315
+ rpcUrl: options.rpcUrl
2316
+ })
2317
+ ]);
2318
+ return {
2319
+ slot,
2320
+ deployed,
2321
+ balances: {
2322
+ eth: {
2323
+ balance: formatEther(ethWei),
2324
+ balanceWei: ethWei.toString()
2325
+ },
2326
+ usdc: {
2327
+ balance: formatUnits(usdcWei, 6),
2328
+ balanceWei: usdcWei.toString()
2329
+ }
2330
+ },
2331
+ queues: {
2332
+ eth: toQueueStatus("eth", ethQueue),
2333
+ usdc: toQueueStatus("usdc", usdcQueue)
2334
+ }
2335
+ };
2336
+ }
2337
+ var WITHDRAW_TYPES = {
2338
+ Withdraw: [
2339
+ { name: "token", type: "address" },
2340
+ { name: "to", type: "address" },
2341
+ { name: "amount", type: "uint256" },
2342
+ { name: "nonce", type: "uint256" },
2343
+ { name: "deadline", type: "uint256" }
2344
+ ]
2345
+ };
2346
+ function buildSubaccountWithdrawTypedData(options) {
2347
+ if (!isAddress(options.forwarderAddress)) {
2348
+ throw new Error("forwarderAddress must be a valid Ethereum address");
2349
+ }
2350
+ if (!isAddress(options.token)) {
2351
+ throw new Error("token must be a valid Ethereum address");
2352
+ }
2353
+ if (!isAddress(options.to)) {
2354
+ throw new Error("to must be a valid Ethereum address");
2355
+ }
2356
+ return {
2357
+ domain: {
2358
+ name: "VeilForwarder",
2359
+ version: FORWARDER_CONTRACT_VERSION,
2360
+ chainId: getAddresses().chainId,
2361
+ verifyingContract: options.forwarderAddress
2362
+ },
2363
+ types: WITHDRAW_TYPES,
2364
+ primaryType: "Withdraw",
2365
+ message: {
2366
+ token: options.token,
2367
+ to: options.to,
2368
+ amount: options.amount,
2369
+ nonce: options.nonce,
2370
+ deadline: options.deadline
2371
+ }
2372
+ };
2373
+ }
2374
+ async function signSubaccountWithdraw(options) {
2375
+ assertPrivateKey(options.childPrivateKey, "childPrivateKey");
2376
+ const account = privateKeyToAccount(options.childPrivateKey);
2377
+ return account.signTypedData({
2378
+ domain: options.typedData.domain,
2379
+ types: options.typedData.types,
2380
+ primaryType: options.typedData.primaryType,
2381
+ message: options.typedData.message
2382
+ });
2383
+ }
2384
+ async function isSubaccountWithdrawNonceUsed(options) {
2385
+ if (!isAddress(options.forwarderAddress)) {
2386
+ throw new Error("forwarderAddress must be a valid Ethereum address");
2387
+ }
2388
+ const publicClient = createBaseClient(options.rpcUrl);
2389
+ try {
2390
+ return await publicClient.readContract({
2391
+ abi: FORWARDER_ABI,
2392
+ address: options.forwarderAddress,
2393
+ functionName: "usedNonces",
2394
+ args: [normalizeNonce(options.nonce)]
2395
+ });
2396
+ } catch (error) {
2397
+ if (String(error).includes("returned no data")) {
2398
+ throw new Error("Subaccount forwarder is not deployed");
2399
+ }
2400
+ throw error;
2401
+ }
2402
+ }
2403
+ async function findNextSubaccountWithdrawNonce(options) {
2404
+ const startNonce = normalizeNonce(options.startNonce ?? 0n);
2405
+ const maxScan = normalizeNonce(options.maxScan ?? DEFAULT_MAX_NONCE_SCAN);
2406
+ const limit = startNonce + maxScan;
2407
+ let nonce = startNonce;
2408
+ while (await isSubaccountWithdrawNonceUsed({
2409
+ forwarderAddress: options.forwarderAddress,
2410
+ nonce,
2411
+ rpcUrl: options.rpcUrl
2412
+ })) {
2413
+ nonce += 1n;
2414
+ if (nonce > limit) {
2415
+ throw new Error("Unable to find an unused withdraw nonce within the scan limit");
2416
+ }
2417
+ }
2418
+ return nonce;
2419
+ }
2420
+ async function buildSubaccountRecoveryTx(options) {
2421
+ if (!isAddress(options.to)) {
2422
+ throw new Error("to must be a valid Ethereum address");
2423
+ }
2424
+ const asset = normalizeAsset(options.asset);
2425
+ const slot = await deriveSubaccountSlot({
2426
+ rootPrivateKey: options.rootPrivateKey,
2427
+ slot: options.slot,
2428
+ rpcUrl: options.rpcUrl
2429
+ });
2430
+ const deployed = await isSubaccountForwarderDeployed({
2431
+ forwarderAddress: slot.forwarderAddress,
2432
+ rpcUrl: options.rpcUrl
2433
+ });
2434
+ if (!deployed) {
2435
+ throw new Error("Subaccount forwarder is not deployed");
2436
+ }
2437
+ const childPrivateKey = deriveSubaccountChildPrivateKey(options.rootPrivateKey, options.slot);
2438
+ const tokenAddress = asset === "eth" ? ETH_ADDRESS : getAddresses().usdcToken;
2439
+ const amountWei = asset === "eth" ? parseEther(options.amount) : parseUnits(options.amount, 6);
2440
+ const nonce = options.nonce === void 0 ? await findNextSubaccountWithdrawNonce({
2441
+ forwarderAddress: slot.forwarderAddress,
2442
+ rpcUrl: options.rpcUrl
2443
+ }) : normalizeNonce(options.nonce);
2444
+ const deadline = normalizeDeadline(options.deadline);
2445
+ const typedData = buildSubaccountWithdrawTypedData({
2446
+ forwarderAddress: slot.forwarderAddress,
2447
+ token: tokenAddress,
2448
+ to: options.to,
2449
+ amount: amountWei,
2450
+ nonce,
2451
+ deadline
2452
+ });
2453
+ const signature = await signSubaccountWithdraw({
2454
+ childPrivateKey,
2455
+ typedData
2456
+ });
2457
+ return {
2458
+ transaction: {
2459
+ to: slot.forwarderAddress,
2460
+ data: encodeFunctionData({
2461
+ abi: FORWARDER_ABI,
2462
+ functionName: "withdraw",
2463
+ args: [tokenAddress, options.to, amountWei, nonce, deadline, signature]
2464
+ })
2465
+ },
2466
+ forwarderAddress: slot.forwarderAddress,
2467
+ asset,
2468
+ amount: options.amount,
2469
+ amountWei: amountWei.toString(),
2470
+ nonce: nonce.toString(),
2471
+ deadline: deadline.toString(),
2472
+ recipient: options.to,
2473
+ tokenAddress,
2474
+ signature
2475
+ };
2476
+ }
1963
2477
 
1964
- export { ADDRESSES, CIRCUIT_CONFIG, ENTRY_ABI, ERC20_ABI, FIELD_SIZE, Keypair, MERKLE_TREE_HEIGHT, POOL_ABI, POOL_CONFIG, QUEUE_ABI, RelayError, Utxo, VEIL_SIGNED_MESSAGE, buildApproveUSDCTx, buildChangeDepositKeyTx, buildDepositETHTx, buildDepositTx, buildDepositUSDCTx, buildMerkleTree, buildRegisterTx, buildTransferProof, buildWithdrawProof, checkRecipientRegistration, checkRelayHealth, getAddresses, getExtDataHash, getMerklePath, getPoolAddress, getPrivateBalance, getQueueAddress, getQueueBalance, getRelayInfo, getRelayUrl, mergeUtxos, packEncryptedMessage, poseidonHash, poseidonHash2, prepareTransaction, prove, randomBN, selectCircuit, selectUtxosForWithdraw, shuffle, submitRelay, toBuffer, toFixedHex, transfer, unpackEncryptedMessage, withdraw };
2478
+ export { ADDRESSES, CIRCUIT_CONFIG, ENTRY_ABI, ERC20_ABI, FIELD_SIZE, FORWARDER_ABI, FORWARDER_CONTRACT_VERSION, FORWARDER_FACTORY_ABI, Keypair, MAX_SUBACCOUNT_SLOTS, MERKLE_TREE_HEIGHT, POOL_ABI, POOL_CONFIG, QUEUE_ABI, RelayError, Utxo, VEIL_SIGNED_MESSAGE, buildApproveUSDCTx, buildChangeDepositKeyTx, buildDepositETHTx, buildDepositTx, buildDepositUSDCTx, buildMerkleTree, buildRegisterTx, buildSubaccountRecoveryTx, buildSubaccountWithdrawTypedData, buildTransferProof, buildWithdrawProof, checkRecipientRegistration, checkRelayHealth, deploySubaccountForwarder, deriveSubaccountChildDepositKey, deriveSubaccountChildOwner, deriveSubaccountChildPrivateKey, deriveSubaccountSalt, deriveSubaccountSlot, findNextSubaccountWithdrawNonce, getAddresses, getExtDataHash, getForwarderFactoryAddress, getMerklePath, getPoolAddress, getPrivateBalance, getQueueAddress, getQueueBalance, getRelayInfo, getRelayUrl, getSubaccountStatus, isSubaccountForwarderDeployed, isSubaccountWithdrawNonceUsed, mergeUtxos, packEncryptedMessage, poseidonHash, poseidonHash2, predictSubaccountForwarder, prepareTransaction, prove, randomBN, selectCircuit, selectUtxosForWithdraw, shuffle, signSubaccountWithdraw, submitRelay, sweepSubaccountForwarder, toBuffer, toFixedHex, transfer, unpackEncryptedMessage, withdraw };
1965
2479
  //# sourceMappingURL=index.js.map
1966
2480
  //# sourceMappingURL=index.js.map