@strkfarm/sdk 2.0.0-dev.1 → 2.0.0-dev.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.browser.global.js +1314 -384
- package/dist/index.browser.mjs +1314 -384
- package/dist/index.d.ts +48 -9
- package/dist/index.js +1315 -384
- package/dist/index.mjs +1314 -384
- package/package.json +1 -1
- package/src/dataTypes/address.ts +1 -1
- package/src/modules/ekubo-quoter.ts +1 -12
- package/src/strategies/universal-adapters/avnu-adapter.ts +11 -14
- package/src/strategies/universal-adapters/extended-adapter.ts +514 -86
- package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +790 -408
- package/src/strategies/universal-lst-muliplier-strategy.tsx +2 -1
- package/src/strategies/universal-strategy.tsx +5 -0
- package/src/strategies/vesu-extended-strategy/services/operationService.ts +8 -2
- package/src/strategies/vesu-extended-strategy/utils/constants.ts +3 -1
- package/src/strategies/vesu-extended-strategy/utils/helper.ts +21 -25
- package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +533 -115
|
@@ -13,7 +13,7 @@ import { logger } from "@/utils";
|
|
|
13
13
|
import { AUDIT_URL } from "../universal-lst-muliplier-strategy";
|
|
14
14
|
import { getNoRiskTags } from "@/interfaces";
|
|
15
15
|
import { _riskFactor } from "../universal-lst-muliplier-strategy";
|
|
16
|
-
import { EXTENDED_QTY_PRECISION, LIMIT_BALANCE, MAX_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED, MIN_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED, MINIMUM_EXTENDED_POSITION_SIZE, USDC_TOKEN_DECIMALS, WBTC_TOKEN_DECIMALS } from "./utils/constants";
|
|
16
|
+
import { BUFFER_USDC_IN_WITHDRAWAL, EXTENDED_QTY_PRECISION, LIMIT_BALANCE, LIMIT_BALANCE_VALUE, MAX_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED, MIN_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED, MINIMUM_EXTENDED_POSITION_SIZE, USDC_TOKEN_DECIMALS, WALLET_ADDRESS, WBTC_TOKEN_DECIMALS } from "./utils/constants";
|
|
17
17
|
import { PricerBase } from "@/modules/pricerBase";
|
|
18
18
|
import { ContractAddr, Web3Number } from "@/dataTypes";
|
|
19
19
|
import { Global } from "@/global";
|
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
} from "./utils/helper";
|
|
54
54
|
import { SingleTokenInfo } from "../base-strategy";
|
|
55
55
|
import { Call } from "starknet";
|
|
56
|
+
import { PositionTypeAvnuExtended} from "../universal-strategy";
|
|
56
57
|
|
|
57
58
|
|
|
58
59
|
export interface VesuExtendedStrategySettings
|
|
@@ -71,7 +72,6 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
71
72
|
>
|
|
72
73
|
extends SVKStrategy<S>
|
|
73
74
|
implements Operations {
|
|
74
|
-
|
|
75
75
|
constructor(
|
|
76
76
|
config: IConfig,
|
|
77
77
|
pricer: PricerBase,
|
|
@@ -109,6 +109,26 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
109
109
|
};
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
async getUnusedBalanceUSDCE(): Promise<SingleTokenInfo> {
|
|
113
|
+
const usdceToken = Global.getDefaultTokens().find(
|
|
114
|
+
(token) => token.symbol === "USDCe"
|
|
115
|
+
)!;
|
|
116
|
+
const balance = await new ERC20(this.config).balanceOf(
|
|
117
|
+
usdceToken.address,
|
|
118
|
+
WALLET_ADDRESS,
|
|
119
|
+
usdceToken.decimals
|
|
120
|
+
);
|
|
121
|
+
const price = await this.pricer.getPrice(usdceToken.symbol);
|
|
122
|
+
const usdValue =
|
|
123
|
+
Number(balance.toFixed(usdceToken.decimals)) * price.price;
|
|
124
|
+
return {
|
|
125
|
+
tokenInfo: usdceToken,
|
|
126
|
+
amount: balance,
|
|
127
|
+
usdValue,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
112
132
|
async getUnusedBalanceWBTC(): Promise<SingleTokenInfo> {
|
|
113
133
|
const collateralToken = this.metadata.additionalInfo.borrowable_assets[0]!;
|
|
114
134
|
const balance = await new ERC20(this.config).balanceOf(
|
|
@@ -159,23 +179,31 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
159
179
|
return extendedAdapter.adapter as ExtendedAdapter;
|
|
160
180
|
}
|
|
161
181
|
|
|
162
|
-
async moveAssetsToVaultAllocator(amount: Web3Number): Promise<Call[]> {
|
|
163
|
-
try{
|
|
164
|
-
const
|
|
165
|
-
(token) => token.symbol === "
|
|
182
|
+
async moveAssetsToVaultAllocator(amount: Web3Number, extendedAdapter: ExtendedAdapter): Promise<Call[]> {
|
|
183
|
+
try {
|
|
184
|
+
const usdceToken = Global.getDefaultTokens().find(
|
|
185
|
+
(token) => token.symbol === "USDCe"
|
|
166
186
|
)!;
|
|
167
187
|
const approveCall = new ERC20(this.config).approve(
|
|
168
|
-
|
|
188
|
+
usdceToken.address,
|
|
169
189
|
this.metadata.additionalInfo.vaultAllocator,
|
|
170
190
|
amount
|
|
171
191
|
);
|
|
172
192
|
const transferCall = new ERC20(this.config).transfer(
|
|
173
|
-
|
|
193
|
+
usdceToken.address,
|
|
174
194
|
this.metadata.additionalInfo.vaultAllocator,
|
|
175
195
|
amount
|
|
176
196
|
);
|
|
177
|
-
|
|
178
|
-
|
|
197
|
+
const proofsInfo = extendedAdapter.getProofsForFromLegacySwap(
|
|
198
|
+
this.getMerkleTree()
|
|
199
|
+
);
|
|
200
|
+
const proofGroups = proofsInfo.proofs;
|
|
201
|
+
const call = this.getManageCall(
|
|
202
|
+
proofGroups,
|
|
203
|
+
await proofsInfo.callConstructor({ amount: amount })
|
|
204
|
+
);
|
|
205
|
+
return [approveCall, transferCall, call];
|
|
206
|
+
} catch (err) {
|
|
179
207
|
logger.error(`error moving assets to vault allocator: ${err}`);
|
|
180
208
|
return [];
|
|
181
209
|
}
|
|
@@ -191,11 +219,14 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
191
219
|
vesuLeverage: number;
|
|
192
220
|
}> {
|
|
193
221
|
try {
|
|
222
|
+
logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest starting`);
|
|
194
223
|
const vesuAdapter = await this.getVesuAdapter();
|
|
195
224
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
196
|
-
|
|
225
|
+
logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest adapters fetched: vesuAdapter=${!!vesuAdapter}, extendedAdapter=${!!extendedAdapter}, extendedAdapter.client=${!!extendedAdapter?.client}`);
|
|
226
|
+
|
|
227
|
+
if (!vesuAdapter) {
|
|
197
228
|
logger.error(
|
|
198
|
-
`
|
|
229
|
+
`Vesu adapter not configured in metadata. This is a configuration issue, not a temporary failure.`
|
|
199
230
|
);
|
|
200
231
|
return {
|
|
201
232
|
shouldInvest: false,
|
|
@@ -207,12 +238,95 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
207
238
|
vesuLeverage: 0,
|
|
208
239
|
};
|
|
209
240
|
}
|
|
241
|
+
if (!extendedAdapter) {
|
|
242
|
+
logger.error(
|
|
243
|
+
`Extended adapter not configured in metadata. This is a configuration issue, not a temporary failure.`
|
|
244
|
+
);
|
|
245
|
+
return {
|
|
246
|
+
shouldInvest: false,
|
|
247
|
+
vesuAmount: new Web3Number(0, 0),
|
|
248
|
+
extendedAmount: new Web3Number(0, 0),
|
|
249
|
+
extendedLeverage: 0,
|
|
250
|
+
collateralPrice: 0,
|
|
251
|
+
debtPrice: 0,
|
|
252
|
+
vesuLeverage: 0,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
if (!extendedAdapter.client) {
|
|
256
|
+
logger.error(
|
|
257
|
+
`Extended adapter client not initialized. This may be a temporary initialization failure - check network connectivity and API availability.`
|
|
258
|
+
);
|
|
259
|
+
return {
|
|
260
|
+
shouldInvest: false,
|
|
261
|
+
vesuAmount: new Web3Number(0, 0),
|
|
262
|
+
extendedAmount: new Web3Number(0, 0),
|
|
263
|
+
extendedLeverage: 0,
|
|
264
|
+
collateralPrice: 0,
|
|
265
|
+
debtPrice: 0,
|
|
266
|
+
vesuLeverage: 0,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest calling getUnusedBalance`);
|
|
210
271
|
const balance = await this.getUnusedBalance();
|
|
272
|
+
|
|
273
|
+
if (!Number.isFinite(balance.usdValue) || balance.usdValue < 0) {
|
|
274
|
+
logger.error(
|
|
275
|
+
`Invalid balance.usdValue: ${balance.usdValue}. Expected a finite, non-negative number.`
|
|
276
|
+
);
|
|
277
|
+
return {
|
|
278
|
+
shouldInvest: false,
|
|
279
|
+
vesuAmount: new Web3Number(0, 0),
|
|
280
|
+
extendedAmount: new Web3Number(0, 0),
|
|
281
|
+
extendedLeverage: 0,
|
|
282
|
+
collateralPrice: 0,
|
|
283
|
+
debtPrice: 0,
|
|
284
|
+
vesuLeverage: 0,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest balance: ${balance.usdValue}`);
|
|
211
288
|
const usdcBalanceOnExtended = await extendedAdapter.getExtendedDepositAmount();
|
|
289
|
+
|
|
290
|
+
if (usdcBalanceOnExtended) {
|
|
291
|
+
const availableForWithdrawal = parseFloat(usdcBalanceOnExtended.availableForWithdrawal);
|
|
292
|
+
if (!Number.isFinite(availableForWithdrawal) || availableForWithdrawal < 0) {
|
|
293
|
+
logger.error(
|
|
294
|
+
`Invalid usdcBalanceOnExtended.availableForWithdrawal: ${usdcBalanceOnExtended.availableForWithdrawal}. Expected a finite, non-negative number.`
|
|
295
|
+
);
|
|
296
|
+
return {
|
|
297
|
+
shouldInvest: false,
|
|
298
|
+
vesuAmount: new Web3Number(0, 0),
|
|
299
|
+
extendedAmount: new Web3Number(0, 0),
|
|
300
|
+
extendedLeverage: 0,
|
|
301
|
+
collateralPrice: 0,
|
|
302
|
+
debtPrice: 0,
|
|
303
|
+
vesuLeverage: 0,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
212
308
|
/** The LIMIT_BALANCE is the bffer amount to keep in the investing Cycle */
|
|
213
|
-
const amountToInvest = balance.
|
|
309
|
+
const amountToInvest = new Web3Number(balance.usdValue, USDC_TOKEN_DECIMALS).plus(usdcBalanceOnExtended?.availableForWithdrawal ?? 0).multipliedBy(1 - LIMIT_BALANCE);
|
|
214
310
|
|
|
215
|
-
|
|
311
|
+
|
|
312
|
+
const amountToInvestNumber = amountToInvest.toNumber();
|
|
313
|
+
if (!Number.isFinite(amountToInvestNumber)) {
|
|
314
|
+
logger.error(
|
|
315
|
+
`Invalid amountToInvest calculation result: ${amountToInvestNumber}. Calculation may have produced NaN or Infinity.`
|
|
316
|
+
);
|
|
317
|
+
return {
|
|
318
|
+
shouldInvest: false,
|
|
319
|
+
vesuAmount: new Web3Number(0, 0),
|
|
320
|
+
extendedAmount: new Web3Number(0, 0),
|
|
321
|
+
extendedLeverage: 0,
|
|
322
|
+
collateralPrice: 0,
|
|
323
|
+
debtPrice: 0,
|
|
324
|
+
vesuLeverage: 0,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest amountToInvest: ${amountToInvestNumber}`);
|
|
329
|
+
if (amountToInvest.lessThan(LIMIT_BALANCE_VALUE)) {
|
|
216
330
|
return {
|
|
217
331
|
shouldInvest: false,
|
|
218
332
|
vesuAmount: new Web3Number(0, 0),
|
|
@@ -244,6 +358,37 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
244
358
|
collateralPrice,
|
|
245
359
|
debtPrice
|
|
246
360
|
} = await this.getAssetPrices();
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
if (!Number.isFinite(collateralPrice.price) || collateralPrice.price <= 0) {
|
|
364
|
+
logger.error(
|
|
365
|
+
`Invalid collateralPrice: ${collateralPrice.price}. Expected a finite, positive number.`
|
|
366
|
+
);
|
|
367
|
+
return {
|
|
368
|
+
shouldInvest: false,
|
|
369
|
+
vesuAmount: new Web3Number(0, 0),
|
|
370
|
+
extendedAmount: new Web3Number(0, 0),
|
|
371
|
+
extendedLeverage: 0,
|
|
372
|
+
collateralPrice: 0,
|
|
373
|
+
debtPrice: 0,
|
|
374
|
+
vesuLeverage: 0,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
if (!Number.isFinite(debtPrice.price) || debtPrice.price <= 0) {
|
|
378
|
+
logger.error(
|
|
379
|
+
`Invalid debtPrice: ${debtPrice.price}. Expected a finite, positive number.`
|
|
380
|
+
);
|
|
381
|
+
return {
|
|
382
|
+
shouldInvest: false,
|
|
383
|
+
vesuAmount: new Web3Number(0, 0),
|
|
384
|
+
extendedAmount: new Web3Number(0, 0),
|
|
385
|
+
extendedLeverage: 0,
|
|
386
|
+
collateralPrice: 0,
|
|
387
|
+
debtPrice: 0,
|
|
388
|
+
vesuLeverage: 0,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
|
|
247
392
|
const { vesu_amount, extended_amount, extended_leverage, vesu_leverage } =
|
|
248
393
|
await calculateAmountDistribution(
|
|
249
394
|
amountToInvest.toNumber(),
|
|
@@ -273,6 +418,7 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
273
418
|
vesuLeverage: 0,
|
|
274
419
|
};
|
|
275
420
|
}
|
|
421
|
+
logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest vesu_amount: ${vesu_amount.toNumber()}, extended_amount: ${extended_amount.toNumber()}`);
|
|
276
422
|
return {
|
|
277
423
|
shouldInvest: true,
|
|
278
424
|
vesuAmount: vesu_amount,
|
|
@@ -300,18 +446,67 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
300
446
|
try {
|
|
301
447
|
const vesuAdapter = await this.getVesuAdapter();
|
|
302
448
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
303
|
-
let calls: Call[] = [];
|
|
304
449
|
if (!vesuAdapter || !extendedAdapter || !extendedAdapter.client) {
|
|
305
450
|
logger.error(
|
|
306
451
|
`vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
|
|
307
452
|
);
|
|
308
|
-
return
|
|
453
|
+
return [];
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
457
|
+
if (!extendedHoldings) {
|
|
458
|
+
logger.error(`error getting extended holdings: ${extendedHoldings}`);
|
|
459
|
+
return [];
|
|
460
|
+
}
|
|
461
|
+
const usdcAmountInWallet = (await this.getUnusedBalance()).amount;
|
|
462
|
+
const usdcAmountOnExtendedAvailableForWithdrawal = parseFloat(
|
|
463
|
+
extendedHoldings.availableForWithdrawal
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldMoveAssets calculating movements - Extended current: ${usdcAmountOnExtendedAvailableForWithdrawal}, Wallet: ${usdcAmountInWallet.toNumber()}, Target Extended: ${extendedAmount.toNumber()}, Target Vesu: ${vesuAmount.toNumber()}`);
|
|
467
|
+
|
|
468
|
+
let totalExtendedWithdrawal = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
469
|
+
let totalExtendedDeposit = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
470
|
+
|
|
471
|
+
if (extendedAmount.isNegative() && extendedAmount.abs().greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
472
|
+
totalExtendedWithdrawal = totalExtendedWithdrawal.plus(extendedAmount.abs());
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Calculate remaining Extended difference (target vs current)
|
|
476
|
+
// If extendedAmount was negative, we've already accounted for that withdrawal
|
|
477
|
+
// So we calculate based on what Extended will be after that withdrawal
|
|
478
|
+
const extendedTargetAmount = extendedAmount.abs(); // Use absolute value as target
|
|
479
|
+
let projectedExtendedBalance = usdcAmountOnExtendedAvailableForWithdrawal;
|
|
480
|
+
|
|
481
|
+
if (extendedAmount.isNegative()) {
|
|
482
|
+
projectedExtendedBalance = projectedExtendedBalance - extendedAmount.abs().toNumber();
|
|
309
483
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
484
|
+
|
|
485
|
+
const extendedAmountDifference = extendedTargetAmount.minus(projectedExtendedBalance);
|
|
486
|
+
const extendedAmountDifferenceAbs = extendedAmountDifference.abs();
|
|
487
|
+
|
|
488
|
+
// Track additional Extended movements
|
|
489
|
+
if (extendedAmountDifference.lessThan(0)) {
|
|
490
|
+
totalExtendedWithdrawal = totalExtendedWithdrawal.plus(extendedAmountDifferenceAbs);
|
|
491
|
+
} else if (extendedAmountDifference.greaterThan(0)) {
|
|
492
|
+
totalExtendedDeposit = totalExtendedDeposit.plus(extendedAmountDifference);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
const vesuTargetAmount = vesuAmount.abs();
|
|
496
|
+
const projectedWalletBalance = usdcAmountInWallet
|
|
497
|
+
.plus(totalExtendedWithdrawal)
|
|
498
|
+
.minus(totalExtendedDeposit);
|
|
499
|
+
|
|
500
|
+
let vesuAmountDifference = vesuTargetAmount.minus(projectedWalletBalance);
|
|
501
|
+
const vesuAmountDifferenceAbs = vesuAmountDifference.abs();
|
|
502
|
+
|
|
503
|
+
logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldMoveAssets calculated movements - Extended withdrawal: ${totalExtendedWithdrawal.toNumber()}, Extended deposit: ${totalExtendedDeposit.toNumber()}, Extended diff: ${extendedAmountDifference.toNumber()}, Projected wallet: ${projectedWalletBalance.toNumber()}, Vesu diff: ${vesuAmountDifference.toNumber()}`);
|
|
504
|
+
let calls: Call[] = [];
|
|
505
|
+
|
|
506
|
+
// Handle negative extendedAmount (initial withdrawal needed)
|
|
507
|
+
if (extendedAmount.isNegative() && extendedAmount.abs().greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
313
508
|
try {
|
|
314
|
-
const extendedCalls = await this.moveAssets(
|
|
509
|
+
const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
|
|
315
510
|
{
|
|
316
511
|
to: Protocols.VAULT.name,
|
|
317
512
|
from: Protocols.EXTENDED.name,
|
|
@@ -320,15 +515,19 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
320
515
|
extendedAdapter,
|
|
321
516
|
vesuAdapter
|
|
322
517
|
);
|
|
323
|
-
|
|
518
|
+
if (extendedStatus) {
|
|
519
|
+
calls.push(...extendedCalls);
|
|
520
|
+
} else {
|
|
521
|
+
return [];
|
|
522
|
+
}
|
|
324
523
|
} catch (err) {
|
|
325
524
|
logger.error(`Failed moving assets to vault: ${err}`);
|
|
326
525
|
}
|
|
327
526
|
}
|
|
328
527
|
|
|
329
|
-
if (vesuAmount.
|
|
528
|
+
if (vesuAmount.isNegative() && vesuAmount.abs().greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
|
|
330
529
|
try {
|
|
331
|
-
const vesuCalls = await this.moveAssets(
|
|
530
|
+
const { calls: vesuCalls, status: vesuStatus } = await this.moveAssets(
|
|
332
531
|
{
|
|
333
532
|
to: Protocols.EXTENDED.name,
|
|
334
533
|
from: Protocols.VESU.name,
|
|
@@ -338,54 +537,91 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
338
537
|
vesuAdapter
|
|
339
538
|
);
|
|
340
539
|
calls.push(...vesuCalls);
|
|
540
|
+
if (!vesuStatus) {
|
|
541
|
+
return [];
|
|
542
|
+
}
|
|
341
543
|
} catch (err) {
|
|
342
544
|
logger.error(`Failed moving assets to vault: ${err}`);
|
|
343
545
|
}
|
|
344
546
|
}
|
|
345
547
|
|
|
346
|
-
|
|
347
|
-
if (
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
{
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
548
|
+
// Handle Extended adjustments based on calculated difference
|
|
549
|
+
if (extendedAmountDifferenceAbs.greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
550
|
+
if (extendedAmountDifference.greaterThan(0)) {
|
|
551
|
+
try {
|
|
552
|
+
const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
|
|
553
|
+
{
|
|
554
|
+
to: Protocols.EXTENDED.name,
|
|
555
|
+
from: Protocols.VAULT.name,
|
|
556
|
+
amount: extendedAmountDifference,
|
|
557
|
+
},
|
|
558
|
+
extendedAdapter,
|
|
559
|
+
vesuAdapter
|
|
560
|
+
);
|
|
561
|
+
if (extendedStatus) {
|
|
562
|
+
calls.push(...extendedCalls);
|
|
563
|
+
} else {
|
|
564
|
+
logger.error(`Failed to move assets to extended - operation returned false status`);
|
|
565
|
+
return [];
|
|
566
|
+
}
|
|
567
|
+
} catch (err) {
|
|
568
|
+
logger.error(`Failed moving assets to extended: ${err}`);
|
|
569
|
+
return [];
|
|
570
|
+
}
|
|
571
|
+
} else if (extendedAmountDifference.lessThan(0)) {
|
|
572
|
+
try {
|
|
573
|
+
const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
|
|
574
|
+
{
|
|
575
|
+
to: Protocols.VAULT.name,
|
|
576
|
+
from: Protocols.EXTENDED.name,
|
|
577
|
+
amount: extendedAmountDifferenceAbs,
|
|
578
|
+
},
|
|
579
|
+
extendedAdapter,
|
|
580
|
+
vesuAdapter
|
|
581
|
+
);
|
|
582
|
+
if (extendedStatus) {
|
|
583
|
+
calls.push(...extendedCalls);
|
|
584
|
+
} else {
|
|
585
|
+
logger.error(`Failed to withdraw from extended - operation returned false status`);
|
|
586
|
+
return [];
|
|
587
|
+
}
|
|
588
|
+
} catch (err) {
|
|
589
|
+
logger.error(`Failed moving assets from extended to vault: ${err}`);
|
|
590
|
+
return [];
|
|
591
|
+
}
|
|
370
592
|
}
|
|
371
593
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
from: Protocols.EXTENDED.name,
|
|
379
|
-
amount: vesuAmount.minus(usdcAmountInWallet),
|
|
380
|
-
},
|
|
381
|
-
extendedAdapter,
|
|
382
|
-
vesuAdapter
|
|
594
|
+
|
|
595
|
+
// Handle Vesu adjustments based on calculated difference (already adjusted for Extended movements)
|
|
596
|
+
if (vesuAmountDifferenceAbs.greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
|
|
597
|
+
if (vesuAmountDifference.lessThanOrEqualTo(0)) {
|
|
598
|
+
logger.warn(
|
|
599
|
+
`Vesu amount difference is negative or zero: ${vesuAmountDifference.toNumber()}. Skipping operation.`
|
|
383
600
|
);
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
601
|
+
} else {
|
|
602
|
+
// Move assets from Extended to Vault (which will then go to Vesu)
|
|
603
|
+
try {
|
|
604
|
+
const { calls: vesuCalls, status: vesuStatus } = await this.moveAssets(
|
|
605
|
+
{
|
|
606
|
+
to: Protocols.VAULT.name,
|
|
607
|
+
from: Protocols.EXTENDED.name,
|
|
608
|
+
amount: vesuAmountDifference,
|
|
609
|
+
},
|
|
610
|
+
extendedAdapter,
|
|
611
|
+
vesuAdapter
|
|
612
|
+
);
|
|
613
|
+
if (!vesuStatus) {
|
|
614
|
+
logger.error(`Failed to move assets to vesu - operation returned false status`);
|
|
615
|
+
return [];
|
|
616
|
+
}
|
|
617
|
+
calls.push(...vesuCalls);
|
|
618
|
+
} catch (err) {
|
|
619
|
+
logger.error(`Failed moving assets to vault: ${err}`);
|
|
620
|
+
return [];
|
|
621
|
+
}
|
|
387
622
|
}
|
|
388
623
|
}
|
|
624
|
+
|
|
389
625
|
return calls;
|
|
390
626
|
} catch (err) {
|
|
391
627
|
logger.error(`Failed moving assets to vesu: ${err}`);
|
|
@@ -401,18 +637,61 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
401
637
|
},
|
|
402
638
|
extendedAdapter: ExtendedAdapter,
|
|
403
639
|
vesuAdapter: VesuMultiplyAdapter
|
|
404
|
-
): Promise<
|
|
640
|
+
): Promise<{
|
|
641
|
+
calls: Call[];
|
|
642
|
+
status: boolean;
|
|
643
|
+
}> {
|
|
405
644
|
try {
|
|
645
|
+
// Validate amount is positive before starting operations
|
|
646
|
+
if (params.amount.lessThanOrEqualTo(0)) {
|
|
647
|
+
logger.error(
|
|
648
|
+
`Invalid amount for moveAssets: ${params.amount.toNumber()}. Amount must be positive.`
|
|
649
|
+
);
|
|
650
|
+
return {
|
|
651
|
+
calls: [],
|
|
652
|
+
status: false
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// Check minimum movement amounts before starting operations
|
|
657
|
+
const amountAbs = params.amount.abs();
|
|
658
|
+
if (params.from === Protocols.EXTENDED.name || params.to === Protocols.EXTENDED.name) {
|
|
659
|
+
if (amountAbs.lessThanOrEqualTo(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
660
|
+
logger.warn(
|
|
661
|
+
`Amount ${amountAbs.toNumber()} is below minimum Extended movement amount ${extendedAdapter.minimumExtendedMovementAmount}. Skipping operation.`
|
|
662
|
+
);
|
|
663
|
+
return {
|
|
664
|
+
calls: [],
|
|
665
|
+
status: false
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
if (params.from === Protocols.VESU.name || params.to === Protocols.VESU.name) {
|
|
670
|
+
if (amountAbs.lessThanOrEqualTo(vesuAdapter.minimumVesuMovementAmount)) {
|
|
671
|
+
logger.warn(
|
|
672
|
+
`Amount ${amountAbs.toNumber()} is below minimum Vesu movement amount ${vesuAdapter.minimumVesuMovementAmount}. Skipping operation.`
|
|
673
|
+
);
|
|
674
|
+
return {
|
|
675
|
+
calls: [],
|
|
676
|
+
status: false
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
406
681
|
const avnuAdapter = await this.getAvnuAdapter();
|
|
407
682
|
if (!avnuAdapter) {
|
|
408
683
|
logger.error(`avnu adapter not found: ${avnuAdapter}`);
|
|
409
|
-
return
|
|
684
|
+
return {
|
|
685
|
+
calls: [],
|
|
686
|
+
status: false
|
|
687
|
+
};
|
|
410
688
|
}
|
|
411
|
-
logger.info(
|
|
689
|
+
logger.info(`moveAssets params, ${JSON.stringify(params)}`);
|
|
412
690
|
const collateralToken = vesuAdapter.config.supportedPositions[0].asset;
|
|
413
691
|
const {
|
|
414
692
|
collateralPrice,
|
|
415
693
|
} = await this.getAssetPrices();
|
|
694
|
+
|
|
416
695
|
if (params.to === Protocols.EXTENDED.name && params.from === Protocols.VAULT.name) {
|
|
417
696
|
const proofsInfo = extendedAdapter.getProofs(
|
|
418
697
|
true,
|
|
@@ -425,23 +704,79 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
425
704
|
await proofsInfo.callConstructor({ amount: params.amount })
|
|
426
705
|
);
|
|
427
706
|
calls.push(call);
|
|
428
|
-
return
|
|
707
|
+
return {
|
|
708
|
+
calls: [call],
|
|
709
|
+
status: true
|
|
710
|
+
};
|
|
429
711
|
} else if (params.to === Protocols.VAULT.name && params.from === Protocols.EXTENDED.name) {
|
|
712
|
+
const extendedLeverage = calculateExtendedLevergae();
|
|
713
|
+
const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
714
|
+
if (!extendedHoldings) {
|
|
715
|
+
logger.error(`error getting extended holdings: ${extendedHoldings}`);
|
|
716
|
+
return {
|
|
717
|
+
calls: [],
|
|
718
|
+
status: false
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
const extendedHoldingAmount = new Web3Number(
|
|
722
|
+
extendedHoldings.availableForWithdrawal,
|
|
723
|
+
USDC_TOKEN_DECIMALS
|
|
724
|
+
);
|
|
725
|
+
logger.info(`${VesuExtendedMultiplierStrategy.name}::moveAssets extendedHoldingAmount: ${extendedHoldingAmount.toNumber()}`);
|
|
726
|
+
if (params.amount.abs().greaterThan(extendedHoldingAmount)) {
|
|
727
|
+
const leftAmountAfterWithdrawalAmountInAccount = params.amount.abs().minus(extendedHoldingAmount);
|
|
728
|
+
logger.info(`${VesuExtendedMultiplierStrategy.name}::moveAssets leftAmountAfterWithdrawalAmountInAccount: ${leftAmountAfterWithdrawalAmountInAccount.toNumber()}`);
|
|
729
|
+
const btcAmount = leftAmountAfterWithdrawalAmountInAccount.dividedBy(collateralPrice.price);
|
|
730
|
+
const openLongPosition = btcAmount.multipliedBy(3).greaterThan(MINIMUM_EXTENDED_POSITION_SIZE) ? await extendedAdapter.createOrder(
|
|
731
|
+
extendedLeverage.toString(),
|
|
732
|
+
btcAmount.toNumber(),
|
|
733
|
+
OrderSide.BUY
|
|
734
|
+
) : await extendedAdapter.createOrder(
|
|
735
|
+
extendedLeverage.toString(),
|
|
736
|
+
0.000035, // just in case amount falls short then we need to create a withdrawal
|
|
737
|
+
OrderSide.BUY
|
|
738
|
+
)
|
|
739
|
+
if (!openLongPosition) {
|
|
740
|
+
logger.error(`error opening long position: ${openLongPosition}`);
|
|
741
|
+
}
|
|
742
|
+
const updatedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
743
|
+
if (!updatedHoldings || new Web3Number(updatedHoldings.availableForWithdrawal, USDC_TOKEN_DECIMALS).lessThan(params.amount.abs())) {
|
|
744
|
+
logger.error(`Insufficient balance after opening position. Available: ${updatedHoldings?.availableForWithdrawal}, Needed: ${params.amount.abs()}`);
|
|
745
|
+
return { calls: [], status: false };
|
|
746
|
+
}
|
|
747
|
+
}
|
|
430
748
|
const withdrawalFromExtended =
|
|
431
749
|
await extendedAdapter.withdrawFromExtended(params.amount);
|
|
432
750
|
if (withdrawalFromExtended) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
const
|
|
751
|
+
/**
|
|
752
|
+
* We need to move assets from my wallet back to vault contract
|
|
753
|
+
*/
|
|
754
|
+
const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
755
|
+
logger.info(`extendedHoldings after withdrawal ${extendedHoldings?.availableForWithdrawal}`);
|
|
756
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
757
|
+
const calls = await this.moveAssetsToVaultAllocator(params.amount, extendedAdapter);
|
|
437
758
|
if (calls.length > 0) {
|
|
438
|
-
return
|
|
759
|
+
return {
|
|
760
|
+
calls: calls,
|
|
761
|
+
status: true
|
|
762
|
+
};
|
|
439
763
|
}
|
|
440
764
|
} else {
|
|
441
765
|
logger.error("withdrawal from extended failed");
|
|
766
|
+
return {
|
|
767
|
+
calls: [],
|
|
768
|
+
status: false
|
|
769
|
+
};
|
|
442
770
|
}
|
|
443
|
-
return [];
|
|
444
771
|
} else if (params.to === Protocols.VAULT.name && params.from === Protocols.VESU.name) {
|
|
772
|
+
const isPriceDifferenceBetweenAvnuAndExtended = await this.checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter, vesuAdapter, avnuAdapter, PositionTypeAvnuExtended.CLOSE);
|
|
773
|
+
if (!isPriceDifferenceBetweenAvnuAndExtended) {
|
|
774
|
+
logger.warn(`price difference between avnu and extended doesn't fit the range for close position, ${avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing}`);
|
|
775
|
+
return {
|
|
776
|
+
calls: [],
|
|
777
|
+
status: false
|
|
778
|
+
};
|
|
779
|
+
}
|
|
445
780
|
//withdraw from vesu
|
|
446
781
|
const vesuAmountInBTC = new Web3Number(
|
|
447
782
|
params.amount.dividedBy(collateralPrice.price).toNumber(),
|
|
@@ -462,8 +797,19 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
462
797
|
await swapProofsInfo.callConstructor({ amount: vesuAmountInBTC })
|
|
463
798
|
);
|
|
464
799
|
calls.push(swapCall);
|
|
465
|
-
return
|
|
800
|
+
return {
|
|
801
|
+
calls: calls,
|
|
802
|
+
status: true
|
|
803
|
+
};
|
|
466
804
|
} else if (params.to === Protocols.EXTENDED.name && params.from === Protocols.VESU.name) {
|
|
805
|
+
const isPriceDifferenceBetweenAvnuAndExtended = await this.checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter, vesuAdapter, avnuAdapter, PositionTypeAvnuExtended.CLOSE);
|
|
806
|
+
if (!isPriceDifferenceBetweenAvnuAndExtended) {
|
|
807
|
+
logger.warn(`price difference between avnu and extended doesn't fit the range for close position, ${avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing}`);
|
|
808
|
+
return {
|
|
809
|
+
calls: [],
|
|
810
|
+
status: false
|
|
811
|
+
};
|
|
812
|
+
}
|
|
467
813
|
const vesuAmountInBTC = new Web3Number(
|
|
468
814
|
params.amount.dividedBy(collateralPrice.price).toNumber(),
|
|
469
815
|
collateralToken.decimals
|
|
@@ -494,19 +840,28 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
494
840
|
await proofsInfoDeposit.callConstructor({ amount: params.amount })
|
|
495
841
|
);
|
|
496
842
|
calls.push(callDeposit);
|
|
497
|
-
return
|
|
843
|
+
return {
|
|
844
|
+
calls: calls,
|
|
845
|
+
status: true
|
|
846
|
+
};
|
|
498
847
|
}
|
|
499
|
-
|
|
500
|
-
|
|
848
|
+
return {
|
|
849
|
+
calls: [],
|
|
850
|
+
status: false
|
|
851
|
+
};
|
|
501
852
|
} catch (err) {
|
|
502
853
|
logger.error(`error moving assets: ${err}`);
|
|
503
|
-
return
|
|
854
|
+
return {
|
|
855
|
+
calls: [],
|
|
856
|
+
status: false
|
|
857
|
+
};
|
|
504
858
|
}
|
|
505
859
|
}
|
|
506
860
|
|
|
507
861
|
async handleDeposit(): Promise<{
|
|
508
|
-
extendedAmountInBTC
|
|
509
|
-
calls:Call[]
|
|
862
|
+
extendedAmountInBTC: Web3Number,
|
|
863
|
+
calls: Call[]
|
|
864
|
+
}> {
|
|
510
865
|
try {
|
|
511
866
|
const vesuAdapter = await this.getVesuAdapter();
|
|
512
867
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
@@ -528,7 +883,7 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
528
883
|
};
|
|
529
884
|
}
|
|
530
885
|
const extendedLeverage = calculateExtendedLevergae();
|
|
531
|
-
const isPriceDifferenceBetweenAvnuAndExtended = await this.checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter, vesuAdapter, avnuAdapter);
|
|
886
|
+
const isPriceDifferenceBetweenAvnuAndExtended = await this.checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter, vesuAdapter, avnuAdapter, PositionTypeAvnuExtended.OPEN);
|
|
532
887
|
if (!isPriceDifferenceBetweenAvnuAndExtended) {
|
|
533
888
|
logger.error("price difference between avnu and extended doesn't fit the range");
|
|
534
889
|
return {
|
|
@@ -545,6 +900,7 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
545
900
|
};
|
|
546
901
|
}
|
|
547
902
|
const extendedPositionValue = position.length > 0 ? parseFloat(position[0].value) : 0;
|
|
903
|
+
const BUFFER_AMOUNT_IN_AVAILABLE_FOR_TRADE = BUFFER_USDC_IN_WITHDRAWAL;
|
|
548
904
|
const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
549
905
|
if (!extendedHoldings) {
|
|
550
906
|
logger.error(`error getting extended holdings: ${extendedHoldings}`);
|
|
@@ -563,14 +919,14 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
563
919
|
const { collateralPrice } = await this.getAssetPrices();
|
|
564
920
|
const { vesuAmountInBTC, extendedAmountInBTC } = calculateVesUPositionSizeGivenExtended(
|
|
565
921
|
extendedPositionValue,
|
|
566
|
-
extendedHoldingAmount,
|
|
922
|
+
extendedHoldingAmount.minus(BUFFER_AMOUNT_IN_AVAILABLE_FOR_TRADE),
|
|
567
923
|
collateralTokenAmount,
|
|
568
924
|
collateralPrice.price
|
|
569
925
|
);
|
|
570
|
-
|
|
571
|
-
|
|
926
|
+
logger.info(`vesuAmountInBTC ${vesuAmountInBTC}, extendedAmountInBTC ${extendedAmountInBTC}`);
|
|
927
|
+
|
|
572
928
|
let calls: Call[] = [];
|
|
573
|
-
if(vesuAmountInBTC.greaterThan(MINIMUM_EXTENDED_POSITION_SIZE)){
|
|
929
|
+
if (vesuAmountInBTC.greaterThan(MINIMUM_EXTENDED_POSITION_SIZE)) {
|
|
574
930
|
const proofsInfo = vesuAdapter.getProofs(true, this.getMerkleTree());
|
|
575
931
|
const proofGroups = proofsInfo.proofs;
|
|
576
932
|
const call = this.getManageCall(
|
|
@@ -581,7 +937,6 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
581
937
|
);
|
|
582
938
|
const { amount: wbtcAmountInVaultAllocator } = await this.getUnusedBalanceWBTC();
|
|
583
939
|
if (wbtcAmountInVaultAllocator.lessThan(vesuAmountInBTC)) {
|
|
584
|
-
console.log("error wbtc amount in vault allocator is less than vesu amount in btc", wbtcAmountInVaultAllocator, vesuAmountInBTC);
|
|
585
940
|
const swapProofsInfo = avnuAdapter.getProofs(true, this.getMerkleTree());
|
|
586
941
|
const swapProofGroups = swapProofsInfo.proofs;
|
|
587
942
|
const swapCall = this.getManageCall(
|
|
@@ -594,7 +949,6 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
594
949
|
}
|
|
595
950
|
calls.push(call);
|
|
596
951
|
}
|
|
597
|
-
|
|
598
952
|
const shortPosition = extendedAmountInBTC.multipliedBy(3).abs().greaterThan(MINIMUM_EXTENDED_POSITION_SIZE) ? await extendedAdapter.createOrder(
|
|
599
953
|
extendedLeverage.toString(),
|
|
600
954
|
extendedAmountInBTC.toNumber(),
|
|
@@ -616,48 +970,67 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
616
970
|
return {
|
|
617
971
|
extendedAmountInBTC: new Web3Number(0, 0),
|
|
618
972
|
calls: [],
|
|
619
|
-
}
|
|
973
|
+
};
|
|
620
974
|
}
|
|
621
975
|
}
|
|
622
976
|
|
|
623
|
-
async checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter:ExtendedAdapter, vesuAdapter:VesuMultiplyAdapter, avnuAdapter:AvnuAdapter): Promise<boolean> {
|
|
977
|
+
async checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter: ExtendedAdapter, vesuAdapter: VesuMultiplyAdapter, avnuAdapter: AvnuAdapter, positionType: PositionTypeAvnuExtended): Promise<boolean> {
|
|
624
978
|
const {
|
|
625
979
|
ask, bid
|
|
626
|
-
}= await extendedAdapter.fetchOrderBookBTCUSDC();
|
|
980
|
+
} = await extendedAdapter.fetchOrderBookBTCUSDC();
|
|
627
981
|
const price = ask.plus(bid).dividedBy(2);
|
|
628
|
-
const btcToken = vesuAdapter.config.supportedPositions[
|
|
982
|
+
const btcToken = vesuAdapter.config.supportedPositions[0].asset;
|
|
629
983
|
const btcPriceAvnu = await avnuAdapter.getPriceOfToken(btcToken.address.toString());
|
|
630
984
|
if (!btcPriceAvnu) {
|
|
631
985
|
logger.error(`error getting btc price avnu: ${btcPriceAvnu}`);
|
|
632
986
|
return false;
|
|
633
987
|
}
|
|
634
|
-
const priceDifference = price.minus(btcPriceAvnu).
|
|
635
|
-
if(priceDifference
|
|
636
|
-
return
|
|
988
|
+
const priceDifference = new Web3Number(price.minus(btcPriceAvnu).toFixed(2), 0);
|
|
989
|
+
if(priceDifference.isNegative()){
|
|
990
|
+
return false;
|
|
991
|
+
}
|
|
992
|
+
if(positionType === PositionTypeAvnuExtended.OPEN){
|
|
993
|
+
logger.info(`price difference between avnu and extended for open position: ${priceDifference.toNumber()}, minimumExtendedPriceDifferenceForSwapOpen: ${avnuAdapter.config.minimumExtendedPriceDifferenceForSwapOpen}`);
|
|
994
|
+
const result = priceDifference.greaterThanOrEqualTo(avnuAdapter.config.minimumExtendedPriceDifferenceForSwapOpen); // 500 for now
|
|
995
|
+
logger.info(`result: ${result}`);
|
|
996
|
+
return result;
|
|
997
|
+
}else{
|
|
998
|
+
logger.info(`price difference between avnu and extended for close position: ${priceDifference.toNumber()}, maximumExtendedPriceDifferenceForSwapClosing: ${avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing}`);
|
|
999
|
+
const result = priceDifference.lessThanOrEqualTo(avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing); // 1000 for now
|
|
1000
|
+
logger.info(`result: ${result}`);
|
|
1001
|
+
return result;
|
|
637
1002
|
}
|
|
638
|
-
logger.error(`price difference between avnu and extended doesn't fit the range, priceDifference: ${priceDifference}`);
|
|
639
|
-
return false;
|
|
640
1003
|
}
|
|
641
1004
|
|
|
642
|
-
async handleWithdraw(amount: Web3Number): Promise<Call[]> {
|
|
1005
|
+
async handleWithdraw(amount: Web3Number): Promise<{ calls: Call[], status: boolean }> {
|
|
643
1006
|
try {
|
|
644
|
-
const usdcBalanceVaultAllocator = await this.getUnusedBalance()
|
|
645
|
-
const usdcBalanceDifference = amount.minus(usdcBalanceVaultAllocator.usdValue);
|
|
1007
|
+
const usdcBalanceVaultAllocator = await this.getUnusedBalance();
|
|
1008
|
+
const usdcBalanceDifference = amount.plus(BUFFER_USDC_IN_WITHDRAWAL).minus(usdcBalanceVaultAllocator.usdValue);
|
|
646
1009
|
logger.info(`usdcBalanceDifference, ${usdcBalanceDifference.toNumber()}`);
|
|
1010
|
+
let calls: Call[] = [];
|
|
1011
|
+
let status: boolean = true;
|
|
647
1012
|
if (usdcBalanceDifference.lessThan(0)) {
|
|
648
1013
|
const withdrawCall = await this.getBringLiquidityCall({
|
|
649
|
-
amount: amount
|
|
1014
|
+
amount: usdcBalanceVaultAllocator.amount
|
|
650
1015
|
})
|
|
651
1016
|
logger.info("withdraw call", withdrawCall);
|
|
652
|
-
|
|
1017
|
+
calls.push(withdrawCall);
|
|
1018
|
+
return {
|
|
1019
|
+
calls: calls,
|
|
1020
|
+
status: true
|
|
1021
|
+
};
|
|
653
1022
|
}
|
|
654
1023
|
const vesuAdapter = await this.getVesuAdapter();
|
|
655
1024
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
656
1025
|
if (!vesuAdapter || !extendedAdapter || !extendedAdapter.client) {
|
|
1026
|
+
status = false;
|
|
657
1027
|
logger.error(
|
|
658
1028
|
`vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
|
|
659
1029
|
);
|
|
660
|
-
return
|
|
1030
|
+
return {
|
|
1031
|
+
calls: calls,
|
|
1032
|
+
status: status
|
|
1033
|
+
};
|
|
661
1034
|
}
|
|
662
1035
|
const { collateralTokenAmount } =
|
|
663
1036
|
await vesuAdapter.vesuAdapter.getAssetPrices();
|
|
@@ -665,22 +1038,35 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
665
1038
|
collateralPrice
|
|
666
1039
|
} = await this.getAssetPrices();
|
|
667
1040
|
const extendedPositon = await extendedAdapter.getAllOpenPositions();
|
|
1041
|
+
if (!extendedPositon) {
|
|
1042
|
+
status = false;
|
|
1043
|
+
logger.error("error getting extended position", extendedPositon);
|
|
1044
|
+
return {
|
|
1045
|
+
calls: calls,
|
|
1046
|
+
status: status
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
668
1049
|
const amountDistributionForWithdrawal =
|
|
669
1050
|
await calculateAmountDistributionForWithdrawal(
|
|
670
|
-
|
|
1051
|
+
usdcBalanceDifference,
|
|
671
1052
|
collateralPrice.price,
|
|
672
1053
|
collateralTokenAmount,
|
|
673
1054
|
extendedPositon
|
|
674
1055
|
);
|
|
675
1056
|
if (!amountDistributionForWithdrawal) {
|
|
1057
|
+
status = false;
|
|
676
1058
|
logger.error(
|
|
677
1059
|
`error calculating amount distribution for withdrawal: ${amountDistributionForWithdrawal}`
|
|
678
1060
|
);
|
|
679
|
-
return
|
|
1061
|
+
return {
|
|
1062
|
+
calls: calls,
|
|
1063
|
+
status: status
|
|
1064
|
+
};
|
|
680
1065
|
}
|
|
681
1066
|
const { vesu_amount, extended_amount } = amountDistributionForWithdrawal;
|
|
682
|
-
|
|
683
|
-
|
|
1067
|
+
|
|
1068
|
+
if (status && vesu_amount.greaterThan(0)) {
|
|
1069
|
+
const { calls: vesuCalls, status: vesuStatus } = await this.moveAssets(
|
|
684
1070
|
{
|
|
685
1071
|
amount: vesu_amount,
|
|
686
1072
|
from: Protocols.VESU.name,
|
|
@@ -689,10 +1075,11 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
689
1075
|
extendedAdapter,
|
|
690
1076
|
vesuAdapter
|
|
691
1077
|
);
|
|
692
|
-
|
|
1078
|
+
status = vesuStatus;
|
|
1079
|
+
calls.push(...vesuCalls);
|
|
693
1080
|
}
|
|
694
|
-
if (extended_amount.greaterThan(0)) {
|
|
695
|
-
const
|
|
1081
|
+
if (status && extended_amount.greaterThan(0)) {
|
|
1082
|
+
const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
|
|
696
1083
|
{
|
|
697
1084
|
amount: extended_amount,
|
|
698
1085
|
from: Protocols.EXTENDED.name,
|
|
@@ -701,12 +1088,32 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
701
1088
|
extendedAdapter,
|
|
702
1089
|
vesuAdapter
|
|
703
1090
|
);
|
|
704
|
-
|
|
1091
|
+
status = extendedStatus;
|
|
1092
|
+
if (status) {
|
|
1093
|
+
calls.push(...extendedCalls);
|
|
1094
|
+
} else {
|
|
1095
|
+
logger.error("error moving assets to vault: extendedStatus: ${extendedStatus}");
|
|
1096
|
+
return {
|
|
1097
|
+
calls: [],
|
|
1098
|
+
status: status
|
|
1099
|
+
};
|
|
1100
|
+
}
|
|
705
1101
|
}
|
|
706
|
-
|
|
1102
|
+
const withdrawCall = await this.getBringLiquidityCall({
|
|
1103
|
+
amount: amount
|
|
1104
|
+
})
|
|
1105
|
+
logger.info("withdraw call", withdrawCall);
|
|
1106
|
+
calls.push(withdrawCall);
|
|
1107
|
+
return {
|
|
1108
|
+
calls: calls,
|
|
1109
|
+
status: status
|
|
1110
|
+
};
|
|
707
1111
|
} catch (err) {
|
|
708
1112
|
logger.error(`error handling withdrawal: ${err}`);
|
|
709
|
-
return
|
|
1113
|
+
return {
|
|
1114
|
+
calls: [],
|
|
1115
|
+
status: false
|
|
1116
|
+
};
|
|
710
1117
|
}
|
|
711
1118
|
}
|
|
712
1119
|
|
|
@@ -714,7 +1121,7 @@ export class VesuExtendedMultiplierStrategy<
|
|
|
714
1121
|
const allPositions: PositionInfo[] = [];
|
|
715
1122
|
for (let adapter of this.metadata.additionalInfo.adapters) {
|
|
716
1123
|
const positions = await adapter.adapter.getPositions();
|
|
717
|
-
|
|
1124
|
+
allPositions.push(...positions);
|
|
718
1125
|
}
|
|
719
1126
|
|
|
720
1127
|
const assetPrice = await this.pricer.getPrice(this.asset().symbol);
|
|
@@ -765,6 +1172,11 @@ function getLooperSettings(
|
|
|
765
1172
|
extendedBackendUrl: string,
|
|
766
1173
|
extendedApiKey: string,
|
|
767
1174
|
vaultIdExtended: number,
|
|
1175
|
+
minimumExtendedMovementAmount: number,
|
|
1176
|
+
minimumVesuMovementAmount: number,
|
|
1177
|
+
minimumExtendedRetriesDelayForOrderStatus: number,
|
|
1178
|
+
minimumExtendedPriceDifferenceForSwapOpen: number,
|
|
1179
|
+
maximumExtendedPriceDifferenceForSwapClosing: number,
|
|
768
1180
|
) {
|
|
769
1181
|
vaultSettings.leafAdapters = [];
|
|
770
1182
|
|
|
@@ -793,6 +1205,8 @@ function getLooperSettings(
|
|
|
793
1205
|
avnuContract: AVNU_MIDDLEWARE,
|
|
794
1206
|
slippage: 0.01,
|
|
795
1207
|
baseUrl: AVNU_QUOTE_URL,
|
|
1208
|
+
minimumExtendedPriceDifferenceForSwapOpen: minimumExtendedPriceDifferenceForSwapOpen,
|
|
1209
|
+
maximumExtendedPriceDifferenceForSwapClosing: maximumExtendedPriceDifferenceForSwapClosing,
|
|
796
1210
|
});
|
|
797
1211
|
|
|
798
1212
|
const extendedAdapter = new ExtendedAdapter({
|
|
@@ -810,6 +1224,8 @@ function getLooperSettings(
|
|
|
810
1224
|
extendedMarketName: "BTC-USD",
|
|
811
1225
|
extendedPrecision: 5,
|
|
812
1226
|
avnuAdapter: avnuAdapter,
|
|
1227
|
+
retryDelayForOrderStatus: minimumExtendedRetriesDelayForOrderStatus ?? 3000,
|
|
1228
|
+
minimumExtendedMovementAmount: minimumExtendedMovementAmount ?? 5, //5 usdcs
|
|
813
1229
|
});
|
|
814
1230
|
|
|
815
1231
|
const vesuMultiplyAdapter = new VesuMultiplyAdapter({
|
|
@@ -824,6 +1240,7 @@ function getLooperSettings(
|
|
|
824
1240
|
{ asset: wbtcToken, isDebt: false },
|
|
825
1241
|
{ asset: usdcToken, isDebt: true },
|
|
826
1242
|
],
|
|
1243
|
+
minimumVesuMovementAmount: minimumVesuMovementAmount ?? 5, //5 usdc
|
|
827
1244
|
});
|
|
828
1245
|
|
|
829
1246
|
const unusedBalanceAdapter = new UnusedBalanceAdapter({
|
|
@@ -863,6 +1280,7 @@ function getLooperSettings(
|
|
|
863
1280
|
vesuMultiplyAdapter.getWithdrawLeaf()
|
|
864
1281
|
);
|
|
865
1282
|
vaultSettings.leafAdapters.push(() => extendedAdapter.getDepositLeaf());
|
|
1283
|
+
vaultSettings.leafAdapters.push(() => extendedAdapter.getSwapFromLegacyLeaf());
|
|
866
1284
|
vaultSettings.leafAdapters.push(() => avnuAdapter.getDepositLeaf());
|
|
867
1285
|
vaultSettings.leafAdapters.push(() => avnuAdapter.getWithdrawLeaf());
|
|
868
1286
|
// Doubt here, should this be usdcToken.address, or wbtcToken.address?
|
|
@@ -956,15 +1374,15 @@ const re7UsdcPrimeDevansh: VesuExtendedStrategySettings = {
|
|
|
956
1374
|
minimumWBTCDifferenceForAvnuSwap: MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP,
|
|
957
1375
|
}
|
|
958
1376
|
|
|
959
|
-
export const VesuExtendedTestStrategies = (extendedBackendUrl: string, extendedApiKey: string, vaultIdExtended: number): IStrategyMetadata<VesuExtendedStrategySettings>[] => {
|
|
1377
|
+
export const VesuExtendedTestStrategies = (extendedBackendUrl: string, extendedApiKey: string, vaultIdExtended: number, minimumExtendedMovementAmount: number, minimumVesuMovementAmount: number, minimumExtendedRetriesDelayForOrderStatus: number, minimumExtendedPriceDifferenceForSwapOpen: number, maximumExtendedPriceDifferenceForSwapClosing: number): IStrategyMetadata<VesuExtendedStrategySettings>[] => {
|
|
960
1378
|
return [
|
|
961
|
-
getStrategySettingsVesuExtended('WBTC', 'USDC', re7UsdcPrimeDevansh, false, false, extendedBackendUrl, extendedApiKey, vaultIdExtended),
|
|
1379
|
+
getStrategySettingsVesuExtended('WBTC', 'USDC', re7UsdcPrimeDevansh, false, false, extendedBackendUrl, extendedApiKey, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing),
|
|
962
1380
|
]
|
|
963
1381
|
}
|
|
964
1382
|
|
|
965
1383
|
|
|
966
1384
|
|
|
967
|
-
function getStrategySettingsVesuExtended(lstSymbol: string, underlyingSymbol: string, addresses: VesuExtendedStrategySettings, isPreview: boolean = false, isLST: boolean, extendedBackendUrl: string, extendedApiKey: string, vaultIdExtended: number): IStrategyMetadata<VesuExtendedStrategySettings> {
|
|
1385
|
+
function getStrategySettingsVesuExtended(lstSymbol: string, underlyingSymbol: string, addresses: VesuExtendedStrategySettings, isPreview: boolean = false, isLST: boolean, extendedBackendUrl: string, extendedApiKey: string, vaultIdExtended: number, minimumExtendedMovementAmount: number, minimumVesuMovementAmount: number, minimumExtendedRetriesDelayForOrderStatus: number, minimumExtendedPriceDifferenceForSwapOpen: number, maximumExtendedPriceDifferenceForSwapClosing: number): IStrategyMetadata<VesuExtendedStrategySettings> {
|
|
968
1386
|
return {
|
|
969
1387
|
name: `Extended Test ${underlyingSymbol}`,
|
|
970
1388
|
description: getDescription(lstSymbol, underlyingSymbol),
|
|
@@ -972,7 +1390,7 @@ function getStrategySettingsVesuExtended(lstSymbol: string, underlyingSymbol: st
|
|
|
972
1390
|
launchBlock: 0,
|
|
973
1391
|
type: 'Other',
|
|
974
1392
|
depositTokens: [Global.getDefaultTokens().find(token => token.symbol === underlyingSymbol)!],
|
|
975
|
-
additionalInfo: getLooperSettings(lstSymbol, underlyingSymbol, addresses, VesuPools.Re7USDCPrime, extendedBackendUrl, extendedApiKey, vaultIdExtended),
|
|
1393
|
+
additionalInfo: getLooperSettings(lstSymbol, underlyingSymbol, addresses, VesuPools.Re7USDCPrime, extendedBackendUrl, extendedApiKey, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing),
|
|
976
1394
|
risk: {
|
|
977
1395
|
riskFactor: _riskFactor,
|
|
978
1396
|
netRisk:
|