@unlink-xyz/react 0.1.3-canary.5e5993b → 0.1.3-canary.7a2ea6a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5292,6 +5292,12 @@ var ReconcileError = class extends CoreError {
5292
5292
  this.status = status;
5293
5293
  }
5294
5294
  };
5295
+ var AdapterError = class extends CoreError {
5296
+ constructor(message) {
5297
+ super(message);
5298
+ this.name = "AdapterError";
5299
+ }
5300
+ };
5295
5301
  init_process();
5296
5302
  init_buffer();
5297
5303
  var RESERVED_PREFIXES = [
@@ -9444,7 +9450,12 @@ var VALID_STATUSES = [
9444
9450
  "failed",
9445
9451
  "dead"
9446
9452
  ];
9447
- var VALID_KINDS = ["deposit", "transfer", "withdraw"];
9453
+ var VALID_KINDS = [
9454
+ "deposit",
9455
+ "transfer",
9456
+ "withdraw",
9457
+ "adapter"
9458
+ ];
9448
9459
  function assertStatus(status) {
9449
9460
  if (!VALID_STATUSES.includes(status)) {
9450
9461
  throw new CoreError(`invalid job status: ${status}`);
@@ -9524,6 +9535,12 @@ function validateDepositRecord(job) {
9524
9535
  }
9525
9536
  }
9526
9537
  }
9538
+ function validateAdapterRecord(job) {
9539
+ ensureAddress("adapter address", job.adapterAddress);
9540
+ if (!job.adapterCalldata) {
9541
+ throw new CoreError("adapterCalldata is required for adapter record");
9542
+ }
9543
+ }
9527
9544
  function validateJob(job) {
9528
9545
  if (!job.relayId) {
9529
9546
  throw new CoreError("relayId is required");
@@ -9543,6 +9560,9 @@ function validateJob(job) {
9543
9560
  validateDepositRecord(job);
9544
9561
  } else {
9545
9562
  validatePoolTransactionRecord(job);
9563
+ if (job.kind === "adapter") {
9564
+ validateAdapterRecord(job);
9565
+ }
9546
9566
  }
9547
9567
  }
9548
9568
  function buildJobKey(relayId) {
@@ -10047,6 +10067,9 @@ function randomBigint(bytes2 = 32) {
10047
10067
  function randomHex(bytes2) {
10048
10068
  return `0x${randomBigint(bytes2).toString(16).padStart(bytes2 * 2, "0")}`;
10049
10069
  }
10070
+ function generateRelayId(prefix) {
10071
+ return globalThis.crypto?.randomUUID?.() ?? `${prefix}-${randomHex(16).slice(2)}`;
10072
+ }
10050
10073
  function normalizeAddress(value) {
10051
10074
  return ensureAddress("address", value);
10052
10075
  }
@@ -36037,9 +36060,6 @@ function buildDepositCalldata(depositor, processedNotes) {
36037
36060
  }))
36038
36061
  ]);
36039
36062
  }
36040
- function generateRelayId(prefix) {
36041
- return globalThis.crypto?.randomUUID?.() ?? `${prefix}-${Date.now().toString(16)}`;
36042
- }
36043
36063
  async function deposit(store, req) {
36044
36064
  if (!req.notes?.length) {
36045
36065
  throw new ValidationError("At least one note is required for deposit");
@@ -53692,6 +53712,28 @@ function computeBoundParamsHash(chainId, poolAddress, adapterDataHash = 0n) {
53692
53712
  );
53693
53713
  return parseHexToBigInt(keccak256(encoded)) % SNARK_SCALAR_FIELD;
53694
53714
  }
53715
+ function computeAdapterDataHash(params) {
53716
+ const coder = AbiCoder.defaultAbiCoder();
53717
+ const encoded = coder.encode(
53718
+ [
53719
+ "tuple(address to, bytes data, uint256 value)[]",
53720
+ "tuple(uint256 npk, uint256 random, address token, uint256 minAmount)[]",
53721
+ "address[]",
53722
+ "uint256",
53723
+ "uint256",
53724
+ "uint256"
53725
+ ],
53726
+ [
53727
+ params.calls,
53728
+ params.reshields,
53729
+ params.inputTokens,
53730
+ params.nonce,
53731
+ params.deadline,
53732
+ BigInt(params.chainId)
53733
+ ]
53734
+ );
53735
+ return parseHexToBigInt(keccak256(encoded)) % SNARK_SCALAR_FIELD;
53736
+ }
53695
53737
  async function buildSingleTransactionProof(store, account, signer, chainId, poolAddress, tx, trees, baseIndex, opts) {
53696
53738
  if (!tx.inputs?.length)
53697
53739
  throw new ValidationError("at least one input note is required");
@@ -53873,7 +53915,7 @@ async function transact(store, req, opts) {
53873
53915
  ciphertexts: r2.ciphertexts
53874
53916
  }))
