@avail-project/ca-common 2.1.0 → 2.2.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.
@@ -3,9 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AutoSelectionError = void 0;
4
4
  exports.aggregateAggregators = aggregateAggregators;
5
5
  exports.autoSelectSourcesV2 = autoSelectSourcesV2;
6
+ exports.autoSelectSourcesV2ByRecipient = autoSelectSourcesV2ByRecipient;
6
7
  exports.determineDestinationSwaps = determineDestinationSwaps;
7
8
  exports.liquidateInputHoldings = liquidateInputHoldings;
9
+ exports.liquidateInputHoldingsByRecipient = liquidateInputHoldingsByRecipient;
8
10
  exports.destinationSwapWithExactIn = destinationSwapWithExactIn;
11
+ exports.getDestinationExactOutSwap = getDestinationExactOutSwap;
12
+ exports.getDestinationExactInSwap = getDestinationExactInSwap;
13
+ exports.liquidateSourceHoldings = liquidateSourceHoldings;
14
+ exports.autoSelectSources = autoSelectSources;
9
15
  const tslib_1 = require("tslib");
10
16
  const es_toolkit_1 = require("es-toolkit");
11
17
  const viem_1 = require("viem");
@@ -108,7 +114,18 @@ cots = [(1 COT, 1), (1 COT, 4)]
108
114
  break
109
115
  5. return quotes and assets used.
110
116
  */
