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