@kohaku-eth/tornado-cash 0.0.2-alpha.16 → 0.0.2-alpha.17

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.
@@ -22194,6 +22194,15 @@ var withdrawThunk = createAsyncThunk("withdraw/executeWithdrawals", async ({
22194
22194
  return getWithdrawalsProofs();
22195
22195
  });
22196
22196
 
22197
+ // ../provider/dist/index.js
22198
+ var createTx = (address, payload, value = BigInt(0)) => {
22199
+ return {
22200
+ to: address,
22201
+ data: payload,
22202
+ value
22203
+ };
22204
+ };
22205
+
22197
22206
  // ../../node_modules/.pnpm/viem@2.48.4_typescript@5.9.3_zod@4.4.3/node_modules/viem/_esm/index.js
22198
22207
  init_exports();
22199
22208
  init_encodeAbiParameters2();
@@ -22368,8 +22377,14 @@ function privateKeyToAccount(privateKey, options = {}) {
22368
22377
  };
22369
22378
  }
22370
22379
 
22380
+ // src/state/thunks/paymasterWithdrawThunk.ts
22381
+ init_esm();
22382
+
22371
22383
  // src/paymaster/fee.ts
22372
22384
  var ERC20_TRANSFER_GAS = 100000n;
22385
+ var PER_DIRECT_WITHDRAW_GAS = 400000n;
22386
+ var PER_DIRECT_WITHDRAW_GAS_ERC20 = 500000n;
22387
+ var FORWARD_GAS = 60000n;
22373
22388
  var baseGasUnits = {
22374
22389
  preVerificationGas: 80000n,
22375
22390
  verificationGasLimit: 50000n,
@@ -22384,6 +22399,15 @@ function reasonableGasUnits(isERC20) {
22384
22399
  paymasterVerificationGasLimit: baseGasUnits.paymasterVerificationGasLimit + ERC20_TRANSFER_GAS
22385
22400
  };
22386
22401
  }
22402
+ function reasonableGasUnitsForBatch(isERC20, extraWithdrawals, hasUserTailCalls) {
22403
+ const base = reasonableGasUnits(isERC20);
22404
+ const perWithdraw = isERC20 ? PER_DIRECT_WITHDRAW_GAS_ERC20 : PER_DIRECT_WITHDRAW_GAS;
22405
+ const executionTail = hasUserTailCalls ? base.callGasLimit : FORWARD_GAS;
22406
+ return {
22407
+ ...base,
22408
+ callGasLimit: BigInt(extraWithdrawals) * perWithdraw + executionTail
22409
+ };
22410
+ }
22387
22411
  function computeMinimumViableFee(reasonableGasUnits2, maxFeePerGas) {
22388
22412
  const baseFeeMultiplier = 1.2;
22389
22413
  const decimals = baseFeeMultiplier.toString().split(".")[1]?.length ?? 0;
@@ -22391,10 +22415,6 @@ function computeMinimumViableFee(reasonableGasUnits2, maxFeePerGas) {
22391
22415
  const multiply = (base) => base * BigInt(Math.ceil(baseFeeMultiplier * denominator)) / BigInt(denominator);
22392
22416
  const requiredGas = reasonableGasUnits2.verificationGasLimit + reasonableGasUnits2.callGasLimit + reasonableGasUnits2.paymasterVerificationGasLimit + reasonableGasUnits2.preVerificationGas + reasonableGasUnits2.paymasterPostOpGasLimit;
22393
22417
  const requiredPrefund = requiredGas * maxFeePerGas;
22394
- console.log("totalGasUnits", requiredGas);
22395
- console.log("maxFeePerGas", maxFeePerGas);
22396
- console.log("requiredPrefund", requiredPrefund);
22397
- console.log("multiply", 1.2);
22398
22418
  return multiply(requiredPrefund);
22399
22419
  }
22400
22420
 
@@ -24091,6 +24111,19 @@ async function getUserOperationGasPrice(client) {
24091
24111
  fast: parse(result.fast)
24092
24112
  };
24093
24113
  }
