@strkfarm/sdk 1.2.0 → 2.0.0-dev-strategy2.1

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 (60) hide show
  1. package/dist/index.browser.global.js +76556 -66640
  2. package/dist/index.browser.mjs +34235 -24392
  3. package/dist/index.d.ts +2372 -793
  4. package/dist/index.js +31967 -22084
  5. package/dist/index.mjs +25545 -15719
  6. package/package.json +86 -76
  7. package/readme.md +56 -1
  8. package/src/data/extended-deposit.abi.json +3613 -0
  9. package/src/data/universal-vault.abi.json +135 -20
  10. package/src/dataTypes/_bignumber.ts +11 -0
  11. package/src/dataTypes/address.ts +7 -0
  12. package/src/global.ts +240 -193
  13. package/src/interfaces/common.tsx +26 -2
  14. package/src/modules/ExtendedWrapperSDk/index.ts +62 -0
  15. package/src/modules/ExtendedWrapperSDk/types.ts +311 -0
  16. package/src/modules/ExtendedWrapperSDk/wrapper.ts +448 -0
  17. package/src/modules/avnu.ts +17 -4
  18. package/src/modules/ekubo-quoter.ts +89 -10
  19. package/src/modules/erc20.ts +67 -21
  20. package/src/modules/harvests.ts +29 -43
  21. package/src/modules/index.ts +5 -1
  22. package/src/modules/lst-apr.ts +36 -0
  23. package/src/modules/midas.ts +159 -0
  24. package/src/modules/pricer-from-api.ts +2 -2
  25. package/src/modules/pricer-lst.ts +1 -1
  26. package/src/modules/pricer.ts +3 -38
  27. package/src/modules/token-market-data.ts +202 -0
  28. package/src/node/deployer.ts +1 -36
  29. package/src/strategies/autoCompounderStrk.ts +1 -1
  30. package/src/strategies/base-strategy.ts +20 -3
  31. package/src/strategies/btc-vesu-extended-strategy/core-strategy.tsx +1486 -0
  32. package/src/strategies/btc-vesu-extended-strategy/services/operationService.ts +32 -0
  33. package/src/strategies/btc-vesu-extended-strategy/utils/constants.ts +3 -0
  34. package/src/strategies/btc-vesu-extended-strategy/utils/helper.ts +396 -0
  35. package/src/strategies/btc-vesu-extended-strategy/utils/types.ts +5 -0
  36. package/src/strategies/ekubo-cl-vault.tsx +123 -306
  37. package/src/strategies/index.ts +7 -1
  38. package/src/strategies/svk-strategy.ts +247 -0
  39. package/src/strategies/universal-adapters/adapter-optimizer.ts +65 -0
  40. package/src/strategies/universal-adapters/adapter-utils.ts +5 -1
  41. package/src/strategies/universal-adapters/avnu-adapter.ts +432 -0
  42. package/src/strategies/universal-adapters/baseAdapter.ts +181 -153
  43. package/src/strategies/universal-adapters/common-adapter.ts +98 -77
  44. package/src/strategies/universal-adapters/extended-adapter.ts +976 -0
  45. package/src/strategies/universal-adapters/index.ts +7 -1
  46. package/src/strategies/universal-adapters/unused-balance-adapter.ts +109 -0
  47. package/src/strategies/universal-adapters/vesu-adapter.ts +230 -230
  48. package/src/strategies/universal-adapters/vesu-borrow-adapter.ts +1247 -0
  49. package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +1306 -0
  50. package/src/strategies/universal-adapters/vesu-supply-only-adapter.ts +58 -51
  51. package/src/strategies/universal-lst-muliplier-strategy.tsx +716 -844
  52. package/src/strategies/universal-strategy.tsx +1103 -1181
  53. package/src/strategies/vesu-extended-strategy/services/operationService.ts +34 -0
  54. package/src/strategies/vesu-extended-strategy/types/transaction-metadata.ts +25 -0
  55. package/src/strategies/vesu-extended-strategy/utils/config.runtime.ts +77 -0
  56. package/src/strategies/vesu-extended-strategy/utils/constants.ts +50 -0
  57. package/src/strategies/vesu-extended-strategy/utils/helper.ts +367 -0
  58. package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +1420 -0
  59. package/src/strategies/vesu-rebalance.tsx +16 -20
  60. package/src/utils/health-factor-math.ts +11 -5
