@avail-project/ca-common 2.2.1 → 3.0.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 (92) hide show
  1. package/dist/cjs/index.js +10593 -20
  2. package/dist/esm/index.mjs +10603 -0
  3. package/dist/types/index.d.ts +2608 -13
  4. package/package.json +41 -37
  5. package/dist/cjs/_polyfill.js +0 -147
  6. package/dist/cjs/balances/ub-api.js +0 -25
  7. package/dist/cjs/cosmos/index.js +0 -31
  8. package/dist/cjs/data/chaindata.js +0 -788
  9. package/dist/cjs/data/chainid.js +0 -93
  10. package/dist/cjs/data/currency.js +0 -78
  11. package/dist/cjs/data/index.js +0 -7
  12. package/dist/cjs/data/utils.js +0 -44
  13. package/dist/cjs/evmabi/erc20.abi.js +0 -349
  14. package/dist/cjs/evmabi/fibrousrouter.abi.js +0 -41
  15. package/dist/cjs/evmabi/index.js +0 -7
  16. package/dist/cjs/evmabi/vault.abi.js +0 -1021
  17. package/dist/cjs/evmabi/yakaggregator.abi.js +0 -275
  18. package/dist/cjs/permitutils/index.js +0 -186
  19. package/dist/cjs/proto/client.js +0 -48
  20. package/dist/cjs/proto/definition.js +0 -4131
  21. package/dist/cjs/proto/grpc.js +0 -298
  22. package/dist/cjs/rff/rff.js +0 -42
  23. package/dist/cjs/types/binarytypes.js +0 -2
  24. package/dist/cjs/types/index.js +0 -5
  25. package/dist/cjs/types/msgpack-axios.js +0 -22
  26. package/dist/cjs/vaultcontracts/index.js +0 -4
  27. package/dist/cjs/vaultcontracts/vaultcontracts.js +0 -222
  28. package/dist/cjs/xcs/autochoice.js +0 -570
  29. package/dist/cjs/xcs/bebop-agg.js +0 -156
  30. package/dist/cjs/xcs/fibrous-agg.js +0 -155
  31. package/dist/cjs/xcs/iface.js +0 -13
  32. package/dist/cjs/xcs/index.js +0 -8
  33. package/dist/cjs/xcs/lifi-agg.js +0 -155
  34. package/dist/esm/_polyfill.js +0 -143
  35. package/dist/esm/balances/ub-api.js +0 -21
  36. package/dist/esm/cosmos/index.js +0 -26
  37. package/dist/esm/data/chaindata.js +0 -785
  38. package/dist/esm/data/chainid.js +0 -87
  39. package/dist/esm/data/currency.js +0 -73
  40. package/dist/esm/data/index.js +0 -4
  41. package/dist/esm/data/utils.js +0 -34
  42. package/dist/esm/evmabi/erc20.abi.js +0 -346
  43. package/dist/esm/evmabi/fibrousrouter.abi.js +0 -38
  44. package/dist/esm/evmabi/index.js +0 -4
  45. package/dist/esm/evmabi/vault.abi.js +0 -1018
  46. package/dist/esm/evmabi/yakaggregator.abi.js +0 -272
  47. package/dist/esm/index.js +0 -13
  48. package/dist/esm/permitutils/index.js +0 -181
  49. package/dist/esm/proto/client.js +0 -11
  50. package/dist/esm/proto/definition.js +0 -4122
  51. package/dist/esm/proto/grpc.js +0 -292
  52. package/dist/esm/rff/rff.js +0 -38
  53. package/dist/esm/types/binarytypes.js +0 -1
  54. package/dist/esm/types/index.js +0 -2
  55. package/dist/esm/types/msgpack-axios.js +0 -18
  56. package/dist/esm/vaultcontracts/index.js +0 -1
  57. package/dist/esm/vaultcontracts/vaultcontracts.js +0 -218
  58. package/dist/esm/xcs/autochoice.js +0 -554
  59. package/dist/esm/xcs/bebop-agg.js +0 -151
  60. package/dist/esm/xcs/fibrous-agg.js +0 -150
  61. package/dist/esm/xcs/iface.js +0 -10
  62. package/dist/esm/xcs/index.js +0 -5
  63. package/dist/esm/xcs/lifi-agg.js +0 -150
  64. package/dist/types/_polyfill.d.ts +0 -1
  65. package/dist/types/balances/ub-api.d.ts +0 -14
  66. package/dist/types/cosmos/index.d.ts +0 -6
  67. package/dist/types/data/chaindata.d.ts +0 -20
  68. package/dist/types/data/chainid.d.ts +0 -31
  69. package/dist/types/data/currency.d.ts +0 -30
  70. package/dist/types/data/index.d.ts +0 -4
  71. package/dist/types/data/utils.d.ts +0 -10
  72. package/dist/types/evmabi/erc20.abi.d.ts +0 -264
  73. package/dist/types/evmabi/fibrousrouter.abi.d.ts +0 -77
  74. package/dist/types/evmabi/index.d.ts +0 -4
  75. package/dist/types/evmabi/vault.abi.d.ts +0 -785
  76. package/dist/types/evmabi/yakaggregator.abi.d.ts +0 -298
  77. package/dist/types/permitutils/index.d.ts +0 -13
  78. package/dist/types/proto/client.d.ts +0 -2
  79. package/dist/types/proto/definition.d.ts +0 -382
  80. package/dist/types/proto/grpc.d.ts +0 -75
  81. package/dist/types/rff/rff.d.ts +0 -9
  82. package/dist/types/types/binarytypes.d.ts +0 -1
  83. package/dist/types/types/index.d.ts +0 -2
  84. package/dist/types/types/msgpack-axios.d.ts +0 -1
  85. package/dist/types/vaultcontracts/index.d.ts +0 -22
  86. package/dist/types/vaultcontracts/vaultcontracts.d.ts +0 -8
  87. package/dist/types/xcs/autochoice.d.ts +0 -105
  88. package/dist/types/xcs/bebop-agg.d.ts +0 -104
  89. package/dist/types/xcs/fibrous-agg.d.ts +0 -56
  90. package/dist/types/xcs/iface.d.ts +0 -69
  91. package/dist/types/xcs/index.d.ts +0 -5
  92. package/dist/types/xcs/lifi-agg.d.ts +0 -39
