@strkfarm/sdk 2.0.0-dev.2 → 2.0.0-dev.21
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 +2006 -1062
- package/dist/index.browser.mjs +1845 -911
- package/dist/index.d.ts +144 -37
- package/dist/index.js +1853 -915
- package/dist/index.mjs +1845 -911
- package/package.json +1 -1
- package/src/modules/ExtendedWrapperSDk/types.ts +1 -1
- package/src/modules/ExtendedWrapperSDk/wrapper.ts +39 -8
- package/src/modules/ekubo-quoter.ts +0 -12
- package/src/strategies/index.ts +2 -1
- package/src/strategies/universal-adapters/avnu-adapter.ts +17 -9
- package/src/strategies/universal-adapters/extended-adapter.ts +500 -146
- package/src/strategies/universal-adapters/index.ts +2 -1
- package/src/strategies/universal-adapters/vesu-adapter.ts +6 -6
- package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +778 -396
- 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 +25 -16
- package/src/strategies/vesu-extended-strategy/types/transaction-metadata.ts +36 -0
- package/src/strategies/vesu-extended-strategy/utils/constants.ts +3 -6
- package/src/strategies/vesu-extended-strategy/utils/helper.ts +50 -16
- package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +746 -305
package/dist/index.browser.mjs
CHANGED
|
@@ -4269,20 +4269,13 @@ var EkuboQuoter = class _EkuboQuoter {
|
|
|
4269
4269
|
async getDexPrice(baseToken, quoteToken, amount) {
|
|
4270
4270
|
const lstTokenInfo = baseToken;
|
|
4271
4271
|
const lstUnderlyingTokenInfo = quoteToken;
|
|
4272
|
-
console.log("lstTokenInfo", lstTokenInfo);
|
|
4273
|
-
console.log("lstUnderlyingTokenInfo", lstUnderlyingTokenInfo);
|
|
4274
|
-
console.log("amount", amount);
|
|
4275
4272
|
const quote = await this.getQuote(
|
|
4276
4273
|
lstTokenInfo.address.address,
|
|
4277
4274
|
lstUnderlyingTokenInfo.address.address,
|
|
4278
4275
|
amount
|
|
4279
4276
|
);
|
|
4280
|
-
console.log("quote", quote);
|
|
4281
4277
|
const outputAmount = Web3Number.fromWei(quote.total_calculated, lstUnderlyingTokenInfo.decimals);
|
|
4282
|
-
console.log("outputAmount", outputAmount);
|
|
4283
|
-
console.log("amount", amount);
|
|
4284
4278
|
const price = outputAmount.toNumber() / amount.toNumber();
|
|
4285
|
-
console.log("price", price);
|
|
4286
4279
|
logger.verbose(`${_EkuboQuoter.name}:: LST Dex Price: ${price}`);
|
|
4287
4280
|
return price;
|
|
4288
4281
|
}
|
|
@@ -4301,16 +4294,12 @@ var EkuboQuoter = class _EkuboQuoter {
|
|
|
4301
4294
|
// debt collateral
|
|
4302
4295
|
async getSwapLimitAmount(fromToken, toToken, amount, max_slippage = 2e-3) {
|
|
4303
4296
|
const isExactAmountIn = amount.greaterThanOrEqualTo(0);
|
|
4304
|
-
console.log("isExactAmountIn", isExactAmountIn);
|
|
4305
4297
|
logger.verbose(`${_EkuboQuoter.name}::getSwapLimitAmount isExactAmountIn: ${isExactAmountIn}, fromToken: ${fromToken.symbol}, toToken: ${toToken.symbol}, amount: ${amount}`);
|
|
4306
4298
|
const isYieldToken = this.tokenMarketData.isAPYSupported(toToken);
|
|
4307
4299
|
console.log("isYieldToken", isYieldToken);
|
|
4308
4300
|
const baseToken = isExactAmountIn ? toToken : fromToken;
|
|
4309
4301
|
const quoteToken = isExactAmountIn ? fromToken : toToken;
|
|
4310
|
-
console.log("baseToken", baseToken);
|
|
4311
|
-
console.log("quoteToken", quoteToken);
|
|
4312
4302
|
const dexPrice = await this.getDexPrice(baseToken, quoteToken, amount);
|
|
4313
|
-
console.log("dexPrice", dexPrice);
|
|
4314
4303
|
const trueExchangeRate = isYieldToken ? await this.tokenMarketData.getTruePrice(baseToken) : dexPrice;
|
|
4315
4304
|
console.log("trueExchangeRate", trueExchangeRate);
|
|
4316
4305
|
if (isExactAmountIn) {
|
|
@@ -4341,7 +4330,6 @@ var EkuboQuoter = class _EkuboQuoter {
|
|
|
4341
4330
|
return quote.splits.map((split) => {
|
|
4342
4331
|
const isNegativeAmount = BigInt(split.amount_specified) <= 0n;
|
|
4343
4332
|
const token = isNegativeAmount ? toTokenInfo : fromTokenInfo;
|
|
4344
|
-
console.log("token for withdrawal", token, isNegativeAmount);
|
|
4345
4333
|
return {
|
|
4346
4334
|
route: split.route.map((_route) => ({
|
|
4347
4335
|
pool_key: {
|
|
@@ -4532,7 +4520,22 @@ var ExtendedWrapper = class {
|
|
|
4532
4520
|
`HTTP ${response.status}: ${errorData.detail || response.statusText}`
|
|
4533
4521
|
);
|
|
4534
4522
|
}
|
|
4535
|
-
const
|
|
4523
|
+
const text = await response.text();
|
|
4524
|
+
const MAX_SAFE_INTEGER_STR = "9007199254740991";
|
|
4525
|
+
const largeIntegerRegex = /"data"\s*:\s*(\d{16,})/g;
|
|
4526
|
+
const modifiedText = text.replace(largeIntegerRegex, (match, largeInt) => {
|
|
4527
|
+
if (largeInt.length > MAX_SAFE_INTEGER_STR.length || largeInt.length === MAX_SAFE_INTEGER_STR.length && largeInt > MAX_SAFE_INTEGER_STR) {
|
|
4528
|
+
return `"data":"${largeInt}"`;
|
|
4529
|
+
}
|
|
4530
|
+
return match;
|
|
4531
|
+
});
|
|
4532
|
+
const data = JSON.parse(modifiedText);
|
|
4533
|
+
if (data && typeof data.data === "string" && /^\d+$/.test(data.data)) {
|
|
4534
|
+
const numValue = Number(data.data);
|
|
4535
|
+
if (Number.isSafeInteger(numValue)) {
|
|
4536
|
+
data.data = numValue;
|
|
4537
|
+
}
|
|
4538
|
+
}
|
|
4536
4539
|
return data;
|
|
4537
4540
|
} catch (error) {
|
|
4538
4541
|
lastError = error;
|
|
@@ -4592,6 +4595,7 @@ var ExtendedWrapper = class {
|
|
|
4592
4595
|
}
|
|
4593
4596
|
/**
|
|
4594
4597
|
* Initiate a withdrawal from Extended Exchange
|
|
4598
|
+
* Returns data as number | string to preserve precision for large integers
|
|
4595
4599
|
*/
|
|
4596
4600
|
async withdraw(request) {
|
|
4597
4601
|
return this.makeRequest("/api/v1/withdraw", {
|
|
@@ -4730,6 +4734,7 @@ var ExtendedWrapper = class {
|
|
|
4730
4734
|
}
|
|
4731
4735
|
/**
|
|
4732
4736
|
* Withdraw USDC (convenience method)
|
|
4737
|
+
* Returns data as number | string to preserve precision for large integers
|
|
4733
4738
|
*/
|
|
4734
4739
|
async withdrawUSDC(amount) {
|
|
4735
4740
|
return this.withdraw({ amount, asset: "USDC" });
|
|
@@ -4739,11 +4744,13 @@ var ExtendedWrapper = class {
|
|
|
4739
4744
|
* @param marketName - The name of the market to get funding rates for
|
|
4740
4745
|
* @returns The funding rates for the specified market
|
|
4741
4746
|
*/
|
|
4742
|
-
async getFundingRates(marketName, side) {
|
|
4747
|
+
async getFundingRates(marketName, side, startTime, endTime) {
|
|
4748
|
+
const endTimeParam = endTime !== void 0 ? `&end_time=${endTime}` : "";
|
|
4749
|
+
const startTimeParam = startTime !== void 0 ? `&start_time=${startTime}` : "";
|
|
4743
4750
|
return this.makeRequest(
|
|
4744
4751
|
`/api/v1/markets/funding-rates?market_name=${encodeURIComponent(
|
|
4745
4752
|
marketName
|
|
4746
|
-
)}&side=${encodeURIComponent(side)}`
|
|
4753
|
+
)}&side=${encodeURIComponent(side)}${startTimeParam}${endTimeParam}`
|
|
4747
4754
|
);
|
|
4748
4755
|
}
|
|
4749
4756
|
};
|
|
@@ -27402,11 +27409,6 @@ var VesuAdapter = class _VesuAdapter extends CacheClass {
|
|
|
27402
27409
|
if (!this.pricer) {
|
|
27403
27410
|
throw new Error("Pricer is not initialized");
|
|
27404
27411
|
}
|
|
27405
|
-
const CACHE_KEY = `positions_${blockNumber}_${this.config.poolId.shortString()}_${this.config.collateral.symbol}_${this.config.debt.symbol}`;
|
|
27406
|
-
const cacheData = this.getCache(CACHE_KEY);
|
|
27407
|
-
if (cacheData) {
|
|
27408
|
-
return cacheData;
|
|
27409
|
-
}
|
|
27410
27412
|
const { contract, isV2 } = this.getVesuSingletonContract(config, this.config.poolId);
|
|
27411
27413
|
const output = await contract.call(isV2 ? "position" : "position_unsafe", [
|
|
27412
27414
|
...isV2 ? [] : [this.config.poolId.address],
|
|
@@ -27432,7 +27434,6 @@ var VesuAdapter = class _VesuAdapter extends CacheClass {
|
|
|
27432
27434
|
usdValue: debtAmount.multipliedBy(token2Price.price).toNumber(),
|
|
27433
27435
|
remarks: "Debt"
|
|
27434
27436
|
}];
|
|
27435
|
-
this.setCache(CACHE_KEY, value, 6e4);
|
|
27436
27437
|
return value.map((v) => ({ ...v, protocol: Protocols.VESU }));
|
|
27437
27438
|
}
|
|
27438
27439
|
async getCollateralization(config, blockNumber = "latest") {
|
|
@@ -28355,15 +28356,14 @@ var MAX_PRICE_DROP_PERCENTAGE = Number(process.env.MAX_PRICE_DROP_PERCENTAGE ??
|
|
|
28355
28356
|
var MAX_LTV_BTC_USDC = 0.8428;
|
|
28356
28357
|
var MAX_LIQUIDATION_RATIO = 0.86;
|
|
28357
28358
|
var VAULT_ID_EXTENDED = process.env.VAULT_ID_EXTENDED ?? 220774;
|
|
28358
|
-
var WALLET_ADDRESS = process.env.WALLET_ADDRESS ?? "
|
|
28359
|
-
var TESTNET_WALLET_ADDRESS = process.env.TESTNET_WALLET_ADDRESS ?? "0x07b84bb6E87588BdAde0bfe6173A615b3C220F9C3803456aE183C50EA1d15Ba1";
|
|
28360
|
-
var TEST_WALLET_2 = process.env.TEST_WALLET_2 ?? "0x004C1bdC61DAc7947F3C93d0163d660012E2aB0521567f7155fcf502848791A7";
|
|
28359
|
+
var WALLET_ADDRESS = process.env.WALLET_ADDRESS ?? "0x007E24592287427aaE9d291770B17d582E8A45f3aE54228F998793Ec769B7D13";
|
|
28361
28360
|
var STRK_API_TEST_RPC = process.env.STRK_API_TEST_RPC ?? "https://sepolia.starknet.a5a.ch";
|
|
28362
28361
|
var STRK_API_RPC = process.env.STRK_API_RPC ?? "https://mainnet.starknet.a5a.ch";
|
|
28363
28362
|
var MAX_RETRIES = Number(process.env.MAX_RETRIES ?? 3);
|
|
28364
28363
|
var MAX_DELAY = Number(process.env.MAX_DELAY ?? 100);
|
|
28365
28364
|
var EXTEND_MARKET_NAME = "BTC-USD";
|
|
28366
|
-
var LIMIT_BALANCE = Number(process.env.LIMIT_BALANCE ??
|
|
28365
|
+
var LIMIT_BALANCE = Number(process.env.LIMIT_BALANCE ?? 0.05);
|
|
28366
|
+
var LIMIT_BALANCE_VALUE = 10;
|
|
28367
28367
|
var REBALANCER_INTERVAL = Number(process.env.REBALANCER_INTERVAL ?? 18e4);
|
|
28368
28368
|
var WITHDRAWAL_INTERVAL = Number(process.env.WITHDRAWAL_INTERVAL ?? 18e6);
|
|
28369
28369
|
var INVESTING_INTERVAL = Number(process.env.INVESTING_INTERVAL ?? 18e4);
|
|
@@ -28381,8 +28381,6 @@ var PRICE_MAX_SLIPPAGE_EKUBO = Number(process.env.PRICE_MAX_SLIPPAGE_EKUBO ?? 5e
|
|
|
28381
28381
|
var MINIMUM_DEBT_AMOUNT_VESU_FOR_REBALANCING = Number(process.env.MINIMUM_DEBT_AMOUNT_VESU_FOR_REBALANCING ?? 1);
|
|
28382
28382
|
var MINIMUM_EXTENDED_POSITION_SIZE = 1e-4;
|
|
28383
28383
|
var MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP = 1e-5;
|
|
28384
|
-
var MAX_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED = 700;
|
|
28385
|
-
var MIN_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED = -100;
|
|
28386
28384
|
|
|
28387
28385
|
// src/strategies/vesu-extended-strategy/utils/helper.ts
|
|
28388
28386
|
var returnFormattedAmount = (amount, toTokenDecimals) => {
|
|
@@ -28402,8 +28400,7 @@ var calculateAmountDistribution = async (amount, client, marketName, collateralP
|
|
|
28402
28400
|
vesu_leverage: 0
|
|
28403
28401
|
};
|
|
28404
28402
|
}
|
|
28405
|
-
const
|
|
28406
|
-
const extendedExposureUSD = extendedBTCExposure.multipliedBy(collateralPrice);
|
|
28403
|
+
const extendedExposureUSD = extendedPosition.length > 0 ? new Web3Number(extendedPosition[0].value, WBTC_TOKEN_DECIMALS) : new Web3Number(0, WBTC_TOKEN_DECIMALS);
|
|
28407
28404
|
const vesuBTCExposureUSD = collateralUnits.multipliedBy(collateralPrice);
|
|
28408
28405
|
const numerator1 = vesu_leverage * amount + vesuBTCExposureUSD.toNumber();
|
|
28409
28406
|
const numerator2 = extendedExposureUSD.toNumber();
|
|
@@ -28440,7 +28437,6 @@ var calculateAmountDistributionForWithdrawal = async (amountInUsdc, collateralPr
|
|
|
28440
28437
|
return null;
|
|
28441
28438
|
}
|
|
28442
28439
|
const extendedExposureUSD = extendedPosition.length > 0 ? new Web3Number(extendedPosition[0].value, USDC_TOKEN_DECIMALS) : new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
28443
|
-
console.log("THe collateral is", collateralPrice, collateralUnits);
|
|
28444
28440
|
const vesuExposureUSD = collateralUnits.multipliedBy(collateralPrice);
|
|
28445
28441
|
if (vesuExposureUSD.lessThan(0)) {
|
|
28446
28442
|
return {
|
|
@@ -28497,10 +28493,10 @@ var calculateExtendedLevergae = () => {
|
|
|
28497
28493
|
const extended_leverage_max = 1 / (MAINTENANCE_MARGIN + MAX_PRICE_DROP_PERCENTAGE);
|
|
28498
28494
|
return Math.floor(extended_leverage_max);
|
|
28499
28495
|
};
|
|
28500
|
-
var calculateDebtAmount = (collateralAmount, debtAmount, debtPrice, maxLtv =
|
|
28496
|
+
var calculateDebtAmount = (collateralAmount, debtAmount, debtPrice, maxLtv = MAX_LIQUIDATION_RATIO, addedAmount, collateralPrice, isDeposit) => {
|
|
28501
28497
|
try {
|
|
28502
|
-
const
|
|
28503
|
-
const numerator1 = collateralAmount.plus(
|
|
28498
|
+
const addedCollateral = addedAmount.multipliedBy(isDeposit ? 1 : -1);
|
|
28499
|
+
const numerator1 = collateralAmount.plus(addedCollateral).multipliedBy(collateralPrice).multipliedBy(maxLtv);
|
|
28504
28500
|
const numerator2 = debtAmount.multipliedBy(debtPrice).multipliedBy(TARGET_HF);
|
|
28505
28501
|
const denominator = TARGET_HF - maxLtv;
|
|
28506
28502
|
const x_debt_usd = numerator1.minus(numerator2).dividedBy(denominator);
|
|
@@ -28535,19 +28531,34 @@ var calculateAmountDepositOnExtendedWhenIncurringLosses = async (client) => {
|
|
|
28535
28531
|
const extendedHoldings = await client.getHoldings();
|
|
28536
28532
|
const extended_leverage = calculateExtendedLevergae();
|
|
28537
28533
|
const latestPosition = (await client.getPositions()).data.pop();
|
|
28538
|
-
console.log("the latest position is", latestPosition, extendedHoldings);
|
|
28539
28534
|
if (!extendedHoldings || !latestPosition) {
|
|
28540
28535
|
logger.error(`error getting extended position: extendedHoldings=${extendedHoldings}, latestPosition=${latestPosition}`);
|
|
28541
28536
|
return null;
|
|
28542
28537
|
}
|
|
28543
|
-
const positionValueInUSD = latestPosition.value;
|
|
28538
|
+
const positionValueInUSD = new Web3Number(latestPosition.value, USDC_TOKEN_DECIMALS);
|
|
28544
28539
|
const equity = extendedHoldings.data.equity;
|
|
28545
|
-
const deposit =
|
|
28546
|
-
return new Web3Number(
|
|
28540
|
+
const deposit = positionValueInUSD.dividedBy(extended_leverage).minus(equity).toFixed(2);
|
|
28541
|
+
return new Web3Number(deposit, USDC_TOKEN_DECIMALS);
|
|
28547
28542
|
} catch (err) {
|
|
28543
|
+
logger.error(`error calculating amount deposit on extended when incurring losses: ${err}`);
|
|
28548
28544
|
return null;
|
|
28549
28545
|
}
|
|
28550
28546
|
};
|
|
28547
|
+
var calculateWBTCAmountToMaintainLTV = (collateralAmount, debtAmount, debtPrice, maxLtv = MAX_LIQUIDATION_RATIO, collateralPrice, targetHF = TARGET_HF) => {
|
|
28548
|
+
try {
|
|
28549
|
+
const numerator1 = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLtv);
|
|
28550
|
+
const numerator2 = debtAmount.multipliedBy(debtPrice).multipliedBy(targetHF);
|
|
28551
|
+
const denominator = maxLtv;
|
|
28552
|
+
const collateralAmountToMaintainLTV = numerator2.minus(numerator1).dividedBy(denominator);
|
|
28553
|
+
let deltaCollateralAmountUnits = new Web3Number(
|
|
28554
|
+
collateralAmountToMaintainLTV.dividedBy(collateralPrice).toFixed(WBTC_TOKEN_DECIMALS),
|
|
28555
|
+
WBTC_TOKEN_DECIMALS
|
|
28556
|
+
);
|
|
28557
|
+
return { deltaCollateralAmountUnits };
|
|
28558
|
+
} catch (err) {
|
|
28559
|
+
return { deltaCollateralAmountUnits: null };
|
|
28560
|
+
}
|
|
28561
|
+
};
|
|
28551
28562
|
var calculateExposureDelta = (exposure_extended, exposure_vesu) => {
|
|
28552
28563
|
const exposure_delta = new Web3Number(exposure_extended - exposure_vesu, 2);
|
|
28553
28564
|
return exposure_delta.absoluteValue().toNumber();
|
|
@@ -28622,21 +28633,36 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28622
28633
|
vaultAllocator: config.vaultAllocator,
|
|
28623
28634
|
id: ""
|
|
28624
28635
|
});
|
|
28625
|
-
this.
|
|
28636
|
+
this.minimumVesuMovementAmount = config.minimumVesuMovementAmount ?? 5;
|
|
28637
|
+
this.tokenMarketData = new TokenMarketData(
|
|
28638
|
+
this.config.pricer,
|
|
28639
|
+
this.config.networkConfig
|
|
28640
|
+
);
|
|
28626
28641
|
}
|
|
28627
28642
|
async getAPY(supportedPosition) {
|
|
28628
28643
|
const CACHE_KEY = `apy_${this.config.poolId.address}_${supportedPosition.asset.symbol}`;
|
|
28629
28644
|
const cacheData = this.getCache(CACHE_KEY);
|
|
28630
|
-
console.log(
|
|
28645
|
+
console.log(
|
|
28646
|
+
`${_VesuMultiplyAdapter.name}::getAPY cacheData: ${JSON.stringify(
|
|
28647
|
+
cacheData
|
|
28648
|
+
)}`,
|
|
28649
|
+
this.vesuAdapter.config.poolId.shortString(),
|
|
28650
|
+
this.vesuAdapter.config.collateral.symbol,
|
|
28651
|
+
this.vesuAdapter.config.debt.symbol
|
|
28652
|
+
);
|
|
28631
28653
|
if (cacheData) {
|
|
28632
28654
|
return cacheData;
|
|
28633
28655
|
}
|
|
28634
28656
|
try {
|
|
28635
28657
|
const allVesuPools = await VesuAdapter.getVesuPools();
|
|
28636
28658
|
const asset = supportedPosition.asset;
|
|
28637
|
-
const pool = allVesuPools.pools.find(
|
|
28659
|
+
const pool = allVesuPools.pools.find(
|
|
28660
|
+
(p) => this.vesuAdapter.config.poolId.eqString(num9.getHexString(p.id))
|
|
28661
|
+
);
|
|
28638
28662
|
if (!pool) {
|
|
28639
|
-
logger.warn(
|
|
28663
|
+
logger.warn(
|
|
28664
|
+
`VesuMultiplyAdapter: Pool not found for token ${asset.symbol}`
|
|
28665
|
+
);
|
|
28640
28666
|
return {
|
|
28641
28667
|
apy: 0,
|
|
28642
28668
|
type: "base" /* BASE */
|
|
@@ -28646,7 +28672,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28646
28672
|
(a) => a.symbol.toLowerCase() === asset.symbol.toLowerCase()
|
|
28647
28673
|
)?.stats;
|
|
28648
28674
|
if (!assetStats) {
|
|
28649
|
-
logger.warn(
|
|
28675
|
+
logger.warn(
|
|
28676
|
+
`VesuMultiplyAdapter: Asset stats not found for token ${asset.symbol}`
|
|
28677
|
+
);
|
|
28650
28678
|
return {
|
|
28651
28679
|
apy: 0,
|
|
28652
28680
|
type: "base" /* BASE */
|
|
@@ -28657,7 +28685,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28657
28685
|
apy = Number(assetStats.borrowApr?.value || 0) / 1e18;
|
|
28658
28686
|
} else {
|
|
28659
28687
|
const isAssetBTC = asset.symbol.toLowerCase().includes("btc");
|
|
28660
|
-
const baseAPY = Number(
|
|
28688
|
+
const baseAPY = Number(
|
|
28689
|
+
isAssetBTC ? assetStats.btcFiSupplyApr?.value + assetStats.supplyApy?.value : assetStats.supplyApy?.value || 0
|
|
28690
|
+
) / 1e18;
|
|
28661
28691
|
const rewardAPY = Number(assetStats.defiSpringSupplyApr?.value || "0") / 1e18;
|
|
28662
28692
|
const isSupported = this.tokenMarketData.isAPYSupported(asset);
|
|
28663
28693
|
apy = baseAPY + rewardAPY;
|
|
@@ -28673,7 +28703,10 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28673
28703
|
this.setCache(CACHE_KEY, result, 3e5);
|
|
28674
28704
|
return result;
|
|
28675
28705
|
} catch (error) {
|
|
28676
|
-
logger.error(
|
|
28706
|
+
logger.error(
|
|
28707
|
+
`VesuMultiplyAdapter: Error getting APY for ${supportedPosition.asset.symbol}:`,
|
|
28708
|
+
error
|
|
28709
|
+
);
|
|
28677
28710
|
throw error;
|
|
28678
28711
|
}
|
|
28679
28712
|
}
|
|
@@ -28686,12 +28719,16 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28686
28719
|
try {
|
|
28687
28720
|
this.vesuAdapter.networkConfig = this.config.networkConfig;
|
|
28688
28721
|
this.vesuAdapter.pricer = this.config.pricer;
|
|
28689
|
-
const positions = await this.vesuAdapter.getPositions(
|
|
28722
|
+
const positions = await this.vesuAdapter.getPositions(
|
|
28723
|
+
this.config.networkConfig
|
|
28724
|
+
);
|
|
28690
28725
|
let position = positions.find(
|
|
28691
28726
|
(p) => p.token.address.eq(supportedPosition.asset.address)
|
|
28692
28727
|
);
|
|
28693
28728
|
if (!position) {
|
|
28694
|
-
logger.warn(
|
|
28729
|
+
logger.warn(
|
|
28730
|
+
`VesuMultiplyAdapter: Position not found for token ${supportedPosition.asset.symbol}`
|
|
28731
|
+
);
|
|
28695
28732
|
return {
|
|
28696
28733
|
amount: new Web3Number("0", supportedPosition.asset.decimals),
|
|
28697
28734
|
remarks: "Position not found"
|
|
@@ -28704,12 +28741,18 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28704
28741
|
this.setCache(CACHE_KEY, position, 6e4);
|
|
28705
28742
|
return position;
|
|
28706
28743
|
} catch (error) {
|
|
28707
|
-
logger.error(
|
|
28744
|
+
logger.error(
|
|
28745
|
+
`VesuMultiplyAdapter: Error getting position for ${supportedPosition.asset.symbol}:`,
|
|
28746
|
+
error
|
|
28747
|
+
);
|
|
28708
28748
|
throw error;
|
|
28709
28749
|
}
|
|
28710
28750
|
}
|
|
28711
28751
|
async maxBorrowableAPY() {
|
|
28712
|
-
const collateralAPY = await this.getAPY({
|
|
28752
|
+
const collateralAPY = await this.getAPY({
|
|
28753
|
+
asset: this.config.collateral,
|
|
28754
|
+
isDebt: false
|
|
28755
|
+
});
|
|
28713
28756
|
const apy = collateralAPY.apy * 0.8;
|
|
28714
28757
|
return apy;
|
|
28715
28758
|
}
|
|
@@ -28719,9 +28762,15 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28719
28762
|
try {
|
|
28720
28763
|
this.vesuAdapter.networkConfig = this.config.networkConfig;
|
|
28721
28764
|
this.vesuAdapter.pricer = this.config.pricer;
|
|
28722
|
-
const positions = await this.vesuAdapter.getPositions(
|
|
28723
|
-
|
|
28724
|
-
|
|
28765
|
+
const positions = await this.vesuAdapter.getPositions(
|
|
28766
|
+
this.config.networkConfig
|
|
28767
|
+
);
|
|
28768
|
+
const collateralPosition = positions.find(
|
|
28769
|
+
(p) => p.token.address.eq(collateral.address)
|
|
28770
|
+
);
|
|
28771
|
+
const debtPosition = positions.find(
|
|
28772
|
+
(p) => p.token.address.eq(debt.address)
|
|
28773
|
+
);
|
|
28725
28774
|
if (!collateralPosition || !debtPosition) {
|
|
28726
28775
|
throw new Error("Could not find current positions");
|
|
28727
28776
|
}
|
|
@@ -28731,13 +28780,23 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28731
28780
|
debt,
|
|
28732
28781
|
maxBorrowableAPY
|
|
28733
28782
|
);
|
|
28734
|
-
logger.verbose(
|
|
28735
|
-
|
|
28783
|
+
logger.verbose(
|
|
28784
|
+
`VesuMultiplyAdapter: Max borrowable: ${maxBorrowable.toNumber()}`
|
|
28785
|
+
);
|
|
28786
|
+
const debtCap = await this.vesuAdapter.getDebtCap(
|
|
28787
|
+
this.config.networkConfig
|
|
28788
|
+
);
|
|
28736
28789
|
logger.verbose(`VesuMultiplyAdapter: Debt cap: ${debtCap.toNumber()}`);
|
|
28737
28790
|
const actualMaxBorrowable = maxBorrowable.minimum(debtCap);
|
|
28738
|
-
logger.verbose(
|
|
28739
|
-
|
|
28740
|
-
|
|
28791
|
+
logger.verbose(
|
|
28792
|
+
`VesuMultiplyAdapter: Actual max borrowable: ${actualMaxBorrowable.toNumber()}`
|
|
28793
|
+
);
|
|
28794
|
+
const maxLTV = await this.vesuAdapter.getLTVConfig(
|
|
28795
|
+
this.config.networkConfig
|
|
28796
|
+
);
|
|
28797
|
+
const collateralPrice = await this.config.pricer.getPrice(
|
|
28798
|
+
collateral.symbol
|
|
28799
|
+
);
|
|
28741
28800
|
if (collateralPrice.price === 0) {
|
|
28742
28801
|
throw new Error("Collateral price is 0");
|
|
28743
28802
|
}
|
|
@@ -28755,14 +28814,25 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28755
28814
|
);
|
|
28756
28815
|
const maxDepositAmount = amount ? amount.minimum(maxCollateralFromDebt) : maxCollateralFromDebt;
|
|
28757
28816
|
const usdValue = await this.getUSDValue(collateral, maxDepositAmount);
|
|
28758
|
-
logger.verbose(
|
|
28759
|
-
|
|
28760
|
-
|
|
28817
|
+
logger.verbose(
|
|
28818
|
+
`VesuMultiplyAdapter: Max deposit::USD value: ${usdValue}, amount: ${maxDepositAmount.toNumber()}`
|
|
28819
|
+
);
|
|
28820
|
+
const apys = await Promise.all([
|
|
28821
|
+
this.getAPY({ asset: collateral, isDebt: false }),
|
|
28822
|
+
this.getAPY({ asset: debt, isDebt: true })
|
|
28823
|
+
]);
|
|
28824
|
+
logger.verbose(
|
|
28825
|
+
`VesuMultiplyAdapter: Apys: ${apys[0].apy}, ${apys[1].apy}`
|
|
28826
|
+
);
|
|
28761
28827
|
const borrowAmountUSD = actualMaxBorrowable.multipliedBy(debtPrice.price);
|
|
28762
|
-
logger.verbose(
|
|
28828
|
+
logger.verbose(
|
|
28829
|
+
`VesuMultiplyAdapter: Borrow amount: ${actualMaxBorrowable.toNumber()}, borrow amount USD: ${borrowAmountUSD.toNumber()}`
|
|
28830
|
+
);
|
|
28763
28831
|
const netCollateralUSD = usdValue + borrowAmountUSD.toNumber();
|
|
28764
28832
|
const netAPY = (apys[0].apy * netCollateralUSD + apys[1].apy * borrowAmountUSD.toNumber()) / usdValue;
|
|
28765
|
-
logger.verbose(
|
|
28833
|
+
logger.verbose(
|
|
28834
|
+
`VesuMultiplyAdapter: Max deposit amount: ${maxDepositAmount.toNumber()}, netAPY: ${netAPY}`
|
|
28835
|
+
);
|
|
28766
28836
|
return {
|
|
28767
28837
|
tokenInfo: collateral,
|
|
28768
28838
|
amount: maxDepositAmount,
|
|
@@ -28775,7 +28845,10 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28775
28845
|
protocol: this.protocol
|
|
28776
28846
|
};
|
|
28777
28847
|
} catch (error) {
|
|
28778
|
-
logger.error(
|
|
28848
|
+
logger.error(
|
|
28849
|
+
`VesuMultiplyAdapter: Error calculating max deposit:`,
|
|
28850
|
+
error
|
|
28851
|
+
);
|
|
28779
28852
|
throw error;
|
|
28780
28853
|
}
|
|
28781
28854
|
}
|
|
@@ -28785,9 +28858,15 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28785
28858
|
try {
|
|
28786
28859
|
this.vesuAdapter.networkConfig = this.config.networkConfig;
|
|
28787
28860
|
this.vesuAdapter.pricer = this.config.pricer;
|
|
28788
|
-
const positions = await this.vesuAdapter.getPositions(
|
|
28789
|
-
|
|
28790
|
-
|
|
28861
|
+
const positions = await this.vesuAdapter.getPositions(
|
|
28862
|
+
this.config.networkConfig
|
|
28863
|
+
);
|
|
28864
|
+
const collateralPosition = positions.find(
|
|
28865
|
+
(p) => p.token.address.eq(collateral.address)
|
|
28866
|
+
);
|
|
28867
|
+
const debtPosition = positions.find(
|
|
28868
|
+
(p) => p.token.address.eq(this.config.debt.address)
|
|
28869
|
+
);
|
|
28791
28870
|
if (!collateralPosition || !debtPosition) {
|
|
28792
28871
|
throw new Error("Could not find current positions");
|
|
28793
28872
|
}
|
|
@@ -28797,11 +28876,20 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28797
28876
|
const result = maxWithdrawable.greaterThan(0) ? maxWithdrawable : new Web3Number("0", collateral.decimals);
|
|
28798
28877
|
const usdValue = await this.getUSDValue(collateral, result);
|
|
28799
28878
|
const debtUSD = debtPosition.usdValue;
|
|
28800
|
-
logger.verbose(
|
|
28801
|
-
|
|
28802
|
-
|
|
28879
|
+
logger.verbose(
|
|
28880
|
+
`VesuMultiplyAdapter: Debt USD: ${debtUSD}, collateral USD: ${usdValue}`
|
|
28881
|
+
);
|
|
28882
|
+
const apys = await Promise.all([
|
|
28883
|
+
this.getAPY({ asset: collateral, isDebt: false }),
|
|
28884
|
+
this.getAPY({ asset: debt, isDebt: true })
|
|
28885
|
+
]);
|
|
28886
|
+
logger.verbose(
|
|
28887
|
+
`VesuMultiplyAdapter: Apys: ${apys[0].apy}, ${apys[1].apy}`
|
|
28888
|
+
);
|
|
28803
28889
|
const netAPY = usdValue - debtUSD > 0 ? (apys[0].apy * usdValue + apys[1].apy * debtUSD) / (usdValue - debtUSD) : 0;
|
|
28804
|
-
logger.verbose(
|
|
28890
|
+
logger.verbose(
|
|
28891
|
+
`VesuMultiplyAdapter: Max withdraw amount: ${result.toNumber()}, netAPY: ${netAPY}`
|
|
28892
|
+
);
|
|
28805
28893
|
return {
|
|
28806
28894
|
tokenInfo: collateral,
|
|
28807
28895
|
amount: result,
|
|
@@ -28814,14 +28902,19 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28814
28902
|
protocol: this.protocol
|
|
28815
28903
|
};
|
|
28816
28904
|
} catch (error) {
|
|
28817
|
-
logger.error(
|
|
28905
|
+
logger.error(
|
|
28906
|
+
`VesuMultiplyAdapter: Error calculating max withdraw:`,
|
|
28907
|
+
error
|
|
28908
|
+
);
|
|
28818
28909
|
throw error;
|
|
28819
28910
|
}
|
|
28820
28911
|
}
|
|
28821
28912
|
_getDepositLeaf() {
|
|
28822
28913
|
const collateral = this.config.collateral;
|
|
28823
28914
|
const debt = this.config.debt;
|
|
28824
|
-
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
28915
|
+
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
28916
|
+
this.config.poolId
|
|
28917
|
+
);
|
|
28825
28918
|
const vesuMultiply = isV2 ? this.vesuAdapter.VESU_MULTIPLY : this.vesuAdapter.VESU_MULTIPLY_V1;
|
|
28826
28919
|
return [
|
|
28827
28920
|
// Approval step for collateral
|
|
@@ -28885,7 +28978,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28885
28978
|
];
|
|
28886
28979
|
}
|
|
28887
28980
|
_getWithdrawLeaf() {
|
|
28888
|
-
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
28981
|
+
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
28982
|
+
this.config.poolId
|
|
28983
|
+
);
|
|
28889
28984
|
const vesuMultiply = isV2 ? this.vesuAdapter.VESU_MULTIPLY : this.vesuAdapter.VESU_MULTIPLY_V1;
|
|
28890
28985
|
const collateral = this.config.collateral;
|
|
28891
28986
|
const debt = this.config.debt;
|
|
@@ -28942,33 +29037,51 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28942
29037
|
const leafConfigs = this._getDepositLeaf();
|
|
28943
29038
|
const leaves = leafConfigs.map((config) => {
|
|
28944
29039
|
const { target, method, packedArguments, sanitizer, id } = config;
|
|
28945
|
-
const leaf = this.constructSimpleLeafData(
|
|
28946
|
-
|
|
28947
|
-
|
|
28948
|
-
|
|
28949
|
-
|
|
28950
|
-
|
|
29040
|
+
const leaf = this.constructSimpleLeafData(
|
|
29041
|
+
{
|
|
29042
|
+
id,
|
|
29043
|
+
target,
|
|
29044
|
+
method,
|
|
29045
|
+
packedArguments
|
|
29046
|
+
},
|
|
29047
|
+
sanitizer
|
|
29048
|
+
);
|
|
28951
29049
|
return leaf;
|
|
28952
29050
|
});
|
|
28953
|
-
return {
|
|
29051
|
+
return {
|
|
29052
|
+
leaves,
|
|
29053
|
+
callConstructor: this.getDepositCall.bind(
|
|
29054
|
+
this
|
|
29055
|
+
)
|
|
29056
|
+
};
|
|
28954
29057
|
}
|
|
28955
29058
|
getWithdrawAdapter() {
|
|
28956
29059
|
const leafConfigs = this._getWithdrawLeaf();
|
|
28957
29060
|
const leaves = leafConfigs.map((config) => {
|
|
28958
29061
|
const { target, method, packedArguments, sanitizer, id } = config;
|
|
28959
|
-
const leaf = this.constructSimpleLeafData(
|
|
28960
|
-
|
|
28961
|
-
|
|
28962
|
-
|
|
28963
|
-
|
|
28964
|
-
|
|
29062
|
+
const leaf = this.constructSimpleLeafData(
|
|
29063
|
+
{
|
|
29064
|
+
id,
|
|
29065
|
+
target,
|
|
29066
|
+
method,
|
|
29067
|
+
packedArguments
|
|
29068
|
+
},
|
|
29069
|
+
sanitizer
|
|
29070
|
+
);
|
|
28965
29071
|
return leaf;
|
|
28966
29072
|
});
|
|
28967
|
-
return {
|
|
29073
|
+
return {
|
|
29074
|
+
leaves,
|
|
29075
|
+
callConstructor: this.getWithdrawCall.bind(
|
|
29076
|
+
this
|
|
29077
|
+
)
|
|
29078
|
+
};
|
|
28968
29079
|
}
|
|
28969
29080
|
async getDepositCall(params) {
|
|
28970
29081
|
const collateral = this.config.collateral;
|
|
28971
|
-
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
29082
|
+
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
29083
|
+
this.config.poolId
|
|
29084
|
+
);
|
|
28972
29085
|
const vesuMultiply = isV2 ? this.vesuAdapter.VESU_MULTIPLY : this.vesuAdapter.VESU_MULTIPLY_V1;
|
|
28973
29086
|
const uint256MarginAmount = uint25612.bnToUint256(params.amount.toWei());
|
|
28974
29087
|
return [
|
|
@@ -29040,7 +29153,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
29040
29153
|
];
|
|
29041
29154
|
}
|
|
29042
29155
|
async getWithdrawCall(params) {
|
|
29043
|
-
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
29156
|
+
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
29157
|
+
this.config.poolId
|
|
29158
|
+
);
|
|
29044
29159
|
const vesuMultiply = isV2 ? this.vesuAdapter.VESU_MULTIPLY : this.vesuAdapter.VESU_MULTIPLY_V1;
|
|
29045
29160
|
return [
|
|
29046
29161
|
// Switch delegation on
|
|
@@ -29095,7 +29210,11 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
29095
29210
|
];
|
|
29096
29211
|
}
|
|
29097
29212
|
async getMultiplyCallCalldata(params, isDeposit) {
|
|
29098
|
-
logger.verbose(
|
|
29213
|
+
logger.verbose(
|
|
29214
|
+
`${_VesuMultiplyAdapter.name}::getMultiplyCallCalldata params: ${JSON.stringify(
|
|
29215
|
+
params
|
|
29216
|
+
)}, isDeposit: ${isDeposit}, collateral: ${this.config.collateral.symbol}, debt: ${this.config.debt.symbol}`
|
|
29217
|
+
);
|
|
29099
29218
|
const { isV2 } = getVesuSingletonAddress(this.config.poolId);
|
|
29100
29219
|
const vesuMultiply = isV2 ? this.vesuAdapter.VESU_MULTIPLY : this.vesuAdapter.VESU_MULTIPLY_V1;
|
|
29101
29220
|
const multiplyContract = new Contract12({
|
|
@@ -29105,42 +29224,83 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
29105
29224
|
});
|
|
29106
29225
|
let leverSwap = [];
|
|
29107
29226
|
let leverSwapLimitAmount = Web3Number.fromWei(0, this.config.debt.decimals);
|
|
29108
|
-
const existingPositions = await this.vesuAdapter.getPositions(
|
|
29109
|
-
|
|
29227
|
+
const existingPositions = await this.vesuAdapter.getPositions(
|
|
29228
|
+
this.config.networkConfig
|
|
29229
|
+
);
|
|
29230
|
+
const collateralisation = await this.vesuAdapter.getCollateralization(
|
|
29231
|
+
this.config.networkConfig
|
|
29232
|
+
);
|
|
29110
29233
|
const existingCollateralInfo = existingPositions[0];
|
|
29111
29234
|
const existingDebtInfo = existingPositions[1];
|
|
29112
29235
|
const isDexPriceRequired = existingDebtInfo.token.symbol !== "USDC";
|
|
29113
|
-
logger.debug(`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall existingCollateralInfo: ${JSON.stringify(
|
|
29114
|
-
|
|
29236
|
+
logger.debug(`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall existingCollateralInfo: ${JSON.stringify(
|
|
29237
|
+
existingCollateralInfo
|
|
29238
|
+
)},
|
|
29239
|
+
existingDebtInfo: ${JSON.stringify(
|
|
29240
|
+
existingDebtInfo
|
|
29241
|
+
)}, collateralisation: ${JSON.stringify(collateralisation)}`);
|
|
29115
29242
|
const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : (await this.config.pricer.getPrice(this.config.collateral.symbol)).price;
|
|
29116
29243
|
const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : (await this.config.pricer.getPrice(this.config.debt.symbol)).price;
|
|
29117
|
-
logger.debug(
|
|
29118
|
-
|
|
29119
|
-
|
|
29120
|
-
const
|
|
29121
|
-
|
|
29244
|
+
logger.debug(
|
|
29245
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`
|
|
29246
|
+
);
|
|
29247
|
+
const legLTV = await this.vesuAdapter.getLTVConfig(
|
|
29248
|
+
this.config.networkConfig
|
|
29249
|
+
);
|
|
29250
|
+
const ekuboQuoter = new EkuboQuoter(
|
|
29251
|
+
this.config.networkConfig,
|
|
29252
|
+
this.config.pricer
|
|
29253
|
+
);
|
|
29254
|
+
const dexPrice = isDexPriceRequired ? await ekuboQuoter.getDexPrice(
|
|
29255
|
+
this.config.collateral,
|
|
29256
|
+
this.config.debt,
|
|
29257
|
+
this.config.quoteAmountToFetchPrice
|
|
29258
|
+
) : 1;
|
|
29259
|
+
logger.verbose(
|
|
29260
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall dexPrice: ${dexPrice}, ltv: ${legLTV}`
|
|
29261
|
+
);
|
|
29122
29262
|
const addedCollateral = params.amount.multipliedBy(isDeposit ? 1 : -1);
|
|
29123
|
-
logger.verbose(
|
|
29263
|
+
logger.verbose(
|
|
29264
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall addedCollateral: ${addedCollateral}`
|
|
29265
|
+
);
|
|
29124
29266
|
const numeratorPart1 = existingCollateralInfo.amount.plus(addedCollateral).multipliedBy(collateralPrice).multipliedBy(legLTV);
|
|
29125
|
-
logger.verbose(
|
|
29267
|
+
logger.verbose(
|
|
29268
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}`
|
|
29269
|
+
);
|
|
29126
29270
|
const numeratorPart2 = existingDebtInfo.amount.multipliedBy(debtPrice).multipliedBy(this.config.targetHealthFactor);
|
|
29127
|
-
logger.verbose(
|
|
29271
|
+
logger.verbose(
|
|
29272
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall numeratorPart2: ${numeratorPart2}`
|
|
29273
|
+
);
|
|
29128
29274
|
const denominatorPart = this.config.targetHealthFactor - legLTV / dexPrice;
|
|
29129
|
-
logger.verbose(
|
|
29275
|
+
logger.verbose(
|
|
29276
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall denominatorPart: ${denominatorPart}`
|
|
29277
|
+
);
|
|
29130
29278
|
const x_debt_usd = numeratorPart1.minus(numeratorPart2).dividedBy(denominatorPart);
|
|
29131
|
-
logger.verbose(
|
|
29132
|
-
|
|
29133
|
-
|
|
29279
|
+
logger.verbose(
|
|
29280
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall x_debt_usd: ${x_debt_usd}`
|
|
29281
|
+
);
|
|
29282
|
+
logger.debug(
|
|
29283
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}, numeratorPart2: ${numeratorPart2}, denominatorPart: ${denominatorPart}`
|
|
29284
|
+
);
|
|
29285
|
+
let debtAmount = new Web3Number(
|
|
29286
|
+
x_debt_usd.dividedBy(debtPrice).toFixed(this.config.debt.decimals),
|
|
29287
|
+
this.config.debt.decimals
|
|
29288
|
+
);
|
|
29134
29289
|
const marginAmount = addedCollateral;
|
|
29135
29290
|
const collateralToken = this.config.collateral;
|
|
29136
29291
|
const debtToken = this.config.debt;
|
|
29137
|
-
const debtAmountInCollateralUnits = new Web3Number(
|
|
29292
|
+
const debtAmountInCollateralUnits = new Web3Number(
|
|
29293
|
+
debtAmount.multipliedBy(debtPrice).dividedBy(collateralPrice).multipliedBy(10 ** collateralToken.decimals).toFixed(0),
|
|
29294
|
+
collateralToken.decimals
|
|
29295
|
+
);
|
|
29138
29296
|
const isIncrease = debtAmount.greaterThanOrEqualTo(0);
|
|
29139
29297
|
if (isIncrease && debtAmount.lessThan(0)) {
|
|
29140
29298
|
} else if (!isIncrease && debtAmount.greaterThan(0)) {
|
|
29141
29299
|
debtAmount = Web3Number.fromWei(0, this.config.debt.decimals);
|
|
29142
29300
|
}
|
|
29143
|
-
logger.verbose(
|
|
29301
|
+
logger.verbose(
|
|
29302
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall debtAmount: ${debtAmount}, marginAmount: ${marginAmount}`
|
|
29303
|
+
);
|
|
29144
29304
|
if (!debtAmount.isZero()) {
|
|
29145
29305
|
try {
|
|
29146
29306
|
const swapQuote = await ekuboQuoter.getQuote(
|
|
@@ -29150,26 +29310,49 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
29150
29310
|
// negative for exact amount out
|
|
29151
29311
|
);
|
|
29152
29312
|
if (swapQuote.price_impact < 0.01) {
|
|
29153
|
-
leverSwap = ekuboQuoter.getVesuMultiplyQuote(
|
|
29313
|
+
leverSwap = debtAmount.isNegative() ? ekuboQuoter.getVesuMultiplyQuote(
|
|
29314
|
+
swapQuote,
|
|
29315
|
+
collateralToken,
|
|
29316
|
+
debtToken
|
|
29317
|
+
) : ekuboQuoter.getVesuMultiplyQuote(
|
|
29318
|
+
swapQuote,
|
|
29319
|
+
debtToken,
|
|
29320
|
+
collateralToken
|
|
29321
|
+
);
|
|
29154
29322
|
const MAX_SLIPPAGE = 2e-3;
|
|
29155
29323
|
if (debtAmount.greaterThan(0)) {
|
|
29156
29324
|
leverSwapLimitAmount = debtAmount.multipliedBy(1 + MAX_SLIPPAGE);
|
|
29157
29325
|
} else if (debtAmount.lessThan(0)) {
|
|
29158
29326
|
leverSwapLimitAmount = debtAmount.abs().multipliedBy(1 - MAX_SLIPPAGE);
|
|
29159
29327
|
} else {
|
|
29160
|
-
leverSwapLimitAmount = Web3Number.fromWei(
|
|
29328
|
+
leverSwapLimitAmount = Web3Number.fromWei(
|
|
29329
|
+
0,
|
|
29330
|
+
this.config.debt.decimals
|
|
29331
|
+
);
|
|
29161
29332
|
}
|
|
29162
29333
|
await new Promise((resolve) => setTimeout(resolve, 1e4));
|
|
29163
29334
|
} else {
|
|
29164
|
-
throw new Error(
|
|
29335
|
+
throw new Error(
|
|
29336
|
+
`VesuMultiplyAdapter: Price impact too high (${swapQuote.price_impact}), skipping swap`
|
|
29337
|
+
);
|
|
29165
29338
|
}
|
|
29166
29339
|
} catch (error) {
|
|
29167
|
-
throw new Error(
|
|
29340
|
+
throw new Error(
|
|
29341
|
+
`VesuMultiplyAdapter: Failed to get swap quote: ${error}`
|
|
29342
|
+
);
|
|
29168
29343
|
}
|
|
29169
29344
|
}
|
|
29170
|
-
const multiplyParams = await this.getLeverParams(
|
|
29345
|
+
const multiplyParams = await this.getLeverParams(
|
|
29346
|
+
isIncrease,
|
|
29347
|
+
params,
|
|
29348
|
+
leverSwap,
|
|
29349
|
+
leverSwapLimitAmount
|
|
29350
|
+
);
|
|
29171
29351
|
const call = multiplyContract.populate("modify_lever", {
|
|
29172
|
-
modify_lever_params: this.formatMultiplyParams(
|
|
29352
|
+
modify_lever_params: this.formatMultiplyParams(
|
|
29353
|
+
isIncrease,
|
|
29354
|
+
multiplyParams
|
|
29355
|
+
)
|
|
29173
29356
|
});
|
|
29174
29357
|
return call.calldata;
|
|
29175
29358
|
}
|
|
@@ -29183,7 +29366,10 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
29183
29366
|
add_margin: params.amount,
|
|
29184
29367
|
// multiplied by collateral decimals in format
|
|
29185
29368
|
margin_swap: [],
|
|
29186
|
-
margin_swap_limit_amount: Web3Number.fromWei(
|
|
29369
|
+
margin_swap_limit_amount: Web3Number.fromWei(
|
|
29370
|
+
0,
|
|
29371
|
+
this.config.collateral.decimals
|
|
29372
|
+
),
|
|
29187
29373
|
lever_swap: leverSwap,
|
|
29188
29374
|
lever_swap_limit_amount: leverSwapLimitAmount
|
|
29189
29375
|
} : {
|
|
@@ -29197,7 +29383,10 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
29197
29383
|
lever_swap_limit_amount: leverSwapLimitAmount,
|
|
29198
29384
|
lever_swap_weights: [],
|
|
29199
29385
|
withdraw_swap: [],
|
|
29200
|
-
withdraw_swap_limit_amount: Web3Number.fromWei(
|
|
29386
|
+
withdraw_swap_limit_amount: Web3Number.fromWei(
|
|
29387
|
+
0,
|
|
29388
|
+
this.config.collateral.decimals
|
|
29389
|
+
),
|
|
29201
29390
|
withdraw_swap_weights: [],
|
|
29202
29391
|
close_position: false
|
|
29203
29392
|
};
|
|
@@ -29213,12 +29402,16 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
29213
29402
|
});
|
|
29214
29403
|
let leverSwap = [];
|
|
29215
29404
|
let leverSwapLimitAmount = Web3Number.fromWei(0, this.config.debt.decimals);
|
|
29216
|
-
const existingPositions = await this.vesuAdapter.getPositions(
|
|
29405
|
+
const existingPositions = await this.vesuAdapter.getPositions(
|
|
29406
|
+
this.config.networkConfig
|
|
29407
|
+
);
|
|
29217
29408
|
const existingCollateralInfo = existingPositions[0];
|
|
29218
29409
|
const existingDebtInfo = existingPositions[1];
|
|
29219
29410
|
const collateralToken = this.config.collateral;
|
|
29220
29411
|
const debtToken = this.config.debt;
|
|
29221
|
-
const collateralPrice = await this.config.pricer.getPrice(
|
|
29412
|
+
const collateralPrice = await this.config.pricer.getPrice(
|
|
29413
|
+
collateralToken.symbol
|
|
29414
|
+
);
|
|
29222
29415
|
const debtPrice = await this.config.pricer.getPrice(debtToken.symbol);
|
|
29223
29416
|
const { deltadebtAmountUnits: debtAmountToRepay } = calculateDebtReductionAmountForWithdrawal(
|
|
29224
29417
|
existingDebtInfo.amount,
|
|
@@ -29232,8 +29425,14 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
29232
29425
|
if (!debtAmountToRepay) {
|
|
29233
29426
|
throw new Error("error calculating debt amount to repay");
|
|
29234
29427
|
}
|
|
29235
|
-
const ekuboQuoter = new EkuboQuoter(
|
|
29236
|
-
|
|
29428
|
+
const ekuboQuoter = new EkuboQuoter(
|
|
29429
|
+
this.config.networkConfig,
|
|
29430
|
+
this.config.pricer
|
|
29431
|
+
);
|
|
29432
|
+
const debtInDebtUnits = new Web3Number(
|
|
29433
|
+
debtAmountToRepay,
|
|
29434
|
+
debtToken.decimals
|
|
29435
|
+
).dividedBy(debtPrice.price).multipliedBy(10 ** debtToken.decimals);
|
|
29237
29436
|
const swapQuote = await ekuboQuoter.getQuote(
|
|
29238
29437
|
debtToken.address.address,
|
|
29239
29438
|
collateralToken.address.address,
|
|
@@ -29241,12 +29440,23 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
29241
29440
|
);
|
|
29242
29441
|
const MAX_SLIPPAGE = 2e-3;
|
|
29243
29442
|
if (swapQuote.price_impact < 25e-4) {
|
|
29244
|
-
leverSwap = ekuboQuoter.getVesuMultiplyQuote(
|
|
29443
|
+
leverSwap = ekuboQuoter.getVesuMultiplyQuote(
|
|
29444
|
+
swapQuote,
|
|
29445
|
+
collateralToken,
|
|
29446
|
+
debtToken
|
|
29447
|
+
);
|
|
29245
29448
|
} else {
|
|
29246
|
-
logger.error(
|
|
29449
|
+
logger.error(
|
|
29450
|
+
`VesuMultiplyAdapter: Price impact too high (${swapQuote.price_impact}), skipping swap`
|
|
29451
|
+
);
|
|
29247
29452
|
}
|
|
29248
29453
|
leverSwapLimitAmount = new Web3Number(debtAmountToRepay, debtToken.decimals).abs().multipliedBy(1 + MAX_SLIPPAGE);
|
|
29249
|
-
const multiplyParams = await this.getLeverParams(
|
|
29454
|
+
const multiplyParams = await this.getLeverParams(
|
|
29455
|
+
false,
|
|
29456
|
+
params,
|
|
29457
|
+
leverSwap,
|
|
29458
|
+
leverSwapLimitAmount
|
|
29459
|
+
);
|
|
29250
29460
|
const call = multiplyContract.populate("modify_lever", {
|
|
29251
29461
|
modify_lever_params: this.formatMultiplyParams(false, multiplyParams)
|
|
29252
29462
|
});
|
|
@@ -29256,100 +29466,132 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
29256
29466
|
if (isIncrease) {
|
|
29257
29467
|
const _params2 = params;
|
|
29258
29468
|
return {
|
|
29259
|
-
action: new CairoCustomEnum3({
|
|
29260
|
-
|
|
29261
|
-
|
|
29262
|
-
|
|
29263
|
-
|
|
29264
|
-
|
|
29265
|
-
|
|
29469
|
+
action: new CairoCustomEnum3({
|
|
29470
|
+
IncreaseLever: {
|
|
29471
|
+
pool_id: _params2.pool_id.toBigInt(),
|
|
29472
|
+
collateral_asset: _params2.collateral_asset.toBigInt(),
|
|
29473
|
+
debt_asset: _params2.debt_asset.toBigInt(),
|
|
29474
|
+
user: _params2.user.toBigInt(),
|
|
29475
|
+
add_margin: BigInt(_params2.add_margin.toWei()),
|
|
29476
|
+
margin_swap: _params2.margin_swap.map((swap) => ({
|
|
29477
|
+
route: swap.route.map((route) => ({
|
|
29478
|
+
pool_key: {
|
|
29479
|
+
token0: route.pool_key.token0.toBigInt(),
|
|
29480
|
+
token1: route.pool_key.token1.toBigInt(),
|
|
29481
|
+
fee: route.pool_key.fee,
|
|
29482
|
+
tick_spacing: route.pool_key.tick_spacing,
|
|
29483
|
+
extension: BigInt(
|
|
29484
|
+
num9.hexToDecimalString(route.pool_key.extension)
|
|
29485
|
+
)
|
|
29486
|
+
},
|
|
29487
|
+
sqrt_ratio_limit: uint25612.bnToUint256(
|
|
29488
|
+
route.sqrt_ratio_limit.toWei()
|
|
29489
|
+
),
|
|
29490
|
+
skip_ahead: BigInt(100)
|
|
29491
|
+
})),
|
|
29492
|
+
token_amount: {
|
|
29493
|
+
token: swap.token_amount.token.toBigInt(),
|
|
29494
|
+
amount: swap.token_amount.amount.toI129()
|
|
29495
|
+
}
|
|
29496
|
+
})),
|
|
29497
|
+
margin_swap_limit_amount: BigInt(
|
|
29498
|
+
_params2.margin_swap_limit_amount.toWei()
|
|
29499
|
+
),
|
|
29500
|
+
lever_swap: _params2.lever_swap.map((swap) => ({
|
|
29501
|
+
route: swap.route.map((route) => ({
|
|
29502
|
+
pool_key: {
|
|
29503
|
+
token0: route.pool_key.token0.toBigInt(),
|
|
29504
|
+
token1: route.pool_key.token1.toBigInt(),
|
|
29505
|
+
fee: route.pool_key.fee,
|
|
29506
|
+
tick_spacing: route.pool_key.tick_spacing,
|
|
29507
|
+
extension: BigInt(
|
|
29508
|
+
num9.hexToDecimalString(route.pool_key.extension)
|
|
29509
|
+
)
|
|
29510
|
+
},
|
|
29511
|
+
sqrt_ratio_limit: uint25612.bnToUint256(
|
|
29512
|
+
route.sqrt_ratio_limit.toWei()
|
|
29513
|
+
),
|
|
29514
|
+
skip_ahead: BigInt(0)
|
|
29515
|
+
})),
|
|
29516
|
+
token_amount: {
|
|
29517
|
+
token: swap.token_amount.token.toBigInt(),
|
|
29518
|
+
amount: swap.token_amount.amount.toI129()
|
|
29519
|
+
}
|
|
29520
|
+
})),
|
|
29521
|
+
lever_swap_limit_amount: BigInt(
|
|
29522
|
+
_params2.lever_swap_limit_amount.toWei()
|
|
29523
|
+
)
|
|
29524
|
+
}
|
|
29525
|
+
})
|
|
29526
|
+
};
|
|
29527
|
+
}
|
|
29528
|
+
const _params = params;
|
|
29529
|
+
return {
|
|
29530
|
+
action: new CairoCustomEnum3({
|
|
29531
|
+
DecreaseLever: {
|
|
29532
|
+
pool_id: _params.pool_id.toBigInt(),
|
|
29533
|
+
collateral_asset: _params.collateral_asset.toBigInt(),
|
|
29534
|
+
debt_asset: _params.debt_asset.toBigInt(),
|
|
29535
|
+
user: _params.user.toBigInt(),
|
|
29536
|
+
sub_margin: BigInt(_params.sub_margin.toWei()),
|
|
29537
|
+
recipient: _params.recipient.toBigInt(),
|
|
29538
|
+
lever_swap: _params.lever_swap.map((swap) => ({
|
|
29266
29539
|
route: swap.route.map((route) => ({
|
|
29267
29540
|
pool_key: {
|
|
29268
29541
|
token0: route.pool_key.token0.toBigInt(),
|
|
29269
29542
|
token1: route.pool_key.token1.toBigInt(),
|
|
29270
29543
|
fee: route.pool_key.fee,
|
|
29271
29544
|
tick_spacing: route.pool_key.tick_spacing,
|
|
29272
|
-
extension:
|
|
29545
|
+
extension: ContractAddr.from(
|
|
29546
|
+
route.pool_key.extension
|
|
29547
|
+
).toBigInt()
|
|
29273
29548
|
},
|
|
29274
|
-
sqrt_ratio_limit: uint25612.bnToUint256(
|
|
29275
|
-
|
|
29549
|
+
sqrt_ratio_limit: uint25612.bnToUint256(
|
|
29550
|
+
route.sqrt_ratio_limit.toWei()
|
|
29551
|
+
),
|
|
29552
|
+
skip_ahead: BigInt(route.skip_ahead.toWei())
|
|
29276
29553
|
})),
|
|
29277
29554
|
token_amount: {
|
|
29278
29555
|
token: swap.token_amount.token.toBigInt(),
|
|
29279
29556
|
amount: swap.token_amount.amount.toI129()
|
|
29280
29557
|
}
|
|
29281
29558
|
})),
|
|
29282
|
-
|
|
29283
|
-
|
|
29559
|
+
lever_swap_limit_amount: BigInt(
|
|
29560
|
+
_params.lever_swap_limit_amount.toWei()
|
|
29561
|
+
),
|
|
29562
|
+
lever_swap_weights: _params.lever_swap_weights.map(
|
|
29563
|
+
(weight) => BigInt(weight.toWei())
|
|
29564
|
+
),
|
|
29565
|
+
withdraw_swap: _params.withdraw_swap.map((swap) => ({
|
|
29284
29566
|
route: swap.route.map((route) => ({
|
|
29285
29567
|
pool_key: {
|
|
29286
29568
|
token0: route.pool_key.token0.toBigInt(),
|
|
29287
29569
|
token1: route.pool_key.token1.toBigInt(),
|
|
29288
29570
|
fee: route.pool_key.fee,
|
|
29289
29571
|
tick_spacing: route.pool_key.tick_spacing,
|
|
29290
|
-
extension:
|
|
29572
|
+
extension: ContractAddr.from(
|
|
29573
|
+
route.pool_key.extension
|
|
29574
|
+
).toBigInt()
|
|
29291
29575
|
},
|
|
29292
|
-
sqrt_ratio_limit: uint25612.bnToUint256(
|
|
29293
|
-
|
|
29576
|
+
sqrt_ratio_limit: uint25612.bnToUint256(
|
|
29577
|
+
route.sqrt_ratio_limit.toWei()
|
|
29578
|
+
),
|
|
29579
|
+
skip_ahead: BigInt(route.skip_ahead.toWei())
|
|
29294
29580
|
})),
|
|
29295
29581
|
token_amount: {
|
|
29296
29582
|
token: swap.token_amount.token.toBigInt(),
|
|
29297
29583
|
amount: swap.token_amount.amount.toI129()
|
|
29298
29584
|
}
|
|
29299
29585
|
})),
|
|
29300
|
-
|
|
29301
|
-
|
|
29302
|
-
|
|
29303
|
-
|
|
29304
|
-
|
|
29305
|
-
|
|
29306
|
-
|
|
29307
|
-
|
|
29308
|
-
|
|
29309
|
-
debt_asset: _params.debt_asset.toBigInt(),
|
|
29310
|
-
user: _params.user.toBigInt(),
|
|
29311
|
-
sub_margin: BigInt(_params.sub_margin.toWei()),
|
|
29312
|
-
recipient: _params.recipient.toBigInt(),
|
|
29313
|
-
lever_swap: _params.lever_swap.map((swap) => ({
|
|
29314
|
-
route: swap.route.map((route) => ({
|
|
29315
|
-
pool_key: {
|
|
29316
|
-
token0: route.pool_key.token0.toBigInt(),
|
|
29317
|
-
token1: route.pool_key.token1.toBigInt(),
|
|
29318
|
-
fee: route.pool_key.fee,
|
|
29319
|
-
tick_spacing: route.pool_key.tick_spacing,
|
|
29320
|
-
extension: ContractAddr.from(route.pool_key.extension).toBigInt()
|
|
29321
|
-
},
|
|
29322
|
-
sqrt_ratio_limit: uint25612.bnToUint256(route.sqrt_ratio_limit.toWei()),
|
|
29323
|
-
skip_ahead: BigInt(route.skip_ahead.toWei())
|
|
29324
|
-
})),
|
|
29325
|
-
token_amount: {
|
|
29326
|
-
token: swap.token_amount.token.toBigInt(),
|
|
29327
|
-
amount: swap.token_amount.amount.toI129()
|
|
29328
|
-
}
|
|
29329
|
-
})),
|
|
29330
|
-
lever_swap_limit_amount: BigInt(_params.lever_swap_limit_amount.toWei()),
|
|
29331
|
-
lever_swap_weights: _params.lever_swap_weights.map((weight) => BigInt(weight.toWei())),
|
|
29332
|
-
withdraw_swap: _params.withdraw_swap.map((swap) => ({
|
|
29333
|
-
route: swap.route.map((route) => ({
|
|
29334
|
-
pool_key: {
|
|
29335
|
-
token0: route.pool_key.token0.toBigInt(),
|
|
29336
|
-
token1: route.pool_key.token1.toBigInt(),
|
|
29337
|
-
fee: route.pool_key.fee,
|
|
29338
|
-
tick_spacing: route.pool_key.tick_spacing,
|
|
29339
|
-
extension: ContractAddr.from(route.pool_key.extension).toBigInt()
|
|
29340
|
-
},
|
|
29341
|
-
sqrt_ratio_limit: uint25612.bnToUint256(route.sqrt_ratio_limit.toWei()),
|
|
29342
|
-
skip_ahead: BigInt(route.skip_ahead.toWei())
|
|
29343
|
-
})),
|
|
29344
|
-
token_amount: {
|
|
29345
|
-
token: swap.token_amount.token.toBigInt(),
|
|
29346
|
-
amount: swap.token_amount.amount.toI129()
|
|
29347
|
-
}
|
|
29348
|
-
})),
|
|
29349
|
-
withdraw_swap_limit_amount: BigInt(_params.withdraw_swap_limit_amount.toWei()),
|
|
29350
|
-
withdraw_swap_weights: _params.withdraw_swap_weights.map((weight) => BigInt(weight.toWei())),
|
|
29351
|
-
close_position: _params.close_position
|
|
29352
|
-
} })
|
|
29586
|
+
withdraw_swap_limit_amount: BigInt(
|
|
29587
|
+
_params.withdraw_swap_limit_amount.toWei()
|
|
29588
|
+
),
|
|
29589
|
+
withdraw_swap_weights: _params.withdraw_swap_weights.map(
|
|
29590
|
+
(weight) => BigInt(weight.toWei())
|
|
29591
|
+
),
|
|
29592
|
+
close_position: _params.close_position
|
|
29593
|
+
}
|
|
29594
|
+
})
|
|
29353
29595
|
};
|
|
29354
29596
|
}
|
|
29355
29597
|
async getHealthFactor() {
|
|
@@ -29358,11 +29600,15 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
29358
29600
|
}
|
|
29359
29601
|
async getNetAPY() {
|
|
29360
29602
|
const positions = await this.getPositions();
|
|
29361
|
-
logger.verbose(
|
|
29603
|
+
logger.verbose(
|
|
29604
|
+
`${this.name}::getNetAPY: positions: ${JSON.stringify(positions)}`
|
|
29605
|
+
);
|
|
29362
29606
|
const allZero = positions.every((p) => p.usdValue === 0);
|
|
29363
29607
|
if (allZero) {
|
|
29364
29608
|
const collateralUSD = 1e3;
|
|
29365
|
-
const maxLTV = await this.vesuAdapter.getLTVConfig(
|
|
29609
|
+
const maxLTV = await this.vesuAdapter.getLTVConfig(
|
|
29610
|
+
this.config.networkConfig
|
|
29611
|
+
);
|
|
29366
29612
|
const targetHF = this.config.targetHealthFactor;
|
|
29367
29613
|
const maxDebt = HealthFactorMath.getMaxDebtAmountOnLooping(
|
|
29368
29614
|
new Web3Number(collateralUSD, this.config.collateral.decimals),
|
|
@@ -29393,18 +29639,20 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29393
29639
|
super(config, _ExtendedAdapter.name, Protocols.EXTENDED);
|
|
29394
29640
|
this.config = config;
|
|
29395
29641
|
const client = new wrapper_default({
|
|
29396
|
-
baseUrl: this.config.
|
|
29397
|
-
apiKey:
|
|
29642
|
+
baseUrl: this.config.extendedBackendWriteUrl,
|
|
29643
|
+
apiKey: "",
|
|
29398
29644
|
timeout: this.config.extendedTimeout,
|
|
29399
29645
|
retries: this.config.extendedRetries
|
|
29400
29646
|
});
|
|
29647
|
+
this.minimumExtendedMovementAmount = this.config.minimumExtendedMovementAmount ?? 5;
|
|
29401
29648
|
this.client = client;
|
|
29649
|
+
this.retryDelayForOrderStatus = this.config.retryDelayForOrderStatus ?? 3e3;
|
|
29402
29650
|
}
|
|
29403
29651
|
//abstract means the method has no implementation in this class; instead, child classes must implement it.
|
|
29404
29652
|
async getAPY(supportedPosition) {
|
|
29405
29653
|
const side = supportedPosition.isDebt ? "LONG" : "SHORT";
|
|
29406
|
-
const fundingRates = await this.
|
|
29407
|
-
if (fundingRates.
|
|
29654
|
+
const fundingRates = await this.getFundingRates(side);
|
|
29655
|
+
if (!fundingRates.success) {
|
|
29408
29656
|
logger.error("error getting funding rates", fundingRates);
|
|
29409
29657
|
return { apy: 0, type: "base" /* BASE */ };
|
|
29410
29658
|
}
|
|
@@ -29412,10 +29660,26 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29412
29660
|
const apy = Number(fundingRate.f) * 365 * 24;
|
|
29413
29661
|
return { apy, type: "base" /* BASE */ };
|
|
29414
29662
|
}
|
|
29415
|
-
async
|
|
29416
|
-
|
|
29417
|
-
|
|
29663
|
+
async getFundingRates(side, startTime, endTime) {
|
|
29664
|
+
try {
|
|
29665
|
+
const response = await axios9.get(`${this.config.extendedBackendReadUrl}/fundingRates/${this.config.extendedMarketName}/${side}`, {
|
|
29666
|
+
params: {
|
|
29667
|
+
startTime: startTime ? startTime.toString() : void 0,
|
|
29668
|
+
endTime: endTime ? endTime.toString() : void 0
|
|
29669
|
+
}
|
|
29670
|
+
});
|
|
29671
|
+
if (!response.data.success) {
|
|
29672
|
+
logger.error("error getting funding rates", response.data);
|
|
29673
|
+
return { success: false, data: [] };
|
|
29674
|
+
}
|
|
29675
|
+
logger.info("success getting funding rates", response.data.data);
|
|
29676
|
+
return { success: true, data: response.data.data };
|
|
29677
|
+
} catch (err) {
|
|
29678
|
+
logger.error("error getting funding rates", err);
|
|
29679
|
+
return { success: false, data: [] };
|
|
29418
29680
|
}
|
|
29681
|
+
}
|
|
29682
|
+
async getPosition(supportedPosition) {
|
|
29419
29683
|
const holdings = await this.getExtendedDepositAmount();
|
|
29420
29684
|
if (!holdings) {
|
|
29421
29685
|
throw new Error("No position found");
|
|
@@ -29423,7 +29687,7 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29423
29687
|
const amount = holdings.equity;
|
|
29424
29688
|
return Promise.resolve({
|
|
29425
29689
|
amount: new Web3Number(amount, 0),
|
|
29426
|
-
remarks:
|
|
29690
|
+
remarks: `Extended Equity`
|
|
29427
29691
|
});
|
|
29428
29692
|
}
|
|
29429
29693
|
async maxDeposit(amount) {
|
|
@@ -29447,14 +29711,14 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29447
29711
|
});
|
|
29448
29712
|
}
|
|
29449
29713
|
_getDepositLeaf() {
|
|
29450
|
-
const usdceToken = Global.getDefaultTokens().find(
|
|
29714
|
+
const usdceToken = Global.getDefaultTokens().find(
|
|
29715
|
+
(token) => token.symbol === "USDCe"
|
|
29716
|
+
);
|
|
29451
29717
|
return [
|
|
29452
29718
|
{
|
|
29453
29719
|
target: this.config.supportedPositions[0].asset.address,
|
|
29454
29720
|
method: "approve",
|
|
29455
|
-
packedArguments: [
|
|
29456
|
-
AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt()
|
|
29457
|
-
],
|
|
29721
|
+
packedArguments: [AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt()],
|
|
29458
29722
|
id: `extended_approve_${this.config.supportedPositions[0].asset.symbol}`,
|
|
29459
29723
|
sanitizer: AVNU_LEGACY_SANITIZER
|
|
29460
29724
|
},
|
|
@@ -29485,25 +29749,33 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29485
29749
|
const leafConfigs = this._getSwapFromLegacyLeaf();
|
|
29486
29750
|
const leaves = leafConfigs.map((config) => {
|
|
29487
29751
|
const { target, method, packedArguments, sanitizer, id } = config;
|
|
29488
|
-
const leaf = this.constructSimpleLeafData(
|
|
29489
|
-
|
|
29490
|
-
|
|
29491
|
-
|
|
29492
|
-
|
|
29493
|
-
|
|
29752
|
+
const leaf = this.constructSimpleLeafData(
|
|
29753
|
+
{
|
|
29754
|
+
id,
|
|
29755
|
+
target,
|
|
29756
|
+
method,
|
|
29757
|
+
packedArguments
|
|
29758
|
+
},
|
|
29759
|
+
sanitizer
|
|
29760
|
+
);
|
|
29494
29761
|
return leaf;
|
|
29495
29762
|
});
|
|
29496
|
-
return {
|
|
29763
|
+
return {
|
|
29764
|
+
leaves,
|
|
29765
|
+
callConstructor: this.getSwapFromLegacyCall.bind(
|
|
29766
|
+
this
|
|
29767
|
+
)
|
|
29768
|
+
};
|
|
29497
29769
|
}
|
|
29498
29770
|
_getSwapFromLegacyLeaf() {
|
|
29499
|
-
const usdceToken = Global.getDefaultTokens().find(
|
|
29771
|
+
const usdceToken = Global.getDefaultTokens().find(
|
|
29772
|
+
(token) => token.symbol === "USDCe"
|
|
29773
|
+
);
|
|
29500
29774
|
return [
|
|
29501
29775
|
{
|
|
29502
29776
|
target: usdceToken.address,
|
|
29503
29777
|
method: "approve",
|
|
29504
|
-
packedArguments: [
|
|
29505
|
-
AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt()
|
|
29506
|
-
],
|
|
29778
|
+
packedArguments: [AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt()],
|
|
29507
29779
|
id: `extendedswaplegacyapprove_${usdceToken.symbol}`,
|
|
29508
29780
|
sanitizer: AVNU_LEGACY_SANITIZER
|
|
29509
29781
|
},
|
|
@@ -29522,11 +29794,13 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29522
29794
|
async getDepositCall(params) {
|
|
29523
29795
|
try {
|
|
29524
29796
|
const usdcToken = this.config.supportedPositions[0].asset;
|
|
29525
|
-
const usdceToken = Global.getDefaultTokens().find(
|
|
29526
|
-
|
|
29527
|
-
|
|
29797
|
+
const usdceToken = Global.getDefaultTokens().find(
|
|
29798
|
+
(token) => token.symbol === "USDCe"
|
|
29799
|
+
);
|
|
29800
|
+
const salt = Math.floor(Math.random() * 10 ** usdcToken.decimals);
|
|
29801
|
+
const amount = uint25613.bnToUint256(
|
|
29802
|
+
params.amount.multipliedBy(10).toWei()
|
|
29528
29803
|
);
|
|
29529
|
-
const amount = uint25613.bnToUint256(params.amount.multipliedBy(10).toWei());
|
|
29530
29804
|
const quotes = await this.config.avnuAdapter.getQuotesAvnu(
|
|
29531
29805
|
usdcToken.address.toString(),
|
|
29532
29806
|
usdceToken.address.toString(),
|
|
@@ -29539,7 +29813,9 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29539
29813
|
logger.error("error getting quotes from avnu");
|
|
29540
29814
|
return [];
|
|
29541
29815
|
}
|
|
29542
|
-
const getCalldata = await this.config.avnuAdapter.getSwapCallData(
|
|
29816
|
+
const getCalldata = await this.config.avnuAdapter.getSwapCallData(
|
|
29817
|
+
quotes
|
|
29818
|
+
);
|
|
29543
29819
|
const swapCallData = getCalldata[0];
|
|
29544
29820
|
return [
|
|
29545
29821
|
{
|
|
@@ -29615,8 +29891,12 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29615
29891
|
async getSwapFromLegacyCall(params) {
|
|
29616
29892
|
try {
|
|
29617
29893
|
const usdcToken = this.config.supportedPositions[0].asset;
|
|
29618
|
-
const usdceToken = Global.getDefaultTokens().find(
|
|
29619
|
-
|
|
29894
|
+
const usdceToken = Global.getDefaultTokens().find(
|
|
29895
|
+
(token) => token.symbol === "USDCe"
|
|
29896
|
+
);
|
|
29897
|
+
const amount = uint25613.bnToUint256(
|
|
29898
|
+
params.amount.multipliedBy(10).toWei()
|
|
29899
|
+
);
|
|
29620
29900
|
const quotes = await this.config.avnuAdapter.getQuotesAvnu(
|
|
29621
29901
|
usdceToken.address.toString(),
|
|
29622
29902
|
usdcToken.address.toString(),
|
|
@@ -29629,7 +29909,9 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29629
29909
|
logger.error("error getting quotes from avnu");
|
|
29630
29910
|
return [];
|
|
29631
29911
|
}
|
|
29632
|
-
const getCalldata = await this.config.avnuAdapter.getSwapCallData(
|
|
29912
|
+
const getCalldata = await this.config.avnuAdapter.getSwapCallData(
|
|
29913
|
+
quotes
|
|
29914
|
+
);
|
|
29633
29915
|
const swapCallData = getCalldata[0];
|
|
29634
29916
|
return [
|
|
29635
29917
|
{
|
|
@@ -29675,38 +29957,131 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29675
29957
|
async withdrawFromExtended(amount) {
|
|
29676
29958
|
try {
|
|
29677
29959
|
if (!this.client) {
|
|
29678
|
-
|
|
29960
|
+
logger.error("Client not initialized");
|
|
29961
|
+
return {
|
|
29962
|
+
status: false,
|
|
29963
|
+
receivedTxnHash: false
|
|
29964
|
+
};
|
|
29965
|
+
}
|
|
29966
|
+
if (amount.lessThanOrEqualTo(0)) {
|
|
29967
|
+
logger.error(
|
|
29968
|
+
`Invalid withdrawal amount: ${amount.toNumber()}. Amount must be positive.`
|
|
29969
|
+
);
|
|
29970
|
+
return {
|
|
29971
|
+
status: false,
|
|
29972
|
+
receivedTxnHash: false
|
|
29973
|
+
};
|
|
29974
|
+
}
|
|
29975
|
+
if (amount.lessThanOrEqualTo(this.minimumExtendedMovementAmount)) {
|
|
29976
|
+
logger.warn(
|
|
29977
|
+
`Withdrawal amount ${amount.toNumber()} is below minimum Extended movement amount ${this.minimumExtendedMovementAmount}. Skipping withdrawal.`
|
|
29978
|
+
);
|
|
29979
|
+
return {
|
|
29980
|
+
status: false,
|
|
29981
|
+
receivedTxnHash: false
|
|
29982
|
+
};
|
|
29983
|
+
}
|
|
29984
|
+
const holdings = await this.getExtendedDepositAmount();
|
|
29985
|
+
if (!holdings) {
|
|
29986
|
+
logger.error(
|
|
29987
|
+
"Cannot get holdings - unable to validate withdrawal amount"
|
|
29988
|
+
);
|
|
29989
|
+
return {
|
|
29990
|
+
status: false,
|
|
29991
|
+
receivedTxnHash: false
|
|
29992
|
+
};
|
|
29993
|
+
}
|
|
29994
|
+
const availableForWithdrawal = parseFloat(
|
|
29995
|
+
holdings.availableForWithdrawal
|
|
29996
|
+
);
|
|
29997
|
+
if (!Number.isFinite(availableForWithdrawal) || availableForWithdrawal < 0) {
|
|
29998
|
+
logger.error(
|
|
29999
|
+
`Invalid availableForWithdrawal: ${holdings.availableForWithdrawal}. Expected a finite, non-negative number.`
|
|
30000
|
+
);
|
|
30001
|
+
return {
|
|
30002
|
+
status: false,
|
|
30003
|
+
receivedTxnHash: false
|
|
30004
|
+
};
|
|
30005
|
+
}
|
|
30006
|
+
const withdrawalAmount = amount.toNumber();
|
|
30007
|
+
if (withdrawalAmount > availableForWithdrawal) {
|
|
30008
|
+
logger.error(
|
|
30009
|
+
`Withdrawal amount ${withdrawalAmount} exceeds available balance ${availableForWithdrawal}`
|
|
30010
|
+
);
|
|
30011
|
+
return {
|
|
30012
|
+
status: false,
|
|
30013
|
+
receivedTxnHash: false
|
|
30014
|
+
};
|
|
29679
30015
|
}
|
|
29680
|
-
|
|
30016
|
+
logger.info(
|
|
30017
|
+
`Withdrawing ${withdrawalAmount} from Extended. Available balance: ${availableForWithdrawal}`
|
|
30018
|
+
);
|
|
30019
|
+
const withdrawalRequest = await this.client.withdrawUSDC(
|
|
30020
|
+
amount.toFixed(2)
|
|
30021
|
+
);
|
|
29681
30022
|
if (withdrawalRequest.status === "OK") {
|
|
29682
|
-
const withdrawalStatus = await this.getDepositOrWithdrawalStatus(
|
|
29683
|
-
|
|
30023
|
+
const withdrawalStatus = await this.getDepositOrWithdrawalStatus(
|
|
30024
|
+
withdrawalRequest.data,
|
|
30025
|
+
"WITHDRAWAL" /* WITHDRAWAL */
|
|
30026
|
+
);
|
|
30027
|
+
return {
|
|
30028
|
+
status: true,
|
|
30029
|
+
receivedTxnHash: withdrawalStatus
|
|
30030
|
+
};
|
|
29684
30031
|
}
|
|
29685
|
-
|
|
30032
|
+
logger.error(
|
|
30033
|
+
`Withdrawal request failed with status: ${withdrawalRequest.status}`
|
|
30034
|
+
);
|
|
30035
|
+
return {
|
|
30036
|
+
status: false,
|
|
30037
|
+
receivedTxnHash: false
|
|
30038
|
+
};
|
|
29686
30039
|
} catch (error) {
|
|
29687
30040
|
logger.error(`Error creating Withdraw Call: ${error}`);
|
|
29688
|
-
return
|
|
30041
|
+
return {
|
|
30042
|
+
status: false,
|
|
30043
|
+
receivedTxnHash: false
|
|
30044
|
+
};
|
|
29689
30045
|
}
|
|
29690
30046
|
}
|
|
29691
30047
|
async getHealthFactor() {
|
|
29692
30048
|
return Promise.resolve(1);
|
|
29693
30049
|
}
|
|
29694
30050
|
async getExtendedDepositAmount() {
|
|
29695
|
-
|
|
29696
|
-
|
|
29697
|
-
|
|
29698
|
-
|
|
29699
|
-
|
|
29700
|
-
|
|
29701
|
-
|
|
29702
|
-
|
|
29703
|
-
|
|
29704
|
-
|
|
29705
|
-
|
|
29706
|
-
|
|
30051
|
+
try {
|
|
30052
|
+
const result = await axios9.get(`${this.config.extendedBackendReadUrl}/holdings`);
|
|
30053
|
+
if (!result.data) {
|
|
30054
|
+
logger.error("error getting holdings - API returned null/undefined");
|
|
30055
|
+
return void 0;
|
|
30056
|
+
}
|
|
30057
|
+
if (!result.data.success) {
|
|
30058
|
+
logger.error(
|
|
30059
|
+
`error getting holdings - API returned status: ${result.status}`
|
|
30060
|
+
);
|
|
30061
|
+
return void 0;
|
|
30062
|
+
}
|
|
30063
|
+
const holdings = result.data.data;
|
|
30064
|
+
if (!holdings) {
|
|
30065
|
+
logger.warn(
|
|
30066
|
+
"holdings data is null/undefined - treating as zero balance"
|
|
30067
|
+
);
|
|
30068
|
+
return {
|
|
30069
|
+
collateral_name: "",
|
|
30070
|
+
balance: "0",
|
|
30071
|
+
equity: "0",
|
|
30072
|
+
availableForTrade: "0",
|
|
30073
|
+
availableForWithdrawal: "0",
|
|
30074
|
+
unrealisedPnl: "0",
|
|
30075
|
+
initialMargin: "0",
|
|
30076
|
+
marginRatio: "0",
|
|
30077
|
+
updatedTime: Date.now()
|
|
30078
|
+
};
|
|
30079
|
+
}
|
|
30080
|
+
return holdings;
|
|
30081
|
+
} catch (error) {
|
|
30082
|
+
logger.error(`error getting holdings - exception: ${error}`);
|
|
29707
30083
|
return void 0;
|
|
29708
30084
|
}
|
|
29709
|
-
return holdings;
|
|
29710
30085
|
}
|
|
29711
30086
|
async setLeverage(leverage, marketName) {
|
|
29712
30087
|
if (this.client === null) {
|
|
@@ -29723,46 +30098,52 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29723
30098
|
return false;
|
|
29724
30099
|
}
|
|
29725
30100
|
async getAllOpenPositions() {
|
|
29726
|
-
|
|
29727
|
-
|
|
29728
|
-
|
|
29729
|
-
|
|
29730
|
-
|
|
29731
|
-
|
|
29732
|
-
|
|
29733
|
-
|
|
29734
|
-
if (response.data.length === 0) {
|
|
29735
|
-
return [];
|
|
29736
|
-
} else {
|
|
29737
|
-
return response.data;
|
|
30101
|
+
try {
|
|
30102
|
+
const response = await axios9.get(`${this.config.extendedBackendReadUrl}/positions`);
|
|
30103
|
+
if (response.data.success) {
|
|
30104
|
+
if (response.data.data.length === 0) {
|
|
30105
|
+
return [];
|
|
30106
|
+
} else {
|
|
30107
|
+
return response.data.data;
|
|
30108
|
+
}
|
|
29738
30109
|
}
|
|
30110
|
+
return null;
|
|
30111
|
+
} catch (err) {
|
|
30112
|
+
logger.error("error getting all open positions", err);
|
|
30113
|
+
return null;
|
|
29739
30114
|
}
|
|
29740
|
-
return null;
|
|
29741
30115
|
}
|
|
29742
30116
|
async getOrderHistory(marketName) {
|
|
29743
|
-
|
|
29744
|
-
|
|
30117
|
+
try {
|
|
30118
|
+
const result = await axios9.get(`${this.config.extendedBackendReadUrl}/marketOrders/${marketName}`);
|
|
30119
|
+
if (!result.data.success) {
|
|
30120
|
+
return null;
|
|
30121
|
+
}
|
|
30122
|
+
return result.data.data;
|
|
30123
|
+
} catch (err) {
|
|
30124
|
+
logger.error("error getting order history", err);
|
|
29745
30125
|
return null;
|
|
29746
30126
|
}
|
|
29747
|
-
const result = await this.client.getOrderHistory(marketName);
|
|
29748
|
-
return result.data;
|
|
29749
30127
|
}
|
|
29750
30128
|
async getOrderStatus(orderId, marketName) {
|
|
29751
|
-
|
|
29752
|
-
|
|
29753
|
-
|
|
29754
|
-
|
|
29755
|
-
|
|
29756
|
-
|
|
29757
|
-
|
|
30129
|
+
try {
|
|
30130
|
+
if (this.client === null) {
|
|
30131
|
+
logger.error("error initializing client");
|
|
30132
|
+
return null;
|
|
30133
|
+
}
|
|
30134
|
+
const orderhistory = await this.getOrderHistory(marketName);
|
|
30135
|
+
if (!orderhistory || orderhistory.length === 0) {
|
|
30136
|
+
return null;
|
|
30137
|
+
}
|
|
30138
|
+
const order = orderhistory.slice(0, 20).find((order2) => order2.id.toString() === orderId);
|
|
30139
|
+
if (order) {
|
|
30140
|
+
return order;
|
|
30141
|
+
}
|
|
29758
30142
|
return null;
|
|
29759
|
-
}
|
|
29760
|
-
|
|
29761
|
-
if (!order) {
|
|
29762
|
-
logger.error(`error getting order: ${order}`);
|
|
30143
|
+
} catch (error) {
|
|
30144
|
+
logger.error(`error getting order status: ${error}`);
|
|
29763
30145
|
return null;
|
|
29764
30146
|
}
|
|
29765
|
-
return order;
|
|
29766
30147
|
}
|
|
29767
30148
|
async fetchOrderBookBTCUSDC() {
|
|
29768
30149
|
try {
|
|
@@ -29813,14 +30194,40 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29813
30194
|
logger.error("error depositing or setting leverage");
|
|
29814
30195
|
return null;
|
|
29815
30196
|
}
|
|
29816
|
-
const
|
|
29817
|
-
if (
|
|
30197
|
+
const { ask, bid } = await this.fetchOrderBookBTCUSDC();
|
|
30198
|
+
if (!ask || !bid || ask.lessThanOrEqualTo(0) || bid.lessThanOrEqualTo(0)) {
|
|
30199
|
+
logger.error(
|
|
30200
|
+
`Invalid orderbook prices: ask=${ask?.toNumber()}, bid=${bid?.toNumber()}`
|
|
30201
|
+
);
|
|
29818
30202
|
return null;
|
|
29819
30203
|
}
|
|
29820
|
-
const { ask, bid } = await this.fetchOrderBookBTCUSDC();
|
|
29821
30204
|
const spread = ask.minus(bid);
|
|
29822
|
-
|
|
29823
|
-
|
|
30205
|
+
const midPrice = ask.plus(bid).div(2);
|
|
30206
|
+
const MAX_PRICE_DEVIATION_MULTIPLIER = 0.5;
|
|
30207
|
+
const priceAdjustmentMultiplier = Math.min(
|
|
30208
|
+
0.2 * attempt,
|
|
30209
|
+
MAX_PRICE_DEVIATION_MULTIPLIER
|
|
30210
|
+
);
|
|
30211
|
+
const priceAdjustment = spread.times(priceAdjustmentMultiplier);
|
|
30212
|
+
let price = midPrice;
|
|
30213
|
+
if (side === "SELL" /* SELL */) {
|
|
30214
|
+
price = midPrice.minus(priceAdjustment);
|
|
30215
|
+
} else {
|
|
30216
|
+
price = midPrice.plus(priceAdjustment);
|
|
30217
|
+
}
|
|
30218
|
+
const maxDeviation = midPrice.times(0.5);
|
|
30219
|
+
if (price.minus(midPrice).abs().greaterThan(maxDeviation)) {
|
|
30220
|
+
logger.error(
|
|
30221
|
+
`Price deviation too large on attempt ${attempt}: price=${price.toNumber()}, midPrice=${midPrice.toNumber()}, deviation=${price.minus(midPrice).abs().toNumber()}`
|
|
30222
|
+
);
|
|
30223
|
+
if (attempt >= maxAttempts) {
|
|
30224
|
+
return null;
|
|
30225
|
+
}
|
|
30226
|
+
price = side === "SELL" /* SELL */ ? midPrice.minus(maxDeviation) : midPrice.plus(maxDeviation);
|
|
30227
|
+
}
|
|
30228
|
+
logger.info(
|
|
30229
|
+
`createOrder attempt ${attempt}/${maxAttempts}: side=${side}, midPrice=${midPrice.toNumber()}, adjustedPrice=${price.toNumber()}, adjustment=${priceAdjustmentMultiplier * 100}%`
|
|
30230
|
+
);
|
|
29824
30231
|
const amount_in_token = (btcAmount * parseInt(leverage)).toFixed(
|
|
29825
30232
|
this.config.extendedPrecision
|
|
29826
30233
|
);
|
|
@@ -29831,14 +30238,57 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29831
30238
|
price.toFixed(0),
|
|
29832
30239
|
side
|
|
29833
30240
|
);
|
|
29834
|
-
if (!result) {
|
|
30241
|
+
if (!result || !result.position_id) {
|
|
30242
|
+
logger.error("Failed to create order - no position_id returned");
|
|
29835
30243
|
return null;
|
|
29836
30244
|
}
|
|
29837
|
-
|
|
29838
|
-
|
|
29839
|
-
|
|
30245
|
+
const positionId = result.position_id;
|
|
30246
|
+
logger.info(
|
|
30247
|
+
`Order created with position_id: ${positionId}. Waiting for API to update...`
|
|
30248
|
+
);
|
|
30249
|
+
let openOrder = await this.getOrderStatus(
|
|
30250
|
+
positionId,
|
|
30251
|
+
this.config.extendedMarketName
|
|
30252
|
+
);
|
|
30253
|
+
const maxStatusRetries = 3;
|
|
30254
|
+
const statusRetryDelay = 5e3;
|
|
30255
|
+
if (!openOrder) {
|
|
30256
|
+
logger.warn(
|
|
30257
|
+
`Order ${positionId} not found in API yet. Retrying status fetch (max ${maxStatusRetries} times)...`
|
|
30258
|
+
);
|
|
30259
|
+
for (let statusRetry = 1; statusRetry <= maxStatusRetries; statusRetry++) {
|
|
30260
|
+
await new Promise((resolve) => setTimeout(resolve, statusRetryDelay));
|
|
30261
|
+
openOrder = await this.getOrderStatus(
|
|
30262
|
+
positionId,
|
|
30263
|
+
this.config.extendedMarketName
|
|
30264
|
+
);
|
|
30265
|
+
if (openOrder) {
|
|
30266
|
+
logger.info(
|
|
30267
|
+
`Order ${positionId} found after ${statusRetry} status retry(ies)`
|
|
30268
|
+
);
|
|
30269
|
+
break;
|
|
30270
|
+
}
|
|
30271
|
+
logger.warn(
|
|
30272
|
+
`Order ${positionId} still not found after ${statusRetry}/${maxStatusRetries} status retries`
|
|
30273
|
+
);
|
|
30274
|
+
}
|
|
30275
|
+
}
|
|
30276
|
+
if (openOrder && openOrder.status === "FILLED" /* FILLED */) {
|
|
30277
|
+
logger.info(
|
|
30278
|
+
`Order ${positionId} successfully filled with quantity ${openOrder.qty}`
|
|
30279
|
+
);
|
|
30280
|
+
return {
|
|
30281
|
+
position_id: positionId,
|
|
30282
|
+
btc_exposure: openOrder.qty
|
|
30283
|
+
};
|
|
30284
|
+
} else if (openOrder && openOrder.status !== "FILLED" /* FILLED */) {
|
|
30285
|
+
logger.warn(
|
|
30286
|
+
`Order ${positionId} found but status is ${openOrder.status}, not FILLED. Retrying order creation...`
|
|
30287
|
+
);
|
|
29840
30288
|
if (attempt >= maxAttempts) {
|
|
29841
|
-
logger.error(
|
|
30289
|
+
logger.error(
|
|
30290
|
+
`Max retries reached \u2014 order ${positionId} status is ${openOrder.status}, not FILLED`
|
|
30291
|
+
);
|
|
29842
30292
|
return null;
|
|
29843
30293
|
} else {
|
|
29844
30294
|
const backoff = 2e3 * attempt;
|
|
@@ -29852,13 +30302,18 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29852
30302
|
);
|
|
29853
30303
|
}
|
|
29854
30304
|
} else {
|
|
30305
|
+
logger.warn(
|
|
30306
|
+
`Order ${positionId} not found in API after ${maxStatusRetries} status retries (API update delayed ~30s). We got position_id from creation, so order exists. Returning position_id - status will be checked in next loop iteration.`
|
|
30307
|
+
);
|
|
29855
30308
|
return {
|
|
29856
|
-
position_id:
|
|
29857
|
-
btc_exposure:
|
|
30309
|
+
position_id: positionId,
|
|
30310
|
+
btc_exposure: amount_in_token
|
|
29858
30311
|
};
|
|
29859
30312
|
}
|
|
29860
30313
|
} catch (err) {
|
|
29861
|
-
logger.error(
|
|
30314
|
+
logger.error(
|
|
30315
|
+
`createShortOrder failed on attempt ${attempt}: ${err.message}`
|
|
30316
|
+
);
|
|
29862
30317
|
if (attempt < maxAttempts) {
|
|
29863
30318
|
const backoff = 1200 * attempt;
|
|
29864
30319
|
logger.info(`Retrying after ${backoff}ms...`);
|
|
@@ -29897,28 +30352,101 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29897
30352
|
}
|
|
29898
30353
|
}
|
|
29899
30354
|
async getDepositOrWithdrawalStatus(orderId, operationsType) {
|
|
29900
|
-
|
|
29901
|
-
|
|
29902
|
-
|
|
29903
|
-
|
|
29904
|
-
|
|
29905
|
-
|
|
29906
|
-
|
|
29907
|
-
|
|
29908
|
-
|
|
30355
|
+
const maxAttempts = 15;
|
|
30356
|
+
const retryDelayMs = 3e4;
|
|
30357
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
30358
|
+
try {
|
|
30359
|
+
let transferHistory = await this.client.getAssetOperations({
|
|
30360
|
+
operationsType: [operationsType],
|
|
30361
|
+
operationsStatus: ["COMPLETED" /* COMPLETED */]
|
|
30362
|
+
});
|
|
30363
|
+
if (operationsType === "DEPOSIT" /* DEPOSIT */) {
|
|
30364
|
+
const myTransferStatus = transferHistory.data.find(
|
|
30365
|
+
(operation) => operation.transactionHash?.toLowerCase() === orderId.toString().toLowerCase()
|
|
30366
|
+
);
|
|
30367
|
+
if (!myTransferStatus) {
|
|
30368
|
+
if (attempt < maxAttempts) {
|
|
30369
|
+
logger.info(
|
|
30370
|
+
`Deposit operation not found for transactionHash ${orderId}, retrying (attempt ${attempt}/${maxAttempts})...`
|
|
30371
|
+
);
|
|
30372
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
30373
|
+
continue;
|
|
30374
|
+
}
|
|
30375
|
+
logger.warn(
|
|
30376
|
+
`Deposit operation not found for transactionHash ${orderId} after ${maxAttempts} attempts`
|
|
30377
|
+
);
|
|
30378
|
+
return false;
|
|
30379
|
+
}
|
|
30380
|
+
if (myTransferStatus.status === "COMPLETED" /* COMPLETED */) {
|
|
30381
|
+
logger.info(
|
|
30382
|
+
`Deposit operation ${orderId} completed successfully`
|
|
30383
|
+
);
|
|
30384
|
+
return true;
|
|
30385
|
+
} else {
|
|
30386
|
+
if (attempt < maxAttempts) {
|
|
30387
|
+
logger.info(
|
|
30388
|
+
`Deposit operation ${orderId} found but status is ${myTransferStatus.status}, not COMPLETED. Retrying (attempt ${attempt}/${maxAttempts})...`
|
|
30389
|
+
);
|
|
30390
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
30391
|
+
continue;
|
|
30392
|
+
}
|
|
30393
|
+
logger.warn(
|
|
30394
|
+
`Deposit operation ${orderId} status is ${myTransferStatus.status} after ${maxAttempts} attempts, expected COMPLETED`
|
|
30395
|
+
);
|
|
30396
|
+
return false;
|
|
30397
|
+
}
|
|
30398
|
+
} else {
|
|
30399
|
+
const myTransferStatus = transferHistory.data.find(
|
|
30400
|
+
(operation) => operation.id === orderId.toString()
|
|
30401
|
+
);
|
|
30402
|
+
if (!myTransferStatus) {
|
|
30403
|
+
if (attempt < maxAttempts) {
|
|
30404
|
+
logger.info(
|
|
30405
|
+
`Withdrawal status not found for orderId ${orderId} in completed operations, retrying (attempt ${attempt}/${maxAttempts})...`
|
|
30406
|
+
);
|
|
30407
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
30408
|
+
continue;
|
|
30409
|
+
}
|
|
30410
|
+
logger.warn(
|
|
30411
|
+
`Withdrawal operation not found for orderId ${orderId} after ${maxAttempts} attempts`
|
|
30412
|
+
);
|
|
30413
|
+
return false;
|
|
30414
|
+
}
|
|
30415
|
+
if (myTransferStatus.status === "COMPLETED" /* COMPLETED */) {
|
|
30416
|
+
logger.info(
|
|
30417
|
+
`Withdrawal operation ${orderId} completed successfully`
|
|
30418
|
+
);
|
|
30419
|
+
return true;
|
|
30420
|
+
} else {
|
|
30421
|
+
if (attempt < maxAttempts) {
|
|
30422
|
+
logger.info(
|
|
30423
|
+
`Withdrawal operation ${orderId} found but status is ${myTransferStatus.status}, not COMPLETED. Retrying (attempt ${attempt}/${maxAttempts})...`
|
|
30424
|
+
);
|
|
30425
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
30426
|
+
continue;
|
|
30427
|
+
}
|
|
30428
|
+
logger.warn(
|
|
30429
|
+
`Withdrawal operation ${orderId} status is ${myTransferStatus.status} after ${maxAttempts} attempts, expected COMPLETED`
|
|
30430
|
+
);
|
|
30431
|
+
return false;
|
|
30432
|
+
}
|
|
29909
30433
|
}
|
|
29910
|
-
|
|
29911
|
-
|
|
29912
|
-
|
|
29913
|
-
|
|
29914
|
-
|
|
30434
|
+
} catch (err) {
|
|
30435
|
+
logger.error(
|
|
30436
|
+
`error getting deposit or withdrawal status (attempt ${attempt}/${maxAttempts}): ${err}`
|
|
30437
|
+
);
|
|
30438
|
+
if (attempt < maxAttempts) {
|
|
30439
|
+
logger.info(`Retrying after ${retryDelayMs}ms...`);
|
|
30440
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
30441
|
+
continue;
|
|
29915
30442
|
}
|
|
29916
|
-
|
|
30443
|
+
logger.error(
|
|
30444
|
+
`Max retry attempts reached for getDepositOrWithdrawalStatus`
|
|
30445
|
+
);
|
|
30446
|
+
return false;
|
|
29917
30447
|
}
|
|
29918
|
-
} catch (err) {
|
|
29919
|
-
logger.error(`error getting deposit or withdrawal status: ${err}`);
|
|
29920
|
-
return false;
|
|
29921
30448
|
}
|
|
30449
|
+
return false;
|
|
29922
30450
|
}
|
|
29923
30451
|
};
|
|
29924
30452
|
|
|
@@ -29998,12 +30526,351 @@ var UnusedBalanceAdapter = class _UnusedBalanceAdapter extends BaseAdapter {
|
|
|
29998
30526
|
}
|
|
29999
30527
|
};
|
|
30000
30528
|
|
|
30529
|
+
// src/strategies/universal-adapters/avnu-adapter.ts
|
|
30530
|
+
import { hash as hash7, uint256 as uint25614 } from "starknet";
|
|
30531
|
+
import axios10 from "axios";
|
|
30532
|
+
var AvnuAdapter = class _AvnuAdapter extends BaseAdapter {
|
|
30533
|
+
constructor(config) {
|
|
30534
|
+
super(config, _AvnuAdapter.name, Protocols.AVNU);
|
|
30535
|
+
this.config = config;
|
|
30536
|
+
this.avnuWrapper = new AvnuWrapper();
|
|
30537
|
+
}
|
|
30538
|
+
//abstract means the method has no implementation in this class; instead, child classes must implement it.
|
|
30539
|
+
async getAPY(supportedPosition) {
|
|
30540
|
+
return Promise.resolve({ apy: 0, type: "base" /* BASE */ });
|
|
30541
|
+
}
|
|
30542
|
+
async getPosition(supportedPosition) {
|
|
30543
|
+
return Promise.resolve({ amount: new Web3Number(0, 0), remarks: "Avnu Positions" });
|
|
30544
|
+
}
|
|
30545
|
+
async maxDeposit(amount) {
|
|
30546
|
+
return Promise.resolve({
|
|
30547
|
+
tokenInfo: this.config.baseToken,
|
|
30548
|
+
amount: new Web3Number(0, 0),
|
|
30549
|
+
usdValue: 0,
|
|
30550
|
+
apy: { apy: 0, type: "base" /* BASE */ },
|
|
30551
|
+
protocol: Protocols.AVNU,
|
|
30552
|
+
remarks: ""
|
|
30553
|
+
});
|
|
30554
|
+
}
|
|
30555
|
+
async maxWithdraw() {
|
|
30556
|
+
return Promise.resolve({
|
|
30557
|
+
tokenInfo: this.config.baseToken,
|
|
30558
|
+
amount: new Web3Number(0, 0),
|
|
30559
|
+
usdValue: 0,
|
|
30560
|
+
apy: { apy: 0, type: "base" /* BASE */ },
|
|
30561
|
+
protocol: Protocols.AVNU,
|
|
30562
|
+
remarks: ""
|
|
30563
|
+
});
|
|
30564
|
+
}
|
|
30565
|
+
_getDepositLeaf() {
|
|
30566
|
+
const vaultAllocator = ContractAddr.from(
|
|
30567
|
+
this.config.vaultAllocator.address
|
|
30568
|
+
);
|
|
30569
|
+
return [
|
|
30570
|
+
{
|
|
30571
|
+
target: this.config.supportedPositions[0].asset.address,
|
|
30572
|
+
method: "approve",
|
|
30573
|
+
packedArguments: [
|
|
30574
|
+
AVNU_EXCHANGE.toBigInt()
|
|
30575
|
+
],
|
|
30576
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
30577
|
+
id: `approve_${this.config.supportedPositions[0].asset.symbol}`
|
|
30578
|
+
},
|
|
30579
|
+
{
|
|
30580
|
+
target: AVNU_EXCHANGE,
|
|
30581
|
+
method: "multi_route_swap",
|
|
30582
|
+
packedArguments: [
|
|
30583
|
+
this.config.supportedPositions[0].asset.address.toBigInt(),
|
|
30584
|
+
//usdc
|
|
30585
|
+
this.config.supportedPositions[1].asset.address.toBigInt(),
|
|
30586
|
+
//wbtc
|
|
30587
|
+
vaultAllocator.toBigInt()
|
|
30588
|
+
],
|
|
30589
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
30590
|
+
id: `asutb_${this.config.supportedPositions[0].asset.symbol}_${this.config.supportedPositions[1].asset.symbol}`
|
|
30591
|
+
}
|
|
30592
|
+
];
|
|
30593
|
+
}
|
|
30594
|
+
_getWithdrawLeaf() {
|
|
30595
|
+
const vaultAllocator = ContractAddr.from(
|
|
30596
|
+
this.config.vaultAllocator.address
|
|
30597
|
+
);
|
|
30598
|
+
const toToken = this.config.supportedPositions[0].asset;
|
|
30599
|
+
const fromToken = this.config.supportedPositions[1].asset;
|
|
30600
|
+
return [
|
|
30601
|
+
{
|
|
30602
|
+
target: fromToken.address,
|
|
30603
|
+
method: "approve",
|
|
30604
|
+
packedArguments: [
|
|
30605
|
+
AVNU_EXCHANGE.toBigInt()
|
|
30606
|
+
],
|
|
30607
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
30608
|
+
id: `approve_${fromToken.symbol}`
|
|
30609
|
+
},
|
|
30610
|
+
{
|
|
30611
|
+
target: AVNU_EXCHANGE,
|
|
30612
|
+
method: "multi_route_swap",
|
|
30613
|
+
packedArguments: [
|
|
30614
|
+
fromToken.address.toBigInt(),
|
|
30615
|
+
//wbtc
|
|
30616
|
+
toToken.address.toBigInt(),
|
|
30617
|
+
//usdc
|
|
30618
|
+
vaultAllocator.toBigInt()
|
|
30619
|
+
],
|
|
30620
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
30621
|
+
id: `asbtu_${fromToken.symbol}_${fromToken.symbol}`
|
|
30622
|
+
}
|
|
30623
|
+
];
|
|
30624
|
+
}
|
|
30625
|
+
_getLegacySwapLeaf() {
|
|
30626
|
+
return [];
|
|
30627
|
+
}
|
|
30628
|
+
async getDepositCall(params) {
|
|
30629
|
+
try {
|
|
30630
|
+
const fromToken = this.config.supportedPositions[0].asset;
|
|
30631
|
+
const toToken = this.config.supportedPositions[1].asset;
|
|
30632
|
+
const vaultAllocator = ContractAddr.from(
|
|
30633
|
+
this.config.vaultAllocator.address
|
|
30634
|
+
);
|
|
30635
|
+
const quote = await this.getQuotesAvnu(
|
|
30636
|
+
fromToken.address.toString(),
|
|
30637
|
+
toToken.address.toString(),
|
|
30638
|
+
params.amount.toNumber(),
|
|
30639
|
+
vaultAllocator.address.toString(),
|
|
30640
|
+
toToken.decimals,
|
|
30641
|
+
true
|
|
30642
|
+
);
|
|
30643
|
+
if (!quote) {
|
|
30644
|
+
logger.error("error getting quote from avnu");
|
|
30645
|
+
return [];
|
|
30646
|
+
}
|
|
30647
|
+
const getCalldata = await this.avnuWrapper.getSwapCallData(
|
|
30648
|
+
quote,
|
|
30649
|
+
vaultAllocator.address
|
|
30650
|
+
);
|
|
30651
|
+
const swapCallData = getCalldata[0];
|
|
30652
|
+
const amount = uint25614.bnToUint256(quote.sellAmountInUsd * 10 ** 7);
|
|
30653
|
+
return [
|
|
30654
|
+
{
|
|
30655
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
30656
|
+
call: {
|
|
30657
|
+
contractAddress: fromToken.address,
|
|
30658
|
+
selector: hash7.getSelectorFromName("approve"),
|
|
30659
|
+
calldata: [
|
|
30660
|
+
AVNU_EXCHANGE.toBigInt(),
|
|
30661
|
+
toBigInt(amount.low.toString()),
|
|
30662
|
+
// amount low
|
|
30663
|
+
toBigInt(amount.high.toString())
|
|
30664
|
+
// amount high
|
|
30665
|
+
]
|
|
30666
|
+
}
|
|
30667
|
+
},
|
|
30668
|
+
{
|
|
30669
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
30670
|
+
call: {
|
|
30671
|
+
contractAddress: AVNU_EXCHANGE,
|
|
30672
|
+
selector: hash7.getSelectorFromName("multi_route_swap"),
|
|
30673
|
+
calldata: swapCallData
|
|
30674
|
+
}
|
|
30675
|
+
}
|
|
30676
|
+
];
|
|
30677
|
+
} catch (error) {
|
|
30678
|
+
logger.error(`Error getting Avnu quote: ${error}`);
|
|
30679
|
+
return [];
|
|
30680
|
+
}
|
|
30681
|
+
}
|
|
30682
|
+
//Swap wbtc to usdc
|
|
30683
|
+
async getWithdrawCall(params) {
|
|
30684
|
+
try {
|
|
30685
|
+
const toToken = this.config.supportedPositions[0].asset;
|
|
30686
|
+
const fromToken = this.config.supportedPositions[1].asset;
|
|
30687
|
+
const vaultAllocator = ContractAddr.from(
|
|
30688
|
+
this.config.vaultAllocator.address
|
|
30689
|
+
);
|
|
30690
|
+
const quote = await this.getQuotesAvnu(
|
|
30691
|
+
fromToken.address.toString(),
|
|
30692
|
+
toToken.address.toString(),
|
|
30693
|
+
params.amount.toNumber(),
|
|
30694
|
+
vaultAllocator.address.toString(),
|
|
30695
|
+
fromToken.decimals,
|
|
30696
|
+
false
|
|
30697
|
+
);
|
|
30698
|
+
if (!quote) {
|
|
30699
|
+
logger.error("No quotes available for this swap, error in quotes avnu");
|
|
30700
|
+
return [];
|
|
30701
|
+
}
|
|
30702
|
+
const getCalldata = await this.avnuWrapper.getSwapCallData(
|
|
30703
|
+
quote,
|
|
30704
|
+
vaultAllocator.address
|
|
30705
|
+
);
|
|
30706
|
+
const swapCallData = getCalldata[0];
|
|
30707
|
+
const amount = uint25614.bnToUint256(params.amount.toWei());
|
|
30708
|
+
return [
|
|
30709
|
+
{
|
|
30710
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
30711
|
+
call: {
|
|
30712
|
+
contractAddress: fromToken.address,
|
|
30713
|
+
selector: hash7.getSelectorFromName("approve"),
|
|
30714
|
+
calldata: [
|
|
30715
|
+
AVNU_EXCHANGE.toBigInt(),
|
|
30716
|
+
toBigInt(amount.low.toString()),
|
|
30717
|
+
// amount low
|
|
30718
|
+
toBigInt(amount.high.toString())
|
|
30719
|
+
// amount high
|
|
30720
|
+
]
|
|
30721
|
+
}
|
|
30722
|
+
},
|
|
30723
|
+
{
|
|
30724
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
30725
|
+
call: {
|
|
30726
|
+
contractAddress: AVNU_EXCHANGE,
|
|
30727
|
+
selector: hash7.getSelectorFromName("multi_route_swap"),
|
|
30728
|
+
calldata: swapCallData
|
|
30729
|
+
}
|
|
30730
|
+
}
|
|
30731
|
+
];
|
|
30732
|
+
} catch (error) {
|
|
30733
|
+
logger.error(`Error getting Avnu quote: ${error}`);
|
|
30734
|
+
return [];
|
|
30735
|
+
}
|
|
30736
|
+
}
|
|
30737
|
+
async getSwapCallData(quote) {
|
|
30738
|
+
return await this.avnuWrapper.getSwapCallData(quote, this.config.vaultAllocator.address);
|
|
30739
|
+
}
|
|
30740
|
+
async getHealthFactor() {
|
|
30741
|
+
return Promise.resolve(1);
|
|
30742
|
+
}
|
|
30743
|
+
async fetchQuoteWithRetry(params, retries = 5) {
|
|
30744
|
+
for (let attempt = 0; attempt < retries; attempt++) {
|
|
30745
|
+
try {
|
|
30746
|
+
const response = await axios10.get(this.config.baseUrl, { params });
|
|
30747
|
+
if (response.data && response.data.length > 0) {
|
|
30748
|
+
return response;
|
|
30749
|
+
}
|
|
30750
|
+
throw new Error("Empty response data");
|
|
30751
|
+
} catch (err) {
|
|
30752
|
+
logger.error(`Error fetching quote with retry: ${err}`);
|
|
30753
|
+
if (attempt === retries - 1) {
|
|
30754
|
+
throw err;
|
|
30755
|
+
}
|
|
30756
|
+
await new Promise((resolve) => setTimeout(resolve, MAX_DELAY));
|
|
30757
|
+
}
|
|
30758
|
+
}
|
|
30759
|
+
throw new Error("Failed to fetch quote after retries");
|
|
30760
|
+
}
|
|
30761
|
+
async getQuotesAvnu(from_token_address, to_token_address, amount, takerAddress, toTokenDecimals, usdcToBtc, maxIterations = 5, tolerance = 5e3) {
|
|
30762
|
+
try {
|
|
30763
|
+
const fromToken = this.config.supportedPositions[0].asset;
|
|
30764
|
+
const toToken = this.config.supportedPositions[1].asset;
|
|
30765
|
+
if (!usdcToBtc) {
|
|
30766
|
+
const sellAmount2 = returnFormattedAmount(amount, toTokenDecimals);
|
|
30767
|
+
const params2 = {
|
|
30768
|
+
sellTokenAddress: from_token_address,
|
|
30769
|
+
buyTokenAddress: to_token_address,
|
|
30770
|
+
takerAddress,
|
|
30771
|
+
sellAmount: sellAmount2
|
|
30772
|
+
};
|
|
30773
|
+
const finalQuote2 = await this.fetchQuoteWithRetry(params2);
|
|
30774
|
+
if (!finalQuote2.data.length) {
|
|
30775
|
+
logger.error("No quotes available for this swap, error in quotes avnu");
|
|
30776
|
+
return null;
|
|
30777
|
+
}
|
|
30778
|
+
const dataObject2 = finalQuote2.data[0];
|
|
30779
|
+
return dataObject2;
|
|
30780
|
+
}
|
|
30781
|
+
const btcPrice = await this.getPriceOfToken(toToken.address.toString());
|
|
30782
|
+
if (!btcPrice) {
|
|
30783
|
+
logger.error(`error getting btc price: ${btcPrice}`);
|
|
30784
|
+
return null;
|
|
30785
|
+
}
|
|
30786
|
+
const estimatedUsdcAmount = Math.floor(amount * btcPrice);
|
|
30787
|
+
logger.info(`${_AvnuAdapter.name}::getQuotesAvnu estimatedUsdcAmount: ${estimatedUsdcAmount}`);
|
|
30788
|
+
const targetBtcBig = BigInt(returnFormattedAmount(amount, toTokenDecimals));
|
|
30789
|
+
logger.info(`${_AvnuAdapter.name}::getQuotesAvnu targetBtcBig: ${targetBtcBig}`);
|
|
30790
|
+
let low = BigInt(
|
|
30791
|
+
Math.floor(
|
|
30792
|
+
estimatedUsdcAmount * 10 ** fromToken.decimals * 0.9
|
|
30793
|
+
)
|
|
30794
|
+
);
|
|
30795
|
+
let high = BigInt(
|
|
30796
|
+
Math.floor(
|
|
30797
|
+
estimatedUsdcAmount * 10 ** fromToken.decimals * 1.1
|
|
30798
|
+
)
|
|
30799
|
+
);
|
|
30800
|
+
let mid = 0n;
|
|
30801
|
+
for (let i = 0; i < maxIterations; i++) {
|
|
30802
|
+
mid = (low + high) / 2n;
|
|
30803
|
+
const sellAmount2 = returnFormattedAmount(Number(mid), 0);
|
|
30804
|
+
const quote = await this.fetchQuoteWithRetry({
|
|
30805
|
+
sellTokenAddress: from_token_address,
|
|
30806
|
+
buyTokenAddress: to_token_address,
|
|
30807
|
+
takerAddress,
|
|
30808
|
+
sellAmount: sellAmount2
|
|
30809
|
+
});
|
|
30810
|
+
const gotBtc = BigInt(quote.data[0].buyAmount);
|
|
30811
|
+
if (gotBtc === targetBtcBig) return quote.data[0];
|
|
30812
|
+
if (gotBtc > targetBtcBig) {
|
|
30813
|
+
high = mid;
|
|
30814
|
+
} else {
|
|
30815
|
+
low = mid;
|
|
30816
|
+
}
|
|
30817
|
+
if (gotBtc >= targetBtcBig && gotBtc <= targetBtcBig + BigInt(tolerance)) {
|
|
30818
|
+
return quote.data[0];
|
|
30819
|
+
}
|
|
30820
|
+
}
|
|
30821
|
+
let sellAmount = returnFormattedAmount(
|
|
30822
|
+
Number(mid),
|
|
30823
|
+
0
|
|
30824
|
+
);
|
|
30825
|
+
const params = {
|
|
30826
|
+
sellTokenAddress: from_token_address,
|
|
30827
|
+
buyTokenAddress: to_token_address,
|
|
30828
|
+
takerAddress,
|
|
30829
|
+
sellAmount
|
|
30830
|
+
};
|
|
30831
|
+
const finalQuote = await this.fetchQuoteWithRetry(params);
|
|
30832
|
+
if (!finalQuote.data.length) {
|
|
30833
|
+
logger.error("No quotes available for this swap, error in quotes avnu");
|
|
30834
|
+
return null;
|
|
30835
|
+
}
|
|
30836
|
+
const dataObject = finalQuote.data[0];
|
|
30837
|
+
const wbtcAmountOut = parseInt(dataObject.buyAmount.toString(), 16);
|
|
30838
|
+
logger.info(`${_AvnuAdapter.name}::getQuotesAvnu finalAmountOfWbtcOut : ${wbtcAmountOut} ${dataObject.buyAmount} ${dataObject.sellAmount.toString()} ${dataObject.sellAmount.toString()}`);
|
|
30839
|
+
return dataObject;
|
|
30840
|
+
} catch (err) {
|
|
30841
|
+
logger.error(`No quotes available for this swap: ${err}`);
|
|
30842
|
+
return null;
|
|
30843
|
+
}
|
|
30844
|
+
}
|
|
30845
|
+
async getPriceOfToken(tokenAddress, retries = MAX_RETRIES) {
|
|
30846
|
+
try {
|
|
30847
|
+
const url = `https://starknet.impulse.avnu.fi/v1/tokens/${tokenAddress}/prices/line`;
|
|
30848
|
+
const response = await axios10.get(url);
|
|
30849
|
+
const length = response.data.length;
|
|
30850
|
+
return response.data[length - 1].value;
|
|
30851
|
+
} catch (err) {
|
|
30852
|
+
if (retries > 0) {
|
|
30853
|
+
await new Promise((resolve) => setTimeout(resolve, MAX_DELAY));
|
|
30854
|
+
return this.getPriceOfToken(tokenAddress, retries - 1);
|
|
30855
|
+
} else {
|
|
30856
|
+
logger.error(`Failed to fetch price for ${tokenAddress} after ${MAX_RETRIES} attempts`);
|
|
30857
|
+
return null;
|
|
30858
|
+
}
|
|
30859
|
+
}
|
|
30860
|
+
}
|
|
30861
|
+
};
|
|
30862
|
+
|
|
30001
30863
|
// src/strategies/universal-strategy.tsx
|
|
30002
30864
|
var AUMTypes = /* @__PURE__ */ ((AUMTypes2) => {
|
|
30003
30865
|
AUMTypes2["FINALISED"] = "finalised";
|
|
30004
30866
|
AUMTypes2["DEFISPRING"] = "defispring";
|
|
30005
30867
|
return AUMTypes2;
|
|
30006
30868
|
})(AUMTypes || {});
|
|
30869
|
+
var PositionTypeAvnuExtended = /* @__PURE__ */ ((PositionTypeAvnuExtended2) => {
|
|
30870
|
+
PositionTypeAvnuExtended2["OPEN"] = "open";
|
|
30871
|
+
PositionTypeAvnuExtended2["CLOSE"] = "close";
|
|
30872
|
+
return PositionTypeAvnuExtended2;
|
|
30873
|
+
})(PositionTypeAvnuExtended || {});
|
|
30007
30874
|
var UNIVERSAL_MANAGE_IDS = /* @__PURE__ */ ((UNIVERSAL_MANAGE_IDS2) => {
|
|
30008
30875
|
UNIVERSAL_MANAGE_IDS2["FLASH_LOAN"] = "flash_loan_init";
|
|
30009
30876
|
UNIVERSAL_MANAGE_IDS2["VESU_LEG1"] = "vesu_leg1";
|
|
@@ -33184,7 +34051,8 @@ function getLooperSettings(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
|
33184
34051
|
minHealthFactor: vaultSettings.minHealthFactor,
|
|
33185
34052
|
quoteAmountToFetchPrice: vaultSettings.quoteAmountToFetchPrice,
|
|
33186
34053
|
...baseAdapterConfig,
|
|
33187
|
-
supportedPositions: [{ asset: lstToken, isDebt: false }, { asset: Global.getDefaultTokens().find((token) => token.symbol === position), isDebt: true }]
|
|
34054
|
+
supportedPositions: [{ asset: lstToken, isDebt: false }, { asset: Global.getDefaultTokens().find((token) => token.symbol === position), isDebt: true }],
|
|
34055
|
+
minimumVesuMovementAmount: 0
|
|
33188
34056
|
}));
|
|
33189
34057
|
const unusedBalanceAdapter = new UnusedBalanceAdapter({
|
|
33190
34058
|
...baseAdapterConfig
|
|
@@ -33413,335 +34281,15 @@ var HyperLSTStrategies = [
|
|
|
33413
34281
|
getStrategySettings("mRe7YIELD", "mRe7YIELD", hypermRe7YIELD, false, false)
|
|
33414
34282
|
];
|
|
33415
34283
|
|
|
33416
|
-
// src/strategies/
|
|
33417
|
-
|
|
33418
|
-
|
|
33419
|
-
|
|
33420
|
-
|
|
33421
|
-
|
|
33422
|
-
|
|
33423
|
-
|
|
33424
|
-
|
|
33425
|
-
//abstract means the method has no implementation in this class; instead, child classes must implement it.
|
|
33426
|
-
async getAPY(supportedPosition) {
|
|
33427
|
-
return Promise.resolve({ apy: 0, type: "base" /* BASE */ });
|
|
33428
|
-
}
|
|
33429
|
-
async getPosition(supportedPosition) {
|
|
33430
|
-
return Promise.resolve({ amount: new Web3Number(0, 0), remarks: "" });
|
|
33431
|
-
}
|
|
33432
|
-
async maxDeposit(amount) {
|
|
33433
|
-
return Promise.resolve({
|
|
33434
|
-
tokenInfo: this.config.baseToken,
|
|
33435
|
-
amount: new Web3Number(0, 0),
|
|
33436
|
-
usdValue: 0,
|
|
33437
|
-
apy: { apy: 0, type: "base" /* BASE */ },
|
|
33438
|
-
protocol: Protocols.AVNU,
|
|
33439
|
-
remarks: ""
|
|
33440
|
-
});
|
|
33441
|
-
}
|
|
33442
|
-
async maxWithdraw() {
|
|
33443
|
-
return Promise.resolve({
|
|
33444
|
-
tokenInfo: this.config.baseToken,
|
|
33445
|
-
amount: new Web3Number(0, 0),
|
|
33446
|
-
usdValue: 0,
|
|
33447
|
-
apy: { apy: 0, type: "base" /* BASE */ },
|
|
33448
|
-
protocol: Protocols.AVNU,
|
|
33449
|
-
remarks: ""
|
|
33450
|
-
});
|
|
33451
|
-
}
|
|
33452
|
-
_getDepositLeaf() {
|
|
33453
|
-
const vaultAllocator = ContractAddr.from(
|
|
33454
|
-
this.config.vaultAllocator.address
|
|
33455
|
-
);
|
|
33456
|
-
return [
|
|
33457
|
-
{
|
|
33458
|
-
target: this.config.supportedPositions[0].asset.address,
|
|
33459
|
-
method: "approve",
|
|
33460
|
-
packedArguments: [
|
|
33461
|
-
AVNU_EXCHANGE.toBigInt()
|
|
33462
|
-
],
|
|
33463
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
33464
|
-
id: `approve_${this.config.supportedPositions[0].asset.symbol}`
|
|
33465
|
-
},
|
|
33466
|
-
{
|
|
33467
|
-
target: AVNU_EXCHANGE,
|
|
33468
|
-
method: "multi_route_swap",
|
|
33469
|
-
packedArguments: [
|
|
33470
|
-
this.config.supportedPositions[0].asset.address.toBigInt(),
|
|
33471
|
-
//usdc
|
|
33472
|
-
this.config.supportedPositions[1].asset.address.toBigInt(),
|
|
33473
|
-
//wbtc
|
|
33474
|
-
vaultAllocator.toBigInt()
|
|
33475
|
-
],
|
|
33476
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
33477
|
-
id: `asutb_${this.config.supportedPositions[0].asset.symbol}_${this.config.supportedPositions[1].asset.symbol}`
|
|
33478
|
-
}
|
|
33479
|
-
];
|
|
33480
|
-
}
|
|
33481
|
-
_getWithdrawLeaf() {
|
|
33482
|
-
const vaultAllocator = ContractAddr.from(
|
|
33483
|
-
this.config.vaultAllocator.address
|
|
33484
|
-
);
|
|
33485
|
-
const toToken = this.config.supportedPositions[0].asset;
|
|
33486
|
-
const fromToken = this.config.supportedPositions[1].asset;
|
|
33487
|
-
return [
|
|
33488
|
-
{
|
|
33489
|
-
target: fromToken.address,
|
|
33490
|
-
method: "approve",
|
|
33491
|
-
packedArguments: [
|
|
33492
|
-
AVNU_EXCHANGE.toBigInt()
|
|
33493
|
-
],
|
|
33494
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
33495
|
-
id: `approve_${fromToken.symbol}`
|
|
33496
|
-
},
|
|
33497
|
-
{
|
|
33498
|
-
target: AVNU_EXCHANGE,
|
|
33499
|
-
method: "multi_route_swap",
|
|
33500
|
-
packedArguments: [
|
|
33501
|
-
fromToken.address.toBigInt(),
|
|
33502
|
-
//wbtc
|
|
33503
|
-
toToken.address.toBigInt(),
|
|
33504
|
-
//usdc
|
|
33505
|
-
vaultAllocator.toBigInt()
|
|
33506
|
-
],
|
|
33507
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
33508
|
-
id: `asbtu_${fromToken.symbol}_${fromToken.symbol}`
|
|
33509
|
-
}
|
|
33510
|
-
];
|
|
33511
|
-
}
|
|
33512
|
-
_getLegacySwapLeaf() {
|
|
33513
|
-
return [];
|
|
33514
|
-
}
|
|
33515
|
-
async getDepositCall(params) {
|
|
33516
|
-
try {
|
|
33517
|
-
const fromToken = this.config.supportedPositions[0].asset;
|
|
33518
|
-
const toToken = this.config.supportedPositions[1].asset;
|
|
33519
|
-
const vaultAllocator = ContractAddr.from(
|
|
33520
|
-
this.config.vaultAllocator.address
|
|
33521
|
-
);
|
|
33522
|
-
const quote = await this.getQuotesAvnu(
|
|
33523
|
-
fromToken.address.toString(),
|
|
33524
|
-
toToken.address.toString(),
|
|
33525
|
-
params.amount.toNumber(),
|
|
33526
|
-
vaultAllocator.address.toString(),
|
|
33527
|
-
toToken.decimals,
|
|
33528
|
-
true
|
|
33529
|
-
);
|
|
33530
|
-
if (!quote) {
|
|
33531
|
-
logger.error("error getting quote from avnu");
|
|
33532
|
-
return [];
|
|
33533
|
-
}
|
|
33534
|
-
const getCalldata = await this.avnuWrapper.getSwapCallData(
|
|
33535
|
-
quote,
|
|
33536
|
-
vaultAllocator.address
|
|
33537
|
-
);
|
|
33538
|
-
const swapCallData = getCalldata[0];
|
|
33539
|
-
const amount = uint25614.bnToUint256(quote.sellAmountInUsd * 10 ** 7);
|
|
33540
|
-
return [
|
|
33541
|
-
{
|
|
33542
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
33543
|
-
call: {
|
|
33544
|
-
contractAddress: fromToken.address,
|
|
33545
|
-
selector: hash7.getSelectorFromName("approve"),
|
|
33546
|
-
calldata: [
|
|
33547
|
-
AVNU_EXCHANGE.toBigInt(),
|
|
33548
|
-
toBigInt(amount.low.toString()),
|
|
33549
|
-
// amount low
|
|
33550
|
-
toBigInt(amount.high.toString())
|
|
33551
|
-
// amount high
|
|
33552
|
-
]
|
|
33553
|
-
}
|
|
33554
|
-
},
|
|
33555
|
-
{
|
|
33556
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
33557
|
-
call: {
|
|
33558
|
-
contractAddress: AVNU_EXCHANGE,
|
|
33559
|
-
selector: hash7.getSelectorFromName("multi_route_swap"),
|
|
33560
|
-
calldata: swapCallData
|
|
33561
|
-
}
|
|
33562
|
-
}
|
|
33563
|
-
];
|
|
33564
|
-
} catch (error) {
|
|
33565
|
-
logger.error(`Error getting Avnu quote: ${error}`);
|
|
33566
|
-
return [];
|
|
33567
|
-
}
|
|
33568
|
-
}
|
|
33569
|
-
//Swap wbtc to usdc
|
|
33570
|
-
async getWithdrawCall(params) {
|
|
33571
|
-
try {
|
|
33572
|
-
const toToken = this.config.supportedPositions[0].asset;
|
|
33573
|
-
const fromToken = this.config.supportedPositions[1].asset;
|
|
33574
|
-
const vaultAllocator = ContractAddr.from(
|
|
33575
|
-
this.config.vaultAllocator.address
|
|
33576
|
-
);
|
|
33577
|
-
const quote = await this.getQuotesAvnu(
|
|
33578
|
-
fromToken.address.toString(),
|
|
33579
|
-
toToken.address.toString(),
|
|
33580
|
-
params.amount.toNumber(),
|
|
33581
|
-
vaultAllocator.address.toString(),
|
|
33582
|
-
fromToken.decimals,
|
|
33583
|
-
false
|
|
33584
|
-
);
|
|
33585
|
-
if (!quote) {
|
|
33586
|
-
logger.error("No quotes available for this swap, error in quotes avnu");
|
|
33587
|
-
return [];
|
|
33588
|
-
}
|
|
33589
|
-
const getCalldata = await this.avnuWrapper.getSwapCallData(
|
|
33590
|
-
quote,
|
|
33591
|
-
vaultAllocator.address
|
|
33592
|
-
);
|
|
33593
|
-
const swapCallData = getCalldata[0];
|
|
33594
|
-
const amount = uint25614.bnToUint256(params.amount.toWei());
|
|
33595
|
-
return [
|
|
33596
|
-
{
|
|
33597
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
33598
|
-
call: {
|
|
33599
|
-
contractAddress: fromToken.address,
|
|
33600
|
-
selector: hash7.getSelectorFromName("approve"),
|
|
33601
|
-
calldata: [
|
|
33602
|
-
AVNU_EXCHANGE.toBigInt(),
|
|
33603
|
-
toBigInt(amount.low.toString()),
|
|
33604
|
-
// amount low
|
|
33605
|
-
toBigInt(amount.high.toString())
|
|
33606
|
-
// amount high
|
|
33607
|
-
]
|
|
33608
|
-
}
|
|
33609
|
-
},
|
|
33610
|
-
{
|
|
33611
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
33612
|
-
call: {
|
|
33613
|
-
contractAddress: AVNU_EXCHANGE,
|
|
33614
|
-
selector: hash7.getSelectorFromName("multi_route_swap"),
|
|
33615
|
-
calldata: swapCallData
|
|
33616
|
-
}
|
|
33617
|
-
}
|
|
33618
|
-
];
|
|
33619
|
-
} catch (error) {
|
|
33620
|
-
logger.error(`Error getting Avnu quote: ${error}`);
|
|
33621
|
-
return [];
|
|
33622
|
-
}
|
|
33623
|
-
}
|
|
33624
|
-
async getSwapCallData(quote) {
|
|
33625
|
-
return await this.avnuWrapper.getSwapCallData(quote, this.config.vaultAllocator.address);
|
|
33626
|
-
}
|
|
33627
|
-
async getHealthFactor() {
|
|
33628
|
-
return Promise.resolve(1);
|
|
33629
|
-
}
|
|
33630
|
-
async fetchQuoteWithRetry(params, retries = 5) {
|
|
33631
|
-
for (let attempt = 0; attempt < retries; attempt++) {
|
|
33632
|
-
try {
|
|
33633
|
-
const response = await axios10.get(this.config.baseUrl, { params });
|
|
33634
|
-
if (response.data && response.data.length > 0) {
|
|
33635
|
-
return response;
|
|
33636
|
-
}
|
|
33637
|
-
throw new Error("Empty response data");
|
|
33638
|
-
} catch (err) {
|
|
33639
|
-
logger.error(`Error fetching quote with retry: ${err}`);
|
|
33640
|
-
if (attempt === retries - 1) {
|
|
33641
|
-
throw err;
|
|
33642
|
-
}
|
|
33643
|
-
await new Promise((resolve) => setTimeout(resolve, MAX_DELAY));
|
|
33644
|
-
}
|
|
33645
|
-
}
|
|
33646
|
-
throw new Error("Failed to fetch quote after retries");
|
|
33647
|
-
}
|
|
33648
|
-
async getQuotesAvnu(from_token_address, to_token_address, amount, takerAddress, toTokenDecimals, usdcToBtc, maxIterations = 5, tolerance = 1e4) {
|
|
33649
|
-
try {
|
|
33650
|
-
const fromToken = this.config.supportedPositions[0].asset;
|
|
33651
|
-
const toToken = this.config.supportedPositions[1].asset;
|
|
33652
|
-
if (!usdcToBtc) {
|
|
33653
|
-
const sellAmount2 = returnFormattedAmount(amount, toTokenDecimals);
|
|
33654
|
-
const params2 = {
|
|
33655
|
-
sellTokenAddress: from_token_address,
|
|
33656
|
-
buyTokenAddress: to_token_address,
|
|
33657
|
-
takerAddress,
|
|
33658
|
-
sellAmount: sellAmount2
|
|
33659
|
-
};
|
|
33660
|
-
const finalQuote2 = await this.fetchQuoteWithRetry(params2);
|
|
33661
|
-
if (!finalQuote2.data.length) {
|
|
33662
|
-
logger.error("No quotes available for this swap, error in quotes avnu");
|
|
33663
|
-
return null;
|
|
33664
|
-
}
|
|
33665
|
-
const dataObject2 = finalQuote2.data[0];
|
|
33666
|
-
return dataObject2;
|
|
33667
|
-
}
|
|
33668
|
-
const btcPrice = await this.getPriceOfToken(toToken.address.toString());
|
|
33669
|
-
if (!btcPrice) {
|
|
33670
|
-
logger.error(`error getting btc price: ${btcPrice}`);
|
|
33671
|
-
return null;
|
|
33672
|
-
}
|
|
33673
|
-
const estimatedUsdcAmount = Math.floor(amount * btcPrice);
|
|
33674
|
-
const targetBtcBig = BigInt(returnFormattedAmount(amount, toTokenDecimals));
|
|
33675
|
-
let low = BigInt(
|
|
33676
|
-
Math.floor(
|
|
33677
|
-
estimatedUsdcAmount * 10 ** fromToken.decimals * 0.9
|
|
33678
|
-
)
|
|
33679
|
-
);
|
|
33680
|
-
let high = BigInt(
|
|
33681
|
-
Math.floor(
|
|
33682
|
-
estimatedUsdcAmount * 10 ** fromToken.decimals * 1.1
|
|
33683
|
-
)
|
|
33684
|
-
);
|
|
33685
|
-
let mid = 0n;
|
|
33686
|
-
for (let i = 0; i < maxIterations; i++) {
|
|
33687
|
-
mid = (low + high) / 2n;
|
|
33688
|
-
const sellAmount2 = returnFormattedAmount(Number(mid), 0);
|
|
33689
|
-
const quote = await this.fetchQuoteWithRetry({
|
|
33690
|
-
sellTokenAddress: from_token_address,
|
|
33691
|
-
buyTokenAddress: to_token_address,
|
|
33692
|
-
takerAddress,
|
|
33693
|
-
sellAmount: sellAmount2
|
|
33694
|
-
});
|
|
33695
|
-
const gotBtc = BigInt(quote.data[0].buyAmount);
|
|
33696
|
-
if (gotBtc === targetBtcBig) return quote.data[0];
|
|
33697
|
-
if (gotBtc > targetBtcBig) {
|
|
33698
|
-
high = mid;
|
|
33699
|
-
} else {
|
|
33700
|
-
low = mid;
|
|
33701
|
-
}
|
|
33702
|
-
if (gotBtc >= targetBtcBig && gotBtc <= targetBtcBig + BigInt(tolerance)) {
|
|
33703
|
-
return quote.data[0];
|
|
33704
|
-
}
|
|
33705
|
-
}
|
|
33706
|
-
let sellAmount = returnFormattedAmount(
|
|
33707
|
-
Number(mid),
|
|
33708
|
-
0
|
|
33709
|
-
);
|
|
33710
|
-
const params = {
|
|
33711
|
-
sellTokenAddress: from_token_address,
|
|
33712
|
-
buyTokenAddress: to_token_address,
|
|
33713
|
-
takerAddress,
|
|
33714
|
-
sellAmount
|
|
33715
|
-
};
|
|
33716
|
-
const finalQuote = await this.fetchQuoteWithRetry(params);
|
|
33717
|
-
if (!finalQuote.data.length) {
|
|
33718
|
-
logger.error("No quotes available for this swap, error in quotes avnu");
|
|
33719
|
-
return null;
|
|
33720
|
-
}
|
|
33721
|
-
const dataObject = finalQuote.data[0];
|
|
33722
|
-
return dataObject;
|
|
33723
|
-
} catch (err) {
|
|
33724
|
-
logger.error(`No quotes available for this swap: ${err}`);
|
|
33725
|
-
return null;
|
|
33726
|
-
}
|
|
33727
|
-
}
|
|
33728
|
-
async getPriceOfToken(tokenAddress, retries = MAX_RETRIES) {
|
|
33729
|
-
try {
|
|
33730
|
-
const url = `https://starknet.impulse.avnu.fi/v1/tokens/${tokenAddress}/prices/line`;
|
|
33731
|
-
const response = await axios10.get(url);
|
|
33732
|
-
const length = response.data.length;
|
|
33733
|
-
return response.data[length - 1].value;
|
|
33734
|
-
} catch (err) {
|
|
33735
|
-
if (retries > 0) {
|
|
33736
|
-
await new Promise((resolve) => setTimeout(resolve, MAX_DELAY));
|
|
33737
|
-
return this.getPriceOfToken(tokenAddress, retries - 1);
|
|
33738
|
-
} else {
|
|
33739
|
-
logger.error(`Failed to fetch price for ${tokenAddress} after ${MAX_RETRIES} attempts`);
|
|
33740
|
-
return null;
|
|
33741
|
-
}
|
|
33742
|
-
}
|
|
33743
|
-
}
|
|
33744
|
-
};
|
|
34284
|
+
// src/strategies/vesu-extended-strategy/types/transaction-metadata.ts
|
|
34285
|
+
var CycleType = /* @__PURE__ */ ((CycleType2) => {
|
|
34286
|
+
CycleType2["INVESTMENT"] = "INVESTMENT";
|
|
34287
|
+
CycleType2["REBALANCE_PRICE_DROP"] = "REBALANCE_PRICE_DROP";
|
|
34288
|
+
CycleType2["REBALANCE_PRICE_RISE"] = "REBALANCE_PRICE_RISE";
|
|
34289
|
+
CycleType2["WITHDRAWAL"] = "WITHDRAWAL";
|
|
34290
|
+
CycleType2["DELTA_NEUTRAL_ADJUSTMENT"] = "DELTA_NEUTRAL_ADJUSTMENT";
|
|
34291
|
+
return CycleType2;
|
|
34292
|
+
})(CycleType || {});
|
|
33745
34293
|
|
|
33746
34294
|
// src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx
|
|
33747
34295
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
@@ -33841,15 +34389,30 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
33841
34389
|
const usdceToken = Global.getDefaultTokens().find(
|
|
33842
34390
|
(token) => token.symbol === "USDCe"
|
|
33843
34391
|
);
|
|
34392
|
+
const walletBalance = await new ERC20(this.config).balanceOf(
|
|
34393
|
+
usdceToken.address,
|
|
34394
|
+
WALLET_ADDRESS,
|
|
34395
|
+
usdceToken.decimals
|
|
34396
|
+
);
|
|
34397
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::moveAssetsToVaultAllocator walletBalance: ${walletBalance}`);
|
|
34398
|
+
const amountToBeTransferred = amount.minimum(walletBalance);
|
|
34399
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::moveAssetsToVaultAllocator amountToBeTransferred: ${amountToBeTransferred.toNumber()}`);
|
|
34400
|
+
if (amountToBeTransferred.lessThan(0)) {
|
|
34401
|
+
logger.error(`${_VesuExtendedMultiplierStrategy.name}::moveAssetsToVaultAllocator amountToBeTransferred is less than 0: ${amountToBeTransferred.toNumber()}`);
|
|
34402
|
+
return {
|
|
34403
|
+
calls: [],
|
|
34404
|
+
status: false
|
|
34405
|
+
};
|
|
34406
|
+
}
|
|
33844
34407
|
const approveCall = new ERC20(this.config).approve(
|
|
33845
34408
|
usdceToken.address,
|
|
33846
34409
|
this.metadata.additionalInfo.vaultAllocator,
|
|
33847
|
-
|
|
34410
|
+
amountToBeTransferred
|
|
33848
34411
|
);
|
|
33849
34412
|
const transferCall = new ERC20(this.config).transfer(
|
|
33850
34413
|
usdceToken.address,
|
|
33851
34414
|
this.metadata.additionalInfo.vaultAllocator,
|
|
33852
|
-
|
|
34415
|
+
amountToBeTransferred
|
|
33853
34416
|
);
|
|
33854
34417
|
const proofsInfo = extendedAdapter.getProofsForFromLegacySwap(
|
|
33855
34418
|
this.getMerkleTree()
|
|
@@ -33857,21 +34420,43 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
33857
34420
|
const proofGroups = proofsInfo.proofs;
|
|
33858
34421
|
const call = this.getManageCall(
|
|
33859
34422
|
proofGroups,
|
|
33860
|
-
await proofsInfo.callConstructor({ amount })
|
|
34423
|
+
await proofsInfo.callConstructor({ amount: amountToBeTransferred })
|
|
33861
34424
|
);
|
|
33862
|
-
return
|
|
34425
|
+
return {
|
|
34426
|
+
calls: [approveCall, transferCall, call],
|
|
34427
|
+
status: true
|
|
34428
|
+
};
|
|
33863
34429
|
} catch (err) {
|
|
33864
34430
|
logger.error(`error moving assets to vault allocator: ${err}`);
|
|
33865
|
-
return
|
|
34431
|
+
return {
|
|
34432
|
+
calls: [],
|
|
34433
|
+
status: false
|
|
34434
|
+
};
|
|
33866
34435
|
}
|
|
33867
34436
|
}
|
|
33868
34437
|
async shouldInvest() {
|
|
33869
34438
|
try {
|
|
34439
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest starting`);
|
|
33870
34440
|
const vesuAdapter = await this.getVesuAdapter();
|
|
33871
34441
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
33872
|
-
|
|
34442
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest adapters fetched: vesuAdapter=${!!vesuAdapter}, extendedAdapter=${!!extendedAdapter}, extendedAdapter.client=${!!extendedAdapter?.client}`);
|
|
34443
|
+
if (!vesuAdapter) {
|
|
33873
34444
|
logger.error(
|
|
33874
|
-
`
|
|
34445
|
+
`Vesu adapter not configured in metadata. This is a configuration issue, not a temporary failure.`
|
|
34446
|
+
);
|
|
34447
|
+
return {
|
|
34448
|
+
shouldInvest: false,
|
|
34449
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34450
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34451
|
+
extendedLeverage: 0,
|
|
34452
|
+
collateralPrice: 0,
|
|
34453
|
+
debtPrice: 0,
|
|
34454
|
+
vesuLeverage: 0
|
|
34455
|
+
};
|
|
34456
|
+
}
|
|
34457
|
+
if (!extendedAdapter) {
|
|
34458
|
+
logger.error(
|
|
34459
|
+
`Extended adapter not configured in metadata. This is a configuration issue, not a temporary failure.`
|
|
33875
34460
|
);
|
|
33876
34461
|
return {
|
|
33877
34462
|
shouldInvest: false,
|
|
@@ -33883,10 +34468,73 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
33883
34468
|
vesuLeverage: 0
|
|
33884
34469
|
};
|
|
33885
34470
|
}
|
|
34471
|
+
if (!extendedAdapter.client) {
|
|
34472
|
+
logger.error(
|
|
34473
|
+
`Extended adapter client not initialized. This may be a temporary initialization failure - check network connectivity and API availability.`
|
|
34474
|
+
);
|
|
34475
|
+
return {
|
|
34476
|
+
shouldInvest: false,
|
|
34477
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34478
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34479
|
+
extendedLeverage: 0,
|
|
34480
|
+
collateralPrice: 0,
|
|
34481
|
+
debtPrice: 0,
|
|
34482
|
+
vesuLeverage: 0
|
|
34483
|
+
};
|
|
34484
|
+
}
|
|
34485
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest calling getUnusedBalance`);
|
|
33886
34486
|
const balance = await this.getUnusedBalance();
|
|
34487
|
+
if (!Number.isFinite(balance.usdValue) || balance.usdValue < 0) {
|
|
34488
|
+
logger.error(
|
|
34489
|
+
`Invalid balance.usdValue: ${balance.usdValue}. Expected a finite, non-negative number.`
|
|
34490
|
+
);
|
|
34491
|
+
return {
|
|
34492
|
+
shouldInvest: false,
|
|
34493
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34494
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34495
|
+
extendedLeverage: 0,
|
|
34496
|
+
collateralPrice: 0,
|
|
34497
|
+
debtPrice: 0,
|
|
34498
|
+
vesuLeverage: 0
|
|
34499
|
+
};
|
|
34500
|
+
}
|
|
34501
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest balance: ${balance.usdValue}`);
|
|
33887
34502
|
const usdcBalanceOnExtended = await extendedAdapter.getExtendedDepositAmount();
|
|
33888
|
-
|
|
33889
|
-
|
|
34503
|
+
if (usdcBalanceOnExtended) {
|
|
34504
|
+
const availableForWithdrawal = parseFloat(usdcBalanceOnExtended.availableForWithdrawal);
|
|
34505
|
+
if (!Number.isFinite(availableForWithdrawal) || availableForWithdrawal < 0) {
|
|
34506
|
+
logger.error(
|
|
34507
|
+
`Invalid usdcBalanceOnExtended.availableForWithdrawal: ${usdcBalanceOnExtended.availableForWithdrawal}. Expected a finite, non-negative number.`
|
|
34508
|
+
);
|
|
34509
|
+
return {
|
|
34510
|
+
shouldInvest: false,
|
|
34511
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34512
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34513
|
+
extendedLeverage: 0,
|
|
34514
|
+
collateralPrice: 0,
|
|
34515
|
+
debtPrice: 0,
|
|
34516
|
+
vesuLeverage: 0
|
|
34517
|
+
};
|
|
34518
|
+
}
|
|
34519
|
+
}
|
|
34520
|
+
const amountToInvest = new Web3Number(balance.usdValue, USDC_TOKEN_DECIMALS).plus(usdcBalanceOnExtended?.availableForWithdrawal ?? 0).multipliedBy(1 - LIMIT_BALANCE);
|
|
34521
|
+
const amountToInvestNumber = amountToInvest.toNumber();
|
|
34522
|
+
if (!Number.isFinite(amountToInvestNumber)) {
|
|
34523
|
+
logger.error(
|
|
34524
|
+
`Invalid amountToInvest calculation result: ${amountToInvestNumber}. Calculation may have produced NaN or Infinity.`
|
|
34525
|
+
);
|
|
34526
|
+
return {
|
|
34527
|
+
shouldInvest: false,
|
|
34528
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34529
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34530
|
+
extendedLeverage: 0,
|
|
34531
|
+
collateralPrice: 0,
|
|
34532
|
+
debtPrice: 0,
|
|
34533
|
+
vesuLeverage: 0
|
|
34534
|
+
};
|
|
34535
|
+
}
|
|
34536
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest amountToInvest: ${amountToInvestNumber}`);
|
|
34537
|
+
if (amountToInvest.lessThan(LIMIT_BALANCE_VALUE)) {
|
|
33890
34538
|
return {
|
|
33891
34539
|
shouldInvest: false,
|
|
33892
34540
|
vesuAmount: new Web3Number(0, 0),
|
|
@@ -33915,6 +34563,34 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
33915
34563
|
collateralPrice,
|
|
33916
34564
|
debtPrice
|
|
33917
34565
|
} = await this.getAssetPrices();
|
|
34566
|
+
if (!Number.isFinite(collateralPrice.price) || collateralPrice.price <= 0) {
|
|
34567
|
+
logger.error(
|
|
34568
|
+
`Invalid collateralPrice: ${collateralPrice.price}. Expected a finite, positive number.`
|
|
34569
|
+
);
|
|
34570
|
+
return {
|
|
34571
|
+
shouldInvest: false,
|
|
34572
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34573
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34574
|
+
extendedLeverage: 0,
|
|
34575
|
+
collateralPrice: 0,
|
|
34576
|
+
debtPrice: 0,
|
|
34577
|
+
vesuLeverage: 0
|
|
34578
|
+
};
|
|
34579
|
+
}
|
|
34580
|
+
if (!Number.isFinite(debtPrice.price) || debtPrice.price <= 0) {
|
|
34581
|
+
logger.error(
|
|
34582
|
+
`Invalid debtPrice: ${debtPrice.price}. Expected a finite, positive number.`
|
|
34583
|
+
);
|
|
34584
|
+
return {
|
|
34585
|
+
shouldInvest: false,
|
|
34586
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34587
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34588
|
+
extendedLeverage: 0,
|
|
34589
|
+
collateralPrice: 0,
|
|
34590
|
+
debtPrice: 0,
|
|
34591
|
+
vesuLeverage: 0
|
|
34592
|
+
};
|
|
34593
|
+
}
|
|
33918
34594
|
const { vesu_amount, extended_amount, extended_leverage, vesu_leverage } = await calculateAmountDistribution(
|
|
33919
34595
|
amountToInvest.toNumber(),
|
|
33920
34596
|
extendedAdapter.client,
|
|
@@ -33938,6 +34614,7 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
33938
34614
|
vesuLeverage: 0
|
|
33939
34615
|
};
|
|
33940
34616
|
}
|
|
34617
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest vesu_amount: ${vesu_amount.toNumber()}, extended_amount: ${extended_amount.toNumber()}`);
|
|
33941
34618
|
return {
|
|
33942
34619
|
shouldInvest: true,
|
|
33943
34620
|
vesuAmount: vesu_amount,
|
|
@@ -33964,111 +34641,251 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
33964
34641
|
try {
|
|
33965
34642
|
const vesuAdapter = await this.getVesuAdapter();
|
|
33966
34643
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
33967
|
-
let calls = [];
|
|
33968
34644
|
if (!vesuAdapter || !extendedAdapter || !extendedAdapter.client) {
|
|
33969
34645
|
logger.error(
|
|
33970
34646
|
`vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
|
|
33971
34647
|
);
|
|
33972
|
-
return
|
|
34648
|
+
return [];
|
|
34649
|
+
}
|
|
34650
|
+
const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
34651
|
+
if (!extendedHoldings) {
|
|
34652
|
+
logger.error(`error getting extended holdings: ${extendedHoldings}`);
|
|
34653
|
+
return [];
|
|
33973
34654
|
}
|
|
33974
|
-
|
|
34655
|
+
const usdcAmountInWallet = (await this.getUnusedBalance()).amount;
|
|
34656
|
+
const usdcAmountOnExtendedAvailableForWithdrawal = parseFloat(
|
|
34657
|
+
extendedHoldings.availableForWithdrawal
|
|
34658
|
+
);
|
|
34659
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldMoveAssets calculating movements - Extended current: ${usdcAmountOnExtendedAvailableForWithdrawal}, Wallet: ${usdcAmountInWallet.toNumber()}, Target Extended: ${extendedAmount.toNumber()}, Target Vesu: ${vesuAmount.toNumber()}`);
|
|
34660
|
+
let totalExtendedWithdrawal = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
34661
|
+
let totalExtendedDeposit = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
34662
|
+
if (extendedAmount.isNegative() && extendedAmount.abs().greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
34663
|
+
totalExtendedWithdrawal = totalExtendedWithdrawal.plus(extendedAmount.abs());
|
|
34664
|
+
}
|
|
34665
|
+
const extendedTargetAmount = extendedAmount.abs();
|
|
34666
|
+
let projectedExtendedBalance = usdcAmountOnExtendedAvailableForWithdrawal;
|
|
34667
|
+
if (extendedAmount.isNegative()) {
|
|
34668
|
+
projectedExtendedBalance = projectedExtendedBalance - extendedAmount.abs().toNumber();
|
|
34669
|
+
}
|
|
34670
|
+
const extendedAmountDifference = extendedTargetAmount.minus(projectedExtendedBalance);
|
|
34671
|
+
const extendedAmountDifferenceAbs = extendedAmountDifference.abs();
|
|
34672
|
+
if (extendedAmountDifference.lessThan(0)) {
|
|
34673
|
+
totalExtendedWithdrawal = totalExtendedWithdrawal.plus(extendedAmountDifferenceAbs);
|
|
34674
|
+
} else if (extendedAmountDifference.greaterThan(0)) {
|
|
34675
|
+
totalExtendedDeposit = totalExtendedDeposit.plus(extendedAmountDifference);
|
|
34676
|
+
}
|
|
34677
|
+
const vesuTargetAmount = vesuAmount.abs();
|
|
34678
|
+
const projectedWalletBalance = usdcAmountInWallet.plus(totalExtendedWithdrawal).minus(totalExtendedDeposit);
|
|
34679
|
+
let vesuAmountDifference = vesuTargetAmount.minus(projectedWalletBalance);
|
|
34680
|
+
const vesuAmountDifferenceAbs = vesuAmountDifference.abs();
|
|
34681
|
+
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()}`);
|
|
34682
|
+
let calls = [];
|
|
34683
|
+
let transactionResults = [];
|
|
34684
|
+
if (extendedAmount.isNegative() && extendedAmount.abs().greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
33975
34685
|
try {
|
|
33976
|
-
const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
|
|
34686
|
+
const { calls: extendedCalls, status: extendedStatus, transactionMetadata: extendedTransactionMetadata } = await this.moveAssets(
|
|
33977
34687
|
{
|
|
33978
34688
|
to: Protocols.VAULT.name,
|
|
33979
34689
|
from: Protocols.EXTENDED.name,
|
|
33980
|
-
amount: extendedAmount.abs()
|
|
34690
|
+
amount: extendedAmount.abs(),
|
|
34691
|
+
cycleType: "INVESTMENT" /* INVESTMENT */
|
|
33981
34692
|
},
|
|
33982
34693
|
extendedAdapter,
|
|
33983
34694
|
vesuAdapter
|
|
33984
34695
|
);
|
|
33985
34696
|
if (extendedStatus) {
|
|
33986
|
-
|
|
34697
|
+
transactionResults.push({
|
|
34698
|
+
status: extendedStatus,
|
|
34699
|
+
calls: extendedCalls,
|
|
34700
|
+
transactionMetadata: {
|
|
34701
|
+
...extendedTransactionMetadata,
|
|
34702
|
+
transactionType: "DEPOSIT"
|
|
34703
|
+
}
|
|
34704
|
+
});
|
|
33987
34705
|
} else {
|
|
33988
|
-
return [];
|
|
34706
|
+
return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: extendedAmount.abs() }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
33989
34707
|
}
|
|
33990
34708
|
} catch (err) {
|
|
33991
34709
|
logger.error(`Failed moving assets to vault: ${err}`);
|
|
34710
|
+
return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: extendedAmount.abs() }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
33992
34711
|
}
|
|
33993
34712
|
}
|
|
33994
|
-
if (vesuAmount.
|
|
34713
|
+
if (vesuAmount.isNegative() && vesuAmount.abs().greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
|
|
33995
34714
|
try {
|
|
33996
|
-
const { calls: vesuCalls, status: vesuStatus } = await this.moveAssets(
|
|
34715
|
+
const { calls: vesuCalls, status: vesuStatus, transactionMetadata: vesuTransactionMetadata } = await this.moveAssets(
|
|
33997
34716
|
{
|
|
33998
34717
|
to: Protocols.EXTENDED.name,
|
|
33999
34718
|
from: Protocols.VESU.name,
|
|
34000
|
-
amount: vesuAmount.abs()
|
|
34719
|
+
amount: vesuAmount.abs(),
|
|
34720
|
+
cycleType: "INVESTMENT" /* INVESTMENT */
|
|
34001
34721
|
},
|
|
34002
34722
|
extendedAdapter,
|
|
34003
34723
|
vesuAdapter
|
|
34004
34724
|
);
|
|
34005
|
-
calls.push(...vesuCalls);
|
|
34006
34725
|
if (!vesuStatus) {
|
|
34007
|
-
return [];
|
|
34008
|
-
}
|
|
34726
|
+
return [this.createTransactionResult([], false, { from: Protocols.VESU.name, to: Protocols.EXTENDED.name, amount: vesuAmount.abs() }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34727
|
+
}
|
|
34728
|
+
transactionResults.push({
|
|
34729
|
+
status: vesuStatus,
|
|
34730
|
+
calls: vesuCalls,
|
|
34731
|
+
transactionMetadata: {
|
|
34732
|
+
...vesuTransactionMetadata,
|
|
34733
|
+
transactionType: "DEPOSIT"
|
|
34734
|
+
}
|
|
34735
|
+
});
|
|
34009
34736
|
} catch (err) {
|
|
34010
|
-
logger.error(`Failed moving assets to vault: ${err}`);
|
|
34737
|
+
logger.error(`Failed moving assets to extended via vault allocator: ${err}`);
|
|
34738
|
+
return [this.createTransactionResult([], false, { from: Protocols.VESU.name, to: Protocols.EXTENDED.name, amount: vesuAmount.abs() }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34011
34739
|
}
|
|
34012
34740
|
}
|
|
34013
|
-
|
|
34014
|
-
|
|
34015
|
-
|
|
34016
|
-
|
|
34017
|
-
|
|
34018
|
-
|
|
34019
|
-
|
|
34020
|
-
|
|
34021
|
-
|
|
34022
|
-
|
|
34023
|
-
|
|
34024
|
-
|
|
34025
|
-
|
|
34026
|
-
|
|
34027
|
-
|
|
34028
|
-
|
|
34029
|
-
|
|
34030
|
-
|
|
34031
|
-
|
|
34032
|
-
|
|
34033
|
-
|
|
34034
|
-
|
|
34035
|
-
|
|
34741
|
+
if (extendedAmountDifferenceAbs.greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
34742
|
+
if (extendedAmountDifference.greaterThan(0)) {
|
|
34743
|
+
try {
|
|
34744
|
+
const { calls: extendedCalls, status: extendedStatus, transactionMetadata: extendedTransactionMetadata } = await this.moveAssets(
|
|
34745
|
+
{
|
|
34746
|
+
to: Protocols.EXTENDED.name,
|
|
34747
|
+
from: Protocols.VAULT.name,
|
|
34748
|
+
amount: extendedAmountDifference,
|
|
34749
|
+
cycleType: "INVESTMENT" /* INVESTMENT */
|
|
34750
|
+
},
|
|
34751
|
+
extendedAdapter,
|
|
34752
|
+
vesuAdapter
|
|
34753
|
+
);
|
|
34754
|
+
if (extendedStatus) {
|
|
34755
|
+
transactionResults.push({
|
|
34756
|
+
status: extendedStatus,
|
|
34757
|
+
calls: extendedCalls,
|
|
34758
|
+
transactionMetadata: extendedTransactionMetadata
|
|
34759
|
+
});
|
|
34760
|
+
} else {
|
|
34761
|
+
logger.error(`Failed to move assets to extended - operation returned false status`);
|
|
34762
|
+
return [this.createTransactionResult([], false, { from: Protocols.VAULT.name, to: Protocols.EXTENDED.name, amount: extendedAmountDifference }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34763
|
+
}
|
|
34764
|
+
} catch (err) {
|
|
34765
|
+
logger.error(`Failed moving assets to extended: ${err}`);
|
|
34766
|
+
return [this.createTransactionResult([], false, { from: Protocols.VAULT.name, to: Protocols.EXTENDED.name, amount: extendedAmountDifference }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34767
|
+
}
|
|
34768
|
+
} else if (extendedAmountDifference.lessThan(0)) {
|
|
34769
|
+
try {
|
|
34770
|
+
const { calls: extendedCalls, status: extendedStatus, transactionMetadata: extendedTransactionMetadata } = await this.moveAssets(
|
|
34771
|
+
{
|
|
34772
|
+
to: Protocols.VAULT.name,
|
|
34773
|
+
from: Protocols.EXTENDED.name,
|
|
34774
|
+
amount: extendedAmountDifferenceAbs,
|
|
34775
|
+
cycleType: "INVESTMENT" /* INVESTMENT */
|
|
34776
|
+
},
|
|
34777
|
+
extendedAdapter,
|
|
34778
|
+
vesuAdapter
|
|
34779
|
+
);
|
|
34780
|
+
if (extendedStatus) {
|
|
34781
|
+
transactionResults.push({
|
|
34782
|
+
status: extendedStatus,
|
|
34783
|
+
calls: extendedCalls,
|
|
34784
|
+
transactionMetadata: {
|
|
34785
|
+
...extendedTransactionMetadata,
|
|
34786
|
+
transactionType: "DEPOSIT"
|
|
34787
|
+
}
|
|
34788
|
+
});
|
|
34789
|
+
} else {
|
|
34790
|
+
logger.error(`Failed to withdraw from extended - operation returned false status`);
|
|
34791
|
+
return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: extendedAmountDifferenceAbs }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34792
|
+
}
|
|
34793
|
+
} catch (err) {
|
|
34794
|
+
logger.error(`Failed moving assets from extended to vault: ${err}`);
|
|
34795
|
+
return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: extendedAmountDifferenceAbs }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34796
|
+
}
|
|
34036
34797
|
}
|
|
34037
34798
|
}
|
|
34038
|
-
if (
|
|
34039
|
-
|
|
34040
|
-
|
|
34041
|
-
{
|
|
34042
|
-
to: Protocols.VAULT.name,
|
|
34043
|
-
from: Protocols.EXTENDED.name,
|
|
34044
|
-
amount: vesuAmount.minus(usdcAmountInWallet)
|
|
34045
|
-
},
|
|
34046
|
-
extendedAdapter,
|
|
34047
|
-
vesuAdapter
|
|
34799
|
+
if (vesuAmountDifferenceAbs.greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
|
|
34800
|
+
if (vesuAmountDifference.lessThanOrEqualTo(0)) {
|
|
34801
|
+
logger.warn(
|
|
34802
|
+
`Vesu amount difference is negative or zero: ${vesuAmountDifference.toNumber()}. Skipping operation.`
|
|
34048
34803
|
);
|
|
34049
|
-
|
|
34050
|
-
|
|
34804
|
+
} else {
|
|
34805
|
+
try {
|
|
34806
|
+
const { calls: vesuCalls, status: vesuStatus, transactionMetadata: vesuTransactionMetadata } = await this.moveAssets(
|
|
34807
|
+
{
|
|
34808
|
+
to: Protocols.VAULT.name,
|
|
34809
|
+
from: Protocols.EXTENDED.name,
|
|
34810
|
+
amount: vesuAmountDifference,
|
|
34811
|
+
cycleType: "INVESTMENT" /* INVESTMENT */
|
|
34812
|
+
},
|
|
34813
|
+
extendedAdapter,
|
|
34814
|
+
vesuAdapter
|
|
34815
|
+
);
|
|
34816
|
+
if (!vesuStatus) {
|
|
34817
|
+
logger.error(`Failed to move assets to vesu - operation returned false status`);
|
|
34818
|
+
return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: vesuAmountDifference }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34819
|
+
}
|
|
34820
|
+
transactionResults.push({
|
|
34821
|
+
status: vesuStatus,
|
|
34822
|
+
calls: vesuCalls,
|
|
34823
|
+
transactionMetadata: {
|
|
34824
|
+
...vesuTransactionMetadata,
|
|
34825
|
+
transactionType: "DEPOSIT"
|
|
34826
|
+
}
|
|
34827
|
+
});
|
|
34828
|
+
} catch (err) {
|
|
34829
|
+
logger.error(`Failed moving assets to vault: ${err}`);
|
|
34830
|
+
return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: vesuAmountDifference }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34051
34831
|
}
|
|
34052
|
-
calls.push(...vesuCalls);
|
|
34053
|
-
} catch (err) {
|
|
34054
|
-
logger.error(`Failed moving assets to vault: ${err}`);
|
|
34055
34832
|
}
|
|
34056
34833
|
}
|
|
34057
|
-
return
|
|
34834
|
+
return transactionResults;
|
|
34058
34835
|
} catch (err) {
|
|
34059
34836
|
logger.error(`Failed moving assets to vesu: ${err}`);
|
|
34060
|
-
return [];
|
|
34837
|
+
return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: new Web3Number(0, USDC_TOKEN_DECIMALS) }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34061
34838
|
}
|
|
34062
34839
|
}
|
|
34840
|
+
/**
|
|
34841
|
+
* Helper method to create transaction result with metadata
|
|
34842
|
+
*/
|
|
34843
|
+
createTransactionResult(calls, status, params, transactionType, cycleType) {
|
|
34844
|
+
if (status) {
|
|
34845
|
+
return {
|
|
34846
|
+
calls,
|
|
34847
|
+
status,
|
|
34848
|
+
transactionMetadata: {
|
|
34849
|
+
protocolFrom: params.from,
|
|
34850
|
+
protocolTo: params.to,
|
|
34851
|
+
transactionType,
|
|
34852
|
+
usdAmount: params.amount.abs().toFixed(),
|
|
34853
|
+
status: "PENDING",
|
|
34854
|
+
cycleType
|
|
34855
|
+
}
|
|
34856
|
+
};
|
|
34857
|
+
}
|
|
34858
|
+
return { calls: [], status: false, transactionMetadata: { protocolFrom: "", protocolTo: "", transactionType: "DEPOSIT", usdAmount: "0", status: "FAILED", cycleType } };
|
|
34859
|
+
}
|
|
34063
34860
|
async moveAssets(params, extendedAdapter, vesuAdapter) {
|
|
34064
34861
|
try {
|
|
34862
|
+
if (params.amount.lessThanOrEqualTo(0)) {
|
|
34863
|
+
logger.error(
|
|
34864
|
+
`Invalid amount for moveAssets: ${params.amount.toNumber()}. Amount must be positive.`
|
|
34865
|
+
);
|
|
34866
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34867
|
+
}
|
|
34868
|
+
const amountAbs = params.amount.abs();
|
|
34869
|
+
if (params.from === Protocols.EXTENDED.name || params.to === Protocols.EXTENDED.name) {
|
|
34870
|
+
if (amountAbs.lessThanOrEqualTo(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
34871
|
+
logger.warn(
|
|
34872
|
+
`Amount ${amountAbs.toNumber()} is below minimum Extended movement amount ${extendedAdapter.minimumExtendedMovementAmount}. Skipping operation.`
|
|
34873
|
+
);
|
|
34874
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34875
|
+
}
|
|
34876
|
+
}
|
|
34877
|
+
if (params.from === Protocols.VESU.name || params.to === Protocols.VESU.name) {
|
|
34878
|
+
if (amountAbs.lessThanOrEqualTo(vesuAdapter.minimumVesuMovementAmount)) {
|
|
34879
|
+
logger.warn(
|
|
34880
|
+
`Amount ${amountAbs.toNumber()} is below minimum Vesu movement amount ${vesuAdapter.minimumVesuMovementAmount}. Skipping operation.`
|
|
34881
|
+
);
|
|
34882
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34883
|
+
}
|
|
34884
|
+
}
|
|
34065
34885
|
const avnuAdapter = await this.getAvnuAdapter();
|
|
34066
34886
|
if (!avnuAdapter) {
|
|
34067
34887
|
logger.error(`avnu adapter not found: ${avnuAdapter}`);
|
|
34068
|
-
return
|
|
34069
|
-
calls: [],
|
|
34070
|
-
status: false
|
|
34071
|
-
};
|
|
34888
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34072
34889
|
}
|
|
34073
34890
|
logger.info(`moveAssets params, ${JSON.stringify(params)}`);
|
|
34074
34891
|
const collateralToken = vesuAdapter.config.supportedPositions[0].asset;
|
|
@@ -34087,61 +34904,72 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34087
34904
|
await proofsInfo.callConstructor({ amount: params.amount })
|
|
34088
34905
|
);
|
|
34089
34906
|
calls.push(call);
|
|
34090
|
-
return
|
|
34091
|
-
calls: [call],
|
|
34092
|
-
status: true
|
|
34093
|
-
};
|
|
34907
|
+
return this.createTransactionResult(calls, true, params, "DEPOSIT", params.cycleType);
|
|
34094
34908
|
} else if (params.to === Protocols.VAULT.name && params.from === Protocols.EXTENDED.name) {
|
|
34095
34909
|
const extendedLeverage = calculateExtendedLevergae();
|
|
34096
34910
|
const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
34097
34911
|
if (!extendedHoldings) {
|
|
34098
34912
|
logger.error(`error getting extended holdings: ${extendedHoldings}`);
|
|
34099
|
-
return
|
|
34100
|
-
calls: [],
|
|
34101
|
-
status: false
|
|
34102
|
-
};
|
|
34913
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34103
34914
|
}
|
|
34104
34915
|
const extendedHoldingAmount = new Web3Number(
|
|
34105
34916
|
extendedHoldings.availableForWithdrawal,
|
|
34106
34917
|
USDC_TOKEN_DECIMALS
|
|
34107
34918
|
);
|
|
34108
|
-
|
|
34109
|
-
|
|
34110
|
-
|
|
34111
|
-
|
|
34112
|
-
btcAmount.
|
|
34113
|
-
|
|
34114
|
-
|
|
34115
|
-
|
|
34116
|
-
|
|
34117
|
-
|
|
34118
|
-
|
|
34119
|
-
|
|
34120
|
-
|
|
34919
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::moveAssets extendedHoldingAmount: ${extendedHoldingAmount.toNumber()}`);
|
|
34920
|
+
if (params.amount.abs().greaterThan(extendedHoldingAmount)) {
|
|
34921
|
+
const leftAmountAfterWithdrawalAmountInAccount = params.amount.abs().minus(extendedHoldingAmount);
|
|
34922
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::moveAssets leftAmountAfterWithdrawalAmountInAccount: ${leftAmountAfterWithdrawalAmountInAccount.toNumber()}`);
|
|
34923
|
+
const btcAmount = leftAmountAfterWithdrawalAmountInAccount.dividedBy(collateralPrice.price);
|
|
34924
|
+
const openLongPosition = btcAmount.multipliedBy(3).greaterThan(MINIMUM_EXTENDED_POSITION_SIZE) ? await extendedAdapter.createOrder(
|
|
34925
|
+
extendedLeverage.toString(),
|
|
34926
|
+
btcAmount.toNumber(),
|
|
34927
|
+
"BUY" /* BUY */
|
|
34928
|
+
) : await extendedAdapter.createOrder(
|
|
34929
|
+
extendedLeverage.toString(),
|
|
34930
|
+
34e-6,
|
|
34931
|
+
// just in case amount falls short then we need to create a withdrawal
|
|
34932
|
+
"BUY" /* BUY */
|
|
34933
|
+
);
|
|
34934
|
+
if (!openLongPosition) {
|
|
34935
|
+
logger.error(`error opening long position: ${openLongPosition}`);
|
|
34936
|
+
}
|
|
34937
|
+
const updatedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
34938
|
+
if (!updatedHoldings || new Web3Number(updatedHoldings.availableForWithdrawal, USDC_TOKEN_DECIMALS).lessThan(params.amount.abs())) {
|
|
34939
|
+
logger.error(`Insufficient balance after opening position. Available: ${updatedHoldings?.availableForWithdrawal}, Needed: ${params.amount.abs()}`);
|
|
34940
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34941
|
+
}
|
|
34121
34942
|
}
|
|
34122
|
-
|
|
34123
|
-
|
|
34124
|
-
|
|
34943
|
+
const {
|
|
34944
|
+
status: withdrawalFromExtendedStatus,
|
|
34945
|
+
receivedTxnHash: withdrawalFromExtendedTxnHash
|
|
34946
|
+
} = await extendedAdapter.withdrawFromExtended(params.amount);
|
|
34947
|
+
logger.info(`withdrawalFromExtendedStatus: ${withdrawalFromExtendedStatus}, withdrawalFromExtendedTxnHash: ${withdrawalFromExtendedTxnHash}`);
|
|
34948
|
+
if (withdrawalFromExtendedStatus && withdrawalFromExtendedTxnHash) {
|
|
34125
34949
|
const extendedHoldings2 = await extendedAdapter.getExtendedDepositAmount();
|
|
34126
|
-
logger.info(`extendedHoldings after withdrawal ${extendedHoldings2}`);
|
|
34127
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
34128
|
-
const calls = await this.moveAssetsToVaultAllocator(params.amount, extendedAdapter);
|
|
34129
|
-
if (calls.length > 0) {
|
|
34130
|
-
return
|
|
34131
|
-
|
|
34132
|
-
|
|
34133
|
-
};
|
|
34950
|
+
logger.info(`extendedHoldings after withdrawal ${extendedHoldings2?.availableForWithdrawal}`);
|
|
34951
|
+
await new Promise((resolve) => setTimeout(resolve, 5e3));
|
|
34952
|
+
const { calls, status } = await this.moveAssetsToVaultAllocator(params.amount, extendedAdapter);
|
|
34953
|
+
if (calls.length > 0 && status) {
|
|
34954
|
+
return this.createTransactionResult(calls, true, params, "WITHDRAWAL", params.cycleType);
|
|
34955
|
+
} else {
|
|
34956
|
+
return this.createTransactionResult([], true, params, "WITHDRAWAL", params.cycleType);
|
|
34134
34957
|
}
|
|
34958
|
+
} else if (withdrawalFromExtendedStatus && !withdrawalFromExtendedTxnHash) {
|
|
34959
|
+
logger.error("withdrawal from extended successful, but funds didn't get transferred to the wallet");
|
|
34960
|
+
return this.createTransactionResult([], true, params, "WITHDRAWAL", params.cycleType);
|
|
34135
34961
|
} else {
|
|
34136
34962
|
logger.error("withdrawal from extended failed");
|
|
34137
|
-
return
|
|
34138
|
-
calls: [],
|
|
34139
|
-
status: false
|
|
34140
|
-
};
|
|
34963
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34141
34964
|
}
|
|
34142
34965
|
} else if (params.to === Protocols.VAULT.name && params.from === Protocols.VESU.name) {
|
|
34966
|
+
const isPriceDifferenceBetweenAvnuAndExtended = await this.checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter, vesuAdapter, avnuAdapter, "close" /* CLOSE */);
|
|
34967
|
+
if (!isPriceDifferenceBetweenAvnuAndExtended) {
|
|
34968
|
+
logger.warn(`price difference between avnu and extended doesn't fit the range for close position, ${avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing}`);
|
|
34969
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34970
|
+
}
|
|
34143
34971
|
const vesuAmountInBTC = new Web3Number(
|
|
34144
|
-
params.amount.dividedBy(collateralPrice.price).
|
|
34972
|
+
params.amount.dividedBy(collateralPrice.price).toFixed(WBTC_TOKEN_DECIMALS),
|
|
34145
34973
|
collateralToken.decimals
|
|
34146
34974
|
);
|
|
34147
34975
|
const proofsInfo = vesuAdapter.getProofs(false, this.getMerkleTree());
|
|
@@ -34159,11 +34987,13 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34159
34987
|
await swapProofsInfo.callConstructor({ amount: vesuAmountInBTC })
|
|
34160
34988
|
);
|
|
34161
34989
|
calls.push(swapCall);
|
|
34162
|
-
return
|
|
34163
|
-
calls,
|
|
34164
|
-
status: true
|
|
34165
|
-
};
|
|
34990
|
+
return this.createTransactionResult(calls, true, params, "WITHDRAWAL", params.cycleType);
|
|
34166
34991
|
} else if (params.to === Protocols.EXTENDED.name && params.from === Protocols.VESU.name) {
|
|
34992
|
+
const isPriceDifferenceBetweenAvnuAndExtended = await this.checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter, vesuAdapter, avnuAdapter, "close" /* CLOSE */);
|
|
34993
|
+
if (!isPriceDifferenceBetweenAvnuAndExtended) {
|
|
34994
|
+
logger.warn(`price difference between avnu and extended doesn't fit the range for close position, ${avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing}`);
|
|
34995
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34996
|
+
}
|
|
34167
34997
|
const vesuAmountInBTC = new Web3Number(
|
|
34168
34998
|
params.amount.dividedBy(collateralPrice.price).toNumber(),
|
|
34169
34999
|
collateralToken.decimals
|
|
@@ -34193,131 +35023,32 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34193
35023
|
await proofsInfoDeposit.callConstructor({ amount: params.amount })
|
|
34194
35024
|
);
|
|
34195
35025
|
calls.push(callDeposit);
|
|
34196
|
-
return
|
|
34197
|
-
calls,
|
|
34198
|
-
status: true
|
|
34199
|
-
};
|
|
35026
|
+
return this.createTransactionResult(calls, true, params, "DEPOSIT", params.cycleType);
|
|
34200
35027
|
}
|
|
34201
|
-
|
|
34202
|
-
|
|
34203
|
-
status: false
|
|
34204
|
-
};
|
|
35028
|
+
logger.error(`Unsupported assets movement: ${params.from} to ${params.to}`);
|
|
35029
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34205
35030
|
} catch (err) {
|
|
34206
35031
|
logger.error(`error moving assets: ${err}`);
|
|
34207
|
-
return
|
|
34208
|
-
calls: [],
|
|
34209
|
-
status: false
|
|
34210
|
-
};
|
|
35032
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34211
35033
|
}
|
|
34212
35034
|
}
|
|
34213
35035
|
async handleDeposit() {
|
|
34214
35036
|
try {
|
|
34215
|
-
|
|
34216
|
-
const extendedAdapter = await this.getExtendedAdapter();
|
|
34217
|
-
const avnuAdapter = await this.getAvnuAdapter();
|
|
34218
|
-
if (!vesuAdapter || !extendedAdapter || !extendedAdapter.client || !avnuAdapter) {
|
|
34219
|
-
logger.error(
|
|
34220
|
-
"vesu or extended adapter not found",
|
|
34221
|
-
vesuAdapter,
|
|
34222
|
-
extendedAdapter
|
|
34223
|
-
);
|
|
34224
|
-
return {
|
|
34225
|
-
extendedAmountInBTC: new Web3Number(0, 0),
|
|
34226
|
-
calls: []
|
|
34227
|
-
};
|
|
34228
|
-
}
|
|
34229
|
-
const extendedLeverage = calculateExtendedLevergae();
|
|
34230
|
-
const isPriceDifferenceBetweenAvnuAndExtended = await this.checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter, vesuAdapter, avnuAdapter);
|
|
34231
|
-
if (!isPriceDifferenceBetweenAvnuAndExtended) {
|
|
34232
|
-
logger.error("price difference between avnu and extended doesn't fit the range");
|
|
34233
|
-
return {
|
|
34234
|
-
extendedAmountInBTC: new Web3Number(0, 0),
|
|
34235
|
-
calls: []
|
|
34236
|
-
};
|
|
34237
|
-
}
|
|
34238
|
-
const position = await extendedAdapter.getAllOpenPositions();
|
|
34239
|
-
if (!position) {
|
|
34240
|
-
logger.error("error getting extended position", position);
|
|
34241
|
-
return {
|
|
34242
|
-
extendedAmountInBTC: new Web3Number(0, 0),
|
|
34243
|
-
calls: []
|
|
34244
|
-
};
|
|
34245
|
-
}
|
|
34246
|
-
const extendedPositionValue = position.length > 0 ? parseFloat(position[0].value) : 0;
|
|
34247
|
-
const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
34248
|
-
if (!extendedHoldings) {
|
|
34249
|
-
logger.error(`error getting extended holdings: ${extendedHoldings}`);
|
|
34250
|
-
return {
|
|
34251
|
-
extendedAmountInBTC: new Web3Number(0, 0),
|
|
34252
|
-
calls: []
|
|
34253
|
-
};
|
|
34254
|
-
}
|
|
34255
|
-
const extendedHoldingAmount = new Web3Number(
|
|
34256
|
-
extendedHoldings.availableForWithdrawal,
|
|
34257
|
-
USDC_TOKEN_DECIMALS
|
|
34258
|
-
);
|
|
34259
|
-
const {
|
|
34260
|
-
collateralTokenAmount
|
|
34261
|
-
} = await vesuAdapter.vesuAdapter.getAssetPrices();
|
|
34262
|
-
const { collateralPrice } = await this.getAssetPrices();
|
|
34263
|
-
const { vesuAmountInBTC, extendedAmountInBTC } = calculateVesUPositionSizeGivenExtended(
|
|
34264
|
-
extendedPositionValue,
|
|
34265
|
-
extendedHoldingAmount,
|
|
34266
|
-
collateralTokenAmount,
|
|
34267
|
-
collateralPrice.price
|
|
34268
|
-
);
|
|
34269
|
-
logger.info(`vesuAmountInBTC ${vesuAmountInBTC}, extendedAmountInBTC ${extendedAmountInBTC}`);
|
|
34270
|
-
let calls = [];
|
|
34271
|
-
if (vesuAmountInBTC.greaterThan(MINIMUM_EXTENDED_POSITION_SIZE)) {
|
|
34272
|
-
const proofsInfo = vesuAdapter.getProofs(true, this.getMerkleTree());
|
|
34273
|
-
const proofGroups = proofsInfo.proofs;
|
|
34274
|
-
const call = this.getManageCall(
|
|
34275
|
-
proofGroups,
|
|
34276
|
-
await proofsInfo.callConstructor({
|
|
34277
|
-
amount: vesuAmountInBTC
|
|
34278
|
-
})
|
|
34279
|
-
);
|
|
34280
|
-
const { amount: wbtcAmountInVaultAllocator } = await this.getUnusedBalanceWBTC();
|
|
34281
|
-
if (wbtcAmountInVaultAllocator.lessThan(vesuAmountInBTC)) {
|
|
34282
|
-
logger.info(`WBTC amount in vault allocator is less than vesu amount required in WBTC thus swapping, wbtcAmountInVaultAllocator: ${wbtcAmountInVaultAllocator}, vesuAmountInBTC: ${vesuAmountInBTC}`);
|
|
34283
|
-
const swapProofsInfo = avnuAdapter.getProofs(true, this.getMerkleTree());
|
|
34284
|
-
const swapProofGroups = swapProofsInfo.proofs;
|
|
34285
|
-
const swapCall = this.getManageCall(
|
|
34286
|
-
swapProofGroups,
|
|
34287
|
-
await swapProofsInfo.callConstructor({
|
|
34288
|
-
amount: vesuAmountInBTC
|
|
34289
|
-
})
|
|
34290
|
-
);
|
|
34291
|
-
calls.push(swapCall);
|
|
34292
|
-
}
|
|
34293
|
-
calls.push(call);
|
|
34294
|
-
}
|
|
34295
|
-
const shortPosition = extendedAmountInBTC.multipliedBy(3).abs().greaterThan(MINIMUM_EXTENDED_POSITION_SIZE) ? await extendedAdapter.createOrder(
|
|
34296
|
-
extendedLeverage.toString(),
|
|
34297
|
-
extendedAmountInBTC.toNumber(),
|
|
34298
|
-
"SELL" /* SELL */
|
|
34299
|
-
) : null;
|
|
34300
|
-
if (!shortPosition && extendedAmountInBTC.multipliedBy(3).abs().greaterThan(MINIMUM_EXTENDED_POSITION_SIZE)) {
|
|
34301
|
-
logger.error(`error creating short position thus no position to be opened on vesu: ${shortPosition}`);
|
|
34302
|
-
return {
|
|
34303
|
-
extendedAmountInBTC: new Web3Number(0, 0),
|
|
34304
|
-
calls: []
|
|
34305
|
-
};
|
|
34306
|
-
}
|
|
34307
|
-
return {
|
|
34308
|
-
extendedAmountInBTC,
|
|
34309
|
-
calls
|
|
34310
|
-
};
|
|
35037
|
+
return this.createTransactionResult([], false, { from: Protocols.VAULT.name, to: Protocols.VAULT.name, amount: new Web3Number(0, 0) }, "NONE", "INVESTMENT" /* INVESTMENT */);
|
|
34311
35038
|
} catch (err) {
|
|
34312
35039
|
logger.error(`error handling deposit: ${err}`);
|
|
34313
|
-
return {
|
|
34314
|
-
extendedAmountInBTC: new Web3Number(0, 0),
|
|
34315
|
-
calls: []
|
|
34316
|
-
};
|
|
34317
|
-
;
|
|
35040
|
+
return this.createTransactionResult([], false, { from: Protocols.VAULT.name, to: Protocols.VAULT.name, amount: new Web3Number(0, 0) }, "NONE", "INVESTMENT" /* INVESTMENT */);
|
|
34318
35041
|
}
|
|
34319
35042
|
}
|
|
34320
|
-
|
|
35043
|
+
/**
|
|
35044
|
+
* Check if the price difference between avnu and extended is within the acceptable range to enhance the position size or close the position
|
|
35045
|
+
* @param extendedAdapter - the extended adapter
|
|
35046
|
+
* @param vesuAdapter - the vesu adapter
|
|
35047
|
+
* @param avnuAdapter - the avnu adapter
|
|
35048
|
+
* @param positionType - the position type (open or close)
|
|
35049
|
+
* @returns true if the price difference is within the acceptable range, false otherwise
|
|
35050
|
+
*/
|
|
35051
|
+
async checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter, vesuAdapter, avnuAdapter, positionType) {
|
|
34321
35052
|
const {
|
|
34322
35053
|
ask,
|
|
34323
35054
|
bid
|
|
@@ -34329,13 +35060,30 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34329
35060
|
logger.error(`error getting btc price avnu: ${btcPriceAvnu}`);
|
|
34330
35061
|
return false;
|
|
34331
35062
|
}
|
|
34332
|
-
|
|
34333
|
-
|
|
34334
|
-
|
|
35063
|
+
logger.info(`price: ${price}`);
|
|
35064
|
+
logger.info(`btcPriceAvnu: ${btcPriceAvnu}`);
|
|
35065
|
+
const priceDifference = new Web3Number(price.minus(btcPriceAvnu).toFixed(2), 0);
|
|
35066
|
+
logger.info(`priceDifference: ${priceDifference}`);
|
|
35067
|
+
if (priceDifference.isNegative()) {
|
|
35068
|
+
return false;
|
|
35069
|
+
}
|
|
35070
|
+
if (positionType === "open" /* OPEN */) {
|
|
35071
|
+
logger.info(`price difference between avnu and extended for open position: ${priceDifference.toNumber()}, minimumExtendedPriceDifferenceForSwapOpen: ${avnuAdapter.config.minimumExtendedPriceDifferenceForSwapOpen}`);
|
|
35072
|
+
const result = priceDifference.greaterThanOrEqualTo(avnuAdapter.config.minimumExtendedPriceDifferenceForSwapOpen);
|
|
35073
|
+
logger.info(`result: ${result}`);
|
|
35074
|
+
return result;
|
|
35075
|
+
} else {
|
|
35076
|
+
logger.info(`price difference between avnu and extended for close position: ${priceDifference.toNumber()}, maximumExtendedPriceDifferenceForSwapClosing: ${avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing}`);
|
|
35077
|
+
const result = priceDifference.lessThanOrEqualTo(avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing);
|
|
35078
|
+
logger.info(`result: ${result}`);
|
|
35079
|
+
return result;
|
|
34335
35080
|
}
|
|
34336
|
-
logger.error(`price difference between avnu and extended doesn't fit the range, priceDifference: ${priceDifference}`);
|
|
34337
|
-
return false;
|
|
34338
35081
|
}
|
|
35082
|
+
/**
|
|
35083
|
+
* Handle the withdrawal of assets from the vault
|
|
35084
|
+
* @param amount - the amount to withdraw in USDC
|
|
35085
|
+
* @returns the calls to be executed and the status of the calls generated along with the metadata for the calls
|
|
35086
|
+
*/
|
|
34339
35087
|
async handleWithdraw(amount) {
|
|
34340
35088
|
try {
|
|
34341
35089
|
const usdcBalanceVaultAllocator = await this.getUnusedBalance();
|
|
@@ -34347,12 +35095,8 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34347
35095
|
const withdrawCall2 = await this.getBringLiquidityCall({
|
|
34348
35096
|
amount: usdcBalanceVaultAllocator.amount
|
|
34349
35097
|
});
|
|
34350
|
-
logger.info("withdraw call", withdrawCall2);
|
|
34351
35098
|
calls.push(withdrawCall2);
|
|
34352
|
-
return {
|
|
34353
|
-
calls,
|
|
34354
|
-
status: true
|
|
34355
|
-
};
|
|
35099
|
+
return [this.createTransactionResult(calls, true, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount }, "WITHDRAWAL", "WITHDRAWAL" /* WITHDRAWAL */)];
|
|
34356
35100
|
}
|
|
34357
35101
|
const vesuAdapter = await this.getVesuAdapter();
|
|
34358
35102
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
@@ -34361,11 +35105,9 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34361
35105
|
logger.error(
|
|
34362
35106
|
`vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
|
|
34363
35107
|
);
|
|
34364
|
-
return {
|
|
34365
|
-
calls,
|
|
34366
|
-
status
|
|
34367
|
-
};
|
|
35108
|
+
return [this.createTransactionResult(calls, status, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount }, "NONE", "WITHDRAWAL" /* WITHDRAWAL */)];
|
|
34368
35109
|
}
|
|
35110
|
+
let transactionResults = [];
|
|
34369
35111
|
const { collateralTokenAmount } = await vesuAdapter.vesuAdapter.getAssetPrices();
|
|
34370
35112
|
const {
|
|
34371
35113
|
collateralPrice
|
|
@@ -34374,10 +35116,7 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34374
35116
|
if (!extendedPositon) {
|
|
34375
35117
|
status = false;
|
|
34376
35118
|
logger.error("error getting extended position", extendedPositon);
|
|
34377
|
-
return {
|
|
34378
|
-
calls,
|
|
34379
|
-
status
|
|
34380
|
-
};
|
|
35119
|
+
return [this.createTransactionResult(calls, status, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount }, "NONE", "WITHDRAWAL" /* WITHDRAWAL */)];
|
|
34381
35120
|
}
|
|
34382
35121
|
const amountDistributionForWithdrawal = await calculateAmountDistributionForWithdrawal(
|
|
34383
35122
|
usdcBalanceDifference,
|
|
@@ -34390,61 +35129,70 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34390
35129
|
logger.error(
|
|
34391
35130
|
`error calculating amount distribution for withdrawal: ${amountDistributionForWithdrawal}`
|
|
34392
35131
|
);
|
|
34393
|
-
return {
|
|
34394
|
-
calls,
|
|
34395
|
-
status
|
|
34396
|
-
};
|
|
35132
|
+
return [this.createTransactionResult(calls, status, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount }, "NONE", "WITHDRAWAL" /* WITHDRAWAL */)];
|
|
34397
35133
|
}
|
|
34398
35134
|
const { vesu_amount, extended_amount } = amountDistributionForWithdrawal;
|
|
34399
35135
|
if (status && vesu_amount.greaterThan(0)) {
|
|
34400
|
-
const { calls: vesuCalls, status: vesuStatus } = await this.moveAssets(
|
|
35136
|
+
const { calls: vesuCalls, status: vesuStatus, transactionMetadata: vesuTransactionMetadata } = await this.moveAssets(
|
|
34401
35137
|
{
|
|
34402
35138
|
amount: vesu_amount,
|
|
34403
35139
|
from: Protocols.VESU.name,
|
|
34404
|
-
to: Protocols.VAULT.name
|
|
35140
|
+
to: Protocols.VAULT.name,
|
|
35141
|
+
cycleType: "WITHDRAWAL" /* WITHDRAWAL */
|
|
34405
35142
|
},
|
|
34406
35143
|
extendedAdapter,
|
|
34407
35144
|
vesuAdapter
|
|
34408
35145
|
);
|
|
34409
35146
|
status = vesuStatus;
|
|
34410
|
-
|
|
35147
|
+
transactionResults.push({
|
|
35148
|
+
status: vesuStatus,
|
|
35149
|
+
calls: vesuCalls,
|
|
35150
|
+
transactionMetadata: vesuTransactionMetadata
|
|
35151
|
+
});
|
|
34411
35152
|
}
|
|
34412
35153
|
if (status && extended_amount.greaterThan(0)) {
|
|
34413
|
-
const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
|
|
35154
|
+
const { calls: extendedCalls, status: extendedStatus, transactionMetadata: extendedTransactionMetadata } = await this.moveAssets(
|
|
34414
35155
|
{
|
|
34415
35156
|
amount: extended_amount,
|
|
34416
35157
|
from: Protocols.EXTENDED.name,
|
|
34417
|
-
to: Protocols.VAULT.name
|
|
35158
|
+
to: Protocols.VAULT.name,
|
|
35159
|
+
cycleType: "WITHDRAWAL" /* WITHDRAWAL */
|
|
34418
35160
|
},
|
|
34419
35161
|
extendedAdapter,
|
|
34420
35162
|
vesuAdapter
|
|
34421
35163
|
);
|
|
34422
35164
|
status = extendedStatus;
|
|
34423
35165
|
if (status) {
|
|
34424
|
-
|
|
35166
|
+
transactionResults.push({
|
|
35167
|
+
status: extendedStatus,
|
|
35168
|
+
calls: extendedCalls,
|
|
35169
|
+
transactionMetadata: extendedTransactionMetadata
|
|
35170
|
+
});
|
|
34425
35171
|
} else {
|
|
34426
35172
|
logger.error("error moving assets to vault: extendedStatus: ${extendedStatus}");
|
|
34427
|
-
return {
|
|
34428
|
-
calls: [],
|
|
34429
|
-
status
|
|
34430
|
-
};
|
|
35173
|
+
return [this.createTransactionResult([], status, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount }, "NONE", "WITHDRAWAL" /* WITHDRAWAL */)];
|
|
34431
35174
|
}
|
|
34432
35175
|
}
|
|
34433
35176
|
const withdrawCall = await this.getBringLiquidityCall({
|
|
34434
35177
|
amount
|
|
34435
35178
|
});
|
|
34436
35179
|
logger.info("withdraw call", withdrawCall);
|
|
34437
|
-
|
|
34438
|
-
|
|
34439
|
-
calls,
|
|
34440
|
-
|
|
34441
|
-
|
|
35180
|
+
transactionResults.push({
|
|
35181
|
+
status,
|
|
35182
|
+
calls: [withdrawCall],
|
|
35183
|
+
transactionMetadata: {
|
|
35184
|
+
protocolFrom: Protocols.VAULT.name,
|
|
35185
|
+
protocolTo: Protocols.NONE.name,
|
|
35186
|
+
transactionType: "WITHDRAWAL",
|
|
35187
|
+
usdAmount: amount.toFixed(),
|
|
35188
|
+
status: "PENDING",
|
|
35189
|
+
cycleType: "WITHDRAWAL" /* WITHDRAWAL */
|
|
35190
|
+
}
|
|
35191
|
+
});
|
|
35192
|
+
return transactionResults;
|
|
34442
35193
|
} catch (err) {
|
|
34443
35194
|
logger.error(`error handling withdrawal: ${err}`);
|
|
34444
|
-
return {
|
|
34445
|
-
calls: [],
|
|
34446
|
-
status: false
|
|
34447
|
-
};
|
|
35195
|
+
return [this.createTransactionResult([], false, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount }, "NONE", "WITHDRAWAL" /* WITHDRAWAL */)];
|
|
34448
35196
|
}
|
|
34449
35197
|
}
|
|
34450
35198
|
async getAUM() {
|
|
@@ -34491,8 +35239,182 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34491
35239
|
splits: [realAUM, estimatedAUMDelta]
|
|
34492
35240
|
};
|
|
34493
35241
|
}
|
|
35242
|
+
async processTransactionDataFromSDK(txnData) {
|
|
35243
|
+
try {
|
|
35244
|
+
const txnsToBeExecuted = txnData.filter((txn) => {
|
|
35245
|
+
return txn.transactionMetadata.transactionType !== "NONE" && txn.transactionMetadata.protocolFrom !== "" && txn.transactionMetadata.protocolTo !== "";
|
|
35246
|
+
});
|
|
35247
|
+
const callsToBeExecutedFinal = txnsToBeExecuted.flatMap((txn) => txn.calls);
|
|
35248
|
+
const txnMetadata = txnsToBeExecuted.map((txn) => txn.transactionMetadata);
|
|
35249
|
+
return { callsToBeExecutedFinal, txnMetadata };
|
|
35250
|
+
} catch (err) {
|
|
35251
|
+
logger.error(`error processing transaction data from SDK: ${err}`);
|
|
35252
|
+
return null;
|
|
35253
|
+
}
|
|
35254
|
+
}
|
|
35255
|
+
async processTransactionMetadata(txnMetadata, extendedIntentFulfilled) {
|
|
35256
|
+
try {
|
|
35257
|
+
const txnMetadataNew = txnMetadata.map((txn) => {
|
|
35258
|
+
const isExtendedProtocol = txn.protocolFrom === Protocols.EXTENDED.name || txn.protocolTo === Protocols.EXTENDED.name;
|
|
35259
|
+
if (isExtendedProtocol) {
|
|
35260
|
+
txn.status = extendedIntentFulfilled ? "COMPLETED" : "PENDING";
|
|
35261
|
+
} else {
|
|
35262
|
+
txn.status = "COMPLETED";
|
|
35263
|
+
}
|
|
35264
|
+
return txn;
|
|
35265
|
+
});
|
|
35266
|
+
return txnMetadataNew;
|
|
35267
|
+
} catch (err) {
|
|
35268
|
+
logger.error(`error processing transaction data from SDK: ${err}`);
|
|
35269
|
+
return null;
|
|
35270
|
+
}
|
|
35271
|
+
}
|
|
35272
|
+
async getMaxBorrowableAmount() {
|
|
35273
|
+
const vesuAdapter = await this.getVesuAdapter();
|
|
35274
|
+
const extendedAdapter = await this.getExtendedAdapter();
|
|
35275
|
+
if (!vesuAdapter || !extendedAdapter) {
|
|
35276
|
+
return new Web3Number(0, 0);
|
|
35277
|
+
}
|
|
35278
|
+
const extendedFundingRate = new Web3Number((await extendedAdapter.getNetAPY()).toFixed(4), 0);
|
|
35279
|
+
const extendedPositions = await extendedAdapter.getAllOpenPositions();
|
|
35280
|
+
if (!extendedPositions || extendedPositions.length === 0) {
|
|
35281
|
+
logger.info(`no extended positions found`);
|
|
35282
|
+
return new Web3Number(0, 0);
|
|
35283
|
+
}
|
|
35284
|
+
const extendePositionSizeUSD = new Web3Number(extendedPositions[0].value || 0, 0);
|
|
35285
|
+
const vesuPositions = await vesuAdapter.getPositions();
|
|
35286
|
+
const vesuSupplyApy = vesuPositions[0].apy.apy;
|
|
35287
|
+
const vesuCollateralSizeUSD = new Web3Number(vesuPositions[0].usdValue.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS);
|
|
35288
|
+
const vesuDebtSizeUSD = new Web3Number(vesuPositions[1].usdValue.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS);
|
|
35289
|
+
const num1 = extendePositionSizeUSD.multipliedBy(extendedFundingRate);
|
|
35290
|
+
const num22 = vesuCollateralSizeUSD.multipliedBy(vesuSupplyApy);
|
|
35291
|
+
const num32 = vesuDebtSizeUSD.abs();
|
|
35292
|
+
const maxBorrowApy = num1.plus(num22).minus(0.1).dividedBy(num32);
|
|
35293
|
+
const vesuMaxBorrowableAmount = await vesuAdapter.vesuAdapter.getMaxBorrowableByInterestRate(this.config, vesuAdapter.config.debt, maxBorrowApy.toNumber());
|
|
35294
|
+
return new Web3Number(vesuMaxBorrowableAmount.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS);
|
|
35295
|
+
}
|
|
35296
|
+
async getVesuHealthFactors() {
|
|
35297
|
+
const vesuAdapter = await this.getVesuAdapter();
|
|
35298
|
+
const extendedAdapter = await this.getExtendedAdapter();
|
|
35299
|
+
if (!vesuAdapter || !extendedAdapter) {
|
|
35300
|
+
return [0, 0];
|
|
35301
|
+
}
|
|
35302
|
+
const vesuPositions = await vesuAdapter.getPositions();
|
|
35303
|
+
const vesuCollateralSizeUSD = new Web3Number(vesuPositions[0].usdValue.toFixed(USDC_TOKEN_DECIMALS), 0);
|
|
35304
|
+
const vesuDebtSizeUSD = new Web3Number(vesuPositions[1].usdValue.toFixed(USDC_TOKEN_DECIMALS), 0);
|
|
35305
|
+
const actualLtv = vesuDebtSizeUSD.dividedBy(vesuCollateralSizeUSD).abs();
|
|
35306
|
+
logger.info(`actualLtv: ${actualLtv.toNumber()}`);
|
|
35307
|
+
const maxLtv = new Web3Number(await vesuAdapter.vesuAdapter.getLTVConfig(this.config), 4);
|
|
35308
|
+
const healthFactor = new Web3Number(maxLtv.dividedBy(actualLtv).toFixed(4), 4);
|
|
35309
|
+
logger.info(`healthFactor: ${healthFactor.toNumber()}`);
|
|
35310
|
+
const extendedBalance = await extendedAdapter.getExtendedDepositAmount();
|
|
35311
|
+
if (!extendedBalance) {
|
|
35312
|
+
return [0, 0];
|
|
35313
|
+
}
|
|
35314
|
+
const extendedLeverage = new Web3Number((Number(extendedBalance.marginRatio) * 100).toFixed(4), 4);
|
|
35315
|
+
logger.info(`extendedLeverage: ${extendedLeverage.toNumber()}`);
|
|
35316
|
+
return [healthFactor.toNumber(), extendedLeverage.toNumber()];
|
|
35317
|
+
}
|
|
35318
|
+
async netAPY() {
|
|
35319
|
+
const allPositions = [];
|
|
35320
|
+
for (let adapter of this.metadata.additionalInfo.adapters) {
|
|
35321
|
+
if (adapter.adapter.name !== ExtendedAdapter.name) {
|
|
35322
|
+
let positions = await adapter.adapter.getPositions();
|
|
35323
|
+
if (positions.length > 0) {
|
|
35324
|
+
allPositions.push(...positions);
|
|
35325
|
+
}
|
|
35326
|
+
}
|
|
35327
|
+
}
|
|
35328
|
+
const extendedAdapter = await this.getExtendedAdapter();
|
|
35329
|
+
if (!extendedAdapter) {
|
|
35330
|
+
return {
|
|
35331
|
+
net: 0,
|
|
35332
|
+
splits: []
|
|
35333
|
+
};
|
|
35334
|
+
}
|
|
35335
|
+
let vesuPositions = allPositions.filter((item) => item.protocol === Protocols.VESU);
|
|
35336
|
+
vesuPositions.map((item) => {
|
|
35337
|
+
item.apy.apy = item.apy.apy * 0.1;
|
|
35338
|
+
});
|
|
35339
|
+
const extendedPositions = await extendedAdapter.getAllOpenPositions();
|
|
35340
|
+
const usdcToken = Global.getDefaultTokens().find((token) => token.symbol === "USDC");
|
|
35341
|
+
if (!extendedPositions || !usdcToken) {
|
|
35342
|
+
return {
|
|
35343
|
+
net: 0,
|
|
35344
|
+
splits: []
|
|
35345
|
+
};
|
|
35346
|
+
}
|
|
35347
|
+
const extendedPosition = extendedPositions[0] || 0;
|
|
35348
|
+
const extendedEquity = (await extendedAdapter.getExtendedDepositAmount())?.equity || 0;
|
|
35349
|
+
const extendedApy = await extendedAdapter.getNetAPY();
|
|
35350
|
+
const totalHoldingsUSDValue = allPositions.reduce((acc, curr) => acc + curr.usdValue, 0) + Number(extendedEquity);
|
|
35351
|
+
console.log(totalHoldingsUSDValue);
|
|
35352
|
+
const extendedPositionSizeMultipliedByApy = Number(extendedPosition.value) * extendedApy;
|
|
35353
|
+
let weightedAPYs = allPositions.reduce((acc, curr) => acc + curr.apy.apy * curr.usdValue, 0) + extendedPositionSizeMultipliedByApy;
|
|
35354
|
+
console.log(weightedAPYs);
|
|
35355
|
+
const netAPY = weightedAPYs / totalHoldingsUSDValue;
|
|
35356
|
+
console.log(netAPY);
|
|
35357
|
+
allPositions.push({
|
|
35358
|
+
tokenInfo: usdcToken,
|
|
35359
|
+
amount: new Web3Number(extendedPosition.size, 0),
|
|
35360
|
+
usdValue: Number(extendedEquity),
|
|
35361
|
+
apy: { apy: extendedApy, type: "base" /* BASE */ },
|
|
35362
|
+
remarks: "finalised" /* FINALISED */,
|
|
35363
|
+
protocol: Protocols.EXTENDED
|
|
35364
|
+
});
|
|
35365
|
+
return {
|
|
35366
|
+
net: netAPY,
|
|
35367
|
+
splits: allPositions.map((p) => ({ apy: p.apy.apy, id: p.remarks ?? "" }))
|
|
35368
|
+
};
|
|
35369
|
+
}
|
|
35370
|
+
async getWalletHoldings() {
|
|
35371
|
+
const usdceToken = Global.getDefaultTokens().find((token) => token.symbol === "USDCe");
|
|
35372
|
+
const wbtcToken = Global.getDefaultTokens().find((token) => token.symbol === "WBTC");
|
|
35373
|
+
const usdcToken = Global.getDefaultTokens().find((token) => token.symbol === "USDC");
|
|
35374
|
+
if (!usdceToken || !wbtcToken || !usdcToken) {
|
|
35375
|
+
return [];
|
|
35376
|
+
}
|
|
35377
|
+
const walletAddress = this.metadata.additionalInfo.walletAddress;
|
|
35378
|
+
const usdceWalletBalance = await new ERC20(this.config).balanceOf(
|
|
35379
|
+
usdceToken.address,
|
|
35380
|
+
walletAddress,
|
|
35381
|
+
usdceToken.decimals
|
|
35382
|
+
);
|
|
35383
|
+
const usdcWalletBalance = await new ERC20(this.config).balanceOf(
|
|
35384
|
+
usdcToken.address,
|
|
35385
|
+
walletAddress,
|
|
35386
|
+
usdcToken.decimals
|
|
35387
|
+
);
|
|
35388
|
+
const wbtcWalletBalance = await new ERC20(this.config).balanceOf(
|
|
35389
|
+
wbtcToken.address,
|
|
35390
|
+
walletAddress,
|
|
35391
|
+
wbtcToken.decimals
|
|
35392
|
+
);
|
|
35393
|
+
const price = await this.pricer.getPrice(usdceToken.symbol);
|
|
35394
|
+
const wbtcPrice = await this.pricer.getPrice(wbtcToken.symbol);
|
|
35395
|
+
const usdceUsdValue = Number(usdceWalletBalance.toFixed(usdceToken.decimals)) * price.price;
|
|
35396
|
+
const usdcUsdValue = Number(usdcWalletBalance.toFixed(usdcToken.decimals)) * price.price;
|
|
35397
|
+
const wbtcUsdValue = Number(wbtcWalletBalance.toFixed(wbtcToken.decimals)) * wbtcPrice.price;
|
|
35398
|
+
return [
|
|
35399
|
+
{
|
|
35400
|
+
tokenInfo: usdceToken,
|
|
35401
|
+
amount: usdceWalletBalance,
|
|
35402
|
+
usdValue: usdceUsdValue
|
|
35403
|
+
},
|
|
35404
|
+
{
|
|
35405
|
+
tokenInfo: usdcToken,
|
|
35406
|
+
amount: usdcWalletBalance,
|
|
35407
|
+
usdValue: usdcUsdValue
|
|
35408
|
+
},
|
|
35409
|
+
{
|
|
35410
|
+
tokenInfo: wbtcToken,
|
|
35411
|
+
amount: wbtcWalletBalance,
|
|
35412
|
+
usdValue: wbtcUsdValue
|
|
35413
|
+
}
|
|
35414
|
+
];
|
|
35415
|
+
}
|
|
34494
35416
|
};
|
|
34495
|
-
function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1,
|
|
35417
|
+
function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing) {
|
|
34496
35418
|
vaultSettings.leafAdapters = [];
|
|
34497
35419
|
const wbtcToken = Global.getDefaultTokens().find(
|
|
34498
35420
|
(token) => token.symbol === lstSymbol
|
|
@@ -34516,7 +35438,9 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
34516
35438
|
...baseAdapterConfig,
|
|
34517
35439
|
avnuContract: AVNU_MIDDLEWARE,
|
|
34518
35440
|
slippage: 0.01,
|
|
34519
|
-
baseUrl: AVNU_QUOTE_URL
|
|
35441
|
+
baseUrl: AVNU_QUOTE_URL,
|
|
35442
|
+
minimumExtendedPriceDifferenceForSwapOpen,
|
|
35443
|
+
maximumExtendedPriceDifferenceForSwapClosing
|
|
34520
35444
|
});
|
|
34521
35445
|
const extendedAdapter = new ExtendedAdapter({
|
|
34522
35446
|
...baseAdapterConfig,
|
|
@@ -34525,14 +35449,17 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
34525
35449
|
],
|
|
34526
35450
|
vaultIdExtended,
|
|
34527
35451
|
extendedContract: EXTENDED_CONTRACT,
|
|
34528
|
-
|
|
34529
|
-
|
|
35452
|
+
extendedBackendWriteUrl,
|
|
35453
|
+
extendedBackendReadUrl,
|
|
34530
35454
|
extendedTimeout: 3e4,
|
|
34531
35455
|
extendedRetries: 3,
|
|
34532
35456
|
extendedBaseUrl: "https://api.starknet.extended.exchange",
|
|
34533
35457
|
extendedMarketName: "BTC-USD",
|
|
34534
35458
|
extendedPrecision: 5,
|
|
34535
|
-
avnuAdapter
|
|
35459
|
+
avnuAdapter,
|
|
35460
|
+
retryDelayForOrderStatus: minimumExtendedRetriesDelayForOrderStatus ?? 3e3,
|
|
35461
|
+
minimumExtendedMovementAmount: minimumExtendedMovementAmount ?? 5
|
|
35462
|
+
//5 usdcs
|
|
34536
35463
|
});
|
|
34537
35464
|
const vesuMultiplyAdapter = new VesuMultiplyAdapter({
|
|
34538
35465
|
poolId: pool1,
|
|
@@ -34545,7 +35472,9 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
34545
35472
|
supportedPositions: [
|
|
34546
35473
|
{ asset: wbtcToken, isDebt: false },
|
|
34547
35474
|
{ asset: usdcToken, isDebt: true }
|
|
34548
|
-
]
|
|
35475
|
+
],
|
|
35476
|
+
minimumVesuMovementAmount: minimumVesuMovementAmount ?? 5
|
|
35477
|
+
//5 usdc
|
|
34549
35478
|
});
|
|
34550
35479
|
const unusedBalanceAdapter = new UnusedBalanceAdapter({
|
|
34551
35480
|
...baseAdapterConfig
|
|
@@ -34641,11 +35570,11 @@ function VaultDescription2(lstSymbol, underlyingSymbol) {
|
|
|
34641
35570
|
] });
|
|
34642
35571
|
}
|
|
34643
35572
|
var re7UsdcPrimeDevansh = {
|
|
34644
|
-
vaultAddress: ContractAddr.from("
|
|
34645
|
-
manager: ContractAddr.from("
|
|
34646
|
-
vaultAllocator: ContractAddr.from("
|
|
34647
|
-
redeemRequestNFT: ContractAddr.from("
|
|
34648
|
-
aumOracle: ContractAddr.from("
|
|
35573
|
+
vaultAddress: ContractAddr.from("0x058905be22d6a81792df79425dc9641cf3e1b77f36748631b7d7e5d713a32b55"),
|
|
35574
|
+
manager: ContractAddr.from("0x02648d703783feb2d967cf0520314cb5aa800d69a9426f3e3b317395af44de16"),
|
|
35575
|
+
vaultAllocator: ContractAddr.from("0x07d533c838eab6a4d854dd3aea96a55993fccd35821921970d00bde946b63b6f"),
|
|
35576
|
+
redeemRequestNFT: ContractAddr.from("0x01ef91f08fb99729c00f82fc6e0ece37917bcc43952596c19996259dc8adbbba"),
|
|
35577
|
+
aumOracle: ContractAddr.from("0x030b6acfec162f5d6e72b8a4d2798aedce78fb39de78a8f549f7cd277ae8bc8d"),
|
|
34649
35578
|
leafAdapters: [],
|
|
34650
35579
|
adapters: [],
|
|
34651
35580
|
targetHealthFactor: 1.4,
|
|
@@ -34658,14 +35587,15 @@ var re7UsdcPrimeDevansh = {
|
|
|
34658
35587
|
Global.getDefaultTokens().find((token) => token.symbol === "WBTC").decimals
|
|
34659
35588
|
),
|
|
34660
35589
|
borrowable_assets: [Global.getDefaultTokens().find((token) => token.symbol === "WBTC")],
|
|
34661
|
-
minimumWBTCDifferenceForAvnuSwap: MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP
|
|
35590
|
+
minimumWBTCDifferenceForAvnuSwap: MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP,
|
|
35591
|
+
walletAddress: WALLET_ADDRESS
|
|
34662
35592
|
};
|
|
34663
|
-
var VesuExtendedTestStrategies = (
|
|
35593
|
+
var VesuExtendedTestStrategies = (extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing) => {
|
|
34664
35594
|
return [
|
|
34665
|
-
getStrategySettingsVesuExtended("WBTC", "USDC", re7UsdcPrimeDevansh, false, false,
|
|
35595
|
+
getStrategySettingsVesuExtended("WBTC", "USDC", re7UsdcPrimeDevansh, false, false, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing)
|
|
34666
35596
|
];
|
|
34667
35597
|
};
|
|
34668
|
-
function getStrategySettingsVesuExtended(lstSymbol, underlyingSymbol, addresses, isPreview = false, isLST,
|
|
35598
|
+
function getStrategySettingsVesuExtended(lstSymbol, underlyingSymbol, addresses, isPreview = false, isLST, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing) {
|
|
34669
35599
|
return {
|
|
34670
35600
|
name: `Extended Test ${underlyingSymbol}`,
|
|
34671
35601
|
description: getDescription2(lstSymbol, underlyingSymbol),
|
|
@@ -34673,7 +35603,7 @@ function getStrategySettingsVesuExtended(lstSymbol, underlyingSymbol, addresses,
|
|
|
34673
35603
|
launchBlock: 0,
|
|
34674
35604
|
type: "Other",
|
|
34675
35605
|
depositTokens: [Global.getDefaultTokens().find((token) => token.symbol === underlyingSymbol)],
|
|
34676
|
-
additionalInfo: getLooperSettings2(lstSymbol, underlyingSymbol, addresses, VesuPools.Re7USDCPrime,
|
|
35606
|
+
additionalInfo: getLooperSettings2(lstSymbol, underlyingSymbol, addresses, VesuPools.Re7USDCPrime, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing),
|
|
34677
35607
|
risk: {
|
|
34678
35608
|
riskFactor: _riskFactor3,
|
|
34679
35609
|
netRisk: _riskFactor3.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor3.reduce((acc, curr) => acc + curr.weight, 0),
|
|
@@ -38358,11 +39288,13 @@ export {
|
|
|
38358
39288
|
AssetOperationStatus,
|
|
38359
39289
|
AssetOperationType,
|
|
38360
39290
|
AutoCompounderSTRK,
|
|
39291
|
+
AvnuAdapter,
|
|
38361
39292
|
AvnuWrapper,
|
|
38362
39293
|
BaseAdapter,
|
|
38363
39294
|
BaseStrategy,
|
|
38364
39295
|
CommonAdapter,
|
|
38365
39296
|
ContractAddr,
|
|
39297
|
+
CycleType,
|
|
38366
39298
|
ERC20,
|
|
38367
39299
|
EXTENDED_CONTRACT,
|
|
38368
39300
|
EXTENDED_SANITIZER,
|
|
@@ -38389,6 +39321,7 @@ export {
|
|
|
38389
39321
|
OrderType,
|
|
38390
39322
|
PRICE_ROUTER,
|
|
38391
39323
|
PositionSide,
|
|
39324
|
+
PositionTypeAvnuExtended,
|
|
38392
39325
|
Pragma,
|
|
38393
39326
|
Pricer,
|
|
38394
39327
|
PricerBase,
|
|
@@ -38432,6 +39365,7 @@ export {
|
|
|
38432
39365
|
calculateExtendedLevergae,
|
|
38433
39366
|
calculateVesUPositionSizeGivenExtended,
|
|
38434
39367
|
calculateVesuLeverage,
|
|
39368
|
+
calculateWBTCAmountToMaintainLTV,
|
|
38435
39369
|
extensionMap,
|
|
38436
39370
|
getContractDetails,
|
|
38437
39371
|
getFAQs,
|