@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.mjs
CHANGED
|
@@ -4328,20 +4328,13 @@ var EkuboQuoter = class _EkuboQuoter {
|
|
|
4328
4328
|
async getDexPrice(baseToken, quoteToken, amount) {
|
|
4329
4329
|
const lstTokenInfo = baseToken;
|
|
4330
4330
|
const lstUnderlyingTokenInfo = quoteToken;
|
|
4331
|
-
console.log("lstTokenInfo", lstTokenInfo);
|
|
4332
|
-
console.log("lstUnderlyingTokenInfo", lstUnderlyingTokenInfo);
|
|
4333
|
-
console.log("amount", amount);
|
|
4334
4331
|
const quote = await this.getQuote(
|
|
4335
4332
|
lstTokenInfo.address.address,
|
|
4336
4333
|
lstUnderlyingTokenInfo.address.address,
|
|
4337
4334
|
amount
|
|
4338
4335
|
);
|
|
4339
|
-
console.log("quote", quote);
|
|
4340
4336
|
const outputAmount = Web3Number.fromWei(quote.total_calculated, lstUnderlyingTokenInfo.decimals);
|
|
4341
|
-
console.log("outputAmount", outputAmount);
|
|
4342
|
-
console.log("amount", amount);
|
|
4343
4337
|
const price = outputAmount.toNumber() / amount.toNumber();
|
|
4344
|
-
console.log("price", price);
|
|
4345
4338
|
logger.verbose(`${_EkuboQuoter.name}:: LST Dex Price: ${price}`);
|
|
4346
4339
|
return price;
|
|
4347
4340
|
}
|
|
@@ -4360,16 +4353,12 @@ var EkuboQuoter = class _EkuboQuoter {
|
|
|
4360
4353
|
// debt collateral
|
|
4361
4354
|
async getSwapLimitAmount(fromToken, toToken, amount, max_slippage = 2e-3) {
|
|
4362
4355
|
const isExactAmountIn = amount.greaterThanOrEqualTo(0);
|
|
4363
|
-
console.log("isExactAmountIn", isExactAmountIn);
|
|
4364
4356
|
logger.verbose(`${_EkuboQuoter.name}::getSwapLimitAmount isExactAmountIn: ${isExactAmountIn}, fromToken: ${fromToken.symbol}, toToken: ${toToken.symbol}, amount: ${amount}`);
|
|
4365
4357
|
const isYieldToken = this.tokenMarketData.isAPYSupported(toToken);
|
|
4366
4358
|
console.log("isYieldToken", isYieldToken);
|
|
4367
4359
|
const baseToken = isExactAmountIn ? toToken : fromToken;
|
|
4368
4360
|
const quoteToken = isExactAmountIn ? fromToken : toToken;
|
|
4369
|
-
console.log("baseToken", baseToken);
|
|
4370
|
-
console.log("quoteToken", quoteToken);
|
|
4371
4361
|
const dexPrice = await this.getDexPrice(baseToken, quoteToken, amount);
|
|
4372
|
-
console.log("dexPrice", dexPrice);
|
|
4373
4362
|
const trueExchangeRate = isYieldToken ? await this.tokenMarketData.getTruePrice(baseToken) : dexPrice;
|
|
4374
4363
|
console.log("trueExchangeRate", trueExchangeRate);
|
|
4375
4364
|
if (isExactAmountIn) {
|
|
@@ -4400,7 +4389,6 @@ var EkuboQuoter = class _EkuboQuoter {
|
|
|
4400
4389
|
return quote.splits.map((split) => {
|
|
4401
4390
|
const isNegativeAmount = BigInt(split.amount_specified) <= 0n;
|
|
4402
4391
|
const token = isNegativeAmount ? toTokenInfo : fromTokenInfo;
|
|
4403
|
-
console.log("token for withdrawal", token, isNegativeAmount);
|
|
4404
4392
|
return {
|
|
4405
4393
|
route: split.route.map((_route) => ({
|
|
4406
4394
|
pool_key: {
|
|
@@ -27077,11 +27065,6 @@ var VesuAdapter = class _VesuAdapter extends CacheClass {
|
|
|
27077
27065
|
if (!this.pricer) {
|
|
27078
27066
|
throw new Error("Pricer is not initialized");
|
|
27079
27067
|
}
|
|
27080
|
-
const CACHE_KEY = `positions_${blockNumber}_${this.config.poolId.shortString()}_${this.config.collateral.symbol}_${this.config.debt.symbol}`;
|
|
27081
|
-
const cacheData = this.getCache(CACHE_KEY);
|
|
27082
|
-
if (cacheData) {
|
|
27083
|
-
return cacheData;
|
|
27084
|
-
}
|
|
27085
27068
|
const { contract, isV2 } = this.getVesuSingletonContract(config, this.config.poolId);
|
|
27086
27069
|
const output = await contract.call(isV2 ? "position" : "position_unsafe", [
|
|
27087
27070
|
...isV2 ? [] : [this.config.poolId.address],
|
|
@@ -27107,7 +27090,6 @@ var VesuAdapter = class _VesuAdapter extends CacheClass {
|
|
|
27107
27090
|
usdValue: debtAmount.multipliedBy(token2Price.price).toNumber(),
|
|
27108
27091
|
remarks: "Debt"
|
|
27109
27092
|
}];
|
|
27110
|
-
this.setCache(CACHE_KEY, value, 6e4);
|
|
27111
27093
|
return value.map((v) => ({ ...v, protocol: Protocols.VESU }));
|
|
27112
27094
|
}
|
|
27113
27095
|
async getCollateralization(config, blockNumber = "latest") {
|
|
@@ -28030,15 +28012,14 @@ var MAX_PRICE_DROP_PERCENTAGE = Number(process.env.MAX_PRICE_DROP_PERCENTAGE ??
|
|
|
28030
28012
|
var MAX_LTV_BTC_USDC = 0.8428;
|
|
28031
28013
|
var MAX_LIQUIDATION_RATIO = 0.86;
|
|
28032
28014
|
var VAULT_ID_EXTENDED = process.env.VAULT_ID_EXTENDED ?? 220774;
|
|
28033
|
-
var WALLET_ADDRESS = process.env.WALLET_ADDRESS ?? "
|
|
28034
|
-
var TESTNET_WALLET_ADDRESS = process.env.TESTNET_WALLET_ADDRESS ?? "0x07b84bb6E87588BdAde0bfe6173A615b3C220F9C3803456aE183C50EA1d15Ba1";
|
|
28035
|
-
var TEST_WALLET_2 = process.env.TEST_WALLET_2 ?? "0x004C1bdC61DAc7947F3C93d0163d660012E2aB0521567f7155fcf502848791A7";
|
|
28015
|
+
var WALLET_ADDRESS = process.env.WALLET_ADDRESS ?? "0x007E24592287427aaE9d291770B17d582E8A45f3aE54228F998793Ec769B7D13";
|
|
28036
28016
|
var STRK_API_TEST_RPC = process.env.STRK_API_TEST_RPC ?? "https://sepolia.starknet.a5a.ch";
|
|
28037
28017
|
var STRK_API_RPC = process.env.STRK_API_RPC ?? "https://mainnet.starknet.a5a.ch";
|
|
28038
28018
|
var MAX_RETRIES = Number(process.env.MAX_RETRIES ?? 3);
|
|
28039
28019
|
var MAX_DELAY = Number(process.env.MAX_DELAY ?? 100);
|
|
28040
28020
|
var EXTEND_MARKET_NAME = "BTC-USD";
|
|
28041
|
-
var LIMIT_BALANCE = Number(process.env.LIMIT_BALANCE ??
|
|
28021
|
+
var LIMIT_BALANCE = Number(process.env.LIMIT_BALANCE ?? 0.05);
|
|
28022
|
+
var LIMIT_BALANCE_VALUE = 10;
|
|
28042
28023
|
var REBALANCER_INTERVAL = Number(process.env.REBALANCER_INTERVAL ?? 18e4);
|
|
28043
28024
|
var WITHDRAWAL_INTERVAL = Number(process.env.WITHDRAWAL_INTERVAL ?? 18e6);
|
|
28044
28025
|
var INVESTING_INTERVAL = Number(process.env.INVESTING_INTERVAL ?? 18e4);
|
|
@@ -28056,8 +28037,6 @@ var PRICE_MAX_SLIPPAGE_EKUBO = Number(process.env.PRICE_MAX_SLIPPAGE_EKUBO ?? 5e
|
|
|
28056
28037
|
var MINIMUM_DEBT_AMOUNT_VESU_FOR_REBALANCING = Number(process.env.MINIMUM_DEBT_AMOUNT_VESU_FOR_REBALANCING ?? 1);
|
|
28057
28038
|
var MINIMUM_EXTENDED_POSITION_SIZE = 1e-4;
|
|
28058
28039
|
var MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP = 1e-5;
|
|
28059
|
-
var MAX_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED = 700;
|
|
28060
|
-
var MIN_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED = -100;
|
|
28061
28040
|
|
|
28062
28041
|
// src/strategies/vesu-extended-strategy/utils/helper.ts
|
|
28063
28042
|
var returnFormattedAmount = (amount, toTokenDecimals) => {
|
|
@@ -28077,8 +28056,7 @@ var calculateAmountDistribution = async (amount, client, marketName, collateralP
|
|
|
28077
28056
|
vesu_leverage: 0
|
|
28078
28057
|
};
|
|
28079
28058
|
}
|
|
28080
|
-
const
|
|
28081
|
-
const extendedExposureUSD = extendedBTCExposure.multipliedBy(collateralPrice);
|
|
28059
|
+
const extendedExposureUSD = extendedPosition.length > 0 ? new Web3Number(extendedPosition[0].value, WBTC_TOKEN_DECIMALS) : new Web3Number(0, WBTC_TOKEN_DECIMALS);
|
|
28082
28060
|
const vesuBTCExposureUSD = collateralUnits.multipliedBy(collateralPrice);
|
|
28083
28061
|
const numerator1 = vesu_leverage * amount + vesuBTCExposureUSD.toNumber();
|
|
28084
28062
|
const numerator2 = extendedExposureUSD.toNumber();
|
|
@@ -28115,7 +28093,6 @@ var calculateAmountDistributionForWithdrawal = async (amountInUsdc, collateralPr
|
|
|
28115
28093
|
return null;
|
|
28116
28094
|
}
|
|
28117
28095
|
const extendedExposureUSD = extendedPosition.length > 0 ? new Web3Number(extendedPosition[0].value, USDC_TOKEN_DECIMALS) : new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
28118
|
-
console.log("THe collateral is", collateralPrice, collateralUnits);
|
|
28119
28096
|
const vesuExposureUSD = collateralUnits.multipliedBy(collateralPrice);
|
|
28120
28097
|
if (vesuExposureUSD.lessThan(0)) {
|
|
28121
28098
|
return {
|
|
@@ -28172,10 +28149,10 @@ var calculateExtendedLevergae = () => {
|
|
|
28172
28149
|
const extended_leverage_max = 1 / (MAINTENANCE_MARGIN + MAX_PRICE_DROP_PERCENTAGE);
|
|
28173
28150
|
return Math.floor(extended_leverage_max);
|
|
28174
28151
|
};
|
|
28175
|
-
var calculateDebtAmount = (collateralAmount, debtAmount, debtPrice, maxLtv =
|
|
28152
|
+
var calculateDebtAmount = (collateralAmount, debtAmount, debtPrice, maxLtv = MAX_LIQUIDATION_RATIO, addedAmount, collateralPrice, isDeposit) => {
|
|
28176
28153
|
try {
|
|
28177
|
-
const
|
|
28178
|
-
const numerator1 = collateralAmount.plus(
|
|
28154
|
+
const addedCollateral = addedAmount.multipliedBy(isDeposit ? 1 : -1);
|
|
28155
|
+
const numerator1 = collateralAmount.plus(addedCollateral).multipliedBy(collateralPrice).multipliedBy(maxLtv);
|
|
28179
28156
|
const numerator2 = debtAmount.multipliedBy(debtPrice).multipliedBy(TARGET_HF);
|
|
28180
28157
|
const denominator = TARGET_HF - maxLtv;
|
|
28181
28158
|
const x_debt_usd = numerator1.minus(numerator2).dividedBy(denominator);
|
|
@@ -28210,19 +28187,34 @@ var calculateAmountDepositOnExtendedWhenIncurringLosses = async (client) => {
|
|
|
28210
28187
|
const extendedHoldings = await client.getHoldings();
|
|
28211
28188
|
const extended_leverage = calculateExtendedLevergae();
|
|
28212
28189
|
const latestPosition = (await client.getPositions()).data.pop();
|
|
28213
|
-
console.log("the latest position is", latestPosition, extendedHoldings);
|
|
28214
28190
|
if (!extendedHoldings || !latestPosition) {
|
|
28215
28191
|
logger.error(`error getting extended position: extendedHoldings=${extendedHoldings}, latestPosition=${latestPosition}`);
|
|
28216
28192
|
return null;
|
|
28217
28193
|
}
|
|
28218
|
-
const positionValueInUSD = latestPosition.value;
|
|
28194
|
+
const positionValueInUSD = new Web3Number(latestPosition.value, USDC_TOKEN_DECIMALS);
|
|
28219
28195
|
const equity = extendedHoldings.data.equity;
|
|
28220
|
-
const deposit =
|
|
28221
|
-
return new Web3Number(
|
|
28196
|
+
const deposit = positionValueInUSD.dividedBy(extended_leverage).minus(equity).toFixed(2);
|
|
28197
|
+
return new Web3Number(deposit, USDC_TOKEN_DECIMALS);
|
|
28222
28198
|
} catch (err) {
|
|
28199
|
+
logger.error(`error calculating amount deposit on extended when incurring losses: ${err}`);
|
|
28223
28200
|
return null;
|
|
28224
28201
|
}
|
|
28225
28202
|
};
|
|
28203
|
+
var calculateWBTCAmountToMaintainLTV = (collateralAmount, debtAmount, debtPrice, maxLtv = MAX_LIQUIDATION_RATIO, collateralPrice, targetHF = TARGET_HF) => {
|
|
28204
|
+
try {
|
|
28205
|
+
const numerator1 = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLtv);
|
|
28206
|
+
const numerator2 = debtAmount.multipliedBy(debtPrice).multipliedBy(targetHF);
|
|
28207
|
+
const denominator = maxLtv;
|
|
28208
|
+
const collateralAmountToMaintainLTV = numerator2.minus(numerator1).dividedBy(denominator);
|
|
28209
|
+
let deltaCollateralAmountUnits = new Web3Number(
|
|
28210
|
+
collateralAmountToMaintainLTV.dividedBy(collateralPrice).toFixed(WBTC_TOKEN_DECIMALS),
|
|
28211
|
+
WBTC_TOKEN_DECIMALS
|
|
28212
|
+
);
|
|
28213
|
+
return { deltaCollateralAmountUnits };
|
|
28214
|
+
} catch (err) {
|
|
28215
|
+
return { deltaCollateralAmountUnits: null };
|
|
28216
|
+
}
|
|
28217
|
+
};
|
|
28226
28218
|
var calculateExposureDelta = (exposure_extended, exposure_vesu) => {
|
|
28227
28219
|
const exposure_delta = new Web3Number(exposure_extended - exposure_vesu, 2);
|
|
28228
28220
|
return exposure_delta.absoluteValue().toNumber();
|
|
@@ -28297,21 +28289,36 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28297
28289
|
vaultAllocator: config.vaultAllocator,
|
|
28298
28290
|
id: ""
|
|
28299
28291
|
});
|
|
28300
|
-
this.
|
|
28292
|
+
this.minimumVesuMovementAmount = config.minimumVesuMovementAmount ?? 5;
|
|
28293
|
+
this.tokenMarketData = new TokenMarketData(
|
|
28294
|
+
this.config.pricer,
|
|
28295
|
+
this.config.networkConfig
|
|
28296
|
+
);
|
|
28301
28297
|
}
|
|
28302
28298
|
async getAPY(supportedPosition) {
|
|
28303
28299
|
const CACHE_KEY = `apy_${this.config.poolId.address}_${supportedPosition.asset.symbol}`;
|
|
28304
28300
|
const cacheData = this.getCache(CACHE_KEY);
|
|
28305
|
-
console.log(
|
|
28301
|
+
console.log(
|
|
28302
|
+
`${_VesuMultiplyAdapter.name}::getAPY cacheData: ${JSON.stringify(
|
|
28303
|
+
cacheData
|
|
28304
|
+
)}`,
|
|
28305
|
+
this.vesuAdapter.config.poolId.shortString(),
|
|
28306
|
+
this.vesuAdapter.config.collateral.symbol,
|
|
28307
|
+
this.vesuAdapter.config.debt.symbol
|
|
28308
|
+
);
|
|
28306
28309
|
if (cacheData) {
|
|
28307
28310
|
return cacheData;
|
|
28308
28311
|
}
|
|
28309
28312
|
try {
|
|
28310
28313
|
const allVesuPools = await VesuAdapter.getVesuPools();
|
|
28311
28314
|
const asset = supportedPosition.asset;
|
|
28312
|
-
const pool = allVesuPools.pools.find(
|
|
28315
|
+
const pool = allVesuPools.pools.find(
|
|
28316
|
+
(p) => this.vesuAdapter.config.poolId.eqString(num9.getHexString(p.id))
|
|
28317
|
+
);
|
|
28313
28318
|
if (!pool) {
|
|
28314
|
-
logger.warn(
|
|
28319
|
+
logger.warn(
|
|
28320
|
+
`VesuMultiplyAdapter: Pool not found for token ${asset.symbol}`
|
|
28321
|
+
);
|
|
28315
28322
|
return {
|
|
28316
28323
|
apy: 0,
|
|
28317
28324
|
type: "base" /* BASE */
|
|
@@ -28321,7 +28328,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28321
28328
|
(a) => a.symbol.toLowerCase() === asset.symbol.toLowerCase()
|
|
28322
28329
|
)?.stats;
|
|
28323
28330
|
if (!assetStats) {
|
|
28324
|
-
logger.warn(
|
|
28331
|
+
logger.warn(
|
|
28332
|
+
`VesuMultiplyAdapter: Asset stats not found for token ${asset.symbol}`
|
|
28333
|
+
);
|
|
28325
28334
|
return {
|
|
28326
28335
|
apy: 0,
|
|
28327
28336
|
type: "base" /* BASE */
|
|
@@ -28332,7 +28341,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28332
28341
|
apy = Number(assetStats.borrowApr?.value || 0) / 1e18;
|
|
28333
28342
|
} else {
|
|
28334
28343
|
const isAssetBTC = asset.symbol.toLowerCase().includes("btc");
|
|
28335
|
-
const baseAPY = Number(
|
|
28344
|
+
const baseAPY = Number(
|
|
28345
|
+
isAssetBTC ? assetStats.btcFiSupplyApr?.value + assetStats.supplyApy?.value : assetStats.supplyApy?.value || 0
|
|
28346
|
+
) / 1e18;
|
|
28336
28347
|
const rewardAPY = Number(assetStats.defiSpringSupplyApr?.value || "0") / 1e18;
|
|
28337
28348
|
const isSupported = this.tokenMarketData.isAPYSupported(asset);
|
|
28338
28349
|
apy = baseAPY + rewardAPY;
|
|
@@ -28348,7 +28359,10 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28348
28359
|
this.setCache(CACHE_KEY, result, 3e5);
|
|
28349
28360
|
return result;
|
|
28350
28361
|
} catch (error) {
|
|
28351
|
-
logger.error(
|
|
28362
|
+
logger.error(
|
|
28363
|
+
`VesuMultiplyAdapter: Error getting APY for ${supportedPosition.asset.symbol}:`,
|
|
28364
|
+
error
|
|
28365
|
+
);
|
|
28352
28366
|
throw error;
|
|
28353
28367
|
}
|
|
28354
28368
|
}
|
|
@@ -28361,12 +28375,16 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28361
28375
|
try {
|
|
28362
28376
|
this.vesuAdapter.networkConfig = this.config.networkConfig;
|
|
28363
28377
|
this.vesuAdapter.pricer = this.config.pricer;
|
|
28364
|
-
const positions = await this.vesuAdapter.getPositions(
|
|
28378
|
+
const positions = await this.vesuAdapter.getPositions(
|
|
28379
|
+
this.config.networkConfig
|
|
28380
|
+
);
|
|
28365
28381
|
let position = positions.find(
|
|
28366
28382
|
(p) => p.token.address.eq(supportedPosition.asset.address)
|
|
28367
28383
|
);
|
|
28368
28384
|
if (!position) {
|
|
28369
|
-
logger.warn(
|
|
28385
|
+
logger.warn(
|
|
28386
|
+
`VesuMultiplyAdapter: Position not found for token ${supportedPosition.asset.symbol}`
|
|
28387
|
+
);
|
|
28370
28388
|
return {
|
|
28371
28389
|
amount: new Web3Number("0", supportedPosition.asset.decimals),
|
|
28372
28390
|
remarks: "Position not found"
|
|
@@ -28379,12 +28397,18 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28379
28397
|
this.setCache(CACHE_KEY, position, 6e4);
|
|
28380
28398
|
return position;
|
|
28381
28399
|
} catch (error) {
|
|
28382
|
-
logger.error(
|
|
28400
|
+
logger.error(
|
|
28401
|
+
`VesuMultiplyAdapter: Error getting position for ${supportedPosition.asset.symbol}:`,
|
|
28402
|
+
error
|
|
28403
|
+
);
|
|
28383
28404
|
throw error;
|
|
28384
28405
|
}
|
|
28385
28406
|
}
|
|
28386
28407
|
async maxBorrowableAPY() {
|
|
28387
|
-
const collateralAPY = await this.getAPY({
|
|
28408
|
+
const collateralAPY = await this.getAPY({
|
|
28409
|
+
asset: this.config.collateral,
|
|
28410
|
+
isDebt: false
|
|
28411
|
+
});
|
|
28388
28412
|
const apy = collateralAPY.apy * 0.8;
|
|
28389
28413
|
return apy;
|
|
28390
28414
|
}
|
|
@@ -28394,9 +28418,15 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28394
28418
|
try {
|
|
28395
28419
|
this.vesuAdapter.networkConfig = this.config.networkConfig;
|
|
28396
28420
|
this.vesuAdapter.pricer = this.config.pricer;
|
|
28397
|
-
const positions = await this.vesuAdapter.getPositions(
|
|
28398
|
-
|
|
28399
|
-
|
|
28421
|
+
const positions = await this.vesuAdapter.getPositions(
|
|
28422
|
+
this.config.networkConfig
|
|
28423
|
+
);
|
|
28424
|
+
const collateralPosition = positions.find(
|
|
28425
|
+
(p) => p.token.address.eq(collateral.address)
|
|
28426
|
+
);
|
|
28427
|
+
const debtPosition = positions.find(
|
|
28428
|
+
(p) => p.token.address.eq(debt.address)
|
|
28429
|
+
);
|
|
28400
28430
|
if (!collateralPosition || !debtPosition) {
|
|
28401
28431
|
throw new Error("Could not find current positions");
|
|
28402
28432
|
}
|
|
@@ -28406,13 +28436,23 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28406
28436
|
debt,
|
|
28407
28437
|
maxBorrowableAPY
|
|
28408
28438
|
);
|
|
28409
|
-
logger.verbose(
|
|
28410
|
-
|
|
28439
|
+
logger.verbose(
|
|
28440
|
+
`VesuMultiplyAdapter: Max borrowable: ${maxBorrowable.toNumber()}`
|
|
28441
|
+
);
|
|
28442
|
+
const debtCap = await this.vesuAdapter.getDebtCap(
|
|
28443
|
+
this.config.networkConfig
|
|
28444
|
+
);
|
|
28411
28445
|
logger.verbose(`VesuMultiplyAdapter: Debt cap: ${debtCap.toNumber()}`);
|
|
28412
28446
|
const actualMaxBorrowable = maxBorrowable.minimum(debtCap);
|
|
28413
|
-
logger.verbose(
|
|
28414
|
-
|
|
28415
|
-
|
|
28447
|
+
logger.verbose(
|
|
28448
|
+
`VesuMultiplyAdapter: Actual max borrowable: ${actualMaxBorrowable.toNumber()}`
|
|
28449
|
+
);
|
|
28450
|
+
const maxLTV = await this.vesuAdapter.getLTVConfig(
|
|
28451
|
+
this.config.networkConfig
|
|
28452
|
+
);
|
|
28453
|
+
const collateralPrice = await this.config.pricer.getPrice(
|
|
28454
|
+
collateral.symbol
|
|
28455
|
+
);
|
|
28416
28456
|
if (collateralPrice.price === 0) {
|
|
28417
28457
|
throw new Error("Collateral price is 0");
|
|
28418
28458
|
}
|
|
@@ -28430,14 +28470,25 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28430
28470
|
);
|
|
28431
28471
|
const maxDepositAmount = amount ? amount.minimum(maxCollateralFromDebt) : maxCollateralFromDebt;
|
|
28432
28472
|
const usdValue = await this.getUSDValue(collateral, maxDepositAmount);
|
|
28433
|
-
logger.verbose(
|
|
28434
|
-
|
|
28435
|
-
|
|
28473
|
+
logger.verbose(
|
|
28474
|
+
`VesuMultiplyAdapter: Max deposit::USD value: ${usdValue}, amount: ${maxDepositAmount.toNumber()}`
|
|
28475
|
+
);
|
|
28476
|
+
const apys = await Promise.all([
|
|
28477
|
+
this.getAPY({ asset: collateral, isDebt: false }),
|
|
28478
|
+
this.getAPY({ asset: debt, isDebt: true })
|
|
28479
|
+
]);
|
|
28480
|
+
logger.verbose(
|
|
28481
|
+
`VesuMultiplyAdapter: Apys: ${apys[0].apy}, ${apys[1].apy}`
|
|
28482
|
+
);
|
|
28436
28483
|
const borrowAmountUSD = actualMaxBorrowable.multipliedBy(debtPrice.price);
|
|
28437
|
-
logger.verbose(
|
|
28484
|
+
logger.verbose(
|
|
28485
|
+
`VesuMultiplyAdapter: Borrow amount: ${actualMaxBorrowable.toNumber()}, borrow amount USD: ${borrowAmountUSD.toNumber()}`
|
|
28486
|
+
);
|
|
28438
28487
|
const netCollateralUSD = usdValue + borrowAmountUSD.toNumber();
|
|
28439
28488
|
const netAPY = (apys[0].apy * netCollateralUSD + apys[1].apy * borrowAmountUSD.toNumber()) / usdValue;
|
|
28440
|
-
logger.verbose(
|
|
28489
|
+
logger.verbose(
|
|
28490
|
+
`VesuMultiplyAdapter: Max deposit amount: ${maxDepositAmount.toNumber()}, netAPY: ${netAPY}`
|
|
28491
|
+
);
|
|
28441
28492
|
return {
|
|
28442
28493
|
tokenInfo: collateral,
|
|
28443
28494
|
amount: maxDepositAmount,
|
|
@@ -28450,7 +28501,10 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28450
28501
|
protocol: this.protocol
|
|
28451
28502
|
};
|
|
28452
28503
|
} catch (error) {
|
|
28453
|
-
logger.error(
|
|
28504
|
+
logger.error(
|
|
28505
|
+
`VesuMultiplyAdapter: Error calculating max deposit:`,
|
|
28506
|
+
error
|
|
28507
|
+
);
|
|
28454
28508
|
throw error;
|
|
28455
28509
|
}
|
|
28456
28510
|
}
|
|
@@ -28460,9 +28514,15 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28460
28514
|
try {
|
|
28461
28515
|
this.vesuAdapter.networkConfig = this.config.networkConfig;
|
|
28462
28516
|
this.vesuAdapter.pricer = this.config.pricer;
|
|
28463
|
-
const positions = await this.vesuAdapter.getPositions(
|
|
28464
|
-
|
|
28465
|
-
|
|
28517
|
+
const positions = await this.vesuAdapter.getPositions(
|
|
28518
|
+
this.config.networkConfig
|
|
28519
|
+
);
|
|
28520
|
+
const collateralPosition = positions.find(
|
|
28521
|
+
(p) => p.token.address.eq(collateral.address)
|
|
28522
|
+
);
|
|
28523
|
+
const debtPosition = positions.find(
|
|
28524
|
+
(p) => p.token.address.eq(this.config.debt.address)
|
|
28525
|
+
);
|
|
28466
28526
|
if (!collateralPosition || !debtPosition) {
|
|
28467
28527
|
throw new Error("Could not find current positions");
|
|
28468
28528
|
}
|
|
@@ -28472,11 +28532,20 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28472
28532
|
const result = maxWithdrawable.greaterThan(0) ? maxWithdrawable : new Web3Number("0", collateral.decimals);
|
|
28473
28533
|
const usdValue = await this.getUSDValue(collateral, result);
|
|
28474
28534
|
const debtUSD = debtPosition.usdValue;
|
|
28475
|
-
logger.verbose(
|
|
28476
|
-
|
|
28477
|
-
|
|
28535
|
+
logger.verbose(
|
|
28536
|
+
`VesuMultiplyAdapter: Debt USD: ${debtUSD}, collateral USD: ${usdValue}`
|
|
28537
|
+
);
|
|
28538
|
+
const apys = await Promise.all([
|
|
28539
|
+
this.getAPY({ asset: collateral, isDebt: false }),
|
|
28540
|
+
this.getAPY({ asset: debt, isDebt: true })
|
|
28541
|
+
]);
|
|
28542
|
+
logger.verbose(
|
|
28543
|
+
`VesuMultiplyAdapter: Apys: ${apys[0].apy}, ${apys[1].apy}`
|
|
28544
|
+
);
|
|
28478
28545
|
const netAPY = usdValue - debtUSD > 0 ? (apys[0].apy * usdValue + apys[1].apy * debtUSD) / (usdValue - debtUSD) : 0;
|
|
28479
|
-
logger.verbose(
|
|
28546
|
+
logger.verbose(
|
|
28547
|
+
`VesuMultiplyAdapter: Max withdraw amount: ${result.toNumber()}, netAPY: ${netAPY}`
|
|
28548
|
+
);
|
|
28480
28549
|
return {
|
|
28481
28550
|
tokenInfo: collateral,
|
|
28482
28551
|
amount: result,
|
|
@@ -28489,14 +28558,19 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28489
28558
|
protocol: this.protocol
|
|
28490
28559
|
};
|
|
28491
28560
|
} catch (error) {
|
|
28492
|
-
logger.error(
|
|
28561
|
+
logger.error(
|
|
28562
|
+
`VesuMultiplyAdapter: Error calculating max withdraw:`,
|
|
28563
|
+
error
|
|
28564
|
+
);
|
|
28493
28565
|
throw error;
|
|
28494
28566
|
}
|
|
28495
28567
|
}
|
|
28496
28568
|
_getDepositLeaf() {
|
|
28497
28569
|
const collateral = this.config.collateral;
|
|
28498
28570
|
const debt = this.config.debt;
|
|
28499
|
-
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
28571
|
+
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
28572
|
+
this.config.poolId
|
|
28573
|
+
);
|
|
28500
28574
|
const vesuMultiply = isV2 ? this.vesuAdapter.VESU_MULTIPLY : this.vesuAdapter.VESU_MULTIPLY_V1;
|
|
28501
28575
|
return [
|
|
28502
28576
|
// Approval step for collateral
|
|
@@ -28560,7 +28634,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28560
28634
|
];
|
|
28561
28635
|
}
|
|
28562
28636
|
_getWithdrawLeaf() {
|
|
28563
|
-
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
28637
|
+
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
28638
|
+
this.config.poolId
|
|
28639
|
+
);
|
|
28564
28640
|
const vesuMultiply = isV2 ? this.vesuAdapter.VESU_MULTIPLY : this.vesuAdapter.VESU_MULTIPLY_V1;
|
|
28565
28641
|
const collateral = this.config.collateral;
|
|
28566
28642
|
const debt = this.config.debt;
|
|
@@ -28617,33 +28693,51 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28617
28693
|
const leafConfigs = this._getDepositLeaf();
|
|
28618
28694
|
const leaves = leafConfigs.map((config) => {
|
|
28619
28695
|
const { target, method, packedArguments, sanitizer, id } = config;
|
|
28620
|
-
const leaf = this.constructSimpleLeafData(
|
|
28621
|
-
|
|
28622
|
-
|
|
28623
|
-
|
|
28624
|
-
|
|
28625
|
-
|
|
28696
|
+
const leaf = this.constructSimpleLeafData(
|
|
28697
|
+
{
|
|
28698
|
+
id,
|
|
28699
|
+
target,
|
|
28700
|
+
method,
|
|
28701
|
+
packedArguments
|
|
28702
|
+
},
|
|
28703
|
+
sanitizer
|
|
28704
|
+
);
|
|
28626
28705
|
return leaf;
|
|
28627
28706
|
});
|
|
28628
|
-
return {
|
|
28707
|
+
return {
|
|
28708
|
+
leaves,
|
|
28709
|
+
callConstructor: this.getDepositCall.bind(
|
|
28710
|
+
this
|
|
28711
|
+
)
|
|
28712
|
+
};
|
|
28629
28713
|
}
|
|
28630
28714
|
getWithdrawAdapter() {
|
|
28631
28715
|
const leafConfigs = this._getWithdrawLeaf();
|
|
28632
28716
|
const leaves = leafConfigs.map((config) => {
|
|
28633
28717
|
const { target, method, packedArguments, sanitizer, id } = config;
|
|
28634
|
-
const leaf = this.constructSimpleLeafData(
|
|
28635
|
-
|
|
28636
|
-
|
|
28637
|
-
|
|
28638
|
-
|
|
28639
|
-
|
|
28718
|
+
const leaf = this.constructSimpleLeafData(
|
|
28719
|
+
{
|
|
28720
|
+
id,
|
|
28721
|
+
target,
|
|
28722
|
+
method,
|
|
28723
|
+
packedArguments
|
|
28724
|
+
},
|
|
28725
|
+
sanitizer
|
|
28726
|
+
);
|
|
28640
28727
|
return leaf;
|
|
28641
28728
|
});
|
|
28642
|
-
return {
|
|
28729
|
+
return {
|
|
28730
|
+
leaves,
|
|
28731
|
+
callConstructor: this.getWithdrawCall.bind(
|
|
28732
|
+
this
|
|
28733
|
+
)
|
|
28734
|
+
};
|
|
28643
28735
|
}
|
|
28644
28736
|
async getDepositCall(params) {
|
|
28645
28737
|
const collateral = this.config.collateral;
|
|
28646
|
-
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
28738
|
+
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
28739
|
+
this.config.poolId
|
|
28740
|
+
);
|
|
28647
28741
|
const vesuMultiply = isV2 ? this.vesuAdapter.VESU_MULTIPLY : this.vesuAdapter.VESU_MULTIPLY_V1;
|
|
28648
28742
|
const uint256MarginAmount = uint25612.bnToUint256(params.amount.toWei());
|
|
28649
28743
|
return [
|
|
@@ -28715,7 +28809,9 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28715
28809
|
];
|
|
28716
28810
|
}
|
|
28717
28811
|
async getWithdrawCall(params) {
|
|
28718
|
-
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
28812
|
+
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
28813
|
+
this.config.poolId
|
|
28814
|
+
);
|
|
28719
28815
|
const vesuMultiply = isV2 ? this.vesuAdapter.VESU_MULTIPLY : this.vesuAdapter.VESU_MULTIPLY_V1;
|
|
28720
28816
|
return [
|
|
28721
28817
|
// Switch delegation on
|
|
@@ -28770,7 +28866,11 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28770
28866
|
];
|
|
28771
28867
|
}
|
|
28772
28868
|
async getMultiplyCallCalldata(params, isDeposit) {
|
|
28773
|
-
logger.verbose(
|
|
28869
|
+
logger.verbose(
|
|
28870
|
+
`${_VesuMultiplyAdapter.name}::getMultiplyCallCalldata params: ${JSON.stringify(
|
|
28871
|
+
params
|
|
28872
|
+
)}, isDeposit: ${isDeposit}, collateral: ${this.config.collateral.symbol}, debt: ${this.config.debt.symbol}`
|
|
28873
|
+
);
|
|
28774
28874
|
const { isV2 } = getVesuSingletonAddress(this.config.poolId);
|
|
28775
28875
|
const vesuMultiply = isV2 ? this.vesuAdapter.VESU_MULTIPLY : this.vesuAdapter.VESU_MULTIPLY_V1;
|
|
28776
28876
|
const multiplyContract = new Contract12({
|
|
@@ -28780,42 +28880,83 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28780
28880
|
});
|
|
28781
28881
|
let leverSwap = [];
|
|
28782
28882
|
let leverSwapLimitAmount = Web3Number.fromWei(0, this.config.debt.decimals);
|
|
28783
|
-
const existingPositions = await this.vesuAdapter.getPositions(
|
|
28784
|
-
|
|
28883
|
+
const existingPositions = await this.vesuAdapter.getPositions(
|
|
28884
|
+
this.config.networkConfig
|
|
28885
|
+
);
|
|
28886
|
+
const collateralisation = await this.vesuAdapter.getCollateralization(
|
|
28887
|
+
this.config.networkConfig
|
|
28888
|
+
);
|
|
28785
28889
|
const existingCollateralInfo = existingPositions[0];
|
|
28786
28890
|
const existingDebtInfo = existingPositions[1];
|
|
28787
28891
|
const isDexPriceRequired = existingDebtInfo.token.symbol !== "USDC";
|
|
28788
|
-
logger.debug(`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall existingCollateralInfo: ${JSON.stringify(
|
|
28789
|
-
|
|
28892
|
+
logger.debug(`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall existingCollateralInfo: ${JSON.stringify(
|
|
28893
|
+
existingCollateralInfo
|
|
28894
|
+
)},
|
|
28895
|
+
existingDebtInfo: ${JSON.stringify(
|
|
28896
|
+
existingDebtInfo
|
|
28897
|
+
)}, collateralisation: ${JSON.stringify(collateralisation)}`);
|
|
28790
28898
|
const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : (await this.config.pricer.getPrice(this.config.collateral.symbol)).price;
|
|
28791
28899
|
const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : (await this.config.pricer.getPrice(this.config.debt.symbol)).price;
|
|
28792
|
-
logger.debug(
|
|
28793
|
-
|
|
28794
|
-
|
|
28795
|
-
const
|
|
28796
|
-
|
|
28900
|
+
logger.debug(
|
|
28901
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`
|
|
28902
|
+
);
|
|
28903
|
+
const legLTV = await this.vesuAdapter.getLTVConfig(
|
|
28904
|
+
this.config.networkConfig
|
|
28905
|
+
);
|
|
28906
|
+
const ekuboQuoter = new EkuboQuoter(
|
|
28907
|
+
this.config.networkConfig,
|
|
28908
|
+
this.config.pricer
|
|
28909
|
+
);
|
|
28910
|
+
const dexPrice = isDexPriceRequired ? await ekuboQuoter.getDexPrice(
|
|
28911
|
+
this.config.collateral,
|
|
28912
|
+
this.config.debt,
|
|
28913
|
+
this.config.quoteAmountToFetchPrice
|
|
28914
|
+
) : 1;
|
|
28915
|
+
logger.verbose(
|
|
28916
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall dexPrice: ${dexPrice}, ltv: ${legLTV}`
|
|
28917
|
+
);
|
|
28797
28918
|
const addedCollateral = params.amount.multipliedBy(isDeposit ? 1 : -1);
|
|
28798
|
-
logger.verbose(
|
|
28919
|
+
logger.verbose(
|
|
28920
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall addedCollateral: ${addedCollateral}`
|
|
28921
|
+
);
|
|
28799
28922
|
const numeratorPart1 = existingCollateralInfo.amount.plus(addedCollateral).multipliedBy(collateralPrice).multipliedBy(legLTV);
|
|
28800
|
-
logger.verbose(
|
|
28923
|
+
logger.verbose(
|
|
28924
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}`
|
|
28925
|
+
);
|
|
28801
28926
|
const numeratorPart2 = existingDebtInfo.amount.multipliedBy(debtPrice).multipliedBy(this.config.targetHealthFactor);
|
|
28802
|
-
logger.verbose(
|
|
28927
|
+
logger.verbose(
|
|
28928
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall numeratorPart2: ${numeratorPart2}`
|
|
28929
|
+
);
|
|
28803
28930
|
const denominatorPart = this.config.targetHealthFactor - legLTV / dexPrice;
|
|
28804
|
-
logger.verbose(
|
|
28931
|
+
logger.verbose(
|
|
28932
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall denominatorPart: ${denominatorPart}`
|
|
28933
|
+
);
|
|
28805
28934
|
const x_debt_usd = numeratorPart1.minus(numeratorPart2).dividedBy(denominatorPart);
|
|
28806
|
-
logger.verbose(
|
|
28807
|
-
|
|
28808
|
-
|
|
28935
|
+
logger.verbose(
|
|
28936
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall x_debt_usd: ${x_debt_usd}`
|
|
28937
|
+
);
|
|
28938
|
+
logger.debug(
|
|
28939
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}, numeratorPart2: ${numeratorPart2}, denominatorPart: ${denominatorPart}`
|
|
28940
|
+
);
|
|
28941
|
+
let debtAmount = new Web3Number(
|
|
28942
|
+
x_debt_usd.dividedBy(debtPrice).toFixed(this.config.debt.decimals),
|
|
28943
|
+
this.config.debt.decimals
|
|
28944
|
+
);
|
|
28809
28945
|
const marginAmount = addedCollateral;
|
|
28810
28946
|
const collateralToken = this.config.collateral;
|
|
28811
28947
|
const debtToken = this.config.debt;
|
|
28812
|
-
const debtAmountInCollateralUnits = new Web3Number(
|
|
28948
|
+
const debtAmountInCollateralUnits = new Web3Number(
|
|
28949
|
+
debtAmount.multipliedBy(debtPrice).dividedBy(collateralPrice).multipliedBy(10 ** collateralToken.decimals).toFixed(0),
|
|
28950
|
+
collateralToken.decimals
|
|
28951
|
+
);
|
|
28813
28952
|
const isIncrease = debtAmount.greaterThanOrEqualTo(0);
|
|
28814
28953
|
if (isIncrease && debtAmount.lessThan(0)) {
|
|
28815
28954
|
} else if (!isIncrease && debtAmount.greaterThan(0)) {
|
|
28816
28955
|
debtAmount = Web3Number.fromWei(0, this.config.debt.decimals);
|
|
28817
28956
|
}
|
|
28818
|
-
logger.verbose(
|
|
28957
|
+
logger.verbose(
|
|
28958
|
+
`${_VesuMultiplyAdapter.name}::getVesuMultiplyCall debtAmount: ${debtAmount}, marginAmount: ${marginAmount}`
|
|
28959
|
+
);
|
|
28819
28960
|
if (!debtAmount.isZero()) {
|
|
28820
28961
|
try {
|
|
28821
28962
|
const swapQuote = await ekuboQuoter.getQuote(
|
|
@@ -28825,26 +28966,49 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28825
28966
|
// negative for exact amount out
|
|
28826
28967
|
);
|
|
28827
28968
|
if (swapQuote.price_impact < 0.01) {
|
|
28828
|
-
leverSwap = ekuboQuoter.getVesuMultiplyQuote(
|
|
28969
|
+
leverSwap = debtAmount.isNegative() ? ekuboQuoter.getVesuMultiplyQuote(
|
|
28970
|
+
swapQuote,
|
|
28971
|
+
collateralToken,
|
|
28972
|
+
debtToken
|
|
28973
|
+
) : ekuboQuoter.getVesuMultiplyQuote(
|
|
28974
|
+
swapQuote,
|
|
28975
|
+
debtToken,
|
|
28976
|
+
collateralToken
|
|
28977
|
+
);
|
|
28829
28978
|
const MAX_SLIPPAGE = 2e-3;
|
|
28830
28979
|
if (debtAmount.greaterThan(0)) {
|
|
28831
28980
|
leverSwapLimitAmount = debtAmount.multipliedBy(1 + MAX_SLIPPAGE);
|
|
28832
28981
|
} else if (debtAmount.lessThan(0)) {
|
|
28833
28982
|
leverSwapLimitAmount = debtAmount.abs().multipliedBy(1 - MAX_SLIPPAGE);
|
|
28834
28983
|
} else {
|
|
28835
|
-
leverSwapLimitAmount = Web3Number.fromWei(
|
|
28984
|
+
leverSwapLimitAmount = Web3Number.fromWei(
|
|
28985
|
+
0,
|
|
28986
|
+
this.config.debt.decimals
|
|
28987
|
+
);
|
|
28836
28988
|
}
|
|
28837
28989
|
await new Promise((resolve) => setTimeout(resolve, 1e4));
|
|
28838
28990
|
} else {
|
|
28839
|
-
throw new Error(
|
|
28991
|
+
throw new Error(
|
|
28992
|
+
`VesuMultiplyAdapter: Price impact too high (${swapQuote.price_impact}), skipping swap`
|
|
28993
|
+
);
|
|
28840
28994
|
}
|
|
28841
28995
|
} catch (error) {
|
|
28842
|
-
throw new Error(
|
|
28996
|
+
throw new Error(
|
|
28997
|
+
`VesuMultiplyAdapter: Failed to get swap quote: ${error}`
|
|
28998
|
+
);
|
|
28843
28999
|
}
|
|
28844
29000
|
}
|
|
28845
|
-
const multiplyParams = await this.getLeverParams(
|
|
29001
|
+
const multiplyParams = await this.getLeverParams(
|
|
29002
|
+
isIncrease,
|
|
29003
|
+
params,
|
|
29004
|
+
leverSwap,
|
|
29005
|
+
leverSwapLimitAmount
|
|
29006
|
+
);
|
|
28846
29007
|
const call = multiplyContract.populate("modify_lever", {
|
|
28847
|
-
modify_lever_params: this.formatMultiplyParams(
|
|
29008
|
+
modify_lever_params: this.formatMultiplyParams(
|
|
29009
|
+
isIncrease,
|
|
29010
|
+
multiplyParams
|
|
29011
|
+
)
|
|
28848
29012
|
});
|
|
28849
29013
|
return call.calldata;
|
|
28850
29014
|
}
|
|
@@ -28858,7 +29022,10 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28858
29022
|
add_margin: params.amount,
|
|
28859
29023
|
// multiplied by collateral decimals in format
|
|
28860
29024
|
margin_swap: [],
|
|
28861
|
-
margin_swap_limit_amount: Web3Number.fromWei(
|
|
29025
|
+
margin_swap_limit_amount: Web3Number.fromWei(
|
|
29026
|
+
0,
|
|
29027
|
+
this.config.collateral.decimals
|
|
29028
|
+
),
|
|
28862
29029
|
lever_swap: leverSwap,
|
|
28863
29030
|
lever_swap_limit_amount: leverSwapLimitAmount
|
|
28864
29031
|
} : {
|
|
@@ -28872,7 +29039,10 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28872
29039
|
lever_swap_limit_amount: leverSwapLimitAmount,
|
|
28873
29040
|
lever_swap_weights: [],
|
|
28874
29041
|
withdraw_swap: [],
|
|
28875
|
-
withdraw_swap_limit_amount: Web3Number.fromWei(
|
|
29042
|
+
withdraw_swap_limit_amount: Web3Number.fromWei(
|
|
29043
|
+
0,
|
|
29044
|
+
this.config.collateral.decimals
|
|
29045
|
+
),
|
|
28876
29046
|
withdraw_swap_weights: [],
|
|
28877
29047
|
close_position: false
|
|
28878
29048
|
};
|
|
@@ -28888,12 +29058,16 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28888
29058
|
});
|
|
28889
29059
|
let leverSwap = [];
|
|
28890
29060
|
let leverSwapLimitAmount = Web3Number.fromWei(0, this.config.debt.decimals);
|
|
28891
|
-
const existingPositions = await this.vesuAdapter.getPositions(
|
|
29061
|
+
const existingPositions = await this.vesuAdapter.getPositions(
|
|
29062
|
+
this.config.networkConfig
|
|
29063
|
+
);
|
|
28892
29064
|
const existingCollateralInfo = existingPositions[0];
|
|
28893
29065
|
const existingDebtInfo = existingPositions[1];
|
|
28894
29066
|
const collateralToken = this.config.collateral;
|
|
28895
29067
|
const debtToken = this.config.debt;
|
|
28896
|
-
const collateralPrice = await this.config.pricer.getPrice(
|
|
29068
|
+
const collateralPrice = await this.config.pricer.getPrice(
|
|
29069
|
+
collateralToken.symbol
|
|
29070
|
+
);
|
|
28897
29071
|
const debtPrice = await this.config.pricer.getPrice(debtToken.symbol);
|
|
28898
29072
|
const { deltadebtAmountUnits: debtAmountToRepay } = calculateDebtReductionAmountForWithdrawal(
|
|
28899
29073
|
existingDebtInfo.amount,
|
|
@@ -28907,8 +29081,14 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28907
29081
|
if (!debtAmountToRepay) {
|
|
28908
29082
|
throw new Error("error calculating debt amount to repay");
|
|
28909
29083
|
}
|
|
28910
|
-
const ekuboQuoter = new EkuboQuoter(
|
|
28911
|
-
|
|
29084
|
+
const ekuboQuoter = new EkuboQuoter(
|
|
29085
|
+
this.config.networkConfig,
|
|
29086
|
+
this.config.pricer
|
|
29087
|
+
);
|
|
29088
|
+
const debtInDebtUnits = new Web3Number(
|
|
29089
|
+
debtAmountToRepay,
|
|
29090
|
+
debtToken.decimals
|
|
29091
|
+
).dividedBy(debtPrice.price).multipliedBy(10 ** debtToken.decimals);
|
|
28912
29092
|
const swapQuote = await ekuboQuoter.getQuote(
|
|
28913
29093
|
debtToken.address.address,
|
|
28914
29094
|
collateralToken.address.address,
|
|
@@ -28916,12 +29096,23 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28916
29096
|
);
|
|
28917
29097
|
const MAX_SLIPPAGE = 2e-3;
|
|
28918
29098
|
if (swapQuote.price_impact < 25e-4) {
|
|
28919
|
-
leverSwap = ekuboQuoter.getVesuMultiplyQuote(
|
|
29099
|
+
leverSwap = ekuboQuoter.getVesuMultiplyQuote(
|
|
29100
|
+
swapQuote,
|
|
29101
|
+
collateralToken,
|
|
29102
|
+
debtToken
|
|
29103
|
+
);
|
|
28920
29104
|
} else {
|
|
28921
|
-
logger.error(
|
|
29105
|
+
logger.error(
|
|
29106
|
+
`VesuMultiplyAdapter: Price impact too high (${swapQuote.price_impact}), skipping swap`
|
|
29107
|
+
);
|
|
28922
29108
|
}
|
|
28923
29109
|
leverSwapLimitAmount = new Web3Number(debtAmountToRepay, debtToken.decimals).abs().multipliedBy(1 + MAX_SLIPPAGE);
|
|
28924
|
-
const multiplyParams = await this.getLeverParams(
|
|
29110
|
+
const multiplyParams = await this.getLeverParams(
|
|
29111
|
+
false,
|
|
29112
|
+
params,
|
|
29113
|
+
leverSwap,
|
|
29114
|
+
leverSwapLimitAmount
|
|
29115
|
+
);
|
|
28925
29116
|
const call = multiplyContract.populate("modify_lever", {
|
|
28926
29117
|
modify_lever_params: this.formatMultiplyParams(false, multiplyParams)
|
|
28927
29118
|
});
|
|
@@ -28931,100 +29122,132 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
28931
29122
|
if (isIncrease) {
|
|
28932
29123
|
const _params2 = params;
|
|
28933
29124
|
return {
|
|
28934
|
-
action: new CairoCustomEnum3({
|
|
28935
|
-
|
|
28936
|
-
|
|
28937
|
-
|
|
28938
|
-
|
|
28939
|
-
|
|
28940
|
-
|
|
29125
|
+
action: new CairoCustomEnum3({
|
|
29126
|
+
IncreaseLever: {
|
|
29127
|
+
pool_id: _params2.pool_id.toBigInt(),
|
|
29128
|
+
collateral_asset: _params2.collateral_asset.toBigInt(),
|
|
29129
|
+
debt_asset: _params2.debt_asset.toBigInt(),
|
|
29130
|
+
user: _params2.user.toBigInt(),
|
|
29131
|
+
add_margin: BigInt(_params2.add_margin.toWei()),
|
|
29132
|
+
margin_swap: _params2.margin_swap.map((swap) => ({
|
|
29133
|
+
route: swap.route.map((route) => ({
|
|
29134
|
+
pool_key: {
|
|
29135
|
+
token0: route.pool_key.token0.toBigInt(),
|
|
29136
|
+
token1: route.pool_key.token1.toBigInt(),
|
|
29137
|
+
fee: route.pool_key.fee,
|
|
29138
|
+
tick_spacing: route.pool_key.tick_spacing,
|
|
29139
|
+
extension: BigInt(
|
|
29140
|
+
num9.hexToDecimalString(route.pool_key.extension)
|
|
29141
|
+
)
|
|
29142
|
+
},
|
|
29143
|
+
sqrt_ratio_limit: uint25612.bnToUint256(
|
|
29144
|
+
route.sqrt_ratio_limit.toWei()
|
|
29145
|
+
),
|
|
29146
|
+
skip_ahead: BigInt(100)
|
|
29147
|
+
})),
|
|
29148
|
+
token_amount: {
|
|
29149
|
+
token: swap.token_amount.token.toBigInt(),
|
|
29150
|
+
amount: swap.token_amount.amount.toI129()
|
|
29151
|
+
}
|
|
29152
|
+
})),
|
|
29153
|
+
margin_swap_limit_amount: BigInt(
|
|
29154
|
+
_params2.margin_swap_limit_amount.toWei()
|
|
29155
|
+
),
|
|
29156
|
+
lever_swap: _params2.lever_swap.map((swap) => ({
|
|
29157
|
+
route: swap.route.map((route) => ({
|
|
29158
|
+
pool_key: {
|
|
29159
|
+
token0: route.pool_key.token0.toBigInt(),
|
|
29160
|
+
token1: route.pool_key.token1.toBigInt(),
|
|
29161
|
+
fee: route.pool_key.fee,
|
|
29162
|
+
tick_spacing: route.pool_key.tick_spacing,
|
|
29163
|
+
extension: BigInt(
|
|
29164
|
+
num9.hexToDecimalString(route.pool_key.extension)
|
|
29165
|
+
)
|
|
29166
|
+
},
|
|
29167
|
+
sqrt_ratio_limit: uint25612.bnToUint256(
|
|
29168
|
+
route.sqrt_ratio_limit.toWei()
|
|
29169
|
+
),
|
|
29170
|
+
skip_ahead: BigInt(0)
|
|
29171
|
+
})),
|
|
29172
|
+
token_amount: {
|
|
29173
|
+
token: swap.token_amount.token.toBigInt(),
|
|
29174
|
+
amount: swap.token_amount.amount.toI129()
|
|
29175
|
+
}
|
|
29176
|
+
})),
|
|
29177
|
+
lever_swap_limit_amount: BigInt(
|
|
29178
|
+
_params2.lever_swap_limit_amount.toWei()
|
|
29179
|
+
)
|
|
29180
|
+
}
|
|
29181
|
+
})
|
|
29182
|
+
};
|
|
29183
|
+
}
|
|
29184
|
+
const _params = params;
|
|
29185
|
+
return {
|
|
29186
|
+
action: new CairoCustomEnum3({
|
|
29187
|
+
DecreaseLever: {
|
|
29188
|
+
pool_id: _params.pool_id.toBigInt(),
|
|
29189
|
+
collateral_asset: _params.collateral_asset.toBigInt(),
|
|
29190
|
+
debt_asset: _params.debt_asset.toBigInt(),
|
|
29191
|
+
user: _params.user.toBigInt(),
|
|
29192
|
+
sub_margin: BigInt(_params.sub_margin.toWei()),
|
|
29193
|
+
recipient: _params.recipient.toBigInt(),
|
|
29194
|
+
lever_swap: _params.lever_swap.map((swap) => ({
|
|
28941
29195
|
route: swap.route.map((route) => ({
|
|
28942
29196
|
pool_key: {
|
|
28943
29197
|
token0: route.pool_key.token0.toBigInt(),
|
|
28944
29198
|
token1: route.pool_key.token1.toBigInt(),
|
|
28945
29199
|
fee: route.pool_key.fee,
|
|
28946
29200
|
tick_spacing: route.pool_key.tick_spacing,
|
|
28947
|
-
extension:
|
|
29201
|
+
extension: ContractAddr.from(
|
|
29202
|
+
route.pool_key.extension
|
|
29203
|
+
).toBigInt()
|
|
28948
29204
|
},
|
|
28949
|
-
sqrt_ratio_limit: uint25612.bnToUint256(
|
|
28950
|
-
|
|
29205
|
+
sqrt_ratio_limit: uint25612.bnToUint256(
|
|
29206
|
+
route.sqrt_ratio_limit.toWei()
|
|
29207
|
+
),
|
|
29208
|
+
skip_ahead: BigInt(route.skip_ahead.toWei())
|
|
28951
29209
|
})),
|
|
28952
29210
|
token_amount: {
|
|
28953
29211
|
token: swap.token_amount.token.toBigInt(),
|
|
28954
29212
|
amount: swap.token_amount.amount.toI129()
|
|
28955
29213
|
}
|
|
28956
29214
|
})),
|
|
28957
|
-
|
|
28958
|
-
|
|
29215
|
+
lever_swap_limit_amount: BigInt(
|
|
29216
|
+
_params.lever_swap_limit_amount.toWei()
|
|
29217
|
+
),
|
|
29218
|
+
lever_swap_weights: _params.lever_swap_weights.map(
|
|
29219
|
+
(weight) => BigInt(weight.toWei())
|
|
29220
|
+
),
|
|
29221
|
+
withdraw_swap: _params.withdraw_swap.map((swap) => ({
|
|
28959
29222
|
route: swap.route.map((route) => ({
|
|
28960
29223
|
pool_key: {
|
|
28961
29224
|
token0: route.pool_key.token0.toBigInt(),
|
|
28962
29225
|
token1: route.pool_key.token1.toBigInt(),
|
|
28963
29226
|
fee: route.pool_key.fee,
|
|
28964
29227
|
tick_spacing: route.pool_key.tick_spacing,
|
|
28965
|
-
extension:
|
|
29228
|
+
extension: ContractAddr.from(
|
|
29229
|
+
route.pool_key.extension
|
|
29230
|
+
).toBigInt()
|
|
28966
29231
|
},
|
|
28967
|
-
sqrt_ratio_limit: uint25612.bnToUint256(
|
|
28968
|
-
|
|
29232
|
+
sqrt_ratio_limit: uint25612.bnToUint256(
|
|
29233
|
+
route.sqrt_ratio_limit.toWei()
|
|
29234
|
+
),
|
|
29235
|
+
skip_ahead: BigInt(route.skip_ahead.toWei())
|
|
28969
29236
|
})),
|
|
28970
29237
|
token_amount: {
|
|
28971
29238
|
token: swap.token_amount.token.toBigInt(),
|
|
28972
29239
|
amount: swap.token_amount.amount.toI129()
|
|
28973
29240
|
}
|
|
28974
29241
|
})),
|
|
28975
|
-
|
|
28976
|
-
|
|
28977
|
-
|
|
28978
|
-
|
|
28979
|
-
|
|
28980
|
-
|
|
28981
|
-
|
|
28982
|
-
|
|
28983
|
-
|
|
28984
|
-
debt_asset: _params.debt_asset.toBigInt(),
|
|
28985
|
-
user: _params.user.toBigInt(),
|
|
28986
|
-
sub_margin: BigInt(_params.sub_margin.toWei()),
|
|
28987
|
-
recipient: _params.recipient.toBigInt(),
|
|
28988
|
-
lever_swap: _params.lever_swap.map((swap) => ({
|
|
28989
|
-
route: swap.route.map((route) => ({
|
|
28990
|
-
pool_key: {
|
|
28991
|
-
token0: route.pool_key.token0.toBigInt(),
|
|
28992
|
-
token1: route.pool_key.token1.toBigInt(),
|
|
28993
|
-
fee: route.pool_key.fee,
|
|
28994
|
-
tick_spacing: route.pool_key.tick_spacing,
|
|
28995
|
-
extension: ContractAddr.from(route.pool_key.extension).toBigInt()
|
|
28996
|
-
},
|
|
28997
|
-
sqrt_ratio_limit: uint25612.bnToUint256(route.sqrt_ratio_limit.toWei()),
|
|
28998
|
-
skip_ahead: BigInt(route.skip_ahead.toWei())
|
|
28999
|
-
})),
|
|
29000
|
-
token_amount: {
|
|
29001
|
-
token: swap.token_amount.token.toBigInt(),
|
|
29002
|
-
amount: swap.token_amount.amount.toI129()
|
|
29003
|
-
}
|
|
29004
|
-
})),
|
|
29005
|
-
lever_swap_limit_amount: BigInt(_params.lever_swap_limit_amount.toWei()),
|
|
29006
|
-
lever_swap_weights: _params.lever_swap_weights.map((weight) => BigInt(weight.toWei())),
|
|
29007
|
-
withdraw_swap: _params.withdraw_swap.map((swap) => ({
|
|
29008
|
-
route: swap.route.map((route) => ({
|
|
29009
|
-
pool_key: {
|
|
29010
|
-
token0: route.pool_key.token0.toBigInt(),
|
|
29011
|
-
token1: route.pool_key.token1.toBigInt(),
|
|
29012
|
-
fee: route.pool_key.fee,
|
|
29013
|
-
tick_spacing: route.pool_key.tick_spacing,
|
|
29014
|
-
extension: ContractAddr.from(route.pool_key.extension).toBigInt()
|
|
29015
|
-
},
|
|
29016
|
-
sqrt_ratio_limit: uint25612.bnToUint256(route.sqrt_ratio_limit.toWei()),
|
|
29017
|
-
skip_ahead: BigInt(route.skip_ahead.toWei())
|
|
29018
|
-
})),
|
|
29019
|
-
token_amount: {
|
|
29020
|
-
token: swap.token_amount.token.toBigInt(),
|
|
29021
|
-
amount: swap.token_amount.amount.toI129()
|
|
29022
|
-
}
|
|
29023
|
-
})),
|
|
29024
|
-
withdraw_swap_limit_amount: BigInt(_params.withdraw_swap_limit_amount.toWei()),
|
|
29025
|
-
withdraw_swap_weights: _params.withdraw_swap_weights.map((weight) => BigInt(weight.toWei())),
|
|
29026
|
-
close_position: _params.close_position
|
|
29027
|
-
} })
|
|
29242
|
+
withdraw_swap_limit_amount: BigInt(
|
|
29243
|
+
_params.withdraw_swap_limit_amount.toWei()
|
|
29244
|
+
),
|
|
29245
|
+
withdraw_swap_weights: _params.withdraw_swap_weights.map(
|
|
29246
|
+
(weight) => BigInt(weight.toWei())
|
|
29247
|
+
),
|
|
29248
|
+
close_position: _params.close_position
|
|
29249
|
+
}
|
|
29250
|
+
})
|
|
29028
29251
|
};
|
|
29029
29252
|
}
|
|
29030
29253
|
async getHealthFactor() {
|
|
@@ -29033,11 +29256,15 @@ var VesuMultiplyAdapter = class _VesuMultiplyAdapter extends BaseAdapter {
|
|
|
29033
29256
|
}
|
|
29034
29257
|
async getNetAPY() {
|
|
29035
29258
|
const positions = await this.getPositions();
|
|
29036
|
-
logger.verbose(
|
|
29259
|
+
logger.verbose(
|
|
29260
|
+
`${this.name}::getNetAPY: positions: ${JSON.stringify(positions)}`
|
|
29261
|
+
);
|
|
29037
29262
|
const allZero = positions.every((p) => p.usdValue === 0);
|
|
29038
29263
|
if (allZero) {
|
|
29039
29264
|
const collateralUSD = 1e3;
|
|
29040
|
-
const maxLTV = await this.vesuAdapter.getLTVConfig(
|
|
29265
|
+
const maxLTV = await this.vesuAdapter.getLTVConfig(
|
|
29266
|
+
this.config.networkConfig
|
|
29267
|
+
);
|
|
29041
29268
|
const targetHF = this.config.targetHealthFactor;
|
|
29042
29269
|
const maxDebt = HealthFactorMath.getMaxDebtAmountOnLooping(
|
|
29043
29270
|
new Web3Number(collateralUSD, this.config.collateral.decimals),
|
|
@@ -29180,7 +29407,22 @@ var ExtendedWrapper = class {
|
|
|
29180
29407
|
`HTTP ${response.status}: ${errorData.detail || response.statusText}`
|
|
29181
29408
|
);
|
|
29182
29409
|
}
|
|
29183
|
-
const
|
|
29410
|
+
const text = await response.text();
|
|
29411
|
+
const MAX_SAFE_INTEGER_STR = "9007199254740991";
|
|
29412
|
+
const largeIntegerRegex = /"data"\s*:\s*(\d{16,})/g;
|
|
29413
|
+
const modifiedText = text.replace(largeIntegerRegex, (match, largeInt) => {
|
|
29414
|
+
if (largeInt.length > MAX_SAFE_INTEGER_STR.length || largeInt.length === MAX_SAFE_INTEGER_STR.length && largeInt > MAX_SAFE_INTEGER_STR) {
|
|
29415
|
+
return `"data":"${largeInt}"`;
|
|
29416
|
+
}
|
|
29417
|
+
return match;
|
|
29418
|
+
});
|
|
29419
|
+
const data = JSON.parse(modifiedText);
|
|
29420
|
+
if (data && typeof data.data === "string" && /^\d+$/.test(data.data)) {
|
|
29421
|
+
const numValue = Number(data.data);
|
|
29422
|
+
if (Number.isSafeInteger(numValue)) {
|
|
29423
|
+
data.data = numValue;
|
|
29424
|
+
}
|
|
29425
|
+
}
|
|
29184
29426
|
return data;
|
|
29185
29427
|
} catch (error) {
|
|
29186
29428
|
lastError = error;
|
|
@@ -29240,6 +29482,7 @@ var ExtendedWrapper = class {
|
|
|
29240
29482
|
}
|
|
29241
29483
|
/**
|
|
29242
29484
|
* Initiate a withdrawal from Extended Exchange
|
|
29485
|
+
* Returns data as number | string to preserve precision for large integers
|
|
29243
29486
|
*/
|
|
29244
29487
|
async withdraw(request) {
|
|
29245
29488
|
return this.makeRequest("/api/v1/withdraw", {
|
|
@@ -29378,6 +29621,7 @@ var ExtendedWrapper = class {
|
|
|
29378
29621
|
}
|
|
29379
29622
|
/**
|
|
29380
29623
|
* Withdraw USDC (convenience method)
|
|
29624
|
+
* Returns data as number | string to preserve precision for large integers
|
|
29381
29625
|
*/
|
|
29382
29626
|
async withdrawUSDC(amount) {
|
|
29383
29627
|
return this.withdraw({ amount, asset: "USDC" });
|
|
@@ -29387,11 +29631,13 @@ var ExtendedWrapper = class {
|
|
|
29387
29631
|
* @param marketName - The name of the market to get funding rates for
|
|
29388
29632
|
* @returns The funding rates for the specified market
|
|
29389
29633
|
*/
|
|
29390
|
-
async getFundingRates(marketName, side) {
|
|
29634
|
+
async getFundingRates(marketName, side, startTime, endTime) {
|
|
29635
|
+
const endTimeParam = endTime !== void 0 ? `&end_time=${endTime}` : "";
|
|
29636
|
+
const startTimeParam = startTime !== void 0 ? `&start_time=${startTime}` : "";
|
|
29391
29637
|
return this.makeRequest(
|
|
29392
29638
|
`/api/v1/markets/funding-rates?market_name=${encodeURIComponent(
|
|
29393
29639
|
marketName
|
|
29394
|
-
)}&side=${encodeURIComponent(side)}`
|
|
29640
|
+
)}&side=${encodeURIComponent(side)}${startTimeParam}${endTimeParam}`
|
|
29395
29641
|
);
|
|
29396
29642
|
}
|
|
29397
29643
|
};
|
|
@@ -29404,18 +29650,20 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29404
29650
|
super(config, _ExtendedAdapter.name, Protocols.EXTENDED);
|
|
29405
29651
|
this.config = config;
|
|
29406
29652
|
const client = new wrapper_default({
|
|
29407
|
-
baseUrl: this.config.
|
|
29408
|
-
apiKey:
|
|
29653
|
+
baseUrl: this.config.extendedBackendWriteUrl,
|
|
29654
|
+
apiKey: "",
|
|
29409
29655
|
timeout: this.config.extendedTimeout,
|
|
29410
29656
|
retries: this.config.extendedRetries
|
|
29411
29657
|
});
|
|
29658
|
+
this.minimumExtendedMovementAmount = this.config.minimumExtendedMovementAmount ?? 5;
|
|
29412
29659
|
this.client = client;
|
|
29660
|
+
this.retryDelayForOrderStatus = this.config.retryDelayForOrderStatus ?? 3e3;
|
|
29413
29661
|
}
|
|
29414
29662
|
//abstract means the method has no implementation in this class; instead, child classes must implement it.
|
|
29415
29663
|
async getAPY(supportedPosition) {
|
|
29416
29664
|
const side = supportedPosition.isDebt ? "LONG" : "SHORT";
|
|
29417
|
-
const fundingRates = await this.
|
|
29418
|
-
if (fundingRates.
|
|
29665
|
+
const fundingRates = await this.getFundingRates(side);
|
|
29666
|
+
if (!fundingRates.success) {
|
|
29419
29667
|
logger.error("error getting funding rates", fundingRates);
|
|
29420
29668
|
return { apy: 0, type: "base" /* BASE */ };
|
|
29421
29669
|
}
|
|
@@ -29423,10 +29671,26 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29423
29671
|
const apy = Number(fundingRate.f) * 365 * 24;
|
|
29424
29672
|
return { apy, type: "base" /* BASE */ };
|
|
29425
29673
|
}
|
|
29426
|
-
async
|
|
29427
|
-
|
|
29428
|
-
|
|
29674
|
+
async getFundingRates(side, startTime, endTime) {
|
|
29675
|
+
try {
|
|
29676
|
+
const response = await axios8.get(`${this.config.extendedBackendReadUrl}/fundingRates/${this.config.extendedMarketName}/${side}`, {
|
|
29677
|
+
params: {
|
|
29678
|
+
startTime: startTime ? startTime.toString() : void 0,
|
|
29679
|
+
endTime: endTime ? endTime.toString() : void 0
|
|
29680
|
+
}
|
|
29681
|
+
});
|
|
29682
|
+
if (!response.data.success) {
|
|
29683
|
+
logger.error("error getting funding rates", response.data);
|
|
29684
|
+
return { success: false, data: [] };
|
|
29685
|
+
}
|
|
29686
|
+
logger.info("success getting funding rates", response.data.data);
|
|
29687
|
+
return { success: true, data: response.data.data };
|
|
29688
|
+
} catch (err) {
|
|
29689
|
+
logger.error("error getting funding rates", err);
|
|
29690
|
+
return { success: false, data: [] };
|
|
29429
29691
|
}
|
|
29692
|
+
}
|
|
29693
|
+
async getPosition(supportedPosition) {
|
|
29430
29694
|
const holdings = await this.getExtendedDepositAmount();
|
|
29431
29695
|
if (!holdings) {
|
|
29432
29696
|
throw new Error("No position found");
|
|
@@ -29434,7 +29698,7 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29434
29698
|
const amount = holdings.equity;
|
|
29435
29699
|
return Promise.resolve({
|
|
29436
29700
|
amount: new Web3Number(amount, 0),
|
|
29437
|
-
remarks:
|
|
29701
|
+
remarks: `Extended Equity`
|
|
29438
29702
|
});
|
|
29439
29703
|
}
|
|
29440
29704
|
async maxDeposit(amount) {
|
|
@@ -29458,14 +29722,14 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29458
29722
|
});
|
|
29459
29723
|
}
|
|
29460
29724
|
_getDepositLeaf() {
|
|
29461
|
-
const usdceToken = Global.getDefaultTokens().find(
|
|
29725
|
+
const usdceToken = Global.getDefaultTokens().find(
|
|
29726
|
+
(token) => token.symbol === "USDCe"
|
|
29727
|
+
);
|
|
29462
29728
|
return [
|
|
29463
29729
|
{
|
|
29464
29730
|
target: this.config.supportedPositions[0].asset.address,
|
|
29465
29731
|
method: "approve",
|
|
29466
|
-
packedArguments: [
|
|
29467
|
-
AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt()
|
|
29468
|
-
],
|
|
29732
|
+
packedArguments: [AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt()],
|
|
29469
29733
|
id: `extended_approve_${this.config.supportedPositions[0].asset.symbol}`,
|
|
29470
29734
|
sanitizer: AVNU_LEGACY_SANITIZER
|
|
29471
29735
|
},
|
|
@@ -29496,25 +29760,33 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29496
29760
|
const leafConfigs = this._getSwapFromLegacyLeaf();
|
|
29497
29761
|
const leaves = leafConfigs.map((config) => {
|
|
29498
29762
|
const { target, method, packedArguments, sanitizer, id } = config;
|
|
29499
|
-
const leaf = this.constructSimpleLeafData(
|
|
29500
|
-
|
|
29501
|
-
|
|
29502
|
-
|
|
29503
|
-
|
|
29504
|
-
|
|
29763
|
+
const leaf = this.constructSimpleLeafData(
|
|
29764
|
+
{
|
|
29765
|
+
id,
|
|
29766
|
+
target,
|
|
29767
|
+
method,
|
|
29768
|
+
packedArguments
|
|
29769
|
+
},
|
|
29770
|
+
sanitizer
|
|
29771
|
+
);
|
|
29505
29772
|
return leaf;
|
|
29506
29773
|
});
|
|
29507
|
-
return {
|
|
29774
|
+
return {
|
|
29775
|
+
leaves,
|
|
29776
|
+
callConstructor: this.getSwapFromLegacyCall.bind(
|
|
29777
|
+
this
|
|
29778
|
+
)
|
|
29779
|
+
};
|
|
29508
29780
|
}
|
|
29509
29781
|
_getSwapFromLegacyLeaf() {
|
|
29510
|
-
const usdceToken = Global.getDefaultTokens().find(
|
|
29782
|
+
const usdceToken = Global.getDefaultTokens().find(
|
|
29783
|
+
(token) => token.symbol === "USDCe"
|
|
29784
|
+
);
|
|
29511
29785
|
return [
|
|
29512
29786
|
{
|
|
29513
29787
|
target: usdceToken.address,
|
|
29514
29788
|
method: "approve",
|
|
29515
|
-
packedArguments: [
|
|
29516
|
-
AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt()
|
|
29517
|
-
],
|
|
29789
|
+
packedArguments: [AVNU_EXCHANGE_FOR_LEGACY_USDC.toBigInt()],
|
|
29518
29790
|
id: `extendedswaplegacyapprove_${usdceToken.symbol}`,
|
|
29519
29791
|
sanitizer: AVNU_LEGACY_SANITIZER
|
|
29520
29792
|
},
|
|
@@ -29533,11 +29805,13 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29533
29805
|
async getDepositCall(params) {
|
|
29534
29806
|
try {
|
|
29535
29807
|
const usdcToken = this.config.supportedPositions[0].asset;
|
|
29536
|
-
const usdceToken = Global.getDefaultTokens().find(
|
|
29537
|
-
|
|
29538
|
-
|
|
29808
|
+
const usdceToken = Global.getDefaultTokens().find(
|
|
29809
|
+
(token) => token.symbol === "USDCe"
|
|
29810
|
+
);
|
|
29811
|
+
const salt = Math.floor(Math.random() * 10 ** usdcToken.decimals);
|
|
29812
|
+
const amount = uint25613.bnToUint256(
|
|
29813
|
+
params.amount.multipliedBy(10).toWei()
|
|
29539
29814
|
);
|
|
29540
|
-
const amount = uint25613.bnToUint256(params.amount.multipliedBy(10).toWei());
|
|
29541
29815
|
const quotes = await this.config.avnuAdapter.getQuotesAvnu(
|
|
29542
29816
|
usdcToken.address.toString(),
|
|
29543
29817
|
usdceToken.address.toString(),
|
|
@@ -29550,7 +29824,9 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29550
29824
|
logger.error("error getting quotes from avnu");
|
|
29551
29825
|
return [];
|
|
29552
29826
|
}
|
|
29553
|
-
const getCalldata = await this.config.avnuAdapter.getSwapCallData(
|
|
29827
|
+
const getCalldata = await this.config.avnuAdapter.getSwapCallData(
|
|
29828
|
+
quotes
|
|
29829
|
+
);
|
|
29554
29830
|
const swapCallData = getCalldata[0];
|
|
29555
29831
|
return [
|
|
29556
29832
|
{
|
|
@@ -29626,8 +29902,12 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29626
29902
|
async getSwapFromLegacyCall(params) {
|
|
29627
29903
|
try {
|
|
29628
29904
|
const usdcToken = this.config.supportedPositions[0].asset;
|
|
29629
|
-
const usdceToken = Global.getDefaultTokens().find(
|
|
29630
|
-
|
|
29905
|
+
const usdceToken = Global.getDefaultTokens().find(
|
|
29906
|
+
(token) => token.symbol === "USDCe"
|
|
29907
|
+
);
|
|
29908
|
+
const amount = uint25613.bnToUint256(
|
|
29909
|
+
params.amount.multipliedBy(10).toWei()
|
|
29910
|
+
);
|
|
29631
29911
|
const quotes = await this.config.avnuAdapter.getQuotesAvnu(
|
|
29632
29912
|
usdceToken.address.toString(),
|
|
29633
29913
|
usdcToken.address.toString(),
|
|
@@ -29640,7 +29920,9 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29640
29920
|
logger.error("error getting quotes from avnu");
|
|
29641
29921
|
return [];
|
|
29642
29922
|
}
|
|
29643
|
-
const getCalldata = await this.config.avnuAdapter.getSwapCallData(
|
|
29923
|
+
const getCalldata = await this.config.avnuAdapter.getSwapCallData(
|
|
29924
|
+
quotes
|
|
29925
|
+
);
|
|
29644
29926
|
const swapCallData = getCalldata[0];
|
|
29645
29927
|
return [
|
|
29646
29928
|
{
|
|
@@ -29686,38 +29968,131 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29686
29968
|
async withdrawFromExtended(amount) {
|
|
29687
29969
|
try {
|
|
29688
29970
|
if (!this.client) {
|
|
29689
|
-
|
|
29971
|
+
logger.error("Client not initialized");
|
|
29972
|
+
return {
|
|
29973
|
+
status: false,
|
|
29974
|
+
receivedTxnHash: false
|
|
29975
|
+
};
|
|
29976
|
+
}
|
|
29977
|
+
if (amount.lessThanOrEqualTo(0)) {
|
|
29978
|
+
logger.error(
|
|
29979
|
+
`Invalid withdrawal amount: ${amount.toNumber()}. Amount must be positive.`
|
|
29980
|
+
);
|
|
29981
|
+
return {
|
|
29982
|
+
status: false,
|
|
29983
|
+
receivedTxnHash: false
|
|
29984
|
+
};
|
|
29985
|
+
}
|
|
29986
|
+
if (amount.lessThanOrEqualTo(this.minimumExtendedMovementAmount)) {
|
|
29987
|
+
logger.warn(
|
|
29988
|
+
`Withdrawal amount ${amount.toNumber()} is below minimum Extended movement amount ${this.minimumExtendedMovementAmount}. Skipping withdrawal.`
|
|
29989
|
+
);
|
|
29990
|
+
return {
|
|
29991
|
+
status: false,
|
|
29992
|
+
receivedTxnHash: false
|
|
29993
|
+
};
|
|
29994
|
+
}
|
|
29995
|
+
const holdings = await this.getExtendedDepositAmount();
|
|
29996
|
+
if (!holdings) {
|
|
29997
|
+
logger.error(
|
|
29998
|
+
"Cannot get holdings - unable to validate withdrawal amount"
|
|
29999
|
+
);
|
|
30000
|
+
return {
|
|
30001
|
+
status: false,
|
|
30002
|
+
receivedTxnHash: false
|
|
30003
|
+
};
|
|
30004
|
+
}
|
|
30005
|
+
const availableForWithdrawal = parseFloat(
|
|
30006
|
+
holdings.availableForWithdrawal
|
|
30007
|
+
);
|
|
30008
|
+
if (!Number.isFinite(availableForWithdrawal) || availableForWithdrawal < 0) {
|
|
30009
|
+
logger.error(
|
|
30010
|
+
`Invalid availableForWithdrawal: ${holdings.availableForWithdrawal}. Expected a finite, non-negative number.`
|
|
30011
|
+
);
|
|
30012
|
+
return {
|
|
30013
|
+
status: false,
|
|
30014
|
+
receivedTxnHash: false
|
|
30015
|
+
};
|
|
30016
|
+
}
|
|
30017
|
+
const withdrawalAmount = amount.toNumber();
|
|
30018
|
+
if (withdrawalAmount > availableForWithdrawal) {
|
|
30019
|
+
logger.error(
|
|
30020
|
+
`Withdrawal amount ${withdrawalAmount} exceeds available balance ${availableForWithdrawal}`
|
|
30021
|
+
);
|
|
30022
|
+
return {
|
|
30023
|
+
status: false,
|
|
30024
|
+
receivedTxnHash: false
|
|
30025
|
+
};
|
|
29690
30026
|
}
|
|
29691
|
-
|
|
30027
|
+
logger.info(
|
|
30028
|
+
`Withdrawing ${withdrawalAmount} from Extended. Available balance: ${availableForWithdrawal}`
|
|
30029
|
+
);
|
|
30030
|
+
const withdrawalRequest = await this.client.withdrawUSDC(
|
|
30031
|
+
amount.toFixed(2)
|
|
30032
|
+
);
|
|
29692
30033
|
if (withdrawalRequest.status === "OK") {
|
|
29693
|
-
const withdrawalStatus = await this.getDepositOrWithdrawalStatus(
|
|
29694
|
-
|
|
30034
|
+
const withdrawalStatus = await this.getDepositOrWithdrawalStatus(
|
|
30035
|
+
withdrawalRequest.data,
|
|
30036
|
+
"WITHDRAWAL" /* WITHDRAWAL */
|
|
30037
|
+
);
|
|
30038
|
+
return {
|
|
30039
|
+
status: true,
|
|
30040
|
+
receivedTxnHash: withdrawalStatus
|
|
30041
|
+
};
|
|
29695
30042
|
}
|
|
29696
|
-
|
|
30043
|
+
logger.error(
|
|
30044
|
+
`Withdrawal request failed with status: ${withdrawalRequest.status}`
|
|
30045
|
+
);
|
|
30046
|
+
return {
|
|
30047
|
+
status: false,
|
|
30048
|
+
receivedTxnHash: false
|
|
30049
|
+
};
|
|
29697
30050
|
} catch (error) {
|
|
29698
30051
|
logger.error(`Error creating Withdraw Call: ${error}`);
|
|
29699
|
-
return
|
|
30052
|
+
return {
|
|
30053
|
+
status: false,
|
|
30054
|
+
receivedTxnHash: false
|
|
30055
|
+
};
|
|
29700
30056
|
}
|
|
29701
30057
|
}
|
|
29702
30058
|
async getHealthFactor() {
|
|
29703
30059
|
return Promise.resolve(1);
|
|
29704
30060
|
}
|
|
29705
30061
|
async getExtendedDepositAmount() {
|
|
29706
|
-
|
|
29707
|
-
|
|
29708
|
-
|
|
29709
|
-
|
|
29710
|
-
|
|
29711
|
-
|
|
29712
|
-
|
|
29713
|
-
|
|
29714
|
-
|
|
29715
|
-
|
|
29716
|
-
|
|
29717
|
-
|
|
30062
|
+
try {
|
|
30063
|
+
const result = await axios8.get(`${this.config.extendedBackendReadUrl}/holdings`);
|
|
30064
|
+
if (!result.data) {
|
|
30065
|
+
logger.error("error getting holdings - API returned null/undefined");
|
|
30066
|
+
return void 0;
|
|
30067
|
+
}
|
|
30068
|
+
if (!result.data.success) {
|
|
30069
|
+
logger.error(
|
|
30070
|
+
`error getting holdings - API returned status: ${result.status}`
|
|
30071
|
+
);
|
|
30072
|
+
return void 0;
|
|
30073
|
+
}
|
|
30074
|
+
const holdings = result.data.data;
|
|
30075
|
+
if (!holdings) {
|
|
30076
|
+
logger.warn(
|
|
30077
|
+
"holdings data is null/undefined - treating as zero balance"
|
|
30078
|
+
);
|
|
30079
|
+
return {
|
|
30080
|
+
collateral_name: "",
|
|
30081
|
+
balance: "0",
|
|
30082
|
+
equity: "0",
|
|
30083
|
+
availableForTrade: "0",
|
|
30084
|
+
availableForWithdrawal: "0",
|
|
30085
|
+
unrealisedPnl: "0",
|
|
30086
|
+
initialMargin: "0",
|
|
30087
|
+
marginRatio: "0",
|
|
30088
|
+
updatedTime: Date.now()
|
|
30089
|
+
};
|
|
30090
|
+
}
|
|
30091
|
+
return holdings;
|
|
30092
|
+
} catch (error) {
|
|
30093
|
+
logger.error(`error getting holdings - exception: ${error}`);
|
|
29718
30094
|
return void 0;
|
|
29719
30095
|
}
|
|
29720
|
-
return holdings;
|
|
29721
30096
|
}
|
|
29722
30097
|
async setLeverage(leverage, marketName) {
|
|
29723
30098
|
if (this.client === null) {
|
|
@@ -29734,46 +30109,52 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29734
30109
|
return false;
|
|
29735
30110
|
}
|
|
29736
30111
|
async getAllOpenPositions() {
|
|
29737
|
-
|
|
29738
|
-
|
|
29739
|
-
|
|
29740
|
-
|
|
29741
|
-
|
|
29742
|
-
|
|
29743
|
-
|
|
29744
|
-
|
|
29745
|
-
if (response.data.length === 0) {
|
|
29746
|
-
return [];
|
|
29747
|
-
} else {
|
|
29748
|
-
return response.data;
|
|
30112
|
+
try {
|
|
30113
|
+
const response = await axios8.get(`${this.config.extendedBackendReadUrl}/positions`);
|
|
30114
|
+
if (response.data.success) {
|
|
30115
|
+
if (response.data.data.length === 0) {
|
|
30116
|
+
return [];
|
|
30117
|
+
} else {
|
|
30118
|
+
return response.data.data;
|
|
30119
|
+
}
|
|
29749
30120
|
}
|
|
30121
|
+
return null;
|
|
30122
|
+
} catch (err) {
|
|
30123
|
+
logger.error("error getting all open positions", err);
|
|
30124
|
+
return null;
|
|
29750
30125
|
}
|
|
29751
|
-
return null;
|
|
29752
30126
|
}
|
|
29753
30127
|
async getOrderHistory(marketName) {
|
|
29754
|
-
|
|
29755
|
-
|
|
30128
|
+
try {
|
|
30129
|
+
const result = await axios8.get(`${this.config.extendedBackendReadUrl}/marketOrders/${marketName}`);
|
|
30130
|
+
if (!result.data.success) {
|
|
30131
|
+
return null;
|
|
30132
|
+
}
|
|
30133
|
+
return result.data.data;
|
|
30134
|
+
} catch (err) {
|
|
30135
|
+
logger.error("error getting order history", err);
|
|
29756
30136
|
return null;
|
|
29757
30137
|
}
|
|
29758
|
-
const result = await this.client.getOrderHistory(marketName);
|
|
29759
|
-
return result.data;
|
|
29760
30138
|
}
|
|
29761
30139
|
async getOrderStatus(orderId, marketName) {
|
|
29762
|
-
|
|
29763
|
-
|
|
29764
|
-
|
|
29765
|
-
|
|
29766
|
-
|
|
29767
|
-
|
|
29768
|
-
|
|
30140
|
+
try {
|
|
30141
|
+
if (this.client === null) {
|
|
30142
|
+
logger.error("error initializing client");
|
|
30143
|
+
return null;
|
|
30144
|
+
}
|
|
30145
|
+
const orderhistory = await this.getOrderHistory(marketName);
|
|
30146
|
+
if (!orderhistory || orderhistory.length === 0) {
|
|
30147
|
+
return null;
|
|
30148
|
+
}
|
|
30149
|
+
const order = orderhistory.slice(0, 20).find((order2) => order2.id.toString() === orderId);
|
|
30150
|
+
if (order) {
|
|
30151
|
+
return order;
|
|
30152
|
+
}
|
|
29769
30153
|
return null;
|
|
29770
|
-
}
|
|
29771
|
-
|
|
29772
|
-
if (!order) {
|
|
29773
|
-
logger.error(`error getting order: ${order}`);
|
|
30154
|
+
} catch (error) {
|
|
30155
|
+
logger.error(`error getting order status: ${error}`);
|
|
29774
30156
|
return null;
|
|
29775
30157
|
}
|
|
29776
|
-
return order;
|
|
29777
30158
|
}
|
|
29778
30159
|
async fetchOrderBookBTCUSDC() {
|
|
29779
30160
|
try {
|
|
@@ -29824,14 +30205,40 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29824
30205
|
logger.error("error depositing or setting leverage");
|
|
29825
30206
|
return null;
|
|
29826
30207
|
}
|
|
29827
|
-
const
|
|
29828
|
-
if (
|
|
30208
|
+
const { ask, bid } = await this.fetchOrderBookBTCUSDC();
|
|
30209
|
+
if (!ask || !bid || ask.lessThanOrEqualTo(0) || bid.lessThanOrEqualTo(0)) {
|
|
30210
|
+
logger.error(
|
|
30211
|
+
`Invalid orderbook prices: ask=${ask?.toNumber()}, bid=${bid?.toNumber()}`
|
|
30212
|
+
);
|
|
29829
30213
|
return null;
|
|
29830
30214
|
}
|
|
29831
|
-
const { ask, bid } = await this.fetchOrderBookBTCUSDC();
|
|
29832
30215
|
const spread = ask.minus(bid);
|
|
29833
|
-
|
|
29834
|
-
|
|
30216
|
+
const midPrice = ask.plus(bid).div(2);
|
|
30217
|
+
const MAX_PRICE_DEVIATION_MULTIPLIER = 0.5;
|
|
30218
|
+
const priceAdjustmentMultiplier = Math.min(
|
|
30219
|
+
0.2 * attempt,
|
|
30220
|
+
MAX_PRICE_DEVIATION_MULTIPLIER
|
|
30221
|
+
);
|
|
30222
|
+
const priceAdjustment = spread.times(priceAdjustmentMultiplier);
|
|
30223
|
+
let price = midPrice;
|
|
30224
|
+
if (side === "SELL" /* SELL */) {
|
|
30225
|
+
price = midPrice.minus(priceAdjustment);
|
|
30226
|
+
} else {
|
|
30227
|
+
price = midPrice.plus(priceAdjustment);
|
|
30228
|
+
}
|
|
30229
|
+
const maxDeviation = midPrice.times(0.5);
|
|
30230
|
+
if (price.minus(midPrice).abs().greaterThan(maxDeviation)) {
|
|
30231
|
+
logger.error(
|
|
30232
|
+
`Price deviation too large on attempt ${attempt}: price=${price.toNumber()}, midPrice=${midPrice.toNumber()}, deviation=${price.minus(midPrice).abs().toNumber()}`
|
|
30233
|
+
);
|
|
30234
|
+
if (attempt >= maxAttempts) {
|
|
30235
|
+
return null;
|
|
30236
|
+
}
|
|
30237
|
+
price = side === "SELL" /* SELL */ ? midPrice.minus(maxDeviation) : midPrice.plus(maxDeviation);
|
|
30238
|
+
}
|
|
30239
|
+
logger.info(
|
|
30240
|
+
`createOrder attempt ${attempt}/${maxAttempts}: side=${side}, midPrice=${midPrice.toNumber()}, adjustedPrice=${price.toNumber()}, adjustment=${priceAdjustmentMultiplier * 100}%`
|
|
30241
|
+
);
|
|
29835
30242
|
const amount_in_token = (btcAmount * parseInt(leverage)).toFixed(
|
|
29836
30243
|
this.config.extendedPrecision
|
|
29837
30244
|
);
|
|
@@ -29842,14 +30249,57 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29842
30249
|
price.toFixed(0),
|
|
29843
30250
|
side
|
|
29844
30251
|
);
|
|
29845
|
-
if (!result) {
|
|
30252
|
+
if (!result || !result.position_id) {
|
|
30253
|
+
logger.error("Failed to create order - no position_id returned");
|
|
29846
30254
|
return null;
|
|
29847
30255
|
}
|
|
29848
|
-
|
|
29849
|
-
|
|
29850
|
-
|
|
30256
|
+
const positionId = result.position_id;
|
|
30257
|
+
logger.info(
|
|
30258
|
+
`Order created with position_id: ${positionId}. Waiting for API to update...`
|
|
30259
|
+
);
|
|
30260
|
+
let openOrder = await this.getOrderStatus(
|
|
30261
|
+
positionId,
|
|
30262
|
+
this.config.extendedMarketName
|
|
30263
|
+
);
|
|
30264
|
+
const maxStatusRetries = 3;
|
|
30265
|
+
const statusRetryDelay = 5e3;
|
|
30266
|
+
if (!openOrder) {
|
|
30267
|
+
logger.warn(
|
|
30268
|
+
`Order ${positionId} not found in API yet. Retrying status fetch (max ${maxStatusRetries} times)...`
|
|
30269
|
+
);
|
|
30270
|
+
for (let statusRetry = 1; statusRetry <= maxStatusRetries; statusRetry++) {
|
|
30271
|
+
await new Promise((resolve) => setTimeout(resolve, statusRetryDelay));
|
|
30272
|
+
openOrder = await this.getOrderStatus(
|
|
30273
|
+
positionId,
|
|
30274
|
+
this.config.extendedMarketName
|
|
30275
|
+
);
|
|
30276
|
+
if (openOrder) {
|
|
30277
|
+
logger.info(
|
|
30278
|
+
`Order ${positionId} found after ${statusRetry} status retry(ies)`
|
|
30279
|
+
);
|
|
30280
|
+
break;
|
|
30281
|
+
}
|
|
30282
|
+
logger.warn(
|
|
30283
|
+
`Order ${positionId} still not found after ${statusRetry}/${maxStatusRetries} status retries`
|
|
30284
|
+
);
|
|
30285
|
+
}
|
|
30286
|
+
}
|
|
30287
|
+
if (openOrder && openOrder.status === "FILLED" /* FILLED */) {
|
|
30288
|
+
logger.info(
|
|
30289
|
+
`Order ${positionId} successfully filled with quantity ${openOrder.qty}`
|
|
30290
|
+
);
|
|
30291
|
+
return {
|
|
30292
|
+
position_id: positionId,
|
|
30293
|
+
btc_exposure: openOrder.qty
|
|
30294
|
+
};
|
|
30295
|
+
} else if (openOrder && openOrder.status !== "FILLED" /* FILLED */) {
|
|
30296
|
+
logger.warn(
|
|
30297
|
+
`Order ${positionId} found but status is ${openOrder.status}, not FILLED. Retrying order creation...`
|
|
30298
|
+
);
|
|
29851
30299
|
if (attempt >= maxAttempts) {
|
|
29852
|
-
logger.error(
|
|
30300
|
+
logger.error(
|
|
30301
|
+
`Max retries reached \u2014 order ${positionId} status is ${openOrder.status}, not FILLED`
|
|
30302
|
+
);
|
|
29853
30303
|
return null;
|
|
29854
30304
|
} else {
|
|
29855
30305
|
const backoff = 2e3 * attempt;
|
|
@@ -29863,13 +30313,18 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29863
30313
|
);
|
|
29864
30314
|
}
|
|
29865
30315
|
} else {
|
|
30316
|
+
logger.warn(
|
|
30317
|
+
`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.`
|
|
30318
|
+
);
|
|
29866
30319
|
return {
|
|
29867
|
-
position_id:
|
|
29868
|
-
btc_exposure:
|
|
30320
|
+
position_id: positionId,
|
|
30321
|
+
btc_exposure: amount_in_token
|
|
29869
30322
|
};
|
|
29870
30323
|
}
|
|
29871
30324
|
} catch (err) {
|
|
29872
|
-
logger.error(
|
|
30325
|
+
logger.error(
|
|
30326
|
+
`createShortOrder failed on attempt ${attempt}: ${err.message}`
|
|
30327
|
+
);
|
|
29873
30328
|
if (attempt < maxAttempts) {
|
|
29874
30329
|
const backoff = 1200 * attempt;
|
|
29875
30330
|
logger.info(`Retrying after ${backoff}ms...`);
|
|
@@ -29908,28 +30363,101 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29908
30363
|
}
|
|
29909
30364
|
}
|
|
29910
30365
|
async getDepositOrWithdrawalStatus(orderId, operationsType) {
|
|
29911
|
-
|
|
29912
|
-
|
|
29913
|
-
|
|
29914
|
-
|
|
29915
|
-
|
|
29916
|
-
|
|
29917
|
-
|
|
29918
|
-
|
|
29919
|
-
|
|
30366
|
+
const maxAttempts = 15;
|
|
30367
|
+
const retryDelayMs = 3e4;
|
|
30368
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
30369
|
+
try {
|
|
30370
|
+
let transferHistory = await this.client.getAssetOperations({
|
|
30371
|
+
operationsType: [operationsType],
|
|
30372
|
+
operationsStatus: ["COMPLETED" /* COMPLETED */]
|
|
30373
|
+
});
|
|
30374
|
+
if (operationsType === "DEPOSIT" /* DEPOSIT */) {
|
|
30375
|
+
const myTransferStatus = transferHistory.data.find(
|
|
30376
|
+
(operation) => operation.transactionHash?.toLowerCase() === orderId.toString().toLowerCase()
|
|
30377
|
+
);
|
|
30378
|
+
if (!myTransferStatus) {
|
|
30379
|
+
if (attempt < maxAttempts) {
|
|
30380
|
+
logger.info(
|
|
30381
|
+
`Deposit operation not found for transactionHash ${orderId}, retrying (attempt ${attempt}/${maxAttempts})...`
|
|
30382
|
+
);
|
|
30383
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
30384
|
+
continue;
|
|
30385
|
+
}
|
|
30386
|
+
logger.warn(
|
|
30387
|
+
`Deposit operation not found for transactionHash ${orderId} after ${maxAttempts} attempts`
|
|
30388
|
+
);
|
|
30389
|
+
return false;
|
|
30390
|
+
}
|
|
30391
|
+
if (myTransferStatus.status === "COMPLETED" /* COMPLETED */) {
|
|
30392
|
+
logger.info(
|
|
30393
|
+
`Deposit operation ${orderId} completed successfully`
|
|
30394
|
+
);
|
|
30395
|
+
return true;
|
|
30396
|
+
} else {
|
|
30397
|
+
if (attempt < maxAttempts) {
|
|
30398
|
+
logger.info(
|
|
30399
|
+
`Deposit operation ${orderId} found but status is ${myTransferStatus.status}, not COMPLETED. Retrying (attempt ${attempt}/${maxAttempts})...`
|
|
30400
|
+
);
|
|
30401
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
30402
|
+
continue;
|
|
30403
|
+
}
|
|
30404
|
+
logger.warn(
|
|
30405
|
+
`Deposit operation ${orderId} status is ${myTransferStatus.status} after ${maxAttempts} attempts, expected COMPLETED`
|
|
30406
|
+
);
|
|
30407
|
+
return false;
|
|
30408
|
+
}
|
|
30409
|
+
} else {
|
|
30410
|
+
const myTransferStatus = transferHistory.data.find(
|
|
30411
|
+
(operation) => operation.id === orderId.toString()
|
|
30412
|
+
);
|
|
30413
|
+
if (!myTransferStatus) {
|
|
30414
|
+
if (attempt < maxAttempts) {
|
|
30415
|
+
logger.info(
|
|
30416
|
+
`Withdrawal status not found for orderId ${orderId} in completed operations, retrying (attempt ${attempt}/${maxAttempts})...`
|
|
30417
|
+
);
|
|
30418
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
30419
|
+
continue;
|
|
30420
|
+
}
|
|
30421
|
+
logger.warn(
|
|
30422
|
+
`Withdrawal operation not found for orderId ${orderId} after ${maxAttempts} attempts`
|
|
30423
|
+
);
|
|
30424
|
+
return false;
|
|
30425
|
+
}
|
|
30426
|
+
if (myTransferStatus.status === "COMPLETED" /* COMPLETED */) {
|
|
30427
|
+
logger.info(
|
|
30428
|
+
`Withdrawal operation ${orderId} completed successfully`
|
|
30429
|
+
);
|
|
30430
|
+
return true;
|
|
30431
|
+
} else {
|
|
30432
|
+
if (attempt < maxAttempts) {
|
|
30433
|
+
logger.info(
|
|
30434
|
+
`Withdrawal operation ${orderId} found but status is ${myTransferStatus.status}, not COMPLETED. Retrying (attempt ${attempt}/${maxAttempts})...`
|
|
30435
|
+
);
|
|
30436
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
30437
|
+
continue;
|
|
30438
|
+
}
|
|
30439
|
+
logger.warn(
|
|
30440
|
+
`Withdrawal operation ${orderId} status is ${myTransferStatus.status} after ${maxAttempts} attempts, expected COMPLETED`
|
|
30441
|
+
);
|
|
30442
|
+
return false;
|
|
30443
|
+
}
|
|
29920
30444
|
}
|
|
29921
|
-
|
|
29922
|
-
|
|
29923
|
-
|
|
29924
|
-
|
|
29925
|
-
|
|
30445
|
+
} catch (err) {
|
|
30446
|
+
logger.error(
|
|
30447
|
+
`error getting deposit or withdrawal status (attempt ${attempt}/${maxAttempts}): ${err}`
|
|
30448
|
+
);
|
|
30449
|
+
if (attempt < maxAttempts) {
|
|
30450
|
+
logger.info(`Retrying after ${retryDelayMs}ms...`);
|
|
30451
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
30452
|
+
continue;
|
|
29926
30453
|
}
|
|
29927
|
-
|
|
30454
|
+
logger.error(
|
|
30455
|
+
`Max retry attempts reached for getDepositOrWithdrawalStatus`
|
|
30456
|
+
);
|
|
30457
|
+
return false;
|
|
29928
30458
|
}
|
|
29929
|
-
} catch (err) {
|
|
29930
|
-
logger.error(`error getting deposit or withdrawal status: ${err}`);
|
|
29931
|
-
return false;
|
|
29932
30459
|
}
|
|
30460
|
+
return false;
|
|
29933
30461
|
}
|
|
29934
30462
|
};
|
|
29935
30463
|
|
|
@@ -30009,12 +30537,351 @@ var UnusedBalanceAdapter = class _UnusedBalanceAdapter extends BaseAdapter {
|
|
|
30009
30537
|
}
|
|
30010
30538
|
};
|
|
30011
30539
|
|
|
30540
|
+
// src/strategies/universal-adapters/avnu-adapter.ts
|
|
30541
|
+
import { hash as hash7, uint256 as uint25614 } from "starknet";
|
|
30542
|
+
import axios9 from "axios";
|
|
30543
|
+
var AvnuAdapter = class _AvnuAdapter extends BaseAdapter {
|
|
30544
|
+
constructor(config) {
|
|
30545
|
+
super(config, _AvnuAdapter.name, Protocols.AVNU);
|
|
30546
|
+
this.config = config;
|
|
30547
|
+
this.avnuWrapper = new AvnuWrapper();
|
|
30548
|
+
}
|
|
30549
|
+
//abstract means the method has no implementation in this class; instead, child classes must implement it.
|
|
30550
|
+
async getAPY(supportedPosition) {
|
|
30551
|
+
return Promise.resolve({ apy: 0, type: "base" /* BASE */ });
|
|
30552
|
+
}
|
|
30553
|
+
async getPosition(supportedPosition) {
|
|
30554
|
+
return Promise.resolve({ amount: new Web3Number(0, 0), remarks: "Avnu Positions" });
|
|
30555
|
+
}
|
|
30556
|
+
async maxDeposit(amount) {
|
|
30557
|
+
return Promise.resolve({
|
|
30558
|
+
tokenInfo: this.config.baseToken,
|
|
30559
|
+
amount: new Web3Number(0, 0),
|
|
30560
|
+
usdValue: 0,
|
|
30561
|
+
apy: { apy: 0, type: "base" /* BASE */ },
|
|
30562
|
+
protocol: Protocols.AVNU,
|
|
30563
|
+
remarks: ""
|
|
30564
|
+
});
|
|
30565
|
+
}
|
|
30566
|
+
async maxWithdraw() {
|
|
30567
|
+
return Promise.resolve({
|
|
30568
|
+
tokenInfo: this.config.baseToken,
|
|
30569
|
+
amount: new Web3Number(0, 0),
|
|
30570
|
+
usdValue: 0,
|
|
30571
|
+
apy: { apy: 0, type: "base" /* BASE */ },
|
|
30572
|
+
protocol: Protocols.AVNU,
|
|
30573
|
+
remarks: ""
|
|
30574
|
+
});
|
|
30575
|
+
}
|
|
30576
|
+
_getDepositLeaf() {
|
|
30577
|
+
const vaultAllocator = ContractAddr.from(
|
|
30578
|
+
this.config.vaultAllocator.address
|
|
30579
|
+
);
|
|
30580
|
+
return [
|
|
30581
|
+
{
|
|
30582
|
+
target: this.config.supportedPositions[0].asset.address,
|
|
30583
|
+
method: "approve",
|
|
30584
|
+
packedArguments: [
|
|
30585
|
+
AVNU_EXCHANGE.toBigInt()
|
|
30586
|
+
],
|
|
30587
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
30588
|
+
id: `approve_${this.config.supportedPositions[0].asset.symbol}`
|
|
30589
|
+
},
|
|
30590
|
+
{
|
|
30591
|
+
target: AVNU_EXCHANGE,
|
|
30592
|
+
method: "multi_route_swap",
|
|
30593
|
+
packedArguments: [
|
|
30594
|
+
this.config.supportedPositions[0].asset.address.toBigInt(),
|
|
30595
|
+
//usdc
|
|
30596
|
+
this.config.supportedPositions[1].asset.address.toBigInt(),
|
|
30597
|
+
//wbtc
|
|
30598
|
+
vaultAllocator.toBigInt()
|
|
30599
|
+
],
|
|
30600
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
30601
|
+
id: `asutb_${this.config.supportedPositions[0].asset.symbol}_${this.config.supportedPositions[1].asset.symbol}`
|
|
30602
|
+
}
|
|
30603
|
+
];
|
|
30604
|
+
}
|
|
30605
|
+
_getWithdrawLeaf() {
|
|
30606
|
+
const vaultAllocator = ContractAddr.from(
|
|
30607
|
+
this.config.vaultAllocator.address
|
|
30608
|
+
);
|
|
30609
|
+
const toToken = this.config.supportedPositions[0].asset;
|
|
30610
|
+
const fromToken = this.config.supportedPositions[1].asset;
|
|
30611
|
+
return [
|
|
30612
|
+
{
|
|
30613
|
+
target: fromToken.address,
|
|
30614
|
+
method: "approve",
|
|
30615
|
+
packedArguments: [
|
|
30616
|
+
AVNU_EXCHANGE.toBigInt()
|
|
30617
|
+
],
|
|
30618
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
30619
|
+
id: `approve_${fromToken.symbol}`
|
|
30620
|
+
},
|
|
30621
|
+
{
|
|
30622
|
+
target: AVNU_EXCHANGE,
|
|
30623
|
+
method: "multi_route_swap",
|
|
30624
|
+
packedArguments: [
|
|
30625
|
+
fromToken.address.toBigInt(),
|
|
30626
|
+
//wbtc
|
|
30627
|
+
toToken.address.toBigInt(),
|
|
30628
|
+
//usdc
|
|
30629
|
+
vaultAllocator.toBigInt()
|
|
30630
|
+
],
|
|
30631
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
30632
|
+
id: `asbtu_${fromToken.symbol}_${fromToken.symbol}`
|
|
30633
|
+
}
|
|
30634
|
+
];
|
|
30635
|
+
}
|
|
30636
|
+
_getLegacySwapLeaf() {
|
|
30637
|
+
return [];
|
|
30638
|
+
}
|
|
30639
|
+
async getDepositCall(params) {
|
|
30640
|
+
try {
|
|
30641
|
+
const fromToken = this.config.supportedPositions[0].asset;
|
|
30642
|
+
const toToken = this.config.supportedPositions[1].asset;
|
|
30643
|
+
const vaultAllocator = ContractAddr.from(
|
|
30644
|
+
this.config.vaultAllocator.address
|
|
30645
|
+
);
|
|
30646
|
+
const quote = await this.getQuotesAvnu(
|
|
30647
|
+
fromToken.address.toString(),
|
|
30648
|
+
toToken.address.toString(),
|
|
30649
|
+
params.amount.toNumber(),
|
|
30650
|
+
vaultAllocator.address.toString(),
|
|
30651
|
+
toToken.decimals,
|
|
30652
|
+
true
|
|
30653
|
+
);
|
|
30654
|
+
if (!quote) {
|
|
30655
|
+
logger.error("error getting quote from avnu");
|
|
30656
|
+
return [];
|
|
30657
|
+
}
|
|
30658
|
+
const getCalldata = await this.avnuWrapper.getSwapCallData(
|
|
30659
|
+
quote,
|
|
30660
|
+
vaultAllocator.address
|
|
30661
|
+
);
|
|
30662
|
+
const swapCallData = getCalldata[0];
|
|
30663
|
+
const amount = uint25614.bnToUint256(quote.sellAmountInUsd * 10 ** 7);
|
|
30664
|
+
return [
|
|
30665
|
+
{
|
|
30666
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
30667
|
+
call: {
|
|
30668
|
+
contractAddress: fromToken.address,
|
|
30669
|
+
selector: hash7.getSelectorFromName("approve"),
|
|
30670
|
+
calldata: [
|
|
30671
|
+
AVNU_EXCHANGE.toBigInt(),
|
|
30672
|
+
toBigInt(amount.low.toString()),
|
|
30673
|
+
// amount low
|
|
30674
|
+
toBigInt(amount.high.toString())
|
|
30675
|
+
// amount high
|
|
30676
|
+
]
|
|
30677
|
+
}
|
|
30678
|
+
},
|
|
30679
|
+
{
|
|
30680
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
30681
|
+
call: {
|
|
30682
|
+
contractAddress: AVNU_EXCHANGE,
|
|
30683
|
+
selector: hash7.getSelectorFromName("multi_route_swap"),
|
|
30684
|
+
calldata: swapCallData
|
|
30685
|
+
}
|
|
30686
|
+
}
|
|
30687
|
+
];
|
|
30688
|
+
} catch (error) {
|
|
30689
|
+
logger.error(`Error getting Avnu quote: ${error}`);
|
|
30690
|
+
return [];
|
|
30691
|
+
}
|
|
30692
|
+
}
|
|
30693
|
+
//Swap wbtc to usdc
|
|
30694
|
+
async getWithdrawCall(params) {
|
|
30695
|
+
try {
|
|
30696
|
+
const toToken = this.config.supportedPositions[0].asset;
|
|
30697
|
+
const fromToken = this.config.supportedPositions[1].asset;
|
|
30698
|
+
const vaultAllocator = ContractAddr.from(
|
|
30699
|
+
this.config.vaultAllocator.address
|
|
30700
|
+
);
|
|
30701
|
+
const quote = await this.getQuotesAvnu(
|
|
30702
|
+
fromToken.address.toString(),
|
|
30703
|
+
toToken.address.toString(),
|
|
30704
|
+
params.amount.toNumber(),
|
|
30705
|
+
vaultAllocator.address.toString(),
|
|
30706
|
+
fromToken.decimals,
|
|
30707
|
+
false
|
|
30708
|
+
);
|
|
30709
|
+
if (!quote) {
|
|
30710
|
+
logger.error("No quotes available for this swap, error in quotes avnu");
|
|
30711
|
+
return [];
|
|
30712
|
+
}
|
|
30713
|
+
const getCalldata = await this.avnuWrapper.getSwapCallData(
|
|
30714
|
+
quote,
|
|
30715
|
+
vaultAllocator.address
|
|
30716
|
+
);
|
|
30717
|
+
const swapCallData = getCalldata[0];
|
|
30718
|
+
const amount = uint25614.bnToUint256(params.amount.toWei());
|
|
30719
|
+
return [
|
|
30720
|
+
{
|
|
30721
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
30722
|
+
call: {
|
|
30723
|
+
contractAddress: fromToken.address,
|
|
30724
|
+
selector: hash7.getSelectorFromName("approve"),
|
|
30725
|
+
calldata: [
|
|
30726
|
+
AVNU_EXCHANGE.toBigInt(),
|
|
30727
|
+
toBigInt(amount.low.toString()),
|
|
30728
|
+
// amount low
|
|
30729
|
+
toBigInt(amount.high.toString())
|
|
30730
|
+
// amount high
|
|
30731
|
+
]
|
|
30732
|
+
}
|
|
30733
|
+
},
|
|
30734
|
+
{
|
|
30735
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
30736
|
+
call: {
|
|
30737
|
+
contractAddress: AVNU_EXCHANGE,
|
|
30738
|
+
selector: hash7.getSelectorFromName("multi_route_swap"),
|
|
30739
|
+
calldata: swapCallData
|
|
30740
|
+
}
|
|
30741
|
+
}
|
|
30742
|
+
];
|
|
30743
|
+
} catch (error) {
|
|
30744
|
+
logger.error(`Error getting Avnu quote: ${error}`);
|
|
30745
|
+
return [];
|
|
30746
|
+
}
|
|
30747
|
+
}
|
|
30748
|
+
async getSwapCallData(quote) {
|
|
30749
|
+
return await this.avnuWrapper.getSwapCallData(quote, this.config.vaultAllocator.address);
|
|
30750
|
+
}
|
|
30751
|
+
async getHealthFactor() {
|
|
30752
|
+
return Promise.resolve(1);
|
|
30753
|
+
}
|
|
30754
|
+
async fetchQuoteWithRetry(params, retries = 5) {
|
|
30755
|
+
for (let attempt = 0; attempt < retries; attempt++) {
|
|
30756
|
+
try {
|
|
30757
|
+
const response = await axios9.get(this.config.baseUrl, { params });
|
|
30758
|
+
if (response.data && response.data.length > 0) {
|
|
30759
|
+
return response;
|
|
30760
|
+
}
|
|
30761
|
+
throw new Error("Empty response data");
|
|
30762
|
+
} catch (err) {
|
|
30763
|
+
logger.error(`Error fetching quote with retry: ${err}`);
|
|
30764
|
+
if (attempt === retries - 1) {
|
|
30765
|
+
throw err;
|
|
30766
|
+
}
|
|
30767
|
+
await new Promise((resolve) => setTimeout(resolve, MAX_DELAY));
|
|
30768
|
+
}
|
|
30769
|
+
}
|
|
30770
|
+
throw new Error("Failed to fetch quote after retries");
|
|
30771
|
+
}
|
|
30772
|
+
async getQuotesAvnu(from_token_address, to_token_address, amount, takerAddress, toTokenDecimals, usdcToBtc, maxIterations = 5, tolerance = 5e3) {
|
|
30773
|
+
try {
|
|
30774
|
+
const fromToken = this.config.supportedPositions[0].asset;
|
|
30775
|
+
const toToken = this.config.supportedPositions[1].asset;
|
|
30776
|
+
if (!usdcToBtc) {
|
|
30777
|
+
const sellAmount2 = returnFormattedAmount(amount, toTokenDecimals);
|
|
30778
|
+
const params2 = {
|
|
30779
|
+
sellTokenAddress: from_token_address,
|
|
30780
|
+
buyTokenAddress: to_token_address,
|
|
30781
|
+
takerAddress,
|
|
30782
|
+
sellAmount: sellAmount2
|
|
30783
|
+
};
|
|
30784
|
+
const finalQuote2 = await this.fetchQuoteWithRetry(params2);
|
|
30785
|
+
if (!finalQuote2.data.length) {
|
|
30786
|
+
logger.error("No quotes available for this swap, error in quotes avnu");
|
|
30787
|
+
return null;
|
|
30788
|
+
}
|
|
30789
|
+
const dataObject2 = finalQuote2.data[0];
|
|
30790
|
+
return dataObject2;
|
|
30791
|
+
}
|
|
30792
|
+
const btcPrice = await this.getPriceOfToken(toToken.address.toString());
|
|
30793
|
+
if (!btcPrice) {
|
|
30794
|
+
logger.error(`error getting btc price: ${btcPrice}`);
|
|
30795
|
+
return null;
|
|
30796
|
+
}
|
|
30797
|
+
const estimatedUsdcAmount = Math.floor(amount * btcPrice);
|
|
30798
|
+
logger.info(`${_AvnuAdapter.name}::getQuotesAvnu estimatedUsdcAmount: ${estimatedUsdcAmount}`);
|
|
30799
|
+
const targetBtcBig = BigInt(returnFormattedAmount(amount, toTokenDecimals));
|
|
30800
|
+
logger.info(`${_AvnuAdapter.name}::getQuotesAvnu targetBtcBig: ${targetBtcBig}`);
|
|
30801
|
+
let low = BigInt(
|
|
30802
|
+
Math.floor(
|
|
30803
|
+
estimatedUsdcAmount * 10 ** fromToken.decimals * 0.9
|
|
30804
|
+
)
|
|
30805
|
+
);
|
|
30806
|
+
let high = BigInt(
|
|
30807
|
+
Math.floor(
|
|
30808
|
+
estimatedUsdcAmount * 10 ** fromToken.decimals * 1.1
|
|
30809
|
+
)
|
|
30810
|
+
);
|
|
30811
|
+
let mid = 0n;
|
|
30812
|
+
for (let i = 0; i < maxIterations; i++) {
|
|
30813
|
+
mid = (low + high) / 2n;
|
|
30814
|
+
const sellAmount2 = returnFormattedAmount(Number(mid), 0);
|
|
30815
|
+
const quote = await this.fetchQuoteWithRetry({
|
|
30816
|
+
sellTokenAddress: from_token_address,
|
|
30817
|
+
buyTokenAddress: to_token_address,
|
|
30818
|
+
takerAddress,
|
|
30819
|
+
sellAmount: sellAmount2
|
|
30820
|
+
});
|
|
30821
|
+
const gotBtc = BigInt(quote.data[0].buyAmount);
|
|
30822
|
+
if (gotBtc === targetBtcBig) return quote.data[0];
|
|
30823
|
+
if (gotBtc > targetBtcBig) {
|
|
30824
|
+
high = mid;
|
|
30825
|
+
} else {
|
|
30826
|
+
low = mid;
|
|
30827
|
+
}
|
|
30828
|
+
if (gotBtc >= targetBtcBig && gotBtc <= targetBtcBig + BigInt(tolerance)) {
|
|
30829
|
+
return quote.data[0];
|
|
30830
|
+
}
|
|
30831
|
+
}
|
|
30832
|
+
let sellAmount = returnFormattedAmount(
|
|
30833
|
+
Number(mid),
|
|
30834
|
+
0
|
|
30835
|
+
);
|
|
30836
|
+
const params = {
|
|
30837
|
+
sellTokenAddress: from_token_address,
|
|
30838
|
+
buyTokenAddress: to_token_address,
|
|
30839
|
+
takerAddress,
|
|
30840
|
+
sellAmount
|
|
30841
|
+
};
|
|
30842
|
+
const finalQuote = await this.fetchQuoteWithRetry(params);
|
|
30843
|
+
if (!finalQuote.data.length) {
|
|
30844
|
+
logger.error("No quotes available for this swap, error in quotes avnu");
|
|
30845
|
+
return null;
|
|
30846
|
+
}
|
|
30847
|
+
const dataObject = finalQuote.data[0];
|
|
30848
|
+
const wbtcAmountOut = parseInt(dataObject.buyAmount.toString(), 16);
|
|
30849
|
+
logger.info(`${_AvnuAdapter.name}::getQuotesAvnu finalAmountOfWbtcOut : ${wbtcAmountOut} ${dataObject.buyAmount} ${dataObject.sellAmount.toString()} ${dataObject.sellAmount.toString()}`);
|
|
30850
|
+
return dataObject;
|
|
30851
|
+
} catch (err) {
|
|
30852
|
+
logger.error(`No quotes available for this swap: ${err}`);
|
|
30853
|
+
return null;
|
|
30854
|
+
}
|
|
30855
|
+
}
|
|
30856
|
+
async getPriceOfToken(tokenAddress, retries = MAX_RETRIES) {
|
|
30857
|
+
try {
|
|
30858
|
+
const url = `https://starknet.impulse.avnu.fi/v1/tokens/${tokenAddress}/prices/line`;
|
|
30859
|
+
const response = await axios9.get(url);
|
|
30860
|
+
const length = response.data.length;
|
|
30861
|
+
return response.data[length - 1].value;
|
|
30862
|
+
} catch (err) {
|
|
30863
|
+
if (retries > 0) {
|
|
30864
|
+
await new Promise((resolve) => setTimeout(resolve, MAX_DELAY));
|
|
30865
|
+
return this.getPriceOfToken(tokenAddress, retries - 1);
|
|
30866
|
+
} else {
|
|
30867
|
+
logger.error(`Failed to fetch price for ${tokenAddress} after ${MAX_RETRIES} attempts`);
|
|
30868
|
+
return null;
|
|
30869
|
+
}
|
|
30870
|
+
}
|
|
30871
|
+
}
|
|
30872
|
+
};
|
|
30873
|
+
|
|
30012
30874
|
// src/strategies/universal-strategy.tsx
|
|
30013
30875
|
var AUMTypes = /* @__PURE__ */ ((AUMTypes2) => {
|
|
30014
30876
|
AUMTypes2["FINALISED"] = "finalised";
|
|
30015
30877
|
AUMTypes2["DEFISPRING"] = "defispring";
|
|
30016
30878
|
return AUMTypes2;
|
|
30017
30879
|
})(AUMTypes || {});
|
|
30880
|
+
var PositionTypeAvnuExtended = /* @__PURE__ */ ((PositionTypeAvnuExtended2) => {
|
|
30881
|
+
PositionTypeAvnuExtended2["OPEN"] = "open";
|
|
30882
|
+
PositionTypeAvnuExtended2["CLOSE"] = "close";
|
|
30883
|
+
return PositionTypeAvnuExtended2;
|
|
30884
|
+
})(PositionTypeAvnuExtended || {});
|
|
30018
30885
|
var UNIVERSAL_MANAGE_IDS = /* @__PURE__ */ ((UNIVERSAL_MANAGE_IDS2) => {
|
|
30019
30886
|
UNIVERSAL_MANAGE_IDS2["FLASH_LOAN"] = "flash_loan_init";
|
|
30020
30887
|
UNIVERSAL_MANAGE_IDS2["VESU_LEG1"] = "vesu_leg1";
|
|
@@ -33195,7 +34062,8 @@ function getLooperSettings(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
|
33195
34062
|
minHealthFactor: vaultSettings.minHealthFactor,
|
|
33196
34063
|
quoteAmountToFetchPrice: vaultSettings.quoteAmountToFetchPrice,
|
|
33197
34064
|
...baseAdapterConfig,
|
|
33198
|
-
supportedPositions: [{ asset: lstToken, isDebt: false }, { asset: Global.getDefaultTokens().find((token) => token.symbol === position), isDebt: true }]
|
|
34065
|
+
supportedPositions: [{ asset: lstToken, isDebt: false }, { asset: Global.getDefaultTokens().find((token) => token.symbol === position), isDebt: true }],
|
|
34066
|
+
minimumVesuMovementAmount: 0
|
|
33199
34067
|
}));
|
|
33200
34068
|
const unusedBalanceAdapter = new UnusedBalanceAdapter({
|
|
33201
34069
|
...baseAdapterConfig
|
|
@@ -33424,335 +34292,15 @@ var HyperLSTStrategies = [
|
|
|
33424
34292
|
getStrategySettings("mRe7YIELD", "mRe7YIELD", hypermRe7YIELD, false, false)
|
|
33425
34293
|
];
|
|
33426
34294
|
|
|
33427
|
-
// src/strategies/
|
|
33428
|
-
|
|
33429
|
-
|
|
33430
|
-
|
|
33431
|
-
|
|
33432
|
-
|
|
33433
|
-
|
|
33434
|
-
|
|
33435
|
-
|
|
33436
|
-
//abstract means the method has no implementation in this class; instead, child classes must implement it.
|
|
33437
|
-
async getAPY(supportedPosition) {
|
|
33438
|
-
return Promise.resolve({ apy: 0, type: "base" /* BASE */ });
|
|
33439
|
-
}
|
|
33440
|
-
async getPosition(supportedPosition) {
|
|
33441
|
-
return Promise.resolve({ amount: new Web3Number(0, 0), remarks: "" });
|
|
33442
|
-
}
|
|
33443
|
-
async maxDeposit(amount) {
|
|
33444
|
-
return Promise.resolve({
|
|
33445
|
-
tokenInfo: this.config.baseToken,
|
|
33446
|
-
amount: new Web3Number(0, 0),
|
|
33447
|
-
usdValue: 0,
|
|
33448
|
-
apy: { apy: 0, type: "base" /* BASE */ },
|
|
33449
|
-
protocol: Protocols.AVNU,
|
|
33450
|
-
remarks: ""
|
|
33451
|
-
});
|
|
33452
|
-
}
|
|
33453
|
-
async maxWithdraw() {
|
|
33454
|
-
return Promise.resolve({
|
|
33455
|
-
tokenInfo: this.config.baseToken,
|
|
33456
|
-
amount: new Web3Number(0, 0),
|
|
33457
|
-
usdValue: 0,
|
|
33458
|
-
apy: { apy: 0, type: "base" /* BASE */ },
|
|
33459
|
-
protocol: Protocols.AVNU,
|
|
33460
|
-
remarks: ""
|
|
33461
|
-
});
|
|
33462
|
-
}
|
|
33463
|
-
_getDepositLeaf() {
|
|
33464
|
-
const vaultAllocator = ContractAddr.from(
|
|
33465
|
-
this.config.vaultAllocator.address
|
|
33466
|
-
);
|
|
33467
|
-
return [
|
|
33468
|
-
{
|
|
33469
|
-
target: this.config.supportedPositions[0].asset.address,
|
|
33470
|
-
method: "approve",
|
|
33471
|
-
packedArguments: [
|
|
33472
|
-
AVNU_EXCHANGE.toBigInt()
|
|
33473
|
-
],
|
|
33474
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
33475
|
-
id: `approve_${this.config.supportedPositions[0].asset.symbol}`
|
|
33476
|
-
},
|
|
33477
|
-
{
|
|
33478
|
-
target: AVNU_EXCHANGE,
|
|
33479
|
-
method: "multi_route_swap",
|
|
33480
|
-
packedArguments: [
|
|
33481
|
-
this.config.supportedPositions[0].asset.address.toBigInt(),
|
|
33482
|
-
//usdc
|
|
33483
|
-
this.config.supportedPositions[1].asset.address.toBigInt(),
|
|
33484
|
-
//wbtc
|
|
33485
|
-
vaultAllocator.toBigInt()
|
|
33486
|
-
],
|
|
33487
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
33488
|
-
id: `asutb_${this.config.supportedPositions[0].asset.symbol}_${this.config.supportedPositions[1].asset.symbol}`
|
|
33489
|
-
}
|
|
33490
|
-
];
|
|
33491
|
-
}
|
|
33492
|
-
_getWithdrawLeaf() {
|
|
33493
|
-
const vaultAllocator = ContractAddr.from(
|
|
33494
|
-
this.config.vaultAllocator.address
|
|
33495
|
-
);
|
|
33496
|
-
const toToken = this.config.supportedPositions[0].asset;
|
|
33497
|
-
const fromToken = this.config.supportedPositions[1].asset;
|
|
33498
|
-
return [
|
|
33499
|
-
{
|
|
33500
|
-
target: fromToken.address,
|
|
33501
|
-
method: "approve",
|
|
33502
|
-
packedArguments: [
|
|
33503
|
-
AVNU_EXCHANGE.toBigInt()
|
|
33504
|
-
],
|
|
33505
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
33506
|
-
id: `approve_${fromToken.symbol}`
|
|
33507
|
-
},
|
|
33508
|
-
{
|
|
33509
|
-
target: AVNU_EXCHANGE,
|
|
33510
|
-
method: "multi_route_swap",
|
|
33511
|
-
packedArguments: [
|
|
33512
|
-
fromToken.address.toBigInt(),
|
|
33513
|
-
//wbtc
|
|
33514
|
-
toToken.address.toBigInt(),
|
|
33515
|
-
//usdc
|
|
33516
|
-
vaultAllocator.toBigInt()
|
|
33517
|
-
],
|
|
33518
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
33519
|
-
id: `asbtu_${fromToken.symbol}_${fromToken.symbol}`
|
|
33520
|
-
}
|
|
33521
|
-
];
|
|
33522
|
-
}
|
|
33523
|
-
_getLegacySwapLeaf() {
|
|
33524
|
-
return [];
|
|
33525
|
-
}
|
|
33526
|
-
async getDepositCall(params) {
|
|
33527
|
-
try {
|
|
33528
|
-
const fromToken = this.config.supportedPositions[0].asset;
|
|
33529
|
-
const toToken = this.config.supportedPositions[1].asset;
|
|
33530
|
-
const vaultAllocator = ContractAddr.from(
|
|
33531
|
-
this.config.vaultAllocator.address
|
|
33532
|
-
);
|
|
33533
|
-
const quote = await this.getQuotesAvnu(
|
|
33534
|
-
fromToken.address.toString(),
|
|
33535
|
-
toToken.address.toString(),
|
|
33536
|
-
params.amount.toNumber(),
|
|
33537
|
-
vaultAllocator.address.toString(),
|
|
33538
|
-
toToken.decimals,
|
|
33539
|
-
true
|
|
33540
|
-
);
|
|
33541
|
-
if (!quote) {
|
|
33542
|
-
logger.error("error getting quote from avnu");
|
|
33543
|
-
return [];
|
|
33544
|
-
}
|
|
33545
|
-
const getCalldata = await this.avnuWrapper.getSwapCallData(
|
|
33546
|
-
quote,
|
|
33547
|
-
vaultAllocator.address
|
|
33548
|
-
);
|
|
33549
|
-
const swapCallData = getCalldata[0];
|
|
33550
|
-
const amount = uint25614.bnToUint256(quote.sellAmountInUsd * 10 ** 7);
|
|
33551
|
-
return [
|
|
33552
|
-
{
|
|
33553
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
33554
|
-
call: {
|
|
33555
|
-
contractAddress: fromToken.address,
|
|
33556
|
-
selector: hash7.getSelectorFromName("approve"),
|
|
33557
|
-
calldata: [
|
|
33558
|
-
AVNU_EXCHANGE.toBigInt(),
|
|
33559
|
-
toBigInt(amount.low.toString()),
|
|
33560
|
-
// amount low
|
|
33561
|
-
toBigInt(amount.high.toString())
|
|
33562
|
-
// amount high
|
|
33563
|
-
]
|
|
33564
|
-
}
|
|
33565
|
-
},
|
|
33566
|
-
{
|
|
33567
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
33568
|
-
call: {
|
|
33569
|
-
contractAddress: AVNU_EXCHANGE,
|
|
33570
|
-
selector: hash7.getSelectorFromName("multi_route_swap"),
|
|
33571
|
-
calldata: swapCallData
|
|
33572
|
-
}
|
|
33573
|
-
}
|
|
33574
|
-
];
|
|
33575
|
-
} catch (error) {
|
|
33576
|
-
logger.error(`Error getting Avnu quote: ${error}`);
|
|
33577
|
-
return [];
|
|
33578
|
-
}
|
|
33579
|
-
}
|
|
33580
|
-
//Swap wbtc to usdc
|
|
33581
|
-
async getWithdrawCall(params) {
|
|
33582
|
-
try {
|
|
33583
|
-
const toToken = this.config.supportedPositions[0].asset;
|
|
33584
|
-
const fromToken = this.config.supportedPositions[1].asset;
|
|
33585
|
-
const vaultAllocator = ContractAddr.from(
|
|
33586
|
-
this.config.vaultAllocator.address
|
|
33587
|
-
);
|
|
33588
|
-
const quote = await this.getQuotesAvnu(
|
|
33589
|
-
fromToken.address.toString(),
|
|
33590
|
-
toToken.address.toString(),
|
|
33591
|
-
params.amount.toNumber(),
|
|
33592
|
-
vaultAllocator.address.toString(),
|
|
33593
|
-
fromToken.decimals,
|
|
33594
|
-
false
|
|
33595
|
-
);
|
|
33596
|
-
if (!quote) {
|
|
33597
|
-
logger.error("No quotes available for this swap, error in quotes avnu");
|
|
33598
|
-
return [];
|
|
33599
|
-
}
|
|
33600
|
-
const getCalldata = await this.avnuWrapper.getSwapCallData(
|
|
33601
|
-
quote,
|
|
33602
|
-
vaultAllocator.address
|
|
33603
|
-
);
|
|
33604
|
-
const swapCallData = getCalldata[0];
|
|
33605
|
-
const amount = uint25614.bnToUint256(params.amount.toWei());
|
|
33606
|
-
return [
|
|
33607
|
-
{
|
|
33608
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
33609
|
-
call: {
|
|
33610
|
-
contractAddress: fromToken.address,
|
|
33611
|
-
selector: hash7.getSelectorFromName("approve"),
|
|
33612
|
-
calldata: [
|
|
33613
|
-
AVNU_EXCHANGE.toBigInt(),
|
|
33614
|
-
toBigInt(amount.low.toString()),
|
|
33615
|
-
// amount low
|
|
33616
|
-
toBigInt(amount.high.toString())
|
|
33617
|
-
// amount high
|
|
33618
|
-
]
|
|
33619
|
-
}
|
|
33620
|
-
},
|
|
33621
|
-
{
|
|
33622
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
33623
|
-
call: {
|
|
33624
|
-
contractAddress: AVNU_EXCHANGE,
|
|
33625
|
-
selector: hash7.getSelectorFromName("multi_route_swap"),
|
|
33626
|
-
calldata: swapCallData
|
|
33627
|
-
}
|
|
33628
|
-
}
|
|
33629
|
-
];
|
|
33630
|
-
} catch (error) {
|
|
33631
|
-
logger.error(`Error getting Avnu quote: ${error}`);
|
|
33632
|
-
return [];
|
|
33633
|
-
}
|
|
33634
|
-
}
|
|
33635
|
-
async getSwapCallData(quote) {
|
|
33636
|
-
return await this.avnuWrapper.getSwapCallData(quote, this.config.vaultAllocator.address);
|
|
33637
|
-
}
|
|
33638
|
-
async getHealthFactor() {
|
|
33639
|
-
return Promise.resolve(1);
|
|
33640
|
-
}
|
|
33641
|
-
async fetchQuoteWithRetry(params, retries = 5) {
|
|
33642
|
-
for (let attempt = 0; attempt < retries; attempt++) {
|
|
33643
|
-
try {
|
|
33644
|
-
const response = await axios9.get(this.config.baseUrl, { params });
|
|
33645
|
-
if (response.data && response.data.length > 0) {
|
|
33646
|
-
return response;
|
|
33647
|
-
}
|
|
33648
|
-
throw new Error("Empty response data");
|
|
33649
|
-
} catch (err) {
|
|
33650
|
-
logger.error(`Error fetching quote with retry: ${err}`);
|
|
33651
|
-
if (attempt === retries - 1) {
|
|
33652
|
-
throw err;
|
|
33653
|
-
}
|
|
33654
|
-
await new Promise((resolve) => setTimeout(resolve, MAX_DELAY));
|
|
33655
|
-
}
|
|
33656
|
-
}
|
|
33657
|
-
throw new Error("Failed to fetch quote after retries");
|
|
33658
|
-
}
|
|
33659
|
-
async getQuotesAvnu(from_token_address, to_token_address, amount, takerAddress, toTokenDecimals, usdcToBtc, maxIterations = 5, tolerance = 1e4) {
|
|
33660
|
-
try {
|
|
33661
|
-
const fromToken = this.config.supportedPositions[0].asset;
|
|
33662
|
-
const toToken = this.config.supportedPositions[1].asset;
|
|
33663
|
-
if (!usdcToBtc) {
|
|
33664
|
-
const sellAmount2 = returnFormattedAmount(amount, toTokenDecimals);
|
|
33665
|
-
const params2 = {
|
|
33666
|
-
sellTokenAddress: from_token_address,
|
|
33667
|
-
buyTokenAddress: to_token_address,
|
|
33668
|
-
takerAddress,
|
|
33669
|
-
sellAmount: sellAmount2
|
|
33670
|
-
};
|
|
33671
|
-
const finalQuote2 = await this.fetchQuoteWithRetry(params2);
|
|
33672
|
-
if (!finalQuote2.data.length) {
|
|
33673
|
-
logger.error("No quotes available for this swap, error in quotes avnu");
|
|
33674
|
-
return null;
|
|
33675
|
-
}
|
|
33676
|
-
const dataObject2 = finalQuote2.data[0];
|
|
33677
|
-
return dataObject2;
|
|
33678
|
-
}
|
|
33679
|
-
const btcPrice = await this.getPriceOfToken(toToken.address.toString());
|
|
33680
|
-
if (!btcPrice) {
|
|
33681
|
-
logger.error(`error getting btc price: ${btcPrice}`);
|
|
33682
|
-
return null;
|
|
33683
|
-
}
|
|
33684
|
-
const estimatedUsdcAmount = Math.floor(amount * btcPrice);
|
|
33685
|
-
const targetBtcBig = BigInt(returnFormattedAmount(amount, toTokenDecimals));
|
|
33686
|
-
let low = BigInt(
|
|
33687
|
-
Math.floor(
|
|
33688
|
-
estimatedUsdcAmount * 10 ** fromToken.decimals * 0.9
|
|
33689
|
-
)
|
|
33690
|
-
);
|
|
33691
|
-
let high = BigInt(
|
|
33692
|
-
Math.floor(
|
|
33693
|
-
estimatedUsdcAmount * 10 ** fromToken.decimals * 1.1
|
|
33694
|
-
)
|
|
33695
|
-
);
|
|
33696
|
-
let mid = 0n;
|
|
33697
|
-
for (let i = 0; i < maxIterations; i++) {
|
|
33698
|
-
mid = (low + high) / 2n;
|
|
33699
|
-
const sellAmount2 = returnFormattedAmount(Number(mid), 0);
|
|
33700
|
-
const quote = await this.fetchQuoteWithRetry({
|
|
33701
|
-
sellTokenAddress: from_token_address,
|
|
33702
|
-
buyTokenAddress: to_token_address,
|
|
33703
|
-
takerAddress,
|
|
33704
|
-
sellAmount: sellAmount2
|
|
33705
|
-
});
|
|
33706
|
-
const gotBtc = BigInt(quote.data[0].buyAmount);
|
|
33707
|
-
if (gotBtc === targetBtcBig) return quote.data[0];
|
|
33708
|
-
if (gotBtc > targetBtcBig) {
|
|
33709
|
-
high = mid;
|
|
33710
|
-
} else {
|
|
33711
|
-
low = mid;
|
|
33712
|
-
}
|
|
33713
|
-
if (gotBtc >= targetBtcBig && gotBtc <= targetBtcBig + BigInt(tolerance)) {
|
|
33714
|
-
return quote.data[0];
|
|
33715
|
-
}
|
|
33716
|
-
}
|
|
33717
|
-
let sellAmount = returnFormattedAmount(
|
|
33718
|
-
Number(mid),
|
|
33719
|
-
0
|
|
33720
|
-
);
|
|
33721
|
-
const params = {
|
|
33722
|
-
sellTokenAddress: from_token_address,
|
|
33723
|
-
buyTokenAddress: to_token_address,
|
|
33724
|
-
takerAddress,
|
|
33725
|
-
sellAmount
|
|
33726
|
-
};
|
|
33727
|
-
const finalQuote = await this.fetchQuoteWithRetry(params);
|
|
33728
|
-
if (!finalQuote.data.length) {
|
|
33729
|
-
logger.error("No quotes available for this swap, error in quotes avnu");
|
|
33730
|
-
return null;
|
|
33731
|
-
}
|
|
33732
|
-
const dataObject = finalQuote.data[0];
|
|
33733
|
-
return dataObject;
|
|
33734
|
-
} catch (err) {
|
|
33735
|
-
logger.error(`No quotes available for this swap: ${err}`);
|
|
33736
|
-
return null;
|
|
33737
|
-
}
|
|
33738
|
-
}
|
|
33739
|
-
async getPriceOfToken(tokenAddress, retries = MAX_RETRIES) {
|
|
33740
|
-
try {
|
|
33741
|
-
const url = `https://starknet.impulse.avnu.fi/v1/tokens/${tokenAddress}/prices/line`;
|
|
33742
|
-
const response = await axios9.get(url);
|
|
33743
|
-
const length = response.data.length;
|
|
33744
|
-
return response.data[length - 1].value;
|
|
33745
|
-
} catch (err) {
|
|
33746
|
-
if (retries > 0) {
|
|
33747
|
-
await new Promise((resolve) => setTimeout(resolve, MAX_DELAY));
|
|
33748
|
-
return this.getPriceOfToken(tokenAddress, retries - 1);
|
|
33749
|
-
} else {
|
|
33750
|
-
logger.error(`Failed to fetch price for ${tokenAddress} after ${MAX_RETRIES} attempts`);
|
|
33751
|
-
return null;
|
|
33752
|
-
}
|
|
33753
|
-
}
|
|
33754
|
-
}
|
|
33755
|
-
};
|
|
34295
|
+
// src/strategies/vesu-extended-strategy/types/transaction-metadata.ts
|
|
34296
|
+
var CycleType = /* @__PURE__ */ ((CycleType2) => {
|
|
34297
|
+
CycleType2["INVESTMENT"] = "INVESTMENT";
|
|
34298
|
+
CycleType2["REBALANCE_PRICE_DROP"] = "REBALANCE_PRICE_DROP";
|
|
34299
|
+
CycleType2["REBALANCE_PRICE_RISE"] = "REBALANCE_PRICE_RISE";
|
|
34300
|
+
CycleType2["WITHDRAWAL"] = "WITHDRAWAL";
|
|
34301
|
+
CycleType2["DELTA_NEUTRAL_ADJUSTMENT"] = "DELTA_NEUTRAL_ADJUSTMENT";
|
|
34302
|
+
return CycleType2;
|
|
34303
|
+
})(CycleType || {});
|
|
33756
34304
|
|
|
33757
34305
|
// src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx
|
|
33758
34306
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
@@ -33852,15 +34400,30 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
33852
34400
|
const usdceToken = Global.getDefaultTokens().find(
|
|
33853
34401
|
(token) => token.symbol === "USDCe"
|
|
33854
34402
|
);
|
|
34403
|
+
const walletBalance = await new ERC20(this.config).balanceOf(
|
|
34404
|
+
usdceToken.address,
|
|
34405
|
+
WALLET_ADDRESS,
|
|
34406
|
+
usdceToken.decimals
|
|
34407
|
+
);
|
|
34408
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::moveAssetsToVaultAllocator walletBalance: ${walletBalance}`);
|
|
34409
|
+
const amountToBeTransferred = amount.minimum(walletBalance);
|
|
34410
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::moveAssetsToVaultAllocator amountToBeTransferred: ${amountToBeTransferred.toNumber()}`);
|
|
34411
|
+
if (amountToBeTransferred.lessThan(0)) {
|
|
34412
|
+
logger.error(`${_VesuExtendedMultiplierStrategy.name}::moveAssetsToVaultAllocator amountToBeTransferred is less than 0: ${amountToBeTransferred.toNumber()}`);
|
|
34413
|
+
return {
|
|
34414
|
+
calls: [],
|
|
34415
|
+
status: false
|
|
34416
|
+
};
|
|
34417
|
+
}
|
|
33855
34418
|
const approveCall = new ERC20(this.config).approve(
|
|
33856
34419
|
usdceToken.address,
|
|
33857
34420
|
this.metadata.additionalInfo.vaultAllocator,
|
|
33858
|
-
|
|
34421
|
+
amountToBeTransferred
|
|
33859
34422
|
);
|
|
33860
34423
|
const transferCall = new ERC20(this.config).transfer(
|
|
33861
34424
|
usdceToken.address,
|
|
33862
34425
|
this.metadata.additionalInfo.vaultAllocator,
|
|
33863
|
-
|
|
34426
|
+
amountToBeTransferred
|
|
33864
34427
|
);
|
|
33865
34428
|
const proofsInfo = extendedAdapter.getProofsForFromLegacySwap(
|
|
33866
34429
|
this.getMerkleTree()
|
|
@@ -33868,21 +34431,43 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
33868
34431
|
const proofGroups = proofsInfo.proofs;
|
|
33869
34432
|
const call = this.getManageCall(
|
|
33870
34433
|
proofGroups,
|
|
33871
|
-
await proofsInfo.callConstructor({ amount })
|
|
34434
|
+
await proofsInfo.callConstructor({ amount: amountToBeTransferred })
|
|
33872
34435
|
);
|
|
33873
|
-
return
|
|
34436
|
+
return {
|
|
34437
|
+
calls: [approveCall, transferCall, call],
|
|
34438
|
+
status: true
|
|
34439
|
+
};
|
|
33874
34440
|
} catch (err) {
|
|
33875
34441
|
logger.error(`error moving assets to vault allocator: ${err}`);
|
|
33876
|
-
return
|
|
34442
|
+
return {
|
|
34443
|
+
calls: [],
|
|
34444
|
+
status: false
|
|
34445
|
+
};
|
|
33877
34446
|
}
|
|
33878
34447
|
}
|
|
33879
34448
|
async shouldInvest() {
|
|
33880
34449
|
try {
|
|
34450
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest starting`);
|
|
33881
34451
|
const vesuAdapter = await this.getVesuAdapter();
|
|
33882
34452
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
33883
|
-
|
|
34453
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest adapters fetched: vesuAdapter=${!!vesuAdapter}, extendedAdapter=${!!extendedAdapter}, extendedAdapter.client=${!!extendedAdapter?.client}`);
|
|
34454
|
+
if (!vesuAdapter) {
|
|
33884
34455
|
logger.error(
|
|
33885
|
-
`
|
|
34456
|
+
`Vesu adapter not configured in metadata. This is a configuration issue, not a temporary failure.`
|
|
34457
|
+
);
|
|
34458
|
+
return {
|
|
34459
|
+
shouldInvest: false,
|
|
34460
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34461
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34462
|
+
extendedLeverage: 0,
|
|
34463
|
+
collateralPrice: 0,
|
|
34464
|
+
debtPrice: 0,
|
|
34465
|
+
vesuLeverage: 0
|
|
34466
|
+
};
|
|
34467
|
+
}
|
|
34468
|
+
if (!extendedAdapter) {
|
|
34469
|
+
logger.error(
|
|
34470
|
+
`Extended adapter not configured in metadata. This is a configuration issue, not a temporary failure.`
|
|
33886
34471
|
);
|
|
33887
34472
|
return {
|
|
33888
34473
|
shouldInvest: false,
|
|
@@ -33894,10 +34479,73 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
33894
34479
|
vesuLeverage: 0
|
|
33895
34480
|
};
|
|
33896
34481
|
}
|
|
34482
|
+
if (!extendedAdapter.client) {
|
|
34483
|
+
logger.error(
|
|
34484
|
+
`Extended adapter client not initialized. This may be a temporary initialization failure - check network connectivity and API availability.`
|
|
34485
|
+
);
|
|
34486
|
+
return {
|
|
34487
|
+
shouldInvest: false,
|
|
34488
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34489
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34490
|
+
extendedLeverage: 0,
|
|
34491
|
+
collateralPrice: 0,
|
|
34492
|
+
debtPrice: 0,
|
|
34493
|
+
vesuLeverage: 0
|
|
34494
|
+
};
|
|
34495
|
+
}
|
|
34496
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest calling getUnusedBalance`);
|
|
33897
34497
|
const balance = await this.getUnusedBalance();
|
|
34498
|
+
if (!Number.isFinite(balance.usdValue) || balance.usdValue < 0) {
|
|
34499
|
+
logger.error(
|
|
34500
|
+
`Invalid balance.usdValue: ${balance.usdValue}. Expected a finite, non-negative number.`
|
|
34501
|
+
);
|
|
34502
|
+
return {
|
|
34503
|
+
shouldInvest: false,
|
|
34504
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34505
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34506
|
+
extendedLeverage: 0,
|
|
34507
|
+
collateralPrice: 0,
|
|
34508
|
+
debtPrice: 0,
|
|
34509
|
+
vesuLeverage: 0
|
|
34510
|
+
};
|
|
34511
|
+
}
|
|
34512
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest balance: ${balance.usdValue}`);
|
|
33898
34513
|
const usdcBalanceOnExtended = await extendedAdapter.getExtendedDepositAmount();
|
|
33899
|
-
|
|
33900
|
-
|
|
34514
|
+
if (usdcBalanceOnExtended) {
|
|
34515
|
+
const availableForWithdrawal = parseFloat(usdcBalanceOnExtended.availableForWithdrawal);
|
|
34516
|
+
if (!Number.isFinite(availableForWithdrawal) || availableForWithdrawal < 0) {
|
|
34517
|
+
logger.error(
|
|
34518
|
+
`Invalid usdcBalanceOnExtended.availableForWithdrawal: ${usdcBalanceOnExtended.availableForWithdrawal}. Expected a finite, non-negative number.`
|
|
34519
|
+
);
|
|
34520
|
+
return {
|
|
34521
|
+
shouldInvest: false,
|
|
34522
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34523
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34524
|
+
extendedLeverage: 0,
|
|
34525
|
+
collateralPrice: 0,
|
|
34526
|
+
debtPrice: 0,
|
|
34527
|
+
vesuLeverage: 0
|
|
34528
|
+
};
|
|
34529
|
+
}
|
|
34530
|
+
}
|
|
34531
|
+
const amountToInvest = new Web3Number(balance.usdValue, USDC_TOKEN_DECIMALS).plus(usdcBalanceOnExtended?.availableForWithdrawal ?? 0).multipliedBy(1 - LIMIT_BALANCE);
|
|
34532
|
+
const amountToInvestNumber = amountToInvest.toNumber();
|
|
34533
|
+
if (!Number.isFinite(amountToInvestNumber)) {
|
|
34534
|
+
logger.error(
|
|
34535
|
+
`Invalid amountToInvest calculation result: ${amountToInvestNumber}. Calculation may have produced NaN or Infinity.`
|
|
34536
|
+
);
|
|
34537
|
+
return {
|
|
34538
|
+
shouldInvest: false,
|
|
34539
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34540
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34541
|
+
extendedLeverage: 0,
|
|
34542
|
+
collateralPrice: 0,
|
|
34543
|
+
debtPrice: 0,
|
|
34544
|
+
vesuLeverage: 0
|
|
34545
|
+
};
|
|
34546
|
+
}
|
|
34547
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest amountToInvest: ${amountToInvestNumber}`);
|
|
34548
|
+
if (amountToInvest.lessThan(LIMIT_BALANCE_VALUE)) {
|
|
33901
34549
|
return {
|
|
33902
34550
|
shouldInvest: false,
|
|
33903
34551
|
vesuAmount: new Web3Number(0, 0),
|
|
@@ -33926,6 +34574,34 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
33926
34574
|
collateralPrice,
|
|
33927
34575
|
debtPrice
|
|
33928
34576
|
} = await this.getAssetPrices();
|
|
34577
|
+
if (!Number.isFinite(collateralPrice.price) || collateralPrice.price <= 0) {
|
|
34578
|
+
logger.error(
|
|
34579
|
+
`Invalid collateralPrice: ${collateralPrice.price}. Expected a finite, positive number.`
|
|
34580
|
+
);
|
|
34581
|
+
return {
|
|
34582
|
+
shouldInvest: false,
|
|
34583
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34584
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34585
|
+
extendedLeverage: 0,
|
|
34586
|
+
collateralPrice: 0,
|
|
34587
|
+
debtPrice: 0,
|
|
34588
|
+
vesuLeverage: 0
|
|
34589
|
+
};
|
|
34590
|
+
}
|
|
34591
|
+
if (!Number.isFinite(debtPrice.price) || debtPrice.price <= 0) {
|
|
34592
|
+
logger.error(
|
|
34593
|
+
`Invalid debtPrice: ${debtPrice.price}. Expected a finite, positive number.`
|
|
34594
|
+
);
|
|
34595
|
+
return {
|
|
34596
|
+
shouldInvest: false,
|
|
34597
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34598
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34599
|
+
extendedLeverage: 0,
|
|
34600
|
+
collateralPrice: 0,
|
|
34601
|
+
debtPrice: 0,
|
|
34602
|
+
vesuLeverage: 0
|
|
34603
|
+
};
|
|
34604
|
+
}
|
|
33929
34605
|
const { vesu_amount, extended_amount, extended_leverage, vesu_leverage } = await calculateAmountDistribution(
|
|
33930
34606
|
amountToInvest.toNumber(),
|
|
33931
34607
|
extendedAdapter.client,
|
|
@@ -33949,6 +34625,7 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
33949
34625
|
vesuLeverage: 0
|
|
33950
34626
|
};
|
|
33951
34627
|
}
|
|
34628
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest vesu_amount: ${vesu_amount.toNumber()}, extended_amount: ${extended_amount.toNumber()}`);
|
|
33952
34629
|
return {
|
|
33953
34630
|
shouldInvest: true,
|
|
33954
34631
|
vesuAmount: vesu_amount,
|
|
@@ -33975,111 +34652,251 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
33975
34652
|
try {
|
|
33976
34653
|
const vesuAdapter = await this.getVesuAdapter();
|
|
33977
34654
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
33978
|
-
let calls = [];
|
|
33979
34655
|
if (!vesuAdapter || !extendedAdapter || !extendedAdapter.client) {
|
|
33980
34656
|
logger.error(
|
|
33981
34657
|
`vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
|
|
33982
34658
|
);
|
|
33983
|
-
return
|
|
34659
|
+
return [];
|
|
34660
|
+
}
|
|
34661
|
+
const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
34662
|
+
if (!extendedHoldings) {
|
|
34663
|
+
logger.error(`error getting extended holdings: ${extendedHoldings}`);
|
|
34664
|
+
return [];
|
|
33984
34665
|
}
|
|
33985
|
-
|
|
34666
|
+
const usdcAmountInWallet = (await this.getUnusedBalance()).amount;
|
|
34667
|
+
const usdcAmountOnExtendedAvailableForWithdrawal = parseFloat(
|
|
34668
|
+
extendedHoldings.availableForWithdrawal
|
|
34669
|
+
);
|
|
34670
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldMoveAssets calculating movements - Extended current: ${usdcAmountOnExtendedAvailableForWithdrawal}, Wallet: ${usdcAmountInWallet.toNumber()}, Target Extended: ${extendedAmount.toNumber()}, Target Vesu: ${vesuAmount.toNumber()}`);
|
|
34671
|
+
let totalExtendedWithdrawal = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
34672
|
+
let totalExtendedDeposit = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
34673
|
+
if (extendedAmount.isNegative() && extendedAmount.abs().greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
34674
|
+
totalExtendedWithdrawal = totalExtendedWithdrawal.plus(extendedAmount.abs());
|
|
34675
|
+
}
|
|
34676
|
+
const extendedTargetAmount = extendedAmount.abs();
|
|
34677
|
+
let projectedExtendedBalance = usdcAmountOnExtendedAvailableForWithdrawal;
|
|
34678
|
+
if (extendedAmount.isNegative()) {
|
|
34679
|
+
projectedExtendedBalance = projectedExtendedBalance - extendedAmount.abs().toNumber();
|
|
34680
|
+
}
|
|
34681
|
+
const extendedAmountDifference = extendedTargetAmount.minus(projectedExtendedBalance);
|
|
34682
|
+
const extendedAmountDifferenceAbs = extendedAmountDifference.abs();
|
|
34683
|
+
if (extendedAmountDifference.lessThan(0)) {
|
|
34684
|
+
totalExtendedWithdrawal = totalExtendedWithdrawal.plus(extendedAmountDifferenceAbs);
|
|
34685
|
+
} else if (extendedAmountDifference.greaterThan(0)) {
|
|
34686
|
+
totalExtendedDeposit = totalExtendedDeposit.plus(extendedAmountDifference);
|
|
34687
|
+
}
|
|
34688
|
+
const vesuTargetAmount = vesuAmount.abs();
|
|
34689
|
+
const projectedWalletBalance = usdcAmountInWallet.plus(totalExtendedWithdrawal).minus(totalExtendedDeposit);
|
|
34690
|
+
let vesuAmountDifference = vesuTargetAmount.minus(projectedWalletBalance);
|
|
34691
|
+
const vesuAmountDifferenceAbs = vesuAmountDifference.abs();
|
|
34692
|
+
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()}`);
|
|
34693
|
+
let calls = [];
|
|
34694
|
+
let transactionResults = [];
|
|
34695
|
+
if (extendedAmount.isNegative() && extendedAmount.abs().greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
33986
34696
|
try {
|
|
33987
|
-
const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
|
|
34697
|
+
const { calls: extendedCalls, status: extendedStatus, transactionMetadata: extendedTransactionMetadata } = await this.moveAssets(
|
|
33988
34698
|
{
|
|
33989
34699
|
to: Protocols.VAULT.name,
|
|
33990
34700
|
from: Protocols.EXTENDED.name,
|
|
33991
|
-
amount: extendedAmount.abs()
|
|
34701
|
+
amount: extendedAmount.abs(),
|
|
34702
|
+
cycleType: "INVESTMENT" /* INVESTMENT */
|
|
33992
34703
|
},
|
|
33993
34704
|
extendedAdapter,
|
|
33994
34705
|
vesuAdapter
|
|
33995
34706
|
);
|
|
33996
34707
|
if (extendedStatus) {
|
|
33997
|
-
|
|
34708
|
+
transactionResults.push({
|
|
34709
|
+
status: extendedStatus,
|
|
34710
|
+
calls: extendedCalls,
|
|
34711
|
+
transactionMetadata: {
|
|
34712
|
+
...extendedTransactionMetadata,
|
|
34713
|
+
transactionType: "DEPOSIT"
|
|
34714
|
+
}
|
|
34715
|
+
});
|
|
33998
34716
|
} else {
|
|
33999
|
-
return [];
|
|
34717
|
+
return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: extendedAmount.abs() }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34000
34718
|
}
|
|
34001
34719
|
} catch (err) {
|
|
34002
34720
|
logger.error(`Failed moving assets to vault: ${err}`);
|
|
34721
|
+
return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: extendedAmount.abs() }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34003
34722
|
}
|
|
34004
34723
|
}
|
|
34005
|
-
if (vesuAmount.
|
|
34724
|
+
if (vesuAmount.isNegative() && vesuAmount.abs().greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
|
|
34006
34725
|
try {
|
|
34007
|
-
const { calls: vesuCalls, status: vesuStatus } = await this.moveAssets(
|
|
34726
|
+
const { calls: vesuCalls, status: vesuStatus, transactionMetadata: vesuTransactionMetadata } = await this.moveAssets(
|
|
34008
34727
|
{
|
|
34009
34728
|
to: Protocols.EXTENDED.name,
|
|
34010
34729
|
from: Protocols.VESU.name,
|
|
34011
|
-
amount: vesuAmount.abs()
|
|
34730
|
+
amount: vesuAmount.abs(),
|
|
34731
|
+
cycleType: "INVESTMENT" /* INVESTMENT */
|
|
34012
34732
|
},
|
|
34013
34733
|
extendedAdapter,
|
|
34014
34734
|
vesuAdapter
|
|
34015
34735
|
);
|
|
34016
|
-
calls.push(...vesuCalls);
|
|
34017
34736
|
if (!vesuStatus) {
|
|
34018
|
-
return [];
|
|
34019
|
-
}
|
|
34737
|
+
return [this.createTransactionResult([], false, { from: Protocols.VESU.name, to: Protocols.EXTENDED.name, amount: vesuAmount.abs() }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34738
|
+
}
|
|
34739
|
+
transactionResults.push({
|
|
34740
|
+
status: vesuStatus,
|
|
34741
|
+
calls: vesuCalls,
|
|
34742
|
+
transactionMetadata: {
|
|
34743
|
+
...vesuTransactionMetadata,
|
|
34744
|
+
transactionType: "DEPOSIT"
|
|
34745
|
+
}
|
|
34746
|
+
});
|
|
34020
34747
|
} catch (err) {
|
|
34021
|
-
logger.error(`Failed moving assets to vault: ${err}`);
|
|
34748
|
+
logger.error(`Failed moving assets to extended via vault allocator: ${err}`);
|
|
34749
|
+
return [this.createTransactionResult([], false, { from: Protocols.VESU.name, to: Protocols.EXTENDED.name, amount: vesuAmount.abs() }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34022
34750
|
}
|
|
34023
34751
|
}
|
|
34024
|
-
|
|
34025
|
-
|
|
34026
|
-
|
|
34027
|
-
|
|
34028
|
-
|
|
34029
|
-
|
|
34030
|
-
|
|
34031
|
-
|
|
34032
|
-
|
|
34033
|
-
|
|
34034
|
-
|
|
34035
|
-
|
|
34036
|
-
|
|
34037
|
-
|
|
34038
|
-
|
|
34039
|
-
|
|
34040
|
-
|
|
34041
|
-
|
|
34042
|
-
|
|
34043
|
-
|
|
34044
|
-
|
|
34045
|
-
|
|
34046
|
-
|
|
34752
|
+
if (extendedAmountDifferenceAbs.greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
34753
|
+
if (extendedAmountDifference.greaterThan(0)) {
|
|
34754
|
+
try {
|
|
34755
|
+
const { calls: extendedCalls, status: extendedStatus, transactionMetadata: extendedTransactionMetadata } = await this.moveAssets(
|
|
34756
|
+
{
|
|
34757
|
+
to: Protocols.EXTENDED.name,
|
|
34758
|
+
from: Protocols.VAULT.name,
|
|
34759
|
+
amount: extendedAmountDifference,
|
|
34760
|
+
cycleType: "INVESTMENT" /* INVESTMENT */
|
|
34761
|
+
},
|
|
34762
|
+
extendedAdapter,
|
|
34763
|
+
vesuAdapter
|
|
34764
|
+
);
|
|
34765
|
+
if (extendedStatus) {
|
|
34766
|
+
transactionResults.push({
|
|
34767
|
+
status: extendedStatus,
|
|
34768
|
+
calls: extendedCalls,
|
|
34769
|
+
transactionMetadata: extendedTransactionMetadata
|
|
34770
|
+
});
|
|
34771
|
+
} else {
|
|
34772
|
+
logger.error(`Failed to move assets to extended - operation returned false status`);
|
|
34773
|
+
return [this.createTransactionResult([], false, { from: Protocols.VAULT.name, to: Protocols.EXTENDED.name, amount: extendedAmountDifference }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34774
|
+
}
|
|
34775
|
+
} catch (err) {
|
|
34776
|
+
logger.error(`Failed moving assets to extended: ${err}`);
|
|
34777
|
+
return [this.createTransactionResult([], false, { from: Protocols.VAULT.name, to: Protocols.EXTENDED.name, amount: extendedAmountDifference }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34778
|
+
}
|
|
34779
|
+
} else if (extendedAmountDifference.lessThan(0)) {
|
|
34780
|
+
try {
|
|
34781
|
+
const { calls: extendedCalls, status: extendedStatus, transactionMetadata: extendedTransactionMetadata } = await this.moveAssets(
|
|
34782
|
+
{
|
|
34783
|
+
to: Protocols.VAULT.name,
|
|
34784
|
+
from: Protocols.EXTENDED.name,
|
|
34785
|
+
amount: extendedAmountDifferenceAbs,
|
|
34786
|
+
cycleType: "INVESTMENT" /* INVESTMENT */
|
|
34787
|
+
},
|
|
34788
|
+
extendedAdapter,
|
|
34789
|
+
vesuAdapter
|
|
34790
|
+
);
|
|
34791
|
+
if (extendedStatus) {
|
|
34792
|
+
transactionResults.push({
|
|
34793
|
+
status: extendedStatus,
|
|
34794
|
+
calls: extendedCalls,
|
|
34795
|
+
transactionMetadata: {
|
|
34796
|
+
...extendedTransactionMetadata,
|
|
34797
|
+
transactionType: "DEPOSIT"
|
|
34798
|
+
}
|
|
34799
|
+
});
|
|
34800
|
+
} else {
|
|
34801
|
+
logger.error(`Failed to withdraw from extended - operation returned false status`);
|
|
34802
|
+
return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: extendedAmountDifferenceAbs }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34803
|
+
}
|
|
34804
|
+
} catch (err) {
|
|
34805
|
+
logger.error(`Failed moving assets from extended to vault: ${err}`);
|
|
34806
|
+
return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: extendedAmountDifferenceAbs }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34807
|
+
}
|
|
34047
34808
|
}
|
|
34048
34809
|
}
|
|
34049
|
-
if (
|
|
34050
|
-
|
|
34051
|
-
|
|
34052
|
-
{
|
|
34053
|
-
to: Protocols.VAULT.name,
|
|
34054
|
-
from: Protocols.EXTENDED.name,
|
|
34055
|
-
amount: vesuAmount.minus(usdcAmountInWallet)
|
|
34056
|
-
},
|
|
34057
|
-
extendedAdapter,
|
|
34058
|
-
vesuAdapter
|
|
34810
|
+
if (vesuAmountDifferenceAbs.greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
|
|
34811
|
+
if (vesuAmountDifference.lessThanOrEqualTo(0)) {
|
|
34812
|
+
logger.warn(
|
|
34813
|
+
`Vesu amount difference is negative or zero: ${vesuAmountDifference.toNumber()}. Skipping operation.`
|
|
34059
34814
|
);
|
|
34060
|
-
|
|
34061
|
-
|
|
34815
|
+
} else {
|
|
34816
|
+
try {
|
|
34817
|
+
const { calls: vesuCalls, status: vesuStatus, transactionMetadata: vesuTransactionMetadata } = await this.moveAssets(
|
|
34818
|
+
{
|
|
34819
|
+
to: Protocols.VAULT.name,
|
|
34820
|
+
from: Protocols.EXTENDED.name,
|
|
34821
|
+
amount: vesuAmountDifference,
|
|
34822
|
+
cycleType: "INVESTMENT" /* INVESTMENT */
|
|
34823
|
+
},
|
|
34824
|
+
extendedAdapter,
|
|
34825
|
+
vesuAdapter
|
|
34826
|
+
);
|
|
34827
|
+
if (!vesuStatus) {
|
|
34828
|
+
logger.error(`Failed to move assets to vesu - operation returned false status`);
|
|
34829
|
+
return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: vesuAmountDifference }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34830
|
+
}
|
|
34831
|
+
transactionResults.push({
|
|
34832
|
+
status: vesuStatus,
|
|
34833
|
+
calls: vesuCalls,
|
|
34834
|
+
transactionMetadata: {
|
|
34835
|
+
...vesuTransactionMetadata,
|
|
34836
|
+
transactionType: "DEPOSIT"
|
|
34837
|
+
}
|
|
34838
|
+
});
|
|
34839
|
+
} catch (err) {
|
|
34840
|
+
logger.error(`Failed moving assets to vault: ${err}`);
|
|
34841
|
+
return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: vesuAmountDifference }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34062
34842
|
}
|
|
34063
|
-
calls.push(...vesuCalls);
|
|
34064
|
-
} catch (err) {
|
|
34065
|
-
logger.error(`Failed moving assets to vault: ${err}`);
|
|
34066
34843
|
}
|
|
34067
34844
|
}
|
|
34068
|
-
return
|
|
34845
|
+
return transactionResults;
|
|
34069
34846
|
} catch (err) {
|
|
34070
34847
|
logger.error(`Failed moving assets to vesu: ${err}`);
|
|
34071
|
-
return [];
|
|
34848
|
+
return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: new Web3Number(0, USDC_TOKEN_DECIMALS) }, "NONE", "INVESTMENT" /* INVESTMENT */)];
|
|
34072
34849
|
}
|
|
34073
34850
|
}
|
|
34851
|
+
/**
|
|
34852
|
+
* Helper method to create transaction result with metadata
|
|
34853
|
+
*/
|
|
34854
|
+
createTransactionResult(calls, status, params, transactionType, cycleType) {
|
|
34855
|
+
if (status) {
|
|
34856
|
+
return {
|
|
34857
|
+
calls,
|
|
34858
|
+
status,
|
|
34859
|
+
transactionMetadata: {
|
|
34860
|
+
protocolFrom: params.from,
|
|
34861
|
+
protocolTo: params.to,
|
|
34862
|
+
transactionType,
|
|
34863
|
+
usdAmount: params.amount.abs().toFixed(),
|
|
34864
|
+
status: "PENDING",
|
|
34865
|
+
cycleType
|
|
34866
|
+
}
|
|
34867
|
+
};
|
|
34868
|
+
}
|
|
34869
|
+
return { calls: [], status: false, transactionMetadata: { protocolFrom: "", protocolTo: "", transactionType: "DEPOSIT", usdAmount: "0", status: "FAILED", cycleType } };
|
|
34870
|
+
}
|
|
34074
34871
|
async moveAssets(params, extendedAdapter, vesuAdapter) {
|
|
34075
34872
|
try {
|
|
34873
|
+
if (params.amount.lessThanOrEqualTo(0)) {
|
|
34874
|
+
logger.error(
|
|
34875
|
+
`Invalid amount for moveAssets: ${params.amount.toNumber()}. Amount must be positive.`
|
|
34876
|
+
);
|
|
34877
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34878
|
+
}
|
|
34879
|
+
const amountAbs = params.amount.abs();
|
|
34880
|
+
if (params.from === Protocols.EXTENDED.name || params.to === Protocols.EXTENDED.name) {
|
|
34881
|
+
if (amountAbs.lessThanOrEqualTo(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
34882
|
+
logger.warn(
|
|
34883
|
+
`Amount ${amountAbs.toNumber()} is below minimum Extended movement amount ${extendedAdapter.minimumExtendedMovementAmount}. Skipping operation.`
|
|
34884
|
+
);
|
|
34885
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34886
|
+
}
|
|
34887
|
+
}
|
|
34888
|
+
if (params.from === Protocols.VESU.name || params.to === Protocols.VESU.name) {
|
|
34889
|
+
if (amountAbs.lessThanOrEqualTo(vesuAdapter.minimumVesuMovementAmount)) {
|
|
34890
|
+
logger.warn(
|
|
34891
|
+
`Amount ${amountAbs.toNumber()} is below minimum Vesu movement amount ${vesuAdapter.minimumVesuMovementAmount}. Skipping operation.`
|
|
34892
|
+
);
|
|
34893
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34894
|
+
}
|
|
34895
|
+
}
|
|
34076
34896
|
const avnuAdapter = await this.getAvnuAdapter();
|
|
34077
34897
|
if (!avnuAdapter) {
|
|
34078
34898
|
logger.error(`avnu adapter not found: ${avnuAdapter}`);
|
|
34079
|
-
return
|
|
34080
|
-
calls: [],
|
|
34081
|
-
status: false
|
|
34082
|
-
};
|
|
34899
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34083
34900
|
}
|
|
34084
34901
|
logger.info(`moveAssets params, ${JSON.stringify(params)}`);
|
|
34085
34902
|
const collateralToken = vesuAdapter.config.supportedPositions[0].asset;
|
|
@@ -34098,61 +34915,72 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34098
34915
|
await proofsInfo.callConstructor({ amount: params.amount })
|
|
34099
34916
|
);
|
|
34100
34917
|
calls.push(call);
|
|
34101
|
-
return
|
|
34102
|
-
calls: [call],
|
|
34103
|
-
status: true
|
|
34104
|
-
};
|
|
34918
|
+
return this.createTransactionResult(calls, true, params, "DEPOSIT", params.cycleType);
|
|
34105
34919
|
} else if (params.to === Protocols.VAULT.name && params.from === Protocols.EXTENDED.name) {
|
|
34106
34920
|
const extendedLeverage = calculateExtendedLevergae();
|
|
34107
34921
|
const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
34108
34922
|
if (!extendedHoldings) {
|
|
34109
34923
|
logger.error(`error getting extended holdings: ${extendedHoldings}`);
|
|
34110
|
-
return
|
|
34111
|
-
calls: [],
|
|
34112
|
-
status: false
|
|
34113
|
-
};
|
|
34924
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34114
34925
|
}
|
|
34115
34926
|
const extendedHoldingAmount = new Web3Number(
|
|
34116
34927
|
extendedHoldings.availableForWithdrawal,
|
|
34117
34928
|
USDC_TOKEN_DECIMALS
|
|
34118
34929
|
);
|
|
34119
|
-
|
|
34120
|
-
|
|
34121
|
-
|
|
34122
|
-
|
|
34123
|
-
btcAmount.
|
|
34124
|
-
|
|
34125
|
-
|
|
34126
|
-
|
|
34127
|
-
|
|
34128
|
-
|
|
34129
|
-
|
|
34130
|
-
|
|
34131
|
-
|
|
34930
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::moveAssets extendedHoldingAmount: ${extendedHoldingAmount.toNumber()}`);
|
|
34931
|
+
if (params.amount.abs().greaterThan(extendedHoldingAmount)) {
|
|
34932
|
+
const leftAmountAfterWithdrawalAmountInAccount = params.amount.abs().minus(extendedHoldingAmount);
|
|
34933
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::moveAssets leftAmountAfterWithdrawalAmountInAccount: ${leftAmountAfterWithdrawalAmountInAccount.toNumber()}`);
|
|
34934
|
+
const btcAmount = leftAmountAfterWithdrawalAmountInAccount.dividedBy(collateralPrice.price);
|
|
34935
|
+
const openLongPosition = btcAmount.multipliedBy(3).greaterThan(MINIMUM_EXTENDED_POSITION_SIZE) ? await extendedAdapter.createOrder(
|
|
34936
|
+
extendedLeverage.toString(),
|
|
34937
|
+
btcAmount.toNumber(),
|
|
34938
|
+
"BUY" /* BUY */
|
|
34939
|
+
) : await extendedAdapter.createOrder(
|
|
34940
|
+
extendedLeverage.toString(),
|
|
34941
|
+
34e-6,
|
|
34942
|
+
// just in case amount falls short then we need to create a withdrawal
|
|
34943
|
+
"BUY" /* BUY */
|
|
34944
|
+
);
|
|
34945
|
+
if (!openLongPosition) {
|
|
34946
|
+
logger.error(`error opening long position: ${openLongPosition}`);
|
|
34947
|
+
}
|
|
34948
|
+
const updatedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
34949
|
+
if (!updatedHoldings || new Web3Number(updatedHoldings.availableForWithdrawal, USDC_TOKEN_DECIMALS).lessThan(params.amount.abs())) {
|
|
34950
|
+
logger.error(`Insufficient balance after opening position. Available: ${updatedHoldings?.availableForWithdrawal}, Needed: ${params.amount.abs()}`);
|
|
34951
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34952
|
+
}
|
|
34132
34953
|
}
|
|
34133
|
-
|
|
34134
|
-
|
|
34135
|
-
|
|
34954
|
+
const {
|
|
34955
|
+
status: withdrawalFromExtendedStatus,
|
|
34956
|
+
receivedTxnHash: withdrawalFromExtendedTxnHash
|
|
34957
|
+
} = await extendedAdapter.withdrawFromExtended(params.amount);
|
|
34958
|
+
logger.info(`withdrawalFromExtendedStatus: ${withdrawalFromExtendedStatus}, withdrawalFromExtendedTxnHash: ${withdrawalFromExtendedTxnHash}`);
|
|
34959
|
+
if (withdrawalFromExtendedStatus && withdrawalFromExtendedTxnHash) {
|
|
34136
34960
|
const extendedHoldings2 = await extendedAdapter.getExtendedDepositAmount();
|
|
34137
|
-
logger.info(`extendedHoldings after withdrawal ${extendedHoldings2}`);
|
|
34138
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
34139
|
-
const calls = await this.moveAssetsToVaultAllocator(params.amount, extendedAdapter);
|
|
34140
|
-
if (calls.length > 0) {
|
|
34141
|
-
return
|
|
34142
|
-
|
|
34143
|
-
|
|
34144
|
-
};
|
|
34961
|
+
logger.info(`extendedHoldings after withdrawal ${extendedHoldings2?.availableForWithdrawal}`);
|
|
34962
|
+
await new Promise((resolve) => setTimeout(resolve, 5e3));
|
|
34963
|
+
const { calls, status } = await this.moveAssetsToVaultAllocator(params.amount, extendedAdapter);
|
|
34964
|
+
if (calls.length > 0 && status) {
|
|
34965
|
+
return this.createTransactionResult(calls, true, params, "WITHDRAWAL", params.cycleType);
|
|
34966
|
+
} else {
|
|
34967
|
+
return this.createTransactionResult([], true, params, "WITHDRAWAL", params.cycleType);
|
|
34145
34968
|
}
|
|
34969
|
+
} else if (withdrawalFromExtendedStatus && !withdrawalFromExtendedTxnHash) {
|
|
34970
|
+
logger.error("withdrawal from extended successful, but funds didn't get transferred to the wallet");
|
|
34971
|
+
return this.createTransactionResult([], true, params, "WITHDRAWAL", params.cycleType);
|
|
34146
34972
|
} else {
|
|
34147
34973
|
logger.error("withdrawal from extended failed");
|
|
34148
|
-
return
|
|
34149
|
-
calls: [],
|
|
34150
|
-
status: false
|
|
34151
|
-
};
|
|
34974
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34152
34975
|
}
|
|
34153
34976
|
} else if (params.to === Protocols.VAULT.name && params.from === Protocols.VESU.name) {
|
|
34977
|
+
const isPriceDifferenceBetweenAvnuAndExtended = await this.checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter, vesuAdapter, avnuAdapter, "close" /* CLOSE */);
|
|
34978
|
+
if (!isPriceDifferenceBetweenAvnuAndExtended) {
|
|
34979
|
+
logger.warn(`price difference between avnu and extended doesn't fit the range for close position, ${avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing}`);
|
|
34980
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34981
|
+
}
|
|
34154
34982
|
const vesuAmountInBTC = new Web3Number(
|
|
34155
|
-
params.amount.dividedBy(collateralPrice.price).
|
|
34983
|
+
params.amount.dividedBy(collateralPrice.price).toFixed(WBTC_TOKEN_DECIMALS),
|
|
34156
34984
|
collateralToken.decimals
|
|
34157
34985
|
);
|
|
34158
34986
|
const proofsInfo = vesuAdapter.getProofs(false, this.getMerkleTree());
|
|
@@ -34170,11 +34998,13 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34170
34998
|
await swapProofsInfo.callConstructor({ amount: vesuAmountInBTC })
|
|
34171
34999
|
);
|
|
34172
35000
|
calls.push(swapCall);
|
|
34173
|
-
return
|
|
34174
|
-
calls,
|
|
34175
|
-
status: true
|
|
34176
|
-
};
|
|
35001
|
+
return this.createTransactionResult(calls, true, params, "WITHDRAWAL", params.cycleType);
|
|
34177
35002
|
} else if (params.to === Protocols.EXTENDED.name && params.from === Protocols.VESU.name) {
|
|
35003
|
+
const isPriceDifferenceBetweenAvnuAndExtended = await this.checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter, vesuAdapter, avnuAdapter, "close" /* CLOSE */);
|
|
35004
|
+
if (!isPriceDifferenceBetweenAvnuAndExtended) {
|
|
35005
|
+
logger.warn(`price difference between avnu and extended doesn't fit the range for close position, ${avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing}`);
|
|
35006
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
35007
|
+
}
|
|
34178
35008
|
const vesuAmountInBTC = new Web3Number(
|
|
34179
35009
|
params.amount.dividedBy(collateralPrice.price).toNumber(),
|
|
34180
35010
|
collateralToken.decimals
|
|
@@ -34204,131 +35034,32 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34204
35034
|
await proofsInfoDeposit.callConstructor({ amount: params.amount })
|
|
34205
35035
|
);
|
|
34206
35036
|
calls.push(callDeposit);
|
|
34207
|
-
return
|
|
34208
|
-
calls,
|
|
34209
|
-
status: true
|
|
34210
|
-
};
|
|
35037
|
+
return this.createTransactionResult(calls, true, params, "DEPOSIT", params.cycleType);
|
|
34211
35038
|
}
|
|
34212
|
-
|
|
34213
|
-
|
|
34214
|
-
status: false
|
|
34215
|
-
};
|
|
35039
|
+
logger.error(`Unsupported assets movement: ${params.from} to ${params.to}`);
|
|
35040
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34216
35041
|
} catch (err) {
|
|
34217
35042
|
logger.error(`error moving assets: ${err}`);
|
|
34218
|
-
return
|
|
34219
|
-
calls: [],
|
|
34220
|
-
status: false
|
|
34221
|
-
};
|
|
35043
|
+
return this.createTransactionResult([], false, params, "NONE", params.cycleType);
|
|
34222
35044
|
}
|
|
34223
35045
|
}
|
|
34224
35046
|
async handleDeposit() {
|
|
34225
35047
|
try {
|
|
34226
|
-
|
|
34227
|
-
const extendedAdapter = await this.getExtendedAdapter();
|
|
34228
|
-
const avnuAdapter = await this.getAvnuAdapter();
|
|
34229
|
-
if (!vesuAdapter || !extendedAdapter || !extendedAdapter.client || !avnuAdapter) {
|
|
34230
|
-
logger.error(
|
|
34231
|
-
"vesu or extended adapter not found",
|
|
34232
|
-
vesuAdapter,
|
|
34233
|
-
extendedAdapter
|
|
34234
|
-
);
|
|
34235
|
-
return {
|
|
34236
|
-
extendedAmountInBTC: new Web3Number(0, 0),
|
|
34237
|
-
calls: []
|
|
34238
|
-
};
|
|
34239
|
-
}
|
|
34240
|
-
const extendedLeverage = calculateExtendedLevergae();
|
|
34241
|
-
const isPriceDifferenceBetweenAvnuAndExtended = await this.checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter, vesuAdapter, avnuAdapter);
|
|
34242
|
-
if (!isPriceDifferenceBetweenAvnuAndExtended) {
|
|
34243
|
-
logger.error("price difference between avnu and extended doesn't fit the range");
|
|
34244
|
-
return {
|
|
34245
|
-
extendedAmountInBTC: new Web3Number(0, 0),
|
|
34246
|
-
calls: []
|
|
34247
|
-
};
|
|
34248
|
-
}
|
|
34249
|
-
const position = await extendedAdapter.getAllOpenPositions();
|
|
34250
|
-
if (!position) {
|
|
34251
|
-
logger.error("error getting extended position", position);
|
|
34252
|
-
return {
|
|
34253
|
-
extendedAmountInBTC: new Web3Number(0, 0),
|
|
34254
|
-
calls: []
|
|
34255
|
-
};
|
|
34256
|
-
}
|
|
34257
|
-
const extendedPositionValue = position.length > 0 ? parseFloat(position[0].value) : 0;
|
|
34258
|
-
const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
34259
|
-
if (!extendedHoldings) {
|
|
34260
|
-
logger.error(`error getting extended holdings: ${extendedHoldings}`);
|
|
34261
|
-
return {
|
|
34262
|
-
extendedAmountInBTC: new Web3Number(0, 0),
|
|
34263
|
-
calls: []
|
|
34264
|
-
};
|
|
34265
|
-
}
|
|
34266
|
-
const extendedHoldingAmount = new Web3Number(
|
|
34267
|
-
extendedHoldings.availableForWithdrawal,
|
|
34268
|
-
USDC_TOKEN_DECIMALS
|
|
34269
|
-
);
|
|
34270
|
-
const {
|
|
34271
|
-
collateralTokenAmount
|
|
34272
|
-
} = await vesuAdapter.vesuAdapter.getAssetPrices();
|
|
34273
|
-
const { collateralPrice } = await this.getAssetPrices();
|
|
34274
|
-
const { vesuAmountInBTC, extendedAmountInBTC } = calculateVesUPositionSizeGivenExtended(
|
|
34275
|
-
extendedPositionValue,
|
|
34276
|
-
extendedHoldingAmount,
|
|
34277
|
-
collateralTokenAmount,
|
|
34278
|
-
collateralPrice.price
|
|
34279
|
-
);
|
|
34280
|
-
logger.info(`vesuAmountInBTC ${vesuAmountInBTC}, extendedAmountInBTC ${extendedAmountInBTC}`);
|
|
34281
|
-
let calls = [];
|
|
34282
|
-
if (vesuAmountInBTC.greaterThan(MINIMUM_EXTENDED_POSITION_SIZE)) {
|
|
34283
|
-
const proofsInfo = vesuAdapter.getProofs(true, this.getMerkleTree());
|
|
34284
|
-
const proofGroups = proofsInfo.proofs;
|
|
34285
|
-
const call = this.getManageCall(
|
|
34286
|
-
proofGroups,
|
|
34287
|
-
await proofsInfo.callConstructor({
|
|
34288
|
-
amount: vesuAmountInBTC
|
|
34289
|
-
})
|
|
34290
|
-
);
|
|
34291
|
-
const { amount: wbtcAmountInVaultAllocator } = await this.getUnusedBalanceWBTC();
|
|
34292
|
-
if (wbtcAmountInVaultAllocator.lessThan(vesuAmountInBTC)) {
|
|
34293
|
-
logger.info(`WBTC amount in vault allocator is less than vesu amount required in WBTC thus swapping, wbtcAmountInVaultAllocator: ${wbtcAmountInVaultAllocator}, vesuAmountInBTC: ${vesuAmountInBTC}`);
|
|
34294
|
-
const swapProofsInfo = avnuAdapter.getProofs(true, this.getMerkleTree());
|
|
34295
|
-
const swapProofGroups = swapProofsInfo.proofs;
|
|
34296
|
-
const swapCall = this.getManageCall(
|
|
34297
|
-
swapProofGroups,
|
|
34298
|
-
await swapProofsInfo.callConstructor({
|
|
34299
|
-
amount: vesuAmountInBTC
|
|
34300
|
-
})
|
|
34301
|
-
);
|
|
34302
|
-
calls.push(swapCall);
|
|
34303
|
-
}
|
|
34304
|
-
calls.push(call);
|
|
34305
|
-
}
|
|
34306
|
-
const shortPosition = extendedAmountInBTC.multipliedBy(3).abs().greaterThan(MINIMUM_EXTENDED_POSITION_SIZE) ? await extendedAdapter.createOrder(
|
|
34307
|
-
extendedLeverage.toString(),
|
|
34308
|
-
extendedAmountInBTC.toNumber(),
|
|
34309
|
-
"SELL" /* SELL */
|
|
34310
|
-
) : null;
|
|
34311
|
-
if (!shortPosition && extendedAmountInBTC.multipliedBy(3).abs().greaterThan(MINIMUM_EXTENDED_POSITION_SIZE)) {
|
|
34312
|
-
logger.error(`error creating short position thus no position to be opened on vesu: ${shortPosition}`);
|
|
34313
|
-
return {
|
|
34314
|
-
extendedAmountInBTC: new Web3Number(0, 0),
|
|
34315
|
-
calls: []
|
|
34316
|
-
};
|
|
34317
|
-
}
|
|
34318
|
-
return {
|
|
34319
|
-
extendedAmountInBTC,
|
|
34320
|
-
calls
|
|
34321
|
-
};
|
|
35048
|
+
return this.createTransactionResult([], false, { from: Protocols.VAULT.name, to: Protocols.VAULT.name, amount: new Web3Number(0, 0) }, "NONE", "INVESTMENT" /* INVESTMENT */);
|
|
34322
35049
|
} catch (err) {
|
|
34323
35050
|
logger.error(`error handling deposit: ${err}`);
|
|
34324
|
-
return {
|
|
34325
|
-
extendedAmountInBTC: new Web3Number(0, 0),
|
|
34326
|
-
calls: []
|
|
34327
|
-
};
|
|
34328
|
-
;
|
|
35051
|
+
return this.createTransactionResult([], false, { from: Protocols.VAULT.name, to: Protocols.VAULT.name, amount: new Web3Number(0, 0) }, "NONE", "INVESTMENT" /* INVESTMENT */);
|
|
34329
35052
|
}
|
|
34330
35053
|
}
|
|
34331
|
-
|
|
35054
|
+
/**
|
|
35055
|
+
* Check if the price difference between avnu and extended is within the acceptable range to enhance the position size or close the position
|
|
35056
|
+
* @param extendedAdapter - the extended adapter
|
|
35057
|
+
* @param vesuAdapter - the vesu adapter
|
|
35058
|
+
* @param avnuAdapter - the avnu adapter
|
|
35059
|
+
* @param positionType - the position type (open or close)
|
|
35060
|
+
* @returns true if the price difference is within the acceptable range, false otherwise
|
|
35061
|
+
*/
|
|
35062
|
+
async checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter, vesuAdapter, avnuAdapter, positionType) {
|
|
34332
35063
|
const {
|
|
34333
35064
|
ask,
|
|
34334
35065
|
bid
|
|
@@ -34340,13 +35071,30 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34340
35071
|
logger.error(`error getting btc price avnu: ${btcPriceAvnu}`);
|
|
34341
35072
|
return false;
|
|
34342
35073
|
}
|
|
34343
|
-
|
|
34344
|
-
|
|
34345
|
-
|
|
35074
|
+
logger.info(`price: ${price}`);
|
|
35075
|
+
logger.info(`btcPriceAvnu: ${btcPriceAvnu}`);
|
|
35076
|
+
const priceDifference = new Web3Number(price.minus(btcPriceAvnu).toFixed(2), 0);
|
|
35077
|
+
logger.info(`priceDifference: ${priceDifference}`);
|
|
35078
|
+
if (priceDifference.isNegative()) {
|
|
35079
|
+
return false;
|
|
35080
|
+
}
|
|
35081
|
+
if (positionType === "open" /* OPEN */) {
|
|
35082
|
+
logger.info(`price difference between avnu and extended for open position: ${priceDifference.toNumber()}, minimumExtendedPriceDifferenceForSwapOpen: ${avnuAdapter.config.minimumExtendedPriceDifferenceForSwapOpen}`);
|
|
35083
|
+
const result = priceDifference.greaterThanOrEqualTo(avnuAdapter.config.minimumExtendedPriceDifferenceForSwapOpen);
|
|
35084
|
+
logger.info(`result: ${result}`);
|
|
35085
|
+
return result;
|
|
35086
|
+
} else {
|
|
35087
|
+
logger.info(`price difference between avnu and extended for close position: ${priceDifference.toNumber()}, maximumExtendedPriceDifferenceForSwapClosing: ${avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing}`);
|
|
35088
|
+
const result = priceDifference.lessThanOrEqualTo(avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing);
|
|
35089
|
+
logger.info(`result: ${result}`);
|
|
35090
|
+
return result;
|
|
34346
35091
|
}
|
|
34347
|
-
logger.error(`price difference between avnu and extended doesn't fit the range, priceDifference: ${priceDifference}`);
|
|
34348
|
-
return false;
|
|
34349
35092
|
}
|
|
35093
|
+
/**
|
|
35094
|
+
* Handle the withdrawal of assets from the vault
|
|
35095
|
+
* @param amount - the amount to withdraw in USDC
|
|
35096
|
+
* @returns the calls to be executed and the status of the calls generated along with the metadata for the calls
|
|
35097
|
+
*/
|
|
34350
35098
|
async handleWithdraw(amount) {
|
|
34351
35099
|
try {
|
|
34352
35100
|
const usdcBalanceVaultAllocator = await this.getUnusedBalance();
|
|
@@ -34358,12 +35106,8 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34358
35106
|
const withdrawCall2 = await this.getBringLiquidityCall({
|
|
34359
35107
|
amount: usdcBalanceVaultAllocator.amount
|
|
34360
35108
|
});
|
|
34361
|
-
logger.info("withdraw call", withdrawCall2);
|
|
34362
35109
|
calls.push(withdrawCall2);
|
|
34363
|
-
return {
|
|
34364
|
-
calls,
|
|
34365
|
-
status: true
|
|
34366
|
-
};
|
|
35110
|
+
return [this.createTransactionResult(calls, true, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount }, "WITHDRAWAL", "WITHDRAWAL" /* WITHDRAWAL */)];
|
|
34367
35111
|
}
|
|
34368
35112
|
const vesuAdapter = await this.getVesuAdapter();
|
|
34369
35113
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
@@ -34372,11 +35116,9 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34372
35116
|
logger.error(
|
|
34373
35117
|
`vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
|
|
34374
35118
|
);
|
|
34375
|
-
return {
|
|
34376
|
-
calls,
|
|
34377
|
-
status
|
|
34378
|
-
};
|
|
35119
|
+
return [this.createTransactionResult(calls, status, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount }, "NONE", "WITHDRAWAL" /* WITHDRAWAL */)];
|
|
34379
35120
|
}
|
|
35121
|
+
let transactionResults = [];
|
|
34380
35122
|
const { collateralTokenAmount } = await vesuAdapter.vesuAdapter.getAssetPrices();
|
|
34381
35123
|
const {
|
|
34382
35124
|
collateralPrice
|
|
@@ -34385,10 +35127,7 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34385
35127
|
if (!extendedPositon) {
|
|
34386
35128
|
status = false;
|
|
34387
35129
|
logger.error("error getting extended position", extendedPositon);
|
|
34388
|
-
return {
|
|
34389
|
-
calls,
|
|
34390
|
-
status
|
|
34391
|
-
};
|
|
35130
|
+
return [this.createTransactionResult(calls, status, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount }, "NONE", "WITHDRAWAL" /* WITHDRAWAL */)];
|
|
34392
35131
|
}
|
|
34393
35132
|
const amountDistributionForWithdrawal = await calculateAmountDistributionForWithdrawal(
|
|
34394
35133
|
usdcBalanceDifference,
|
|
@@ -34401,61 +35140,70 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34401
35140
|
logger.error(
|
|
34402
35141
|
`error calculating amount distribution for withdrawal: ${amountDistributionForWithdrawal}`
|
|
34403
35142
|
);
|
|
34404
|
-
return {
|
|
34405
|
-
calls,
|
|
34406
|
-
status
|
|
34407
|
-
};
|
|
35143
|
+
return [this.createTransactionResult(calls, status, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount }, "NONE", "WITHDRAWAL" /* WITHDRAWAL */)];
|
|
34408
35144
|
}
|
|
34409
35145
|
const { vesu_amount, extended_amount } = amountDistributionForWithdrawal;
|
|
34410
35146
|
if (status && vesu_amount.greaterThan(0)) {
|
|
34411
|
-
const { calls: vesuCalls, status: vesuStatus } = await this.moveAssets(
|
|
35147
|
+
const { calls: vesuCalls, status: vesuStatus, transactionMetadata: vesuTransactionMetadata } = await this.moveAssets(
|
|
34412
35148
|
{
|
|
34413
35149
|
amount: vesu_amount,
|
|
34414
35150
|
from: Protocols.VESU.name,
|
|
34415
|
-
to: Protocols.VAULT.name
|
|
35151
|
+
to: Protocols.VAULT.name,
|
|
35152
|
+
cycleType: "WITHDRAWAL" /* WITHDRAWAL */
|
|
34416
35153
|
},
|
|
34417
35154
|
extendedAdapter,
|
|
34418
35155
|
vesuAdapter
|
|
34419
35156
|
);
|
|
34420
35157
|
status = vesuStatus;
|
|
34421
|
-
|
|
35158
|
+
transactionResults.push({
|
|
35159
|
+
status: vesuStatus,
|
|
35160
|
+
calls: vesuCalls,
|
|
35161
|
+
transactionMetadata: vesuTransactionMetadata
|
|
35162
|
+
});
|
|
34422
35163
|
}
|
|
34423
35164
|
if (status && extended_amount.greaterThan(0)) {
|
|
34424
|
-
const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
|
|
35165
|
+
const { calls: extendedCalls, status: extendedStatus, transactionMetadata: extendedTransactionMetadata } = await this.moveAssets(
|
|
34425
35166
|
{
|
|
34426
35167
|
amount: extended_amount,
|
|
34427
35168
|
from: Protocols.EXTENDED.name,
|
|
34428
|
-
to: Protocols.VAULT.name
|
|
35169
|
+
to: Protocols.VAULT.name,
|
|
35170
|
+
cycleType: "WITHDRAWAL" /* WITHDRAWAL */
|
|
34429
35171
|
},
|
|
34430
35172
|
extendedAdapter,
|
|
34431
35173
|
vesuAdapter
|
|
34432
35174
|
);
|
|
34433
35175
|
status = extendedStatus;
|
|
34434
35176
|
if (status) {
|
|
34435
|
-
|
|
35177
|
+
transactionResults.push({
|
|
35178
|
+
status: extendedStatus,
|
|
35179
|
+
calls: extendedCalls,
|
|
35180
|
+
transactionMetadata: extendedTransactionMetadata
|
|
35181
|
+
});
|
|
34436
35182
|
} else {
|
|
34437
35183
|
logger.error("error moving assets to vault: extendedStatus: ${extendedStatus}");
|
|
34438
|
-
return {
|
|
34439
|
-
calls: [],
|
|
34440
|
-
status
|
|
34441
|
-
};
|
|
35184
|
+
return [this.createTransactionResult([], status, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount }, "NONE", "WITHDRAWAL" /* WITHDRAWAL */)];
|
|
34442
35185
|
}
|
|
34443
35186
|
}
|
|
34444
35187
|
const withdrawCall = await this.getBringLiquidityCall({
|
|
34445
35188
|
amount
|
|
34446
35189
|
});
|
|
34447
35190
|
logger.info("withdraw call", withdrawCall);
|
|
34448
|
-
|
|
34449
|
-
|
|
34450
|
-
calls,
|
|
34451
|
-
|
|
34452
|
-
|
|
35191
|
+
transactionResults.push({
|
|
35192
|
+
status,
|
|
35193
|
+
calls: [withdrawCall],
|
|
35194
|
+
transactionMetadata: {
|
|
35195
|
+
protocolFrom: Protocols.VAULT.name,
|
|
35196
|
+
protocolTo: Protocols.NONE.name,
|
|
35197
|
+
transactionType: "WITHDRAWAL",
|
|
35198
|
+
usdAmount: amount.toFixed(),
|
|
35199
|
+
status: "PENDING",
|
|
35200
|
+
cycleType: "WITHDRAWAL" /* WITHDRAWAL */
|
|
35201
|
+
}
|
|
35202
|
+
});
|
|
35203
|
+
return transactionResults;
|
|
34453
35204
|
} catch (err) {
|
|
34454
35205
|
logger.error(`error handling withdrawal: ${err}`);
|
|
34455
|
-
return {
|
|
34456
|
-
calls: [],
|
|
34457
|
-
status: false
|
|
34458
|
-
};
|
|
35206
|
+
return [this.createTransactionResult([], false, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount }, "NONE", "WITHDRAWAL" /* WITHDRAWAL */)];
|
|
34459
35207
|
}
|
|
34460
35208
|
}
|
|
34461
35209
|
async getAUM() {
|
|
@@ -34502,8 +35250,182 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34502
35250
|
splits: [realAUM, estimatedAUMDelta]
|
|
34503
35251
|
};
|
|
34504
35252
|
}
|
|
35253
|
+
async processTransactionDataFromSDK(txnData) {
|
|
35254
|
+
try {
|
|
35255
|
+
const txnsToBeExecuted = txnData.filter((txn) => {
|
|
35256
|
+
return txn.transactionMetadata.transactionType !== "NONE" && txn.transactionMetadata.protocolFrom !== "" && txn.transactionMetadata.protocolTo !== "";
|
|
35257
|
+
});
|
|
35258
|
+
const callsToBeExecutedFinal = txnsToBeExecuted.flatMap((txn) => txn.calls);
|
|
35259
|
+
const txnMetadata = txnsToBeExecuted.map((txn) => txn.transactionMetadata);
|
|
35260
|
+
return { callsToBeExecutedFinal, txnMetadata };
|
|
35261
|
+
} catch (err) {
|
|
35262
|
+
logger.error(`error processing transaction data from SDK: ${err}`);
|
|
35263
|
+
return null;
|
|
35264
|
+
}
|
|
35265
|
+
}
|
|
35266
|
+
async processTransactionMetadata(txnMetadata, extendedIntentFulfilled) {
|
|
35267
|
+
try {
|
|
35268
|
+
const txnMetadataNew = txnMetadata.map((txn) => {
|
|
35269
|
+
const isExtendedProtocol = txn.protocolFrom === Protocols.EXTENDED.name || txn.protocolTo === Protocols.EXTENDED.name;
|
|
35270
|
+
if (isExtendedProtocol) {
|
|
35271
|
+
txn.status = extendedIntentFulfilled ? "COMPLETED" : "PENDING";
|
|
35272
|
+
} else {
|
|
35273
|
+
txn.status = "COMPLETED";
|
|
35274
|
+
}
|
|
35275
|
+
return txn;
|
|
35276
|
+
});
|
|
35277
|
+
return txnMetadataNew;
|
|
35278
|
+
} catch (err) {
|
|
35279
|
+
logger.error(`error processing transaction data from SDK: ${err}`);
|
|
35280
|
+
return null;
|
|
35281
|
+
}
|
|
35282
|
+
}
|
|
35283
|
+
async getMaxBorrowableAmount() {
|
|
35284
|
+
const vesuAdapter = await this.getVesuAdapter();
|
|
35285
|
+
const extendedAdapter = await this.getExtendedAdapter();
|
|
35286
|
+
if (!vesuAdapter || !extendedAdapter) {
|
|
35287
|
+
return new Web3Number(0, 0);
|
|
35288
|
+
}
|
|
35289
|
+
const extendedFundingRate = new Web3Number((await extendedAdapter.getNetAPY()).toFixed(4), 0);
|
|
35290
|
+
const extendedPositions = await extendedAdapter.getAllOpenPositions();
|
|
35291
|
+
if (!extendedPositions || extendedPositions.length === 0) {
|
|
35292
|
+
logger.info(`no extended positions found`);
|
|
35293
|
+
return new Web3Number(0, 0);
|
|
35294
|
+
}
|
|
35295
|
+
const extendePositionSizeUSD = new Web3Number(extendedPositions[0].value || 0, 0);
|
|
35296
|
+
const vesuPositions = await vesuAdapter.getPositions();
|
|
35297
|
+
const vesuSupplyApy = vesuPositions[0].apy.apy;
|
|
35298
|
+
const vesuCollateralSizeUSD = new Web3Number(vesuPositions[0].usdValue.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS);
|
|
35299
|
+
const vesuDebtSizeUSD = new Web3Number(vesuPositions[1].usdValue.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS);
|
|
35300
|
+
const num1 = extendePositionSizeUSD.multipliedBy(extendedFundingRate);
|
|
35301
|
+
const num22 = vesuCollateralSizeUSD.multipliedBy(vesuSupplyApy);
|
|
35302
|
+
const num32 = vesuDebtSizeUSD.abs();
|
|
35303
|
+
const maxBorrowApy = num1.plus(num22).minus(0.1).dividedBy(num32);
|
|
35304
|
+
const vesuMaxBorrowableAmount = await vesuAdapter.vesuAdapter.getMaxBorrowableByInterestRate(this.config, vesuAdapter.config.debt, maxBorrowApy.toNumber());
|
|
35305
|
+
return new Web3Number(vesuMaxBorrowableAmount.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS);
|
|
35306
|
+
}
|
|
35307
|
+
async getVesuHealthFactors() {
|
|
35308
|
+
const vesuAdapter = await this.getVesuAdapter();
|
|
35309
|
+
const extendedAdapter = await this.getExtendedAdapter();
|
|
35310
|
+
if (!vesuAdapter || !extendedAdapter) {
|
|
35311
|
+
return [0, 0];
|
|
35312
|
+
}
|
|
35313
|
+
const vesuPositions = await vesuAdapter.getPositions();
|
|
35314
|
+
const vesuCollateralSizeUSD = new Web3Number(vesuPositions[0].usdValue.toFixed(USDC_TOKEN_DECIMALS), 0);
|
|
35315
|
+
const vesuDebtSizeUSD = new Web3Number(vesuPositions[1].usdValue.toFixed(USDC_TOKEN_DECIMALS), 0);
|
|
35316
|
+
const actualLtv = vesuDebtSizeUSD.dividedBy(vesuCollateralSizeUSD).abs();
|
|
35317
|
+
logger.info(`actualLtv: ${actualLtv.toNumber()}`);
|
|
35318
|
+
const maxLtv = new Web3Number(await vesuAdapter.vesuAdapter.getLTVConfig(this.config), 4);
|
|
35319
|
+
const healthFactor = new Web3Number(maxLtv.dividedBy(actualLtv).toFixed(4), 4);
|
|
35320
|
+
logger.info(`healthFactor: ${healthFactor.toNumber()}`);
|
|
35321
|
+
const extendedBalance = await extendedAdapter.getExtendedDepositAmount();
|
|
35322
|
+
if (!extendedBalance) {
|
|
35323
|
+
return [0, 0];
|
|
35324
|
+
}
|
|
35325
|
+
const extendedLeverage = new Web3Number((Number(extendedBalance.marginRatio) * 100).toFixed(4), 4);
|
|
35326
|
+
logger.info(`extendedLeverage: ${extendedLeverage.toNumber()}`);
|
|
35327
|
+
return [healthFactor.toNumber(), extendedLeverage.toNumber()];
|
|
35328
|
+
}
|
|
35329
|
+
async netAPY() {
|
|
35330
|
+
const allPositions = [];
|
|
35331
|
+
for (let adapter of this.metadata.additionalInfo.adapters) {
|
|
35332
|
+
if (adapter.adapter.name !== ExtendedAdapter.name) {
|
|
35333
|
+
let positions = await adapter.adapter.getPositions();
|
|
35334
|
+
if (positions.length > 0) {
|
|
35335
|
+
allPositions.push(...positions);
|
|
35336
|
+
}
|
|
35337
|
+
}
|
|
35338
|
+
}
|
|
35339
|
+
const extendedAdapter = await this.getExtendedAdapter();
|
|
35340
|
+
if (!extendedAdapter) {
|
|
35341
|
+
return {
|
|
35342
|
+
net: 0,
|
|
35343
|
+
splits: []
|
|
35344
|
+
};
|
|
35345
|
+
}
|
|
35346
|
+
let vesuPositions = allPositions.filter((item) => item.protocol === Protocols.VESU);
|
|
35347
|
+
vesuPositions.map((item) => {
|
|
35348
|
+
item.apy.apy = item.apy.apy * 0.1;
|
|
35349
|
+
});
|
|
35350
|
+
const extendedPositions = await extendedAdapter.getAllOpenPositions();
|
|
35351
|
+
const usdcToken = Global.getDefaultTokens().find((token) => token.symbol === "USDC");
|
|
35352
|
+
if (!extendedPositions || !usdcToken) {
|
|
35353
|
+
return {
|
|
35354
|
+
net: 0,
|
|
35355
|
+
splits: []
|
|
35356
|
+
};
|
|
35357
|
+
}
|
|
35358
|
+
const extendedPosition = extendedPositions[0] || 0;
|
|
35359
|
+
const extendedEquity = (await extendedAdapter.getExtendedDepositAmount())?.equity || 0;
|
|
35360
|
+
const extendedApy = await extendedAdapter.getNetAPY();
|
|
35361
|
+
const totalHoldingsUSDValue = allPositions.reduce((acc, curr) => acc + curr.usdValue, 0) + Number(extendedEquity);
|
|
35362
|
+
console.log(totalHoldingsUSDValue);
|
|
35363
|
+
const extendedPositionSizeMultipliedByApy = Number(extendedPosition.value) * extendedApy;
|
|
35364
|
+
let weightedAPYs = allPositions.reduce((acc, curr) => acc + curr.apy.apy * curr.usdValue, 0) + extendedPositionSizeMultipliedByApy;
|
|
35365
|
+
console.log(weightedAPYs);
|
|
35366
|
+
const netAPY = weightedAPYs / totalHoldingsUSDValue;
|
|
35367
|
+
console.log(netAPY);
|
|
35368
|
+
allPositions.push({
|
|
35369
|
+
tokenInfo: usdcToken,
|
|
35370
|
+
amount: new Web3Number(extendedPosition.size, 0),
|
|
35371
|
+
usdValue: Number(extendedEquity),
|
|
35372
|
+
apy: { apy: extendedApy, type: "base" /* BASE */ },
|
|
35373
|
+
remarks: "finalised" /* FINALISED */,
|
|
35374
|
+
protocol: Protocols.EXTENDED
|
|
35375
|
+
});
|
|
35376
|
+
return {
|
|
35377
|
+
net: netAPY,
|
|
35378
|
+
splits: allPositions.map((p) => ({ apy: p.apy.apy, id: p.remarks ?? "" }))
|
|
35379
|
+
};
|
|
35380
|
+
}
|
|
35381
|
+
async getWalletHoldings() {
|
|
35382
|
+
const usdceToken = Global.getDefaultTokens().find((token) => token.symbol === "USDCe");
|
|
35383
|
+
const wbtcToken = Global.getDefaultTokens().find((token) => token.symbol === "WBTC");
|
|
35384
|
+
const usdcToken = Global.getDefaultTokens().find((token) => token.symbol === "USDC");
|
|
35385
|
+
if (!usdceToken || !wbtcToken || !usdcToken) {
|
|
35386
|
+
return [];
|
|
35387
|
+
}
|
|
35388
|
+
const walletAddress = this.metadata.additionalInfo.walletAddress;
|
|
35389
|
+
const usdceWalletBalance = await new ERC20(this.config).balanceOf(
|
|
35390
|
+
usdceToken.address,
|
|
35391
|
+
walletAddress,
|
|
35392
|
+
usdceToken.decimals
|
|
35393
|
+
);
|
|
35394
|
+
const usdcWalletBalance = await new ERC20(this.config).balanceOf(
|
|
35395
|
+
usdcToken.address,
|
|
35396
|
+
walletAddress,
|
|
35397
|
+
usdcToken.decimals
|
|
35398
|
+
);
|
|
35399
|
+
const wbtcWalletBalance = await new ERC20(this.config).balanceOf(
|
|
35400
|
+
wbtcToken.address,
|
|
35401
|
+
walletAddress,
|
|
35402
|
+
wbtcToken.decimals
|
|
35403
|
+
);
|
|
35404
|
+
const price = await this.pricer.getPrice(usdceToken.symbol);
|
|
35405
|
+
const wbtcPrice = await this.pricer.getPrice(wbtcToken.symbol);
|
|
35406
|
+
const usdceUsdValue = Number(usdceWalletBalance.toFixed(usdceToken.decimals)) * price.price;
|
|
35407
|
+
const usdcUsdValue = Number(usdcWalletBalance.toFixed(usdcToken.decimals)) * price.price;
|
|
35408
|
+
const wbtcUsdValue = Number(wbtcWalletBalance.toFixed(wbtcToken.decimals)) * wbtcPrice.price;
|
|
35409
|
+
return [
|
|
35410
|
+
{
|
|
35411
|
+
tokenInfo: usdceToken,
|
|
35412
|
+
amount: usdceWalletBalance,
|
|
35413
|
+
usdValue: usdceUsdValue
|
|
35414
|
+
},
|
|
35415
|
+
{
|
|
35416
|
+
tokenInfo: usdcToken,
|
|
35417
|
+
amount: usdcWalletBalance,
|
|
35418
|
+
usdValue: usdcUsdValue
|
|
35419
|
+
},
|
|
35420
|
+
{
|
|
35421
|
+
tokenInfo: wbtcToken,
|
|
35422
|
+
amount: wbtcWalletBalance,
|
|
35423
|
+
usdValue: wbtcUsdValue
|
|
35424
|
+
}
|
|
35425
|
+
];
|
|
35426
|
+
}
|
|
34505
35427
|
};
|
|
34506
|
-
function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1,
|
|
35428
|
+
function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing) {
|
|
34507
35429
|
vaultSettings.leafAdapters = [];
|
|
34508
35430
|
const wbtcToken = Global.getDefaultTokens().find(
|
|
34509
35431
|
(token) => token.symbol === lstSymbol
|
|
@@ -34527,7 +35449,9 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
34527
35449
|
...baseAdapterConfig,
|
|
34528
35450
|
avnuContract: AVNU_MIDDLEWARE,
|
|
34529
35451
|
slippage: 0.01,
|
|
34530
|
-
baseUrl: AVNU_QUOTE_URL
|
|
35452
|
+
baseUrl: AVNU_QUOTE_URL,
|
|
35453
|
+
minimumExtendedPriceDifferenceForSwapOpen,
|
|
35454
|
+
maximumExtendedPriceDifferenceForSwapClosing
|
|
34531
35455
|
});
|
|
34532
35456
|
const extendedAdapter = new ExtendedAdapter({
|
|
34533
35457
|
...baseAdapterConfig,
|
|
@@ -34536,14 +35460,17 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
34536
35460
|
],
|
|
34537
35461
|
vaultIdExtended,
|
|
34538
35462
|
extendedContract: EXTENDED_CONTRACT,
|
|
34539
|
-
|
|
34540
|
-
|
|
35463
|
+
extendedBackendWriteUrl,
|
|
35464
|
+
extendedBackendReadUrl,
|
|
34541
35465
|
extendedTimeout: 3e4,
|
|
34542
35466
|
extendedRetries: 3,
|
|
34543
35467
|
extendedBaseUrl: "https://api.starknet.extended.exchange",
|
|
34544
35468
|
extendedMarketName: "BTC-USD",
|
|
34545
35469
|
extendedPrecision: 5,
|
|
34546
|
-
avnuAdapter
|
|
35470
|
+
avnuAdapter,
|
|
35471
|
+
retryDelayForOrderStatus: minimumExtendedRetriesDelayForOrderStatus ?? 3e3,
|
|
35472
|
+
minimumExtendedMovementAmount: minimumExtendedMovementAmount ?? 5
|
|
35473
|
+
//5 usdcs
|
|
34547
35474
|
});
|
|
34548
35475
|
const vesuMultiplyAdapter = new VesuMultiplyAdapter({
|
|
34549
35476
|
poolId: pool1,
|
|
@@ -34556,7 +35483,9 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1, e
|
|
|
34556
35483
|
supportedPositions: [
|
|
34557
35484
|
{ asset: wbtcToken, isDebt: false },
|
|
34558
35485
|
{ asset: usdcToken, isDebt: true }
|
|
34559
|
-
]
|
|
35486
|
+
],
|
|
35487
|
+
minimumVesuMovementAmount: minimumVesuMovementAmount ?? 5
|
|
35488
|
+
//5 usdc
|
|
34560
35489
|
});
|
|
34561
35490
|
const unusedBalanceAdapter = new UnusedBalanceAdapter({
|
|
34562
35491
|
...baseAdapterConfig
|
|
@@ -34652,11 +35581,11 @@ function VaultDescription2(lstSymbol, underlyingSymbol) {
|
|
|
34652
35581
|
] });
|
|
34653
35582
|
}
|
|
34654
35583
|
var re7UsdcPrimeDevansh = {
|
|
34655
|
-
vaultAddress: ContractAddr.from("
|
|
34656
|
-
manager: ContractAddr.from("
|
|
34657
|
-
vaultAllocator: ContractAddr.from("
|
|
34658
|
-
redeemRequestNFT: ContractAddr.from("
|
|
34659
|
-
aumOracle: ContractAddr.from("
|
|
35584
|
+
vaultAddress: ContractAddr.from("0x058905be22d6a81792df79425dc9641cf3e1b77f36748631b7d7e5d713a32b55"),
|
|
35585
|
+
manager: ContractAddr.from("0x02648d703783feb2d967cf0520314cb5aa800d69a9426f3e3b317395af44de16"),
|
|
35586
|
+
vaultAllocator: ContractAddr.from("0x07d533c838eab6a4d854dd3aea96a55993fccd35821921970d00bde946b63b6f"),
|
|
35587
|
+
redeemRequestNFT: ContractAddr.from("0x01ef91f08fb99729c00f82fc6e0ece37917bcc43952596c19996259dc8adbbba"),
|
|
35588
|
+
aumOracle: ContractAddr.from("0x030b6acfec162f5d6e72b8a4d2798aedce78fb39de78a8f549f7cd277ae8bc8d"),
|
|
34660
35589
|
leafAdapters: [],
|
|
34661
35590
|
adapters: [],
|
|
34662
35591
|
targetHealthFactor: 1.4,
|
|
@@ -34669,14 +35598,15 @@ var re7UsdcPrimeDevansh = {
|
|
|
34669
35598
|
Global.getDefaultTokens().find((token) => token.symbol === "WBTC").decimals
|
|
34670
35599
|
),
|
|
34671
35600
|
borrowable_assets: [Global.getDefaultTokens().find((token) => token.symbol === "WBTC")],
|
|
34672
|
-
minimumWBTCDifferenceForAvnuSwap: MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP
|
|
35601
|
+
minimumWBTCDifferenceForAvnuSwap: MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP,
|
|
35602
|
+
walletAddress: WALLET_ADDRESS
|
|
34673
35603
|
};
|
|
34674
|
-
var VesuExtendedTestStrategies = (
|
|
35604
|
+
var VesuExtendedTestStrategies = (extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing) => {
|
|
34675
35605
|
return [
|
|
34676
|
-
getStrategySettingsVesuExtended("WBTC", "USDC", re7UsdcPrimeDevansh, false, false,
|
|
35606
|
+
getStrategySettingsVesuExtended("WBTC", "USDC", re7UsdcPrimeDevansh, false, false, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing)
|
|
34677
35607
|
];
|
|
34678
35608
|
};
|
|
34679
|
-
function getStrategySettingsVesuExtended(lstSymbol, underlyingSymbol, addresses, isPreview = false, isLST,
|
|
35609
|
+
function getStrategySettingsVesuExtended(lstSymbol, underlyingSymbol, addresses, isPreview = false, isLST, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing) {
|
|
34680
35610
|
return {
|
|
34681
35611
|
name: `Extended Test ${underlyingSymbol}`,
|
|
34682
35612
|
description: getDescription2(lstSymbol, underlyingSymbol),
|
|
@@ -34684,7 +35614,7 @@ function getStrategySettingsVesuExtended(lstSymbol, underlyingSymbol, addresses,
|
|
|
34684
35614
|
launchBlock: 0,
|
|
34685
35615
|
type: "Other",
|
|
34686
35616
|
depositTokens: [Global.getDefaultTokens().find((token) => token.symbol === underlyingSymbol)],
|
|
34687
|
-
additionalInfo: getLooperSettings2(lstSymbol, underlyingSymbol, addresses, VesuPools.Re7USDCPrime,
|
|
35617
|
+
additionalInfo: getLooperSettings2(lstSymbol, underlyingSymbol, addresses, VesuPools.Re7USDCPrime, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing),
|
|
34688
35618
|
risk: {
|
|
34689
35619
|
riskFactor: _riskFactor3,
|
|
34690
35620
|
netRisk: _riskFactor3.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor3.reduce((acc, curr) => acc + curr.weight, 0),
|
|
@@ -38927,11 +39857,13 @@ export {
|
|
|
38927
39857
|
AssetOperationStatus,
|
|
38928
39858
|
AssetOperationType,
|
|
38929
39859
|
AutoCompounderSTRK,
|
|
39860
|
+
AvnuAdapter,
|
|
38930
39861
|
AvnuWrapper,
|
|
38931
39862
|
BaseAdapter,
|
|
38932
39863
|
BaseStrategy,
|
|
38933
39864
|
CommonAdapter,
|
|
38934
39865
|
ContractAddr,
|
|
39866
|
+
CycleType,
|
|
38935
39867
|
deployer_default as Deployer,
|
|
38936
39868
|
ERC20,
|
|
38937
39869
|
EXTENDED_CONTRACT,
|
|
@@ -38960,6 +39892,7 @@ export {
|
|
|
38960
39892
|
PRICE_ROUTER,
|
|
38961
39893
|
PasswordJsonCryptoUtil,
|
|
38962
39894
|
PositionSide,
|
|
39895
|
+
PositionTypeAvnuExtended,
|
|
38963
39896
|
Pragma,
|
|
38964
39897
|
Pricer,
|
|
38965
39898
|
PricerBase,
|
|
@@ -39009,6 +39942,7 @@ export {
|
|
|
39009
39942
|
calculateExtendedLevergae,
|
|
39010
39943
|
calculateVesUPositionSizeGivenExtended,
|
|
39011
39944
|
calculateVesuLeverage,
|
|
39945
|
+
calculateWBTCAmountToMaintainLTV,
|
|
39012
39946
|
extensionMap,
|
|
39013
39947
|
getAPIUsingHeadlessBrowser,
|
|
39014
39948
|
getContractDetails,
|