@@ -1,554 +0,0 @@
1
- import { groupBy } from "es-toolkit";
2
- import { bytesToHex } from "viem";
3
- import Decimal from "decimal.js";
4
- import { QuoteSeriousness, QuoteType, } from "./iface";
5
- import { ChaindataMap, convertBigIntToDecimal, convertDecimalToBigInt, CurrencyID, maxByBigInt, minByBigInt, } from "../data";
6
- export class AutoSelectionError extends Error {
7
- }
8
- const safetyMultiplier = new Decimal("1.025");
9
- export async function aggregateAggregators(requests, aggregators, mode) {
10
- const responses = await Promise.all(aggregators.map(async (agg) => {
11
- let quotes;
12
- try {
13
- quotes = await agg.getQuotes(requests);
14
- }
15
- catch (e) {
16
- console.log("XCS | Failed to get quote from", agg, "in aggregateAggregators.", requests, "with:", e);
17
- quotes = new Array(requests.length).fill(null);
18
- }
19
- return {
20
- quotes,
21
- agg,
22
- };
23
- }));
24
- const final = new Array(requests.length);
25
- switch (mode) {
26
- case 0 /* AggregateAggregatorsMode.MaximizeOutput */: {
27
- for (let i = 0; i < requests.length; i++) {
28
- const best = maxByBigInt(responses.map((ra) => ({ quote: ra.quotes[i], aggregator: ra.agg })), (r) => r.quote?.output.amountRaw ?? 0n);
29
- if (best != null) {
30
- final[i] = best;
31
- }
32
- else {
33
- final[i] = {
34
- quote: null,
35
- aggregator: aggregators[0],
36
- };
37
- }
38
- }
39
- break;
40
- }
41
- case 1 /* AggregateAggregatorsMode.MinimizeInput */: {
42
- for (let i = 0; i < requests.length; i++) {
43
- const best = minByBigInt(responses.map((ra) => ({ quote: ra.quotes[i], aggregator: ra.agg })),
44
- // Default null quotes to MAX so they never win as the minimum
45
- (r) => r.quote?.input.amountRaw ?? BigInt(Number.MAX_SAFE_INTEGER));
46
- if (best != null) {
47
- final[i] = best;
48
- }
49
- else {
50
- final[i] = {
51
- quote: null,
52
- aggregator: aggregators[0],
53
- };
54
- }
55
- }
56
- break;
57
- }
58
- }
59
- return final;
60
- }
61
- /*
62
- In original autoSelectSources:
63
- Assets = [1 ETH, 1 COT, 1 ETH, 1 USDT, 1 COT]
64
- Output = 4
65
-
66
- First loop that just removes cot:
67
- quoteAssets = [1 ETH, 1 ETH, 1 USDT]
68
- Output = 4
69
-
70
- Outside the function we can just remove all COT's and assume those as being used
71
- but that's incorrect as we want to use assets in exact order as holdings array.
72
- We can't remove only COT's that are going to be used because we don't know which ones are going
73
- to get used.
74
-
75
- Proposed solution:
76
- It should actually use assets in exact order, so it cant be done outside the function
77
- 1. The function has to keep an order of assets, separate out COT and non-COT assets.
78
- 2. Get quote for non-COT assets, then loop over the original order
79
- 3. Used either COT or quote depending on original order
80
- 4. Send back quotes and COT's used
81
-
82
- Alg:
83
- Assets = [1 ETH, 1 COT, 1 ETH, 1 USDT, 1 COT]
84
- Output = 4
85
-
86
- 1. separate into two with indexes:
87
- quotes = [(1 ETH, 0), (1 ETH, 2), (1 USDT, 3)]
88
- cots = [(1 COT, 1), (1 COT, 4)]
89
-
90
- 2. Get quotes using only quotes
91
- 3. merge quote cots and sort by order
92
- 4. loop assets (original order):
93
- if a quote:
94
- output = output - quote_output_amount
95
- if a cot:
96
- output = output - cot_amount
97
- if output <= 0:
98
- break
99
- 5. return quotes and assets used.
100
- */
101
- /**
102
- * @deprecated Use {@link autoSelectSources} (object args; per-holding `takerAddress` and
103
- * `receiverAddress` on each `HoldingWithSwapAddresses`).
104
- */
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) {
113
- // Assumption: Holding is already sorted in usage priority
114
- console.debug("XCS | SSV2:", {
115
- holdings,
116
- outputRequired: outputRequired.toFixed(),
117
- });
118
- const fullLiquidationQuotes = [];
119
- const cotList = [];
120
- for (const [idx, holding] of holdings.entries()) {
121
- const chain = ChaindataMap.get(holding.chainID);
122
- if (chain == null) {
123
- throw new AutoSelectionError("Chain not found");
124
- }
125
- const correspondingCurrency = chain.Currencies.find((cur) => cur.currencyID === commonCurrencyID);
126
- if (correspondingCurrency == null) {
127
- console.debug("XCS | SS | Skipping because correspondingCurrency is null", {
128
- chain,
129
- correspondingCurrency,
130
- });
131
- continue;
132
- }
133
- if (Buffer.compare(holding.tokenAddress, correspondingCurrency.tokenAddress) === 0) {
134
- const normalizedAmount = new Decimal(holding.amountRaw).div(Decimal.pow(10, correspondingCurrency.decimals));
135
- cotList.push({
136
- amount: normalizedAmount,
137
- idx,
138
- chainID: holding.chainID,
139
- currency: correspondingCurrency,
140
- originalHolding: holding,
141
- });
142
- }
143
- else {
144
- fullLiquidationQuotes.push({
145
- req: {
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,
150
- type: QuoteType.EXACT_IN,
151
- chain: chain.ChainID,
152
- inputToken: holding.tokenAddress,
153
- inputAmount: holding.amountRaw,
154
- outputToken: correspondingCurrency.tokenAddress,
155
- seriousness: QuoteSeriousness.PRICE_SURVEY,
156
- },
157
- originalHolding: holding,
158
- cur: correspondingCurrency,
159
- idx,
160
- });
161
- }
162
- }
163
- // Check if continuous COTs from the start can cover the entire requirement
164
- // We can skip quoting unused holdings
165
- if (cotList.length > 0 && cotList[0].idx === 0) {
166
- let continuousCOTAmount = new Decimal(0);
167
- let continuousCount = 0;
168
- for (const cot of cotList) {
169
- // only consecutive cots allowed, otherwise we need to go to quoting
170
- if (cot.idx !== continuousCount)
171
- break;
172
- continuousCOTAmount = continuousCOTAmount.add(cot.amount);
173
- continuousCount++;
174
- if (continuousCOTAmount.gte(outputRequired)) {
175
- console.log("XCS | SS | Continuous COTs can satisfy requirement, skipping quotes");
176
- const usedCOTs = [];
177
- let remainder = outputRequired;
178
- for (let i = 0; i < continuousCount; i++) {
179
- const cot = cotList[i];
180
- const amountToUse = Decimal.min(remainder, cot.amount);
181
- usedCOTs.push({
182
- originalHolding: cot.originalHolding,
183
- amountUsed: amountToUse,
184
- idx: cot.idx,
185
- cur: cot.currency,
186
- });
187
- remainder = remainder.minus(amountToUse);
188
- if (remainder.lte(0))
189
- break;
190
- }
191
- console.debug("XCS | SS | Early return with continuous COTs:", {
192
- cots: usedCOTs,
193
- });
194
- return { quoteResponses: [], usedCOTs };
195
- }
196
- }
197
- }
198
- const processingQueue = [];
199
- // Add COT holdings
200
- for (const cot of cotList) {
201
- processingQueue.push({
202
- idx: cot.idx,
203
- isCOT: true,
204
- cotData: cot,
205
- });
206
- }
207
- // Add non-COT holdings
208
- for (let i = 0; i < fullLiquidationQuotes.length; i++) {
209
- processingQueue.push({
210
- idx: fullLiquidationQuotes[i].idx,
211
- isCOT: false,
212
- quoteData: fullLiquidationQuotes[i],
213
- responseIdx: i,
214
- });
215
- }
216
- // Sort by original index to maintain priority
217
- processingQueue.sort((a, b) => a.idx - b.idx);
218
- const responses = await aggregateAggregators(fullLiquidationQuotes.map((fq) => fq.req), aggregators, 0 /* AggregateAggregatorsMode.MaximizeOutput */);
219
- console.debug("AutoSelectSources:Quotes", responses);
220
- const final = [];
221
- const usedCOTs = [];
222
- let remainder = outputRequired;
223
- for (const item of processingQueue) {
224
- if (remainder.lte(0)) {
225
- break;
226
- }
227
- if (item.isCOT) {
228
- // Process COT holding - direct usage, no quote
229
- const { cotData } = item;
230
- const amountToUse = Decimal.min(remainder, cotData.amount);
231
- usedCOTs.push({
232
- originalHolding: cotData.originalHolding,
233
- amountUsed: amountToUse,
234
- idx: cotData.idx,
235
- cur: cotData.currency,
236
- });
237
- remainder = remainder.minus(amountToUse);
238
- console.debug("selection:cot", {
239
- idx: cotData.idx,
240
- amountToUse: amountToUse.toFixed(),
241
- remainder: remainder.toFixed(),
242
- });
243
- }
244
- else {
245
- // Process non-COT holding - use existing quote logic
246
- const { quoteData, responseIdx } = item;
247
- const { quote: resp, aggregator } = responses[responseIdx];
248
- if (resp == null) {
249
- continue;
250
- }
251
- console.debug("selection:quote", {
252
- remainder: remainder.toFixed(),
253
- input: resp.input,
254
- output: resp.output,
255
- });
256
- const divisor = Decimal.pow(10, quoteData.cur.decimals);
257
- const oamD = new Decimal(resp.output.amount);
258
- if (oamD.gt(remainder)) {
259
- const indicativePrice = Decimal.div(resp.input.amountRaw, resp.output.amountRaw);
260
- const userBal = new Decimal(quoteData.originalHolding.amountRaw);
261
- // remainder is the output we want, so the input amount is remainder × indicativePrice
262
- let expectedInput = Decimal.min(remainder.mul(divisor).mul(indicativePrice).mul(safetyMultiplier), userBal);
263
- let attempts = 0;
264
- while (true) {
265
- if (++attempts > 10) {
266
- throw new AutoSelectionError("Partial quote did not converge");
267
- }
268
- console.debug("partial_quote_loop", {
269
- indicativePrice: indicativePrice.toFixed(),
270
- expectedInput: expectedInput.toFixed(),
271
- userBal: userBal.toFixed(),
272
- remainder: remainder.toFixed(),
273
- });
274
- const adequateQuoteResult = await aggregateAggregators([
275
- {
276
- ...quoteData.req,
277
- seriousness: QuoteSeriousness.SERIOUS,
278
- inputAmount: convertDecimalToBigInt(expectedInput),
279
- },
280
- ], aggregators, 0 /* AggregateAggregatorsMode.MaximizeOutput */);
281
- if (adequateQuoteResult.length !== 1) {
282
- throw new AutoSelectionError("Unexpected response length from aggregateAggregators");
283
- }
284
- const adequateQuote = adequateQuoteResult[0];
285
- if (adequateQuote.quote == null) {
286
- throw new AutoSelectionError("Couldn't get buy quote");
287
- }
288
- const quote = adequateQuote.quote;
289
- console.log("partial_quote", {
290
- quote,
291
- });
292
- const oam2D = new Decimal(adequateQuote.quote.output.amount);
293
- if (oam2D.gte(remainder)) {
294
- final.push({
295
- quote,
296
- aggregator: adequateQuote.aggregator,
297
- holding: quoteData.originalHolding,
298
- chainID: Number(quoteData.req.chain.chainID),
299
- });
300
- remainder = remainder.minus(oam2D);
301
- break;
302
- }
303
- else if (expectedInput.eq(userBal)) {
304
- throw new AutoSelectionError("Holding was supposedly enough to meet the full requirement but ceased to be so subsequently");
305
- }
306
- else {
307
- expectedInput = Decimal.min(expectedInput.mul(safetyMultiplier), userBal); // try again with higher amount
308
- }
309
- }
310
- }
311
- else {
312
- console.debug("full_quote", resp);
313
- final.push({
314
- quote: resp,
315
- holding: quoteData.originalHolding,
316
- aggregator,
317
- chainID: Number(quoteData.req.chain.chainID),
318
- });
319
- remainder = remainder.minus(resp.output.amount);
320
- }
321
- }
322
- }
323
- console.debug("quotes_and_remainder", {
324
- remainder: remainder.toFixed(),
325
- final,
326
- });
327
- if (remainder.gt(0)) {
328
- throw new AutoSelectionError("NOT_ENOUGH_SWAP_FOR_REQUIREMENT");
329
- }
330
- console.log("final_quotes", { quotes: final, cots: usedCOTs });
331
- return { quoteResponses: final, usedCOTs };
332
- }
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) {
338
- const chaindata = ChaindataMap.get(requirement.chainID);
339
- if (chaindata == null) {
340
- throw new AutoSelectionError("Chain not found");
341
- }
342
- const COT = chaindata.Currencies.find((cur) => cur.currencyID === commonCurrencyID);
343
- if (COT == null) {
344
- throw new AutoSelectionError("COT not present on the destination chain");
345
- }
346
- // FIXME: Replace with oracle usage - should reduce time.
347
- // what happens if we happen to sell the requirement for the COT, what would the amount be?
348
- const fullLiquidationQR = {
349
- type: QuoteType.EXACT_IN,
350
- chain: requirement.chainID,
351
- userAddress,
352
- receiverAddress,
353
- inputToken: requirement.tokenAddress,
354
- outputToken: COT.tokenAddress,
355
- inputAmount: requirement.amountRaw,
356
- seriousness: QuoteSeriousness.PRICE_SURVEY,
357
- };
358
- const fullLiquidationResult = await aggregateAggregators([fullLiquidationQR], aggregators, 0 /* AggregateAggregatorsMode.MaximizeOutput */);
359
- if (fullLiquidationResult.length !== 1) {
360
- throw new AutoSelectionError("Unexpected response length from aggregateAggregators");
361
- }
362
- const fullLiquidationQuote = fullLiquidationResult[0];
363
- if (fullLiquidationQuote.quote == null) {
364
- throw new AutoSelectionError("Couldn't get full liquidation quote");
365
- }
366
- let curAmount = convertBigIntToDecimal(fullLiquidationQuote.quote.output.amountRaw).mul(safetyMultiplier);
367
- let attempts = 0;
368
- while (true) {
369
- if (++attempts > 10) {
370
- throw new AutoSelectionError("Destination swap quote did not converge");
371
- }
372
- const buyQuoteResult = await aggregateAggregators([
373
- {
374
- type: QuoteType.EXACT_IN,
375
- userAddress,
376
- receiverAddress,
377
- chain: requirement.chainID,
378
- inputToken: COT.tokenAddress,
379
- outputToken: requirement.tokenAddress,
380
- inputAmount: convertDecimalToBigInt(curAmount),
381
- seriousness: QuoteSeriousness.SERIOUS,
382
- },
383
- ], aggregators, 0 /* AggregateAggregatorsMode.MaximizeOutput */);
384
- if (buyQuoteResult.length !== 1) {
385
- throw new AutoSelectionError("Unexpected response length from aggregateAggregators");
386
- }
387
- const buyQuote = buyQuoteResult[0];
388
- if (buyQuote.quote == null) {
389
- throw new AutoSelectionError("Couldn't get buy quote");
390
- }
391
- console.debug("XCS | DDS | 2⒜ iteration", {
392
- buyQuote,
393
- curAmount,
394
- });
395
- if (buyQuote.quote.output.amountRaw >= requirement.amountRaw) {
396
- return {
397
- chainID: Number(requirement.chainID.chainID),
398
- quote: buyQuote.quote,
399
- aggregator: buyQuote.aggregator,
400
- holding: requirement,
401
- };
402
- }
403
- else {
404
- curAmount = curAmount.mul(safetyMultiplier); // try again with higher amount
405
- }
406
- }
407
- }
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) {
420
- console.debug("XCS | LIH | Holdings:", holdings);
421
- const groupedByChainID = groupBy(holdings, (h) => bytesToHex(h.chainID.toBytes()));
422
- const fullLiquidationQuotes = [];
423
- for (const holdings of Object.values(groupedByChainID)) {
424
- const chain = ChaindataMap.get(holdings[0].chainID);
425
- if (chain == null) {
426
- throw new AutoSelectionError("Chain not found");
427
- }
428
- const correspondingCurrency = chain.Currencies.find((cur) => cur.currencyID === commonCurrencyID);
429
- if (correspondingCurrency == null) {
430
- console.debug("XCS | LIH | Skipping because correspondingCurrency is null", {
431
- chain,
432
- correspondingCurrency,
433
- });
434
- continue;
435
- }
436
- for (const holding of holdings) {
437
- if (Buffer.compare(holding.tokenAddress, correspondingCurrency.tokenAddress) === 0) {
438
- console.log("XCS | LIH | Disqualifying", holding, "because holding.tokenAddress = CA asset");
439
- continue;
440
- }
441
- fullLiquidationQuotes.push({
442
- req: {
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,
447
- type: QuoteType.EXACT_IN,
448
- chain: chain.ChainID,
449
- inputToken: holding.tokenAddress,
450
- inputAmount: holding.amountRaw,
451
- outputToken: correspondingCurrency.tokenAddress,
452
- seriousness: QuoteSeriousness.SERIOUS,
453
- },
454
- // necessary for various purposes
455
- originalHolding: holding,
456
- cur: correspondingCurrency,
457
- });
458
- }
459
- }
460
- const responses = await aggregateAggregators(fullLiquidationQuotes.map((fq) => fq.req), aggregators, 0 /* AggregateAggregatorsMode.MaximizeOutput */);
461
- console.debug("XCS | LIH | Responses:", responses);
462
- const quotes = [];
463
- for (const [i, response] of responses.entries()) {
464
- if (response.quote !== null) {
465
- quotes.push({
466
- quote: response.quote,
467
- aggregator: response.aggregator,
468
- holding: fullLiquidationQuotes[i].originalHolding,
469
- chainID: Number(fullLiquidationQuotes[i].req.chain.chainID),
470
- });
471
- }
472
- }
473
- return quotes;
474
- }
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) {
480
- const chaindata = ChaindataMap.get(omniChainID);
481
- if (chaindata == null) {
482
- throw new AutoSelectionError("Chain not found");
483
- }
484
- const COT = chaindata.Currencies.find((cur) => cur.currencyID === inputCurrency);
485
- if (COT == null) {
486
- throw new AutoSelectionError("COT not present on the destination chain");
487
- }
488
- const fullLiquidationResult = await aggregateAggregators([
489
- {
490
- type: QuoteType.EXACT_IN,
491
- chain: omniChainID,
492
- userAddress,
493
- receiverAddress,
494
- inputToken: COT.tokenAddress,
495
- outputToken: outputToken,
496
- inputAmount: inputAmount,
497
- seriousness: QuoteSeriousness.SERIOUS,
498
- },
499
- ], aggregators, 0 /* AggregateAggregatorsMode.MaximizeOutput */);
500
- if (fullLiquidationResult.length !== 1) {
501
- throw new AutoSelectionError("Unexpected response length from aggregateAggregators");
502
- }
503
- const fullLiquidationQuote = fullLiquidationResult[0];
504
- if (fullLiquidationQuote.quote == null) {
505
- throw new AutoSelectionError("Couldn't get full liquidation quote");
506
- }
507
- return {
508
- chainID: Number(omniChainID.chainID),
509
- quote: fullLiquidationQuote.quote,
510
- aggregator: fullLiquidationQuote.aggregator,
511
- holding: {
512
- amountRaw: inputAmount,
513
- chainID: omniChainID,
514
- tokenAddress: COT.tokenAddress,
515
- },
516
- };
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
- }