@unlink-xyz/core 0.1.3-canary.0bfbcf1 → 0.1.3-canary.18566ec

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.
Files changed (65) hide show
  1. package/dist/browser/index.js +955 -81
  2. package/dist/browser/index.js.map +1 -1
  3. package/dist/browser/wallet/index.js +1370 -548
  4. package/dist/browser/wallet/index.js.map +1 -1
  5. package/dist/clients/indexer.d.ts +4 -0
  6. package/dist/clients/indexer.d.ts.map +1 -1
  7. package/dist/clients/indexer.js +4 -0
  8. package/dist/errors.d.ts +3 -0
  9. package/dist/errors.d.ts.map +1 -1
  10. package/dist/errors.js +6 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +2 -0
  14. package/dist/state/store/index.d.ts +1 -1
  15. package/dist/state/store/index.d.ts.map +1 -1
  16. package/dist/state/store/job-store.d.ts.map +1 -1
  17. package/dist/state/store/job-store.js +15 -1
  18. package/dist/state/store/jobs.d.ts +9 -4
  19. package/dist/state/store/jobs.d.ts.map +1 -1
  20. package/dist/state/store/records.d.ts +8 -0
  21. package/dist/state/store/records.d.ts.map +1 -1
  22. package/dist/transactions/adapter.d.ts +31 -0
  23. package/dist/transactions/adapter.d.ts.map +1 -0
  24. package/dist/transactions/adapter.js +106 -0
  25. package/dist/transactions/deposit.d.ts.map +1 -1
  26. package/dist/transactions/deposit.js +1 -6
  27. package/dist/transactions/index.d.ts +4 -2
  28. package/dist/transactions/index.d.ts.map +1 -1
  29. package/dist/transactions/index.js +3 -2
  30. package/dist/transactions/note-sync.d.ts +3 -3
  31. package/dist/transactions/note-sync.d.ts.map +1 -1
  32. package/dist/transactions/note-sync.js +129 -3
  33. package/dist/transactions/reconcile.d.ts +1 -1
  34. package/dist/transactions/reconcile.d.ts.map +1 -1
  35. package/dist/transactions/reconcile.js +13 -3
  36. package/dist/transactions/transact.d.ts +21 -2
  37. package/dist/transactions/transact.d.ts.map +1 -1
  38. package/dist/transactions/transact.js +45 -15
  39. package/dist/transactions/types/deposit.d.ts +3 -3
  40. package/dist/transactions/types/deposit.d.ts.map +1 -1
  41. package/dist/transactions/types/options.d.ts +6 -0
  42. package/dist/transactions/types/options.d.ts.map +1 -1
  43. package/dist/transactions/types/state-stores.d.ts +8 -0
  44. package/dist/transactions/types/state-stores.d.ts.map +1 -1
  45. package/dist/transactions/types/transact.d.ts +5 -0
  46. package/dist/transactions/types/transact.d.ts.map +1 -1
  47. package/dist/tsconfig.tsbuildinfo +1 -1
  48. package/dist/utils/random.d.ts +5 -0
  49. package/dist/utils/random.d.ts.map +1 -1
  50. package/dist/utils/random.js +7 -0
  51. package/dist/wallet/adapter.d.ts +21 -0
  52. package/dist/wallet/adapter.d.ts.map +1 -0
  53. package/dist/wallet/adapter.js +210 -0
  54. package/dist/wallet/index.d.ts +3 -2
  55. package/dist/wallet/index.d.ts.map +1 -1
  56. package/dist/wallet/index.js +2 -1
  57. package/dist/wallet/sdk.d.ts +8 -0
  58. package/dist/wallet/sdk.d.ts.map +1 -1
  59. package/dist/wallet/sdk.js +66 -50
  60. package/dist/wallet/types.d.ts +193 -14
  61. package/dist/wallet/types.d.ts.map +1 -1
  62. package/dist/wallet/unlink-wallet.d.ts +187 -0
  63. package/dist/wallet/unlink-wallet.d.ts.map +1 -0
  64. package/dist/wallet/unlink-wallet.js +345 -0
  65. package/package.json +2 -2
@@ -3611,6 +3611,12 @@ var ReconcileError = class extends CoreError {
3611
3611
  this.status = status;
3612
3612
  }
3613
3613
  };
3614
+ var AdapterError = class extends CoreError {
3615
+ constructor(message) {
3616
+ super(message);
3617
+ this.name = "AdapterError";
3618
+ }
3619
+ };
3614
3620
 
3615
3621
  // keys.ts
3616
3622
  init_process();
@@ -7962,7 +7968,12 @@ var VALID_STATUSES = [
7962
7968
  "failed",
7963
7969
  "dead"
7964
7970
  ];
7965
- var VALID_KINDS = ["deposit", "transfer", "withdraw"];
7971
+ var VALID_KINDS = [
7972
+ "deposit",
7973
+ "transfer",
7974
+ "withdraw",
7975
+ "adapter"
7976
+ ];
7966
7977
  function assertStatus(status) {
7967
7978
  if (!VALID_STATUSES.includes(status)) {
7968
7979
  throw new CoreError(`invalid job status: ${status}`);
@@ -8042,6 +8053,12 @@ function validateDepositRecord(job) {
8042
8053
  }
8043
8054
  }
8044
8055
  }
8056
+ function validateAdapterRecord(job) {
8057
+ ensureAddress("adapter address", job.adapterAddress);
8058
+ if (!job.adapterCalldata) {
8059
+ throw new CoreError("adapterCalldata is required for adapter record");
8060
+ }
8061
+ }
8045
8062
  function validateJob(job) {
8046
8063
  if (!job.relayId) {
8047
8064
  throw new CoreError("relayId is required");
@@ -8061,6 +8078,9 @@ function validateJob(job) {
8061
8078
  validateDepositRecord(job);
8062
8079
  } else {
8063
8080
  validatePoolTransactionRecord(job);
8081
+ if (job.kind === "adapter") {
8082
+ validateAdapterRecord(job);
8083
+ }
8064
8084
  }
8065
8085
  }
8066
8086
  function buildJobKey(relayId) {
@@ -8585,6 +8605,9 @@ function randomBigint(bytes2 = 32) {
8585
8605
  function randomHex(bytes2) {
8586
8606
  return `0x${randomBigint(bytes2).toString(16).padStart(bytes2 * 2, "0")}`;
8587
8607
  }
8608
+ function generateRelayId(prefix) {
8609
+ return globalThis.crypto?.randomUUID?.() ?? `${prefix}-${randomHex(16).slice(2)}`;
8610
+ }
8588
8611
 
8589
8612
  // utils/format.ts
8590
8613
  function normalizeAddress(value) {
@@ -34653,7 +34676,11 @@ function createIndexerClient(baseUrl, deps) {
34653
34676
  root: record.root,
34654
34677
  txHash: record.tx_hash,
34655
34678
  insertedAt: record.inserted_at,
34656
- eventType: record.event_type ?? "unknown"
34679
+ eventType: record.event_type ?? "unknown",
34680
+ adapterNpk: record.adapter_npk,
34681
+ adapterToken: record.adapter_token,
34682
+ adapterAmount: record.adapter_amount,
34683
+ adapterRandom: record.adapter_random
34657
34684
  });
34658
34685
  const normalizeNullifierRecord = (record) => ({
34659
34686
  nullifier: record.nullifier,
@@ -35024,9 +35051,6 @@ function buildDepositCalldata(depositor, processedNotes) {
35024
35051
  }))
35025
35052
  ]);
35026
35053
  }
