@kohaku-eth/tornado-cash 0.0.2-alpha.19 → 0.0.2-alpha.20
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 +37 -2
- package/dist/index.js +43 -5
- package/dist/state-manager.worker.js +203 -55
- package/dist/state-manager.worker.node.js +203 -55
- package/dist/worker-loader.browser.d.ts +53 -1
- package/dist/worker-loader.node.d.ts +53 -1
- package/package.json +9 -6
package/dist/index.d.ts
CHANGED
|
@@ -42,6 +42,14 @@ interface ISecretManager {
|
|
|
42
42
|
deriveDelegatorSigner: (params: {
|
|
43
43
|
path: string;
|
|
44
44
|
}) => Promise<`0x${string}`>;
|
|
45
|
+
/**
|
|
46
|
+
* Derives the ephemeral signer for an imported legacy note. Legacy secrets
|
|
47
|
+
* have no keystore-derived `depositIndex`, so this is a pure function of
|
|
48
|
+
* the note's own nullifier instead of a BIP-32 derivation.
|
|
49
|
+
*/
|
|
50
|
+
deriveLegacyEphemeralSigner: (params: {
|
|
51
|
+
nullifier: Nullifier$1;
|
|
52
|
+
}) => Promise<`0x${string}`>;
|
|
45
53
|
}
|
|
46
54
|
interface SecretManagerParams {
|
|
47
55
|
host: Pick<Host, 'keystore'>;
|
|
@@ -361,6 +369,18 @@ declare enum DepositStrategy {
|
|
|
361
369
|
MinFee = 1
|
|
362
370
|
}
|
|
363
371
|
|
|
372
|
+
type ImportNoteResult = {
|
|
373
|
+
note: string;
|
|
374
|
+
status: 'imported';
|
|
375
|
+
poolAddress: Address;
|
|
376
|
+
} | {
|
|
377
|
+
note: string;
|
|
378
|
+
status: 'wrong-chain';
|
|
379
|
+
} | {
|
|
380
|
+
note: string;
|
|
381
|
+
status: 'not-found';
|
|
382
|
+
};
|
|
383
|
+
|
|
364
384
|
/**
|
|
365
385
|
* How the batch delegator for a tail-call paymaster withdrawal is produced.
|
|
366
386
|
* Only honored when `tailCalls` are present (see `paymasterWithdrawThunk`).
|
|
@@ -545,6 +565,14 @@ interface IStateManager {
|
|
|
545
565
|
* @param assets - Optional filter by specific assets
|
|
546
566
|
*/
|
|
547
567
|
getNotes: (params: IGetNotesParams) => Promise<TCNote[]>;
|
|
568
|
+
/**
|
|
569
|
+
* Parses legacy (pre-SDK) Tornado Cash note strings and, for any that match
|
|
570
|
+
* a synced on-chain deposit on the current chain, registers them as
|
|
571
|
+
* importable user secrets.
|
|
572
|
+
*/
|
|
573
|
+
importNotes: (params: {
|
|
574
|
+
notes: string[];
|
|
575
|
+
}) => Promise<ImportNoteResult[]>;
|
|
548
576
|
dumpState: () => Record<StoreStorageKey, PublicRootState>;
|
|
549
577
|
}
|
|
550
578
|
|
|
@@ -558,6 +586,7 @@ interface TCBaseCredential {
|
|
|
558
586
|
accountIndex: number;
|
|
559
587
|
}
|
|
560
588
|
interface TCPluginParameters extends TCBroadcasterParameters, TCBaseCredential, Pick<TCProtocolParams, 'initialState' | 'minExternalSyncBlocksAmount'> {
|
|
589
|
+
secretManagerFactory?: TCProtocolParams['secretManagerFactory'];
|
|
561
590
|
protocolConfig: TCProtocolConfig;
|
|
562
591
|
relayerConfig?: IRelayerFeeConfig;
|
|
563
592
|
stateManagerWorkerUrl?: string;
|
|
@@ -602,6 +631,7 @@ type TCInstance = PluginInstance<TCAddress, {
|
|
|
602
631
|
prepareShield(asset: TCAssetAmount, options: TCPrepareShieldOptions): Promise<TCPublicOperation>;
|
|
603
632
|
prepareUnshield(asset: TCAssetAmount, to: Address$1, options: TCRelayerUnshieldOptions): Promise<TCPrivateOperation<'relayer'>>;
|
|
604
633
|
prepareUnshield(asset: TCAssetAmount, to: Address$1, options: TCPaymasterUnshieldOptions): Promise<TCPrivateOperation<'paymaster'>>;
|
|
634
|
+
importNotes(notes: string | string[]): Promise<ImportNoteResult[]>;
|
|
605
635
|
};
|
|
606
636
|
publicOp: TCPublicOperation;
|
|
607
637
|
privateOp: TCPrivateOperation;
|
|
@@ -614,7 +644,7 @@ type RequireOnly<T, Keys extends keyof T> = Partial<T> & Pick<T, Keys>;
|
|
|
614
644
|
declare class TornadoCashProtocol implements TCInstance {
|
|
615
645
|
readonly host: Host;
|
|
616
646
|
private stateManager;
|
|
617
|
-
constructor(host: Host, { accountIndex, initialState, protocolConfig, artifactsLoader, stateManagerWorkerUrl, relayerConfig, paymasterConfig, relayerClientFactory, minExternalSyncBlocksAmount, }: RequireOnly<TCProtocolParams, 'protocolConfig'>);
|
|
647
|
+
constructor(host: Host, { accountIndex, initialState, protocolConfig, artifactsLoader, stateManagerWorkerUrl, relayerConfig, paymasterConfig, relayerClientFactory, minExternalSyncBlocksAmount, secretManagerFactory, }: RequireOnly<TCProtocolParams, 'protocolConfig'>);
|
|
618
648
|
instanceId: () => Promise<"0x1">;
|
|
619
649
|
/**
|
|
620
650
|
* Only process supported assets or error out?
|
|
@@ -628,6 +658,11 @@ declare class TornadoCashProtocol implements TCInstance {
|
|
|
628
658
|
* @param includeSpent - Include notes with zero balance (default: false)
|
|
629
659
|
*/
|
|
630
660
|
notes(assets?: ERC20AssetId[], includeSpent?: boolean): Promise<TCNote[]>;
|
|
661
|
+
/**
|
|
662
|
+
* Parses legacy (pre-SDK) Tornado Cash note strings and registers any that
|
|
663
|
+
* match a synced on-chain deposit on the current chain as user secrets.
|
|
664
|
+
*/
|
|
665
|
+
importNotes(notes: string | string[]): Promise<ImportNoteResult[]>;
|
|
631
666
|
prepareShield(assets: TCAssetAmount, options?: TCPrepareShieldOptions | `0x${string}`): Promise<TCPublicOperation>;
|
|
632
667
|
prepareUnshield(assets: AssetAmount, to: AccountId): Promise<TCPrivateOperation<'relayer'>>;
|
|
633
668
|
prepareUnshield(assets: AssetAmount, to: AccountId, options?: TCRelayerUnshieldOptions): Promise<TCPrivateOperation<'relayer'>>;
|
|
@@ -717,4 +752,4 @@ declare const TornadoCashConfigs: {
|
|
|
717
752
|
};
|
|
718
753
|
};
|
|
719
754
|
|
|
720
|
-
export { type Commitment, DepositStrategy, E_ADDRESS, type ISecretManager, type Nullifier, SecretManager, type SecretManagerParams, type TCAddress, type TCAssetAmount, type TCAssetBalance, type TCBroadcaster, type TCBroadcasterParameters, type TCInstance, type TCNote, type TCPaymasterUnshieldOptions, type TCPluginParameters, type TCPrepareShieldOptions, type TCPrepareUnshieldOptions, type TCRelayerUnshieldOptions, TornadoCashConfigs, TornadoCashProtocol, TornadoPaymasterConfigs, createTCBroadcaster, createTCPlugin };
|
|
755
|
+
export { type Commitment, DepositStrategy, E_ADDRESS, type ISecretManager, type ImportNoteResult, type Nullifier, SecretManager, type SecretManagerParams, type TCAddress, type TCAssetAmount, type TCAssetBalance, type TCBroadcaster, type TCBroadcasterParameters, type TCInstance, type TCNote, type TCPaymasterUnshieldOptions, type TCPluginParameters, type TCPrepareShieldOptions, type TCPrepareUnshieldOptions, type TCRelayerUnshieldOptions, TornadoCashConfigs, TornadoCashProtocol, TornadoPaymasterConfigs, createTCBroadcaster, createTCPlugin };
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { proxy } from 'comlink';
|
|
|
5
5
|
import { loadStateManagerWorker } from '#worker-loader';
|
|
6
6
|
import 'viem/accounts';
|
|
7
7
|
import { createBundlerClient } from 'viem/account-abstraction';
|
|
8
|
-
import {
|
|
8
|
+
import { asciiToBytes, numberToBytesLE, concatBytes, bytesToHex, bytesToNumberLE } 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
11
|
|
|
@@ -216,10 +216,29 @@ createSelector(
|
|
|
216
216
|
([, relayer]) => deserialize(relayer, { ensName: true, hostname: true })
|
|
217
217
|
)
|
|
218
218
|
);
|
|
219
|
-
var
|
|
219
|
+
var derivedUserSecretsSelector = selectEntityMap(
|
|
220
220
|
(s) => s.userSecrets.byPool,
|
|
221
221
|
deserialize
|
|
222
222
|
);
|
|
223
|
+
var legacyUserSecretsSelector = selectEntityMap(
|
|
224
|
+
(s) => s.legacySecrets.byPool,
|
|
225
|
+
deserialize
|
|
226
|
+
);
|
|
227
|
+
createSelector(
|
|
228
|
+
[derivedUserSecretsSelector, legacyUserSecretsSelector],
|
|
229
|
+
(derived, legacy) => {
|
|
230
|
+
const result = /* @__PURE__ */ new Map();
|
|
231
|
+
for (const [poolAddress, records] of legacy) {
|
|
232
|
+
const existing = result.get(poolAddress) ?? [];
|
|
233
|
+
result.set(poolAddress, [...existing, ...records.map((record) => ({ kind: "legacy", ...record }))]);
|
|
234
|
+
}
|
|
235
|
+
for (const [poolAddress, records] of derived) {
|
|
236
|
+
const existing = result.get(poolAddress) ?? [];
|
|
237
|
+
result.set(poolAddress, [...existing, ...records.map((record) => ({ kind: "derived", ...record }))]);
|
|
238
|
+
}
|
|
239
|
+
return result;
|
|
240
|
+
}
|
|
241
|
+
);
|
|
223
242
|
|
|
224
243
|
// src/state/thunks/getDepositPayloadThunk.ts
|
|
225
244
|
var DepositStrategy = /* @__PURE__ */ ((DepositStrategy2) => {
|
|
@@ -266,7 +285,7 @@ createAsyncThunk(
|
|
|
266
285
|
const state = getState();
|
|
267
286
|
const pools = poolsSelector(state);
|
|
268
287
|
const { chainId } = instanceRegistryInfoSelector(state);
|
|
269
|
-
const userSecrets =
|
|
288
|
+
const userSecrets = derivedUserSecretsSelector(state);
|
|
270
289
|
const poolsCandidates = Array.from(pools.values()).filter((p) => p.asset === asset);
|
|
271
290
|
if (poolsCandidates.length === 0) throw new Error(`No pools available for asset ${addressToHex(asset)}`);
|
|
272
291
|
const poolsToDepositInto = calculatePoolsDeposits(poolsCandidates, amount, strategy);
|
|
@@ -456,7 +475,8 @@ var TornadoCashProtocol = class {
|
|
|
456
475
|
relayerConfig,
|
|
457
476
|
paymasterConfig = TornadoPaymasterConfigs,
|
|
458
477
|
relayerClientFactory = () => new RelayerClient(host),
|
|
459
|
-
minExternalSyncBlocksAmount
|
|
478
|
+
minExternalSyncBlocksAmount,
|
|
479
|
+
secretManagerFactory
|
|
460
480
|
}) {
|
|
461
481
|
this.host = host;
|
|
462
482
|
this.stateManager = (async () => {
|
|
@@ -479,6 +499,7 @@ var TornadoCashProtocol = class {
|
|
|
479
499
|
firstCoveredBlock: (params) => externalSyncProvider.firstCoveredBlock(params),
|
|
480
500
|
lastCoveredBlock: (params) => externalSyncProvider.lastCoveredBlock(params)
|
|
481
501
|
};
|
|
502
|
+
const resolvedSecretManager = secretManagerFactory ? await secretManagerFactory({ host: { keystore: host.keystore }, accountIndex }) : void 0;
|
|
482
503
|
await Promise.race([
|
|
483
504
|
remote.init(
|
|
484
505
|
proxy(host.provider),
|
|
@@ -487,6 +508,7 @@ var TornadoCashProtocol = class {
|
|
|
487
508
|
proxy(host.storage),
|
|
488
509
|
proxy(initialState),
|
|
489
510
|
proxy(artifactsLoader),
|
|
511
|
+
resolvedSecretManager ? proxy(resolvedSecretManager) : void 0,
|
|
490
512
|
externalSyncClient ? proxy(externalSyncClient) : void 0,
|
|
491
513
|
{ protocolConfig, accountIndex, relayerConfig, paymasterConfig, minExternalSyncBlocksAmount }
|
|
492
514
|
),
|
|
@@ -497,6 +519,7 @@ var TornadoCashProtocol = class {
|
|
|
497
519
|
getBalances: ((assets) => remote.getBalances(assets)),
|
|
498
520
|
getNotes: (params) => remote.getNotes(params),
|
|
499
521
|
getDepositPayload: (params) => remote.getDepositPayload(params),
|
|
522
|
+
importNotes: (params) => remote.importNotes(params),
|
|
500
523
|
getWithdrawalPayloads: (params) => {
|
|
501
524
|
if (params.mode === "paymaster") {
|
|
502
525
|
const { tailCalls, ...rest } = params;
|
|
@@ -560,6 +583,15 @@ var TornadoCashProtocol = class {
|
|
|
560
583
|
assets: assetAddresses.length > 0 ? assetAddresses : void 0
|
|
561
584
|
});
|
|
562
585
|
}
|
|
586
|
+
/**
|
|
587
|
+
* Parses legacy (pre-SDK) Tornado Cash note strings and registers any that
|
|
588
|
+
* match a synced on-chain deposit on the current chain as user secrets.
|
|
589
|
+
*/
|
|
590
|
+
async importNotes(notes) {
|
|
591
|
+
const stateManager = await this.stateManager;
|
|
592
|
+
await stateManager.sync();
|
|
593
|
+
return stateManager.importNotes({ notes: Array.isArray(notes) ? notes : [notes] });
|
|
594
|
+
}
|
|
563
595
|
async prepareShield(assets, options) {
|
|
564
596
|
const { asset, amount } = assets;
|
|
565
597
|
const strategy = typeof options === "string" ? 1 /* MinFee */ : options?.strategy || 1 /* MinFee */;
|
|
@@ -768,10 +800,16 @@ async function SecretManager({
|
|
|
768
800
|
const deriveDelegatorSigner = async ({ path }) => {
|
|
769
801
|
return Promise.resolve(keystore.deriveAt(path));
|
|
770
802
|
};
|
|
803
|
+
const LEGACY_EPHEMERAL_SALT = asciiToBytes("KOHAKU7702");
|
|
804
|
+
const deriveLegacyEphemeralSigner = async ({ nullifier }) => {
|
|
805
|
+
const hash = keccak_256(concatBytes(numberToBytesLE(nullifier, 31), LEGACY_EPHEMERAL_SALT));
|
|
806
|
+
return `0x${bytesToHex(hash)}`;
|
|
807
|
+
};
|
|
771
808
|
return {
|
|
772
809
|
getDepositSecrets: (params) => deriveSecrets(params),
|
|
773
810
|
deriveEphemeralSigner,
|
|
774
|
-
deriveDelegatorSigner
|
|
811
|
+
deriveDelegatorSigner,
|
|
812
|
+
deriveLegacyEphemeralSigner
|
|
775
813
|
};
|
|
776
814
|
}
|
|
777
815
|
function tcPath({ accountIndex, secretType, depositIndex }) {
|