@strkfarm/sdk 2.0.0-dev.7 → 2.0.0-dev.9
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 +509 -122
- package/dist/index.browser.mjs +509 -122
- package/dist/index.d.ts +2 -1
- package/dist/index.js +509 -122
- package/dist/index.mjs +509 -122
- package/package.json +1 -1
- package/src/strategies/universal-adapters/avnu-adapter.ts +2 -3
- package/src/strategies/universal-adapters/extended-adapter.ts +312 -85
- package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +285 -52
|
@@ -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;
|
|
93950
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;
|
|
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) {
|
|
@@ -94195,32 +94315,101 @@ spurious results.`);
|
|
|
94195
94315
|
}
|
|
94196
94316
|
}
|
|
94197
94317
|
async getDepositOrWithdrawalStatus(orderId, operationsType) {
|
|
94198
|
-
|
|
94199
|
-
|
|
94200
|
-
|
|
94201
|
-
|
|
94202
|
-
|
|
94203
|
-
|
|
94204
|
-
|
|
94205
|
-
|
|
94206
|
-
)
|
|
94207
|
-
|
|
94208
|
-
|
|
94318
|
+
const maxAttempts = 5;
|
|
94319
|
+
const retryDelayMs = 3e4;
|
|
94320
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
94321
|
+
try {
|
|
94322
|
+
let transferHistory = await this.client.getAssetOperations({
|
|
94323
|
+
operationsType: [operationsType],
|
|
94324
|
+
operationsStatus: ["COMPLETED" /* COMPLETED */]
|
|
94325
|
+
});
|
|
94326
|
+
if (operationsType === "DEPOSIT" /* DEPOSIT */) {
|
|
94327
|
+
const myTransferStatus = transferHistory.data.find(
|
|
94328
|
+
(operation) => operation.transactionHash === orderId
|
|
94329
|
+
);
|
|
94330
|
+
if (!myTransferStatus) {
|
|
94331
|
+
if (attempt < maxAttempts) {
|
|
94332
|
+
logger2.info(
|
|
94333
|
+
`Deposit operation not found for transactionHash ${orderId}, retrying (attempt ${attempt}/${maxAttempts})...`
|
|
94334
|
+
);
|
|
94335
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
94336
|
+
continue;
|
|
94337
|
+
}
|
|
94338
|
+
logger2.warn(
|
|
94339
|
+
`Deposit operation not found for transactionHash ${orderId} after ${maxAttempts} attempts`
|
|
94340
|
+
);
|
|
94341
|
+
return false;
|
|
94342
|
+
}
|
|
94343
|
+
if (myTransferStatus.status === "COMPLETED" /* COMPLETED */) {
|
|
94344
|
+
logger2.info(
|
|
94345
|
+
`Deposit operation ${orderId} completed successfully`
|
|
94346
|
+
);
|
|
94347
|
+
return true;
|
|
94348
|
+
} else {
|
|
94349
|
+
if (attempt < maxAttempts) {
|
|
94350
|
+
logger2.info(
|
|
94351
|
+
`Deposit operation ${orderId} found but status is ${myTransferStatus.status}, not COMPLETED. Retrying (attempt ${attempt}/${maxAttempts})...`
|
|
94352
|
+
);
|
|
94353
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
94354
|
+
continue;
|
|
94355
|
+
}
|
|
94356
|
+
logger2.warn(
|
|
94357
|
+
`Deposit operation ${orderId} status is ${myTransferStatus.status} after ${maxAttempts} attempts, expected COMPLETED`
|
|
94358
|
+
);
|
|
94359
|
+
return false;
|
|
94360
|
+
}
|
|
94361
|
+
} else {
|
|
94362
|
+
const myTransferStatus = transferHistory.data.find(
|
|
94363
|
+
(operation) => operation.id.toString() === orderId.toString()
|
|
94364
|
+
);
|
|
94365
|
+
if (!myTransferStatus) {
|
|
94366
|
+
if (attempt < maxAttempts) {
|
|
94367
|
+
logger2.info(
|
|
94368
|
+
`Withdrawal status not found for orderId ${orderId} in completed operations, retrying (attempt ${attempt}/${maxAttempts})...`
|
|
94369
|
+
);
|
|
94370
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
94371
|
+
continue;
|
|
94372
|
+
}
|
|
94373
|
+
logger2.warn(
|
|
94374
|
+
`Withdrawal operation not found for orderId ${orderId} after ${maxAttempts} attempts`
|
|
94375
|
+
);
|
|
94376
|
+
return false;
|
|
94377
|
+
}
|
|
94378
|
+
if (myTransferStatus.status === "COMPLETED" /* COMPLETED */) {
|
|
94379
|
+
logger2.info(
|
|
94380
|
+
`Withdrawal operation ${orderId} completed successfully`
|
|
94381
|
+
);
|
|
94382
|
+
return true;
|
|
94383
|
+
} else {
|
|
94384
|
+
if (attempt < maxAttempts) {
|
|
94385
|
+
logger2.info(
|
|
94386
|
+
`Withdrawal operation ${orderId} found but status is ${myTransferStatus.status}, not COMPLETED. Retrying (attempt ${attempt}/${maxAttempts})...`
|
|
94387
|
+
);
|
|
94388
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
94389
|
+
continue;
|
|
94390
|
+
}
|
|
94391
|
+
logger2.warn(
|
|
94392
|
+
`Withdrawal operation ${orderId} status is ${myTransferStatus.status} after ${maxAttempts} attempts, expected COMPLETED`
|
|
94393
|
+
);
|
|
94394
|
+
return false;
|
|
94395
|
+
}
|
|
94209
94396
|
}
|
|
94210
|
-
|
|
94211
|
-
|
|
94212
|
-
|
|
94213
|
-
(operation) => operation.id.toString() === orderId.toString()
|
|
94397
|
+
} catch (err2) {
|
|
94398
|
+
logger2.error(
|
|
94399
|
+
`error getting deposit or withdrawal status (attempt ${attempt}/${maxAttempts}): ${err2}`
|
|
94214
94400
|
);
|
|
94215
|
-
if (
|
|
94216
|
-
|
|
94401
|
+
if (attempt < maxAttempts) {
|
|
94402
|
+
logger2.info(`Retrying after ${retryDelayMs}ms...`);
|
|
94403
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
94404
|
+
continue;
|
|
94217
94405
|
}
|
|
94218
|
-
|
|
94406
|
+
logger2.error(
|
|
94407
|
+
`Max retry attempts reached for getDepositOrWithdrawalStatus`
|
|
94408
|
+
);
|
|
94409
|
+
return false;
|
|
94219
94410
|
}
|
|
94220
|
-
} catch (err2) {
|
|
94221
|
-
logger2.error(`error getting deposit or withdrawal status: ${err2}`);
|
|
94222
|
-
return false;
|
|
94223
94411
|
}
|
|
94412
|
+
return false;
|
|
94224
94413
|
}
|
|
94225
94414
|
};
|
|
94226
94415
|
|
|
@@ -98165,11 +98354,27 @@ spurious results.`);
|
|
|
98165
98354
|
}
|
|
98166
98355
|
async shouldInvest() {
|
|
98167
98356
|
try {
|
|
98357
|
+
logger2.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest starting`);
|
|
98168
98358
|
const vesuAdapter = await this.getVesuAdapter();
|
|
98169
98359
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
98170
|
-
|
|
98360
|
+
logger2.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest adapters fetched: vesuAdapter=${!!vesuAdapter}, extendedAdapter=${!!extendedAdapter}, extendedAdapter.client=${!!extendedAdapter?.client}`);
|
|
98361
|
+
if (!vesuAdapter) {
|
|
98171
98362
|
logger2.error(
|
|
98172
|
-
`
|
|
98363
|
+
`Vesu adapter not configured in metadata. This is a configuration issue, not a temporary failure.`
|
|
98364
|
+
);
|
|
98365
|
+
return {
|
|
98366
|
+
shouldInvest: false,
|
|
98367
|
+
vesuAmount: new Web3Number(0, 0),
|
|
98368
|
+
extendedAmount: new Web3Number(0, 0),
|
|
98369
|
+
extendedLeverage: 0,
|
|
98370
|
+
collateralPrice: 0,
|
|
98371
|
+
debtPrice: 0,
|
|
98372
|
+
vesuLeverage: 0
|
|
98373
|
+
};
|
|
98374
|
+
}
|
|
98375
|
+
if (!extendedAdapter) {
|
|
98376
|
+
logger2.error(
|
|
98377
|
+
`Extended adapter not configured in metadata. This is a configuration issue, not a temporary failure.`
|
|
98173
98378
|
);
|
|
98174
98379
|
return {
|
|
98175
98380
|
shouldInvest: false,
|
|
@@ -98181,10 +98386,72 @@ spurious results.`);
|
|
|
98181
98386
|
vesuLeverage: 0
|
|
98182
98387
|
};
|
|
98183
98388
|
}
|
|
98389
|
+
if (!extendedAdapter.client) {
|
|
98390
|
+
logger2.error(
|
|
98391
|
+
`Extended adapter client not initialized. This may be a temporary initialization failure - check network connectivity and API availability.`
|
|
98392
|
+
);
|
|
98393
|
+
return {
|
|
98394
|
+
shouldInvest: false,
|
|
98395
|
+
vesuAmount: new Web3Number(0, 0),
|
|
98396
|
+
extendedAmount: new Web3Number(0, 0),
|
|
98397
|
+
extendedLeverage: 0,
|
|
98398
|
+
collateralPrice: 0,
|
|
98399
|
+
debtPrice: 0,
|
|
98400
|
+
vesuLeverage: 0
|
|
98401
|
+
};
|
|
98402
|
+
}
|
|
98403
|
+
logger2.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest calling getUnusedBalance`);
|
|
98184
98404
|
const balance = await this.getUnusedBalance();
|
|
98405
|
+
if (!Number.isFinite(balance.usdValue) || balance.usdValue < 0) {
|
|
98406
|
+
logger2.error(
|
|
98407
|
+
`Invalid balance.usdValue: ${balance.usdValue}. Expected a finite, non-negative number.`
|
|
98408
|
+
);
|
|
98409
|
+
return {
|
|
98410
|
+
shouldInvest: false,
|
|
98411
|
+
vesuAmount: new Web3Number(0, 0),
|
|
98412
|
+
extendedAmount: new Web3Number(0, 0),
|
|
98413
|
+
extendedLeverage: 0,
|
|
98414
|
+
collateralPrice: 0,
|
|
98415
|
+
debtPrice: 0,
|
|
98416
|
+
vesuLeverage: 0
|
|
98417
|
+
};
|
|
98418
|
+
}
|
|
98419
|
+
logger2.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest balance: ${balance.usdValue}`);
|
|
98185
98420
|
const usdcBalanceOnExtended = await extendedAdapter.getExtendedDepositAmount();
|
|
98421
|
+
if (usdcBalanceOnExtended) {
|
|
98422
|
+
const availableForWithdrawal = parseFloat(usdcBalanceOnExtended.availableForWithdrawal);
|
|
98423
|
+
if (!Number.isFinite(availableForWithdrawal) || availableForWithdrawal < 0) {
|
|
98424
|
+
logger2.error(
|
|
98425
|
+
`Invalid usdcBalanceOnExtended.availableForWithdrawal: ${usdcBalanceOnExtended.availableForWithdrawal}. Expected a finite, non-negative number.`
|
|
98426
|
+
);
|
|
98427
|
+
return {
|
|
98428
|
+
shouldInvest: false,
|
|
98429
|
+
vesuAmount: new Web3Number(0, 0),
|
|
98430
|
+
extendedAmount: new Web3Number(0, 0),
|
|
98431
|
+
extendedLeverage: 0,
|
|
98432
|
+
collateralPrice: 0,
|
|
98433
|
+
debtPrice: 0,
|
|
98434
|
+
vesuLeverage: 0
|
|
98435
|
+
};
|
|
98436
|
+
}
|
|
98437
|
+
}
|
|
98186
98438
|
const amountToInvest = new Web3Number(balance.usdValue, USDC_TOKEN_DECIMALS).plus(usdcBalanceOnExtended?.availableForWithdrawal ?? 0).multipliedBy(1 - LIMIT_BALANCE);
|
|
98187
|
-
|
|
98439
|
+
const amountToInvestNumber = amountToInvest.toNumber();
|
|
98440
|
+
if (!Number.isFinite(amountToInvestNumber)) {
|
|
98441
|
+
logger2.error(
|
|
98442
|
+
`Invalid amountToInvest calculation result: ${amountToInvestNumber}. Calculation may have produced NaN or Infinity.`
|
|
98443
|
+
);
|
|
98444
|
+
return {
|
|
98445
|
+
shouldInvest: false,
|
|
98446
|
+
vesuAmount: new Web3Number(0, 0),
|
|
98447
|
+
extendedAmount: new Web3Number(0, 0),
|
|
98448
|
+
extendedLeverage: 0,
|
|
98449
|
+
collateralPrice: 0,
|
|
98450
|
+
debtPrice: 0,
|
|
98451
|
+
vesuLeverage: 0
|
|
98452
|
+
};
|
|
98453
|
+
}
|
|
98454
|
+
logger2.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest amountToInvest: ${amountToInvestNumber}`);
|
|
98188
98455
|
if (amountToInvest.lessThan(0)) {
|
|
98189
98456
|
return {
|
|
98190
98457
|
shouldInvest: false,
|
|
@@ -98214,6 +98481,34 @@ spurious results.`);
|
|
|
98214
98481
|
collateralPrice,
|
|
98215
98482
|
debtPrice
|
|
98216
98483
|
} = await this.getAssetPrices();
|
|
98484
|
+
if (!Number.isFinite(collateralPrice.price) || collateralPrice.price <= 0) {
|
|
98485
|
+
logger2.error(
|
|
98486
|
+
`Invalid collateralPrice: ${collateralPrice.price}. Expected a finite, positive number.`
|
|
98487
|
+
);
|
|
98488
|
+
return {
|
|
98489
|
+
shouldInvest: false,
|
|
98490
|
+
vesuAmount: new Web3Number(0, 0),
|
|
98491
|
+
extendedAmount: new Web3Number(0, 0),
|
|
98492
|
+
extendedLeverage: 0,
|
|
98493
|
+
collateralPrice: 0,
|
|
98494
|
+
debtPrice: 0,
|
|
98495
|
+
vesuLeverage: 0
|
|
98496
|
+
};
|
|
98497
|
+
}
|
|
98498
|
+
if (!Number.isFinite(debtPrice.price) || debtPrice.price <= 0) {
|
|
98499
|
+
logger2.error(
|
|
98500
|
+
`Invalid debtPrice: ${debtPrice.price}. Expected a finite, positive number.`
|
|
98501
|
+
);
|
|
98502
|
+
return {
|
|
98503
|
+
shouldInvest: false,
|
|
98504
|
+
vesuAmount: new Web3Number(0, 0),
|
|
98505
|
+
extendedAmount: new Web3Number(0, 0),
|
|
98506
|
+
extendedLeverage: 0,
|
|
98507
|
+
collateralPrice: 0,
|
|
98508
|
+
debtPrice: 0,
|
|
98509
|
+
vesuLeverage: 0
|
|
98510
|
+
};
|
|
98511
|
+
}
|
|
98217
98512
|
const { vesu_amount, extended_amount, extended_leverage, vesu_leverage } = await calculateAmountDistribution(
|
|
98218
98513
|
amountToInvest.toNumber(),
|
|
98219
98514
|
extendedAdapter.client,
|
|
@@ -98264,13 +98559,45 @@ spurious results.`);
|
|
|
98264
98559
|
try {
|
|
98265
98560
|
const vesuAdapter = await this.getVesuAdapter();
|
|
98266
98561
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
98267
|
-
let calls = [];
|
|
98268
98562
|
if (!vesuAdapter || !extendedAdapter || !extendedAdapter.client) {
|
|
98269
98563
|
logger2.error(
|
|
98270
98564
|
`vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
|
|
98271
98565
|
);
|
|
98272
|
-
return
|
|
98566
|
+
return [];
|
|
98567
|
+
}
|
|
98568
|
+
const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
98569
|
+
if (!extendedHoldings) {
|
|
98570
|
+
logger2.error(`error getting extended holdings: ${extendedHoldings}`);
|
|
98571
|
+
return [];
|
|
98273
98572
|
}
|
|
98573
|
+
const usdcAmountInWallet = (await this.getUnusedBalance()).amount;
|
|
98574
|
+
const usdcAmountOnExtendedAvailableForWithdrawal = parseFloat(
|
|
98575
|
+
extendedHoldings.availableForWithdrawal
|
|
98576
|
+
);
|
|
98577
|
+
logger2.info(`${_VesuExtendedMultiplierStrategy.name}::shouldMoveAssets calculating movements - Extended current: ${usdcAmountOnExtendedAvailableForWithdrawal}, Wallet: ${usdcAmountInWallet.toNumber()}, Target Extended: ${extendedAmount.toNumber()}, Target Vesu: ${vesuAmount.toNumber()}`);
|
|
98578
|
+
let totalExtendedWithdrawal = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
98579
|
+
let totalExtendedDeposit = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
98580
|
+
if (extendedAmount.isNegative() && extendedAmount.abs().greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
98581
|
+
totalExtendedWithdrawal = totalExtendedWithdrawal.plus(extendedAmount.abs());
|
|
98582
|
+
}
|
|
98583
|
+
const extendedTargetAmount = extendedAmount.abs();
|
|
98584
|
+
let projectedExtendedBalance = usdcAmountOnExtendedAvailableForWithdrawal;
|
|
98585
|
+
if (extendedAmount.isNegative()) {
|
|
98586
|
+
projectedExtendedBalance = projectedExtendedBalance - extendedAmount.abs().toNumber();
|
|
98587
|
+
}
|
|
98588
|
+
const extendedAmountDifference = extendedTargetAmount.minus(projectedExtendedBalance);
|
|
98589
|
+
const extendedAmountDifferenceAbs = extendedAmountDifference.abs();
|
|
98590
|
+
if (extendedAmountDifference.lessThan(0)) {
|
|
98591
|
+
totalExtendedWithdrawal = totalExtendedWithdrawal.plus(extendedAmountDifferenceAbs);
|
|
98592
|
+
} else if (extendedAmountDifference.greaterThan(0)) {
|
|
98593
|
+
totalExtendedDeposit = totalExtendedDeposit.plus(extendedAmountDifference);
|
|
98594
|
+
}
|
|
98595
|
+
const vesuTargetAmount = vesuAmount.abs();
|
|
98596
|
+
const projectedWalletBalance = usdcAmountInWallet.plus(totalExtendedWithdrawal).minus(totalExtendedDeposit);
|
|
98597
|
+
let vesuAmountDifference = vesuTargetAmount.minus(projectedWalletBalance);
|
|
98598
|
+
const vesuAmountDifferenceAbs = vesuAmountDifference.abs();
|
|
98599
|
+
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()}`);
|
|
98600
|
+
let calls = [];
|
|
98274
98601
|
if (extendedAmount.isNegative() && extendedAmount.abs().greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
98275
98602
|
try {
|
|
98276
98603
|
const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
|
|
@@ -98291,7 +98618,7 @@ spurious results.`);
|
|
|
98291
98618
|
logger2.error(`Failed moving assets to vault: ${err2}`);
|
|
98292
98619
|
}
|
|
98293
98620
|
}
|
|
98294
|
-
if (vesuAmount.isNegative() && vesuAmount.
|
|
98621
|
+
if (vesuAmount.isNegative() && vesuAmount.abs().greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
|
|
98295
98622
|
try {
|
|
98296
98623
|
const { calls: vesuCalls, status: vesuStatus } = await this.moveAssets(
|
|
98297
98624
|
{
|
|
@@ -98310,48 +98637,76 @@ spurious results.`);
|
|
|
98310
98637
|
logger2.error(`Failed moving assets to vault: ${err2}`);
|
|
98311
98638
|
}
|
|
98312
98639
|
}
|
|
98313
|
-
|
|
98314
|
-
|
|
98315
|
-
|
|
98316
|
-
|
|
98317
|
-
|
|
98318
|
-
|
|
98319
|
-
|
|
98320
|
-
|
|
98321
|
-
|
|
98322
|
-
|
|
98323
|
-
|
|
98324
|
-
|
|
98325
|
-
{
|
|
98326
|
-
|
|
98327
|
-
|
|
98328
|
-
|
|
98329
|
-
|
|
98330
|
-
|
|
98331
|
-
|
|
98332
|
-
|
|
98333
|
-
|
|
98334
|
-
|
|
98335
|
-
|
|
98640
|
+
if (extendedAmountDifferenceAbs.greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
98641
|
+
if (extendedAmountDifference.greaterThan(0)) {
|
|
98642
|
+
try {
|
|
98643
|
+
const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
|
|
98644
|
+
{
|
|
98645
|
+
to: Protocols.EXTENDED.name,
|
|
98646
|
+
from: Protocols.VAULT.name,
|
|
98647
|
+
amount: extendedAmountDifference
|
|
98648
|
+
},
|
|
98649
|
+
extendedAdapter,
|
|
98650
|
+
vesuAdapter
|
|
98651
|
+
);
|
|
98652
|
+
if (extendedStatus) {
|
|
98653
|
+
calls.push(...extendedCalls);
|
|
98654
|
+
} else {
|
|
98655
|
+
logger2.error(`Failed to move assets to extended - operation returned false status`);
|
|
98656
|
+
return [];
|
|
98657
|
+
}
|
|
98658
|
+
} catch (err2) {
|
|
98659
|
+
logger2.error(`Failed moving assets to extended: ${err2}`);
|
|
98660
|
+
return [];
|
|
98661
|
+
}
|
|
98662
|
+
} else if (extendedAmountDifference.lessThan(0)) {
|
|
98663
|
+
try {
|
|
98664
|
+
const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
|
|
98665
|
+
{
|
|
98666
|
+
to: Protocols.VAULT.name,
|
|
98667
|
+
from: Protocols.EXTENDED.name,
|
|
98668
|
+
amount: extendedAmountDifferenceAbs
|
|
98669
|
+
},
|
|
98670
|
+
extendedAdapter,
|
|
98671
|
+
vesuAdapter
|
|
98672
|
+
);
|
|
98673
|
+
if (extendedStatus) {
|
|
98674
|
+
calls.push(...extendedCalls);
|
|
98675
|
+
} else {
|
|
98676
|
+
logger2.error(`Failed to withdraw from extended - operation returned false status`);
|
|
98677
|
+
return [];
|
|
98678
|
+
}
|
|
98679
|
+
} catch (err2) {
|
|
98680
|
+
logger2.error(`Failed moving assets from extended to vault: ${err2}`);
|
|
98681
|
+
return [];
|
|
98682
|
+
}
|
|
98336
98683
|
}
|
|
98337
98684
|
}
|
|
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
|
|
98685
|
+
if (vesuAmountDifferenceAbs.greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
|
|
98686
|
+
if (vesuAmountDifference.lessThanOrEqualTo(0)) {
|
|
98687
|
+
logger2.warn(
|
|
98688
|
+
`Vesu amount difference is negative or zero: ${vesuAmountDifference.toNumber()}. Skipping operation.`
|
|
98348
98689
|
);
|
|
98349
|
-
|
|
98690
|
+
} else {
|
|
98691
|
+
try {
|
|
98692
|
+
const { calls: vesuCalls, status: vesuStatus } = await this.moveAssets(
|
|
98693
|
+
{
|
|
98694
|
+
to: Protocols.VAULT.name,
|
|
98695
|
+
from: Protocols.EXTENDED.name,
|
|
98696
|
+
amount: vesuAmountDifference
|
|
98697
|
+
},
|
|
98698
|
+
extendedAdapter,
|
|
98699
|
+
vesuAdapter
|
|
98700
|
+
);
|
|
98701
|
+
if (!vesuStatus) {
|
|
98702
|
+
logger2.error(`Failed to move assets to vesu - operation returned false status`);
|
|
98703
|
+
return [];
|
|
98704
|
+
}
|
|
98705
|
+
calls.push(...vesuCalls);
|
|
98706
|
+
} catch (err2) {
|
|
98707
|
+
logger2.error(`Failed moving assets to vault: ${err2}`);
|
|
98350
98708
|
return [];
|
|
98351
98709
|
}
|
|
98352
|
-
calls.push(...vesuCalls);
|
|
98353
|
-
} catch (err2) {
|
|
98354
|
-
logger2.error(`Failed moving assets to vault: ${err2}`);
|
|
98355
98710
|
}
|
|
98356
98711
|
}
|
|
98357
98712
|
return calls;
|
|
@@ -98362,6 +98717,38 @@ spurious results.`);
|
|
|
98362
98717
|
}
|
|
98363
98718
|
async moveAssets(params, extendedAdapter, vesuAdapter) {
|
|
98364
98719
|
try {
|
|
98720
|
+
if (params.amount.lessThanOrEqualTo(0)) {
|
|
98721
|
+
logger2.error(
|
|
98722
|
+
`Invalid amount for moveAssets: ${params.amount.toNumber()}. Amount must be positive.`
|
|
98723
|
+
);
|
|
98724
|
+
return {
|
|
98725
|
+
calls: [],
|
|
98726
|
+
status: false
|
|
98727
|
+
};
|
|
98728
|
+
}
|
|
98729
|
+
const amountAbs = params.amount.abs();
|
|
98730
|
+
if (params.from === Protocols.EXTENDED.name || params.to === Protocols.EXTENDED.name) {
|
|
98731
|
+
if (amountAbs.lessThanOrEqualTo(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
98732
|
+
logger2.warn(
|
|
98733
|
+
`Amount ${amountAbs.toNumber()} is below minimum Extended movement amount ${extendedAdapter.minimumExtendedMovementAmount}. Skipping operation.`
|
|
98734
|
+
);
|
|
98735
|
+
return {
|
|
98736
|
+
calls: [],
|
|
98737
|
+
status: false
|
|
98738
|
+
};
|
|
98739
|
+
}
|
|
98740
|
+
}
|
|
98741
|
+
if (params.from === Protocols.VESU.name || params.to === Protocols.VESU.name) {
|
|
98742
|
+
if (amountAbs.lessThanOrEqualTo(vesuAdapter.minimumVesuMovementAmount)) {
|
|
98743
|
+
logger2.warn(
|
|
98744
|
+
`Amount ${amountAbs.toNumber()} is below minimum Vesu movement amount ${vesuAdapter.minimumVesuMovementAmount}. Skipping operation.`
|
|
98745
|
+
);
|
|
98746
|
+
return {
|
|
98747
|
+
calls: [],
|
|
98748
|
+
status: false
|
|
98749
|
+
};
|
|
98750
|
+
}
|
|
98751
|
+
}
|
|
98365
98752
|
const avnuAdapter = await this.getAvnuAdapter();
|
|
98366
98753
|
if (!avnuAdapter) {
|
|
98367
98754
|
logger2.error(`avnu adapter not found: ${avnuAdapter}`);
|
|
@@ -98422,18 +98809,18 @@ spurious results.`);
|
|
|
98422
98809
|
);
|
|
98423
98810
|
if (!openLongPosition) {
|
|
98424
98811
|
logger2.error(`error opening long position: ${openLongPosition}`);
|
|
98425
|
-
return {
|
|
98426
|
-
calls: [],
|
|
98427
|
-
status: false
|
|
98428
|
-
};
|
|
98429
98812
|
}
|
|
98430
|
-
|
|
98813
|
+
const updatedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
98814
|
+
if (!updatedHoldings || new Web3Number(updatedHoldings.availableForWithdrawal, USDC_TOKEN_DECIMALS).lessThan(params.amount.abs())) {
|
|
98815
|
+
logger2.error(`Insufficient balance after opening position. Available: ${updatedHoldings?.availableForWithdrawal}, Needed: ${params.amount.abs()}`);
|
|
98816
|
+
return { calls: [], status: false };
|
|
98817
|
+
}
|
|
98431
98818
|
}
|
|
98432
98819
|
const withdrawalFromExtended = await extendedAdapter.withdrawFromExtended(params.amount);
|
|
98433
98820
|
if (withdrawalFromExtended) {
|
|
98434
98821
|
const extendedHoldings2 = await extendedAdapter.getExtendedDepositAmount();
|
|
98435
98822
|
logger2.info(`extendedHoldings after withdrawal ${extendedHoldings2?.availableForWithdrawal}`);
|
|
98436
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
98823
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
98437
98824
|
const calls = await this.moveAssetsToVaultAllocator(params.amount, extendedAdapter);
|
|
98438
98825
|
if (calls.length > 0) {
|
|
98439
98826
|
return {
|