@anywalletkit/protocol-swap2-lifi 0.5.0 → 0.6.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.
package/dist/protocol.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  LifiSwap2Protocol
3
- } from "./chunk-V56FCCBC.js";
4
- import "./chunk-67QPKWAY.js";
3
+ } from "./chunk-YABKNR7N.js";
4
+ import "./chunk-IZ7TP4KT.js";
5
5
  import "./chunk-6N4HZ5XX.js";
6
6
  import "./chunk-EU7XQVZQ.js";
7
7
  export {
package/dist/provider.cjs CHANGED
@@ -126,10 +126,10 @@ var BRIDGE_CALLS = {
126
126
  // startBridgeTokensViaChainflip (ChainflipFacet)
127
127
  "0xee3314a1": { sourceSwaps: true, facet: "Chainflip" },
128
128
  // swapAndStartBridgeTokensViaChainflip (ChainflipFacet)
129
- "0xbff90b61": { sourceSwaps: false, facet: "Eco" },
130
- // startBridgeTokensViaEco (EcoFacet)
131
- "0x762aea18": { sourceSwaps: true, facet: "Eco" },
132
- // swapAndStartBridgeTokensViaEco (EcoFacet)
129
+ "0x05c54990": { sourceSwaps: false, facet: "Eco" },
130
+ // startBridgeTokensViaEco (EcoFacet v3.0.0, 9001792)
131
+ "0x8352664c": { sourceSwaps: true, facet: "Eco" },
132
+ // swapAndStartBridgeTokensViaEco (EcoFacet v3.0.0, 9001792)
133
133
  "0x678786ea": { sourceSwaps: false, facet: "Frax" },
134
134
  // startBridgeTokensViaFrax (FraxFacet)
135
135
  "0x07b8e4c7": { sourceSwaps: true, facet: "Frax" },
@@ -343,20 +343,50 @@ function acrossSwapRefunds(r, at) {
343
343
  if (target === 3n) return [["the sponsored CCTP refund recipient", c.address(64), true]];
344
344
  throw new Error("unknown Across Swap API target");
345
345
  }
346
+ var ERC20_TRANSFER = "0xa9059cbb";
347
+ function ecoDelivery(r, at, e) {
348
+ if (kindOf(e.toToken) === "native") return "an Eco route to the native token cannot be checked here";
349
+ const destination = r.word(at + 32 * 3);
350
+ if (destination !== e.destChainId) return `the Eco intent executes on chain ${destination}, not the destination ${e.destChainId} \u2014 a route whose delivery cannot be checked here`;
351
+ const route = r.bytes(at, at + 32 * 4);
352
+ const tuple = route.small(0);
353
+ const calls = tuple + route.small(tuple + 32 * 5);
354
+ const n = route.small(calls);
355
+ if (n === 0) return "the Eco route makes no calls on the destination chain";
356
+ if (n > 16) return `the Eco route makes ${n} calls on the destination chain, more than the 16 read here`;
357
+ const last = calls + 32 + route.small(calls + 32 + 32 * (n - 1));
358
+ const target = route.address(last);
359
+ const data = route.bytes(last, last + 32);
360
+ if (route.word(last + 64) !== 0n || data.length !== 68 || data.raw(0, 4) !== ERC20_TRANSFER) return "the Eco route does not end in a token transfer";
361
+ const to = data.address(4);
362
+ const amount = data.word(36);
363
+ if (!same(target, e.toToken)) return `the Eco route delivers ${target}, not ${e.toToken}`;
364
+ if (!same(to, e.receiver)) return `the Eco route pays ${to}, not ${e.receiver}`;
365
+ if (amount < e.minOut) return `the Eco route delivers ${amount}, below the ${e.minOut} shown`;
366
+ return null;
367
+ }
368
+ function m0Delivery(r, at, e) {
369
+ if (kindOf(e.toToken) === "native") return "an M0 order cannot deliver the native token";
370
+ const tokenOut = r.address(at + 32 * 3);
371
+ const amountOut = r.word(at + 32 * 5);
372
+ if (!same(tokenOut, e.toToken)) return `the M0 order asks for ${tokenOut}, not ${e.toToken}`;
373
+ if (amountOut < e.minOut) return `the M0 order asks for ${amountOut}, below the ${e.minOut} shown`;
374
+ return null;
375
+ }
346
376
  var FACET_DATA = {
347
377
  AcrossV4: { refunds: [["refundAddress", 1]], zeroRefused: true },
348
378
  // the SpokePool depositor: an expired deposit refunds the input there
349
379
  AcrossV4Swap: { nested: acrossSwapRefunds },
350
380
  Centrifuge: { inline: 2, refunds: [["refundRecipient", 1]], zeroRefused: true },
351
381
  Chainflip: { nested: chainflipRefunds },
352
- Eco: { refunds: [["refundRecipient", 5]], zeroRefused: true },
382
+ Eco: { refunds: [["refundRecipient", 6]], zeroRefused: true, delivery: ecoDelivery },
353
383
  // the intent's creator, refunded its reward (the input) on expiry
354
384
  Frax: { inline: 5, refunds: [["refundRecipient", 3]], zeroRefused: true },
355
385
  Glacis: { inline: 4, refunds: [["refundAddress", 1]], zeroRefused: true },
356
386
  LayerSwap: { refunds: [["refundRecipient", 2]], zeroRefused: true },
357
387
  LiFiIntentEscrowV2: { refunds: [["depositAndRefundAddress", 2]], zeroRefused: true },
358
388
  // the escrow order's user
359
- M0: { inline: 7, refunds: [["refundRecipient", 1], ["orderOwner", 2]], zeroRefused: true },
389
+ M0: { inline: 7, refunds: [["refundRecipient", 1], ["orderOwner", 2]], zeroRefused: true, delivery: m0Delivery },
360
390
  // orderOwner gets a cancelled order back
361
391
  Mayan: { refunds: [["refundRecipient", 7]], nested: mayanRefunds, zeroRefused: true },
362
392
  NEARIntents: { refunds: [["refundRecipient", 6]], zeroRefused: true },
@@ -367,11 +397,14 @@ var FACET_DATA = {
367
397
  Superset: { refunds: [["refundAddress", 2], ["fallbackEoA", 3]], zeroRefused: true }
368
398
  };
369
399
  var NO_REFUND_FIELDS = /* @__PURE__ */ new Set(["Across", "AllBridge", "ArbitrumBridge", "CelerCircleBridge", "GasZip", "GnosisBridge", "MegaETHBridge", "OmniBridge", "OptimismBridge", "PolygonBridge", "Unit"]);
400
+ function facetDataAt(r, bridge, spec) {
401
+ const slot = 4 + (bridge.sourceSwaps ? 64 : 32);
402
+ return spec.inline ? slot : 4 + r.small(slot);
403
+ }
370
404
  function refundMismatch(r, bridge, e) {
371
405
  const spec = FACET_DATA[bridge.facet];
372
406
  if (!spec) return NO_REFUND_FIELDS.has(bridge.facet) ? null : `no known refund layout for ${bridge.facet}`;
373
- const slot = 4 + (bridge.sourceSwaps ? 64 : 32);
374
- const at = spec.inline ? slot : 4 + r.small(slot);
407
+ const at = facetDataAt(r, bridge, spec);
375
408
  const paid = (spec.refunds ?? []).map(([field, word]) => [`${bridge.facet} ${field}`, r.address(at + 32 * word), spec.zeroRefused === true]);
376
409
  paid.push(...spec.nested?.(r, at) ?? []);
377
410
  for (const [what, to, zeroRefused] of paid) {
@@ -426,6 +459,9 @@ function diamondCallMismatch(data, e) {
426
459
  if (hasSourceSwaps !== bridge.sourceSwaps) return `unknown Diamond call ${selector}`;
427
460
  const refund = refundMismatch(r, bridge, e);
428
461
  if (refund) return refund;
462
+ const spec = FACET_DATA[bridge.facet];
463
+ const delivery = spec?.delivery?.(r, facetDataAt(r, bridge, spec), e);
464
+ if (delivery) return delivery;
429
465
  if (hasSourceSwaps) {
430
466
  if (minAmount === 0n) return "bridges nothing after the source swaps";
431
467
  return checkSteps(swapsAt(r, 4, 4 + 32), e, sendingAssetId);
@@ -740,6 +776,9 @@ function lifiProvider(config = {}) {
740
776
  const fromToken = lifiToken(params);
741
777
  if (!fromToken) return null;
742
778
  const solanaSource = isSolana(params.sourceChain);
779
+ const crossChain = params.sourceChain !== params.destChain;
780
+ const noDestinationCall = crossChain && !solanaSource;
781
+ let routeScope = config.routeWideSlippage === true && !solanaSource && !isSolana(params.destChain);
743
782
  const dry = params.dry !== false;
744
783
  const fromAddress = params.refundAddress || (dry ? solanaSource ? SOLANA_PLACEHOLDER : EVM_PLACEHOLDER : "");
745
784
  const toAddress = params.destAddress || (dry ? fromAddress : "");
@@ -749,7 +788,7 @@ function lifiProvider(config = {}) {
749
788
  let sentSlippage = slippageBps / 1e4;
750
789
  let deadline;
751
790
  let choice = null;
752
- if (config.chooseRoute && params.sourceChain !== params.destChain) {
791
+ if (config.chooseRoute && crossChain) {
753
792
  try {
754
793
  const res = await fetch(`${apiBase}/advanced/routes`, {
755
794
  method: "POST",
@@ -762,7 +801,13 @@ function lifiProvider(config = {}) {
762
801
  fromAmount: params.amountIn,
763
802
  fromAddress,
764
803
  toAddress,
765
- options: { slippage: slippageBps / 1e4, ...solanaSource ? {} : { bridges: { deny: UNBOUND_TOOLS } }, ...integrator().trim() ? { integrator: integrator().trim() } : {} }
804
+ options: {
805
+ slippage: slippageBps / 1e4,
806
+ ...routeScope ? { slippageScope: "route" } : {},
807
+ ...solanaSource ? {} : { bridges: { deny: UNBOUND_TOOLS } },
808
+ ...noDestinationCall ? { allowDestinationCall: false } : {},
809
+ ...integrator().trim() ? { integrator: integrator().trim() } : {}
810
+ }
766
811
  }),
767
812
  signal: signal ?? (0, import_util3.timeoutSignal)(8e3)
768
813
  });
@@ -787,7 +832,9 @@ function lifiProvider(config = {}) {
787
832
  if (sentSlippage !== void 0) {
788
833
  url.searchParams.set("slippage", String(sentSlippage));
789
834
  }
790
- const unbound = params.sourceChain !== params.destChain && !solanaSource ? UNBOUND_TOOLS : [];
835
+ if (routeScope) url.searchParams.set("slippageScope", "route");
836
+ if (noDestinationCall) url.searchParams.set("allowDestinationCall", "false");
837
+ const unbound = crossChain && !solanaSource ? UNBOUND_TOOLS : [];
791
838
  for (const t of (choice?.allowBridges ?? []).filter((b) => solanaSource || !UNBOUND_TOOLS.includes(b))) url.searchParams.append("allowBridges", t);
792
839
  for (const t of /* @__PURE__ */ new Set([...choice?.denyBridges ?? [], ...unbound])) url.searchParams.append("denyBridges", t);
793
840
  if (choice?.order) url.searchParams.set("order", choice.order);
@@ -801,6 +848,11 @@ function lifiProvider(config = {}) {
801
848
  if (!res.ok) {
802
849
  const body = await res.json().catch(() => null);
803
850
  const reasons = [...new Set((body?.errors?.filteredOut ?? []).map((f) => f.reason).filter((r) => typeof r === "string"))];
851
+ if (routeScope && [typeof body?.message === "string" ? body.message : "", ...reasons].some((r) => /^ROUTE_SLIPPAGE_(UNSUPPORTED|UNAVAILABLE)/.test(r))) {
852
+ routeScope = false;
853
+ attempt--;
854
+ continue;
855
+ }
804
856
  const why = reasons.length === 1 ? ` (${reasons[0].slice(0, 200)})` : "";
805
857
  params.onRefusal?.(`lifi: ${typeof body?.message === "string" ? body.message.slice(0, 200) : `HTTP ${res.status}`}${why}`);
806
858
  return null;