@kohaku-eth/tornado-cash 0.0.2-alpha.11 → 0.0.2-alpha.13
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.d.ts +161 -65
- package/dist/index.js +87 -116
- package/dist/merkle-tree-worker.browser.js +3570 -0
- package/dist/merkle-tree-worker.node.js +3595 -0
- package/dist/merkle-tree.browser.js +13 -0
- package/dist/merkle-tree.node.js +13 -0
- package/dist/msm-worker.browser.js +1 -1
- package/dist/msm-worker.js +1 -1
- package/dist/state-manager.worker.js +20889 -26307
- package/dist/{state-manager.worker.node.cjs → state-manager.worker.node.js} +19900 -23948
- package/dist/worker-loader.browser.d.ts +86 -26
- package/dist/worker-loader.node.d.ts +86 -26
- package/dist/worker-loader.node.js +1 -6
- package/package.json +10 -11
package/dist/index.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { createSelector, createAsyncThunk } from '@reduxjs/toolkit';
|
|
2
2
|
import { createTx } from '@kohaku-eth/provider';
|
|
3
|
-
import { encodeFunctionData, toHex, erc20Abi } from 'viem';
|
|
3
|
+
import { encodeFunctionData, toHex, erc20Abi, http } from 'viem';
|
|
4
4
|
import { proxy } from 'comlink';
|
|
5
5
|
import { loadStateManagerWorker } from '#worker-loader';
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
6
|
+
import 'viem/accounts';
|
|
7
|
+
import { createBundlerClient } from 'viem/account-abstraction';
|
|
8
8
|
import { numberToBytesLE, bytesToNumberLE, concatBytes } from '@noble/curves/utils.js';
|
|
9
9
|
import { keccak_256 } from '@noble/hashes/sha3.js';
|
|
10
10
|
import { pedersenHash as pedersenHash$1, Point } from 'micro-zk-proofs/pedersen.js';
|
|
11
|
-
import 'micro-zk-proofs/mimcsponge.js';
|
|
12
|
-
import 'fixed-merkle-tree';
|
|
13
11
|
|
|
14
12
|
// src/state/thunks/getDepositPayloadThunk.ts
|
|
15
13
|
|
|
@@ -350,11 +348,12 @@ var TornadoPaymasterConfigs = {
|
|
|
350
348
|
11155111: {
|
|
351
349
|
bundlerUrl: "https://public.pimlico.io/v2/11155111/rpc",
|
|
352
350
|
entryPointAddress: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
|
|
353
|
-
paymasterAddress: "
|
|
351
|
+
paymasterAddress: "0x1c5aCCb9c09D72945b79EC986776136bE01d7B2F",
|
|
354
352
|
poolsAccountsMap: {
|
|
355
|
-
|
|
356
|
-
"
|
|
357
|
-
"
|
|
353
|
+
// pool -> per-pool TornadoFeeAdapter (eth_0_1, eth_1, dai_100)
|
|
354
|
+
"0x8c4a04d872a6c1be37964a21ba3a138525dff50b": "0xa616aAE443FCCABfc2F1EA2Afe001E5046FFDCe0",
|
|
355
|
+
"0x8cc930096b4df705a007c4a039bdfa1320ed2508": "0x67a898343F32641206d0f30CB3367944a8919A3A",
|
|
356
|
+
"0x6921fd1a97441dd603a997ed6ddf388658daf754": "0xbF0a7969dacF8337716d0F283df0574dF56b0479"
|
|
358
357
|
}
|
|
359
358
|
},
|
|
360
359
|
1: {}
|
|
@@ -373,8 +372,7 @@ var TornadoCashConfigs = {
|
|
|
373
372
|
aggregator: {
|
|
374
373
|
address: 0xE8F47A78A6D52D317D0D2FFFac56739fE14D1b49n
|
|
375
374
|
},
|
|
376
|
-
weth: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2n
|
|
377
|
-
uniswapQuoterV2: 0x61fFE014bA17989E743c5F6cB21bF9697530B21en
|
|
375
|
+
weth: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2n
|
|
378
376
|
},
|
|
379
377
|
11155111: {
|
|
380
378
|
ensSubdomainKey: "sepolia-tornado",
|
|
@@ -389,8 +387,7 @@ var TornadoCashConfigs = {
|
|
|
389
387
|
aggregator: {
|
|
390
388
|
address: 0x4088712AC9fad39ea133cdb9130E465d235e9642n
|
|
391
389
|
},
|
|
392
|
-
weth: 0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14n
|
|
393
|
-
uniswapQuoterV2: 0xEd1f6473345F45b75F8179591dd5bA1888cf2FB3n
|
|
390
|
+
weth: 0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14n
|
|
394
391
|
}
|
|
395
392
|
};
|
|
396
393
|
|
|
@@ -423,7 +420,7 @@ var TornadoCashProtocol = class {
|
|
|
423
420
|
relayerConfig,
|
|
424
421
|
paymasterConfig = TornadoPaymasterConfigs,
|
|
425
422
|
relayerClientFactory = () => new RelayerClient(host),
|
|
426
|
-
|
|
423
|
+
minExternalSyncBlocksAmount
|
|
427
424
|
}) {
|
|
428
425
|
this.host = host;
|
|
429
426
|
this.stateManager = (async () => {
|
|
@@ -434,6 +431,17 @@ var TornadoCashProtocol = class {
|
|
|
434
431
|
reject(err);
|
|
435
432
|
});
|
|
436
433
|
});
|
|
434
|
+
const { externalSyncProvider } = host;
|
|
435
|
+
const externalSyncClient = externalSyncProvider && {
|
|
436
|
+
getEvents: async (params) => {
|
|
437
|
+
const events = [];
|
|
438
|
+
for await (const event of externalSyncProvider.streamEvents(params)) {
|
|
439
|
+
events.push(event);
|
|
440
|
+
}
|
|
441
|
+
return events;
|
|
442
|
+
},
|
|
443
|
+
lastCoveredBlock: (params) => externalSyncProvider.lastCoveredBlock(params)
|
|
444
|
+
};
|
|
437
445
|
await Promise.race([
|
|
438
446
|
remote.init(
|
|
439
447
|
proxy(host.provider),
|
|
@@ -442,15 +450,26 @@ var TornadoCashProtocol = class {
|
|
|
442
450
|
proxy(host.storage),
|
|
443
451
|
proxy(initialState),
|
|
444
452
|
proxy(artifactsLoader),
|
|
445
|
-
|
|
453
|
+
externalSyncClient ? proxy(externalSyncClient) : void 0,
|
|
454
|
+
{ protocolConfig, accountIndex, relayerConfig, paymasterConfig, minExternalSyncBlocksAmount }
|
|
446
455
|
),
|
|
447
456
|
workerReady
|
|
448
457
|
]);
|
|
449
458
|
return {
|
|
450
459
|
sync: () => remote.sync(),
|
|
451
460
|
getBalances: ((assets) => remote.getBalances(assets)),
|
|
461
|
+
getNotes: (params) => remote.getNotes(params),
|
|
452
462
|
getDepositPayload: (params) => remote.getDepositPayload(params),
|
|
453
|
-
getWithdrawalPayloads: (params) =>
|
|
463
|
+
getWithdrawalPayloads: (params) => {
|
|
464
|
+
if (params.mode === "paymaster") {
|
|
465
|
+
const { tailCalls, ...rest } = params;
|
|
466
|
+
return remote.getWithdrawalPayloads(
|
|
467
|
+
rest,
|
|
468
|
+
tailCalls ? proxy(tailCalls) : void 0
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
return remote.getWithdrawalPayloads(params);
|
|
472
|
+
},
|
|
454
473
|
dumpState: (() => remote.dumpState())
|
|
455
474
|
};
|
|
456
475
|
})();
|
|
@@ -487,6 +506,23 @@ var TornadoCashProtocol = class {
|
|
|
487
506
|
};
|
|
488
507
|
});
|
|
489
508
|
}
|
|
509
|
+
/**
|
|
510
|
+
* Returns all notes for the account.
|
|
511
|
+
* @param assets - Filter by specific assets (optional, if empty returns all)
|
|
512
|
+
* @param includeSpent - Include notes with zero balance (default: false)
|
|
513
|
+
*/
|
|
514
|
+
async notes(assets = [], includeSpent = false) {
|
|
515
|
+
const stateManager = await this.stateManager;
|
|
516
|
+
await stateManager.sync();
|
|
517
|
+
const assetAddresses = assets.map(({ contract }) => {
|
|
518
|
+
const parsedAddress = BigInt(contract);
|
|
519
|
+
return parsedAddress === E_ADDRESS_BIGINT ? 0n : parsedAddress;
|
|
520
|
+
});
|
|
521
|
+
return stateManager.getNotes({
|
|
522
|
+
includeSpent,
|
|
523
|
+
assets: assetAddresses.length > 0 ? assetAddresses : void 0
|
|
524
|
+
});
|
|
525
|
+
}
|
|
490
526
|
async prepareShield(assets, options) {
|
|
491
527
|
const { asset, amount } = assets;
|
|
492
528
|
const strategy = typeof options === "string" ? 1 /* MinFee */ : options?.strategy || 1 /* MinFee */;
|
|
@@ -500,7 +536,10 @@ var TornadoCashProtocol = class {
|
|
|
500
536
|
});
|
|
501
537
|
return { txns: tx };
|
|
502
538
|
}
|
|
503
|
-
async prepareUnshield(assets, to, options) {
|
|
539
|
+
async prepareUnshield(assets, to, options = { mode: "relayer" }) {
|
|
540
|
+
if (options.mode === "relayer" && options.tailCalls !== void 0) {
|
|
541
|
+
throw new Error("Tail Calls are only supported when using paymaster mode.");
|
|
542
|
+
}
|
|
504
543
|
const { asset, amount } = assets;
|
|
505
544
|
const parsedAsset = BigInt(asset.contract || E_ADDRESS_BIGINT);
|
|
506
545
|
const stateManager = await this.stateManager;
|
|
@@ -515,7 +554,8 @@ var TornadoCashProtocol = class {
|
|
|
515
554
|
withdrawals = await stateManager.getWithdrawalPayloads({
|
|
516
555
|
...baseParams,
|
|
517
556
|
mode: "paymaster",
|
|
518
|
-
delegation: options.delegation
|
|
557
|
+
delegation: options.delegation,
|
|
558
|
+
tailCalls: options.tailCalls
|
|
519
559
|
});
|
|
520
560
|
} else {
|
|
521
561
|
withdrawals = await stateManager.getWithdrawalPayloads({
|
|
@@ -538,120 +578,51 @@ var TornadoCashProtocol = class {
|
|
|
538
578
|
return stateManager.dumpState();
|
|
539
579
|
}
|
|
540
580
|
};
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
var ERC20_TRANSFER_GAS = 100000n;
|
|
544
|
-
var baseGasUnits = {
|
|
545
|
-
preVerificationGas: 80000n,
|
|
546
|
-
verificationGasLimit: 50000n,
|
|
547
|
-
callGasLimit: 300000n,
|
|
548
|
-
paymasterVerificationGasLimit: 350000n,
|
|
549
|
-
paymasterPostOpGasLimit: 10000n
|
|
550
|
-
};
|
|
551
|
-
function reasonableGasUnits(isERC20) {
|
|
552
|
-
if (!isERC20) return baseGasUnits;
|
|
553
|
-
return {
|
|
554
|
-
...baseGasUnits,
|
|
555
|
-
callGasLimit: baseGasUnits.callGasLimit + ERC20_TRANSFER_GAS
|
|
556
|
-
};
|
|
581
|
+
function createPaymasterBundlerClient(bundlerUrl) {
|
|
582
|
+
return createBundlerClient({ transport: http(bundlerUrl) });
|
|
557
583
|
}
|
|
558
|
-
async function
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
nonce
|
|
563
|
-
}) {
|
|
564
|
-
const account = privateKeyToAccount(privateKey);
|
|
565
|
-
const authorization = await account.signAuthorization({
|
|
566
|
-
contractAddress: accountAddress,
|
|
567
|
-
chainId,
|
|
568
|
-
nonce
|
|
584
|
+
async function sendSerializedUserOperation(client, op, entryPoint) {
|
|
585
|
+
return client.request({
|
|
586
|
+
method: "eth_sendUserOperation",
|
|
587
|
+
params: [op, entryPoint]
|
|
569
588
|
});
|
|
570
|
-
return { authorization, senderAddress: account.address };
|
|
571
589
|
}
|
|
572
590
|
|
|
573
591
|
// src/paymaster/paymaster-broadcaster.ts
|
|
574
592
|
var PaymasterBroadcaster = class _PaymasterBroadcaster {
|
|
575
|
-
constructor(provider, options) {
|
|
576
|
-
this.provider = provider;
|
|
577
|
-
this.options = options;
|
|
578
|
-
}
|
|
579
|
-
provider;
|
|
580
|
-
options;
|
|
581
593
|
async broadcast(withdrawals) {
|
|
582
|
-
const
|
|
583
|
-
const {
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
])
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
}
|
|
594
|
+
const bySender = /* @__PURE__ */ new Map();
|
|
595
|
+
for (const w of withdrawals) {
|
|
596
|
+
const key = w.userOperation.sender.toLowerCase();
|
|
597
|
+
const group = bySender.get(key) ?? [];
|
|
598
|
+
group.push(w);
|
|
599
|
+
bySender.set(key, group);
|
|
600
|
+
}
|
|
601
|
+
const groupResults = await Promise.allSettled(
|
|
602
|
+
[...bySender.values()].map(async (group) => {
|
|
603
|
+
const out = [];
|
|
604
|
+
for (const w of group) {
|
|
605
|
+
out.push(await _PaymasterBroadcaster.broadcastOne(w));
|
|
606
|
+
}
|
|
607
|
+
return out;
|
|
608
|
+
})
|
|
597
609
|
);
|
|
598
|
-
const failed =
|
|
610
|
+
const failed = groupResults.filter((r) => r.status === "rejected");
|
|
599
611
|
if (failed.length > 0) {
|
|
600
612
|
console.warn(
|
|
601
613
|
`Some paymaster withdrawals failed.`,
|
|
602
614
|
failed.map((e) => e.reason).join("\n")
|
|
603
615
|
);
|
|
604
616
|
}
|
|
605
|
-
return
|
|
617
|
+
return groupResults.filter((r) => r.status === "fulfilled").flatMap((r) => r.value);
|
|
606
618
|
}
|
|
607
|
-
static async broadcastOne(withdrawal
|
|
608
|
-
const {
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
bundlerUrl,
|
|
613
|
-
accountAddress,
|
|
614
|
-
isERC20
|
|
615
|
-
} = withdrawal;
|
|
616
|
-
const [root, nullifierHash, recipient, _paymasterAddress, feeHex] = proofArgs;
|
|
617
|
-
if (BigInt(paymasterAddress) !== BigInt(_paymasterAddress)) {
|
|
618
|
-
throw new Error(`relayer must be paymaster when using the 4337 paymaster flow: ${paymasterAddress} != ${_paymasterAddress}`);
|
|
619
|
-
}
|
|
620
|
-
const delegation = withdrawal.delegation ?? await _PaymasterBroadcaster.generateRandomDelegation(accountAddress, provider);
|
|
621
|
-
const { senderAddress, authorization } = delegation;
|
|
622
|
-
const bundlerClient = new BundlerClient(bundlerUrl, entryPointAddress);
|
|
623
|
-
const { standard: { maxFeePerGas, maxPriorityFeePerGas } } = await bundlerClient.getUserOperationGasPrice();
|
|
624
|
-
let gas;
|
|
625
|
-
{
|
|
626
|
-
gas = {
|
|
627
|
-
type: "manual",
|
|
628
|
-
...reasonableGasUnits(isERC20),
|
|
629
|
-
maxFeePerGas,
|
|
630
|
-
maxPriorityFeePerGas
|
|
631
|
-
};
|
|
632
|
-
}
|
|
633
|
-
const op = await new TornadoBuilder(senderAddress).withPaymaster(paymasterAddress).withAuthorization(authorization).withWithdraw(
|
|
634
|
-
proofHex,
|
|
635
|
-
root,
|
|
636
|
-
nullifierHash,
|
|
637
|
-
recipient,
|
|
638
|
-
_paymasterAddress,
|
|
639
|
-
BigInt(feeHex)
|
|
640
|
-
).withGas(gas).build(provider, bundlerClient);
|
|
641
|
-
const userOpHash = await bundlerClient.sendUserOperation(op);
|
|
642
|
-
await bundlerClient.waitForUserOperationReceipt(userOpHash);
|
|
619
|
+
static async broadcastOne(withdrawal) {
|
|
620
|
+
const { bundlerUrl, entryPointAddress, userOperation } = withdrawal;
|
|
621
|
+
const bundlerClient = createPaymasterBundlerClient(bundlerUrl);
|
|
622
|
+
const userOpHash = await sendSerializedUserOperation(bundlerClient, userOperation, entryPointAddress);
|
|
623
|
+
await bundlerClient.waitForUserOperationReceipt({ hash: userOpHash });
|
|
643
624
|
return { userOpHash };
|
|
644
625
|
}
|
|
645
|
-
static async generateRandomDelegation(accountAddress, provider) {
|
|
646
|
-
const privateKey = generatePrivateKey();
|
|
647
|
-
const chainId = Number(await provider.getChainId());
|
|
648
|
-
return signDelegationAuthorization({
|
|
649
|
-
privateKey,
|
|
650
|
-
accountAddress,
|
|
651
|
-
chainId,
|
|
652
|
-
nonce: 0
|
|
653
|
-
});
|
|
654
|
-
}
|
|
655
626
|
};
|
|
656
627
|
|
|
657
628
|
// src/plugin/broadcaster.ts
|
|
@@ -663,7 +634,7 @@ var TornadoCashBroadcaster = class {
|
|
|
663
634
|
host,
|
|
664
635
|
relayerClientFactory = () => new RelayerClient({ network: host.network }),
|
|
665
636
|
paymasterConfig,
|
|
666
|
-
paymasterClientFactory = () => new PaymasterBroadcaster(
|
|
637
|
+
paymasterClientFactory = () => new PaymasterBroadcaster()
|
|
667
638
|
}) {
|
|
668
639
|
this.provider = host.provider;
|
|
669
640
|
this.relayerClient = relayerClientFactory();
|