@anywalletkit/protocol-swap2-core 0.4.1 → 0.5.0

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 (44) hide show
  1. package/README.md +1 -0
  2. package/dist/{chunk-4H2JVYXT.js → chunk-3Y6HV2OL.js} +2 -2
  3. package/dist/{chunk-Y3VUEWYI.js → chunk-IC3MZIMB.js} +68 -13
  4. package/dist/chunk-IC3MZIMB.js.map +1 -0
  5. package/dist/{chunk-SKV5BVXK.js → chunk-MNJTMSFN.js} +8 -2
  6. package/dist/chunk-MNJTMSFN.js.map +1 -0
  7. package/dist/{chunk-GDRKGFLH.js → chunk-OWO27YBK.js} +2 -2
  8. package/dist/index.cjs +79 -21
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +2 -1
  11. package/dist/index.d.ts +2 -1
  12. package/dist/index.js +7 -5
  13. package/dist/remote.cjs +1 -0
  14. package/dist/remote.cjs.map +1 -1
  15. package/dist/remote.js +2 -2
  16. package/dist/server.cjs +8 -4
  17. package/dist/server.cjs.map +1 -1
  18. package/dist/server.d.cts +7 -0
  19. package/dist/server.d.ts +7 -0
  20. package/dist/server.js +8 -5
  21. package/dist/server.js.map +1 -1
  22. package/dist/swap2/base.cjs +63 -11
  23. package/dist/swap2/base.cjs.map +1 -1
  24. package/dist/swap2/base.d.cts +21 -1
  25. package/dist/swap2/base.d.ts +21 -1
  26. package/dist/swap2/base.js +1 -1
  27. package/dist/swap2/single.cjs +63 -11
  28. package/dist/swap2/single.cjs.map +1 -1
  29. package/dist/swap2/single.d.cts +1 -0
  30. package/dist/swap2/single.d.ts +1 -0
  31. package/dist/swap2/single.js +2 -2
  32. package/dist/types.cjs.map +1 -1
  33. package/dist/types.d.cts +6 -0
  34. package/dist/types.d.ts +6 -0
  35. package/dist/util.cjs +6 -0
  36. package/dist/util.cjs.map +1 -1
  37. package/dist/util.d.cts +12 -1
  38. package/dist/util.d.ts +12 -1
  39. package/dist/util.js +3 -1
  40. package/package.json +6 -6
  41. package/dist/chunk-SKV5BVXK.js.map +0 -1
  42. package/dist/chunk-Y3VUEWYI.js.map +0 -1
  43. /package/dist/{chunk-4H2JVYXT.js.map → chunk-3Y6HV2OL.js.map} +0 -0
  44. /package/dist/{chunk-GDRKGFLH.js.map → chunk-OWO27YBK.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -54,6 +54,7 @@ __export(src_exports, {
54
54
  remoteProvider: () => remoteProvider,
55
55
  shortAddress: () => shortAddress,
56
56
  slippageClassOf: () => slippageClassOf,
57
+ sourceAssetOf: () => sourceAssetOf,
57
58
  suggestSlippage: () => suggestSlippage,
58
59
  swap2ChainId: () => swap2ChainId,
59
60
  validQuote: () => validQuote
@@ -158,6 +159,7 @@ function validQuote(q, params, provider) {
158
159
  }
159
160
 
160
161
  // src/util.ts
162
+ var import_swap2_assets = require("@anywalletkit/swap2-assets");
161
163
  function namespace(chain) {
162
164
  return chain.split(":")[0] ?? "";
163
165
  }
@@ -190,6 +192,10 @@ function anySignal(signals) {
190
192
  function redactUrls(text) {
191
193
  return text.replace(/\b[a-z][a-z0-9+.-]*:\/\/[^\s"'<>]+/gi, "<url>");
192
194
  }
195
+ function sourceAssetOf(params) {
196
+ const decimals = params.sourceDecimals;
197
+ return (0, import_swap2_assets.resolveAsset)(params.sourceChain, params.sourceToken, decimals === void 0 ? {} : { allowUnlisted: true, decimals });
198
+ }
193
199
 
194
200
  // src/remote.ts
195
201
  function remoteProvider(opts) {
@@ -268,7 +274,7 @@ function remoteProvider(opts) {
268
274
  var import_core = require("@anywalletkit/core");
269
275
  var import_viem = require("viem");
270
276
  var import_tx_preview_evm = require("@anywalletkit/tx-preview-evm");
271
- var import_swap2_assets = require("@anywalletkit/swap2-assets");
277
+ var import_swap2_assets2 = require("@anywalletkit/swap2-assets");
272
278
  var ZERO = "0x0000000000000000000000000000000000000000";
273
279
  var ERC20_TRANSFER_ABI = [
274
280
  {
@@ -448,15 +454,16 @@ function toCaip2(chain, fallback) {
448
454
  return swap2ChainId(chain);
449
455
  }
450
456
  function toSymbol(caip2, ref) {
451
- const byToken = ref.startsWith("0x") || ref.length > 20 ? (0, import_swap2_assets.ccAssetByToken)(caip2, ref) : void 0;
457
+ const byToken = ref.startsWith("0x") || ref.length > 20 ? (0, import_swap2_assets2.ccAssetByToken)(caip2, ref) : void 0;
452
458
  if (byToken) return byToken.symbol;
453
- if ((0, import_swap2_assets.ccAsset)(caip2, ref)) return ref;
459
+ if ((0, import_swap2_assets2.ccAsset)(caip2, ref)) return ref;
454
460
  return ref;
455
461
  }
456
- function toDestAddress(caip2, ref) {
462
+ function toDestAddress(caip2, ref, allowUnlisted = false) {
457
463
  if (ref.startsWith("0x")) return ref;
458
- const asset = (0, import_swap2_assets.ccAssetByToken)(caip2, ref) ?? (0, import_swap2_assets.ccAsset)(caip2, ref);
464
+ const asset = (0, import_swap2_assets2.ccAssetByToken)(caip2, ref) ?? (0, import_swap2_assets2.ccAsset)(caip2, ref);
459
465
  if (!asset) {
466
+ if (allowUnlisted && (0, import_swap2_assets2.isTokenAddress)(caip2, ref)) return ref;
460
467
  throw new Error(`swap2: unknown destination token '${ref}' on ${caip2}`);
461
468
  }
462
469
  return asset.contract ?? ZERO;
@@ -538,6 +545,15 @@ function mapStatus(s) {
538
545
  const status = s.state === "completed" ? "completed" : s.state === "action-required" ? "action-required" : s.state === "refund-pending" ? "refund-pending" : s.state === "partial" ? "partial" : s.state === "failed" ? "failed" : s.state === "refunded" ? "refunded" : s.state === "cancelled" ? "cancelled" : s.state === "expired" ? "expired" : "pending";
539
546
  return s.destTxHash ? { status, transactions: [{ hash: s.destTxHash, type: "destination" }] } : { status };
540
547
  }
548
+ function blankToUndefined(v) {
549
+ return typeof v === "string" && v.trim() === "" ? void 0 : v;
550
+ }
551
+ function withoutBlankAddresses(o) {
552
+ const { recipient, refundAddress, ...rest } = o;
553
+ const r = blankToUndefined(recipient);
554
+ const f = blankToUndefined(refundAddress);
555
+ return { ...rest, ...r !== void 0 ? { recipient: r } : {}, ...f !== void 0 ? { refundAddress: f } : {} };
556
+ }
541
557
  var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
542
558
  fromChain;
543
559
  constructor(account, config) {
@@ -570,19 +586,61 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
570
586
  pairSupported(fromChain, toChain) {
571
587
  return this.chainSupported(fromChain) && this.chainSupported(toChain);
572
588
  }
589
+ unlistedAllowed() {
590
+ return this._config.allowUnlistedTokens === true;
591
+ }
592
+ /** The source asset the options name: the catalog's, or (allowUnlistedTokens) an unlisted one with its decimals. */
593
+ sourceAsset(options) {
594
+ const decimals = options.fromTokenDecimals;
595
+ return (0, import_swap2_assets2.resolveAsset)(this.fromChain, toSymbol(this.fromChain, options.fromToken), {
596
+ allowUnlisted: this.unlistedAllowed(),
597
+ ...decimals !== void 0 ? { decimals } : {}
598
+ });
599
+ }
600
+ unlistedDecimals = /* @__PURE__ */ new Map();
601
+ /**
602
+ * Options ready to quote: with `allowUnlistedTokens`, an unlisted source token gets its decimals,
603
+ * read from the chain through the account (cached per token) — a caller's `fromTokenDecimals` that
604
+ * disagrees is refused. Listed tokens and every option otherwise pass through unchanged.
605
+ */
606
+ async prepareOptions(options) {
607
+ if (!this.unlistedAllowed()) return options;
608
+ const ref = toSymbol(this.fromChain, options.fromToken);
609
+ if ((0, import_swap2_assets2.resolveAsset)(this.fromChain, ref) || !(0, import_swap2_assets2.isTokenAddress)(this.fromChain, ref)) return options;
610
+ const key = ref.startsWith("0x") ? ref.toLowerCase() : ref;
611
+ let decimals = this.unlistedDecimals.get(key);
612
+ if (decimals === void 0) {
613
+ const reader = this._account;
614
+ if (typeof reader?.getTokenInfo !== "function") {
615
+ if (options.fromTokenDecimals === void 0) {
616
+ throw new Swap2ValidationError(`swap2: '${ref}' is not in the catalog \u2014 pass fromTokenDecimals, or use an account that can read token info`);
617
+ }
618
+ return options;
619
+ }
620
+ decimals = (await reader.getTokenInfo(ref)).decimals;
621
+ this.unlistedDecimals.set(key, decimals);
622
+ }
623
+ if (options.fromTokenDecimals !== void 0 && options.fromTokenDecimals !== decimals) {
624
+ throw new Swap2ValidationError(`swap2: fromTokenDecimals ${options.fromTokenDecimals} does not match the token's ${decimals}`);
625
+ }
626
+ return snapshotOptions({ ...options, fromTokenDecimals: decimals });
627
+ }
573
628
  /** Swap2Options → the engine's QuoteParams (exact-in only). */
574
- toParams(options, dry) {
629
+ toParams(given, dry) {
630
+ const options = withoutBlankAddresses(given);
575
631
  if (options.fromTokenAmount == null) {
576
632
  throw new Swap2UnsupportedOperationError("swap2: exact-out swap2 is not supported by the engine");
577
633
  }
578
634
  const destChain = toCaip2(options.toChain, this.fromChain);
579
635
  const constraints = callerConstraints(options);
580
636
  const amountIn = exactPositiveAmount(options.fromTokenAmount, "fromTokenAmount");
637
+ const source = this.sourceAsset(options);
581
638
  const params = {
582
639
  sourceChain: this.fromChain,
583
- sourceToken: toSymbol(this.fromChain, options.fromToken),
640
+ sourceToken: (0, import_swap2_assets2.isUnlisted)(source) ? source.contract : toSymbol(this.fromChain, options.fromToken),
641
+ ...(0, import_swap2_assets2.isUnlisted)(source) ? { sourceDecimals: source.decimals } : {},
584
642
  destChain,
585
- destToken: toDestAddress(destChain, options.toToken),
643
+ destToken: toDestAddress(destChain, options.toToken, this.unlistedAllowed()),
586
644
  amountIn: amountIn.toString(),
587
645
  destAddress: options.recipient ?? "",
588
646
  dry,
@@ -638,7 +696,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
638
696
  }
639
697
  }
640
698
  assertQuoteFeeCaps(q, options, config) {
641
- const source = (0, import_swap2_assets.ccAsset)(this.fromChain, toSymbol(this.fromChain, options.fromToken));
699
+ const source = this.sourceAsset(options);
642
700
  if (!source) throw new Error(`swap2: unknown source token '${options.fromToken}' on ${this.fromChain}`);
643
701
  const token = source.contract ?? source.assetId;
644
702
  const fees = q.fees?.map((fee) => ({ ...fee, amount: BigInt(fee.amount) }));
@@ -683,7 +741,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
683
741
  * gave one.
684
742
  */
685
743
  async quoteSwap2(options) {
686
- const snapshot = snapshotOptions(options);
744
+ const snapshot = await this.prepareOptions(snapshotOptions(options));
687
745
  const q = await this.resolveQuote(this.toParams(snapshot, true));
688
746
  if (!q) {
689
747
  const detail = this.noRouteDetail();
@@ -725,9 +783,9 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
725
783
  this.assertFeeConfig(configSnapshot);
726
784
  await this.assertAccountChain(signer);
727
785
  const selfAddress = await signer.getAddress();
728
- const recipient = snapshot.recipient ?? selfAddress;
729
- const refundAddress = snapshot.refundAddress ?? selfAddress;
730
- const executionOptions = snapshotOptions({ ...snapshot, recipient, refundAddress });
786
+ const recipient = blankToUndefined(snapshot.recipient) ?? selfAddress;
787
+ const refundAddress = blankToUndefined(snapshot.refundAddress) ?? selfAddress;
788
+ const executionOptions = await this.prepareOptions(snapshotOptions({ ...snapshot, recipient, refundAddress }));
731
789
  const params = this.toParams(executionOptions, false);
732
790
  const resolved = await this.resolveQuote(params);
733
791
  if (!resolved) {
@@ -808,7 +866,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
808
866
  }
809
867
  let tokenId;
810
868
  if (!unsigned.data && !unsigned.bodyBoc && !unsigned.typedData && !serialized) {
811
- const src = (0, import_swap2_assets.ccAsset)(this.fromChain, toSymbol(this.fromChain, executionOptions.fromToken));
869
+ const src = this.sourceAsset(executionOptions);
812
870
  if (src?.contract) {
813
871
  if (this.fromChain.startsWith("eip155:")) {
814
872
  unsigned = {
@@ -834,7 +892,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
834
892
  if (tokenId && (cellBody !== void 0 || unsigned.memo !== void 0 && !tronSource && !nearSource && !tonSource)) {
835
893
  throw new Error("swap2: token deposit with memo/cell payload is not implemented");
836
894
  }
837
- const source = (0, import_swap2_assets.ccAsset)(this.fromChain, toSymbol(this.fromChain, executionOptions.fromToken));
895
+ const source = this.sourceAsset(executionOptions);
838
896
  if (!source) throw new Error(`swap2: unknown source token '${executionOptions.fromToken}' on ${this.fromChain}`);
839
897
  const executionValue = BigInt(unsigned.value);
840
898
  if (serialized) {
@@ -1230,7 +1288,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
1230
1288
  /** Source chains this protocol can swap from. */
1231
1289
  async getSupportedChains() {
1232
1290
  if (!this.protocolEnabled()) return [];
1233
- return import_swap2_assets.CC_SOURCE_CHAINS.filter((c) => this.chainSupported(c.caip2)).map((c) => ({
1291
+ return import_swap2_assets2.CC_SOURCE_CHAINS.filter((c) => this.chainSupported(c.caip2)).map((c) => ({
1234
1292
  id: c.caip2,
1235
1293
  name: c.label,
1236
1294
  type: chainType(c.caip2),
@@ -1243,7 +1301,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
1243
1301
  const wantTo = options?.toChain != null ? toCaip2(options.toChain, "") : void 0;
1244
1302
  if (!this.protocolEnabled() || wantFrom && wantTo && !this.pairSupported(wantFrom, wantTo)) return [];
1245
1303
  const out = [];
1246
- for (const c of import_swap2_assets.CC_SOURCE_CHAINS) {
1304
+ for (const c of import_swap2_assets2.CC_SOURCE_CHAINS) {
1247
1305
  if (!this.chainSupported(c.caip2)) continue;
1248
1306
  if ((wantFrom || wantTo) && c.caip2 !== wantFrom && c.caip2 !== wantTo) continue;
1249
1307
  for (const a of c.assets) {
@@ -1330,7 +1388,7 @@ var SingleProviderSwap2 = class extends BaseSwap2Protocol {
1330
1388
 
1331
1389
  // src/activity.ts
1332
1390
  var import_core2 = require("@anywalletkit/core");
1333
- var import_swap2_assets2 = require("@anywalletkit/swap2-assets");
1391
+ var import_swap2_assets3 = require("@anywalletkit/swap2-assets");
1334
1392
  function calledContract(tx) {
1335
1393
  const to = tx.call?.to ?? tx.to;
1336
1394
  if (!to) return null;
@@ -1367,7 +1425,7 @@ function matchesCall(tx, contracts, selectors) {
1367
1425
  return sel !== void 0 && want.has(sel);
1368
1426
  }
1369
1427
  function chainLabel(caip2) {
1370
- return (0, import_swap2_assets2.ccChain)(caip2)?.label ?? caip2;
1428
+ return (0, import_swap2_assets3.ccChain)(caip2)?.label ?? caip2;
1371
1429
  }
1372
1430
  function shortAddress(a) {
1373
1431
  return a.length > 14 ? `${a.slice(0, 6)}\u2026${a.slice(-4)}` : a;
@@ -1386,7 +1444,7 @@ function assetMetaFor(tx) {
1386
1444
  const key = token === null ? null : token.startsWith("0x") ? token.toLowerCase() : token;
1387
1445
  const known = fromTransfers.get(key);
1388
1446
  if (known?.symbol !== void 0 && known.decimals !== void 0) return known;
1389
- const cat = (0, import_swap2_assets2.ccAssetByToken)(tx.chain, token ?? "");
1447
+ const cat = (0, import_swap2_assets3.ccAssetByToken)(tx.chain, token ?? "");
1390
1448
  if (!cat) return known;
1391
1449
  const meta = { symbol: known?.symbol ?? cat.symbol, decimals: known?.decimals ?? cat.decimals };
1392
1450
  return meta;
@@ -1394,7 +1452,7 @@ function assetMetaFor(tx) {
1394
1452
  }
1395
1453
  function assetLabel(tx, a) {
1396
1454
  if (a.symbol) return a.symbol;
1397
- if (a.token === null) return (0, import_swap2_assets2.ccAssetByToken)(tx.chain, "")?.symbol ?? "native";
1455
+ if (a.token === null) return (0, import_swap2_assets3.ccAssetByToken)(tx.chain, "")?.symbol ?? "native";
1398
1456
  return shortAddress(a.token);
1399
1457
  }
1400
1458
  function ownerAssets(tx, ctx) {