@strkfarm/sdk 2.0.0-dev.7 → 2.0.0-dev.8
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 +418 -99
- package/dist/index.browser.mjs +418 -99
- package/dist/index.js +418 -99
- package/dist/index.mjs +418 -99
- package/package.json +1 -1
- package/src/strategies/universal-adapters/avnu-adapter.ts +2 -3
- package/src/strategies/universal-adapters/extended-adapter.ts +217 -63
- package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +284 -50
|
@@ -93946,8 +93946,47 @@ spurious results.`);
|
|
|
93946
93946
|
async withdrawFromExtended(amount) {
|
|
93947
93947
|
try {
|
|
93948
93948
|
if (!this.client) {
|
|
93949
|
-
|
|
93949
|
+
logger2.error("Client not initialized");
|
|
93950
|
+
return false;
|
|
93951
|
+
}
|
|
93952
|
+
if (amount.lessThanOrEqualTo(0)) {
|
|
93953
|
+
logger2.error(
|
|
93954
|
+
`Invalid withdrawal amount: ${amount.toNumber()}. Amount must be positive.`
|
|
93955
|
+
);
|
|
93956
|
+
return false;
|
|
93957
|
+
}
|
|
93958
|
+
if (amount.lessThanOrEqualTo(this.minimumExtendedMovementAmount)) {
|
|
93959
|
+
logger2.warn(
|
|
93960
|
+
`Withdrawal amount ${amount.toNumber()} is below minimum Extended movement amount ${this.minimumExtendedMovementAmount}. Skipping withdrawal.`
|
|
93961
|
+
);
|
|
93962
|
+
return false;
|
|
93963
|
+
}
|
|
93964
|
+
const holdings = await this.getExtendedDepositAmount();
|
|
93965
|
+
if (!holdings) {
|
|
93966
|
+
logger2.error(
|
|
93967
|
+
"Cannot get holdings - unable to validate withdrawal amount"
|
|
93968
|
+
);
|
|
93969
|
+
return false;
|
|
93950
93970
|
}
|
|
93971
|
+
const availableForWithdrawal = parseFloat(
|
|
93972
|
+
holdings.availableForWithdrawal
|
|
93973
|
+
);
|
|
93974
|
+
if (!Number.isFinite(availableForWithdrawal) || availableForWithdrawal < 0) {
|
|
93975
|
+
logger2.error(
|
|
93976
|
+
`Invalid availableForWithdrawal: ${holdings.availableForWithdrawal}. Expected a finite, non-negative number.`
|
|
93977
|
+
);
|
|
93978
|
+
return false;
|
|
93979
|
+
}
|
|
93980
|
+
const withdrawalAmount = amount.toNumber();
|
|
93981
|
+
if (withdrawalAmount > availableForWithdrawal) {
|
|
93982
|
+
logger2.error(
|
|
93983
|
+
`Withdrawal amount ${withdrawalAmount} exceeds available balance ${availableForWithdrawal}`
|
|
93984
|
+
);
|
|
93985
|
+
return false;
|
|
93986
|
+
}
|
|
93987
|
+
logger2.info(
|
|
93988
|
+
`Withdrawing ${withdrawalAmount} from Extended. Available balance: ${availableForWithdrawal}`
|
|
93989
|
+
);
|
|
93951
93990
|
const withdrawalRequest = await this.client.withdrawUSDC(
|
|
93952
93991
|
amount.toFixed(2)
|
|
93953
93992
|
);
|
|
@@ -93958,6 +93997,9 @@ spurious results.`);
|
|
|
93958
93997
|
);
|
|
93959
93998
|
return withdrawalStatus;
|
|
93960
93999
|
}
|
|
94000
|
+
logger2.error(
|
|
94001
|
+
`Withdrawal request failed with status: ${withdrawalRequest.status}`
|
|
94002
|
+
);
|
|
93961
94003
|
return false;
|
|
93962
94004
|
} catch (error2) {
|
|
93963
94005
|
logger2.error(`Error creating Withdraw Call: ${error2}`);
|
|
@@ -93968,21 +94010,44 @@ spurious results.`);
|
|
|
93968
94010
|
return Promise.resolve(1);
|
|
93969
94011
|
}
|
|
93970
94012
|
async getExtendedDepositAmount() {
|
|
93971
|
-
|
|
93972
|
-
|
|
93973
|
-
|
|
93974
|
-
|
|
93975
|
-
|
|
93976
|
-
|
|
93977
|
-
|
|
93978
|
-
|
|
93979
|
-
|
|
93980
|
-
|
|
93981
|
-
|
|
93982
|
-
|
|
94013
|
+
try {
|
|
94014
|
+
if (this.client === null) {
|
|
94015
|
+
logger2.error("error initializing client - client is null");
|
|
94016
|
+
return void 0;
|
|
94017
|
+
}
|
|
94018
|
+
const result2 = await this.client.getHoldings();
|
|
94019
|
+
if (!result2) {
|
|
94020
|
+
logger2.error("error getting holdings - API returned null/undefined");
|
|
94021
|
+
return void 0;
|
|
94022
|
+
}
|
|
94023
|
+
if (result2.status && result2.status !== "OK") {
|
|
94024
|
+
logger2.error(
|
|
94025
|
+
`error getting holdings - API returned status: ${result2.status}`
|
|
94026
|
+
);
|
|
94027
|
+
return void 0;
|
|
94028
|
+
}
|
|
94029
|
+
const holdings = result2.data;
|
|
94030
|
+
if (!holdings) {
|
|
94031
|
+
logger2.warn(
|
|
94032
|
+
"holdings data is null/undefined - treating as zero balance"
|
|
94033
|
+
);
|
|
94034
|
+
return {
|
|
94035
|
+
collateral_name: "",
|
|
94036
|
+
balance: "0",
|
|
94037
|
+
equity: "0",
|
|
94038
|
+
availableForTrade: "0",
|
|
94039
|
+
availableForWithdrawal: "0",
|
|
94040
|
+
unrealisedPnl: "0",
|
|
94041
|
+
initialMargin: "0",
|
|
94042
|
+
marginRatio: "0",
|
|
94043
|
+
updatedTime: Date.now()
|
|
94044
|
+
};
|
|
94045
|
+
}
|
|
94046
|
+
return holdings;
|
|
94047
|
+
} catch (error2) {
|
|
94048
|
+
logger2.error(`error getting holdings - exception: ${error2}`);
|
|
93983
94049
|
return void 0;
|
|
93984
94050
|
}
|
|
93985
|
-
return holdings;
|
|
93986
94051
|
}
|
|
93987
94052
|
async setLeverage(leverage, marketName) {
|
|
93988
94053
|
if (this.client === null) {
|
|
@@ -94024,38 +94089,24 @@ spurious results.`);
|
|
|
94024
94089
|
return result2.data;
|
|
94025
94090
|
}
|
|
94026
94091
|
async getOrderStatus(orderId, marketName) {
|
|
94027
|
-
|
|
94028
|
-
|
|
94029
|
-
|
|
94030
|
-
|
|
94031
|
-
let orderhistory = await this.getOrderHistory(marketName);
|
|
94032
|
-
if (!orderhistory || orderhistory.length === 0) {
|
|
94033
|
-
logger2.error(`error getting order history: ${orderId}`);
|
|
94034
|
-
} else {
|
|
94035
|
-
const order = orderhistory.slice(0, 10).find((order2) => order2.id.toString() === orderId);
|
|
94036
|
-
if (order) {
|
|
94037
|
-
return order;
|
|
94092
|
+
try {
|
|
94093
|
+
if (this.client === null) {
|
|
94094
|
+
logger2.error("error initializing client");
|
|
94095
|
+
return null;
|
|
94038
94096
|
}
|
|
94039
|
-
|
|
94040
|
-
for (let attempt = 1; attempt <= 5; attempt++) {
|
|
94041
|
-
await new Promise((resolve) => setTimeout(resolve, this.retryDelayForOrderStatus));
|
|
94042
|
-
orderhistory = await this.getOrderHistory(marketName);
|
|
94097
|
+
const orderhistory = await this.getOrderHistory(marketName);
|
|
94043
94098
|
if (!orderhistory || orderhistory.length === 0) {
|
|
94044
|
-
|
|
94045
|
-
`error getting order history on retry ${attempt}: ${orderId}`
|
|
94046
|
-
);
|
|
94047
|
-
continue;
|
|
94099
|
+
return null;
|
|
94048
94100
|
}
|
|
94049
|
-
const order = orderhistory.slice(0,
|
|
94050
|
-
if (order
|
|
94101
|
+
const order = orderhistory.slice(0, 20).find((order2) => order2.id.toString() === orderId);
|
|
94102
|
+
if (order) {
|
|
94051
94103
|
return order;
|
|
94052
94104
|
}
|
|
94053
|
-
|
|
94054
|
-
|
|
94055
|
-
);
|
|
94105
|
+
return null;
|
|
94106
|
+
} catch (error2) {
|
|
94107
|
+
logger2.error(`error getting order status: ${error2}`);
|
|
94108
|
+
return null;
|
|
94056
94109
|
}
|
|
94057
|
-
logger2.error(`error getting order after all retries: ${orderId}`);
|
|
94058
|
-
return null;
|
|
94059
94110
|
}
|
|
94060
94111
|
async fetchOrderBookBTCUSDC() {
|
|
94061
94112
|
try {
|
|
@@ -94106,14 +94157,40 @@ spurious results.`);
|
|
|
94106
94157
|
logger2.error("error depositing or setting leverage");
|
|
94107
94158
|
return null;
|
|
94108
94159
|
}
|
|
94109
|
-
const
|
|
94110
|
-
if (
|
|
94160
|
+
const { ask, bid } = await this.fetchOrderBookBTCUSDC();
|
|
94161
|
+
if (!ask || !bid || ask.lessThanOrEqualTo(0) || bid.lessThanOrEqualTo(0)) {
|
|
94162
|
+
logger2.error(
|
|
94163
|
+
`Invalid orderbook prices: ask=${ask?.toNumber()}, bid=${bid?.toNumber()}`
|
|
94164
|
+
);
|
|
94111
94165
|
return null;
|
|
94112
94166
|
}
|
|
94113
|
-
const { ask, bid } = await this.fetchOrderBookBTCUSDC();
|
|
94114
94167
|
const spread3 = ask.minus(bid);
|
|
94115
|
-
|
|
94116
|
-
|
|
94168
|
+
const midPrice = ask.plus(bid).div(2);
|
|
94169
|
+
const MAX_PRICE_DEVIATION_MULTIPLIER = 0.5;
|
|
94170
|
+
const priceAdjustmentMultiplier = Math.min(
|
|
94171
|
+
0.2 * attempt,
|
|
94172
|
+
MAX_PRICE_DEVIATION_MULTIPLIER
|
|
94173
|
+
);
|
|
94174
|
+
const priceAdjustment = spread3.times(priceAdjustmentMultiplier);
|
|
94175
|
+
let price = midPrice;
|
|
94176
|
+
if (side === "SELL" /* SELL */) {
|
|
94177
|
+
price = midPrice.minus(priceAdjustment);
|
|
94178
|
+
} else {
|
|
94179
|
+
price = midPrice.plus(priceAdjustment);
|
|
94180
|
+
}
|
|
94181
|
+
const maxDeviation = midPrice.times(0.5);
|
|
94182
|
+
if (price.minus(midPrice).abs().greaterThan(maxDeviation)) {
|
|
94183
|
+
logger2.error(
|
|
94184
|
+
`Price deviation too large on attempt ${attempt}: price=${price.toNumber()}, midPrice=${midPrice.toNumber()}, deviation=${price.minus(midPrice).abs().toNumber()}`
|
|
94185
|
+
);
|
|
94186
|
+
if (attempt >= maxAttempts) {
|
|
94187
|
+
return null;
|
|
94188
|
+
}
|
|
94189
|
+
price = side === "SELL" /* SELL */ ? midPrice.minus(maxDeviation) : midPrice.plus(maxDeviation);
|
|
94190
|
+
}
|
|
94191
|
+
logger2.info(
|
|
94192
|
+
`createOrder attempt ${attempt}/${maxAttempts}: side=${side}, midPrice=${midPrice.toNumber()}, adjustedPrice=${price.toNumber()}, adjustment=${priceAdjustmentMultiplier * 100}%`
|
|
94193
|
+
);
|
|
94117
94194
|
const amount_in_token = (btcAmount * parseInt(leverage)).toFixed(
|
|
94118
94195
|
this.config.extendedPrecision
|
|
94119
94196
|
);
|
|
@@ -94124,17 +94201,57 @@ spurious results.`);
|
|
|
94124
94201
|
price.toFixed(0),
|
|
94125
94202
|
side
|
|
94126
94203
|
);
|
|
94127
|
-
if (!result2) {
|
|
94204
|
+
if (!result2 || !result2.position_id) {
|
|
94205
|
+
logger2.error("Failed to create order - no position_id returned");
|
|
94128
94206
|
return null;
|
|
94129
94207
|
}
|
|
94130
|
-
|
|
94131
|
-
|
|
94132
|
-
|
|
94208
|
+
const positionId = result2.position_id;
|
|
94209
|
+
logger2.info(
|
|
94210
|
+
`Order created with position_id: ${positionId}. Waiting for API to update...`
|
|
94211
|
+
);
|
|
94212
|
+
let openOrder = await this.getOrderStatus(
|
|
94213
|
+
positionId,
|
|
94133
94214
|
this.config.extendedMarketName
|
|
94134
94215
|
);
|
|
94216
|
+
const maxStatusRetries = 3;
|
|
94217
|
+
const statusRetryDelay = 5e3;
|
|
94135
94218
|
if (!openOrder) {
|
|
94219
|
+
logger2.warn(
|
|
94220
|
+
`Order ${positionId} not found in API yet. Retrying status fetch (max ${maxStatusRetries} times)...`
|
|
94221
|
+
);
|
|
94222
|
+
for (let statusRetry = 1; statusRetry <= maxStatusRetries; statusRetry++) {
|
|
94223
|
+
await new Promise((resolve) => setTimeout(resolve, statusRetryDelay));
|
|
94224
|
+
openOrder = await this.getOrderStatus(
|
|
94225
|
+
positionId,
|
|
94226
|
+
this.config.extendedMarketName
|
|
94227
|
+
);
|
|
94228
|
+
if (openOrder) {
|
|
94229
|
+
logger2.info(
|
|
94230
|
+
`Order ${positionId} found after ${statusRetry} status retry(ies)`
|
|
94231
|
+
);
|
|
94232
|
+
break;
|
|
94233
|
+
}
|
|
94234
|
+
logger2.warn(
|
|
94235
|
+
`Order ${positionId} still not found after ${statusRetry}/${maxStatusRetries} status retries`
|
|
94236
|
+
);
|
|
94237
|
+
}
|
|
94238
|
+
}
|
|
94239
|
+
if (openOrder && openOrder.status === "FILLED" /* FILLED */) {
|
|
94240
|
+
logger2.info(
|
|
94241
|
+
`Order ${positionId} successfully filled with quantity ${openOrder.qty}`
|
|
94242
|
+
);
|
|
94243
|
+
return {
|
|
94244
|
+
position_id: positionId,
|
|
94245
|
+
btc_exposure: openOrder.qty
|
|
94246
|
+
};
|
|
94247
|
+
} else if (openOrder && openOrder.status !== "FILLED" /* FILLED */) {
|
|
94248
|
+
logger2.warn(
|
|
94249
|
+
`Order ${positionId} found but status is ${openOrder.status}, not FILLED. Retrying order creation...`
|
|
94250
|
+
);
|
|
94136
94251
|
if (attempt >= maxAttempts) {
|
|
94137
|
-
logger2.error(
|
|
94252
|
+
logger2.error(
|
|
94253
|
+
`Max retries reached \u2014 order ${positionId} status is ${openOrder.status}, not FILLED`
|
|
94254
|
+
);
|
|
94138
94255
|
return null;
|
|
94139
94256
|
} else {
|
|
94140
94257
|
const backoff = 2e3 * attempt;
|
|
@@ -94148,9 +94265,12 @@ spurious results.`);
|
|
|
94148
94265
|
);
|
|
94149
94266
|
}
|
|
94150
94267
|
} else {
|
|
94268
|
+
logger2.warn(
|
|
94269
|
+
`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.`
|
|
94270
|
+
);
|
|
94151
94271
|
return {
|
|
94152
|
-
position_id:
|
|
94153
|
-
btc_exposure:
|
|
94272
|
+
position_id: positionId,
|
|
94273
|
+
btc_exposure: amount_in_token
|
|
94154
94274
|
};
|
|
94155
94275
|
}
|
|
94156
94276
|
} catch (err2) {
|
|
@@ -98165,11 +98285,27 @@ spurious results.`);
|
|
|
98165
98285
|
}
|
|
98166
98286
|
async shouldInvest() {
|
|
98167
98287
|
try {
|
|
98288
|
+
logger2.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest starting`);
|
|
98168
98289
|
const vesuAdapter = await this.getVesuAdapter();
|
|
98169
98290
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
98170
|
-
|
|
98291
|
+
logger2.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest adapters fetched: vesuAdapter=${!!vesuAdapter}, extendedAdapter=${!!extendedAdapter}, extendedAdapter.client=${!!extendedAdapter?.client}`);
|
|
98292
|
+
if (!vesuAdapter) {
|
|
98171
98293
|
logger2.error(
|
|
98172
|
-
`
|
|
98294
|
+
`Vesu adapter not configured in metadata. This is a configuration issue, not a temporary failure.`
|
|
98295
|
+
);
|
|
98296
|
+
return {
|
|
98297
|
+
shouldInvest: false,
|
|
98298
|
+
vesuAmount: new Web3Number(0, 0),
|
|
98299
|
+
extendedAmount: new Web3Number(0, 0),
|
|
98300
|
+
extendedLeverage: 0,
|
|
98301
|
+
collateralPrice: 0,
|
|
98302
|
+
debtPrice: 0,
|
|
98303
|
+
vesuLeverage: 0
|
|
98304
|
+
};
|
|
98305
|
+
}
|
|
98306
|
+
if (!extendedAdapter) {
|
|
98307
|
+
logger2.error(
|
|
98308
|
+
`Extended adapter not configured in metadata. This is a configuration issue, not a temporary failure.`
|
|
98173
98309
|
);
|
|
98174
98310
|
return {
|
|
98175
98311
|
shouldInvest: false,
|
|
@@ -98181,10 +98317,72 @@ spurious results.`);
|
|
|
98181
98317
|
vesuLeverage: 0
|
|
98182
98318
|
};
|
|
98183
98319
|
}
|
|
98320
|
+
if (!extendedAdapter.client) {
|
|
98321
|
+
logger2.error(
|
|
98322
|
+
`Extended adapter client not initialized. This may be a temporary initialization failure - check network connectivity and API availability.`
|
|
98323
|
+
);
|
|
98324
|
+
return {
|
|
98325
|
+
shouldInvest: false,
|
|
98326
|
+
vesuAmount: new Web3Number(0, 0),
|
|
98327
|
+
extendedAmount: new Web3Number(0, 0),
|
|
98328
|
+
extendedLeverage: 0,
|
|
98329
|
+
collateralPrice: 0,
|
|
98330
|
+
debtPrice: 0,
|
|
98331
|
+
vesuLeverage: 0
|
|
98332
|
+
};
|
|
98333
|
+
}
|
|
98334
|
+
logger2.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest calling getUnusedBalance`);
|
|
98184
98335
|
const balance = await this.getUnusedBalance();
|
|
98336
|
+
if (!Number.isFinite(balance.usdValue) || balance.usdValue < 0) {
|
|
98337
|
+
logger2.error(
|
|
98338
|
+
`Invalid balance.usdValue: ${balance.usdValue}. Expected a finite, non-negative number.`
|
|
98339
|
+
);
|
|
98340
|
+
return {
|
|
98341
|
+
shouldInvest: false,
|
|
98342
|
+
vesuAmount: new Web3Number(0, 0),
|
|
98343
|
+
extendedAmount: new Web3Number(0, 0),
|
|
98344
|
+
extendedLeverage: 0,
|
|
98345
|
+
collateralPrice: 0,
|
|
98346
|
+
debtPrice: 0,
|
|
98347
|
+
vesuLeverage: 0
|
|
98348
|
+
};
|
|
98349
|
+
}
|
|
98350
|
+
logger2.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest balance: ${balance.usdValue}`);
|
|
98185
98351
|
const usdcBalanceOnExtended = await extendedAdapter.getExtendedDepositAmount();
|
|
98352
|
+
if (usdcBalanceOnExtended) {
|
|
98353
|
+
const availableForWithdrawal = parseFloat(usdcBalanceOnExtended.availableForWithdrawal);
|
|
98354
|
+
if (!Number.isFinite(availableForWithdrawal) || availableForWithdrawal < 0) {
|
|
98355
|
+
logger2.error(
|
|
98356
|
+
`Invalid usdcBalanceOnExtended.availableForWithdrawal: ${usdcBalanceOnExtended.availableForWithdrawal}. Expected a finite, non-negative number.`
|
|
98357
|
+
);
|
|
98358
|
+
return {
|
|
98359
|
+
shouldInvest: false,
|
|
98360
|
+
vesuAmount: new Web3Number(0, 0),
|
|
98361
|
+
extendedAmount: new Web3Number(0, 0),
|
|
98362
|
+
extendedLeverage: 0,
|
|
98363
|
+
collateralPrice: 0,
|
|
98364
|
+
debtPrice: 0,
|
|
98365
|
+
vesuLeverage: 0
|
|
98366
|
+
};
|
|
98367
|
+
}
|
|
98368
|
+
}
|
|
98186
98369
|
const amountToInvest = new Web3Number(balance.usdValue, USDC_TOKEN_DECIMALS).plus(usdcBalanceOnExtended?.availableForWithdrawal ?? 0).multipliedBy(1 - LIMIT_BALANCE);
|
|
98187
|
-
|
|
98370
|
+
const amountToInvestNumber = amountToInvest.toNumber();
|
|
98371
|
+
if (!Number.isFinite(amountToInvestNumber)) {
|
|
98372
|
+
logger2.error(
|
|
98373
|
+
`Invalid amountToInvest calculation result: ${amountToInvestNumber}. Calculation may have produced NaN or Infinity.`
|
|
98374
|
+
);
|
|
98375
|
+
return {
|
|
98376
|
+
shouldInvest: false,
|
|
98377
|
+
vesuAmount: new Web3Number(0, 0),
|
|
98378
|
+
extendedAmount: new Web3Number(0, 0),
|
|
98379
|
+
extendedLeverage: 0,
|
|
98380
|
+
collateralPrice: 0,
|
|
98381
|
+
debtPrice: 0,
|
|
98382
|
+
vesuLeverage: 0
|
|
98383
|
+
};
|
|
98384
|
+
}
|
|
98385
|
+
logger2.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest amountToInvest: ${amountToInvestNumber}`);
|
|
98188
98386
|
if (amountToInvest.lessThan(0)) {
|
|
98189
98387
|
return {
|
|
98190
98388
|
shouldInvest: false,
|
|
@@ -98214,6 +98412,34 @@ spurious results.`);
|
|
|
98214
98412
|
collateralPrice,
|
|
98215
98413
|
debtPrice
|
|
98216
98414
|
} = await this.getAssetPrices();
|
|
98415
|
+
if (!Number.isFinite(collateralPrice.price) || collateralPrice.price <= 0) {
|
|
98416
|
+
logger2.error(
|
|
98417
|
+
`Invalid collateralPrice: ${collateralPrice.price}. Expected a finite, positive number.`
|
|
98418
|
+
);
|
|
98419
|
+
return {
|
|
98420
|
+
shouldInvest: false,
|
|
98421
|
+
vesuAmount: new Web3Number(0, 0),
|
|
98422
|
+
extendedAmount: new Web3Number(0, 0),
|
|
98423
|
+
extendedLeverage: 0,
|
|
98424
|
+
collateralPrice: 0,
|
|
98425
|
+
debtPrice: 0,
|
|
98426
|
+
vesuLeverage: 0
|
|
98427
|
+
};
|
|
98428
|
+
}
|
|
98429
|
+
if (!Number.isFinite(debtPrice.price) || debtPrice.price <= 0) {
|
|
98430
|
+
logger2.error(
|
|
98431
|
+
`Invalid debtPrice: ${debtPrice.price}. Expected a finite, positive number.`
|
|
98432
|
+
);
|
|
98433
|
+
return {
|
|
98434
|
+
shouldInvest: false,
|
|
98435
|
+
vesuAmount: new Web3Number(0, 0),
|
|
98436
|
+
extendedAmount: new Web3Number(0, 0),
|
|
98437
|
+
extendedLeverage: 0,
|
|
98438
|
+
collateralPrice: 0,
|
|
98439
|
+
debtPrice: 0,
|
|
98440
|
+
vesuLeverage: 0
|
|
98441
|
+
};
|
|
98442
|
+
}
|
|
98217
98443
|
const { vesu_amount, extended_amount, extended_leverage, vesu_leverage } = await calculateAmountDistribution(
|
|
98218
98444
|
amountToInvest.toNumber(),
|
|
98219
98445
|
extendedAdapter.client,
|
|
@@ -98264,13 +98490,45 @@ spurious results.`);
|
|
|
98264
98490
|
try {
|
|
98265
98491
|
const vesuAdapter = await this.getVesuAdapter();
|
|
98266
98492
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
98267
|
-
let calls = [];
|
|
98268
98493
|
if (!vesuAdapter || !extendedAdapter || !extendedAdapter.client) {
|
|
98269
98494
|
logger2.error(
|
|
98270
98495
|
`vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
|
|
98271
98496
|
);
|
|
98272
|
-
return
|
|
98497
|
+
return [];
|
|
98273
98498
|
}
|
|
98499
|
+
const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
98500
|
+
if (!extendedHoldings) {
|
|
98501
|
+
logger2.error(`error getting extended holdings: ${extendedHoldings}`);
|
|
98502
|
+
return [];
|
|
98503
|
+
}
|
|
98504
|
+
const usdcAmountInWallet = (await this.getUnusedBalance()).amount;
|
|
98505
|
+
const usdcAmountOnExtendedAvailableForWithdrawal = parseFloat(
|
|
98506
|
+
extendedHoldings.availableForWithdrawal
|
|
98507
|
+
);
|
|
98508
|
+
logger2.info(`${_VesuExtendedMultiplierStrategy.name}::shouldMoveAssets calculating movements - Extended current: ${usdcAmountOnExtendedAvailableForWithdrawal}, Wallet: ${usdcAmountInWallet.toNumber()}, Target Extended: ${extendedAmount.toNumber()}, Target Vesu: ${vesuAmount.toNumber()}`);
|
|
98509
|
+
let totalExtendedWithdrawal = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
98510
|
+
let totalExtendedDeposit = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
98511
|
+
if (extendedAmount.isNegative() && extendedAmount.abs().greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
98512
|
+
totalExtendedWithdrawal = totalExtendedWithdrawal.plus(extendedAmount.abs());
|
|
98513
|
+
}
|
|
98514
|
+
const extendedTargetAmount = extendedAmount.abs();
|
|
98515
|
+
let projectedExtendedBalance = usdcAmountOnExtendedAvailableForWithdrawal;
|
|
98516
|
+
if (extendedAmount.isNegative()) {
|
|
98517
|
+
projectedExtendedBalance = projectedExtendedBalance - extendedAmount.abs().toNumber();
|
|
98518
|
+
}
|
|
98519
|
+
const extendedAmountDifference = extendedTargetAmount.minus(projectedExtendedBalance);
|
|
98520
|
+
const extendedAmountDifferenceAbs = extendedAmountDifference.abs();
|
|
98521
|
+
if (extendedAmountDifference.lessThan(0)) {
|
|
98522
|
+
totalExtendedWithdrawal = totalExtendedWithdrawal.plus(extendedAmountDifferenceAbs);
|
|
98523
|
+
} else if (extendedAmountDifference.greaterThan(0)) {
|
|
98524
|
+
totalExtendedDeposit = totalExtendedDeposit.plus(extendedAmountDifference);
|
|
98525
|
+
}
|
|
98526
|
+
const vesuTargetAmount = vesuAmount.abs();
|
|
98527
|
+
const projectedWalletBalance = usdcAmountInWallet.plus(totalExtendedWithdrawal).minus(totalExtendedDeposit);
|
|
98528
|
+
let vesuAmountDifference = vesuTargetAmount.minus(projectedWalletBalance);
|
|
98529
|
+
const vesuAmountDifferenceAbs = vesuAmountDifference.abs();
|
|
98530
|
+
logger2.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()}`);
|
|
98531
|
+
let calls = [];
|
|
98274
98532
|
if (extendedAmount.isNegative() && extendedAmount.abs().greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
98275
98533
|
try {
|
|
98276
98534
|
const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
|
|
@@ -98291,7 +98549,7 @@ spurious results.`);
|
|
|
98291
98549
|
logger2.error(`Failed moving assets to vault: ${err2}`);
|
|
98292
98550
|
}
|
|
98293
98551
|
}
|
|
98294
|
-
if (vesuAmount.isNegative() && vesuAmount.
|
|
98552
|
+
if (vesuAmount.isNegative() && vesuAmount.abs().greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
|
|
98295
98553
|
try {
|
|
98296
98554
|
const { calls: vesuCalls, status: vesuStatus } = await this.moveAssets(
|
|
98297
98555
|
{
|
|
@@ -98310,48 +98568,76 @@ spurious results.`);
|
|
|
98310
98568
|
logger2.error(`Failed moving assets to vault: ${err2}`);
|
|
98311
98569
|
}
|
|
98312
98570
|
}
|
|
98313
|
-
|
|
98314
|
-
|
|
98315
|
-
|
|
98316
|
-
|
|
98317
|
-
|
|
98318
|
-
|
|
98319
|
-
|
|
98320
|
-
|
|
98321
|
-
|
|
98322
|
-
|
|
98323
|
-
|
|
98324
|
-
|
|
98325
|
-
{
|
|
98326
|
-
|
|
98327
|
-
|
|
98328
|
-
|
|
98329
|
-
|
|
98330
|
-
|
|
98331
|
-
|
|
98332
|
-
|
|
98333
|
-
|
|
98334
|
-
|
|
98335
|
-
|
|
98571
|
+
if (extendedAmountDifferenceAbs.greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
98572
|
+
if (extendedAmountDifference.greaterThan(0)) {
|
|
98573
|
+
try {
|
|
98574
|
+
const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
|
|
98575
|
+
{
|
|
98576
|
+
to: Protocols.EXTENDED.name,
|
|
98577
|
+
from: Protocols.VAULT.name,
|
|
98578
|
+
amount: extendedAmountDifference
|
|
98579
|
+
},
|
|
98580
|
+
extendedAdapter,
|
|
98581
|
+
vesuAdapter
|
|
98582
|
+
);
|
|
98583
|
+
if (extendedStatus) {
|
|
98584
|
+
calls.push(...extendedCalls);
|
|
98585
|
+
} else {
|
|
98586
|
+
logger2.error(`Failed to move assets to extended - operation returned false status`);
|
|
98587
|
+
return [];
|
|
98588
|
+
}
|
|
98589
|
+
} catch (err2) {
|
|
98590
|
+
logger2.error(`Failed moving assets to extended: ${err2}`);
|
|
98591
|
+
return [];
|
|
98592
|
+
}
|
|
98593
|
+
} else if (extendedAmountDifference.lessThan(0)) {
|
|
98594
|
+
try {
|
|
98595
|
+
const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
|
|
98596
|
+
{
|
|
98597
|
+
to: Protocols.VAULT.name,
|
|
98598
|
+
from: Protocols.EXTENDED.name,
|
|
98599
|
+
amount: extendedAmountDifferenceAbs
|
|
98600
|
+
},
|
|
98601
|
+
extendedAdapter,
|
|
98602
|
+
vesuAdapter
|
|
98603
|
+
);
|
|
98604
|
+
if (extendedStatus) {
|
|
98605
|
+
calls.push(...extendedCalls);
|
|
98606
|
+
} else {
|
|
98607
|
+
logger2.error(`Failed to withdraw from extended - operation returned false status`);
|
|
98608
|
+
return [];
|
|
98609
|
+
}
|
|
98610
|
+
} catch (err2) {
|
|
98611
|
+
logger2.error(`Failed moving assets from extended to vault: ${err2}`);
|
|
98612
|
+
return [];
|
|
98613
|
+
}
|
|
98336
98614
|
}
|
|
98337
98615
|
}
|
|
98338
|
-
if (
|
|
98339
|
-
|
|
98340
|
-
|
|
98341
|
-
{
|
|
98342
|
-
to: Protocols.VAULT.name,
|
|
98343
|
-
from: Protocols.EXTENDED.name,
|
|
98344
|
-
amount: vesuAmount.minus(usdcAmountInWallet)
|
|
98345
|
-
},
|
|
98346
|
-
extendedAdapter,
|
|
98347
|
-
vesuAdapter
|
|
98616
|
+
if (vesuAmountDifferenceAbs.greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
|
|
98617
|
+
if (vesuAmountDifference.lessThanOrEqualTo(0)) {
|
|
98618
|
+
logger2.warn(
|
|
98619
|
+
`Vesu amount difference is negative or zero: ${vesuAmountDifference.toNumber()}. Skipping operation.`
|
|
98348
98620
|
);
|
|
98349
|
-
|
|
98621
|
+
} else {
|
|
98622
|
+
try {
|
|
98623
|
+
const { calls: vesuCalls, status: vesuStatus } = await this.moveAssets(
|
|
98624
|
+
{
|
|
98625
|
+
to: Protocols.VAULT.name,
|
|
98626
|
+
from: Protocols.EXTENDED.name,
|
|
98627
|
+
amount: vesuAmountDifference
|
|
98628
|
+
},
|
|
98629
|
+
extendedAdapter,
|
|
98630
|
+
vesuAdapter
|
|
98631
|
+
);
|
|
98632
|
+
if (!vesuStatus) {
|
|
98633
|
+
logger2.error(`Failed to move assets to vesu - operation returned false status`);
|
|
98634
|
+
return [];
|
|
98635
|
+
}
|
|
98636
|
+
calls.push(...vesuCalls);
|
|
98637
|
+
} catch (err2) {
|
|
98638
|
+
logger2.error(`Failed moving assets to vault: ${err2}`);
|
|
98350
98639
|
return [];
|
|
98351
98640
|
}
|
|
98352
|
-
calls.push(...vesuCalls);
|
|
98353
|
-
} catch (err2) {
|
|
98354
|
-
logger2.error(`Failed moving assets to vault: ${err2}`);
|
|
98355
98641
|
}
|
|
98356
98642
|
}
|
|
98357
98643
|
return calls;
|
|
@@ -98362,6 +98648,38 @@ spurious results.`);
|
|
|
98362
98648
|
}
|
|
98363
98649
|
async moveAssets(params, extendedAdapter, vesuAdapter) {
|
|
98364
98650
|
try {
|
|
98651
|
+
if (params.amount.lessThanOrEqualTo(0)) {
|
|
98652
|
+
logger2.error(
|
|
98653
|
+
`Invalid amount for moveAssets: ${params.amount.toNumber()}. Amount must be positive.`
|
|
98654
|
+
);
|
|
98655
|
+
return {
|
|
98656
|
+
calls: [],
|
|
98657
|
+
status: false
|
|
98658
|
+
};
|
|
98659
|
+
}
|
|
98660
|
+
const amountAbs = params.amount.abs();
|
|
98661
|
+
if (params.from === Protocols.EXTENDED.name || params.to === Protocols.EXTENDED.name) {
|
|
98662
|
+
if (amountAbs.lessThanOrEqualTo(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
98663
|
+
logger2.warn(
|
|
98664
|
+
`Amount ${amountAbs.toNumber()} is below minimum Extended movement amount ${extendedAdapter.minimumExtendedMovementAmount}. Skipping operation.`
|
|
98665
|
+
);
|
|
98666
|
+
return {
|
|
98667
|
+
calls: [],
|
|
98668
|
+
status: false
|
|
98669
|
+
};
|
|
98670
|
+
}
|
|
98671
|
+
}
|
|
98672
|
+
if (params.from === Protocols.VESU.name || params.to === Protocols.VESU.name) {
|
|
98673
|
+
if (amountAbs.lessThanOrEqualTo(vesuAdapter.minimumVesuMovementAmount)) {
|
|
98674
|
+
logger2.warn(
|
|
98675
|
+
`Amount ${amountAbs.toNumber()} is below minimum Vesu movement amount ${vesuAdapter.minimumVesuMovementAmount}. Skipping operation.`
|
|
98676
|
+
);
|
|
98677
|
+
return {
|
|
98678
|
+
calls: [],
|
|
98679
|
+
status: false
|
|
98680
|
+
};
|
|
98681
|
+
}
|
|
98682
|
+
}
|
|
98365
98683
|
const avnuAdapter = await this.getAvnuAdapter();
|
|
98366
98684
|
if (!avnuAdapter) {
|
|
98367
98685
|
logger2.error(`avnu adapter not found: ${avnuAdapter}`);
|
|
@@ -98422,12 +98740,13 @@ spurious results.`);
|
|
|
98422
98740
|
);
|
|
98423
98741
|
if (!openLongPosition) {
|
|
98424
98742
|
logger2.error(`error opening long position: ${openLongPosition}`);
|
|
98425
|
-
return {
|
|
98426
|
-
calls: [],
|
|
98427
|
-
status: false
|
|
98428
|
-
};
|
|
98429
98743
|
}
|
|
98430
98744
|
await new Promise((resolve) => setTimeout(resolve, 5e3));
|
|
98745
|
+
const updatedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
98746
|
+
if (!updatedHoldings || new Web3Number(updatedHoldings.availableForWithdrawal, USDC_TOKEN_DECIMALS).lessThan(params.amount.abs())) {
|
|
98747
|
+
logger2.error(`Insufficient balance after opening position. Available: ${updatedHoldings?.availableForWithdrawal}, Needed: ${params.amount.abs()}`);
|
|
98748
|
+
return { calls: [], status: false };
|
|
98749
|
+
}
|
|
98431
98750
|
}
|
|
98432
98751
|
const withdrawalFromExtended = await extendedAdapter.withdrawFromExtended(params.amount);
|
|
98433
98752
|
if (withdrawalFromExtended) {
|