117
+ /**
118
+ * @deprecated Use {@link autoSelectSources} (object args; per-holding `takerAddress` and
119
+ * `receiverAddress` on each `HoldingWithSwapAddresses`).
120
+ */
111
121
  async function autoSelectSourcesV2(userAddress, holdings, outputRequired, aggregators, commonCurrencyID = data_1.CurrencyID.USDC) {
122
+ return autoSelectSourcesV2ByRecipient(holdings.map((holding) => ({ ...holding, recipient: userAddress })), outputRequired, aggregators, commonCurrencyID);
123
+ }
124
+ /**
125
+ * @deprecated Use {@link autoSelectSources} (object args; per-holding `takerAddress` and
126
+ * `receiverAddress` on each `HoldingWithSwapAddresses`).
127
+ */
128
+ async function autoSelectSourcesV2ByRecipient(holdings, outputRequired, aggregators, commonCurrencyID = data_1.CurrencyID.USDC) {
112
129
  // Assumption: Holding is already sorted in usage priority
113
130
  console.debug("XCS | SSV2:", {
114
131
  holdings,
@@ -142,7 +159,10 @@ async function autoSelectSourcesV2(userAddress, holdings, outputRequired, aggreg
142
159
  else {
143
160
  fullLiquidationQuotes.push({
144
161
  req: {
145
- userAddress,
162
+ userAddress: holding.recipient,
163
+ // New wrappers thread per-holding receiver via this field. Falls back to taker
164
+ // (`recipient`) when absent — preserves legacy positional-call behavior.
165
+ receiverAddress: holding.receiverAddress,
146
166
  type: iface_1.QuoteType.EXACT_IN,
147
167
  chain: chain.ChainID,
148
168
  inputToken: holding.tokenAddress,
@@ -326,7 +346,11 @@ async function autoSelectSourcesV2(userAddress, holdings, outputRequired, aggreg
326
346
  console.log("final_quotes", { quotes: final, cots: usedCOTs });
327
347
  return { quoteResponses: final, usedCOTs };
328
348
  }
329
- async function determineDestinationSwaps(userAddress, requirement, aggregators, commonCurrencyID = data_1.CurrencyID.USDC) {
349
+ /**
350
+ * @deprecated Use {@link getDestinationExactOutSwap} (object args; explicit `takerAddress` and
351
+ * `receiverAddress`, both required).
352
+ */
353
+ async function determineDestinationSwaps(userAddress, requirement, aggregators, commonCurrencyID = data_1.CurrencyID.USDC, receiverAddress) {
330
354
  const chaindata = data_1.ChaindataMap.get(requirement.chainID);
331
355
  if (chaindata == null) {
332
356
  throw new AutoSelectionError("Chain not found");
@@ -341,6 +365,7 @@ async function determineDestinationSwaps(userAddress, requirement, aggregators,
341
365
  type: iface_1.QuoteType.EXACT_IN,
342
366
  chain: requirement.chainID,
343
367
  userAddress,
368
+ receiverAddress,
344
369
  inputToken: requirement.tokenAddress,
345
370
  outputToken: COT.tokenAddress,
346
371
  inputAmount: requirement.amountRaw,
@@ -364,6 +389,7 @@ async function determineDestinationSwaps(userAddress, requirement, aggregators,
364
389
  {
365
390
  type: iface_1.QuoteType.EXACT_IN,
366
391
  userAddress,
392
+ receiverAddress,
367
393
  chain: requirement.chainID,
368
394
  inputToken: COT.tokenAddress,
369
395
  outputToken: requirement.tokenAddress,
@@ -395,7 +421,18 @@ async function determineDestinationSwaps(userAddress, requirement, aggregators,
395
421
  }
396
422
  }
397
423
  }
398
- async function liquidateInputHoldings(userAddress, holdings, aggregators, commonCurrencyID = data_1.CurrencyID.USDC) {
424
+ /**
425
+ * @deprecated Use {@link liquidateSourceHoldings} (object args; per-holding `takerAddress`
426
+ * and `receiverAddress` on each `HoldingWithSwapAddresses`).
427
+ */
428
+ async function liquidateInputHoldings(userAddress, holdings, aggregators, commonCurrencyID = data_1.CurrencyID.USDC, receiverAddress) {
429
+ return liquidateInputHoldingsByRecipient(holdings.map((holding) => ({ ...holding, recipient: userAddress })), aggregators, commonCurrencyID, receiverAddress);
430
+ }
431
+ /**
432
+ * @deprecated Use {@link liquidateSourceHoldings} (object args; per-holding `takerAddress`
433
+ * and `receiverAddress` on each `HoldingWithSwapAddresses`).
434
+ */
435
+ async function liquidateInputHoldingsByRecipient(holdings, aggregators, commonCurrencyID = data_1.CurrencyID.USDC, receiverAddress) {
399
436
  console.debug("XCS | LIH | Holdings:", holdings);
400
437
  const groupedByChainID = (0, es_toolkit_1.groupBy)(holdings, (h) => (0, viem_1.bytesToHex)(h.chainID.toBytes()));
401
438
  const fullLiquidationQuotes = [];
@@ -419,7 +456,10 @@ async function liquidateInputHoldings(userAddress, holdings, aggregators, common
419
456
  }
420
457
  fullLiquidationQuotes.push({
421
458
  req: {
422
- userAddress,
459
+ userAddress: holding.recipient,
460
+ // Per-holding receiver wins (set by the new wrappers); shared param is the legacy
461
+ // positional-call fallback.
462
+ receiverAddress: holding.receiverAddress ?? receiverAddress,
423
463
  type: iface_1.QuoteType.EXACT_IN,
424
464
  chain: chain.ChainID,
425
465
  inputToken: holding.tokenAddress,
@@ -448,7 +488,11 @@ async function liquidateInputHoldings(userAddress, holdings, aggregators, common
448
488
  }
449
489
  return quotes;
450
490
  }
451
- async function destinationSwapWithExactIn(userAddress, omniChainID, inputAmount, outputToken, aggregators, inputCurrency = data_1.CurrencyID.USDC) {
491
+ /**
492
+ * @deprecated Use {@link getDestinationExactInSwap} (object args; explicit `takerAddress`
493
+ * and `receiverAddress`, both required).
494
+ */
495
+ async function destinationSwapWithExactIn(userAddress, omniChainID, inputAmount, outputToken, aggregators, inputCurrency = data_1.CurrencyID.USDC, receiverAddress) {
452
496
  const chaindata = data_1.ChaindataMap.get(omniChainID);
453
497
  if (chaindata == null) {
454
498
  throw new AutoSelectionError("Chain not found");
@@ -462,6 +506,7 @@ async function destinationSwapWithExactIn(userAddress, omniChainID, inputAmount,
462
506
  type: iface_1.QuoteType.EXACT_IN,
463
507
  chain: omniChainID,
464
508
  userAddress,
509
+ receiverAddress,
465
510
  inputToken: COT.tokenAddress,
466
511
  outputToken: outputToken,
467
512
  inputAmount: inputAmount,
@@ -486,3 +531,40 @@ async function destinationSwapWithExactIn(userAddress, omniChainID, inputAmount,
486
531
  },
487
532
  };
488
533
  }
534
+ // =====================================================================================
535
+ // Object-arg wrappers around the legacy positional functions above.
536
+ //
537
+ // Aggregator vocabulary:
538
+ // takerAddress — on-chain executor of the swap (drives aggregator simulation /
539
+ // permit / approval routing). On 7702 chains this is the ephemeral; on
540
+ // non-Pectra chains it's the deployed Safe. Maps to the underlying
541
+ // QuoteRequest's `userAddress`.
542
+ // receiverAddress — recipient of the swap output. Maps to the underlying QuoteRequest's
543
+ // `receiverAddress`. Required on all 4 wrappers — the GS013-class bug we
544
+ // fixed came from forgetting this and silently defaulting to the wrong
545
+ // address. Even on source side (where it equals the taker today), require
546
+ // it explicitly so the type system forces every call site to acknowledge
547
+ // both roles.
548
+ //
549
+ // Wrap-only: each wrapper delegates to the deprecated positional fn. No business logic added.
550
+ // =====================================================================================
551
+ async function getDestinationExactOutSwap(args) {
552
+ return determineDestinationSwaps(args.takerAddress, args.requirement, args.aggregators, args.commonCurrencyID, args.receiverAddress);
553
+ }
554
+ async function getDestinationExactInSwap(args) {
555
+ return destinationSwapWithExactIn(args.takerAddress, args.chain, args.inputAmount, args.outputToken, args.aggregators, args.inputCurrency, args.receiverAddress);
556
+ }
557
+ async function liquidateSourceHoldings(args) {
558
+ return liquidateInputHoldingsByRecipient(args.holdings.map((h) => ({
559
+ ...h,
560
+ recipient: h.takerAddress,
561
+ receiverAddress: h.receiverAddress,
562
+ })), args.aggregators, args.commonCurrencyID);
563
+ }
564
+ async function autoSelectSources(args) {
565
+ return autoSelectSourcesV2ByRecipient(args.holdings.map((h) => ({
566
+ ...h,
567
+ recipient: h.takerAddress,
568
+ receiverAddress: h.receiverAddress,
569
+ })), args.outputRequired, args.aggregators, args.commonCurrencyID);
570
+ }
@@ -14,17 +14,11 @@ const ChainNameMapping = new Map(Object.entries({
14
14
  arbitrum: 42161,
15
15
  optimism: 10,
16
16
  base: 8453,
17
- taiko: 167000,
18
17
  bsc: 56,
19
- monadtestnet: 10143,
20
- megaethtestnet: 6342,
21
- berachain: 80094,
18
+ avalanche: 43114,
22
19
  polygon: 137,
23
- zksync: 324,
24
- blast: 81457,
25
- mode: 34443,
26
20
  scroll: 534352,
27
- superseed: 5330,
21
+ hyperevm: 999,
28
22
  }).map(([k, v]) => [(0, viem_1.bytesToHex)((0, data_1.encodeChainID36)(definition_1.Universe.ETHEREUM, v)), k]));
29
23
  class BebopAggregator {
30
24
  static BASE_URL = "https://api.bebop.xyz/router";
@@ -56,6 +50,9 @@ class BebopAggregator {
56
50
  const inputTokenAddr = (0, viem_1.getAddress)((0, viem_1.bytesToHex)(r.inputToken.subarray(12)));
57
51
  const outputTokenAddr = (0, viem_1.getAddress)((0, viem_1.bytesToHex)(r.outputToken.subarray(12)));
58
52
  const userAddrHex = (0, viem_1.getAddress)((0, viem_1.bytesToHex)(r.userAddress.subarray(12)));
53
+ const receiverAddrHex = r.receiverAddress != null
54
+ ? (0, viem_1.getAddress)((0, viem_1.bytesToHex)(r.receiverAddress.subarray(12)))
55
+ : userAddrHex;
59
56
  switch (r.type) {
60
57
  case iface_1.QuoteType.EXACT_IN: {
61
58
  respPromise = this.axios({
@@ -65,6 +62,7 @@ class BebopAggregator {
65
62
  sell_tokens: inputTokenAddr,
66
63
  buy_tokens: outputTokenAddr,
67
64
  taker_address: userAddrHex,
65
+ receiver_address: receiverAddrHex,
68
66
  sell_amounts: r.inputAmount.toString(),
69
67
  ...BebopAggregator.COMMON_OPTIONS,
70
68
  },
@@ -79,6 +77,7 @@ class BebopAggregator {
79
77
  sell_tokens: inputTokenAddr,
80
78
  buy_tokens: outputTokenAddr,
81
79
  taker_address: userAddrHex,
80
+ receiver_address: receiverAddrHex,
82
81
  buy_amounts: r.outputAmount.toString(),
83
82
  ...BebopAggregator.COMMON_OPTIONS,
84
83
  },
@@ -10,7 +10,7 @@ const evmabi_1 = require("../evmabi");
10
10
  const definition_1 = require("../proto/definition");
11
11
  const iface_1 = require("./iface");
12
12
  const ChainNameMapping = new data_1.ChainIDKeyedMap([
13
- [new data_1.OmniversalChainID(definition_1.Universe.ETHEREUM, 8453), "base"],
13
+ // [new OmniversalChainID(Universe.ETHEREUM, 8453), "base"], // Disabled because of few liquidity issues
14
14
  [new data_1.OmniversalChainID(definition_1.Universe.ETHEREUM, 999), "hyperevm"],
15
15
  [new data_1.OmniversalChainID(definition_1.Universe.ETHEREUM, 143), "monad"],
16
16
  [new data_1.OmniversalChainID(definition_1.Universe.ETHEREUM, 4114), "citrea"],
@@ -43,6 +43,9 @@ class FibrousAggregator {
43
43
  const inputTokenAddr = (0, viem_1.getAddress)((0, viem_1.bytesToHex)(r.inputToken.subarray(12)));
44
44
  const outputTokenAddr = (0, viem_1.getAddress)((0, viem_1.bytesToHex)(r.outputToken.subarray(12)));
45
45
  const userAddrHex = (0, viem_1.getAddress)((0, viem_1.bytesToHex)(r.userAddress.subarray(12)));
46
+ const receiverAddrHex = r.receiverAddress != null
47
+ ? (0, viem_1.getAddress)((0, viem_1.bytesToHex)(r.receiverAddress.subarray(12)))
48
+ : userAddrHex;
46
49
  let resp;
47
50
  try {
48
51
  resp = await this.axios({
@@ -53,7 +56,7 @@ class FibrousAggregator {
53
56
  tokenInAddress: inputTokenAddr,
54
57
  tokenOutAddress: outputTokenAddr,
55
58
  slippage: this.slippage,
56
- destination: userAddrHex,
59
+ destination: receiverAddrHex,
57
60
  },
58
61
  });
59
62
  }
@@ -7,6 +7,20 @@ const viem_1 = require("viem");
7
7
  const iface_1 = require("./iface");
8
8
  const definition_1 = require("../proto/definition");
9
9
  const decimal_js_1 = tslib_1.__importDefault(require("decimal.js"));
10
+ const ALLOWED_CHAINS = new Set([
11
+ 1, // Ethereum
12
+ 10, // Optimism
13
+ 56, // BSC
14
+ 137, // Polygon
15
+ 143, // Monad
16
+ 999, // HyperEVM
17
+ 4326, // MegaETH
18
+ 8453, // Base
19
+ 42161, // Arbitrum
20
+ 43114, // Avalanche
21
+ 8217, // Kaia
22
+ 534352, // Scroll
23
+ ]);
10
24
  class LiFiAggregator {
11
25
  static BASE_URL_V1 = "https://li.quest/v1";
12
26
  static COMMON_OPTIONS = {
@@ -29,11 +43,17 @@ class LiFiAggregator {
29
43
  if (r.chain.universe !== definition_1.Universe.ETHEREUM) {
30
44
  return null;
31
45
  }
46
+ if (!ALLOWED_CHAINS.has(Number(r.chain.chainID))) {
47
+ return null;
48
+ }
32
49
  let respPromise;
33
50
  const chIDStr = r.chain.chainID.toString();
34
51
  const inputTokenAddr = (0, viem_1.getAddress)((0, viem_1.bytesToHex)(r.inputToken.subarray(12)));
35
52
  const outputTokenAddr = (0, viem_1.getAddress)((0, viem_1.bytesToHex)(r.outputToken.subarray(12)));
36
53
  const userAddrHex = (0, viem_1.getAddress)((0, viem_1.bytesToHex)(r.userAddress.subarray(12)));
54
+ const receiverAddrHex = r.receiverAddress != null
55
+ ? (0, viem_1.getAddress)((0, viem_1.bytesToHex)(r.receiverAddress.subarray(12)))
56
+ : userAddrHex;
37
57
  switch (r.type) {
38
58
  case iface_1.QuoteType.EXACT_IN: {
39
59
  respPromise = this.axios({
@@ -45,6 +65,7 @@ class LiFiAggregator {
45
65
  fromToken: inputTokenAddr,
46
66
  toToken: outputTokenAddr,
47
67
  fromAddress: userAddrHex,
68
+ toAddress: receiverAddrHex,
48
69
  fromAmount: r.inputAmount.toString(),
49
70
  ...LiFiAggregator.COMMON_OPTIONS,
50
71
  },
@@ -61,6 +82,7 @@ class LiFiAggregator {
61
82
  fromToken: inputTokenAddr,
62
83
  toToken: outputTokenAddr,
63
84
  fromAddress: userAddrHex,
85
+ toAddress: receiverAddrHex,
64
86
  toAmount: r.outputAmount.toString(),
65
87
  ...LiFiAggregator.COMMON_OPTIONS,
66
88
  },
@@ -98,7 +98,18 @@ cots = [(1 COT, 1), (1 COT, 4)]
98
98
  break
99
99
  5. return quotes and assets used.
100
100
  */
101
+ /**
102
+ * @deprecated Use {@link autoSelectSources} (object args; per-holding `takerAddress` and
103
+ * `receiverAddress` on each `HoldingWithSwapAddresses`).
104
+ */
101
105
  export async function autoSelectSourcesV2(userAddress, holdings, outputRequired, aggregators, commonCurrencyID = CurrencyID.USDC) {
106
+ return autoSelectSourcesV2ByRecipient(holdings.map((holding) => ({ ...holding, recipient: userAddress })), outputRequired, aggregators, commonCurrencyID);
107
+ }
108
+ /**
109
+ * @deprecated Use {@link autoSelectSources} (object args; per-holding `takerAddress` and
110
+ * `receiverAddress` on each `HoldingWithSwapAddresses`).
111
+ */
112
+ export async function autoSelectSourcesV2ByRecipient(holdings, outputRequired, aggregators, commonCurrencyID = CurrencyID.USDC) {
102
113
  // Assumption: Holding is already sorted in usage priority
103
114
  console.debug("XCS | SSV2:", {
104
115
  holdings,
@@ -132,7 +143,10 @@ export async function autoSelectSourcesV2(userAddress, holdings, outputRequired,
132
143
  else {
133
144
  fullLiquidationQuotes.push({
134
145
  req: {
135
- userAddress,
146
+ userAddress: holding.recipient,
147
+ // New wrappers thread per-holding receiver via this field. Falls back to taker
148
+ // (`recipient`) when absent — preserves legacy positional-call behavior.
149
+ receiverAddress: holding.receiverAddress,
136
150
  type: QuoteType.EXACT_IN,
137
151
  chain: chain.ChainID,
138
152
  inputToken: holding.tokenAddress,
@@ -316,7 +330,11 @@ export async function autoSelectSourcesV2(userAddress, holdings, outputRequired,
316
330
  console.log("final_quotes", { quotes: final, cots: usedCOTs });
317
331
  return { quoteResponses: final, usedCOTs };
318
332
  }
319
- export async function determineDestinationSwaps(userAddress, requirement, aggregators, commonCurrencyID = CurrencyID.USDC) {
333
+ /**
334
+ * @deprecated Use {@link getDestinationExactOutSwap} (object args; explicit `takerAddress` and
335
+ * `receiverAddress`, both required).
336
+ */
337
+ export async function determineDestinationSwaps(userAddress, requirement, aggregators, commonCurrencyID = CurrencyID.USDC, receiverAddress) {
320
338
  const chaindata = ChaindataMap.get(requirement.chainID);
321
339
  if (chaindata == null) {
322
340
  throw new AutoSelectionError("Chain not found");
@@ -331,6 +349,7 @@ export async function determineDestinationSwaps(userAddress, requirement, aggreg
331
349
  type: QuoteType.EXACT_IN,
332
350
  chain: requirement.chainID,
333
351
  userAddress,
352
+ receiverAddress,
334
353
  inputToken: requirement.tokenAddress,
335
354
  outputToken: COT.tokenAddress,
336
355
  inputAmount: requirement.amountRaw,
@@ -354,6 +373,7 @@ export async function determineDestinationSwaps(userAddress, requirement, aggreg
354
373
  {
355
374
  type: QuoteType.EXACT_IN,
356
375
  userAddress,
376
+ receiverAddress,
357
377
  chain: requirement.chainID,
358
378
  inputToken: COT.tokenAddress,
359
379
  outputToken: requirement.tokenAddress,
@@ -385,7 +405,18 @@ export async function determineDestinationSwaps(userAddress, requirement, aggreg
385
405
  }
386
406
  }
387
407
  }
388
- export async function liquidateInputHoldings(userAddress, holdings, aggregators, commonCurrencyID = CurrencyID.USDC) {
408
+ /**
409
+ * @deprecated Use {@link liquidateSourceHoldings} (object args; per-holding `takerAddress`
410
+ * and `receiverAddress` on each `HoldingWithSwapAddresses`).
411
+ */
412
+ export async function liquidateInputHoldings(userAddress, holdings, aggregators, commonCurrencyID = CurrencyID.USDC, receiverAddress) {
413
+ return liquidateInputHoldingsByRecipient(holdings.map((holding) => ({ ...holding, recipient: userAddress })), aggregators, commonCurrencyID, receiverAddress);
414
+ }
415
+ /**
416
+ * @deprecated Use {@link liquidateSourceHoldings} (object args; per-holding `takerAddress`
417
+ * and `receiverAddress` on each `HoldingWithSwapAddresses`).
418
+ */
419
+ export async function liquidateInputHoldingsByRecipient(holdings, aggregators, commonCurrencyID = CurrencyID.USDC, receiverAddress) {
389
420
  console.debug("XCS | LIH | Holdings:", holdings);
390
421
  const groupedByChainID = groupBy(holdings, (h) => bytesToHex(h.chainID.toBytes()));
391
422
  const fullLiquidationQuotes = [];
@@ -409,7 +440,10 @@ export async function liquidateInputHoldings(userAddress, holdings, aggregators,
409
440
  }
410
441
  fullLiquidationQuotes.push({
411
442
  req: {
412
- userAddress,
443
+ userAddress: holding.recipient,
444
+ // Per-holding receiver wins (set by the new wrappers); shared param is the legacy
445
+ // positional-call fallback.
446
+ receiverAddress: holding.receiverAddress ?? receiverAddress,
413
447
  type: QuoteType.EXACT_IN,
414
448
  chain: chain.ChainID,
415
449
  inputToken: holding.tokenAddress,
@@ -438,7 +472,11 @@ export async function liquidateInputHoldings(userAddress, holdings, aggregators,
438
472
  }
439
473
  return quotes;
440
474
  }
441
- export async function destinationSwapWithExactIn(userAddress, omniChainID, inputAmount, outputToken, aggregators, inputCurrency = CurrencyID.USDC) {
475
+ /**
476
+ * @deprecated Use {@link getDestinationExactInSwap} (object args; explicit `takerAddress`
477
+ * and `receiverAddress`, both required).
478
+ */
479
+ export async function destinationSwapWithExactIn(userAddress, omniChainID, inputAmount, outputToken, aggregators, inputCurrency = CurrencyID.USDC, receiverAddress) {
442
480
  const chaindata = ChaindataMap.get(omniChainID);
443
481
  if (chaindata == null) {
444
482
  throw new AutoSelectionError("Chain not found");
@@ -452,6 +490,7 @@ export async function destinationSwapWithExactIn(userAddress, omniChainID, input
452
490
  type: QuoteType.EXACT_IN,
453
491
  chain: omniChainID,
454
492
  userAddress,
493
+ receiverAddress,
455
494
  inputToken: COT.tokenAddress,
456
495
  outputToken: outputToken,
457
496
  inputAmount: inputAmount,
@@ -476,3 +515,40 @@ export async function destinationSwapWithExactIn(userAddress, omniChainID, input
476
515
  },
477
516
  };
478
517
  }
518
+ // =====================================================================================
519
+ // Object-arg wrappers around the legacy positional functions above.
520
+ //
521
+ // Aggregator vocabulary:
522
+ // takerAddress — on-chain executor of the swap (drives aggregator simulation /
523
+ // permit / approval routing). On 7702 chains this is the ephemeral; on
524
+ // non-Pectra chains it's the deployed Safe. Maps to the underlying
525
+ // QuoteRequest's `userAddress`.
526
+ // receiverAddress — recipient of the swap output. Maps to the underlying QuoteRequest's
527
+ // `receiverAddress`. Required on all 4 wrappers — the GS013-class bug we
528
+ // fixed came from forgetting this and silently defaulting to the wrong
529
+ // address. Even on source side (where it equals the taker today), require
530
+ // it explicitly so the type system forces every call site to acknowledge
531
+ // both roles.
532
+ //
533
+ // Wrap-only: each wrapper delegates to the deprecated positional fn. No business logic added.
534
+ // =====================================================================================
535
+ export async function getDestinationExactOutSwap(args) {
536
+ return determineDestinationSwaps(args.takerAddress, args.requirement, args.aggregators, args.commonCurrencyID, args.receiverAddress);
537
+ }
538
+ export async function getDestinationExactInSwap(args) {
539
+ return destinationSwapWithExactIn(args.takerAddress, args.chain, args.inputAmount, args.outputToken, args.aggregators, args.inputCurrency, args.receiverAddress);
540
+ }
541
+ export async function liquidateSourceHoldings(args) {
542
+ return liquidateInputHoldingsByRecipient(args.holdings.map((h) => ({
543
+ ...h,
544
+ recipient: h.takerAddress,
545
+ receiverAddress: h.receiverAddress,
546
+ })), args.aggregators, args.commonCurrencyID);
547
+ }
548
+ export async function autoSelectSources(args) {
549
+ return autoSelectSourcesV2ByRecipient(args.holdings.map((h) => ({
550
+ ...h,
551
+ recipient: h.takerAddress,
552
+ receiverAddress: h.receiverAddress,
553
+ })), args.outputRequired, args.aggregators, args.commonCurrencyID);
554
+ }
@@ -10,17 +10,11 @@ const ChainNameMapping = new Map(Object.entries({
10
10
  arbitrum: 42161,
11
11
  optimism: 10,
12
12
  base: 8453,
13
- taiko: 167000,
14
13
  bsc: 56,
15
- monadtestnet: 10143,
16
- megaethtestnet: 6342,
17
- berachain: 80094,
14
+ avalanche: 43114,
18
15
  polygon: 137,
19
- zksync: 324,
20
- blast: 81457,
21
- mode: 34443,
22
16
  scroll: 534352,
23
- superseed: 5330,
17
+ hyperevm: 999,
24
18
  }).map(([k, v]) => [bytesToHex(encodeChainID36(Universe.ETHEREUM, v)), k]));
25
19
  export class BebopAggregator {
26
20
  static BASE_URL = "https://api.bebop.xyz/router";
@@ -52,6 +46,9 @@ export class BebopAggregator {
52
46
  const inputTokenAddr = getAddress(bytesToHex(r.inputToken.subarray(12)));
53
47
  const outputTokenAddr = getAddress(bytesToHex(r.outputToken.subarray(12)));
54
48
  const userAddrHex = getAddress(bytesToHex(r.userAddress.subarray(12)));
49
+ const receiverAddrHex = r.receiverAddress != null
50
+ ? getAddress(bytesToHex(r.receiverAddress.subarray(12)))
51
+ : userAddrHex;
55
52
  switch (r.type) {
56
53
  case QuoteType.EXACT_IN: {
57
54
  respPromise = this.axios({
@@ -61,6 +58,7 @@ export class BebopAggregator {
61
58
  sell_tokens: inputTokenAddr,
62
59
  buy_tokens: outputTokenAddr,
63
60
  taker_address: userAddrHex,
61
+ receiver_address: receiverAddrHex,
64
62
  sell_amounts: r.inputAmount.toString(),
65
63
  ...BebopAggregator.COMMON_OPTIONS,
66
64
  },
@@ -75,6 +73,7 @@ export class BebopAggregator {
75
73
  sell_tokens: inputTokenAddr,
76
74
  buy_tokens: outputTokenAddr,
77
75
  taker_address: userAddrHex,
76
+ receiver_address: receiverAddrHex,
78
77
  buy_amounts: r.outputAmount.toString(),
79
78
  ...BebopAggregator.COMMON_OPTIONS,
80
79
  },
@@ -6,7 +6,7 @@ import { FibrousRouterABI } from "../evmabi";
6
6
  import { Universe } from "../proto/definition";
7
7
  import { QuoteType, } from "./iface";
8
8
  const ChainNameMapping = new ChainIDKeyedMap([
9
- [new OmniversalChainID(Universe.ETHEREUM, 8453), "base"],
9
+ // [new OmniversalChainID(Universe.ETHEREUM, 8453), "base"], // Disabled because of few liquidity issues
10
10
  [new OmniversalChainID(Universe.ETHEREUM, 999), "hyperevm"],
11
11
  [new OmniversalChainID(Universe.ETHEREUM, 143), "monad"],
12
12
  [new OmniversalChainID(Universe.ETHEREUM, 4114), "citrea"],
@@ -39,6 +39,9 @@ export class FibrousAggregator {
39
39
  const inputTokenAddr = getAddress(bytesToHex(r.inputToken.subarray(12)));
40
40
  const outputTokenAddr = getAddress(bytesToHex(r.outputToken.subarray(12)));
41
41
  const userAddrHex = getAddress(bytesToHex(r.userAddress.subarray(12)));
42
+ const receiverAddrHex = r.receiverAddress != null
43
+ ? getAddress(bytesToHex(r.receiverAddress.subarray(12)))
44
+ : userAddrHex;
42
45
  let resp;
43
46
  try {
44
47
  resp = await this.axios({
@@ -49,7 +52,7 @@ export class FibrousAggregator {
49
52
  tokenInAddress: inputTokenAddr,
50
53
  tokenOutAddress: outputTokenAddr,
51
54
  slippage: this.slippage,
52
- destination: userAddrHex,
55
+ destination: receiverAddrHex,
53
56
  },
54
57
  });
55
58
  }
@@ -3,6 +3,20 @@ import { bytesToHex, getAddress } from "viem";
3
3
  import { QuoteType, } from "./iface";
4
4
  import { Universe } from "../proto/definition";
5
5
  import Decimal from "decimal.js";
6
+ const ALLOWED_CHAINS = new Set([
7
+ 1, // Ethereum
8
+ 10, // Optimism
9
+ 56, // BSC
10
+ 137, // Polygon
11
+ 143, // Monad
12
+ 999, // HyperEVM
13
+ 4326, // MegaETH
14
+ 8453, // Base
15
+ 42161, // Arbitrum
16
+ 43114, // Avalanche
17
+ 8217, // Kaia
18
+ 534352, // Scroll
19
+ ]);
6
20
  export class LiFiAggregator {
7
21
  static BASE_URL_V1 = "https://li.quest/v1";
8
22
  static COMMON_OPTIONS = {
@@ -25,11 +39,17 @@ export class LiFiAggregator {
25
39
  if (r.chain.universe !== Universe.ETHEREUM) {
26
40
  return null;
27
41
  }
42
+ if (!ALLOWED_CHAINS.has(Number(r.chain.chainID))) {
43
+ return null;
44
+ }
28
45
  let respPromise;
29
46
  const chIDStr = r.chain.chainID.toString();
30
47
  const inputTokenAddr = getAddress(bytesToHex(r.inputToken.subarray(12)));
31
48
  const outputTokenAddr = getAddress(bytesToHex(r.outputToken.subarray(12)));
32
49
  const userAddrHex = getAddress(bytesToHex(r.userAddress.subarray(12)));
50
+ const receiverAddrHex = r.receiverAddress != null
51
+ ? getAddress(bytesToHex(r.receiverAddress.subarray(12)))
52
+ : userAddrHex;
33
53
  switch (r.type) {
34
54
  case QuoteType.EXACT_IN: {
35
55
  respPromise = this.axios({
@@ -41,6 +61,7 @@ export class LiFiAggregator {
41
61
  fromToken: inputTokenAddr,
42
62
  toToken: outputTokenAddr,
43
63
  fromAddress: userAddrHex,
64
+ toAddress: receiverAddrHex,
44
65
  fromAmount: r.inputAmount.toString(),
45
66
  ...LiFiAggregator.COMMON_OPTIONS,
46
67
  },
@@ -57,6 +78,7 @@ export class LiFiAggregator {
57
78
  fromToken: inputTokenAddr,
58
79
  toToken: outputTokenAddr,
59
80
  fromAddress: userAddrHex,
81
+ toAddress: receiverAddrHex,
60
82
  toAmount: r.outputAmount.toString(),
61
83
  ...LiFiAggregator.COMMON_OPTIONS,
62
84
  },
@@ -3,6 +3,14 @@ import { Aggregator, Quote, QuoteRequestExactInput, QuoteRequestExactOutput, Quo
3
3
  import { Currency, CurrencyID, OmniversalChainID } from "../data";
4
4
  import { Bytes } from "../types";
5
5
  import { Holding } from "./iface";
6
+ export type HoldingWithRecipient = Holding & {
7
+ recipient: Bytes;
8
+ receiverAddress?: Bytes;
9
+ };
10
+ export type HoldingWithSwapAddresses = Holding & {
11
+ takerAddress: Bytes;
12
+ receiverAddress: Bytes;
13
+ };
6
14
  export declare class AutoSelectionError extends Error {
7
15
  }
8
16
  declare const enum AggregateAggregatorsMode {
@@ -13,6 +21,10 @@ export declare function aggregateAggregators(requests: (QuoteRequestExactInput |
13
21
  quote: Quote | null;
14
22
  aggregator: Aggregator;
15
23
  }[]>;
24
+ /**
25
+ * @deprecated Use {@link autoSelectSources} (object args; per-holding `takerAddress` and
26
+ * `receiverAddress` on each `HoldingWithSwapAddresses`).
27
+ */
16
28
  export declare function autoSelectSourcesV2(userAddress: Bytes, holdings: Holding[], outputRequired: Decimal, aggregators: Aggregator[], commonCurrencyID?: CurrencyID): Promise<{
17
29
  quoteResponses: QuoteResponse[];
18
30
  usedCOTs: {
@@ -22,7 +34,72 @@ export declare function autoSelectSourcesV2(userAddress: Bytes, holdings: Holdin
22
34
  cur: Currency;
23
35
  }[];
24
36
  }>;
25
- export declare function determineDestinationSwaps(userAddress: Bytes, requirement: Holding, aggregators: Aggregator[], commonCurrencyID?: CurrencyID): Promise<QuoteResponse>;
26
- export declare function liquidateInputHoldings(userAddress: Bytes, holdings: Holding[], aggregators: Aggregator[], commonCurrencyID?: CurrencyID): Promise<QuoteResponse[]>;
27
- export declare function destinationSwapWithExactIn(userAddress: Bytes, omniChainID: OmniversalChainID, inputAmount: bigint, outputToken: Bytes, aggregators: Aggregator[], inputCurrency?: CurrencyID): Promise<QuoteResponse>;
37
+ /**
38
+ * @deprecated Use {@link autoSelectSources} (object args; per-holding `takerAddress` and
39
+ * `receiverAddress` on each `HoldingWithSwapAddresses`).
40
+ */
41
+ export declare function autoSelectSourcesV2ByRecipient(holdings: HoldingWithRecipient[], outputRequired: Decimal, aggregators: Aggregator[], commonCurrencyID?: CurrencyID): Promise<{
42
+ quoteResponses: QuoteResponse[];
43
+ usedCOTs: {
44
+ originalHolding: Holding;
45
+ amountUsed: Decimal;
46
+ idx: number;
47
+ cur: Currency;
48
+ }[];
49
+ }>;
50
+ /**
51
+ * @deprecated Use {@link getDestinationExactOutSwap} (object args; explicit `takerAddress` and
52
+ * `receiverAddress`, both required).
53
+ */
54
+ export declare function determineDestinationSwaps(userAddress: Bytes, requirement: Holding, aggregators: Aggregator[], commonCurrencyID?: CurrencyID, receiverAddress?: Bytes): Promise<QuoteResponse>;
55
+ /**
56
+ * @deprecated Use {@link liquidateSourceHoldings} (object args; per-holding `takerAddress`
57
+ * and `receiverAddress` on each `HoldingWithSwapAddresses`).
58
+ */
59
+ export declare function liquidateInputHoldings(userAddress: Bytes, holdings: Holding[], aggregators: Aggregator[], commonCurrencyID?: CurrencyID, receiverAddress?: Bytes): Promise<QuoteResponse[]>;
60
+ /**
61
+ * @deprecated Use {@link liquidateSourceHoldings} (object args; per-holding `takerAddress`
62
+ * and `receiverAddress` on each `HoldingWithSwapAddresses`).
63
+ */
64
+ export declare function liquidateInputHoldingsByRecipient(holdings: HoldingWithRecipient[], aggregators: Aggregator[], commonCurrencyID?: CurrencyID, receiverAddress?: Bytes): Promise<QuoteResponse[]>;
65
+ /**
66
+ * @deprecated Use {@link getDestinationExactInSwap} (object args; explicit `takerAddress`
67
+ * and `receiverAddress`, both required).
68
+ */
69
+ export declare function destinationSwapWithExactIn(userAddress: Bytes, omniChainID: OmniversalChainID, inputAmount: bigint, outputToken: Bytes, aggregators: Aggregator[], inputCurrency?: CurrencyID, receiverAddress?: Bytes): Promise<QuoteResponse>;
70
+ export declare function getDestinationExactOutSwap(args: {
71
+ takerAddress: Bytes;
72
+ receiverAddress: Bytes;
73
+ requirement: Holding;
74
+ aggregators: Aggregator[];
75
+ commonCurrencyID?: CurrencyID;
76
+ }): Promise<QuoteResponse>;
77
+ export declare function getDestinationExactInSwap(args: {
78
+ takerAddress: Bytes;
79
+ receiverAddress: Bytes;
80
+ chain: OmniversalChainID;
81
+ inputAmount: bigint;
82
+ outputToken: Bytes;
83
+ aggregators: Aggregator[];
84
+ inputCurrency?: CurrencyID;
85
+ }): Promise<QuoteResponse>;
86
+ export declare function liquidateSourceHoldings(args: {
87
+ holdings: HoldingWithSwapAddresses[];
88
+ aggregators: Aggregator[];
89
+ commonCurrencyID?: CurrencyID;
90
+ }): Promise<QuoteResponse[]>;
91
+ export declare function autoSelectSources(args: {
92
+ holdings: HoldingWithSwapAddresses[];
93
+ outputRequired: Decimal;
94
+ aggregators: Aggregator[];
95
+ commonCurrencyID?: CurrencyID;
96
+ }): Promise<{
97
+ quoteResponses: QuoteResponse[];
98
+ usedCOTs: {
99
+ originalHolding: Holding;
100
+ amountUsed: Decimal;
101
+ idx: number;
102
+ cur: Currency;
103
+ }[];
104
+ }>;
28
105
  export {};
@@ -49,6 +49,7 @@ export interface Quote {
49
49
  }
50
50
  type CommonQuoteParameters = {
51
51
  userAddress: Bytes;
52
+ receiverAddress?: Bytes;
52
53
  chain: OmniversalChainID;
53
54
  inputToken: Bytes;
54
55
  outputToken: Bytes;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@avail-project/ca-common",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "common utilities for CA",
5
5
  "files": [
6
6
  "dist"