24114
+ async function estimateUserOperationGas2(client, op, entryPoint) {
24115
+ const result = await client.request({
24116
+ method: "eth_estimateUserOperationGas",
24117
+ params: [op, entryPoint]
24118
+ });
24119
+ return {
24120
+ callGasLimit: BigInt(result.callGasLimit),
24121
+ verificationGasLimit: BigInt(result.verificationGasLimit),
24122
+ preVerificationGas: BigInt(result.preVerificationGas),
24123
+ paymasterVerificationGasLimit: BigInt(result.paymasterVerificationGasLimit ?? 0),
24124
+ paymasterPostOpGasLimit: BigInt(result.paymasterPostOpGasLimit ?? 0)
24125
+ };
24126
+ }
24094
24127
  async function buildSignedTornadoUserOp({
24095
24128
  signer,
24096
24129
  chainId,
@@ -24221,12 +24254,32 @@ var paymasterWithdrawThunk = createAsyncThunk("withdraw/executePaymasterWithdraw
24221
24254
  );
24222
24255
  const bundlerClient = createPaymasterBundlerClient(bundlerUrl);
24223
24256
  const { standard: { maxFeePerGas, maxPriorityFeePerGas } } = await getUserOperationGasPrice(bundlerClient);
24224
- const gasUnits = reasonableGasUnits(poolInfo.isERC20);
24225
- const ethFee = computeMinimumViableFee(gasUnits, maxFeePerGas);
24226
- const fee = poolInfo.isERC20 ? await dataService.quoteWeiInToken(BigInt(paymasterAddress), poolInfo.asset, ethFee) : ethFee;
24227
24257
  const relayerAddress = BigInt(paymasterAddress);
24228
24258
  const bigintChainId = await dataService.getChainId();
24229
24259
  const { recipient: originalRecipient, ...restWithoutRecipient } = rest;
24260
+ const quoteFee = async (ethFee) => poolInfo.isERC20 ? dataService.quoteWeiInToken(BigInt(paymasterAddress), poolInfo.asset, ethFee) : ethFee;
24261
+ const prove = async (deposit, recipient, relayer, depositFee) => unwrapResult(await dispatch(withdrawalsProofThunk({
24262
+ ...restWithoutRecipient,
24263
+ recipient,
24264
+ deposit,
24265
+ relayerAddress: relayer,
24266
+ fee: depositFee
24267
+ })));
24268
+ const buildPaymasterData = (poolAddress, proof) => {
24269
+ const [root, nullifierHash, proofRecipient, relayerArg, feeArg, refundArg] = proof.args;
24270
+ return encodePaymasterData(
24271
+ poolAcountsMap.get(poolAddress),
24272
+ encodeTornadoAdapterData(
24273
+ proof.proof,
24274
+ root,
24275
+ nullifierHash,
24276
+ proofRecipient,
24277
+ relayerArg,
24278
+ BigInt(feeArg),
24279
+ BigInt(refundArg)
24280
+ )
24281
+ );
24282
+ };
24230
24283
  const ephemeralSigner = async (deposit) => privateKeyToAccount(await secretManager.deriveEphemeralSigner({
24231
24284
  depositIndex: deposit.index,
24232
24285
  chainId: bigintChainId,
@@ -24241,78 +24294,115 @@ var paymasterWithdrawThunk = createAsyncThunk("withdraw/executePaymasterWithdraw
24241
24294
  return ephemeralSigner(deposits[0]);
24242
24295
  };
24243
24296
  const resolveIndependentSigner = (deposit) => delegation?.mode === "deterministic" ? ephemeralSigner(deposit) : Promise.resolve(privateKeyToAccount(generatePrivateKey()));
24244
- const sharedDelegator = tailCalls ? await resolveBatchDelegator() : null;
24245
- const proofOutputs = [];
24246
- const userOperations = [];
24247
- for (let i = 0; i < deposits.length; i++) {
24248
- const deposit = deposits[i];
24249
- const isLast = i === deposits.length - 1;
24250
- const signer = sharedDelegator ?? await resolveIndependentSigner(deposit);
24251
- const recipient = sharedDelegator ? BigInt(signer.address) : originalRecipient;
24252
- const effectiveTailCalls = isLast ? tailCalls : void 0;
24253
- const gas = { ...gasUnits, callGasLimit: effectiveTailCalls ? gasUnits.callGasLimit : 0n };
24254
- const withdrawResultAction = await dispatch(
24255
- withdrawalsProofThunk({
24256
- ...restWithoutRecipient,
24257
- recipient,
24258
- deposit,
24259
- relayerAddress,
24260
- fee
24261
- })
24262
- );
24263
- const proof = { ...unwrapResult(withdrawResultAction), poolAddress: deposit.pool };
24264
- proofOutputs.push(proof);
24265
- const { poolAddress, ...proofArgs } = proof;
24266
- const [root, nullifierHash, proofRecipient, relayerArg, feeArg, refundArg] = proofArgs.args;
24267
- const paymasterData = encodePaymasterData(
24268
- poolAcountsMap.get(poolAddress),
24269
- encodeTornadoAdapterData(
24270
- proofArgs.proof,
24271
- root,
24272
- nullifierHash,
24273
- proofRecipient,
24274
- relayerArg,
24275
- BigInt(feeArg),
24276
- BigInt(refundArg)
24277
- )
24278
- );
24279
- userOperations.push(
24280
- await buildSignedTornadoUserOp({
24281
- signer,
24282
- chainId,
24283
- paymasterAddress,
24284
- paymasterData,
24285
- gas,
24286
- maxFeePerGas,
24287
- maxPriorityFeePerGas,
24288
- tailCalls: effectiveTailCalls,
24289
- // When sharing one delegator across multiple deposits each userOp needs
24290
- // a distinct nonce (0, 1, 2 …) on the shared sender.
24291
- nonce: sharedDelegator ? BigInt(i) : 0n
24292
- })
24293
- );
24297
+ const needsConsolidation = deposits.length > 1 || tailCalls != null;
24298
+ if (!needsConsolidation) {
24299
+ const deposit = deposits[0];
24300
+ const signer2 = await resolveIndependentSigner(deposit);
24301
+ const gasUnits = reasonableGasUnits(poolInfo.isERC20);
24302
+ const fee2 = await quoteFee(computeMinimumViableFee(gasUnits, maxFeePerGas));
24303
+ const proof = await prove(deposit, originalRecipient, relayerAddress, fee2);
24304
+ const userOperation2 = await buildSignedTornadoUserOp({
24305
+ signer: signer2,
24306
+ chainId,
24307
+ paymasterAddress,
24308
+ paymasterData: buildPaymasterData(deposit.pool, proof),
24309
+ gas: { ...gasUnits, callGasLimit: 0n },
24310
+ maxFeePerGas,
24311
+ maxPriorityFeePerGas,
24312
+ nonce: 0n
24313
+ });
24314
+ return [{
24315
+ mode: "paymaster",
24316
+ proof,
24317
+ poolAddress: deposit.pool,
24318
+ isERC20: poolInfo.isERC20,
24319
+ paymasterAddress,
24320
+ entryPointAddress,
24321
+ bundlerUrl,
24322
+ userOperation: userOperation2
24323
+ }];
24324
+ }
24325
+ const signer = await resolveBatchDelegator();
24326
+ const senderAddress = BigInt(signer.address);
24327
+ const sponsoringDeposit = deposits[0];
24328
+ const directDeposits = deposits.slice(1);
24329
+ const ZERO_ADDRESS = 0n;
24330
+ const directWithdrawCalls = [];
24331
+ for (const deposit of directDeposits) {
24332
+ const proof = await prove(deposit, senderAddress, ZERO_ADDRESS, 0n);
24333
+ const [root, nullifierHash, proofRecipient, relayerArg, feeArg, refundArg] = proof.args;
24334
+ const data = encodeFunctionData({
24335
+ abi: poolAbi,
24336
+ functionName: "withdraw",
24337
+ args: [proof.proof, root, nullifierHash, proofRecipient, relayerArg, BigInt(feeArg), BigInt(refundArg)]
24338
+ });
24339
+ directWithdrawCalls.push(createTx(addressToHex(deposit.pool), data, 0n));
24340
+ }
24341
+ const totalDenomination = deposits.reduce(
24342
+ (sum, d) => sum + pools.get(d.pool).denomination,
24343
+ 0n
24344
+ );
24345
+ const forwardCalls = (fee2) => {
24346
+ const amount2 = totalDenomination - fee2;
24347
+ if (poolInfo.isERC20) {
24348
+ const data = encodeFunctionData({
24349
+ abi: erc20Abi,
24350
+ functionName: "transfer",
24351
+ args: [addressToHex(originalRecipient), amount2]
24352
+ });
24353
+ return [createTx(addressToHex(poolInfo.asset), data, 0n)];
24354
+ }
24355
+ return [createTx(addressToHex(originalRecipient), "0x", amount2)];
24356
+ };
24357
+ const composeTailCalls = (fee2) => async (addr) => [
24358
+ ...directWithdrawCalls,
24359
+ ...tailCalls ? await tailCalls(addr) : forwardCalls(fee2)
24360
+ ];
24361
+ const buildOp = (gas2, fee2, paymasterData) => buildSignedTornadoUserOp({
24362
+ signer,
24363
+ chainId,
24364
+ paymasterAddress,
24365
+ paymasterData,
24366
+ gas: gas2,
24367
+ maxFeePerGas,
24368
+ maxPriorityFeePerGas,
24369
+ tailCalls: composeTailCalls(fee2),
24370
+ nonce: 0n
24371
+ });
24372
+ const baselineGas = reasonableGasUnitsForBatch(poolInfo.isERC20, directDeposits.length, tailCalls != null);
24373
+ let fee = await quoteFee(computeMinimumViableFee(baselineGas, maxFeePerGas));
24374
+ let gas = baselineGas;
24375
+ let sponsoringProof = await prove(sponsoringDeposit, senderAddress, relayerAddress, fee);
24376
+ let userOperation = await buildOp(gas, fee, buildPaymasterData(sponsoringDeposit.pool, sponsoringProof));
24377
+ try {
24378
+ const estimated = await estimateUserOperationGas2(bundlerClient, userOperation, entryPointAddress);
24379
+ const buffer2 = (x) => x * 12n / 10n;
24380
+ const orBaseline = (e, b) => e > 0n ? buffer2(e) : b;
24381
+ const refinedGas = {
24382
+ callGasLimit: orBaseline(estimated.callGasLimit, baselineGas.callGasLimit),
24383
+ verificationGasLimit: orBaseline(estimated.verificationGasLimit, baselineGas.verificationGasLimit),
24384
+ preVerificationGas: orBaseline(estimated.preVerificationGas, baselineGas.preVerificationGas),
24385
+ paymasterVerificationGasLimit: orBaseline(estimated.paymasterVerificationGasLimit, baselineGas.paymasterVerificationGasLimit),
24386
+ paymasterPostOpGasLimit: orBaseline(estimated.paymasterPostOpGasLimit, baselineGas.paymasterPostOpGasLimit)
24387
+ };
24388
+ fee = await quoteFee(computeMinimumViableFee(refinedGas, maxFeePerGas));
24389
+ gas = refinedGas;
24390
+ sponsoringProof = await prove(sponsoringDeposit, senderAddress, relayerAddress, fee);
24391
+ userOperation = await buildOp(gas, fee, buildPaymasterData(sponsoringDeposit.pool, sponsoringProof));
24392
+ } catch {
24294
24393
  }
24295
- return proofOutputs.map(({ poolAddress, ...proof }, i) => ({
24394
+ return [{
24296
24395
  mode: "paymaster",
24297
- proof,
24298
- poolAddress,
24396
+ proof: sponsoringProof,
24397
+ poolAddress: sponsoringDeposit.pool,
24299
24398
  isERC20: poolInfo.isERC20,
24300
24399
  paymasterAddress,
24301
24400
  entryPointAddress,
24302
24401
  bundlerUrl,
24303
- userOperation: userOperations[i]
24304
- }));
24402
+ userOperation
24403
+ }];
24305
24404
  });
24306
24405
 
24307
- // ../provider/dist/index.js
24308
- var createTx = (address, payload, value = BigInt(0)) => {
24309
- return {
24310
- to: address,
24311
- data: payload,
24312
- value
24313
- };
24314
- };
24315
-
24316
24406
  // src/account/tx/shield.ts
24317
24407
  init_esm();
24318
24408
  init_esm();
@@ -21420,6 +21420,15 @@ var withdrawThunk = createAsyncThunk("withdraw/executeWithdrawals", async ({
21420
21420
  return getWithdrawalsProofs();
21421
21421
  });
21422
21422
 
21423
+ // ../provider/dist/index.js
21424
+ var createTx = (address, payload, value = BigInt(0)) => {
21425
+ return {
21426
+ to: address,
21427
+ data: payload,
21428
+ value
21429
+ };
21430
+ };
21431
+
21423
21432
  // ../../node_modules/.pnpm/viem@2.48.4_typescript@5.9.3_zod@4.4.3/node_modules/viem/_esm/index.js
21424
21433
  init_exports();
21425
21434
  init_encodeAbiParameters2();
@@ -21594,8 +21603,14 @@ function privateKeyToAccount(privateKey, options = {}) {
21594
21603
  };
21595
21604
  }
21596
21605
 
21606
+ // src/state/thunks/paymasterWithdrawThunk.ts
21607
+ init_esm();
21608
+
21597
21609
  // src/paymaster/fee.ts
21598
21610
  var ERC20_TRANSFER_GAS = 100000n;
21611
+ var PER_DIRECT_WITHDRAW_GAS = 400000n;
21612
+ var PER_DIRECT_WITHDRAW_GAS_ERC20 = 500000n;
21613
+ var FORWARD_GAS = 60000n;
21599
21614
  var baseGasUnits = {
21600
21615
  preVerificationGas: 80000n,
21601
21616
  verificationGasLimit: 50000n,
@@ -21610,6 +21625,15 @@ function reasonableGasUnits(isERC20) {
21610
21625
  paymasterVerificationGasLimit: baseGasUnits.paymasterVerificationGasLimit + ERC20_TRANSFER_GAS
21611
21626
  };
21612
21627
  }
21628
+ function reasonableGasUnitsForBatch(isERC20, extraWithdrawals, hasUserTailCalls) {
21629
+ const base = reasonableGasUnits(isERC20);
21630
+ const perWithdraw = isERC20 ? PER_DIRECT_WITHDRAW_GAS_ERC20 : PER_DIRECT_WITHDRAW_GAS;
21631
+ const executionTail = hasUserTailCalls ? base.callGasLimit : FORWARD_GAS;
21632
+ return {
21633
+ ...base,
21634
+ callGasLimit: BigInt(extraWithdrawals) * perWithdraw + executionTail
21635
+ };
21636
+ }
21613
21637
  function computeMinimumViableFee(reasonableGasUnits2, maxFeePerGas) {
21614
21638
  const baseFeeMultiplier = 1.2;
21615
21639
  const decimals = baseFeeMultiplier.toString().split(".")[1]?.length ?? 0;
@@ -21617,10 +21641,6 @@ function computeMinimumViableFee(reasonableGasUnits2, maxFeePerGas) {
21617
21641
  const multiply = (base) => base * BigInt(Math.ceil(baseFeeMultiplier * denominator)) / BigInt(denominator);
21618
21642
  const requiredGas = reasonableGasUnits2.verificationGasLimit + reasonableGasUnits2.callGasLimit + reasonableGasUnits2.paymasterVerificationGasLimit + reasonableGasUnits2.preVerificationGas + reasonableGasUnits2.paymasterPostOpGasLimit;
21619
21643
  const requiredPrefund = requiredGas * maxFeePerGas;
21620
- console.log("totalGasUnits", requiredGas);
21621
- console.log("maxFeePerGas", maxFeePerGas);
21622
- console.log("requiredPrefund", requiredPrefund);
21623
- console.log("multiply", 1.2);
21624
21644
  return multiply(requiredPrefund);
21625
21645
  }
21626
21646
 
@@ -23317,6 +23337,19 @@ async function getUserOperationGasPrice(client) {
23317
23337
  fast: parse(result.fast)
23318
23338
  };
23319
23339
  }
23340
+ async function estimateUserOperationGas2(client, op, entryPoint) {
23341
+ const result = await client.request({
23342
+ method: "eth_estimateUserOperationGas",
23343
+ params: [op, entryPoint]
23344
+ });
23345
+ return {
23346
+ callGasLimit: BigInt(result.callGasLimit),
23347
+ verificationGasLimit: BigInt(result.verificationGasLimit),
23348
+ preVerificationGas: BigInt(result.preVerificationGas),
23349
+ paymasterVerificationGasLimit: BigInt(result.paymasterVerificationGasLimit ?? 0),
23350
+ paymasterPostOpGasLimit: BigInt(result.paymasterPostOpGasLimit ?? 0)
23351
+ };
23352
+ }
23320
23353
  async function buildSignedTornadoUserOp({
23321
23354
  signer,
23322
23355
  chainId,
@@ -23447,12 +23480,32 @@ var paymasterWithdrawThunk = createAsyncThunk("withdraw/executePaymasterWithdraw
23447
23480
  );
23448
23481
  const bundlerClient = createPaymasterBundlerClient(bundlerUrl);
23449
23482
  const { standard: { maxFeePerGas, maxPriorityFeePerGas } } = await getUserOperationGasPrice(bundlerClient);
23450
- const gasUnits = reasonableGasUnits(poolInfo.isERC20);
23451
- const ethFee = computeMinimumViableFee(gasUnits, maxFeePerGas);
23452
- const fee = poolInfo.isERC20 ? await dataService.quoteWeiInToken(BigInt(paymasterAddress), poolInfo.asset, ethFee) : ethFee;
23453
23483
  const relayerAddress = BigInt(paymasterAddress);
23454
23484
  const bigintChainId = await dataService.getChainId();
23455
23485
  const { recipient: originalRecipient, ...restWithoutRecipient } = rest;
23486
+ const quoteFee = async (ethFee) => poolInfo.isERC20 ? dataService.quoteWeiInToken(BigInt(paymasterAddress), poolInfo.asset, ethFee) : ethFee;
23487
+ const prove = async (deposit, recipient, relayer, depositFee) => unwrapResult(await dispatch(withdrawalsProofThunk({
23488
+ ...restWithoutRecipient,
23489
+ recipient,
23490
+ deposit,
23491
+ relayerAddress: relayer,
23492
+ fee: depositFee
23493
+ })));
23494
+ const buildPaymasterData = (poolAddress, proof) => {
23495
+ const [root, nullifierHash, proofRecipient, relayerArg, feeArg, refundArg] = proof.args;
23496
+ return encodePaymasterData(
23497
+ poolAcountsMap.get(poolAddress),
23498
+ encodeTornadoAdapterData(
23499
+ proof.proof,
23500
+ root,
23501
+ nullifierHash,
23502
+ proofRecipient,
23503
+ relayerArg,
23504
+ BigInt(feeArg),
23505
+ BigInt(refundArg)
23506
+ )
23507
+ );
23508
+ };
23456
23509
  const ephemeralSigner = async (deposit) => privateKeyToAccount(await secretManager.deriveEphemeralSigner({
23457
23510
  depositIndex: deposit.index,
23458
23511
  chainId: bigintChainId,
@@ -23467,78 +23520,115 @@ var paymasterWithdrawThunk = createAsyncThunk("withdraw/executePaymasterWithdraw
23467
23520
  return ephemeralSigner(deposits[0]);
23468
23521
  };
23469
23522
  const resolveIndependentSigner = (deposit) => delegation?.mode === "deterministic" ? ephemeralSigner(deposit) : Promise.resolve(privateKeyToAccount(generatePrivateKey()));
23470
- const sharedDelegator = tailCalls ? await resolveBatchDelegator() : null;
23471
- const proofOutputs = [];
23472
- const userOperations = [];
23473
- for (let i = 0; i < deposits.length; i++) {
23474
- const deposit = deposits[i];
23475
- const isLast = i === deposits.length - 1;
23476
- const signer = sharedDelegator ?? await resolveIndependentSigner(deposit);
23477
- const recipient = sharedDelegator ? BigInt(signer.address) : originalRecipient;
23478
- const effectiveTailCalls = isLast ? tailCalls : void 0;
23479
- const gas = { ...gasUnits, callGasLimit: effectiveTailCalls ? gasUnits.callGasLimit : 0n };
23480
- const withdrawResultAction = await dispatch(
23481
- withdrawalsProofThunk({
23482
- ...restWithoutRecipient,
23483
- recipient,
23484
- deposit,
23485
- relayerAddress,
23486
- fee
23487
- })
23488
- );
23489
- const proof = { ...unwrapResult(withdrawResultAction), poolAddress: deposit.pool };
23490
- proofOutputs.push(proof);
23491
- const { poolAddress, ...proofArgs } = proof;
23492
- const [root, nullifierHash, proofRecipient, relayerArg, feeArg, refundArg] = proofArgs.args;
23493
- const paymasterData = encodePaymasterData(
23494
- poolAcountsMap.get(poolAddress),
23495
- encodeTornadoAdapterData(
23496
- proofArgs.proof,
23497
- root,
23498
- nullifierHash,
23499
- proofRecipient,
23500
- relayerArg,
23501
- BigInt(feeArg),
23502
- BigInt(refundArg)
23503
- )
23504
- );
23505
- userOperations.push(
23506
- await buildSignedTornadoUserOp({
23507
- signer,
23508
- chainId,
23509
- paymasterAddress,
23510
- paymasterData,
23511
- gas,
23512
- maxFeePerGas,
23513
- maxPriorityFeePerGas,
23514
- tailCalls: effectiveTailCalls,
23515
- // When sharing one delegator across multiple deposits each userOp needs
23516
- // a distinct nonce (0, 1, 2 …) on the shared sender.
23517
- nonce: sharedDelegator ? BigInt(i) : 0n
23518
- })
23519
- );
23523
+ const needsConsolidation = deposits.length > 1 || tailCalls != null;
23524
+ if (!needsConsolidation) {
23525
+ const deposit = deposits[0];
23526
+ const signer2 = await resolveIndependentSigner(deposit);
23527
+ const gasUnits = reasonableGasUnits(poolInfo.isERC20);
23528
+ const fee2 = await quoteFee(computeMinimumViableFee(gasUnits, maxFeePerGas));
23529
+ const proof = await prove(deposit, originalRecipient, relayerAddress, fee2);
23530
+ const userOperation2 = await buildSignedTornadoUserOp({
23531
+ signer: signer2,
23532
+ chainId,
23533
+ paymasterAddress,
23534
+ paymasterData: buildPaymasterData(deposit.pool, proof),
23535
+ gas: { ...gasUnits, callGasLimit: 0n },
23536
+ maxFeePerGas,
23537
+ maxPriorityFeePerGas,
23538
+ nonce: 0n
23539
+ });
23540
+ return [{
23541
+ mode: "paymaster",
23542
+ proof,
23543
+ poolAddress: deposit.pool,
23544
+ isERC20: poolInfo.isERC20,
23545
+ paymasterAddress,
23546
+ entryPointAddress,
23547
+ bundlerUrl,
23548
+ userOperation: userOperation2
23549
+ }];
23550
+ }
23551
+ const signer = await resolveBatchDelegator();
23552
+ const senderAddress = BigInt(signer.address);
23553
+ const sponsoringDeposit = deposits[0];
23554
+ const directDeposits = deposits.slice(1);
23555
+ const ZERO_ADDRESS = 0n;
23556
+ const directWithdrawCalls = [];
23557
+ for (const deposit of directDeposits) {
23558
+ const proof = await prove(deposit, senderAddress, ZERO_ADDRESS, 0n);
23559
+ const [root, nullifierHash, proofRecipient, relayerArg, feeArg, refundArg] = proof.args;
23560
+ const data = encodeFunctionData({
23561
+ abi: poolAbi,
23562
+ functionName: "withdraw",
23563
+ args: [proof.proof, root, nullifierHash, proofRecipient, relayerArg, BigInt(feeArg), BigInt(refundArg)]
23564
+ });
23565
+ directWithdrawCalls.push(createTx(addressToHex(deposit.pool), data, 0n));
23566
+ }
23567
+ const totalDenomination = deposits.reduce(
23568
+ (sum, d) => sum + pools.get(d.pool).denomination,
23569
+ 0n
23570
+ );
23571
+ const forwardCalls = (fee2) => {
23572
+ const amount2 = totalDenomination - fee2;
23573
+ if (poolInfo.isERC20) {
23574
+ const data = encodeFunctionData({
23575
+ abi: erc20Abi,
23576
+ functionName: "transfer",
23577
+ args: [addressToHex(originalRecipient), amount2]
23578
+ });
23579
+ return [createTx(addressToHex(poolInfo.asset), data, 0n)];
23580
+ }
23581
+ return [createTx(addressToHex(originalRecipient), "0x", amount2)];
23582
+ };
23583
+ const composeTailCalls = (fee2) => async (addr) => [
23584
+ ...directWithdrawCalls,
23585
+ ...tailCalls ? await tailCalls(addr) : forwardCalls(fee2)
23586
+ ];
23587
+ const buildOp = (gas2, fee2, paymasterData) => buildSignedTornadoUserOp({
23588
+ signer,
23589
+ chainId,
23590
+ paymasterAddress,
23591
+ paymasterData,
23592
+ gas: gas2,
23593
+ maxFeePerGas,
23594
+ maxPriorityFeePerGas,
23595
+ tailCalls: composeTailCalls(fee2),
23596
+ nonce: 0n
23597
+ });
23598
+ const baselineGas = reasonableGasUnitsForBatch(poolInfo.isERC20, directDeposits.length, tailCalls != null);
23599
+ let fee = await quoteFee(computeMinimumViableFee(baselineGas, maxFeePerGas));
23600
+ let gas = baselineGas;
23601
+ let sponsoringProof = await prove(sponsoringDeposit, senderAddress, relayerAddress, fee);
23602
+ let userOperation = await buildOp(gas, fee, buildPaymasterData(sponsoringDeposit.pool, sponsoringProof));
23603
+ try {
23604
+ const estimated = await estimateUserOperationGas2(bundlerClient, userOperation, entryPointAddress);
23605
+ const buffer2 = (x) => x * 12n / 10n;
23606
+ const orBaseline = (e, b) => e > 0n ? buffer2(e) : b;
23607
+ const refinedGas = {
23608
+ callGasLimit: orBaseline(estimated.callGasLimit, baselineGas.callGasLimit),
23609
+ verificationGasLimit: orBaseline(estimated.verificationGasLimit, baselineGas.verificationGasLimit),
23610
+ preVerificationGas: orBaseline(estimated.preVerificationGas, baselineGas.preVerificationGas),
23611
+ paymasterVerificationGasLimit: orBaseline(estimated.paymasterVerificationGasLimit, baselineGas.paymasterVerificationGasLimit),
23612
+ paymasterPostOpGasLimit: orBaseline(estimated.paymasterPostOpGasLimit, baselineGas.paymasterPostOpGasLimit)
23613
+ };
23614
+ fee = await quoteFee(computeMinimumViableFee(refinedGas, maxFeePerGas));
23615
+ gas = refinedGas;
23616
+ sponsoringProof = await prove(sponsoringDeposit, senderAddress, relayerAddress, fee);
23617
+ userOperation = await buildOp(gas, fee, buildPaymasterData(sponsoringDeposit.pool, sponsoringProof));
23618
+ } catch {
23520
23619
  }
23521
- return proofOutputs.map(({ poolAddress, ...proof }, i) => ({
23620
+ return [{
23522
23621
  mode: "paymaster",
23523
- proof,
23524
- poolAddress,
23622
+ proof: sponsoringProof,
23623
+ poolAddress: sponsoringDeposit.pool,
23525
23624
  isERC20: poolInfo.isERC20,
23526
23625
  paymasterAddress,
23527
23626
  entryPointAddress,
23528
23627
  bundlerUrl,
23529
- userOperation: userOperations[i]
23530
- }));
23628
+ userOperation
23629
+ }];
23531
23630
  });
23532
23631
 
23533
- // ../provider/dist/index.js
23534
- var createTx = (address, payload, value = BigInt(0)) => {
23535
- return {
23536
- to: address,
23537
- data: payload,
23538
- value
23539
- };
23540
- };
23541
-
23542
23632
  // src/account/tx/shield.ts
23543
23633
  init_esm();
23544
23634
  init_esm();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kohaku-eth/tornado-cash",
3
- "version": "0.0.2-alpha.16",
3
+ "version": "0.0.2-alpha.17",
4
4
  "description": "Tornado Cash Shielded Pool Kohaku Plugin",
5
5
  "type": "module",
6
6
  "private": false,