35027
- function generateRelayId(prefix) {
35028
- return globalThis.crypto?.randomUUID?.() ?? `${prefix}-${Date.now().toString(16)}`;
35029
- }
35030
35054
  async function deposit(store, req) {
35031
35055
  if (!req.notes?.length) {
35032
35056
  throw new ValidationError("At least one note is required for deposit");
@@ -52677,7 +52701,7 @@ async function proveTransaction(input, options) {
52677
52701
  }
52678
52702
 
52679
52703
  // transactions/transact.ts
52680
- var TRANSACT_ABI = "function transact(((uint256[2] pA, uint256[2][2] pB, uint256[2] pC) proof, uint256 merkleRoot, uint256[] nullifierHashes, uint256[] newCommitments, (uint64 chainId, address poolAddress) context, (uint256 npk, uint256 amount, address token) withdrawal, (uint256 ephemeralKey, uint256[3] data)[] ciphertexts)[] _transactions)";
52704
+ var TRANSACT_ABI = "function transact(((uint256[2] pA, uint256[2][2] pB, uint256[2] pC) proof, uint256 merkleRoot, uint256[] nullifierHashes, uint256[] newCommitments, (uint64 chainId, address poolAddress, uint256 adapterDataHash) context, (uint256 npk, uint256 amount, address token) withdrawal, (uint256 ephemeralKey, uint256[3] data)[] ciphertexts)[] _transactions)";
52681
52705
  var DEFAULT_PROOF_TIMEOUT_MS = 6e4;
52682
52706
  var transactInterface = new Interface([TRANSACT_ABI]);
52683
52707
  var DEFAULT_WITHDRAWAL = {
@@ -52685,11 +52709,33 @@ var DEFAULT_WITHDRAWAL = {
52685
52709
  amount: 0n,
52686
52710
  token: "0x0000000000000000000000000000000000000000"
52687
52711
  };
52688
- function computeBoundParamsHash(chainId, poolAddress) {
52712
+ function computeBoundParamsHash(chainId, poolAddress, adapterDataHash = 0n) {
52713
+ const coder = AbiCoder.defaultAbiCoder();
52714
+ const encoded = coder.encode(
52715
+ ["uint64", "uint160", "uint256"],
52716
+ [BigInt(chainId), BigInt(poolAddress), adapterDataHash]
52717
+ );
52718
+ return parseHexToBigInt(keccak256(encoded)) % SNARK_SCALAR_FIELD;
52719
+ }
52720
+ function computeAdapterDataHash(params) {
52689
52721
  const coder = AbiCoder.defaultAbiCoder();
52690
52722
  const encoded = coder.encode(
52691
- ["uint64", "uint160"],
52692
- [BigInt(chainId), BigInt(poolAddress)]
52723
+ [
52724
+ "tuple(address to, bytes data, uint256 value)[]",
52725
+ "tuple(uint256 npk, uint256 random, address token, uint256 minAmount)[]",
52726
+ "address[]",
52727
+ "uint256",
52728
+ "uint256",
52729
+ "uint256"
52730
+ ],
52731
+ [
52732
+ params.calls,
52733
+ params.reshields,
52734
+ params.inputTokens,
52735
+ params.nonce,
52736
+ params.deadline,
52737
+ BigInt(params.chainId)
52738
+ ]
52693
52739
  );
52694
52740
  return parseHexToBigInt(keccak256(encoded)) % SNARK_SCALAR_FIELD;
52695
52741
  }
@@ -52744,7 +52790,12 @@ async function buildSingleTransactionProof(store, account, signer, chainId, pool
52744
52790
  const allCommitmentsOut = hasWithdrawal ? [...outputs.map((o) => o.value), withdrawalCommitment] : outputs.map((o) => o.value);
52745
52791
  const allNpkOut = hasWithdrawal ? [...tx.outputs.map((o) => poseidon([o.mpk, o.random])), withdrawal.npk] : tx.outputs.map((o) => poseidon([o.mpk, o.random]));
52746
52792
  const allValueOut = hasWithdrawal ? [...tx.outputs.map((o) => o.amount), withdrawal.amount] : tx.outputs.map((o) => o.amount);
52747
- const boundParams = computeBoundParamsHash(chainId, poolAddress);
52793
+ const adapterDataHash = tx.adapterDataHash ?? 0n;
52794
+ const boundParams = computeBoundParamsHash(
52795
+ chainId,
52796
+ poolAddress,
52797
+ adapterDataHash
52798
+ );
52748
52799
  const pubSignals = [
52749
52800
  parseHexToBigInt(merkleRoot),
52750
52801
  boundParams,
@@ -52851,7 +52902,7 @@ async function transact(store, req, opts) {
52851
52902
  );
52852
52903
  const results = await Promise.all(proofPromises);
52853
52904
  const calldata = transactInterface.encodeFunctionData("transact", [
52854
- results.map((r2) => ({
52905
+ results.map((r2, i) => ({
52855
52906
  proof: { pA: r2.proof.pA, pB: r2.proof.pB, pC: r2.proof.pC },
52856
52907
  merkleRoot: parseHexToBigInt(r2.merkleRoot),
52857
52908
  nullifierHashes: r2.contexts.map((c) => c.nullifier),
@@ -52860,12 +52911,16 @@ async function transact(store, req, opts) {
52860
52911
  // Skip root + boundParams + nullifiers
52861
52912
  r2.withdrawal.amount > 0n ? r2.proof.pubSignals.length - 1 : void 0
52862
52913
  ),
52863
- context: { chainId: BigInt(req.chainId), poolAddress: req.poolAddress },
52914
+ context: {
52915
+ chainId: BigInt(req.chainId),
52916
+ poolAddress: req.poolAddress,
52917
+ adapterDataHash: req.transactions[i]?.adapterDataHash ?? 0n
52918
+ },
52864
52919
  withdrawal: r2.withdrawal,
52865
52920
  ciphertexts: r2.ciphertexts
52866
52921
  }))
52867
52922
  ]);
52868
- const relayId = globalThis.crypto?.randomUUID?.() ?? `tx-${Date.now().toString(16)}`;
52923
+ const relayId = generateRelayId("tx");
52869
52924
  const hasAnyWithdrawal = results.some((r2) => r2.withdrawal.amount > 0n);
52870
52925
  const historyKind = hasAnyWithdrawal ? "Withdraw" : "Send";
52871
52926
  const deltasByToken = /* @__PURE__ */ new Map();
@@ -52908,7 +52963,7 @@ async function transact(store, req, opts) {
52908
52963
  };
52909
52964
  const job = hasAnyWithdrawal ? { ...jobBase, kind: "withdraw" } : { ...jobBase, kind: "transfer" };
52910
52965
  let txHash = null;
52911
- if (broadcaster) {
52966
+ if (!opts.skipBroadcast && broadcaster) {
52912
52967
  const submission = await broadcaster.submitRelay({
52913
52968
  clientTxId: relayId,
52914
52969
  chainId: req.chainId,
@@ -52952,11 +53007,13 @@ async function transact(store, req, opts) {
52952
53007
  throw new CoreError("broadcaster relay timed out");
52953
53008
  }
52954
53009
  }
52955
- await store.putJob({
52956
- ...job,
52957
- status: "broadcasting",
52958
- txHash
52959
- });
53010
+ if (opts.persistJob !== false) {
53011
+ await store.putJob({
53012
+ ...job,
53013
+ status: "broadcasting",
53014
+ txHash
53015
+ });
53016
+ }
52960
53017
  const transactionResults = results.map((r2) => ({
52961
53018
  proof: r2.proof,
52962
53019
  witnesses: r2.witnesses,
@@ -52971,7 +53028,7 @@ async function transact(store, req, opts) {
52971
53028
  }
52972
53029
  async function syncTransact(store, relayId, opts) {
52973
53030
  const record = await store.getJob(relayId);
52974
- if (!record || record.kind !== "transfer" && record.kind !== "withdraw")
53031
+ if (!record || record.kind !== "transfer" && record.kind !== "withdraw" && record.kind !== "adapter")
52975
53032
  throw new CoreError(`unknown pool transaction relay ${relayId}`);
52976
53033
  const job = record;
52977
53034
  const serviceConfig = createServiceConfig(opts.gatewayUrl);
@@ -53074,6 +53131,116 @@ async function syncTransact(store, relayId, opts) {
53074
53131
  };
53075
53132
  }
53076
53133
 
53134
+ // transactions/adapter.ts
53135
+ init_process();
53136
+ init_buffer();
53137
+ var ADAPTER_EXECUTE_ABI = [
53138
+ "function execute(bytes _transactData, (address to, bytes data, uint256 value)[] _calls, (uint256 npk, uint256 random, address token, uint256 minAmount)[] _reshields, address[] _inputTokens, uint256 _nonce, uint256 _deadline)"
53139
+ ];
53140
+ var adapterInterface = new Interface(ADAPTER_EXECUTE_ABI);
53141
+ var approveInterface = new Interface([
53142
+ "function approve(address spender, uint256 amount)"
53143
+ ]);
53144
+ var HEX_DATA_REGEX = /^0x[0-9a-fA-F]*$/;
53145
+ function ensureNonNegative(label, value) {
53146
+ if (value < 0n) {
53147
+ throw new AdapterError(`${label} must be non-negative`);
53148
+ }
53149
+ return value;
53150
+ }
53151
+ function ensureHexData(label, value) {
53152
+ if (typeof value !== "string" || !HEX_DATA_REGEX.test(value) || value.length % 2 !== 0) {
53153
+ throw new AdapterError(`${label} must be 0x-prefixed even-length hex data`);
53154
+ }
53155
+ return value;
53156
+ }
53157
+ function normalizeCall(call, index) {
53158
+ const to = ensureAddress(`calls[${index}].to`, call.to);
53159
+ const data = ensureHexData(`calls[${index}].data`, call.data);
53160
+ const value = ensureNonNegative(`calls[${index}].value`, call.value);
53161
+ return { to, data, value };
53162
+ }
53163
+ function normalizeReshield(reshield, index) {
53164
+ const token = ensureAddress(`reshields[${index}].token`, reshield.token);
53165
+ const npk = ensureNonNegative(`reshields[${index}].npk`, reshield.npk);
53166
+ const random = ensureNonNegative(
53167
+ `reshields[${index}].random`,
53168
+ reshield.random
53169
+ );
53170
+ const minAmount = ensureNonNegative(
53171
+ `reshields[${index}].minAmount`,
53172
+ reshield.minAmount
53173
+ );
53174
+ return { npk, random, token, minAmount };
53175
+ }
53176
+ function buildCall(params) {
53177
+ const to = ensureAddress("call.to", params.to);
53178
+ if (typeof params.abi !== "string" || params.abi.trim().length === 0) {
53179
+ throw new AdapterError("call.abi must be a non-empty ABI fragment string");
53180
+ }
53181
+ if (typeof params.functionName !== "string" || params.functionName.trim().length === 0) {
53182
+ throw new AdapterError("call.functionName must be a non-empty string");
53183
+ }
53184
+ if (!Array.isArray(params.args)) {
53185
+ throw new AdapterError("call.args must be an array");
53186
+ }
53187
+ const value = ensureNonNegative("call.value", params.value ?? 0n);
53188
+ let iface;
53189
+ try {
53190
+ iface = new Interface([params.abi]);
53191
+ } catch (err) {
53192
+ throw new AdapterError(
53193
+ `invalid ABI fragment for call: ${err instanceof Error ? err.message : String(err)}`
53194
+ );
53195
+ }
53196
+ let data;
53197
+ try {
53198
+ data = iface.encodeFunctionData(params.functionName, params.args);
53199
+ } catch (err) {
53200
+ throw new AdapterError(
53201
+ `failed to encode ${params.functionName}: ${err instanceof Error ? err.message : String(err)}`
53202
+ );
53203
+ }
53204
+ return { to, data, value };
53205
+ }
53206
+ function buildApproveCall(token, spender, amount) {
53207
+ const normalizedToken = ensureAddress("token", token);
53208
+ const normalizedSpender = ensureAddress("spender", spender);
53209
+ const normalizedAmount = ensureNonNegative("amount", amount);
53210
+ const data = approveInterface.encodeFunctionData("approve", [
53211
+ normalizedSpender,
53212
+ normalizedAmount
53213
+ ]);
53214
+ return {
53215
+ to: normalizedToken,
53216
+ data,
53217
+ value: 0n
53218
+ };
53219
+ }
53220
+ function encodeAdapterExecute(params) {
53221
+ const transactCalldata = ensureHexData(
53222
+ "transactCalldata",
53223
+ params.transactCalldata
53224
+ );
53225
+ const calls = params.calls.map((call, i) => normalizeCall(call, i));
53226
+ const reshields = params.reshields.map(
53227
+ (reshield, i) => normalizeReshield(reshield, i)
53228
+ );
53229
+ const inputTokens = params.inputTokens.map(
53230
+ (token, i) => ensureAddress(`inputTokens[${i}]`, token)
53231
+ );
53232
+ const nonce = ensureNonNegative("nonce", params.nonce);
53233
+ const deadline = ensureNonNegative("deadline", params.deadline);
53234
+ return adapterInterface.encodeFunctionData("execute", [
53235
+ transactCalldata,
53236
+ calls,
53237
+ reshields,
53238
+ inputTokens,
53239
+ nonce,
53240
+ deadline
53241
+ ]);
53242
+ }
53243
+
53077
53244
  // transactions/transaction-planner.ts
53078
53245
  init_process();
53079
53246
  init_buffer();
@@ -53515,12 +53682,20 @@ function createJobReconciler(deps) {
53515
53682
  latest.status
53516
53683
  );
53517
53684
  }
53518
- return null;
53685
+ if (latest.kind === "deposit") {
53686
+ return depositClient.syncPendingDeposit(latest.relayId);
53687
+ }
53688
+ return transactService.syncPendingTransact(latest.relayId);
53519
53689
  }
53520
53690
  if (latest.status !== "succeeded" && isTimedOut(latest)) {
53521
53691
  await markDead(latest, "job timed out");
53522
53692
  const current = await stateStore.getJob(latest.relayId);
53523
- if (current?.status === "succeeded") return null;
53693
+ if (current?.status === "succeeded") {
53694
+ if (current.kind === "deposit") {
53695
+ return depositClient.syncPendingDeposit(current.relayId);
53696
+ }
53697
+ return transactService.syncPendingTransact(current.relayId);
53698
+ }
53524
53699
  throw new ReconcileError("job timed out", "dead");
53525
53700
  }
53526
53701
  if (latest.kind === "deposit") {
@@ -53646,7 +53821,43 @@ function createNoteSyncService(stateStore, options = {}) {
53646
53821
  };
53647
53822
  return spentAt === void 0 ? base : { ...base, spentAt };
53648
53823
  }
53824
+ function tryReconstructAdapterNote(chainId, record, account) {
53825
+ if (!record.adapterNpk || !record.adapterToken || !record.adapterAmount || !record.adapterRandom) {
53826
+ return null;
53827
+ }
53828
+ const eventNpk = parseHexToBigInt(record.adapterNpk);
53829
+ const eventRandom = parseHexToBigInt(record.adapterRandom);
53830
+ const eventAmount = parseHexToBigInt(record.adapterAmount);
53831
+ const eventToken = record.adapterToken.toLowerCase();
53832
+ const derivedNpk = poseidon([account.masterPublicKey, eventRandom]);
53833
+ if (derivedNpk !== eventNpk) {
53834
+ return null;
53835
+ }
53836
+ const commitment = poseidon([eventNpk, BigInt(eventToken), eventAmount]);
53837
+ if (commitment !== parseHexToBigInt(record.commitment)) {
53838
+ return null;
53839
+ }
53840
+ const nullifier = poseidon([account.nullifyingKey, BigInt(record.index)]);
53841
+ const nullifierHex = formatUint256(nullifier);
53842
+ return createNoteRecord({
53843
+ chainId,
53844
+ index: record.index,
53845
+ commitment: record.commitment,
53846
+ token: eventToken,
53847
+ amount: eventAmount,
53848
+ npk: eventNpk,
53849
+ mpk: account.masterPublicKey,
53850
+ random: eventRandom,
53851
+ nullifier: nullifierHex,
53852
+ createdTxHash: record.txHash,
53853
+ createdEventType: record.eventType,
53854
+ createdAt: record.insertedAt != null ? record.insertedAt * 1e3 : void 0
53855
+ });
53856
+ }
53649
53857
  function tryDecryptNoteRecord(chainId, record, account) {
53858
+ if (record.eventType === "adapter_deposit") {
53859
+ return tryReconstructAdapterNote(chainId, record, account);
53860
+ }
53650
53861
  const ciphertext = buildCiphertext(record.ephemeralKey, record.ciphertext);
53651
53862
  if (ciphertext.ephemeralKey === 0n) {
53652
53863
  return null;
@@ -53721,6 +53932,10 @@ function createNoteSyncService(stateStore, options = {}) {
53721
53932
  commitment: record.commitment,
53722
53933
  txHash: record.txHash,
53723
53934
  eventType: record.eventType,
53935
+ adapterNpk: record.adapterNpk,
53936
+ adapterToken: record.adapterToken,
53937
+ adapterAmount: record.adapterAmount,
53938
+ adapterRandom: record.adapterRandom,
53724
53939
  insertedAt: record.insertedAt
53725
53940
  },
53726
53941
  ciphertext: {
@@ -53877,12 +54092,81 @@ function createNoteSyncService(stateStore, options = {}) {
53877
54092
  const noteSet = new Set(allNotes.map((n2) => n2.index));
53878
54093
  const ctMap = new Map(allCiphertexts.map((c) => [c.index, c.payload]));
53879
54094
  const leafMap = new Map(allLeaves.map((l) => [l.index, l]));
54095
+ const adapterRecords = /* @__PURE__ */ new Map();
54096
+ const missingAdapterIndices = [];
54097
+ for (let index = fromIndex; index < leafCount; index++) {
54098
+ const leaf = leafMap.get(index);
54099
+ if (!leaf || leaf.eventType !== "adapter_deposit") continue;
54100
+ if (leaf.adapterNpk && leaf.adapterToken && leaf.adapterAmount && leaf.adapterRandom) {
54101
+ adapterRecords.set(index, {
54102
+ index,
54103
+ commitment: leaf.commitment,
54104
+ txHash: leaf.txHash,
54105
+ insertedAt: leaf.insertedAt,
54106
+ eventType: leaf.eventType ?? "adapter_deposit",
54107
+ adapterNpk: leaf.adapterNpk,
54108
+ adapterToken: leaf.adapterToken,
54109
+ adapterAmount: leaf.adapterAmount,
54110
+ adapterRandom: leaf.adapterRandom
54111
+ });
54112
+ } else {
54113
+ missingAdapterIndices.push(index);
54114
+ }
54115
+ }
54116
+ if (missingAdapterIndices.length > 0) {
54117
+ const missingSet = new Set(missingAdapterIndices);
54118
+ const minIndex = missingAdapterIndices[0];
54119
+ const maxIndex = missingAdapterIndices[missingAdapterIndices.length - 1];
54120
+ let cursor = minIndex;
54121
+ while (cursor <= maxIndex && missingSet.size > 0) {
54122
+ const batch = await indexerClient.fetchCommitmentBatch({
54123
+ chainId,
54124
+ start: cursor,
54125
+ limit
54126
+ });
54127
+ if (batch.commitments.length === 0) break;
54128
+ for (const record of batch.commitments) {
54129
+ if (!missingSet.has(record.index)) continue;
54130
+ adapterRecords.set(record.index, record);
54131
+ missingSet.delete(record.index);
54132
+ }
54133
+ cursor = batch.commitments[batch.commitments.length - 1].index + 1;
54134
+ }
54135
+ }
53880
54136
  for (let index = fromIndex; index < leafCount; index++) {
53881
54137
  if (noteSet.has(index)) continue;
53882
54138
  const ciphertextBytes = ctMap.get(index);
53883
- if (!ciphertextBytes) continue;
53884
54139
  const leaf = leafMap.get(index);
53885
54140
  if (!leaf) continue;
54141
+ if (leaf.eventType === "adapter_deposit") {
54142
+ const record = adapterRecords.get(index);
54143
+ if (record) {
54144
+ const adapterNote = tryReconstructAdapterNote(
54145
+ chainId,
54146
+ record,
54147
+ account
54148
+ );
54149
+ if (adapterNote) {
54150
+ const baseParams = {
54151
+ chainId,
54152
+ index,
54153
+ commitment: record.commitment,
54154
+ token: adapterNote.token,
54155
+ amount: BigInt(adapterNote.value),
54156
+ npk: parseHexToBigInt(adapterNote.npk),
54157
+ mpk: account.masterPublicKey,
54158
+ random: parseHexToBigInt(adapterNote.random),
54159
+ nullifier: adapterNote.nullifier,
54160
+ createdTxHash: record.txHash || leaf.txHash,
54161
+ createdEventType: record.eventType || leaf.eventType,
54162
+ createdAt: record.insertedAt != null ? record.insertedAt * 1e3 : leaf.insertedAt != null ? leaf.insertedAt * 1e3 : void 0
54163
+ };
54164
+ pendingNotes.push({ note: adapterNote, baseParams });
54165
+ }
54166
+ }
54167
+ continue;
54168
+ }
54169
+ if (!ciphertextBytes) continue;
53886
54170
  const ciphertext = decodeCiphertext(ciphertextBytes);
53887
54171
  if (ciphertext.ephemeralKey === 0n) continue;
53888
54172
  let note;
@@ -54073,6 +54357,10 @@ function createNoteSyncService(stateStore, options = {}) {
54073
54357
  };
54074
54358
  }
54075
54359
 
54360
+ // wallet/unlink-wallet.ts
54361
+ init_process();
54362
+ init_buffer();
54363
+
54076
54364
  // wallet/sdk.ts
54077
54365
  init_process();
54078
54366
  init_buffer();
@@ -54343,6 +54631,231 @@ function createSeedService(deps) {
54343
54631
  };
54344
54632
  }
54345
54633
 
54634
+ // wallet/adapter.ts
54635
+ init_process();
54636
+ init_buffer();
54637
+ var DEFAULT_DEADLINE_WINDOW_SECONDS = 600n;
54638
+ var HEX_DATA_REGEX2 = /^0x[0-9a-fA-F]*$/;
54639
+ function ensureHexData2(label, value) {
54640
+ if (typeof value !== "string" || !HEX_DATA_REGEX2.test(value) || value.length % 2 !== 0) {
54641
+ throw new AdapterError(`${label} must be 0x-prefixed even-length hex data`);
54642
+ }
54643
+ return value;
54644
+ }
54645
+ function normalizeCall2(call, index) {
54646
+ const to = ensureAddress(`calls[${index}].to`, call.to);
54647
+ const data = ensureHexData2(`calls[${index}].data`, call.data);
54648
+ if (call.value < 0n) {
54649
+ throw new AdapterError(`calls[${index}].value must be non-negative`);
54650
+ }
54651
+ return {
54652
+ to,
54653
+ data,
54654
+ value: call.value
54655
+ };
54656
+ }
54657
+ function normalizeInputSpec(input, index) {
54658
+ const token = ensureAddress(`inputs[${index}].token`, input.token);
54659
+ if (input.amount <= 0n) {
54660
+ throw new AdapterError(`inputs[${index}].amount must be greater than zero`);
54661
+ }
54662
+ return {
54663
+ token,
54664
+ amount: input.amount
54665
+ };
54666
+ }
54667
+ function normalizeReshieldSpec(reshield, index) {
54668
+ const token = ensureAddress(`reshields[${index}].token`, reshield.token);
54669
+ if (reshield.minAmount < 0n) {
54670
+ throw new AdapterError(
54671
+ `reshields[${index}].minAmount must be non-negative`
54672
+ );
54673
+ }
54674
+ return {
54675
+ token,
54676
+ minAmount: reshield.minAmount
54677
+ };
54678
+ }
54679
+ function randomFieldElement(randomBigintFn) {
54680
+ const value = randomBigintFn() % SNARK_SCALAR_FIELD;
54681
+ return value < 0n ? value + SNARK_SCALAR_FIELD : value;
54682
+ }
54683
+ function createAdapterService(deps) {
54684
+ const planWithdrawalsImpl = deps.planWithdrawalsFn ?? planWithdrawals;
54685
+ const transactImpl = deps.transactFn ?? transact;
54686
+ const randomBigintImpl = deps.randomBigintFn ?? randomBigint;
54687
+ const nowImpl = deps.nowFn ?? Date.now;
54688
+ return {
54689
+ async execute(params, opts, overrides) {
54690
+ ensureChainId(params.chainId);
54691
+ const poolAddress = ensureAddress("poolAddress", params.poolAddress);
54692
+ const adapterAddress = ensureAddress(
54693
+ "adapterAddress",
54694
+ params.adapterAddress
54695
+ );
54696
+ if (!params.inputs.length) {
54697
+ throw new AdapterError("at least one input token is required");
54698
+ }
54699
+ if (!params.calls.length) {
54700
+ throw new AdapterError("at least one adapter call is required");
54701
+ }
54702
+ if (!params.reshields.length) {
54703
+ throw new AdapterError("at least one reshield output is required");
54704
+ }
54705
+ const inputs = params.inputs.map(
54706
+ (input, i) => normalizeInputSpec(input, i)
54707
+ );
54708
+ const seenTokens = /* @__PURE__ */ new Set();
54709
+ for (const input of inputs) {
54710
+ const lower = input.token.toLowerCase();
54711
+ if (seenTokens.has(lower)) {
54712
+ throw new AdapterError(
54713
+ `duplicate input token ${input.token}; combine amounts per token instead`
54714
+ );
54715
+ }
54716
+ seenTokens.add(lower);
54717
+ }
54718
+ const calls = params.calls.map((call, i) => normalizeCall2(call, i));
54719
+ const reshieldSpecs = params.reshields.map(
54720
+ (reshield, i) => normalizeReshieldSpec(reshield, i)
54721
+ );
54722
+ const account = overrides?.account ?? await deps.requireActiveAccount();
54723
+ const signer = overrides?.signer ?? deps.requireSigner(account);
54724
+ const nowSeconds = BigInt(Math.floor(nowImpl() / 1e3));
54725
+ const deadline = params.deadline ?? nowSeconds + DEFAULT_DEADLINE_WINDOW_SECONDS;
54726
+ if (deadline <= nowSeconds) {
54727
+ throw new AdapterError("deadline must be in the future");
54728
+ }
54729
+ const executionCalls = calls;
54730
+ const reshields = reshieldSpecs.map(
54731
+ (reshield) => {
54732
+ const random = randomFieldElement(randomBigintImpl);
54733
+ const npk = poseidon([account.masterPublicKey, random]);
54734
+ return {
54735
+ npk,
54736
+ random,
54737
+ token: reshield.token,
54738
+ minAmount: reshield.minAmount
54739
+ };
54740
+ }
54741
+ );
54742
+ const inputTokens = inputs.map((input) => input.token);
54743
+ const nonce = randomFieldElement(randomBigintImpl);
54744
+ const adapterDataHash = computeAdapterDataHash({
54745
+ calls: executionCalls,
54746
+ reshields,
54747
+ inputTokens,
54748
+ nonce,
54749
+ deadline,
54750
+ chainId: params.chainId
54751
+ });
54752
+ const notes = await deps.stateStore.listNotes({
54753
+ chainId: params.chainId,
54754
+ mpk: formatUint256(account.masterPublicKey),
54755
+ includeSpent: false
54756
+ });
54757
+ const withdrawalPlans = planWithdrawalsImpl(
54758
+ notes,
54759
+ inputs.map((input) => ({
54760
+ token: input.token,
54761
+ amount: input.amount,
54762
+ recipient: adapterAddress
54763
+ })),
54764
+ account.masterPublicKey,
54765
+ account.viewingKeyPair.pubkey
54766
+ );
54767
+ const transactResult = await transactImpl(
54768
+ deps.stateStore,
54769
+ {
54770
+ account,
54771
+ signer,
54772
+ chainId: params.chainId,
54773
+ poolAddress,
54774
+ transactions: withdrawalPlans.map((plan) => ({
54775
+ token: plan.token,
54776
+ inputs: plan.inputs.map((note) => ({ index: note.index })),
54777
+ outputs: plan.outputNotes,
54778
+ withdrawal: plan.withdrawal,
54779
+ adapterDataHash
54780
+ }))
54781
+ },
54782
+ {
54783
+ ...deps.txOpts,
54784
+ skipBroadcast: true,
54785
+ persistJob: false
54786
+ }
54787
+ );
54788
+ const adapterCalldata = encodeAdapterExecute({
54789
+ transactCalldata: transactResult.calldata,
54790
+ calls: executionCalls,
54791
+ reshields,
54792
+ inputTokens,
54793
+ nonce,
54794
+ deadline
54795
+ });
54796
+ if (opts?.skipBroadcast) {
54797
+ return {
54798
+ relayId: transactResult.relayId,
54799
+ adapterCalldata,
54800
+ transactCalldata: transactResult.calldata,
54801
+ transactResult,
54802
+ reshields
54803
+ };
54804
+ }
54805
+ const relayId = generateRelayId("adapter");
54806
+ const submission = await deps.broadcasterClient.submitRelay({
54807
+ clientTxId: relayId,
54808
+ chainId: params.chainId,
54809
+ payload: {
54810
+ kind: "call_data",
54811
+ to: adapterAddress,
54812
+ data: adapterCalldata
54813
+ }
54814
+ });
54815
+ if (!submission.accepted) {
54816
+ throw new AdapterError(submission.message ?? "broadcaster rejected");
54817
+ }
54818
+ await deps.stateStore.putJob({
54819
+ relayId,
54820
+ kind: "adapter",
54821
+ chainId: params.chainId,
54822
+ mpk: formatUint256(account.masterPublicKey),
54823
+ status: "broadcasting",
54824
+ txHash: null,
54825
+ createdAt: nowImpl(),
54826
+ timeoutMs: DEFAULT_JOB_TIMEOUT_MS,
54827
+ poolAddress,
54828
+ calldata: transactResult.calldata,
54829
+ transactions: withdrawalPlans.map((plan, i) => ({
54830
+ token: plan.token,
54831
+ nullifiers: transactResult.transactions[i]?.nullifiers ?? [],
54832
+ predictedCommitments: (transactResult.transactions[i]?.predictedCommitments ?? []).map((hex2) => ({ hex: hex2 })),
54833
+ withdrawal: {
54834
+ amount: plan.withdrawal.amount.toString(),
54835
+ recipient: adapterAddress
54836
+ }
54837
+ })),
54838
+ adapterAddress,
54839
+ adapterCalldata,
54840
+ historyPreview: {
54841
+ kind: "Withdraw",
54842
+ amounts: inputs.map((input) => ({
54843
+ token: input.token,
54844
+ delta: (-input.amount).toString()
54845
+ }))
54846
+ }
54847
+ });
54848
+ return {
54849
+ relayId,
54850
+ adapterCalldata,
54851
+ transactCalldata: transactResult.calldata,
54852
+ transactResult,
54853
+ reshields
54854
+ };
54855
+ }
54856
+ };
54857
+ }
54858
+
54346
54859
  // wallet/burner/service.ts
54347
54860
  init_process();
54348
54861
  init_buffer();
@@ -54692,7 +55205,26 @@ function createWalletSDK(deps, options) {
54692
55205
  }
54693
55206
  return account;
54694
55207
  }
54695
- if (configuredChainId) {
55208
+ function requireSigner(acct) {
55209
+ if (!("spendingKeyPair" in acct)) {
55210
+ throw new Error(
55211
+ "No signer: account has no spending key and no SignerOverride was provided"
55212
+ );
55213
+ }
55214
+ const { spendingKeyPair } = acct;
55215
+ return createSingleKeySigner(
55216
+ spendingKeyPair.privateKey,
55217
+ spendingKeyPair.pubkey
55218
+ );
55219
+ }
55220
+ const adapterService = createAdapterService({
55221
+ stateStore,
55222
+ txOpts,
55223
+ broadcasterClient,
55224
+ requireActiveAccount,
55225
+ requireSigner
55226
+ });
55227
+ if (configuredChainId && options.autoSync !== false) {
54696
55228
  scheduler.start();
54697
55229
  }
54698
55230
  let burnerService;
@@ -54792,10 +55324,13 @@ function createWalletSDK(deps, options) {
54792
55324
  return getBurnerService().sweepToPool(index, params);
54793
55325
  }
54794
55326
  },
55327
+ adapter: {
55328
+ execute: async (params, opts, overrides) => adapterService.execute(params, opts, overrides)
55329
+ },
54795
55330
  balances: {
54796
- async list(chainId) {
55331
+ async list(chainId, overrides) {
54797
55332
  ensureChainId(chainId);
54798
- const account = await requireActiveAccount();
55333
+ const account = overrides?.account ?? await requireActiveAccount();
54799
55334
  const notes = await stateStore.listNotes({
54800
55335
  chainId,
54801
55336
  mpk: formatUint256(account.masterPublicKey),
@@ -54803,15 +55338,15 @@ function createWalletSDK(deps, options) {
54803
55338
  });
54804
55339
  return computeBalances(notes);
54805
55340
  },
54806
- async get(chainId, token) {
54807
- const balances = await this.list(chainId);
55341
+ async get(chainId, token, overrides) {
55342
+ const balances = await this.list(chainId, overrides);
54808
55343
  return balances[token.toLowerCase()] ?? 0n;
54809
55344
  }
54810
55345
  },
54811
55346
  deposit: {
54812
55347
  async request(params) {
54813
55348
  ensureChainId(params.chainId);
54814
- const account = await requireActiveAccount();
55349
+ const account = params.account ?? await requireActiveAccount();
54815
55350
  const notes = params.deposits.map((d2) => {
54816
55351
  const randomBytes5 = rng(32);
54817
55352
  const random = BigInt(
@@ -54834,11 +55369,9 @@ function createWalletSDK(deps, options) {
54834
55369
  });
54835
55370
  },
54836
55371
  async reconcile(relayId) {
54837
- const res = await reconciler.reconcileRelay(relayId);
54838
- if (!res) {
54839
- throw new ReconcileError("job already succeeded", "succeeded");
54840
- }
54841
- const result = res;
55372
+ const result = await reconciler.reconcileRelay(
55373
+ relayId
55374
+ );
54842
55375
  const account = await requireActiveAccount();
54843
55376
  await historyService.rebuildHistory({
54844
55377
  chainId: result.chainId,
@@ -54848,9 +55381,9 @@ function createWalletSDK(deps, options) {
54848
55381
  }
54849
55382
  },
54850
55383
  history: {
54851
- async list(chainId, options2) {
55384
+ async list(chainId, options2, overrides) {
54852
55385
  ensureChainId(chainId);
54853
- const account = await requireActiveAccount();
55386
+ const account = overrides?.account ?? await requireActiveAccount();
54854
55387
  return historyService.getHistory({
54855
55388
  chainId,
54856
55389
  mpk: formatUint256(account.masterPublicKey),
@@ -54875,9 +55408,9 @@ function createWalletSDK(deps, options) {
54875
55408
  });
54876
55409
  await historyService.rebuildHistory({ chainId: note.chainId, mpk });
54877
55410
  },
54878
- async list(chainId) {
55411
+ async list(chainId, overrides) {
54879
55412
  ensureChainId(chainId);
54880
- const account = await requireActiveAccount();
55413
+ const account = overrides?.account ?? await requireActiveAccount();
54881
55414
  return stateStore.listNotes({
54882
55415
  chainId,
54883
55416
  mpk: formatUint256(account.masterPublicKey),
@@ -54886,30 +55419,25 @@ function createWalletSDK(deps, options) {
54886
55419
  }
54887
55420
  },
54888
55421
  transact: {
54889
- async transact(params) {
54890
- const account = await requireActiveAccount();
54891
- const signer = createSingleKeySigner(
54892
- account.spendingKeyPair.privateKey,
54893
- account.spendingKeyPair.pubkey
54894
- );
55422
+ async transact(params, opts, overrides) {
55423
+ const acct = overrides?.account ?? await requireActiveAccount();
55424
+ const signer = overrides?.signer ?? requireSigner(acct);
54895
55425
  return transact(
54896
55426
  stateStore,
54897
55427
  {
54898
- account,
55428
+ account: acct,
54899
55429
  signer,
54900
55430
  chainId: params.chainId,
54901
55431
  poolAddress: params.poolAddress,
54902
55432
  transactions: params.transactions
54903
55433
  },
54904
- txOpts
55434
+ { ...txOpts, ...opts }
54905
55435
  );
54906
55436
  },
54907
55437
  reconcile: async (relayId) => {
54908
- const res = await reconciler.reconcileRelay(relayId);
54909
- if (!res) {
54910
- throw new ReconcileError("job already succeeded", "succeeded");
54911
- }
54912
- const result = res;
55438
+ const result = await reconciler.reconcileRelay(
55439
+ relayId
55440
+ );
54913
55441
  const account = await requireActiveAccount();
54914
55442
  await historyService.rebuildHistory({
54915
55443
  chainId: result.chainId,
@@ -54919,12 +55447,12 @@ function createWalletSDK(deps, options) {
54919
55447
  }
54920
55448
  },
54921
55449
  transfer: {
54922
- async plan(params) {
55450
+ async plan(params, account) {
54923
55451
  ensureChainId(params.chainId);
54924
- const account = await requireActiveAccount();
55452
+ const acct = account ?? await requireActiveAccount();
54925
55453
  const notes = await stateStore.listNotes({
54926
55454
  chainId: params.chainId,
54927
- mpk: formatUint256(account.masterPublicKey),
55455
+ mpk: formatUint256(acct.masterPublicKey),
54928
55456
  includeSpent: false
54929
55457
  });
54930
55458
  return planTransfers(
@@ -54938,12 +55466,13 @@ function createWalletSDK(deps, options) {
54938
55466
  recipientViewingPubKey: parsed.viewingPublicKey
54939
55467
  };
54940
55468
  }),
54941
- account.masterPublicKey,
54942
- account.viewingKeyPair.pubkey
55469
+ acct.masterPublicKey,
55470
+ acct.viewingKeyPair.pubkey
54943
55471
  );
54944
55472
  },
54945
- async execute(plans, params) {
54946
- const account = await requireActiveAccount();
55473
+ async execute(plans, params, overrides) {
55474
+ const acct = overrides?.account ?? await requireActiveAccount();
55475
+ const signer = overrides?.signer ?? requireSigner(acct);
54947
55476
  const transactions = plans.map((plan) => ({
54948
55477
  token: plan.token,
54949
55478
  inputs: plan.inputs.map((note) => ({
@@ -54951,14 +55480,10 @@ function createWalletSDK(deps, options) {
54951
55480
  })),
54952
55481
  outputs: plan.outputNotes
54953
55482
  }));
54954
- const signer = createSingleKeySigner(
54955
- account.spendingKeyPair.privateKey,
54956
- account.spendingKeyPair.pubkey
54957
- );
54958
55483
  const transactResult = await transact(
54959
55484
  stateStore,
54960
55485
  {
54961
- account,
55486
+ account: acct,
54962
55487
  signer,
54963
55488
  chainId: params.chainId,
54964
55489
  poolAddress: params.poolAddress,
@@ -54972,18 +55497,18 @@ function createWalletSDK(deps, options) {
54972
55497
  transactResult
54973
55498
  };
54974
55499
  },
54975
- async send(params) {
54976
- const plans = await this.plan(params);
54977
- return this.execute(plans, params);
55500
+ async send(params, overrides) {
55501
+ const plans = await this.plan(params, overrides?.account);
55502
+ return this.execute(plans, params, overrides);
54978
55503
  }
54979
55504
  },
54980
55505
  withdraw: {
54981
- async plan(params) {
55506
+ async plan(params, account) {
54982
55507
  ensureChainId(params.chainId);
54983
- const account = await requireActiveAccount();
55508
+ const acct = account ?? await requireActiveAccount();
54984
55509
  const notes = await stateStore.listNotes({
54985
55510
  chainId: params.chainId,
54986
- mpk: formatUint256(account.masterPublicKey),
55511
+ mpk: formatUint256(acct.masterPublicKey),
54987
55512
  includeSpent: false
54988
55513
  });
54989
55514
  return planWithdrawals(
@@ -54993,12 +55518,13 @@ function createWalletSDK(deps, options) {
54993
55518
  amount: w.amount,
54994
55519
  recipient: w.recipient
54995
55520
  })),
54996
- account.masterPublicKey,
54997
- account.viewingKeyPair.pubkey
55521
+ acct.masterPublicKey,
55522
+ acct.viewingKeyPair.pubkey
54998
55523
  );
54999
55524
  },
55000
- async execute(plans, params) {
55001
- const account = await requireActiveAccount();
55525
+ async execute(plans, params, overrides) {
55526
+ const acct = overrides?.account ?? await requireActiveAccount();
55527
+ const signer = overrides?.signer ?? requireSigner(acct);
55002
55528
  const transactions = plans.map((plan) => ({
55003
55529
  token: plan.token,
55004
55530
  inputs: plan.inputs.map((note) => ({
@@ -55007,14 +55533,10 @@ function createWalletSDK(deps, options) {
55007
55533
  outputs: plan.outputNotes,
55008
55534
  withdrawal: plan.withdrawal
55009
55535
  }));
55010
- const signer = createSingleKeySigner(
55011
- account.spendingKeyPair.privateKey,
55012
- account.spendingKeyPair.pubkey
55013
- );
55014
55536
  const transactResult = await transact(
55015
55537
  stateStore,
55016
55538
  {
55017
- account,
55539
+ account: acct,
55018
55540
  signer,
55019
55541
  chainId: params.chainId,
55020
55542
  poolAddress: params.poolAddress,
@@ -55028,9 +55550,9 @@ function createWalletSDK(deps, options) {
55028
55550
  transactResult
55029
55551
  };
55030
55552
  },
55031
- async send(params) {
55032
- const plans = await this.plan(params);
55033
- return this.execute(plans, params);
55553
+ async send(params, overrides) {
55554
+ const plans = await this.plan(params, overrides?.account);
55555
+ return this.execute(plans, params, overrides);
55034
55556
  }
55035
55557
  },
55036
55558
  events: {
@@ -55132,10 +55654,353 @@ async function createBrowserWalletSDK(options) {
55132
55654
  }
55133
55655
  };
55134
55656
  }
55657
+
55658
+ // wallet/unlink-wallet.ts
55659
+ var UnlinkWallet = class _UnlinkWallet {
55660
+ /** @internal */
55661
+ sdk;
55662
+ /** Chain ID this wallet operates on. */
55663
+ chainId;
55664
+ /** Pool contract address this wallet transacts with. */
55665
+ poolAddress;
55666
+ constructor(sdk, chainId, poolAddress) {
55667
+ this.sdk = sdk;
55668
+ this.chainId = chainId;
55669
+ this.poolAddress = poolAddress;
55670
+ }
55671
+ /**
55672
+ * Create a new UnlinkWallet instance.
55673
+ *
55674
+ * Handles all initialization internally:
55675
+ * - Resolves environment config (if using `environment` instead of explicit URLs)
55676
+ * - Auto-detects storage (IndexedDB in browser) and rng (crypto.getRandomValues)
55677
+ * - Runs schema migration via `initCore()`
55678
+ * - Creates the internal SDK
55679
+ */
55680
+ static async create(config2) {
55681
+ let gatewayUrl;
55682
+ let poolAddress;
55683
+ let proverConfig = config2.prover;
55684
+ if ("gatewayUrl" in config2) {
55685
+ gatewayUrl = config2.gatewayUrl;
55686
+ poolAddress = config2.poolAddress;
55687
+ if (typeof window !== "undefined" && !config2.prover?.artifactSource?.version) {
55688
+ throw new InitializationError(
55689
+ "prover.artifactSource.version is required in browser when using explicit gatewayUrl mode. Use environment mode or provide a pinned artifact version."
55690
+ );
55691
+ }
55692
+ } else {
55693
+ const envConfig = await fetchEnvironmentConfig(config2.environment);
55694
+ gatewayUrl = envConfig.gatewayUrl;
55695
+ poolAddress = config2.poolAddress ?? envConfig.poolAddress;
55696
+ proverConfig = {
55697
+ artifactSource: {
55698
+ baseUrl: config2.prover?.artifactSource?.baseUrl ?? envConfig.artifactBaseUrl,
55699
+ version: config2.prover?.artifactSource?.version ?? envConfig.artifactVersion,
55700
+ preferLocalFiles: config2.prover?.artifactSource?.preferLocalFiles
55701
+ }
55702
+ };
55703
+ }
55704
+ const storage = config2.storage ?? detectStorage();
55705
+ const rng = config2.rng ?? defaultRng;
55706
+ const fetchImpl = config2.fetch ?? globalThis.fetch;
55707
+ const core = await initCore({ storage, rng });
55708
+ const sdk = createWalletSDK(
55709
+ { core, fetch: fetchImpl },
55710
+ {
55711
+ chainId: config2.chainId,
55712
+ gatewayUrl,
55713
+ chainRpcUrl: config2.chainRpcUrl,
55714
+ prover: proverConfig,
55715
+ autoSync: config2.autoSync
55716
+ }
55717
+ );
55718
+ return new _UnlinkWallet(sdk, config2.chainId, poolAddress);
55719
+ }
55720
+ // ===== Seed Lifecycle =====
55721
+ /** Seed management (create, import, export, delete mnemonic). */
55722
+ get seed() {
55723
+ return this.sdk.seed;
55724
+ }
55725
+ // ===== Account Management =====
55726
+ /** Account management (create, list, switch accounts). */
55727
+ get accounts() {
55728
+ return this.sdk.accounts;
55729
+ }
55730
+ // ===== Core Operations =====
55731
+ /**
55732
+ * Request a deposit (1 or more tokens).
55733
+ * Returns calldata the depositor must submit on-chain via their EOA.
55734
+ */
55735
+ async deposit(params) {
55736
+ return this.sdk.deposit.request({
55737
+ chainId: this.chainId,
55738
+ poolAddress: this.poolAddress,
55739
+ depositor: params.depositor,
55740
+ deposits: params.deposits,
55741
+ account: params.account
55742
+ });
55743
+ }
55744
+ /** Wait for a deposit to be confirmed on-chain. */
55745
+ async confirmDeposit(relayId) {
55746
+ return this.sdk.deposit.reconcile(relayId);
55747
+ }
55748
+ /**
55749
+ * Execute a private transfer (1 or more recipients).
55750
+ * Handles note selection, circuit selection, and proof generation automatically.
55751
+ */
55752
+ async transfer(params, overrides) {
55753
+ return this.sdk.transfer.send(
55754
+ {
55755
+ chainId: this.chainId,
55756
+ poolAddress: this.poolAddress,
55757
+ transfers: params.transfers
55758
+ },
55759
+ overrides
55760
+ );
55761
+ }
55762
+ /**
55763
+ * Get a transfer plan without executing (for preview/confirmation UIs).
55764
+ */
55765
+ async planTransfer(params, account) {
55766
+ return this.sdk.transfer.plan(
55767
+ {
55768
+ chainId: this.chainId,
55769
+ poolAddress: this.poolAddress,
55770
+ transfers: params.transfers
55771
+ },
55772
+ account
55773
+ );
55774
+ }
55775
+ /** Execute a pre-built transfer plan. */
55776
+ async executeTransfer(plans, overrides) {
55777
+ return this.sdk.transfer.execute(
55778
+ plans,
55779
+ { chainId: this.chainId, poolAddress: this.poolAddress },
55780
+ overrides
55781
+ );
55782
+ }
55783
+ /**
55784
+ * Execute a withdrawal (1 or more recipients).
55785
+ * Handles note selection, circuit selection, and proof generation automatically.
55786
+ */
55787
+ async withdraw(params, overrides) {
55788
+ return this.sdk.withdraw.send(
55789
+ {
55790
+ chainId: this.chainId,
55791
+ poolAddress: this.poolAddress,
55792
+ withdrawals: params.withdrawals
55793
+ },
55794
+ overrides
55795
+ );
55796
+ }
55797
+ /**
55798
+ * Get a withdrawal plan without executing (for preview/confirmation UIs).
55799
+ */
55800
+ async planWithdraw(params, account) {
55801
+ return this.sdk.withdraw.plan(
55802
+ {
55803
+ chainId: this.chainId,
55804
+ poolAddress: this.poolAddress,
55805
+ withdrawals: params.withdrawals
55806
+ },
55807
+ account
55808
+ );
55809
+ }
55810
+ /** Execute a pre-built withdrawal plan. */
55811
+ async executeWithdraw(plans, overrides) {
55812
+ return this.sdk.withdraw.execute(
55813
+ plans,
55814
+ { chainId: this.chainId, poolAddress: this.poolAddress },
55815
+ overrides
55816
+ );
55817
+ }
55818
+ /** Wait for a transfer or withdrawal to be confirmed on-chain. */
55819
+ async confirmTransaction(relayId) {
55820
+ return this.sdk.transact.reconcile(relayId);
55821
+ }
55822
+ // ===== Queries =====
55823
+ /**
55824
+ * Get balance for a specific token (defaults to all tokens if no token specified).
55825
+ * @param token Token address. If omitted, returns balance for all tokens via getBalances().
55826
+ */
55827
+ async getBalance(token, overrides) {
55828
+ return this.sdk.balances.get(this.chainId, token, overrides);
55829
+ }
55830
+ /** Get balances for all tokens. */
55831
+ async getBalances(overrides) {
55832
+ return this.sdk.balances.list(this.chainId, overrides);
55833
+ }
55834
+ /** Get transaction history. */
55835
+ async getHistory(options, overrides) {
55836
+ return this.sdk.history.list(this.chainId, options, overrides);
55837
+ }
55838
+ /** Get UTXO notes for the active account (or override account). */
55839
+ async getNotes(overrides) {
55840
+ return this.sdk.notes.list(this.chainId, overrides);
55841
+ }
55842
+ // ===== Sync =====
55843
+ /**
55844
+ * Sync notes from the blockchain.
55845
+ * Automatically resolves the active account (no need to pass it).
55846
+ */
55847
+ async sync(options, overrides) {
55848
+ const account = overrides?.account ?? await this.requireActiveAccount();
55849
+ return this.sdk.sync.syncChain(this.chainId, account, options);
55850
+ }
55851
+ /** Start auto-sync at the given interval (default: 5000ms). */
55852
+ startAutoSync(intervalMs) {
55853
+ void this.sdk.sync.startAutoSync(intervalMs);
55854
+ }
55855
+ /** Stop auto-sync. */
55856
+ stopAutoSync() {
55857
+ this.sdk.sync.stopAutoSync();
55858
+ }
55859
+ // ===== Transaction Status =====
55860
+ /** Get the current status of a transaction. */
55861
+ async getTxStatus(txId) {
55862
+ return this.sdk.tx.getStatus(txId);
55863
+ }
55864
+ /** Start tracking a transaction for status-changed events. */
55865
+ trackTx(txId) {
55866
+ this.sdk.tx.track(txId);
55867
+ }
55868
+ /** Stop tracking a transaction. */
55869
+ untrackTx(txId) {
55870
+ this.sdk.tx.untrack(txId);
55871
+ }
55872
+ // ===== Events =====
55873
+ /**
55874
+ * Subscribe to wallet events (notes-updated, sync-error, tx-status-changed, etc.).
55875
+ * @returns Unsubscribe function.
55876
+ */
55877
+ on(listener) {
55878
+ return this.sdk.events.on(listener);
55879
+ }
55880
+ // ===== Burner =====
55881
+ /**
55882
+ * Burner account operations (BIP-44 derived EOAs for DeFi interactions).
55883
+ * chainId/poolAddress are injected automatically for fund/sweepToPool.
55884
+ */
55885
+ burner = {
55886
+ /** Derive burner address for a given index. */
55887
+ addressOf: (index) => {
55888
+ return this.sdk.burner.addressOf(index);
55889
+ },
55890
+ /** Send a transaction from burner at index. */
55891
+ send: (index, tx) => {
55892
+ return this.sdk.burner.send(index, tx);
55893
+ },
55894
+ /** Export the raw private key (0x-prefixed hex) for wallet import. */
55895
+ exportKey: (index) => {
55896
+ return this.sdk.burner.exportKey(index);
55897
+ },
55898
+ /** Withdraw from shielded pool to fund this burner. */
55899
+ fund: (index, params) => {
55900
+ return this.sdk.burner.fund(index, {
55901
+ chainId: this.chainId,
55902
+ poolAddress: this.poolAddress,
55903
+ token: params.token,
55904
+ amount: params.amount
55905
+ });
55906
+ },
55907
+ /** Approve + deposit tokens from burner back into shielded pool. */
55908
+ sweepToPool: (index, params) => {
55909
+ return this.sdk.burner.sweepToPool(index, {
55910
+ chainId: this.chainId,
55911
+ poolAddress: this.poolAddress,
55912
+ token: params.token,
55913
+ amount: params.amount
55914
+ });
55915
+ },
55916
+ /** Get ERC-20 token balance of any address. */
55917
+ getTokenBalance: (address, token) => {
55918
+ return this.sdk.burner.getTokenBalance(address, token);
55919
+ },
55920
+ /** Get native ETH balance of any address. */
55921
+ getBalance: (address) => {
55922
+ return this.sdk.burner.getBalance(address);
55923
+ }
55924
+ };
55925
+ // ===== Adapter =====
55926
+ /**
55927
+ * Private DeFi adapter operations.
55928
+ * chainId/poolAddress are injected automatically.
55929
+ */
55930
+ adapter = {
55931
+ /**
55932
+ * Execute an atomic unshield -> call(s) -> reshield flow through an adapter.
55933
+ */
55934
+ execute: (params, opts, overrides) => {
55935
+ return this.sdk.adapter.execute(
55936
+ {
55937
+ chainId: this.chainId,
55938
+ poolAddress: this.poolAddress,
55939
+ adapterAddress: params.adapterAddress,
55940
+ inputs: params.inputs,
55941
+ calls: params.calls,
55942
+ reshields: params.reshields,
55943
+ deadline: params.deadline
55944
+ },
55945
+ opts,
55946
+ overrides
55947
+ );
55948
+ }
55949
+ };
55950
+ // ===== Advanced =====
55951
+ /**
55952
+ * Advanced escape hatch for raw JoinSplit transaction building.
55953
+ * Use this for custom transaction construction (e.g. swap adapters).
55954
+ */
55955
+ advanced = {
55956
+ /** Build and submit raw JoinSplit transactions. */
55957
+ transact: (params, opts) => {
55958
+ return this.sdk.transact.transact(
55959
+ {
55960
+ chainId: this.chainId,
55961
+ poolAddress: this.poolAddress,
55962
+ transactions: params.transactions
55963
+ },
55964
+ opts
55965
+ );
55966
+ },
55967
+ /** Wait for a raw transaction to be confirmed on-chain. */
55968
+ reconcile: (relayId) => {
55969
+ return this.sdk.transact.reconcile(relayId);
55970
+ }
55971
+ };
55972
+ // ===== Private Helpers =====
55973
+ async requireActiveAccount() {
55974
+ const account = await this.sdk.accounts.getActive();
55975
+ if (!account) {
55976
+ throw new Error("No active account. Create an account first.");
55977
+ }
55978
+ return account;
55979
+ }
55980
+ };
55981
+ function detectStorage() {
55982
+ if (typeof globalThis.indexedDB !== "undefined" && typeof globalThis.window !== "undefined") {
55983
+ return createIndexedDbStorage({ name: "unlink-wallet" });
55984
+ }
55985
+ throw new InitializationError(
55986
+ "No storage backend detected. In Node.js, provide a storage option (e.g. createSqliteStorage or createMemoryStorage)."
55987
+ );
55988
+ }
55989
+ var defaultRng = (n2) => {
55990
+ if (!globalThis.crypto?.getRandomValues) {
55991
+ throw new InitializationError(
55992
+ "crypto.getRandomValues unavailable. Provide a custom rng in config."
55993
+ );
55994
+ }
55995
+ return globalThis.crypto.getRandomValues(new Uint8Array(n2));
55996
+ };
55135
55997
  export {
55998
+ ADAPTER_EXECUTE_ABI,
55999
+ AdapterError,
55136
56000
  CORE_SCHEMA_VERSION,
55137
56001
  CoreError,
55138
56002
  DEFAULT_JOB_TIMEOUT_MS,
56003
+ DEPOSIT_ABI,
55139
56004
  ETH_TOKEN,
55140
56005
  FieldSize,
55141
56006
  Hex,
@@ -55152,9 +56017,15 @@ export {
55152
56017
  ReconcileError,
55153
56018
  SNARK_SCALAR_FIELD,
55154
56019
  SchemaMismatchError,
56020
+ UnlinkWallet,
55155
56021
  ValidationError,
55156
56022
  assertNonNegative,
56023
+ buildApproveCall,
56024
+ buildCall,
56025
+ computeAdapterDataHash,
55157
56026
  computeBalances,
56027
+ computeBoundParamsHash,
56028
+ computeCommitment,
55158
56029
  computeMasterPublicKey,
55159
56030
  computeNullifyingKey,
55160
56031
  createBroadcasterClient,
@@ -55183,10 +56054,13 @@ export {
55183
56054
  deriveAccount,
55184
56055
  deriveAccountFromMnemonic,
55185
56056
  deriveAccountKeys,
56057
+ deriveNpk,
55186
56058
  deriveSpendingKeyPair,
55187
56059
  derivePublicKey as deriveSpendingPublicKey,
55188
56060
  deriveViewingKeyPair,
56061
+ encodeAdapterExecute,
55189
56062
  encodeAddress,
56063
+ encryptNote,
55190
56064
  ensureAddress,
55191
56065
  ensureBigIntString,
55192
56066
  ensureChainId,