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