@unlink-xyz/core 0.1.5 → 0.1.7-canary.252b8ea

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 (38) hide show
  1. package/dist/account/account.d.ts +1 -1
  2. package/dist/account/account.d.ts.map +1 -1
  3. package/dist/browser/index.js +476 -215
  4. package/dist/browser/index.js.map +1 -1
  5. package/dist/browser/wallet/index.js +427 -213
  6. package/dist/browser/wallet/index.js.map +1 -1
  7. package/dist/clients/http.d.ts.map +1 -1
  8. package/dist/config.d.ts +20 -8
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/index.d.ts +3 -3
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +399 -138
  13. package/dist/index.js.map +1 -1
  14. package/dist/transactions/adapter.d.ts +34 -1
  15. package/dist/transactions/adapter.d.ts.map +1 -1
  16. package/dist/transactions/index.d.ts +1 -1
  17. package/dist/transactions/index.d.ts.map +1 -1
  18. package/dist/tsconfig.tsbuildinfo +1 -1
  19. package/dist/utils/async.js.map +1 -1
  20. package/dist/utils/validators.d.ts +1 -1
  21. package/dist/wallet/adapter.d.ts +2 -2
  22. package/dist/wallet/adapter.d.ts.map +1 -1
  23. package/dist/wallet/burner/service.d.ts +1 -0
  24. package/dist/wallet/burner/service.d.ts.map +1 -1
  25. package/dist/wallet/burner/types.d.ts +2 -2
  26. package/dist/wallet/burner/types.d.ts.map +1 -1
  27. package/dist/wallet/index.d.ts +2 -2
  28. package/dist/wallet/index.d.ts.map +1 -1
  29. package/dist/wallet/index.js +350 -136
  30. package/dist/wallet/index.js.map +1 -1
  31. package/dist/wallet/sdk.d.ts +8 -9
  32. package/dist/wallet/sdk.d.ts.map +1 -1
  33. package/dist/wallet/types.d.ts +61 -52
  34. package/dist/wallet/types.d.ts.map +1 -1
  35. package/dist/wallet/{unlink-wallet.d.ts → unlink.d.ts} +44 -38
  36. package/dist/wallet/unlink.d.ts.map +1 -0
  37. package/package.json +1 -1
  38. package/dist/wallet/unlink-wallet.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -3675,9 +3675,9 @@ var Hex = class _Hex {
3675
3675
  // keys/address.ts
3676
3676
  import { bech32m } from "@scure/base";
3677
3677
  var VERSION = 1;
3678
- var LIMIT = 127;
3678
+ var LIMIT = 130;
3679
3679
  var ALL_CHAINS = "ffffffffffffffff";
3680
- var PREFIX = "0zk";
3680
+ var PREFIX = "unlink";
3681
3681
  var SALT = new TextEncoder().encode("unlink");
3682
3682
  function xorWithSalt(hex) {
3683
3683
  const bytes = Hex.toBytes(hex);
@@ -3821,7 +3821,7 @@ function parseZkAddress(value) {
3821
3821
  };
3822
3822
  } catch (err) {
3823
3823
  throw new ValidationError(
3824
- `Invalid ZK address (expected 0zk1... format): ${err instanceof Error ? err.message : "unknown error"}`
3824
+ `Invalid ZK address (expected unlink1... format): ${err instanceof Error ? err.message : "unknown error"}`
3825
3825
  );
3826
3826
  }
3827
3827
  }
@@ -5333,29 +5333,41 @@ function createJsonHttpClient(baseUrl, deps) {
5333
5333
  fetch: fetchImpl,
5334
5334
  // Disable ky's automatic error throwing to prevent browser DevTools
5335
5335
  // from logging expected 404s as network errors
5336
- throwHttpErrors: false
5336
+ throwHttpErrors: false,
5337
+ retry: 0
5337
5338
  });
