@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
package/dist/index.mjs
CHANGED
|
@@ -29930,8 +29930,47 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29930
29930
|
async withdrawFromExtended(amount) {
|
|
29931
29931
|
try {
|
|
29932
29932
|
if (!this.client) {
|
|
29933
|
-
|
|
29933
|
+
logger.error("Client not initialized");
|
|
29934
|
+
return false;
|
|
29935
|
+
}
|
|
29936
|
+
if (amount.lessThanOrEqualTo(0)) {
|
|
29937
|
+
logger.error(
|
|
29938
|
+
`Invalid withdrawal amount: ${amount.toNumber()}. Amount must be positive.`
|
|
29939
|
+
);
|
|
29940
|
+
return false;
|
|
29941
|
+
}
|
|
29942
|
+
if (amount.lessThanOrEqualTo(this.minimumExtendedMovementAmount)) {
|
|
29943
|
+
logger.warn(
|
|
29944
|
+
`Withdrawal amount ${amount.toNumber()} is below minimum Extended movement amount ${this.minimumExtendedMovementAmount}. Skipping withdrawal.`
|
|
29945
|
+
);
|
|
29946
|
+
return false;
|
|
29947
|
+
}
|
|
29948
|
+
const holdings = await this.getExtendedDepositAmount();
|
|
29949
|
+
if (!holdings) {
|
|
29950
|
+
logger.error(
|
|
29951
|
+
"Cannot get holdings - unable to validate withdrawal amount"
|
|
29952
|
+
);
|
|
29953
|
+
return false;
|
|
29934
29954
|
}
|
|
29955
|
+
const availableForWithdrawal = parseFloat(
|
|
29956
|
+
holdings.availableForWithdrawal
|
|
29957
|
+
);
|
|
29958
|
+
if (!Number.isFinite(availableForWithdrawal) || availableForWithdrawal < 0) {
|
|
29959
|
+
logger.error(
|
|
29960
|
+
`Invalid availableForWithdrawal: ${holdings.availableForWithdrawal}. Expected a finite, non-negative number.`
|
|
29961
|
+
);
|
|
29962
|
+
return false;
|
|
29963
|
+
}
|
|
29964
|
+
const withdrawalAmount = amount.toNumber();
|
|
29965
|
+
if (withdrawalAmount > availableForWithdrawal) {
|
|
29966
|
+
logger.error(
|
|
29967
|
+
`Withdrawal amount ${withdrawalAmount} exceeds available balance ${availableForWithdrawal}`
|
|
29968
|
+
);
|
|
29969
|
+
return false;
|
|
29970
|
+
}
|
|
29971
|
+
logger.info(
|
|
29972
|
+
`Withdrawing ${withdrawalAmount} from Extended. Available balance: ${availableForWithdrawal}`
|
|
29973
|
+
);
|
|
29935
29974
|
const withdrawalRequest = await this.client.withdrawUSDC(
|
|
29936
29975
|
amount.toFixed(2)
|
|
29937
29976
|
);
|
|
@@ -29942,6 +29981,9 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29942
29981
|
);
|
|
29943
29982
|
return withdrawalStatus;
|
|
29944
29983
|
}
|
|
29984
|
+
logger.error(
|
|
29985
|
+
`Withdrawal request failed with status: ${withdrawalRequest.status}`
|
|
29986
|
+
);
|
|
29945
29987
|
return false;
|
|
29946
29988
|
} catch (error) {
|
|
29947
29989
|
logger.error(`Error creating Withdraw Call: ${error}`);
|
|
@@ -29952,21 +29994,44 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
29952
29994
|
return Promise.resolve(1);
|
|
29953
29995
|
}
|
|
29954
29996
|
async getExtendedDepositAmount() {
|
|
29955
|
-
|
|
29956
|
-
|
|
29957
|
-
|
|
29958
|
-
|
|
29959
|
-
|
|
29960
|
-
|
|
29961
|
-
|
|
29962
|
-
|
|
29963
|
-
|
|
29964
|
-
|
|
29965
|
-
|
|
29966
|
-
|
|
29997
|
+
try {
|
|
29998
|
+
if (this.client === null) {
|
|
29999
|
+
logger.error("error initializing client - client is null");
|
|
30000
|
+
return void 0;
|
|
30001
|
+
}
|
|
30002
|
+
const result = await this.client.getHoldings();
|
|
30003
|
+
if (!result) {
|
|
30004
|
+
logger.error("error getting holdings - API returned null/undefined");
|
|
30005
|
+
return void 0;
|
|
30006
|
+
}
|
|
30007
|
+
if (result.status && result.status !== "OK") {
|
|
30008
|
+
logger.error(
|
|
30009
|
+
`error getting holdings - API returned status: ${result.status}`
|
|
30010
|
+
);
|
|
30011
|
+
return void 0;
|
|
30012
|
+
}
|
|
30013
|
+
const holdings = result.data;
|
|
30014
|
+
if (!holdings) {
|
|
30015
|
+
logger.warn(
|
|
30016
|
+
"holdings data is null/undefined - treating as zero balance"
|
|
30017
|
+
);
|
|
30018
|
+
return {
|
|
30019
|
+
collateral_name: "",
|
|
30020
|
+
balance: "0",
|
|
30021
|
+
equity: "0",
|
|
30022
|
+
availableForTrade: "0",
|
|
30023
|
+
availableForWithdrawal: "0",
|
|
30024
|
+
unrealisedPnl: "0",
|
|
30025
|
+
initialMargin: "0",
|
|
30026
|
+
marginRatio: "0",
|
|
30027
|
+
updatedTime: Date.now()
|
|
30028
|
+
};
|
|
30029
|
+
}
|
|
30030
|
+
return holdings;
|
|
30031
|
+
} catch (error) {
|
|
30032
|
+
logger.error(`error getting holdings - exception: ${error}`);
|
|
29967
30033
|
return void 0;
|
|
29968
30034
|
}
|
|
29969
|
-
return holdings;
|
|
29970
30035
|
}
|
|
29971
30036
|
async setLeverage(leverage, marketName) {
|
|
29972
30037
|
if (this.client === null) {
|
|
@@ -30008,38 +30073,24 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
30008
30073
|
return result.data;
|
|
30009
30074
|
}
|
|
30010
30075
|
async getOrderStatus(orderId, marketName) {
|
|
30011
|
-
|
|
30012
|
-
|
|
30013
|
-
|
|
30014
|
-
|
|
30015
|
-
let orderhistory = await this.getOrderHistory(marketName);
|
|
30016
|
-
if (!orderhistory || orderhistory.length === 0) {
|
|
30017
|
-
logger.error(`error getting order history: ${orderId}`);
|
|
30018
|
-
} else {
|
|
30019
|
-
const order = orderhistory.slice(0, 10).find((order2) => order2.id.toString() === orderId);
|
|
30020
|
-
if (order) {
|
|
30021
|
-
return order;
|
|
30076
|
+
try {
|
|
30077
|
+
if (this.client === null) {
|
|
30078
|
+
logger.error("error initializing client");
|
|
30079
|
+
return null;
|
|
30022
30080
|
}
|
|
30023
|
-
|
|
30024
|
-
for (let attempt = 1; attempt <= 5; attempt++) {
|
|
30025
|
-
await new Promise((resolve) => setTimeout(resolve, this.retryDelayForOrderStatus));
|
|
30026
|
-
orderhistory = await this.getOrderHistory(marketName);
|
|
30081
|
+
const orderhistory = await this.getOrderHistory(marketName);
|
|
30027
30082
|
if (!orderhistory || orderhistory.length === 0) {
|
|
30028
|
-
|
|
30029
|
-
`error getting order history on retry ${attempt}: ${orderId}`
|
|
30030
|
-
);
|
|
30031
|
-
continue;
|
|
30083
|
+
return null;
|
|
30032
30084
|
}
|
|
30033
|
-
const order = orderhistory.slice(0,
|
|
30034
|
-
if (order
|
|
30085
|
+
const order = orderhistory.slice(0, 20).find((order2) => order2.id.toString() === orderId);
|
|
30086
|
+
if (order) {
|
|
30035
30087
|
return order;
|
|
30036
30088
|
}
|
|
30037
|
-
|
|
30038
|
-
|
|
30039
|
-
);
|
|
30089
|
+
return null;
|
|
30090
|
+
} catch (error) {
|
|
30091
|
+
logger.error(`error getting order status: ${error}`);
|
|
30092
|
+
return null;
|
|
30040
30093
|
}
|
|
30041
|
-
logger.error(`error getting order after all retries: ${orderId}`);
|
|
30042
|
-
return null;
|
|
30043
30094
|
}
|
|
30044
30095
|
async fetchOrderBookBTCUSDC() {
|
|
30045
30096
|
try {
|
|
@@ -30090,14 +30141,40 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
30090
30141
|
logger.error("error depositing or setting leverage");
|
|
30091
30142
|
return null;
|
|
30092
30143
|
}
|
|
30093
|
-
const
|
|
30094
|
-
if (
|
|
30144
|
+
const { ask, bid } = await this.fetchOrderBookBTCUSDC();
|
|
30145
|
+
if (!ask || !bid || ask.lessThanOrEqualTo(0) || bid.lessThanOrEqualTo(0)) {
|
|
30146
|
+
logger.error(
|
|
30147
|
+
`Invalid orderbook prices: ask=${ask?.toNumber()}, bid=${bid?.toNumber()}`
|
|
30148
|
+
);
|
|
30095
30149
|
return null;
|
|
30096
30150
|
}
|
|
30097
|
-
const { ask, bid } = await this.fetchOrderBookBTCUSDC();
|
|
30098
30151
|
const spread = ask.minus(bid);
|
|
30099
|
-
|
|
30100
|
-
|
|
30152
|
+
const midPrice = ask.plus(bid).div(2);
|
|
30153
|
+
const MAX_PRICE_DEVIATION_MULTIPLIER = 0.5;
|
|
30154
|
+
const priceAdjustmentMultiplier = Math.min(
|
|
30155
|
+
0.2 * attempt,
|
|
30156
|
+
MAX_PRICE_DEVIATION_MULTIPLIER
|
|
30157
|
+
);
|
|
30158
|
+
const priceAdjustment = spread.times(priceAdjustmentMultiplier);
|
|
30159
|
+
let price = midPrice;
|
|
30160
|
+
if (side === "SELL" /* SELL */) {
|
|
30161
|
+
price = midPrice.minus(priceAdjustment);
|
|
30162
|
+
} else {
|
|
30163
|
+
price = midPrice.plus(priceAdjustment);
|
|
30164
|
+
}
|
|
30165
|
+
const maxDeviation = midPrice.times(0.5);
|
|
30166
|
+
if (price.minus(midPrice).abs().greaterThan(maxDeviation)) {
|
|
30167
|
+
logger.error(
|
|
30168
|
+
`Price deviation too large on attempt ${attempt}: price=${price.toNumber()}, midPrice=${midPrice.toNumber()}, deviation=${price.minus(midPrice).abs().toNumber()}`
|
|
30169
|
+
);
|
|
30170
|
+
if (attempt >= maxAttempts) {
|
|
30171
|
+
return null;
|
|
30172
|
+
}
|
|
30173
|
+
price = side === "SELL" /* SELL */ ? midPrice.minus(maxDeviation) : midPrice.plus(maxDeviation);
|
|
30174
|
+
}
|
|
30175
|
+
logger.info(
|
|
30176
|
+
`createOrder attempt ${attempt}/${maxAttempts}: side=${side}, midPrice=${midPrice.toNumber()}, adjustedPrice=${price.toNumber()}, adjustment=${priceAdjustmentMultiplier * 100}%`
|
|
30177
|
+
);
|
|
30101
30178
|
const amount_in_token = (btcAmount * parseInt(leverage)).toFixed(
|
|
30102
30179
|
this.config.extendedPrecision
|
|
30103
30180
|
);
|
|
@@ -30108,17 +30185,57 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
30108
30185
|
price.toFixed(0),
|
|
30109
30186
|
side
|
|
30110
30187
|
);
|
|
30111
|
-
if (!result) {
|
|
30188
|
+
if (!result || !result.position_id) {
|
|
30189
|
+
logger.error("Failed to create order - no position_id returned");
|
|
30112
30190
|
return null;
|
|
30113
30191
|
}
|
|
30114
|
-
|
|
30115
|
-
|
|
30116
|
-
|
|
30192
|
+
const positionId = result.position_id;
|
|
30193
|
+
logger.info(
|
|
30194
|
+
`Order created with position_id: ${positionId}. Waiting for API to update...`
|
|
30195
|
+
);
|
|
30196
|
+
let openOrder = await this.getOrderStatus(
|
|
30197
|
+
positionId,
|
|
30117
30198
|
this.config.extendedMarketName
|
|
30118
30199
|
);
|
|
30200
|
+
const maxStatusRetries = 3;
|
|
30201
|
+
const statusRetryDelay = 5e3;
|
|
30119
30202
|
if (!openOrder) {
|
|
30203
|
+
logger.warn(
|
|
30204
|
+
`Order ${positionId} not found in API yet. Retrying status fetch (max ${maxStatusRetries} times)...`
|
|
30205
|
+
);
|
|
30206
|
+
for (let statusRetry = 1; statusRetry <= maxStatusRetries; statusRetry++) {
|
|
30207
|
+
await new Promise((resolve) => setTimeout(resolve, statusRetryDelay));
|
|
30208
|
+
openOrder = await this.getOrderStatus(
|
|
30209
|
+
positionId,
|
|
30210
|
+
this.config.extendedMarketName
|
|
30211
|
+
);
|
|
30212
|
+
if (openOrder) {
|
|
30213
|
+
logger.info(
|
|
30214
|
+
`Order ${positionId} found after ${statusRetry} status retry(ies)`
|
|
30215
|
+
);
|
|
30216
|
+
break;
|
|
30217
|
+
}
|
|
30218
|
+
logger.warn(
|
|
30219
|
+
`Order ${positionId} still not found after ${statusRetry}/${maxStatusRetries} status retries`
|
|
30220
|
+
);
|
|
30221
|
+
}
|
|
30222
|
+
}
|
|
30223
|
+
if (openOrder && openOrder.status === "FILLED" /* FILLED */) {
|
|
30224
|
+
logger.info(
|
|
30225
|
+
`Order ${positionId} successfully filled with quantity ${openOrder.qty}`
|
|
30226
|
+
);
|
|
30227
|
+
return {
|
|
30228
|
+
position_id: positionId,
|
|
30229
|
+
btc_exposure: openOrder.qty
|
|
30230
|
+
};
|
|
30231
|
+
} else if (openOrder && openOrder.status !== "FILLED" /* FILLED */) {
|
|
30232
|
+
logger.warn(
|
|
30233
|
+
`Order ${positionId} found but status is ${openOrder.status}, not FILLED. Retrying order creation...`
|
|
30234
|
+
);
|
|
30120
30235
|
if (attempt >= maxAttempts) {
|
|
30121
|
-
logger.error(
|
|
30236
|
+
logger.error(
|
|
30237
|
+
`Max retries reached \u2014 order ${positionId} status is ${openOrder.status}, not FILLED`
|
|
30238
|
+
);
|
|
30122
30239
|
return null;
|
|
30123
30240
|
} else {
|
|
30124
30241
|
const backoff = 2e3 * attempt;
|
|
@@ -30132,9 +30249,12 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
30132
30249
|
);
|
|
30133
30250
|
}
|
|
30134
30251
|
} else {
|
|
30252
|
+
logger.warn(
|
|
30253
|
+
`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.`
|
|
30254
|
+
);
|
|
30135
30255
|
return {
|
|
30136
|
-
position_id:
|
|
30137
|
-
btc_exposure:
|
|
30256
|
+
position_id: positionId,
|
|
30257
|
+
btc_exposure: amount_in_token
|
|
30138
30258
|
};
|
|
30139
30259
|
}
|
|
30140
30260
|
} catch (err) {
|
|
@@ -30179,32 +30299,101 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
30179
30299
|
}
|
|
30180
30300
|
}
|
|
30181
30301
|
async getDepositOrWithdrawalStatus(orderId, operationsType) {
|
|
30182
|
-
|
|
30183
|
-
|
|
30184
|
-
|
|
30185
|
-
|
|
30186
|
-
|
|
30187
|
-
|
|
30188
|
-
|
|
30189
|
-
|
|
30190
|
-
)
|
|
30191
|
-
|
|
30192
|
-
|
|
30302
|
+
const maxAttempts = 5;
|
|
30303
|
+
const retryDelayMs = 3e4;
|
|
30304
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
30305
|
+
try {
|
|
30306
|
+
let transferHistory = await this.client.getAssetOperations({
|
|
30307
|
+
operationsType: [operationsType],
|
|
30308
|
+
operationsStatus: ["COMPLETED" /* COMPLETED */]
|
|
30309
|
+
});
|
|
30310
|
+
if (operationsType === "DEPOSIT" /* DEPOSIT */) {
|
|
30311
|
+
const myTransferStatus = transferHistory.data.find(
|
|
30312
|
+
(operation) => operation.transactionHash === orderId
|
|
30313
|
+
);
|
|
30314
|
+
if (!myTransferStatus) {
|
|
30315
|
+
if (attempt < maxAttempts) {
|
|
30316
|
+
logger.info(
|
|
30317
|
+
`Deposit operation not found for transactionHash ${orderId}, retrying (attempt ${attempt}/${maxAttempts})...`
|
|
30318
|
+
);
|
|
30319
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
30320
|
+
continue;
|
|
30321
|
+
}
|
|
30322
|
+
logger.warn(
|
|
30323
|
+
`Deposit operation not found for transactionHash ${orderId} after ${maxAttempts} attempts`
|
|
30324
|
+
);
|
|
30325
|
+
return false;
|
|
30326
|
+
}
|
|
30327
|
+
if (myTransferStatus.status === "COMPLETED" /* COMPLETED */) {
|
|
30328
|
+
logger.info(
|
|
30329
|
+
`Deposit operation ${orderId} completed successfully`
|
|
30330
|
+
);
|
|
30331
|
+
return true;
|
|
30332
|
+
} else {
|
|
30333
|
+
if (attempt < maxAttempts) {
|
|
30334
|
+
logger.info(
|
|
30335
|
+
`Deposit operation ${orderId} found but status is ${myTransferStatus.status}, not COMPLETED. Retrying (attempt ${attempt}/${maxAttempts})...`
|
|
30336
|
+
);
|
|
30337
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
30338
|
+
continue;
|
|
30339
|
+
}
|
|
30340
|
+
logger.warn(
|
|
30341
|
+
`Deposit operation ${orderId} status is ${myTransferStatus.status} after ${maxAttempts} attempts, expected COMPLETED`
|
|
30342
|
+
);
|
|
30343
|
+
return false;
|
|
30344
|
+
}
|
|
30345
|
+
} else {
|
|
30346
|
+
const myTransferStatus = transferHistory.data.find(
|
|
30347
|
+
(operation) => operation.id.toString() === orderId.toString()
|
|
30348
|
+
);
|
|
30349
|
+
if (!myTransferStatus) {
|
|
30350
|
+
if (attempt < maxAttempts) {
|
|
30351
|
+
logger.info(
|
|
30352
|
+
`Withdrawal status not found for orderId ${orderId} in completed operations, retrying (attempt ${attempt}/${maxAttempts})...`
|
|
30353
|
+
);
|
|
30354
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
30355
|
+
continue;
|
|
30356
|
+
}
|
|
30357
|
+
logger.warn(
|
|
30358
|
+
`Withdrawal operation not found for orderId ${orderId} after ${maxAttempts} attempts`
|
|
30359
|
+
);
|
|
30360
|
+
return false;
|
|
30361
|
+
}
|
|
30362
|
+
if (myTransferStatus.status === "COMPLETED" /* COMPLETED */) {
|
|
30363
|
+
logger.info(
|
|
30364
|
+
`Withdrawal operation ${orderId} completed successfully`
|
|
30365
|
+
);
|
|
30366
|
+
return true;
|
|
30367
|
+
} else {
|
|
30368
|
+
if (attempt < maxAttempts) {
|
|
30369
|
+
logger.info(
|
|
30370
|
+
`Withdrawal operation ${orderId} found but status is ${myTransferStatus.status}, not COMPLETED. Retrying (attempt ${attempt}/${maxAttempts})...`
|
|
30371
|
+
);
|
|
30372
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
30373
|
+
continue;
|
|
30374
|
+
}
|
|
30375
|
+
logger.warn(
|
|
30376
|
+
`Withdrawal operation ${orderId} status is ${myTransferStatus.status} after ${maxAttempts} attempts, expected COMPLETED`
|
|
30377
|
+
);
|
|
30378
|
+
return false;
|
|
30379
|
+
}
|
|
30193
30380
|
}
|
|
30194
|
-
|
|
30195
|
-
|
|
30196
|
-
|
|
30197
|
-
(operation) => operation.id.toString() === orderId.toString()
|
|
30381
|
+
} catch (err) {
|
|
30382
|
+
logger.error(
|
|
30383
|
+
`error getting deposit or withdrawal status (attempt ${attempt}/${maxAttempts}): ${err}`
|
|
30198
30384
|
);
|
|
30199
|
-
if (
|
|
30200
|
-
|
|
30385
|
+
if (attempt < maxAttempts) {
|
|
30386
|
+
logger.info(`Retrying after ${retryDelayMs}ms...`);
|
|
30387
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
30388
|
+
continue;
|
|
30201
30389
|
}
|
|
30202
|
-
|
|
30390
|
+
logger.error(
|
|
30391
|
+
`Max retry attempts reached for getDepositOrWithdrawalStatus`
|
|
30392
|
+
);
|
|
30393
|
+
return false;
|
|
30203
30394
|
}
|
|
30204
|
-
} catch (err) {
|
|
30205
|
-
logger.error(`error getting deposit or withdrawal status: ${err}`);
|
|
30206
|
-
return false;
|
|
30207
30395
|
}
|
|
30396
|
+
return false;
|
|
30208
30397
|
}
|
|
30209
30398
|
};
|
|
30210
30399
|
|
|
@@ -34154,11 +34343,27 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34154
34343
|
}
|
|
34155
34344
|
async shouldInvest() {
|
|
34156
34345
|
try {
|
|
34346
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest starting`);
|
|
34157
34347
|
const vesuAdapter = await this.getVesuAdapter();
|
|
34158
34348
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
34159
|
-
|
|
34349
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest adapters fetched: vesuAdapter=${!!vesuAdapter}, extendedAdapter=${!!extendedAdapter}, extendedAdapter.client=${!!extendedAdapter?.client}`);
|
|
34350
|
+
if (!vesuAdapter) {
|
|
34160
34351
|
logger.error(
|
|
34161
|
-
`
|
|
34352
|
+
`Vesu adapter not configured in metadata. This is a configuration issue, not a temporary failure.`
|
|
34353
|
+
);
|
|
34354
|
+
return {
|
|
34355
|
+
shouldInvest: false,
|
|
34356
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34357
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34358
|
+
extendedLeverage: 0,
|
|
34359
|
+
collateralPrice: 0,
|
|
34360
|
+
debtPrice: 0,
|
|
34361
|
+
vesuLeverage: 0
|
|
34362
|
+
};
|
|
34363
|
+
}
|
|
34364
|
+
if (!extendedAdapter) {
|
|
34365
|
+
logger.error(
|
|
34366
|
+
`Extended adapter not configured in metadata. This is a configuration issue, not a temporary failure.`
|
|
34162
34367
|
);
|
|
34163
34368
|
return {
|
|
34164
34369
|
shouldInvest: false,
|
|
@@ -34170,10 +34375,72 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34170
34375
|
vesuLeverage: 0
|
|
34171
34376
|
};
|
|
34172
34377
|
}
|
|
34378
|
+
if (!extendedAdapter.client) {
|
|
34379
|
+
logger.error(
|
|
34380
|
+
`Extended adapter client not initialized. This may be a temporary initialization failure - check network connectivity and API availability.`
|
|
34381
|
+
);
|
|
34382
|
+
return {
|
|
34383
|
+
shouldInvest: false,
|
|
34384
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34385
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34386
|
+
extendedLeverage: 0,
|
|
34387
|
+
collateralPrice: 0,
|
|
34388
|
+
debtPrice: 0,
|
|
34389
|
+
vesuLeverage: 0
|
|
34390
|
+
};
|
|
34391
|
+
}
|
|
34392
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest calling getUnusedBalance`);
|
|
34173
34393
|
const balance = await this.getUnusedBalance();
|
|
34394
|
+
if (!Number.isFinite(balance.usdValue) || balance.usdValue < 0) {
|
|
34395
|
+
logger.error(
|
|
34396
|
+
`Invalid balance.usdValue: ${balance.usdValue}. Expected a finite, non-negative number.`
|
|
34397
|
+
);
|
|
34398
|
+
return {
|
|
34399
|
+
shouldInvest: false,
|
|
34400
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34401
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34402
|
+
extendedLeverage: 0,
|
|
34403
|
+
collateralPrice: 0,
|
|
34404
|
+
debtPrice: 0,
|
|
34405
|
+
vesuLeverage: 0
|
|
34406
|
+
};
|
|
34407
|
+
}
|
|
34408
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest balance: ${balance.usdValue}`);
|
|
34174
34409
|
const usdcBalanceOnExtended = await extendedAdapter.getExtendedDepositAmount();
|
|
34410
|
+
if (usdcBalanceOnExtended) {
|
|
34411
|
+
const availableForWithdrawal = parseFloat(usdcBalanceOnExtended.availableForWithdrawal);
|
|
34412
|
+
if (!Number.isFinite(availableForWithdrawal) || availableForWithdrawal < 0) {
|
|
34413
|
+
logger.error(
|
|
34414
|
+
`Invalid usdcBalanceOnExtended.availableForWithdrawal: ${usdcBalanceOnExtended.availableForWithdrawal}. Expected a finite, non-negative number.`
|
|
34415
|
+
);
|
|
34416
|
+
return {
|
|
34417
|
+
shouldInvest: false,
|
|
34418
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34419
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34420
|
+
extendedLeverage: 0,
|
|
34421
|
+
collateralPrice: 0,
|
|
34422
|
+
debtPrice: 0,
|
|
34423
|
+
vesuLeverage: 0
|
|
34424
|
+
};
|
|
34425
|
+
}
|
|
34426
|
+
}
|
|
34175
34427
|
const amountToInvest = new Web3Number(balance.usdValue, USDC_TOKEN_DECIMALS).plus(usdcBalanceOnExtended?.availableForWithdrawal ?? 0).multipliedBy(1 - LIMIT_BALANCE);
|
|
34176
|
-
|
|
34428
|
+
const amountToInvestNumber = amountToInvest.toNumber();
|
|
34429
|
+
if (!Number.isFinite(amountToInvestNumber)) {
|
|
34430
|
+
logger.error(
|
|
34431
|
+
`Invalid amountToInvest calculation result: ${amountToInvestNumber}. Calculation may have produced NaN or Infinity.`
|
|
34432
|
+
);
|
|
34433
|
+
return {
|
|
34434
|
+
shouldInvest: false,
|
|
34435
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34436
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34437
|
+
extendedLeverage: 0,
|
|
34438
|
+
collateralPrice: 0,
|
|
34439
|
+
debtPrice: 0,
|
|
34440
|
+
vesuLeverage: 0
|
|
34441
|
+
};
|
|
34442
|
+
}
|
|
34443
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldInvest amountToInvest: ${amountToInvestNumber}`);
|
|
34177
34444
|
if (amountToInvest.lessThan(0)) {
|
|
34178
34445
|
return {
|
|
34179
34446
|
shouldInvest: false,
|
|
@@ -34203,6 +34470,34 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34203
34470
|
collateralPrice,
|
|
34204
34471
|
debtPrice
|
|
34205
34472
|
} = await this.getAssetPrices();
|
|
34473
|
+
if (!Number.isFinite(collateralPrice.price) || collateralPrice.price <= 0) {
|
|
34474
|
+
logger.error(
|
|
34475
|
+
`Invalid collateralPrice: ${collateralPrice.price}. Expected a finite, positive number.`
|
|
34476
|
+
);
|
|
34477
|
+
return {
|
|
34478
|
+
shouldInvest: false,
|
|
34479
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34480
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34481
|
+
extendedLeverage: 0,
|
|
34482
|
+
collateralPrice: 0,
|
|
34483
|
+
debtPrice: 0,
|
|
34484
|
+
vesuLeverage: 0
|
|
34485
|
+
};
|
|
34486
|
+
}
|
|
34487
|
+
if (!Number.isFinite(debtPrice.price) || debtPrice.price <= 0) {
|
|
34488
|
+
logger.error(
|
|
34489
|
+
`Invalid debtPrice: ${debtPrice.price}. Expected a finite, positive number.`
|
|
34490
|
+
);
|
|
34491
|
+
return {
|
|
34492
|
+
shouldInvest: false,
|
|
34493
|
+
vesuAmount: new Web3Number(0, 0),
|
|
34494
|
+
extendedAmount: new Web3Number(0, 0),
|
|
34495
|
+
extendedLeverage: 0,
|
|
34496
|
+
collateralPrice: 0,
|
|
34497
|
+
debtPrice: 0,
|
|
34498
|
+
vesuLeverage: 0
|
|
34499
|
+
};
|
|
34500
|
+
}
|
|
34206
34501
|
const { vesu_amount, extended_amount, extended_leverage, vesu_leverage } = await calculateAmountDistribution(
|
|
34207
34502
|
amountToInvest.toNumber(),
|
|
34208
34503
|
extendedAdapter.client,
|
|
@@ -34253,13 +34548,45 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34253
34548
|
try {
|
|
34254
34549
|
const vesuAdapter = await this.getVesuAdapter();
|
|
34255
34550
|
const extendedAdapter = await this.getExtendedAdapter();
|
|
34256
|
-
let calls = [];
|
|
34257
34551
|
if (!vesuAdapter || !extendedAdapter || !extendedAdapter.client) {
|
|
34258
34552
|
logger.error(
|
|
34259
34553
|
`vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
|
|
34260
34554
|
);
|
|
34261
|
-
return
|
|
34555
|
+
return [];
|
|
34556
|
+
}
|
|
34557
|
+
const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
34558
|
+
if (!extendedHoldings) {
|
|
34559
|
+
logger.error(`error getting extended holdings: ${extendedHoldings}`);
|
|
34560
|
+
return [];
|
|
34262
34561
|
}
|
|
34562
|
+
const usdcAmountInWallet = (await this.getUnusedBalance()).amount;
|
|
34563
|
+
const usdcAmountOnExtendedAvailableForWithdrawal = parseFloat(
|
|
34564
|
+
extendedHoldings.availableForWithdrawal
|
|
34565
|
+
);
|
|
34566
|
+
logger.info(`${_VesuExtendedMultiplierStrategy.name}::shouldMoveAssets calculating movements - Extended current: ${usdcAmountOnExtendedAvailableForWithdrawal}, Wallet: ${usdcAmountInWallet.toNumber()}, Target Extended: ${extendedAmount.toNumber()}, Target Vesu: ${vesuAmount.toNumber()}`);
|
|
34567
|
+
let totalExtendedWithdrawal = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
34568
|
+
let totalExtendedDeposit = new Web3Number(0, USDC_TOKEN_DECIMALS);
|
|
34569
|
+
if (extendedAmount.isNegative() && extendedAmount.abs().greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
34570
|
+
totalExtendedWithdrawal = totalExtendedWithdrawal.plus(extendedAmount.abs());
|
|
34571
|
+
}
|
|
34572
|
+
const extendedTargetAmount = extendedAmount.abs();
|
|
34573
|
+
let projectedExtendedBalance = usdcAmountOnExtendedAvailableForWithdrawal;
|
|
34574
|
+
if (extendedAmount.isNegative()) {
|
|
34575
|
+
projectedExtendedBalance = projectedExtendedBalance - extendedAmount.abs().toNumber();
|
|
34576
|
+
}
|
|
34577
|
+
const extendedAmountDifference = extendedTargetAmount.minus(projectedExtendedBalance);
|
|
34578
|
+
const extendedAmountDifferenceAbs = extendedAmountDifference.abs();
|
|
34579
|
+
if (extendedAmountDifference.lessThan(0)) {
|
|
34580
|
+
totalExtendedWithdrawal = totalExtendedWithdrawal.plus(extendedAmountDifferenceAbs);
|
|
34581
|
+
} else if (extendedAmountDifference.greaterThan(0)) {
|
|
34582
|
+
totalExtendedDeposit = totalExtendedDeposit.plus(extendedAmountDifference);
|
|
34583
|
+
}
|
|
34584
|
+
const vesuTargetAmount = vesuAmount.abs();
|
|
34585
|
+
const projectedWalletBalance = usdcAmountInWallet.plus(totalExtendedWithdrawal).minus(totalExtendedDeposit);
|
|
34586
|
+
let vesuAmountDifference = vesuTargetAmount.minus(projectedWalletBalance);
|
|
34587
|
+
const vesuAmountDifferenceAbs = vesuAmountDifference.abs();
|
|
34588
|
+
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()}`);
|
|
34589
|
+
let calls = [];
|
|
34263
34590
|
if (extendedAmount.isNegative() && extendedAmount.abs().greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
34264
34591
|
try {
|
|
34265
34592
|
const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
|
|
@@ -34280,7 +34607,7 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34280
34607
|
logger.error(`Failed moving assets to vault: ${err}`);
|
|
34281
34608
|
}
|
|
34282
34609
|
}
|
|
34283
|
-
if (vesuAmount.isNegative() && vesuAmount.
|
|
34610
|
+
if (vesuAmount.isNegative() && vesuAmount.abs().greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
|
|
34284
34611
|
try {
|
|
34285
34612
|
const { calls: vesuCalls, status: vesuStatus } = await this.moveAssets(
|
|
34286
34613
|
{
|
|
@@ -34299,48 +34626,76 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34299
34626
|
logger.error(`Failed moving assets to vault: ${err}`);
|
|
34300
34627
|
}
|
|
34301
34628
|
}
|
|
34302
|
-
|
|
34303
|
-
|
|
34304
|
-
|
|
34305
|
-
|
|
34306
|
-
|
|
34307
|
-
|
|
34308
|
-
|
|
34309
|
-
|
|
34310
|
-
|
|
34311
|
-
|
|
34312
|
-
|
|
34313
|
-
|
|
34314
|
-
{
|
|
34315
|
-
|
|
34316
|
-
|
|
34317
|
-
|
|
34318
|
-
|
|
34319
|
-
|
|
34320
|
-
|
|
34321
|
-
|
|
34322
|
-
|
|
34323
|
-
|
|
34324
|
-
|
|
34629
|
+
if (extendedAmountDifferenceAbs.greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
34630
|
+
if (extendedAmountDifference.greaterThan(0)) {
|
|
34631
|
+
try {
|
|
34632
|
+
const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
|
|
34633
|
+
{
|
|
34634
|
+
to: Protocols.EXTENDED.name,
|
|
34635
|
+
from: Protocols.VAULT.name,
|
|
34636
|
+
amount: extendedAmountDifference
|
|
34637
|
+
},
|
|
34638
|
+
extendedAdapter,
|
|
34639
|
+
vesuAdapter
|
|
34640
|
+
);
|
|
34641
|
+
if (extendedStatus) {
|
|
34642
|
+
calls.push(...extendedCalls);
|
|
34643
|
+
} else {
|
|
34644
|
+
logger.error(`Failed to move assets to extended - operation returned false status`);
|
|
34645
|
+
return [];
|
|
34646
|
+
}
|
|
34647
|
+
} catch (err) {
|
|
34648
|
+
logger.error(`Failed moving assets to extended: ${err}`);
|
|
34649
|
+
return [];
|
|
34650
|
+
}
|
|
34651
|
+
} else if (extendedAmountDifference.lessThan(0)) {
|
|
34652
|
+
try {
|
|
34653
|
+
const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
|
|
34654
|
+
{
|
|
34655
|
+
to: Protocols.VAULT.name,
|
|
34656
|
+
from: Protocols.EXTENDED.name,
|
|
34657
|
+
amount: extendedAmountDifferenceAbs
|
|
34658
|
+
},
|
|
34659
|
+
extendedAdapter,
|
|
34660
|
+
vesuAdapter
|
|
34661
|
+
);
|
|
34662
|
+
if (extendedStatus) {
|
|
34663
|
+
calls.push(...extendedCalls);
|
|
34664
|
+
} else {
|
|
34665
|
+
logger.error(`Failed to withdraw from extended - operation returned false status`);
|
|
34666
|
+
return [];
|
|
34667
|
+
}
|
|
34668
|
+
} catch (err) {
|
|
34669
|
+
logger.error(`Failed moving assets from extended to vault: ${err}`);
|
|
34670
|
+
return [];
|
|
34671
|
+
}
|
|
34325
34672
|
}
|
|
34326
34673
|
}
|
|
34327
|
-
if (
|
|
34328
|
-
|
|
34329
|
-
|
|
34330
|
-
{
|
|
34331
|
-
to: Protocols.VAULT.name,
|
|
34332
|
-
from: Protocols.EXTENDED.name,
|
|
34333
|
-
amount: vesuAmount.minus(usdcAmountInWallet)
|
|
34334
|
-
},
|
|
34335
|
-
extendedAdapter,
|
|
34336
|
-
vesuAdapter
|
|
34674
|
+
if (vesuAmountDifferenceAbs.greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
|
|
34675
|
+
if (vesuAmountDifference.lessThanOrEqualTo(0)) {
|
|
34676
|
+
logger.warn(
|
|
34677
|
+
`Vesu amount difference is negative or zero: ${vesuAmountDifference.toNumber()}. Skipping operation.`
|
|
34337
34678
|
);
|
|
34338
|
-
|
|
34679
|
+
} else {
|
|
34680
|
+
try {
|
|
34681
|
+
const { calls: vesuCalls, status: vesuStatus } = await this.moveAssets(
|
|
34682
|
+
{
|
|
34683
|
+
to: Protocols.VAULT.name,
|
|
34684
|
+
from: Protocols.EXTENDED.name,
|
|
34685
|
+
amount: vesuAmountDifference
|
|
34686
|
+
},
|
|
34687
|
+
extendedAdapter,
|
|
34688
|
+
vesuAdapter
|
|
34689
|
+
);
|
|
34690
|
+
if (!vesuStatus) {
|
|
34691
|
+
logger.error(`Failed to move assets to vesu - operation returned false status`);
|
|
34692
|
+
return [];
|
|
34693
|
+
}
|
|
34694
|
+
calls.push(...vesuCalls);
|
|
34695
|
+
} catch (err) {
|
|
34696
|
+
logger.error(`Failed moving assets to vault: ${err}`);
|
|
34339
34697
|
return [];
|
|
34340
34698
|
}
|
|
34341
|
-
calls.push(...vesuCalls);
|
|
34342
|
-
} catch (err) {
|
|
34343
|
-
logger.error(`Failed moving assets to vault: ${err}`);
|
|
34344
34699
|
}
|
|
34345
34700
|
}
|
|
34346
34701
|
return calls;
|
|
@@ -34351,6 +34706,38 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34351
34706
|
}
|
|
34352
34707
|
async moveAssets(params, extendedAdapter, vesuAdapter) {
|
|
34353
34708
|
try {
|
|
34709
|
+
if (params.amount.lessThanOrEqualTo(0)) {
|
|
34710
|
+
logger.error(
|
|
34711
|
+
`Invalid amount for moveAssets: ${params.amount.toNumber()}. Amount must be positive.`
|
|
34712
|
+
);
|
|
34713
|
+
return {
|
|
34714
|
+
calls: [],
|
|
34715
|
+
status: false
|
|
34716
|
+
};
|
|
34717
|
+
}
|
|
34718
|
+
const amountAbs = params.amount.abs();
|
|
34719
|
+
if (params.from === Protocols.EXTENDED.name || params.to === Protocols.EXTENDED.name) {
|
|
34720
|
+
if (amountAbs.lessThanOrEqualTo(extendedAdapter.minimumExtendedMovementAmount)) {
|
|
34721
|
+
logger.warn(
|
|
34722
|
+
`Amount ${amountAbs.toNumber()} is below minimum Extended movement amount ${extendedAdapter.minimumExtendedMovementAmount}. Skipping operation.`
|
|
34723
|
+
);
|
|
34724
|
+
return {
|
|
34725
|
+
calls: [],
|
|
34726
|
+
status: false
|
|
34727
|
+
};
|
|
34728
|
+
}
|
|
34729
|
+
}
|
|
34730
|
+
if (params.from === Protocols.VESU.name || params.to === Protocols.VESU.name) {
|
|
34731
|
+
if (amountAbs.lessThanOrEqualTo(vesuAdapter.minimumVesuMovementAmount)) {
|
|
34732
|
+
logger.warn(
|
|
34733
|
+
`Amount ${amountAbs.toNumber()} is below minimum Vesu movement amount ${vesuAdapter.minimumVesuMovementAmount}. Skipping operation.`
|
|
34734
|
+
);
|
|
34735
|
+
return {
|
|
34736
|
+
calls: [],
|
|
34737
|
+
status: false
|
|
34738
|
+
};
|
|
34739
|
+
}
|
|
34740
|
+
}
|
|
34354
34741
|
const avnuAdapter = await this.getAvnuAdapter();
|
|
34355
34742
|
if (!avnuAdapter) {
|
|
34356
34743
|
logger.error(`avnu adapter not found: ${avnuAdapter}`);
|
|
@@ -34411,18 +34798,18 @@ var VesuExtendedMultiplierStrategy = class _VesuExtendedMultiplierStrategy exten
|
|
|
34411
34798
|
);
|
|
34412
34799
|
if (!openLongPosition) {
|
|
34413
34800
|
logger.error(`error opening long position: ${openLongPosition}`);
|
|
34414
|
-
return {
|
|
34415
|
-
calls: [],
|
|
34416
|
-
status: false
|
|
34417
|
-
};
|
|
34418
34801
|
}
|
|
34419
|
-
|
|
34802
|
+
const updatedHoldings = await extendedAdapter.getExtendedDepositAmount();
|
|
34803
|
+
if (!updatedHoldings || new Web3Number(updatedHoldings.availableForWithdrawal, USDC_TOKEN_DECIMALS).lessThan(params.amount.abs())) {
|
|
34804
|
+
logger.error(`Insufficient balance after opening position. Available: ${updatedHoldings?.availableForWithdrawal}, Needed: ${params.amount.abs()}`);
|
|
34805
|
+
return { calls: [], status: false };
|
|
34806
|
+
}
|
|
34420
34807
|
}
|
|
34421
34808
|
const withdrawalFromExtended = await extendedAdapter.withdrawFromExtended(params.amount);
|
|
34422
34809
|
if (withdrawalFromExtended) {
|
|
34423
34810
|
const extendedHoldings2 = await extendedAdapter.getExtendedDepositAmount();
|
|
34424
34811
|
logger.info(`extendedHoldings after withdrawal ${extendedHoldings2?.availableForWithdrawal}`);
|
|
34425
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
34812
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
34426
34813
|
const calls = await this.moveAssetsToVaultAllocator(params.amount, extendedAdapter);
|
|
34427
34814
|
if (calls.length > 0) {
|
|
34428
34815
|
return {
|