53875
53917
  ]);
53876
- const relayId = globalThis.crypto?.randomUUID?.() ?? `tx-${Date.now().toString(16)}`;
53918
+ const relayId = generateRelayId("tx");
53877
53919
  const hasAnyWithdrawal = results.some((r2) => r2.withdrawal.amount > 0n);
53878
53920
  const historyKind = hasAnyWithdrawal ? "Withdraw" : "Send";
53879
53921
  const deltasByToken = /* @__PURE__ */ new Map();
@@ -53960,11 +54002,13 @@ async function transact(store, req, opts) {
53960
54002
  throw new CoreError("broadcaster relay timed out");
53961
54003
  }
53962
54004
  }
53963
- await store.putJob({
53964
- ...job,
53965
- status: "broadcasting",
53966
- txHash
53967
- });
54005
+ if (opts.persistJob !== false) {
54006
+ await store.putJob({
54007
+ ...job,
54008
+ status: "broadcasting",
54009
+ txHash
54010
+ });
54011
+ }
53968
54012
  const transactionResults = results.map((r2) => ({
53969
54013
  proof: r2.proof,
53970
54014
  witnesses: r2.witnesses,
@@ -53979,7 +54023,7 @@ async function transact(store, req, opts) {
53979
54023
  }
53980
54024
  async function syncTransact(store, relayId, opts) {
53981
54025
  const record = await store.getJob(relayId);
53982
- if (!record || record.kind !== "transfer" && record.kind !== "withdraw")
54026
+ if (!record || record.kind !== "transfer" && record.kind !== "withdraw" && record.kind !== "adapter")
53983
54027
  throw new CoreError(`unknown pool transaction relay ${relayId}`);
53984
54028
  const job = record;
53985
54029
  const serviceConfig = createServiceConfig(opts.gatewayUrl);
@@ -54083,6 +54127,70 @@ async function syncTransact(store, relayId, opts) {
54083
54127
  }
54084
54128
  init_process();
54085
54129
  init_buffer();
54130
+ var ADAPTER_EXECUTE_ABI = [
54131
+ "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)"
54132
+ ];
54133
+ var adapterInterface = new Interface(ADAPTER_EXECUTE_ABI);
54134
+ var approveInterface = new Interface([
54135
+ "function approve(address spender, uint256 amount)"
54136
+ ]);
54137
+ var HEX_DATA_REGEX = /^0x[0-9a-fA-F]*$/;
54138
+ function ensureNonNegative(label, value) {
54139
+ if (value < 0n) {
54140
+ throw new AdapterError(`${label} must be non-negative`);
54141
+ }
54142
+ return value;
54143
+ }
54144
+ function ensureHexData(label, value) {
54145
+ if (typeof value !== "string" || !HEX_DATA_REGEX.test(value) || value.length % 2 !== 0) {
54146
+ throw new AdapterError(`${label} must be 0x-prefixed even-length hex data`);
54147
+ }
54148
+ return value;
54149
+ }
54150
+ function normalizeCall(call, index) {
54151
+ const to = ensureAddress(`calls[${index}].to`, call.to);
54152
+ const data = ensureHexData(`calls[${index}].data`, call.data);
54153
+ const value = ensureNonNegative(`calls[${index}].value`, call.value);
54154
+ return { to, data, value };
54155
+ }
54156
+ function normalizeReshield(reshield, index) {
54157
+ const token = ensureAddress(`reshields[${index}].token`, reshield.token);
54158
+ const npk = ensureNonNegative(`reshields[${index}].npk`, reshield.npk);
54159
+ const random = ensureNonNegative(
54160
+ `reshields[${index}].random`,
54161
+ reshield.random
54162
+ );
54163
+ const minAmount = ensureNonNegative(
54164
+ `reshields[${index}].minAmount`,
54165
+ reshield.minAmount
54166
+ );
54167
+ return { npk, random, token, minAmount };
54168
+ }
54169
+ function encodeAdapterExecute(params) {
54170
+ const transactCalldata = ensureHexData(
54171
+ "transactCalldata",
54172
+ params.transactCalldata
54173
+ );
54174
+ const calls = params.calls.map((call, i) => normalizeCall(call, i));
54175
+ const reshields = params.reshields.map(
54176
+ (reshield, i) => normalizeReshield(reshield, i)
54177
+ );
54178
+ const inputTokens = params.inputTokens.map(
54179
+ (token, i) => ensureAddress(`inputTokens[${i}]`, token)
54180
+ );
54181
+ const nonce = ensureNonNegative("nonce", params.nonce);
54182
+ const deadline = ensureNonNegative("deadline", params.deadline);
54183
+ return adapterInterface.encodeFunctionData("execute", [
54184
+ transactCalldata,
54185
+ calls,
54186
+ reshields,
54187
+ inputTokens,
54188
+ nonce,
54189
+ deadline
54190
+ ]);
54191
+ }
54192
+ init_process();
54193
+ init_buffer();
54086
54194
  init_process();
54087
54195
  init_buffer();
54088
54196
  var MAX_CIRCUIT_INPUTS = Math.max(
@@ -55447,6 +55555,229 @@ function createSeedService(deps) {
55447
55555
  }
55448
55556
  init_process();
55449
55557
  init_buffer();
55558
+ var DEFAULT_DEADLINE_WINDOW_SECONDS = 600n;
55559
+ var HEX_DATA_REGEX2 = /^0x[0-9a-fA-F]*$/;
55560
+ function ensureHexData2(label, value) {
55561
+ if (typeof value !== "string" || !HEX_DATA_REGEX2.test(value) || value.length % 2 !== 0) {
55562
+ throw new AdapterError(`${label} must be 0x-prefixed even-length hex data`);
55563
+ }
55564
+ return value;
55565
+ }
55566
+ function normalizeCall2(call, index) {
55567
+ const to = ensureAddress(`calls[${index}].to`, call.to);
55568
+ const data = ensureHexData2(`calls[${index}].data`, call.data);
55569
+ if (call.value < 0n) {
55570
+ throw new AdapterError(`calls[${index}].value must be non-negative`);
55571
+ }
55572
+ return {
55573
+ to,
55574
+ data,
55575
+ value: call.value
55576
+ };
55577
+ }
55578
+ function normalizeInputSpec(input, index) {
55579
+ const token = ensureAddress(`inputs[${index}].token`, input.token);
55580
+ if (input.amount <= 0n) {
55581
+ throw new AdapterError(`inputs[${index}].amount must be greater than zero`);
55582
+ }
55583
+ return {
55584
+ token,
55585
+ amount: input.amount
55586
+ };
55587
+ }
55588
+ function normalizeReshieldSpec(reshield, index) {
55589
+ const token = ensureAddress(`reshields[${index}].token`, reshield.token);
55590
+ if (reshield.minAmount < 0n) {
55591
+ throw new AdapterError(
55592
+ `reshields[${index}].minAmount must be non-negative`
55593
+ );
55594
+ }
55595
+ return {
55596
+ token,
55597
+ minAmount: reshield.minAmount
55598
+ };
55599
+ }
55600
+ function randomFieldElement(randomBigintFn) {
55601
+ const value = randomBigintFn() % SNARK_SCALAR_FIELD;
55602
+ return value < 0n ? value + SNARK_SCALAR_FIELD : value;
55603
+ }
55604
+ function createAdapterService(deps) {
55605
+ const planWithdrawalsImpl = deps.planWithdrawalsFn ?? planWithdrawals;
55606
+ const transactImpl = deps.transactFn ?? transact;
55607
+ const randomBigintImpl = deps.randomBigintFn ?? randomBigint;
55608
+ const nowImpl = deps.nowFn ?? Date.now;
55609
+ return {
55610
+ async execute(params, opts, overrides) {
55611
+ ensureChainId(params.chainId);
55612
+ const poolAddress = ensureAddress("poolAddress", params.poolAddress);
55613
+ const adapterAddress = ensureAddress(
55614
+ "adapterAddress",
55615
+ params.adapterAddress
55616
+ );
55617
+ if (!params.inputs.length) {
55618
+ throw new AdapterError("at least one input token is required");
55619
+ }
55620
+ if (!params.calls.length) {
55621
+ throw new AdapterError("at least one adapter call is required");
55622
+ }
55623
+ if (!params.reshields.length) {
55624
+ throw new AdapterError("at least one reshield output is required");
55625
+ }
55626
+ const inputs = params.inputs.map(
55627
+ (input, i) => normalizeInputSpec(input, i)
55628
+ );
55629
+ const seenTokens = /* @__PURE__ */ new Set();
55630
+ for (const input of inputs) {
55631
+ const lower = input.token.toLowerCase();
55632
+ if (seenTokens.has(lower)) {
55633
+ throw new AdapterError(
55634
+ `duplicate input token ${input.token}; combine amounts per token instead`
55635
+ );
55636
+ }
55637
+ seenTokens.add(lower);
55638
+ }
55639
+ const calls = params.calls.map((call, i) => normalizeCall2(call, i));
55640
+ const reshieldSpecs = params.reshields.map(
55641
+ (reshield, i) => normalizeReshieldSpec(reshield, i)
55642
+ );
55643
+ const account = overrides?.account ?? await deps.requireActiveAccount();
55644
+ const signer = overrides?.signer ?? deps.requireSigner(account);
55645
+ const nowSeconds = BigInt(Math.floor(nowImpl() / 1e3));
55646
+ const deadline = params.deadline ?? nowSeconds + DEFAULT_DEADLINE_WINDOW_SECONDS;
55647
+ if (deadline <= nowSeconds) {
55648
+ throw new AdapterError("deadline must be in the future");
55649
+ }
55650
+ const executionCalls = calls;
55651
+ const reshields = reshieldSpecs.map(
55652
+ (reshield) => {
55653
+ const random = randomFieldElement(randomBigintImpl);
55654
+ const npk = poseidon([account.masterPublicKey, random]);
55655
+ return {
55656
+ npk,
55657
+ random,
55658
+ token: reshield.token,
55659
+ minAmount: reshield.minAmount
55660
+ };
55661
+ }
55662
+ );
55663
+ const inputTokens = inputs.map((input) => input.token);
55664
+ const nonce = randomFieldElement(randomBigintImpl);
55665
+ const adapterDataHash = computeAdapterDataHash({
55666
+ calls: executionCalls,
55667
+ reshields,
55668
+ inputTokens,
55669
+ nonce,
55670
+ deadline,
55671
+ chainId: params.chainId
55672
+ });
55673
+ const notes = await deps.stateStore.listNotes({
55674
+ chainId: params.chainId,
55675
+ mpk: formatUint256(account.masterPublicKey),
55676
+ includeSpent: false
55677
+ });
55678
+ const withdrawalPlans = planWithdrawalsImpl(
55679
+ notes,
55680
+ inputs.map((input) => ({
55681
+ token: input.token,
55682
+ amount: input.amount,
55683
+ recipient: adapterAddress
55684
+ })),
55685
+ account.masterPublicKey,
55686
+ account.viewingKeyPair.pubkey
55687
+ );
55688
+ const transactResult = await transactImpl(
55689
+ deps.stateStore,
55690
+ {
55691
+ account,
55692
+ signer,
55693
+ chainId: params.chainId,
55694
+ poolAddress,
55695
+ transactions: withdrawalPlans.map((plan) => ({
55696
+ token: plan.token,
55697
+ inputs: plan.inputs.map((note) => ({ index: note.index })),
55698
+ outputs: plan.outputNotes,
55699
+ withdrawal: plan.withdrawal,
55700
+ adapterDataHash
55701
+ }))
55702
+ },
55703
+ {
55704
+ ...deps.txOpts,
55705
+ skipBroadcast: true,
55706
+ persistJob: false
55707
+ }
55708
+ );
55709
+ const adapterCalldata = encodeAdapterExecute({
55710
+ transactCalldata: transactResult.calldata,
55711
+ calls: executionCalls,
55712
+ reshields,
55713
+ inputTokens,
55714
+ nonce,
55715
+ deadline
55716
+ });
55717
+ if (opts?.skipBroadcast) {
55718
+ return {
55719
+ relayId: transactResult.relayId,
55720
+ adapterCalldata,
55721
+ transactCalldata: transactResult.calldata,
55722
+ transactResult,
55723
+ reshields
55724
+ };
55725
+ }
55726
+ const relayId = generateRelayId("adapter");
55727
+ const submission = await deps.broadcasterClient.submitRelay({
55728
+ clientTxId: relayId,
55729
+ chainId: params.chainId,
55730
+ payload: {
55731
+ kind: "call_data",
55732
+ to: adapterAddress,
55733
+ data: adapterCalldata
55734
+ }
55735
+ });
55736
+ if (!submission.accepted) {
55737
+ throw new AdapterError(submission.message ?? "broadcaster rejected");
55738
+ }
55739
+ await deps.stateStore.putJob({
55740
+ relayId,
55741
+ kind: "adapter",
55742
+ chainId: params.chainId,
55743
+ mpk: formatUint256(account.masterPublicKey),
55744
+ status: "broadcasting",
55745
+ txHash: null,
55746
+ createdAt: nowImpl(),
55747
+ timeoutMs: DEFAULT_JOB_TIMEOUT_MS,
55748
+ poolAddress,
55749
+ calldata: transactResult.calldata,
55750
+ transactions: withdrawalPlans.map((plan, i) => ({
55751
+ token: plan.token,
55752
+ nullifiers: transactResult.transactions[i]?.nullifiers ?? [],
55753
+ predictedCommitments: (transactResult.transactions[i]?.predictedCommitments ?? []).map((hex2) => ({ hex: hex2 })),
55754
+ withdrawal: {
55755
+ amount: plan.withdrawal.amount.toString(),
55756
+ recipient: adapterAddress
55757
+ }
55758
+ })),
55759
+ adapterAddress,
55760
+ adapterCalldata,
55761
+ historyPreview: {
55762
+ kind: "Withdraw",
55763
+ amounts: inputs.map((input) => ({
55764
+ token: input.token,
55765
+ delta: (-input.amount).toString()
55766
+ }))
55767
+ }
55768
+ });
55769
+ return {
55770
+ relayId,
55771
+ adapterCalldata,
55772
+ transactCalldata: transactResult.calldata,
55773
+ transactResult,
55774
+ reshields
55775
+ };
55776
+ }
55777
+ };
55778
+ }
55779
+ init_process();
55780
+ init_buffer();
55450
55781
  var BIP44_ETH_PREFIX = "m/44'/60'/0'/0";
55451
55782
  var ERC20_BALANCE_OF = "function balanceOf(address) view returns (uint256)";
55452
55783
  function createBurnerService(deps) {
@@ -55803,7 +56134,14 @@ function createWalletSDK(deps, options) {
55803
56134
  spendingKeyPair.pubkey
55804
56135
  );
55805
56136
  }
55806
- if (configuredChainId) {
56137
+ const adapterService = createAdapterService({
56138
+ stateStore,
56139
+ txOpts,
56140
+ broadcasterClient,
56141
+ requireActiveAccount,
56142
+ requireSigner
56143
+ });
56144
+ if (configuredChainId && options.autoSync !== false) {
55807
56145
  scheduler.start();
55808
56146
  }
55809
56147
  let burnerService;
@@ -55903,6 +56241,9 @@ function createWalletSDK(deps, options) {
55903
56241
  return getBurnerService().sweepToPool(index, params);
55904
56242
  }
55905
56243
  },
56244
+ adapter: {
56245
+ execute: async (params, opts, overrides) => adapterService.execute(params, opts, overrides)
56246
+ },
55906
56247
  balances: {
55907
56248
  async list(chainId, overrides) {
55908
56249
  ensureChainId(chainId);
@@ -56234,7 +56575,8 @@ var UnlinkWallet = class _UnlinkWallet {
56234
56575
  chainId: config22.chainId,
56235
56576
  gatewayUrl,
56236
56577
  chainRpcUrl: config22.chainRpcUrl,
56237
- prover: proverConfig
56578
+ prover: proverConfig,
56579
+ autoSync: config22.autoSync
56238
56580
  }
56239
56581
  );
56240
56582
  return new _UnlinkWallet(sdk, config22.chainId, poolAddress);
@@ -56444,6 +56786,31 @@ var UnlinkWallet = class _UnlinkWallet {
56444
56786
  return this.sdk.burner.getBalance(address);
56445
56787
  }
56446
56788
  };
56789
+ // ===== Adapter =====
56790
+ /**
56791
+ * Private DeFi adapter operations.
56792
+ * chainId/poolAddress are injected automatically.
56793
+ */
56794
+ adapter = {
56795
+ /**
56796
+ * Execute an atomic unshield -> call(s) -> reshield flow through an adapter.
56797
+ */
56798
+ execute: (params, opts, overrides) => {
56799
+ return this.sdk.adapter.execute(
56800
+ {
56801
+ chainId: this.chainId,
56802
+ poolAddress: this.poolAddress,
56803
+ adapterAddress: params.adapterAddress,
56804
+ inputs: params.inputs,
56805
+ calls: params.calls,
56806
+ reshields: params.reshields,
56807
+ deadline: params.deadline
56808
+ },
56809
+ opts,
56810
+ overrides
56811
+ );
56812
+ }
56813
+ };
56447
56814
  // ===== Advanced =====
56448
56815
  /**
56449
56816
  * Advanced escape hatch for raw JoinSplit transaction building.