@@ -0,0 +1,1247 @@
1
+ import {
2
+ BaseAdapterConfig,
3
+ BaseAdapter,
4
+ DepositParams,
5
+ WithdrawParams,
6
+ PositionInfo,
7
+ ManageCall,
8
+ AdapterLeafType,
9
+ GenerateCallFn,
10
+ } from "./baseAdapter";
11
+ import { num } from "starknet";
12
+ import { StandardMerkleTree } from "@/utils";
13
+ import VesuMultiplyAbi from "@/data/vesu-multiple.abi.json";
14
+ import { ContractAddr, Web3Number } from "@/dataTypes";
15
+ import { TokenInfo, VaultPosition } from "@/interfaces";
16
+ import {
17
+ DecreaseLeverParams,
18
+ IncreaseLeverParams,
19
+ Swap,
20
+ VesuAdapter,
21
+ } from "./vesu-adapter";
22
+ import { EkuboQuoter, TokenMarketData } from "@/modules";
23
+ import { Protocols } from "@/interfaces";
24
+ import { SupportedPosition, PositionAPY, APYType } from "./baseAdapter";
25
+ import {
26
+ SIMPLE_SANITIZER,
27
+ SIMPLE_SANITIZER_V2,
28
+ VESU_V2_MODIFY_POSITION_SANITIZER,
29
+ } from "./adapter-utils";
30
+ import { getVesuSingletonAddress } from "./vesu-adapter";
31
+ import { hash, Contract, CairoCustomEnum, Uint256 } from "starknet";
32
+ import VesuPoolV2Abi from "@/data/vesu-pool-v2.abi.json";
33
+ import { toBigInt } from "./adapter-utils";
34
+ import { logger } from "@/utils";
35
+ import { uint256 } from "starknet";
36
+ import { ExtendedAdapter, VesuMultiplyAdapter } from "../universal-adapters";
37
+ import { AvnuAdapter } from "./avnu-adapter";
38
+ import { DepositParamsForLendingBorrowing } from "../btc-vesu-extended-strategy/utils/types";
39
+ import { WBTC_TOKEN_DECIMALS } from "../vesu-extended-strategy/utils/constants";
40
+
41
+ export interface VesuBorrowSupplyAdapterConfig extends BaseAdapterConfig {
42
+ poolId: ContractAddr;
43
+ borrowToken: TokenInfo;
44
+ supplyToken: TokenInfo;
45
+ targetHealthFactor: number;
46
+ minHealthFactor: number;
47
+ quoteAmountToFetchPrice: Web3Number;
48
+ vaultIdExtended: number;
49
+ extendedContract: ContractAddr;
50
+ extendedBackendUrl: string;
51
+ extendedApiKey: string;
52
+ extendedTimeout: number;
53
+ extendedRetries: number;
54
+ extendedBaseUrl: string;
55
+ extendedMarketName: string;
56
+ extendedPrecision: number;
57
+ extendedAdapter: ExtendedAdapter;
58
+ avnuAdapter: AvnuAdapter;
59
+ retryDelayForOrderStatus: number;
60
+ minimumExtendedMovementAmount: number;
61
+ }
62
+
63
+ export class VesuBorrowSupplyAdapter extends BaseAdapter<
64
+ DepositParams,
65
+ WithdrawParams
66
+ > {
67
+ readonly config: VesuBorrowSupplyAdapterConfig;
68
+ readonly vesuAdapter: VesuAdapter;
69
+ readonly tokenMarketData: TokenMarketData;
70
+ protected extendedAdapter: ExtendedAdapter;
71
+
72
+ constructor(config: VesuBorrowSupplyAdapterConfig) {
73
+ super(config, VesuBorrowSupplyAdapter.name, Protocols.VESU);
74
+ this.config = config;
75
+ this.vesuAdapter = new VesuAdapter({
76
+ poolId: config.poolId,
77
+ collateral: config.supplyToken, //wbtc
78
+ debt: config.borrowToken, //usdc
79
+ vaultAllocator: config.vaultAllocator,
80
+ id: "",
81
+ });
82
+ this.tokenMarketData = new TokenMarketData(
83
+ this.config.pricer,
84
+ this.config.networkConfig
85
+ );
86
+ this.extendedAdapter = new ExtendedAdapter({
87
+ baseToken: this.config.baseToken,
88
+ supportedPositions: this.config.supportedPositions,
89
+ networkConfig: this.config.networkConfig,
90
+ pricer: this.config.pricer,
91
+ vaultAddress: this.config.vaultAddress,
92
+ vaultAllocator: this.config.vaultAllocator,
93
+ vaultIdExtended: this.config.vaultIdExtended,
94
+ extendedContract: this.config.extendedContract,
95
+ extendedBackendUrl: this.config.extendedBackendUrl,
96
+ extendedApiKey: this.config.extendedApiKey,
97
+ extendedTimeout: this.config.extendedTimeout,
98
+ extendedRetries: this.config.extendedRetries,
99
+ extendedBaseUrl: this.config.extendedBaseUrl,
100
+ extendedMarketName: this.config.extendedMarketName,
101
+ extendedPrecision: this.config.extendedPrecision,
102
+ avnuAdapter: this.config.avnuAdapter,
103
+ retryDelayForOrderStatus: this.config.retryDelayForOrderStatus,
104
+ minimumExtendedMovementAmount: this.config.minimumExtendedMovementAmount,
105
+ });
106
+ }
107
+
108
+ protected async getAPY(
109
+ supportedPosition: SupportedPosition
110
+ ): Promise<PositionAPY> {
111
+ return {
112
+ apy: 0,
113
+ type: APYType.BASE,
114
+ };
115
+ }
116
+
117
+ protected async getPosition(
118
+ supportedPosition: SupportedPosition
119
+ ): Promise<VaultPosition> {
120
+ return {} as VaultPosition;
121
+ }
122
+
123
+ async maxBorrowableAPY(): Promise<number> {
124
+ // get collateral APY
125
+ const collateralAPY = await this.getAPY({
126
+ asset: this.config.supplyToken,
127
+ isDebt: false,
128
+ });
129
+ const apy = collateralAPY.apy * 0.8;
130
+ return apy;
131
+ }
132
+
133
+ async maxDeposit(amount?: Web3Number): Promise<PositionInfo> {
134
+ return {
135
+ tokenInfo: this.config.supplyToken,
136
+ amount: new Web3Number(
137
+ "999999999999999999999999999",
138
+ this.config.supplyToken.decimals
139
+ ),
140
+ usdValue: 999999999999999999999999999,
141
+ remarks: "Max deposit (infinity)",
142
+ apy: await this.getAPY({ asset: this.config.supplyToken, isDebt: false }),
143
+ protocol: this.protocol,
144
+ };
145
+ }
146
+
147
+ async maxWithdraw(): Promise<PositionInfo> {
148
+ return {
149
+ tokenInfo: this.config.borrowToken,
150
+ amount: new Web3Number(
151
+ "999999999999999999999999999",
152
+ this.config.borrowToken.decimals
153
+ ),
154
+ usdValue: 999999999999999999999999999,
155
+ remarks: "Max withdraw (infinity)",
156
+ apy: await this.getAPY({ asset: this.config.borrowToken, isDebt: false }),
157
+ protocol: this.protocol,
158
+ };
159
+ }
160
+
161
+ protected _getDepositLeaf(): {
162
+ target: ContractAddr;
163
+ method: string;
164
+ packedArguments: bigint[];
165
+ sanitizer: ContractAddr;
166
+ id: string;
167
+ }[] {
168
+ const supplyToken = this.config.supplyToken; //wbtc
169
+ const borrowToken = this.config.borrowToken; //usdc
170
+ const { addr: vesuSingleton } = getVesuSingletonAddress(this.config.poolId);
171
+ return [
172
+ {
173
+ target: supplyToken.address,
174
+ method: "approve",
175
+ packedArguments: [
176
+ vesuSingleton.toBigInt(), // spender
177
+ ],
178
+ sanitizer: SIMPLE_SANITIZER,
179
+ id: `approve_supply_${supplyToken.symbol}`,
180
+ },
181
+ {
182
+ target: vesuSingleton,
183
+ method: "modify_position",
184
+ packedArguments: [
185
+ supplyToken.address.toBigInt(),
186
+ borrowToken.address.toBigInt(),
187
+ this.config.vaultAllocator.toBigInt(),
188
+ ],
189
+ sanitizer: VESU_V2_MODIFY_POSITION_SANITIZER,
190
+ id: `modify_position_supply_${supplyToken.symbol}`,
191
+ },
192
+ ];
193
+ }
194
+
195
+ protected _getPayDebtLeaf(): {
196
+ target: ContractAddr;
197
+ method: string;
198
+ packedArguments: bigint[];
199
+ sanitizer: ContractAddr;
200
+ id: string;
201
+ }[] {
202
+ const supplyToken = this.config.supplyToken; //wbtc
203
+ const borrowToken = this.config.borrowToken; //usdc
204
+ const { addr: vesuSingleton } = getVesuSingletonAddress(this.config.poolId);
205
+ return [
206
+ {
207
+ target: borrowToken.address,
208
+ method: "approve",
209
+ packedArguments: [
210
+ vesuSingleton.toBigInt(), // spender
211
+ ],
212
+ sanitizer: SIMPLE_SANITIZER,
213
+ id: `approve_borrow_${borrowToken.symbol}`,
214
+ },
215
+ {
216
+ target: vesuSingleton,
217
+ method: "modify_position",
218
+ packedArguments: [
219
+ supplyToken.address.toBigInt(),
220
+ borrowToken.address.toBigInt(),
221
+ this.config.vaultAllocator.toBigInt(),
222
+ ],
223
+ sanitizer: VESU_V2_MODIFY_POSITION_SANITIZER,
224
+ id: `modify_position_borrow_${borrowToken.symbol}`,
225
+ },
226
+ ];
227
+ }
228
+
229
+ protected _getBorrowLeaf(): {
230
+ target: ContractAddr;
231
+ method: string;
232
+ packedArguments: bigint[];
233
+ sanitizer: ContractAddr;
234
+ id: string;
235
+ }[] {
236
+ const supplyToken = this.config.supplyToken; //wbtc
237
+ const borrowToken = this.config.borrowToken; //usdc
238
+ const { addr: vesuSingleton } = getVesuSingletonAddress(this.config.poolId);
239
+ return [
240
+ {
241
+ target: supplyToken.address,
242
+ method: "approve",
243
+ packedArguments: [
244
+ vesuSingleton.toBigInt(), // spender
245
+ ],
246
+ sanitizer: SIMPLE_SANITIZER,
247
+ id: `approval_supply_${supplyToken.symbol}`,
248
+ },
249
+ {
250
+ target: vesuSingleton,
251
+ method: "modify_position",
252
+ packedArguments: [
253
+ supplyToken.address.toBigInt(),
254
+ borrowToken.address.toBigInt(),
255
+ this.config.vaultAllocator.toBigInt(),
256
+ ],
257
+ sanitizer: VESU_V2_MODIFY_POSITION_SANITIZER,
258
+ id: `modification_posn_sup_${supplyToken.symbol}`,
259
+ },
260
+ ];
261
+ }
262
+
263
+ protected _getMultiplyLeaf(): {
264
+ target: ContractAddr;
265
+ method: string;
266
+ packedArguments: bigint[];
267
+ sanitizer: ContractAddr;
268
+ id: string;
269
+ }[] {
270
+ const collateral = this.config.supplyToken;
271
+ const debt = this.config.borrowToken;
272
+ const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
273
+ this.config.poolId
274
+ );
275
+ const vesuMultiply = isV2
276
+ ? this.vesuAdapter.VESU_MULTIPLY
277
+ : this.vesuAdapter.VESU_MULTIPLY_V1;
278
+
279
+ return [
280
+ // Approval step for collateral
281
+ {
282
+ target: collateral.address,
283
+ method: "approve",
284
+ packedArguments: [
285
+ vesuMultiply.toBigInt(), // spender
286
+ ],
287
+ sanitizer: SIMPLE_SANITIZER,
288
+ // amc = approve multiply collateral
289
+ id: `amc_${this.config.poolId.shortString()}_${collateral.symbol}_supplyLend`,
290
+ },
291
+ // Switch delegation on
292
+ {
293
+ target: vesuSingleton,
294
+ method: "modify_delegation",
295
+ packedArguments: isV2
296
+ ? [
297
+ vesuMultiply.toBigInt(), // delegatee
298
+ ]
299
+ : [
300
+ this.config.poolId.toBigInt(),
301
+ vesuMultiply.toBigInt(), // delegatee
302
+ ],
303
+ sanitizer: isV2 ? SIMPLE_SANITIZER_V2 : SIMPLE_SANITIZER,
304
+ // sd1 = switch delegation on
305
+ id: `sd1_${this.config.poolId.shortString()}_${collateral.symbol}_supplyLend`,
306
+ },
307
+ // Vesu multiply call
308
+ {
309
+ target: vesuMultiply,
310
+ method: "modify_lever",
311
+ packedArguments: [
312
+ this.config.poolId.toBigInt(),
313
+ collateral.address.toBigInt(),
314
+ debt.address.toBigInt(),
315
+ this.config.vaultAllocator.toBigInt(),
316
+ ],
317
+ sanitizer: SIMPLE_SANITIZER_V2,
318
+ // vm = vesu multiply
319
+ id: `vm_${this.config.poolId.shortString()}_${collateral.symbol}_supplyLend`,
320
+ },
321
+ // Switch delegation off
322
+ {
323
+ target: vesuSingleton,
324
+ method: "modify_delegation",
325
+ packedArguments: isV2
326
+ ? [
327
+ vesuMultiply.toBigInt(), // delegatee
328
+ ]
329
+ : [
330
+ this.config.poolId.toBigInt(),
331
+ vesuMultiply.toBigInt(), // delegatee
332
+ ],
333
+ sanitizer: isV2 ? SIMPLE_SANITIZER_V2 : SIMPLE_SANITIZER,
334
+ // sd2 = switch delegation off
335
+ id: `sd2_${this.config.poolId.shortString()}_${collateral.symbol}_supplyLend`,
336
+ },
337
+ ];
338
+ }
339
+
340
+ protected _getWithdrawLeaf(): {
341
+ target: ContractAddr;
342
+ method: string;
343
+ packedArguments: bigint[];
344
+ sanitizer: ContractAddr;
345
+ id: string;
346
+ }[] {
347
+ // Withdraw supply token
348
+ const borrowToken = this.config.borrowToken;
349
+ const supplyToken = this.config.supplyToken;
350
+ const { addr: vesuSingleton } = getVesuSingletonAddress(this.config.poolId);
351
+ return [
352
+ {
353
+ target: supplyToken.address,
354
+ method: "approve",
355
+ packedArguments: [
356
+ vesuSingleton.toBigInt(), // spender
357
+ ],
358
+ sanitizer: SIMPLE_SANITIZER,
359
+ id: `approve_supply_USDC`,
360
+ },
361
+ {
362
+ target: vesuSingleton,
363
+ method: "modify_position",
364
+ packedArguments: [
365
+ this.config.poolId.toBigInt(),
366
+ supplyToken.address.toBigInt(),
367
+ borrowToken.address.toBigInt(),
368
+ this.config.vaultAllocator.toBigInt(),
369
+ ],
370
+ sanitizer: SIMPLE_SANITIZER,
371
+ id: `modify_position_supply_USDC`,
372
+ },
373
+ ];
374
+ }
375
+
376
+ async getHealthFactor(): Promise<number> {
377
+ const healthFactor = await this.vesuAdapter.getHealthFactor();
378
+ return healthFactor;
379
+ }
380
+
381
+ getPayDebtLeaf(): AdapterLeafType<DepositParams> {
382
+ const leafConfigs = this._getPayDebtLeaf();
383
+ const leaves = leafConfigs.map((config) => {
384
+ const { target, method, packedArguments, sanitizer, id } = config;
385
+ const leaf = this.constructSimpleLeafData(
386
+ {
387
+ id: id,
388
+ target,
389
+ method,
390
+ packedArguments,
391
+ },
392
+ sanitizer
393
+ );
394
+ return leaf;
395
+ });
396
+ return {
397
+ leaves,
398
+ callConstructor: this.getPayDebtCall.bind(
399
+ this
400
+ ) as unknown as GenerateCallFn<DepositParams>,
401
+ };
402
+ }
403
+
404
+ getMultiplyLeaf(): AdapterLeafType<DepositParams> {
405
+ const leafConfigs = this._getMultiplyLeaf();
406
+ const leaves = leafConfigs.map((config) => {
407
+ const { target, method, packedArguments, sanitizer, id } = config;
408
+ const leaf = this.constructSimpleLeafData(
409
+ {
410
+ id: id,
411
+ target,
412
+ method,
413
+ packedArguments,
414
+ },
415
+ sanitizer
416
+ );
417
+ return leaf;
418
+ });
419
+ return {
420
+ leaves,
421
+ callConstructor: this.getMultiplyCall.bind(
422
+ this
423
+ ) as unknown as GenerateCallFn<DepositParams>,
424
+ };
425
+ }
426
+
427
+ getBorrowLeaf(): AdapterLeafType<DepositParams> {
428
+ const leafConfigs = this._getBorrowLeaf();
429
+ const leaves = leafConfigs.map((config) => {
430
+ const { target, method, packedArguments, sanitizer, id } = config;
431
+ const leaf = this.constructSimpleLeafData(
432
+ { id: id, target, method, packedArguments },
433
+ sanitizer
434
+ );
435
+ return leaf;
436
+ });
437
+ return {
438
+ leaves,
439
+ callConstructor: this.getBorrowCall.bind(this) as unknown as GenerateCallFn<DepositParams>,
440
+ };
441
+ }
442
+
443
+ async getDepositCall(params: DepositParams): Promise<ManageCall[]> {
444
+ return [
445
+ ];
446
+ }
447
+
448
+
449
+
450
+ async getWithdrawCall(params: WithdrawParams): Promise<ManageCall[]> {
451
+ return [
452
+ ];
453
+ }
454
+
455
+ /**
456
+ * Pay the debt amount against the collateral amount
457
+ * @param params { supplyAmount: Web3Number; debtAmount: Web3Number; }
458
+ * @returns { ManageCall[] }
459
+ */
460
+ async getPayDebtCall(params: {
461
+ supplyAmount: Web3Number;
462
+ debtAmount: Web3Number;
463
+ }): Promise<ManageCall[]> {
464
+ const borrowToken = this.config.borrowToken;
465
+ const { addr: vesuSingleton } = getVesuSingletonAddress(this.config.poolId);
466
+ const uint256MarginAmount = uint256.bnToUint256(params.debtAmount.toWei());
467
+ console.log(
468
+ "uint256MarginAmount",
469
+ uint256MarginAmount,
470
+ params.debtAmount.toWei()
471
+ );
472
+ return [
473
+ {
474
+ sanitizer: SIMPLE_SANITIZER,
475
+ call: {
476
+ contractAddress: borrowToken.address,
477
+ selector: hash.getSelectorFromName("approve"),
478
+ calldata: [
479
+ vesuSingleton.toBigInt(), // spender,
480
+ toBigInt(uint256MarginAmount.low.toString()), // amount low
481
+ toBigInt(uint256MarginAmount.high.toString()), // amount high
482
+ ],
483
+ },
484
+ },
485
+ {
486
+ sanitizer: VESU_V2_MODIFY_POSITION_SANITIZER,
487
+ call: {
488
+ contractAddress: vesuSingleton,
489
+ selector: hash.getSelectorFromName("modify_position"),
490
+ /**
491
+ * In case of debt payment, just call this, the calldata is dynamic for both operations
492
+ */
493
+ calldata: (await this.getDepositCalldata(
494
+ params.supplyAmount,
495
+ params.debtAmount,
496
+
497
+ )) as bigint[],
498
+ },
499
+ },
500
+ ];
501
+ }
502
+
503
+ /**
504
+ * Increase the debt amount against the collateral amount
505
+ * @param params { supplyAmount: Web3Number; debtAmount: Web3Number; }
506
+ * @returns { ManageCall[] }
507
+ */
508
+ async getBorrowCall(params: {
509
+ supplyAmount: Web3Number;
510
+ debtAmount: Web3Number;
511
+ }): Promise<ManageCall[]> {
512
+ const supplyToken = this.config.supplyToken;
513
+ const { addr: vesuSingleton } = getVesuSingletonAddress(this.config.poolId);
514
+ const uint256MarginAmount = uint256.bnToUint256(params.supplyAmount.toWei());
515
+ console.log(
516
+ "Supply token uint256MarginAmount",
517
+ uint256MarginAmount,
518
+ params.supplyAmount.toWei()
519
+ );
520
+ const uint256DebtAmount = uint256.bnToUint256(params.debtAmount.toWei());
521
+ console.log(
522
+ "Debt token uint256MarginAmount",
523
+ uint256DebtAmount,
524
+ params.debtAmount.toWei()
525
+ );
526
+ return [
527
+ {
528
+ sanitizer: SIMPLE_SANITIZER,
529
+ call: {
530
+ contractAddress: supplyToken.address,
531
+ selector: hash.getSelectorFromName("approve"),
532
+ calldata: [
533
+ vesuSingleton.toBigInt(), // spender,
534
+ toBigInt(uint256MarginAmount.low.toString()), // amount low
535
+ toBigInt(uint256MarginAmount.high.toString()), // amount high
536
+ ],
537
+ },
538
+ },
539
+ {
540
+ sanitizer: VESU_V2_MODIFY_POSITION_SANITIZER,
541
+ call: {
542
+ contractAddress: vesuSingleton,
543
+ selector: hash.getSelectorFromName("modify_position"),
544
+ /**
545
+ * In case of debt payment, just call this, the calldata is dynamic for both operations
546
+ */
547
+ calldata: (await this.getDepositCalldata(
548
+ params.debtAmount,
549
+ params.supplyAmount,
550
+ )) as bigint[],
551
+ },
552
+ },
553
+ ];
554
+ }
555
+
556
+ private async getMultiplyCall({
557
+ amount,
558
+ debtAmount,
559
+ isWithdraw,
560
+ closePosition
561
+ }: {
562
+ amount: Web3Number;
563
+ debtAmount: Web3Number;
564
+ isWithdraw: boolean;
565
+ closePosition: boolean;
566
+ }): Promise<ManageCall[]> {
567
+ const collateralToken = this.config.supplyToken;
568
+ const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
569
+ this.config.poolId
570
+ );
571
+ const vesuMultiply = isV2
572
+ ? this.vesuAdapter.VESU_MULTIPLY
573
+ : this.vesuAdapter.VESU_MULTIPLY_V1;
574
+
575
+ logger.info(`amount: ${amount} isWithdraw: ${isWithdraw}`);
576
+ const uint256MarginAmount = uint256.bnToUint256(amount.abs().toWei());
577
+ logger.info(`uint256MarginAmount: ${uint256MarginAmount} amount: ${amount.abs().toWei()}`);
578
+ return [
579
+ {
580
+ sanitizer: SIMPLE_SANITIZER,
581
+ call: {
582
+ contractAddress: collateralToken.address,
583
+ selector: hash.getSelectorFromName("approve"),
584
+ calldata: [
585
+ vesuMultiply.toBigInt(), // spender
586
+ toBigInt(uint256MarginAmount.low.toString()), // amount low
587
+ toBigInt(uint256MarginAmount.high.toString()), // amount high
588
+ ],
589
+ },
590
+ },
591
+ // Switch delegation on
592
+ {
593
+ sanitizer: isV2 ? SIMPLE_SANITIZER_V2 : SIMPLE_SANITIZER,
594
+ call: {
595
+ contractAddress: vesuSingleton,
596
+ selector: hash.getSelectorFromName("modify_delegation"),
597
+ calldata: isV2
598
+ ? [
599
+ vesuMultiply.toBigInt(), // delegatee
600
+ BigInt(1), // delegation: true
601
+ ]
602
+ : [
603
+ this.config.poolId.toBigInt(),
604
+ vesuMultiply.toBigInt(), // delegatee
605
+ BigInt(1), // delegation: true
606
+ ],
607
+ },
608
+ },
609
+ {
610
+ sanitizer: SIMPLE_SANITIZER_V2,
611
+ call: {
612
+ contractAddress: vesuMultiply,
613
+ selector: hash.getSelectorFromName("modify_lever"),
614
+ calldata: !isWithdraw ? await this.getMultiplyCallCalldata(
615
+ amount,
616
+ debtAmount,
617
+ ) : closePosition ? await this.getClosePositionCalldata(amount, debtAmount) : await this.getWithdrawalMultiplyCalldata(amount, debtAmount),
618
+ },
619
+ },
620
+ {
621
+ sanitizer: isV2 ? SIMPLE_SANITIZER_V2 : SIMPLE_SANITIZER,
622
+ call: {
623
+ contractAddress: vesuSingleton,
624
+ selector: hash.getSelectorFromName("modify_delegation"),
625
+ calldata: isV2
626
+ ? [
627
+ vesuMultiply.toBigInt(), // delegatee
628
+ BigInt(0), // delegation: false
629
+ ]
630
+ : [
631
+ this.config.poolId.toBigInt(),
632
+ vesuMultiply.toBigInt(), // delegatee
633
+ BigInt(0), // delegation: false
634
+ ],
635
+ },
636
+ },
637
+ ];
638
+ }
639
+
640
+ private async getMultiplyCallCalldata(
641
+ params: Web3Number,
642
+ debtAmount: Web3Number,
643
+ ): Promise<bigint[]> {
644
+ const collateralToken = this.config.supplyToken;
645
+ const debtToken = this.config.borrowToken;
646
+ const { isV2 } = getVesuSingletonAddress(this.config.poolId);
647
+ const vesuMultiply = isV2
648
+ ? this.vesuAdapter.VESU_MULTIPLY
649
+ : this.vesuAdapter.VESU_MULTIPLY_V1;
650
+
651
+ const multiplyContract = new Contract({
652
+ abi: VesuMultiplyAbi,
653
+ address: vesuMultiply.address,
654
+ providerOrAccount: this.config.networkConfig.provider,
655
+ });
656
+ let leverSwap: Swap[] = [];
657
+ let leverSwapLimitAmount = Web3Number.fromWei(
658
+ 0,
659
+ this.config.borrowToken.decimals
660
+ );
661
+ const collateralPrice = (
662
+ await this.config.pricer.getPrice(collateralToken.symbol)
663
+ ).price;
664
+ const debtPrice = (await this.config.pricer.getPrice(debtToken.symbol))
665
+ .price;
666
+ const ekuboQuoter = new EkuboQuoter(
667
+ this.config.networkConfig,
668
+ this.config.pricer
669
+ );
670
+ const debtAmountInCollateralUnits = new Web3Number(
671
+ debtAmount
672
+ .multipliedBy(debtPrice)
673
+ .dividedBy(collateralPrice)
674
+ .multipliedBy(10 ** collateralToken.decimals)
675
+ .toFixed(0),
676
+ collateralToken.decimals
677
+ );
678
+ logger.info(`debtAmount: ${debtAmount}`);
679
+ logger.info(`debtPrice: ${debtPrice}`);
680
+ logger.info(`collateralPrice: ${collateralPrice}`);
681
+ logger.info(`debtAmountInCollateralUnits: ${debtAmountInCollateralUnits}`);
682
+ // increase multiply lever or not
683
+ const isIncrease = debtAmount.greaterThanOrEqualTo(0);
684
+
685
+ // due to directional limitations in multiply contract
686
+ if (isIncrease && debtAmount.lessThan(0)) {
687
+ // we are increasing lever but math says reduce debt
688
+ // - this is ok
689
+ } else if (!isIncrease && debtAmount.greaterThan(0)) {
690
+ // we are decreasing level but math says increase debt
691
+ // - such actions must be done with zero margin amount
692
+ // - so just set debt 0
693
+ debtAmount = Web3Number.fromWei(0, debtToken.decimals);
694
+ }
695
+ logger.verbose(
696
+ `${VesuMultiplyAdapter.name}::getVesuMultiplyCall debtAmount: ${debtAmount}`
697
+ );
698
+ if (!debtAmount.isZero()) {
699
+ // Get swap quote for leverage operation
700
+ // Determine swap direction based on operation type
701
+
702
+ try {
703
+ console.log("debtAmountInCollateralUnits", debtAmountInCollateralUnits);
704
+ console.log("debtToken.address.address", debtToken.address.address);
705
+ console.log("collateralToken.address.address", collateralToken.address.address);
706
+ const swapQuote = await ekuboQuoter.getQuote(
707
+ collateralToken.address.address,
708
+ debtToken.address.address,
709
+ debtAmountInCollateralUnits.multipliedBy(-1) // negative for exact amount out
710
+ );
711
+
712
+ // todo add better slip checks
713
+ // Check price impact
714
+ if (swapQuote.price_impact < 0.01) {
715
+ // 1% max price impact
716
+ // from and toToken param position reversed, to fetch the required quote and keep things generalised
717
+
718
+ leverSwap = debtAmount.isNegative()
719
+ ? ekuboQuoter.getVesuMultiplyQuote(
720
+ swapQuote,
721
+ collateralToken,
722
+ debtToken
723
+ )
724
+ : ekuboQuoter.getVesuMultiplyQuote(
725
+ swapQuote,
726
+ debtToken,
727
+ collateralToken
728
+ );
729
+ //console.log(JSON.stringify(leverSwap));
730
+ // Calculate limit amount with slippage protection
731
+ const MAX_SLIPPAGE = 0.002; // 0.2% slippage
732
+ if (debtAmount.greaterThan(0)) {
733
+ // For increase: minimum amount of collateral received
734
+ // from debt token to collateral token
735
+ //console.log("debtAmountInCollateralUnits", debtAmountInCollateralUnits.toNumber());
736
+ //leverSwapLimitAmount = await ekuboQuoter.getSwapLimitAmount(debtToken, collateralToken, debtAmount, MAX_SLIPPAGE);
737
+ leverSwapLimitAmount = debtAmount.multipliedBy(1 + MAX_SLIPPAGE);
738
+ //console.log("anotherleverSwapLimitAmount", anotherleverSwapLimitAmount, leverSwapLimitAmount);
739
+ } else if (debtAmount.lessThan(0)) {
740
+ // For decrease: maximum amount of collateral used
741
+ // from collateral token to debt token
742
+ //leverSwapLimitAmount = await ekuboQuoter.getSwapLimitAmount(collateralToken, debtToken, debtAmountInCollateralUnits.multipliedBy(-1), MAX_SLIPPAGE);
743
+ leverSwapLimitAmount = debtAmount
744
+ .abs()
745
+ .multipliedBy(1 - MAX_SLIPPAGE);
746
+ //console.log("anotherleverSwapLimitAmount", anotherleverSwapLimitAmount, leverSwapLimitAmount);
747
+ } else {
748
+ leverSwapLimitAmount = Web3Number.fromWei(0, debtToken.decimals);
749
+ }
750
+ await new Promise((resolve) => setTimeout(resolve, 1000));
751
+ //console.log("leverSwapLimitAmount", leverSwapLimitAmount);
752
+ } else {
753
+ throw new Error(
754
+ `VesuMultiplyAdapter: Price impact too high (${swapQuote.price_impact}), skipping swap`
755
+ );
756
+ }
757
+ } catch (error) {
758
+ throw new Error(
759
+ `VesuMultiplyAdapter: Failed to get swap quote: ${error}`
760
+ );
761
+ }
762
+ }
763
+
764
+ logger.info(`leverSwapLimitAmount: ${leverSwapLimitAmount} debtAmount: ${debtAmount} isIncrease: ${isIncrease}`);
765
+ const multiplyParams = await this.getLeverParams(
766
+ isIncrease,
767
+ params,
768
+ leverSwap,
769
+ leverSwapLimitAmount
770
+ );
771
+
772
+ const call = multiplyContract.populate("modify_lever", {
773
+ modify_lever_params: this.formatMultiplyParams(
774
+ isIncrease,
775
+ multiplyParams
776
+ ),
777
+ });
778
+ const calldata = call.calldata as bigint[];
779
+ if (calldata) {
780
+ console.log("calldata", calldata);
781
+ }
782
+ return calldata;
783
+ }
784
+
785
+ private async getWithdrawalMultiplyCalldata(
786
+ params: Web3Number,
787
+ debtAmount: Web3Number,
788
+ ): Promise<bigint[]> {
789
+ //params.amount must be in btc here
790
+ const { isV2 } = getVesuSingletonAddress(this.config.poolId);
791
+ const vesuMultiply = isV2
792
+ ? this.vesuAdapter.VESU_MULTIPLY
793
+ : this.vesuAdapter.VESU_MULTIPLY_V1;
794
+ const multiplyContract = new Contract({
795
+ abi: VesuMultiplyAbi,
796
+ address: vesuMultiply.address,
797
+ providerOrAccount: this.config.networkConfig.provider,
798
+ });
799
+ let leverSwap: Swap[] = [];
800
+ let leverSwapLimitAmount = Web3Number.fromWei(0, this.config.borrowToken.decimals);
801
+ const collateralToken = this.config.supplyToken;
802
+ const debtToken = this.config.borrowToken;
803
+ const debtPrice = await this.config.pricer.getPrice(debtToken.symbol);
804
+ // the debt amount is negative as we are reducing debt to withdraw
805
+ //console.log("debtAmountToRepay", debtAmountToRepay);
806
+ const ekuboQuoter = new EkuboQuoter(
807
+ this.config.networkConfig,
808
+ this.config.pricer
809
+ );
810
+ const debtInDebtUnits = debtAmount
811
+ .dividedBy(debtPrice.price)
812
+ .multipliedBy(10 ** debtToken.decimals);
813
+ const swapQuote = await ekuboQuoter.getQuote(
814
+ debtToken.address.address,
815
+ collateralToken.address.address,
816
+ debtInDebtUnits
817
+ );
818
+ const MAX_SLIPPAGE = 0.002; // 0.2% slippag
819
+ // const debtInCollateralUnits = new Web3Number(existingDebtInfo.amount.dividedBy(collateralPrice.price).multipliedBy(debtPrice.price).toFixed(WBTC_TOKEN_DECIMALS), collateralToken.decimals);
820
+ // console.log("debtInCollateralUnits", debtInCollateralUnits, existingDebtInfo.amount, collateralPrice.price, debtPrice.price, WBTC_TOKEN_DECIMALS);
821
+ if (swapQuote.price_impact < 0.0025) {
822
+ leverSwap = ekuboQuoter.getVesuMultiplyQuote(
823
+ swapQuote,
824
+ collateralToken,
825
+ debtToken
826
+ );
827
+ } else {
828
+ logger.error(
829
+ `VesuMultiplyAdapter: Price impact too high (${swapQuote.price_impact}), skipping swap`
830
+ );
831
+ }
832
+
833
+ leverSwapLimitAmount = debtAmount
834
+ .abs()
835
+ .multipliedBy(1 + MAX_SLIPPAGE);
836
+
837
+ // leverSwapLimitAmount = debtInCollateralUnits; this is used when closing position
838
+ console.log("leverSwapLimitAmount", leverSwapLimitAmount);
839
+ //leverSwapLimitAmount = await ekuboQuoter.getSwapLimitAmount(debtToken, collateralToken, debtInCollateralUnits, MAX_SLIPPAGE);
840
+ const multiplyParams = await this.getLeverParams(
841
+ false,
842
+ params,
843
+ leverSwap,
844
+ leverSwapLimitAmount
845
+ );
846
+ const call = multiplyContract.populate("modify_lever", {
847
+ modify_lever_params: this.formatMultiplyParams(false, multiplyParams),
848
+ });
849
+ console.log("call", call.calldata);
850
+ return call.calldata as bigint[];
851
+ }
852
+
853
+ formatMultiplyParams(
854
+ isIncrease: boolean,
855
+ params: IncreaseLeverParams | DecreaseLeverParams
856
+ ) {
857
+ if (isIncrease) {
858
+ const _params = params as IncreaseLeverParams;
859
+ return {
860
+ action: new CairoCustomEnum({
861
+ IncreaseLever: {
862
+ pool_id: _params.pool_id.toBigInt(),
863
+ collateral_asset: _params.collateral_asset.toBigInt(),
864
+ debt_asset: _params.debt_asset.toBigInt(),
865
+ user: _params.user.toBigInt(),
866
+ add_margin: BigInt(_params.add_margin.toWei()),
867
+ margin_swap: _params.margin_swap.map((swap) => ({
868
+ route: swap.route.map((route) => ({
869
+ pool_key: {
870
+ token0: route.pool_key.token0.toBigInt(),
871
+ token1: route.pool_key.token1.toBigInt(),
872
+ fee: route.pool_key.fee,
873
+ tick_spacing: route.pool_key.tick_spacing,
874
+ extension: BigInt(
875
+ num.hexToDecimalString(route.pool_key.extension)
876
+ ),
877
+ },
878
+ sqrt_ratio_limit: uint256.bnToUint256(
879
+ route.sqrt_ratio_limit.toWei()
880
+ ),
881
+ skip_ahead: BigInt(100),
882
+ })),
883
+ token_amount: {
884
+ token: swap.token_amount.token.toBigInt(),
885
+ amount: swap.token_amount.amount.toI129(),
886
+ },
887
+ })),
888
+ margin_swap_limit_amount: BigInt(
889
+ _params.margin_swap_limit_amount.toWei()
890
+ ),
891
+ lever_swap: _params.lever_swap.map((swap) => ({
892
+ route: swap.route.map((route) => ({
893
+ pool_key: {
894
+ token0: route.pool_key.token0.toBigInt(),
895
+ token1: route.pool_key.token1.toBigInt(),
896
+ fee: route.pool_key.fee,
897
+ tick_spacing: route.pool_key.tick_spacing,
898
+ extension: ContractAddr.from(
899
+ route.pool_key.extension
900
+ ).toBigInt(),
901
+ },
902
+ sqrt_ratio_limit: uint256.bnToUint256(
903
+ route.sqrt_ratio_limit.toWei()
904
+ ),
905
+ skip_ahead: BigInt(route.skip_ahead.toWei()),
906
+ })),
907
+ token_amount: {
908
+ token: swap.token_amount.token.toBigInt(),
909
+ amount: swap.token_amount.amount.toI129(),
910
+ },
911
+ })),
912
+ lever_swap_limit_amount: BigInt(
913
+ _params.lever_swap_limit_amount.toWei()
914
+ ),
915
+ },
916
+ }),
917
+ };
918
+ }
919
+
920
+ const _params = params as DecreaseLeverParams;
921
+ return {
922
+ action: new CairoCustomEnum({
923
+ DecreaseLever: {
924
+ pool_id: _params.pool_id.toBigInt(),
925
+ collateral_asset: _params.collateral_asset.toBigInt(),
926
+ debt_asset: _params.debt_asset.toBigInt(),
927
+ user: _params.user.toBigInt(),
928
+ sub_margin: BigInt(_params.sub_margin.toWei()),
929
+ recipient: _params.recipient.toBigInt(),
930
+ lever_swap: _params.lever_swap.map((swap) => ({
931
+ route: swap.route.map((route) => ({
932
+ pool_key: {
933
+ token0: route.pool_key.token0.toBigInt(),
934
+ token1: route.pool_key.token1.toBigInt(),
935
+ fee: route.pool_key.fee,
936
+ tick_spacing: route.pool_key.tick_spacing,
937
+ extension: ContractAddr.from(
938
+ route.pool_key.extension
939
+ ).toBigInt(),
940
+ },
941
+ sqrt_ratio_limit: uint256.bnToUint256(
942
+ route.sqrt_ratio_limit.toWei()
943
+ ),
944
+ skip_ahead: BigInt(route.skip_ahead.toWei()),
945
+ })),
946
+ token_amount: {
947
+ token: swap.token_amount.token.toBigInt(),
948
+ amount: swap.token_amount.amount.toI129(),
949
+ },
950
+ })),
951
+ lever_swap_limit_amount: BigInt(
952
+ _params.lever_swap_limit_amount.toWei()
953
+ ),
954
+ lever_swap_weights: _params.lever_swap_weights.map((weight) =>
955
+ BigInt(weight.toWei())
956
+ ),
957
+ withdraw_swap: _params.withdraw_swap.map((swap) => ({
958
+ route: swap.route.map((route) => ({
959
+ pool_key: {
960
+ token0: route.pool_key.token0.toBigInt(),
961
+ token1: route.pool_key.token1.toBigInt(),
962
+ fee: route.pool_key.fee,
963
+ tick_spacing: route.pool_key.tick_spacing,
964
+ extension: ContractAddr.from(
965
+ route.pool_key.extension
966
+ ).toBigInt(),
967
+ },
968
+ sqrt_ratio_limit: uint256.bnToUint256(
969
+ route.sqrt_ratio_limit.toWei()
970
+ ),
971
+ skip_ahead: BigInt(route.skip_ahead.toWei()),
972
+ })),
973
+ token_amount: {
974
+ token: swap.token_amount.token.toBigInt(),
975
+ amount: swap.token_amount.amount.toI129(),
976
+ },
977
+ })),
978
+ withdraw_swap_limit_amount: BigInt(
979
+ _params.withdraw_swap_limit_amount.toWei()
980
+ ),
981
+ withdraw_swap_weights: _params.withdraw_swap_weights.map((weight) =>
982
+ BigInt(weight.toWei())
983
+ ),
984
+ close_position: _params.close_position,
985
+ },
986
+ }),
987
+ };
988
+ }
989
+
990
+ private async getLeverParams(
991
+ isIncrease: boolean,
992
+ params: Web3Number,
993
+ leverSwap: Swap[],
994
+ leverSwapLimitAmount: Web3Number,
995
+ closePosition?: boolean
996
+ ): Promise<IncreaseLeverParams | DecreaseLeverParams> {
997
+ logger.info(`isIncrease: ${isIncrease} params: ${JSON.stringify(params)} leverSwap: ${JSON.stringify(leverSwap)} leverSwapLimitAmount: ${leverSwapLimitAmount} closePosition: ${closePosition}`);
998
+ const multiplyParams: IncreaseLeverParams | DecreaseLeverParams = isIncrease
999
+ ? {
1000
+ user: this.config.vaultAllocator,
1001
+ pool_id: this.config.poolId,
1002
+ collateral_asset: this.config.supplyToken.address,
1003
+ debt_asset: this.config.borrowToken.address,
1004
+ recipient: this.config.vaultAllocator,
1005
+ add_margin: params, // multiplied by collateral decimals in format
1006
+ margin_swap: [],
1007
+ margin_swap_limit_amount: Web3Number.fromWei(
1008
+ 0,
1009
+ this.config.supplyToken.decimals
1010
+ ),
1011
+ lever_swap: leverSwap,
1012
+ lever_swap_limit_amount: leverSwapLimitAmount,
1013
+ }
1014
+ : {
1015
+ user: this.config.vaultAllocator,
1016
+ pool_id: this.config.poolId,
1017
+ collateral_asset: this.config.supplyToken.address,
1018
+ debt_asset: this.config.borrowToken.address,
1019
+ recipient: this.config.vaultAllocator,
1020
+ sub_margin: params,
1021
+ lever_swap: leverSwap,
1022
+ lever_swap_limit_amount: leverSwapLimitAmount,
1023
+ lever_swap_weights: [],
1024
+ withdraw_swap: [],
1025
+ withdraw_swap_limit_amount: Web3Number.fromWei(
1026
+ 0,
1027
+ this.config.supplyToken.decimals
1028
+ ),
1029
+ withdraw_swap_weights: [],
1030
+ close_position: closePosition ?? false,
1031
+ };
1032
+ return multiplyParams;
1033
+ }
1034
+
1035
+ //params amount must be in usdc
1036
+ /**
1037
+ * The amount for debt payment or taken is already calculated and sent here, in
1038
+ * In case of debt payment, amount is the debtToBe Repaid
1039
+ * In case of debt taken, amount is the added collateral
1040
+ * @returns
1041
+ */
1042
+ private async getDepositCalldata(
1043
+ debtAmount: Web3Number,
1044
+ supplyAmount: Web3Number,
1045
+ ): Promise<bigint[]> {
1046
+ try {
1047
+ const supplyToken = this.config.supplyToken;
1048
+ const borrowToken = this.config.borrowToken;
1049
+ let supplyAmountInI257: { mag: Uint256; sign: 0 | 1 };
1050
+ let debtAmountInI257: { mag: Uint256; sign: 0 | 1 };
1051
+ const { addr: vesuSingleton } = getVesuSingletonAddress(
1052
+ this.config.poolId
1053
+ );
1054
+ const multiplyContract = new Contract({
1055
+ abi: VesuPoolV2Abi,
1056
+ address: vesuSingleton.address,
1057
+ providerOrAccount: this.config.networkConfig.provider,
1058
+ });
1059
+
1060
+ /**
1061
+ * The amount that is borrowed is slightly more than 60%, in order to trasnfer proper funds to extended and vesu
1062
+ */
1063
+ supplyAmountInI257 = supplyAmount.toI257();
1064
+ debtAmountInI257 = debtAmount.toI257();
1065
+ logger.info(`debtAmountInI257: ${debtAmountInI257}`);
1066
+
1067
+
1068
+ const depositParams = multiplyContract.populate("modify_position", {
1069
+ params: {
1070
+ collateral_asset: supplyToken.address.toBigInt(),
1071
+ debt_asset: borrowToken.address.toBigInt(),
1072
+ user: this.config.vaultAllocator.toBigInt(),
1073
+ collateral: {
1074
+ denomination: new CairoCustomEnum({ Assets: {} }),
1075
+ value: {
1076
+ abs: supplyAmountInI257.mag,
1077
+ is_negative: supplyAmountInI257.sign === 1,
1078
+ },
1079
+ },
1080
+ debt: {
1081
+ denomination: new CairoCustomEnum({ Assets: {} }),
1082
+ value: {
1083
+ abs: debtAmountInI257.mag,
1084
+ is_negative: debtAmountInI257.sign === 1,
1085
+ },
1086
+ },
1087
+ },
1088
+ });
1089
+ console.log("depositParams.calldata", depositParams.calldata);
1090
+ return depositParams.calldata as bigint[];
1091
+ } catch (err) {
1092
+ console.log("error getting deposit calldata", err);
1093
+ return [];
1094
+ }
1095
+ }
1096
+
1097
+ private async getClosePositionCalldata(
1098
+ debtAmount: Web3Number,
1099
+ supplyAmount: Web3Number,
1100
+ ): Promise<bigint[]> {
1101
+ try {
1102
+ const { isV2 } = getVesuSingletonAddress(this.config.poolId);
1103
+ const vesuMultiply = isV2
1104
+ ? this.vesuAdapter.VESU_MULTIPLY
1105
+ : this.vesuAdapter.VESU_MULTIPLY_V1;
1106
+ const multiplyContract = new Contract({
1107
+ abi: VesuMultiplyAbi,
1108
+ address: vesuMultiply.address,
1109
+ providerOrAccount: this.config.networkConfig.provider,
1110
+ });
1111
+ let leverSwap: Swap[] = [];
1112
+ let leverSwapLimitAmount = Web3Number.fromWei(0, this.config.borrowToken.decimals);
1113
+ const collateralToken = this.config.supplyToken;
1114
+ const debtToken = this.config.borrowToken;
1115
+ const debtPrice = await this.config.pricer.getPrice(debtToken.symbol);
1116
+ const collateralPrice = await this.config.pricer.getPrice(collateralToken.symbol);
1117
+ // the debt amount is negative as we are reducing debt to withdraw
1118
+ //console.log("debtAmountToRepay", debtAmountToRepay);
1119
+ const ekuboQuoter = new EkuboQuoter(
1120
+ this.config.networkConfig,
1121
+ this.config.pricer
1122
+ );
1123
+ const debtInCollateralUnits = new Web3Number(debtAmount.dividedBy(collateralPrice.price).multipliedBy(debtPrice.price).toFixed(WBTC_TOKEN_DECIMALS), collateralToken.decimals);
1124
+ console.log("debtInCollateralUnits", debtInCollateralUnits, collateralPrice.price, debtPrice.price, WBTC_TOKEN_DECIMALS);
1125
+ const swapQuote = await ekuboQuoter.getQuote(
1126
+ collateralToken.address.address,
1127
+ debtToken.address.address,
1128
+ debtInCollateralUnits.multipliedBy(10 ** 8)
1129
+ );
1130
+ console.log("swapQuote", swapQuote);
1131
+ const MAX_SLIPPAGE = 0.002; // 0.2% slippag
1132
+
1133
+ // if (swapQuote.price_impact < 0.0025) {
1134
+ leverSwap = ekuboQuoter.getVesuMultiplyQuote(
1135
+ swapQuote,
1136
+ debtToken,
1137
+ collateralToken
1138
+ );
1139
+ leverSwapLimitAmount = debtInCollateralUnits.multipliedBy(1 + MAX_SLIPPAGE); //this is used when closing position
1140
+ console.log("leverSwapLimitAmount", leverSwapLimitAmount);
1141
+ //leverSwapLimitAmount = await ekuboQuoter.getSwapLimitAmount(debtToken, collateralToken, debtInCollateralUnits, MAX_SLIPPAGE);
1142
+ const multiplyParams = await this.getLeverParams(
1143
+ false,
1144
+ supplyAmount,
1145
+ leverSwap,
1146
+ leverSwapLimitAmount,
1147
+ true
1148
+ );
1149
+ const call = multiplyContract.populate("modify_lever", {
1150
+ modify_lever_params: this.formatMultiplyParams(false, multiplyParams),
1151
+ });
1152
+ console.log("call", call.calldata);
1153
+ return call.calldata as bigint[];
1154
+ } catch (err) {
1155
+ console.log("error getting close position calldata", err);
1156
+ return [];
1157
+ }
1158
+ }
1159
+
1160
+ getProofsForDebtPayment<T>(tree: StandardMerkleTree): {
1161
+ proofs: string[][];
1162
+ callConstructor:
1163
+ GenerateCallFn<DepositParamsForLendingBorrowing>
1164
+ } {
1165
+ let proofGroups: string[][] = [];
1166
+
1167
+ const ids = this.getPayDebtLeaf().leaves.map((l) => l.readableId);
1168
+ // console.log(`${this.name}::getProofs ids: ${ids}`);
1169
+ for (const [i, v] of tree.entries()) {
1170
+ // console.log(`${this.name}::getProofs v: ${v.readableId}`);
1171
+ if (ids.includes(v.readableId)) {
1172
+ //console.log(`${this.name}::getProofs found id: ${v.readableId}`);
1173
+ proofGroups.push(tree.getProof(i));
1174
+ }
1175
+ }
1176
+ if (proofGroups.length != ids.length) {
1177
+ throw new Error(`Not all proofs found for IDs: ${ids.join(", ")}`);
1178
+ }
1179
+
1180
+ // find leaf adapter
1181
+ return {
1182
+ proofs: proofGroups,
1183
+ callConstructor: this.getPayDebtCall.bind(this),
1184
+ };
1185
+ }
1186
+
1187
+ getProofsForBorrowing<T>(tree: StandardMerkleTree): {
1188
+ proofs: string[][];
1189
+ callConstructor:
1190
+ GenerateCallFn<DepositParamsForLendingBorrowing>;
1191
+ } {
1192
+ let proofGroups: string[][] = [];
1193
+
1194
+ const ids = this.getBorrowLeaf().leaves.map((l) => l.readableId);
1195
+ // console.log(`${this.name}::getProofs ids: ${ids}`);
1196
+ for (const [i, v] of tree.entries()) {
1197
+ // console.log(`${this.name}::getProofs v: ${v.readableId}`);
1198
+ if (ids.includes(v.readableId)) {
1199
+ console.log(`${this.name}::getProofs found id: ${v.readableId}`);
1200
+ proofGroups.push(tree.getProof(i));
1201
+ }
1202
+ }
1203
+ if (proofGroups.length != ids.length) {
1204
+ throw new Error(`Not all proofs found for IDs: ${ids.join(", ")}`);
1205
+ }
1206
+
1207
+ // find leaf adapter
1208
+ return {
1209
+ proofs: proofGroups,
1210
+ callConstructor: this.getBorrowCall.bind(this),
1211
+ };
1212
+ }
1213
+
1214
+ getProofsForMultiply(tree: StandardMerkleTree): {
1215
+ proofs: string[][];
1216
+ callConstructor:
1217
+ GenerateCallFn<({
1218
+ amount: Web3Number;
1219
+ debtAmount: Web3Number;
1220
+ isWithdraw: boolean;
1221
+ closePosition: boolean;
1222
+ })>;
1223
+ } {
1224
+ let proofGroups: string[][] = [];
1225
+
1226
+ const ids = this.getMultiplyLeaf().leaves.map((l) => l.readableId);
1227
+ logger.verbose(`${this.name}::getProofsForMultiply searching for IDs: ${ids.join(", ")}`);
1228
+ const treeIds: string[] = [];
1229
+ for (const [i, v] of tree.entries()) {
1230
+ // console.log(`${this.name}::getProofs v: ${v.readableId}`);
1231
+ if (ids.includes(v.readableId)) {
1232
+ logger.verbose(`${this.name}::getProofsForMultiply found id: ${v.readableId}`);
1233
+ proofGroups.push(tree.getProof(i));
1234
+ }
1235
+ }
1236
+ if (proofGroups.length != ids.length) {
1237
+ throw new Error(`Not all proofs found for IDs: ${ids.join(", ")}`);
1238
+ }
1239
+
1240
+ // find leaf adapter
1241
+ return {
1242
+ proofs: proofGroups,
1243
+ callConstructor: this.getMultiplyCall.bind(this),
1244
+ };
1245
+ }
1246
+
1247
+ }