5339
+ const RETRYABLE_STATUSES = [502, 503, 504];
5340
+ const MAX_RETRIES = 3;
5341
+ const BASE_DELAY_MS = 500;
5338
5342
  return {
5339
5343
  async request(opts) {
5340
5344
  let res;
5341
- try {
5342
- res = await api(opts.path.replace(/^\//, ""), {
5343
- method: opts.method,
5344
- searchParams: opts.query,
5345
- json: opts.json,
5346
- body: opts.body,
5347
- headers: opts.headers,
5348
- signal: opts.signal
5349
- });
5350
- } catch (err) {
5351
- if (err instanceof TimeoutError) {
5352
- throw new HttpError("HTTP timeout", 408, null);
5345
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
5346
+ try {
5347
+ res = await api(opts.path.replace(/^\//, ""), {
5348
+ method: opts.method,
5349
+ searchParams: opts.query,
5350
+ json: opts.json,
5351
+ body: opts.body,
5352
+ headers: opts.headers,
5353
+ signal: opts.signal
5354
+ });
5355
+ } catch (err) {
5356
+ if (err instanceof TimeoutError) {
5357
+ throw new HttpError("HTTP timeout", 408, null);
5358
+ }
5359
+ throw new HttpError(
5360
+ err instanceof Error ? err.message : "Network error",
5361
+ 0,
5362
+ null
5363
+ );
5353
5364
  }
5354
- throw new HttpError(
5355
- err instanceof Error ? err.message : "Network error",
5356
- 0,
5357
- null
5358
- );
5365
+ if (RETRYABLE_STATUSES.includes(res.status) && attempt < MAX_RETRIES) {
5366
+ const delay = BASE_DELAY_MS * 2 ** attempt + Math.random() * 200;
5367
+ await new Promise((r2) => setTimeout(r2, delay));
5368
+ continue;
5369
+ }
5370
+ break;
5359
5371
  }
5360
5372
  if (!res.ok) {
5361
5373
  const body = await readErrorBodySafe(res);
@@ -5556,64 +5568,115 @@ var Runtime = {
5556
5568
  };
5557
5569
 
5558
5570
  // config.ts
5571
+ var DEFAULT_RPC_URLS = {
5572
+ "monad-testnet": "https://testnet-rpc.monad.xyz",
5573
+ "monad-testnet-staging": "https://testnet-rpc.monad.xyz"
5574
+ };
5559
5575
  var CONFIG_URL = "https://config.unlink.xyz/networks.json";
5560
- function parseRequiredString(env, field, value) {
5576
+ function parseRequiredString(chain, field, value) {
5561
5577
  if (typeof value !== "string" || value.trim().length === 0) {
5562
5578
  throw new InitializationError(
5563
- `Invalid SDK config for ${env}: ${field} must be a non-empty string`
5579
+ `Invalid SDK config for ${chain}: ${field} must be a non-empty string`
5564
5580
  );
5565
5581
  }
5566
5582
  return value.trim();
5567
5583
  }
5568
- function parseOptionalString(env, field, value) {
5584
+ function parseOptionalString(chain, field, value) {
5569
5585
  if (value === void 0) return void 0;
5570
5586
  if (typeof value !== "string" || value.trim().length === 0) {
5571
5587
  throw new InitializationError(
5572
- `Invalid SDK config for ${env}: ${field} must be a non-empty string when provided`
5588
+ `Invalid SDK config for ${chain}: ${field} must be a non-empty string when provided`
5573
5589
  );
5574
5590
  }
5575
5591
  return value.trim();
5576
5592
  }
5577
- function parseEnvironmentConfig(env, value) {
5593
+ function parseRequiredChainId(chain, value) {
5594
+ if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
5595
+ throw new InitializationError(
5596
+ `Invalid SDK config for ${chain}: chainId must be a positive integer`
5597
+ );
5598
+ }
5599
+ return value;
5600
+ }
5601
+ function parseChainConfig(chain, value) {
5578
5602
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
5579
5603
  throw new InitializationError(
5580
- `Invalid SDK config for ${env}: expected object`
5604
+ `Invalid SDK config for ${chain}: expected object`
5581
5605
  );
5582
5606
  }
5583
5607
  const raw = value;
5608
+ const chainId = parseRequiredChainId(chain, raw.chainId);
5584
5609
  const gatewayUrl = parseRequiredString(
5585
- env,
5610
+ chain,
5586
5611
  "gatewayUrl",
5587
5612
  raw.gatewayUrl
5588
5613
  ).replace(/\/+$/, "");
5589
- const poolAddress = parseRequiredString(env, "poolAddress", raw.poolAddress);
5614
+ const poolAddress = parseRequiredString(
5615
+ chain,
5616
+ "poolAddress",
5617
+ raw.poolAddress
5618
+ );
5590
5619
  const artifactVersion = parseRequiredString(
5591
- env,
5620
+ chain,
5592
5621
  "artifactVersion",
5593
5622
  raw.artifactVersion
5594
5623
  ).replace(/^\/+|\/+$/g, "");
5624
+ const adapterAddress = parseOptionalString(
5625
+ chain,
5626
+ "adapterAddress",
5627
+ raw.adapterAddress
5628
+ );
5629
+ const frostUrl = parseOptionalString(
5630
+ chain,
5631
+ "frostUrl",
5632
+ raw.frostUrl
5633
+ )?.replace(/\/+$/, "");
5595
5634
  const artifactBaseUrl = parseOptionalString(
5596
- env,
5635
+ chain,
5597
5636
  "artifactBaseUrl",
5598
5637
  raw.artifactBaseUrl
5599
5638
  )?.replace(/\/+$/, "");
5639
+ let tokenAddresses;
5640
+ if (raw.tokenAddresses !== void 0) {
5641
+ if (raw.tokenAddresses === null || typeof raw.tokenAddresses !== "object" || Array.isArray(raw.tokenAddresses)) {
5642
+ throw new InitializationError(
5643
+ `Invalid SDK config for ${chain}: tokenAddresses must be an object`
5644
+ );
5645
+ }
5646
+ tokenAddresses = {};
5647
+ for (const [name, addr] of Object.entries(
5648
+ raw.tokenAddresses
5649
+ )) {
5650
+ tokenAddresses[name] = parseRequiredString(
5651
+ chain,
5652
+ `tokenAddresses.${name}`,
5653
+ addr
5654
+ );
5655
+ }
5656
+ }
5600
5657
  return {
5658
+ chainId,
5601
5659
  gatewayUrl,
5660
+ ...frostUrl !== void 0 ? { frostUrl } : {},
5602
5661
  poolAddress,
5662
+ ...adapterAddress !== void 0 ? { adapterAddress } : {},
5603
5663
  artifactVersion,
5604
- ...artifactBaseUrl !== void 0 ? { artifactBaseUrl } : { artifactBaseUrl: DEFAULT_ARTIFACT_BASE_URL }
5664
+ ...artifactBaseUrl !== void 0 ? { artifactBaseUrl } : { artifactBaseUrl: DEFAULT_ARTIFACT_BASE_URL },
5665
+ ...tokenAddresses !== void 0 ? { tokenAddresses } : {}
5605
5666
  };
5606
5667
  }
5607
- async function fetchEnvironmentConfig(env) {
5668
+ async function fetchChainConfig(chain) {
5608
5669
  const res = await fetch(CONFIG_URL);
5609
5670
  if (!res.ok) {
5610
5671
  throw new InitializationError(`Failed to fetch SDK config: ${res.status}`);
5611
5672
  }
5612
5673
  const config = await res.json();
5613
- if (!config[env]) {
5614
- throw new InitializationError(`Unknown environment: ${env}`);
5674
+ if (!config[chain]) {
5675
+ throw new InitializationError(
5676
+ `Unknown chain: "${chain}". Supported chains: ${Object.keys(config).join(", ")}`
5677
+ );
5615
5678
  }
5616
- return parseEnvironmentConfig(env, config[env]);
5679
+ return parseChainConfig(chain, config[chain]);
5617
5680
  }
5618
5681
  function createServiceConfig(gatewayUrl) {
5619
5682
  const baseUrl = gatewayUrl.replace(/\/+$/, "");
@@ -6130,6 +6193,114 @@ var circuits_default = {
6130
6193
  template: "JoinSplit",
6131
6194
  pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6132
6195
  params: [5, 2, 16]
6196
+ },
6197
+ joinsplit_1x3_16: {
6198
+ file: "joinsplit",
6199
+ template: "JoinSplit",
6200
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6201
+ params: [1, 3, 16]
6202
+ },
6203
+ joinsplit_4x3_16: {
6204
+ file: "joinsplit",
6205
+ template: "JoinSplit",
6206
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6207
+ params: [4, 3, 16]
6208
+ },
6209
+ joinsplit_5x3_16: {
6210
+ file: "joinsplit",
6211
+ template: "JoinSplit",
6212
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6213
+ params: [5, 3, 16]
6214
+ },
6215
+ joinsplit_6x1_16: {
6216
+ file: "joinsplit",
6217
+ template: "JoinSplit",
6218
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6219
+ params: [6, 1, 16]
6220
+ },
6221
+ joinsplit_6x2_16: {
6222
+ file: "joinsplit",
6223
+ template: "JoinSplit",
6224
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6225
+ params: [6, 2, 16]
6226
+ },
6227
+ joinsplit_6x3_16: {
6228
+ file: "joinsplit",
6229
+ template: "JoinSplit",
6230
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6231
+ params: [6, 3, 16]
6232
+ },
6233
+ joinsplit_7x1_16: {
6234
+ file: "joinsplit",
6235
+ template: "JoinSplit",
6236
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6237
+ params: [7, 1, 16]
6238
+ },
6239
+ joinsplit_7x2_16: {
6240
+ file: "joinsplit",
6241
+ template: "JoinSplit",
6242
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6243
+ params: [7, 2, 16]
6244
+ },
6245
+ joinsplit_7x3_16: {
6246
+ file: "joinsplit",
6247
+ template: "JoinSplit",
6248
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6249
+ params: [7, 3, 16]
6250
+ },
6251
+ joinsplit_8x1_16: {
6252
+ file: "joinsplit",
6253
+ template: "JoinSplit",
6254
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6255
+ params: [8, 1, 16]
6256
+ },
6257
+ joinsplit_8x2_16: {
6258
+ file: "joinsplit",
6259
+ template: "JoinSplit",
6260
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6261
+ params: [8, 2, 16]
6262
+ },
6263
+ joinsplit_8x3_16: {
6264
+ file: "joinsplit",
6265
+ template: "JoinSplit",
6266
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6267
+ params: [8, 3, 16]
6268
+ },
6269
+ joinsplit_9x1_16: {
6270
+ file: "joinsplit",
6271
+ template: "JoinSplit",
6272
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6273
+ params: [9, 1, 16]
6274
+ },
6275
+ joinsplit_9x2_16: {
6276
+ file: "joinsplit",
6277
+ template: "JoinSplit",
6278
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6279
+ params: [9, 2, 16]
6280
+ },
6281
+ joinsplit_9x3_16: {
6282
+ file: "joinsplit",
6283
+ template: "JoinSplit",
6284
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6285
+ params: [9, 3, 16]
6286
+ },
6287
+ joinsplit_10x1_16: {
6288
+ file: "joinsplit",
6289
+ template: "JoinSplit",
6290
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6291
+ params: [10, 1, 16]
6292
+ },
6293
+ joinsplit_10x2_16: {
6294
+ file: "joinsplit",
6295
+ template: "JoinSplit",
6296
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6297
+ params: [10, 2, 16]
6298
+ },
6299
+ joinsplit_10x3_16: {
6300
+ file: "joinsplit",
6301
+ template: "JoinSplit",
6302
+ pubs: ["merkleRoot", "boundParamsHash", "nullifiers", "commitmentsOut"],
6303
+ params: [10, 3, 16]
6133
6304
  }
6134
6305
  };
6135
6306
 
@@ -6149,7 +6320,7 @@ function getCircuitConfig(inputs, outputs) {
6149
6320
  }
6150
6321
 
6151
6322
  // prover/prover.ts
6152
- var MAX_ARTIFACT_CACHE_ENTRIES = 8;
6323
+ var MAX_ARTIFACT_CACHE_ENTRIES = 16;
6153
6324
  var artifactCache = /* @__PURE__ */ new Map();
6154
6325
  function selectCircuit(inputs, outputs) {
6155
6326
  const config = getCircuitConfig(inputs, outputs);
@@ -7005,7 +7176,7 @@ function buildCall(params) {
7005
7176
  }
7006
7177
  return { to, data, value };
7007
7178
  }
7008
- function buildApproveCall(token, spender, amount) {
7179
+ function approve(token, spender, amount) {
7009
7180
  const normalizedToken = ensureAddress("token", token);
7010
7181
  const normalizedSpender = ensureAddress("spender", spender);
7011
7182
  const normalizedAmount = ensureNonNegative("amount", amount);
@@ -7019,6 +7190,44 @@ function buildApproveCall(token, spender, amount) {
7019
7190
  value: 0n
7020
7191
  };
7021
7192
  }
7193
+ function toCall(tx) {
7194
+ if (tx.to == null) {
7195
+ throw new AdapterError("tx.to is required");
7196
+ }
7197
+ const to = ensureAddress("tx.to", tx.to);
7198
+ if (tx.data == null) {
7199
+ throw new AdapterError("tx.data is required");
7200
+ }
7201
+ const data = ensureHexData("tx.data", tx.data);
7202
+ let value;
7203
+ if (tx.value == null) {
7204
+ value = 0n;
7205
+ } else {
7206
+ try {
7207
+ value = BigInt(tx.value);
7208
+ } catch {
7209
+ throw new AdapterError(
7210
+ `tx.value must be convertible to bigint, received: ${String(tx.value)}`
7211
+ );
7212
+ }
7213
+ }
7214
+ return { to, data, value: ensureNonNegative("tx.value", value) };
7215
+ }
7216
+ function contract(address, abi) {
7217
+ const to = ensureAddress("contract.address", address);
7218
+ const iface = new Interface3(abi);
7219
+ return new Proxy(
7220
+ {},
7221
+ {
7222
+ get(_, method) {
7223
+ return (...args) => {
7224
+ const data = iface.encodeFunctionData(method, args);
7225
+ return { to, data, value: 0n };
7226
+ };
7227
+ }
7228
+ }
7229
+ );
7230
+ }
7022
7231
  function encodeAdapterExecute(params) {
7023
7232
  const transactCalldata = ensureHexData(
7024
7233
  "transactCalldata",
@@ -7042,6 +7251,7 @@ function encodeAdapterExecute(params) {
7042
7251
  deadline
7043
7252
  ]);
7044
7253
  }
7254
+ var buildApproveCall = approve;
7045
7255
 
7046
7256
  // transactions/note-selection.ts
7047
7257
  var MAX_CIRCUIT_INPUTS = Math.max(
@@ -8420,26 +8630,34 @@ function normalizeCall2(call, index) {
8420
8630
  value: call.value
8421
8631
  };
8422
8632
  }
8423
- function normalizeInputSpec(input, index) {
8424
- const token = ensureAddress(`inputs[${index}].token`, input.token);
8633
+ function normalizeSpendInput(input, index) {
8634
+ const token = ensureAddress(`spend[${index}].token`, input.token);
8635
+ if (token.toLowerCase() === ETH_TOKEN.toLowerCase()) {
8636
+ throw new AdapterError(
8637
+ `spend[${index}].token: native ETH is not supported in adapter execution`
8638
+ );
8639
+ }
8425
8640
  if (input.amount <= 0n) {
8426
- throw new AdapterError(`inputs[${index}].amount must be greater than zero`);
8641
+ throw new AdapterError(`spend[${index}].amount must be greater than zero`);
8427
8642
  }
8428
8643
  return {
8429
8644
  token,
8430
8645
  amount: input.amount
8431
8646
  };
8432
8647
  }
8433
- function normalizeReshieldSpec(reshield, index) {
8434
- const token = ensureAddress(`reshields[${index}].token`, reshield.token);
8435
- if (reshield.minAmount < 0n) {
8648
+ function normalizeReceiveInput(receive, index) {
8649
+ const token = ensureAddress(`receive[${index}].token`, receive.token);
8650
+ if (token.toLowerCase() === ETH_TOKEN.toLowerCase()) {
8436
8651
  throw new AdapterError(
8437
- `reshields[${index}].minAmount must be non-negative`
8652
+ `receive[${index}].token: native ETH is not supported in adapter execution`
8438
8653
  );
8439
8654
  }
8655
+ if (receive.minAmount < 0n) {
8656
+ throw new AdapterError(`receive[${index}].minAmount must be non-negative`);
8657
+ }
8440
8658
  return {
8441
8659
  token,
8442
- minAmount: reshield.minAmount
8660
+ minAmount: receive.minAmount
8443
8661
  };
8444
8662
  }
8445
8663
  function randomFieldElement(randomBigintFn) {
@@ -8459,32 +8677,42 @@ function createAdapterService(deps) {
8459
8677
  "adapterAddress",
8460
8678
  params.adapterAddress
8461
8679
  );
8462
- if (!params.inputs.length) {
8463
- throw new AdapterError("at least one input token is required");
8680
+ if (!params.spend.length) {
8681
+ throw new AdapterError("at least one spend token is required");
8464
8682
  }
8465
8683
  if (!params.calls.length) {
8466
8684
  throw new AdapterError("at least one adapter call is required");
8467
8685
  }
8468
- if (!params.reshields.length) {
8469
- throw new AdapterError("at least one reshield output is required");
8686
+ if (!params.receive.length) {
8687
+ throw new AdapterError("at least one receive output is required");
8470
8688
  }
8471
- const inputs = params.inputs.map(
8472
- (input, i) => normalizeInputSpec(input, i)
8689
+ const spendInputs = params.spend.map(
8690
+ (input, i) => normalizeSpendInput(input, i)
8473
8691
  );
8474
8692
  const seenTokens = /* @__PURE__ */ new Set();
8475
- for (const input of inputs) {
8693
+ for (const input of spendInputs) {
8476
8694
  const lower = input.token.toLowerCase();
8477
8695
  if (seenTokens.has(lower)) {
8478
8696
  throw new AdapterError(
8479
- `duplicate input token ${input.token}; combine amounts per token instead`
8697
+ `duplicate spend token ${input.token}; combine amounts per token instead`
8480
8698
  );
8481
8699
  }
8482
8700
  seenTokens.add(lower);
8483
8701
  }
8484
8702
  const calls = params.calls.map((call, i) => normalizeCall2(call, i));
8485
- const reshieldSpecs = params.reshields.map(
8486
- (reshield, i) => normalizeReshieldSpec(reshield, i)
8703
+ const receiveSpecs = params.receive.map(
8704
+ (receive, i) => normalizeReceiveInput(receive, i)
8487
8705
  );
8706
+ const seenReceiveTokens = /* @__PURE__ */ new Set();
8707
+ for (const r2 of receiveSpecs) {
8708
+ const lower = r2.token.toLowerCase();
8709
+ if (seenReceiveTokens.has(lower)) {
8710
+ throw new AdapterError(
8711
+ `duplicate receive token ${r2.token}; each receive must target a unique token`
8712
+ );
8713
+ }
8714
+ seenReceiveTokens.add(lower);
8715
+ }
8488
8716
  const account = overrides?.account ?? await deps.requireActiveAccount();
8489
8717
  const signer = overrides?.signer ?? deps.requireSigner(account);
8490
8718
  const nowSeconds = BigInt(Math.floor(nowImpl() / 1e3));
@@ -8493,19 +8721,19 @@ function createAdapterService(deps) {
8493
8721
  throw new AdapterError("deadline must be in the future");
8494
8722
  }
8495
8723
  const executionCalls = calls;
8496
- const reshields = reshieldSpecs.map(
8497
- (reshield) => {
8724
+ const reshields = receiveSpecs.map(
8725
+ (receive) => {
8498
8726
  const random = randomFieldElement(randomBigintImpl);
8499
8727
  const npk = poseidon([account.masterPublicKey, random]);
8500
8728
  return {
8501
8729
  npk,
8502
8730
  random,
8503
- token: reshield.token,
8504
- minAmount: reshield.minAmount
8731
+ token: receive.token,
8732
+ minAmount: receive.minAmount
8505
8733
  };
8506
8734
  }
8507
8735
  );
8508
- const inputTokens = inputs.map((input) => input.token);
8736
+ const inputTokens = spendInputs.map((input) => input.token);
8509
8737
  const nonce = randomFieldElement(randomBigintImpl);
8510
8738
  const adapterDataHash = computeAdapterDataHash({
8511
8739
  calls: executionCalls,
@@ -8522,7 +8750,7 @@ function createAdapterService(deps) {
8522
8750
  });
8523
8751
  const withdrawalPlans = planWithdrawalsImpl(
8524
8752
  notes,
8525
- inputs.map((input) => ({
8753
+ spendInputs.map((input) => ({
8526
8754
  token: input.token,
8527
8755
  amount: input.amount,
8528
8756
  recipient: adapterAddress
@@ -8605,7 +8833,7 @@ function createAdapterService(deps) {
8605
8833
  adapterCalldata,
8606
8834
  historyPreview: {
8607
8835
  kind: "Withdraw",
8608
- amounts: inputs.map((input) => ({
8836
+ amounts: spendInputs.map((input) => ({
8609
8837
  token: input.token,
8610
8838
  delta: (-input.amount).toString()
8611
8839
  }))
@@ -8632,6 +8860,9 @@ import {
8632
8860
  } from "ethers";
8633
8861
  var BIP44_ETH_PREFIX = "m/44'/60'/0'/0";
8634
8862
  var ERC20_BALANCE_OF = "function balanceOf(address) view returns (uint256)";
8863
+ function isNativeToken(token) {
8864
+ return token.toLowerCase() === ETH_TOKEN.toLowerCase();
8865
+ }
8635
8866
  function createBurnerService(deps) {
8636
8867
  const { chainRpcUrl, getMasterSeed, withdrawToAddress, requestDeposit } = deps;
8637
8868
  const provider = new JsonRpcProvider(chainRpcUrl);
@@ -8679,8 +8910,8 @@ function createBurnerService(deps) {
8679
8910
  }
8680
8911
  async function getTokenBalance(address, token) {
8681
8912
  const iface = new Interface4([ERC20_BALANCE_OF]);
8682
- const contract = new Contract(token, iface, provider);
8683
- const bal = await contract.getFunction("balanceOf")(address);
8913
+ const contract2 = new Contract(token, iface, provider);
8914
+ const bal = await contract2.getFunction("balanceOf")(address);
8684
8915
  return BigInt(bal ?? 0);
8685
8916
  }
8686
8917
  async function getBalance(address) {
@@ -8699,6 +8930,12 @@ function createBurnerService(deps) {
8699
8930
  }
8700
8931
  async function sweepToPool(index, params) {
8701
8932
  const { address } = await addressOf(index);
8933
+ const native = isNativeToken(params.token);
8934
+ if (native && params.amount == null) {
8935
+ throw new Error(
8936
+ "amount is required for native ETH sweeps (needed to reserve gas)"
8937
+ );
8938
+ }
8702
8939
  const amount = params.amount ?? await getTokenBalance(address, params.token);
8703
8940
  if (amount === 0n) {
8704
8941
  throw new Error("No token balance to sweep");
@@ -8709,17 +8946,20 @@ function createBurnerService(deps) {
8709
8946
  depositor: address,
8710
8947
  deposits: [{ token: params.token, amount }]
8711
8948
  });
8712
- const erc20Iface = new Interface4([
8713
- "function approve(address spender, uint256 amount)"
8714
- ]);
8715
- const approveData = erc20Iface.encodeFunctionData("approve", [
8716
- params.poolAddress,
8717
- amount
8718
- ]);
8719
- await send(index, { to: params.token, data: approveData });
8949
+ if (!native) {
8950
+ const erc20Iface = new Interface4([
8951
+ "function approve(address spender, uint256 amount)"
8952
+ ]);
8953
+ const approveData = erc20Iface.encodeFunctionData("approve", [
8954
+ params.poolAddress,
8955
+ amount
8956
+ ]);
8957
+ await send(index, { to: params.token, data: approveData });
8958
+ }
8720
8959
  const { txHash } = await send(index, {
8721
8960
  to: depositResult.to,
8722
- data: depositResult.calldata
8961
+ data: depositResult.calldata,
8962
+ value: depositResult.value
8723
8963
  });
8724
8964
  return { txHash };
8725
8965
  }
@@ -9375,28 +9615,31 @@ function createWalletSDK(deps, options) {
9375
9615
  return sdk;
9376
9616
  }
9377
9617
  async function createBrowserWalletSDK(options) {
9618
+ let chainId;
9378
9619
  let gatewayUrl;
9379
9620
  let poolAddress;
9380
9621
  let prover = options.prover;
9381
- if ("gatewayUrl" in options) {
9622
+ if ("chain" in options) {
9623
+ const chainConfig = await fetchChainConfig(options.chain);
9624
+ chainId = chainConfig.chainId;
9625
+ gatewayUrl = chainConfig.gatewayUrl;
9626
+ poolAddress = options.poolAddress ?? chainConfig.poolAddress;
9627
+ prover = {
9628
+ artifactSource: {
9629
+ baseUrl: options.prover?.artifactSource?.baseUrl ?? chainConfig.artifactBaseUrl,
9630
+ version: options.prover?.artifactSource?.version ?? chainConfig.artifactVersion,
9631
+ preferLocalFiles: options.prover?.artifactSource?.preferLocalFiles
9632
+ }
9633
+ };
9634
+ } else {
9635
+ chainId = options.chainId;
9382
9636
  gatewayUrl = options.gatewayUrl;
9383
9637
  poolAddress = options.poolAddress;
9384
9638
  if (typeof window !== "undefined" && !options.prover?.artifactSource?.version) {
9385
9639
  throw new InitializationError(
9386
- "prover.artifactSource.version is required in browser when using explicit gatewayUrl mode. Use environment mode or provide a pinned artifact version."
9640
+ "prover.artifactSource.version is required in browser when using explicit gatewayUrl mode. Use chain mode or provide a pinned artifact version."
9387
9641
  );
9388
9642
  }
9389
- } else {
9390
- const envConfig = await fetchEnvironmentConfig(options.environment);
9391
- gatewayUrl = envConfig.gatewayUrl;
9392
- poolAddress = options.poolAddress ?? envConfig.poolAddress;
9393
- prover = {
9394
- artifactSource: {
9395
- baseUrl: options.prover?.artifactSource?.baseUrl ?? envConfig.artifactBaseUrl,
9396
- version: options.prover?.artifactSource?.version ?? envConfig.artifactVersion,
9397
- preferLocalFiles: options.prover?.artifactSource?.preferLocalFiles
9398
- }
9399
- };
9400
9643
  }
9401
9644
  const storage = createIndexedDbStorage({ name: "unlink-wallet" });
9402
9645
  const rng = (n) => {
@@ -9413,7 +9656,7 @@ async function createBrowserWalletSDK(options) {
9413
9656
  core,
9414
9657
  fetch: globalThis.fetch
9415
9658
  },
9416
- { chainId: options.chainId, gatewayUrl, prover }
9659
+ { chainId, gatewayUrl, prover }
9417
9660
  );
9418
9661
  return {
9419
9662
  sdk,
@@ -9426,51 +9669,63 @@ async function createBrowserWalletSDK(options) {
9426
9669
  };
9427
9670
  }
9428
9671
 
9429
- // wallet/unlink-wallet.ts
9430
- var UnlinkWallet = class _UnlinkWallet {
9672
+ // wallet/unlink.ts
9673
+ var Unlink = class _Unlink {
9431
9674
  /** @internal */
9432
9675
  sdk;
9433
9676
  /** Chain ID this wallet operates on. */
9434
9677
  chainId;
9435
9678
  /** Pool contract address this wallet transacts with. */
9436
9679
  poolAddress;
9437
- constructor(sdk, chainId, poolAddress) {
9680
+ /** Adapter contract address for DeFi operations. */
9681
+ adapterAddress;
9682
+ constructor(sdk, chainId, poolAddress, adapterAddress) {
9438
9683
  this.sdk = sdk;
9439
9684
  this.chainId = chainId;
9440
9685
  this.poolAddress = poolAddress;
9686
+ this.adapterAddress = adapterAddress;
9687
+ this.adapter = {
9688
+ address: adapterAddress
9689
+ };
9441
9690
  }
9442
9691
  /**
9443
- * Create a new UnlinkWallet instance.
9692
+ * Create a new Unlink instance.
9444
9693
  *
9445
9694
  * Handles all initialization internally:
9446
- * - Resolves environment config (if using `environment` instead of explicit URLs)
9695
+ * - Resolves chain config (if using `chain` instead of explicit URLs)
9447
9696
  * - Auto-detects storage (IndexedDB in browser) and rng (crypto.getRandomValues)
9448
9697
  * - Runs schema migration via `initCore()`
9449
9698
  * - Creates the internal SDK
9450
9699
  */
9451
9700
  static async create(config) {
9701
+ let chainId;
9452
9702
  let gatewayUrl;
9453
9703
  let poolAddress;
9704
+ let adapterAddress;
9454
9705
  let proverConfig = config.prover;
9455
- if ("gatewayUrl" in config) {
9706
+ if ("chain" in config) {
9707
+ const chainConfig = await fetchChainConfig(config.chain);
9708
+ chainId = chainConfig.chainId;
9709
+ gatewayUrl = chainConfig.gatewayUrl;
9710
+ poolAddress = config.poolAddress ?? chainConfig.poolAddress;
9711
+ adapterAddress = config.adapterAddress ?? chainConfig.adapterAddress;
9712
+ proverConfig = {
9713
+ artifactSource: {
9714
+ baseUrl: config.prover?.artifactSource?.baseUrl ?? chainConfig.artifactBaseUrl,
9715
+ version: config.prover?.artifactSource?.version ?? chainConfig.artifactVersion,
9716
+ preferLocalFiles: config.prover?.artifactSource?.preferLocalFiles
9717
+ }
9718
+ };
9719
+ } else {
9720
+ chainId = config.chainId;
9456
9721
  gatewayUrl = config.gatewayUrl;
9457
9722
  poolAddress = config.poolAddress;
9723
+ adapterAddress = config.adapterAddress;
9458
9724
  if (typeof window !== "undefined" && !config.prover?.artifactSource?.version) {
9459
9725
  throw new InitializationError(
9460
- "prover.artifactSource.version is required in browser when using explicit gatewayUrl mode. Use environment mode or provide a pinned artifact version."
9726
+ "prover.artifactSource.version is required in browser when using explicit gatewayUrl mode. Use chain mode or provide a pinned artifact version."
9461
9727
  );
9462
9728
  }
9463
- } else {
9464
- const envConfig = await fetchEnvironmentConfig(config.environment);
9465
- gatewayUrl = envConfig.gatewayUrl;
9466
- poolAddress = config.poolAddress ?? envConfig.poolAddress;
9467
- proverConfig = {
9468
- artifactSource: {
9469
- baseUrl: config.prover?.artifactSource?.baseUrl ?? envConfig.artifactBaseUrl,
9470
- version: config.prover?.artifactSource?.version ?? envConfig.artifactVersion,
9471
- preferLocalFiles: config.prover?.artifactSource?.preferLocalFiles
9472
- }
9473
- };
9474
9729
  }
9475
9730
  const storage = config.storage ?? detectStorage();
9476
9731
  const rng = config.rng ?? defaultRng;
@@ -9479,14 +9734,14 @@ var UnlinkWallet = class _UnlinkWallet {
9479
9734
  const sdk = createWalletSDK(
9480
9735
  { core, fetch: fetchImpl },
9481
9736
  {
9482
- chainId: config.chainId,
9737
+ chainId,
9483
9738
  gatewayUrl,
9484
9739
  chainRpcUrl: config.chainRpcUrl,
9485
9740
  prover: proverConfig,
9486
9741
  autoSync: config.autoSync
9487
9742
  }
9488
9743
  );
9489
- return new _UnlinkWallet(sdk, config.chainId, poolAddress);
9744
+ return new _Unlink(sdk, chainId, poolAddress, adapterAddress ?? "");
9490
9745
  }
9491
9746
  // ===== Seed Lifecycle =====
9492
9747
  /** Seed management (create, import, export, delete mnemonic). */
@@ -9517,10 +9772,10 @@ var UnlinkWallet = class _UnlinkWallet {
9517
9772
  return this.sdk.deposit.reconcile(relayId);
9518
9773
  }
9519
9774
  /**
9520
- * Execute a private transfer (1 or more recipients).
9775
+ * Send a private transfer (1 or more recipients).
9521
9776
  * Handles note selection, circuit selection, and proof generation automatically.
9522
9777
  */
9523
- async transfer(params, overrides) {
9778
+ async send(params, overrides) {
9524
9779
  return this.sdk.transfer.send(
9525
9780
  {
9526
9781
  chainId: this.chainId,
@@ -9531,9 +9786,9 @@ var UnlinkWallet = class _UnlinkWallet {
9531
9786
  );
9532
9787
  }
9533
9788
  /**
9534
- * Get a transfer plan without executing (for preview/confirmation UIs).
9789
+ * Get a send plan without executing (for preview/confirmation UIs).
9535
9790
  */
9536
- async planTransfer(params, account) {
9791
+ async planSend(params, account) {
9537
9792
  return this.sdk.transfer.plan(
9538
9793
  {
9539
9794
  chainId: this.chainId,
@@ -9543,8 +9798,8 @@ var UnlinkWallet = class _UnlinkWallet {
9543
9798
  account
9544
9799
  );
9545
9800
  }
9546
- /** Execute a pre-built transfer plan. */
9547
- async executeTransfer(plans, overrides) {
9801
+ /** Execute a pre-built send plan. */
9802
+ async executeSend(plans, overrides) {
9548
9803
  return this.sdk.transfer.execute(
9549
9804
  plans,
9550
9805
  { chainId: this.chainId, poolAddress: this.poolAddress },
@@ -9693,31 +9948,31 @@ var UnlinkWallet = class _UnlinkWallet {
9693
9948
  return this.sdk.burner.getBalance(address);
9694
9949
  }
9695
9950
  };
9696
- // ===== Adapter =====
9951
+ // ===== Interact (Private DeFi) =====
9697
9952
  /**
9698
- * Private DeFi adapter operations.
9699
- * chainId/poolAddress are injected automatically.
9953
+ * Adapter contract address (resolved from config).
9954
+ * Use for building DeFi calls that reference the adapter.
9700
9955
  */
9701
- adapter = {
9702
- /**
9703
- * Execute an atomic unshield -> call(s) -> reshield flow through an adapter.
9704
- */
9705
- execute: (params, opts, overrides) => {
9706
- return this.sdk.adapter.execute(
9707
- {
9708
- chainId: this.chainId,
9709
- poolAddress: this.poolAddress,
9710
- adapterAddress: params.adapterAddress,
9711
- inputs: params.inputs,
9712
- calls: params.calls,
9713
- reshields: params.reshields,
9714
- deadline: params.deadline
9715
- },
9716
- opts,
9717
- overrides
9718
- );
9719
- }
9720
- };
9956
+ adapter;
9957
+ /**
9958
+ * Execute an atomic unshield -> DeFi call(s) -> reshield flow through an adapter.
9959
+ * chainId/poolAddress/adapterAddress are injected automatically.
9960
+ */
9961
+ async interact(params, opts, overrides) {
9962
+ return this.sdk.adapter.execute(
9963
+ {
9964
+ chainId: this.chainId,
9965
+ poolAddress: this.poolAddress,
9966
+ adapterAddress: this.adapterAddress,
9967
+ spend: params.spend,
9968
+ calls: params.calls,
9969
+ receive: params.receive,
9970
+ deadline: params.deadline
9971
+ },
9972
+ opts,
9973
+ overrides
9974
+ );
9975
+ }
9721
9976
  // ===== Advanced =====
9722
9977
  /**
9723
9978
  * Advanced escape hatch for raw JoinSplit transaction building.
@@ -9765,12 +10020,14 @@ var defaultRng = (n) => {
9765
10020
  }
9766
10021
  return globalThis.crypto.getRandomValues(new Uint8Array(n));
9767
10022
  };
10023
+ var UnlinkWallet = Unlink;
9768
10024
  export {
9769
10025
  ADAPTER_EXECUTE_ABI,
9770
10026
  AdapterError,
9771
10027
  CORE_SCHEMA_VERSION,
9772
10028
  CoreError,
9773
10029
  DEFAULT_JOB_TIMEOUT_MS,
10030
+ DEFAULT_RPC_URLS,
9774
10031
  DEPOSIT_ABI,
9775
10032
  ETH_TOKEN,
9776
10033
  FieldSize,
@@ -9788,8 +10045,10 @@ export {
9788
10045
  ReconcileError,
9789
10046
  SNARK_SCALAR_FIELD,
9790
10047
  SchemaMismatchError,
10048
+ Unlink,
9791
10049
  UnlinkWallet,
9792
10050
  ValidationError,
10051
+ approve,
9793
10052
  assertNonNegative,
9794
10053
  buildApproveCall,
9795
10054
  buildCall,
@@ -9799,6 +10058,7 @@ export {
9799
10058
  computeCommitment,
9800
10059
  computeMasterPublicKey,
9801
10060
  computeNullifyingKey,
10061
+ contract,
9802
10062
  createBroadcasterClient,
9803
10063
  createBrowserWalletSDK,
9804
10064
  createCiphertextStore,
@@ -9840,7 +10100,7 @@ export {
9840
10100
  ensureNoteCommitmentInput,
9841
10101
  ensurePositiveInt,
9842
10102
  ensureWithdrawalInput,
9843
- fetchEnvironmentConfig,
10103
+ fetchChainConfig,
9844
10104
  formatAmount,
9845
10105
  formatUint256,
9846
10106
  generateMasterSeed,
@@ -9871,6 +10131,7 @@ export {
9871
10131
  syncDeposit,
9872
10132
  syncTransact,
9873
10133
  toAccountView,
10134
+ toCall,
9874
10135
  transact,
9875
10136
  validateKey,
9876
10137
  verifySignature,