@suilend/sdk 12.4.0-next.g7a809d2 → 12.4.0-next.gd4b87be
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/package.json +1 -1
- package/strategies.d.ts +3 -2
- package/strategies.js +129 -53
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@suilend/sdk","version":"12.4.0-next.
|
|
1
|
+
{"name":"@suilend/sdk","version":"12.4.0-next.gd4b87be","private":false,"description":"A TypeScript SDK for interacting with the Suilend program","author":"Suilend","license":"MIT","main":"./index.js","exports":{".":"./index.js","./client":"./client.js","./mmt":"./mmt.js","./strategies":"./strategies.js","./api/events":"./api/events.js","./api":"./api/index.js","./lib/constants":"./lib/constants.js","./lib":"./lib/index.js","./lib/initialize":"./lib/initialize.js","./lib/liquidityMining":"./lib/liquidityMining.js","./lib/proCompatible":"./lib/proCompatible.js","./lib/pyth":"./lib/pyth.js","./lib/strategyOwnerCap":"./lib/strategyOwnerCap.js","./lib/transactions":"./lib/transactions.js","./lib/types":"./lib/types.js","./margin":"./margin/index.js","./parsers/apiReserveAssetDataEvent":"./parsers/apiReserveAssetDataEvent.js","./parsers":"./parsers/index.js","./parsers/lendingMarket":"./parsers/lendingMarket.js","./parsers/obligation":"./parsers/obligation.js","./parsers/rateLimiter":"./parsers/rateLimiter.js","./parsers/reserve":"./parsers/reserve.js","./swap":"./swap/index.js","./swap/quote":"./swap/quote.js","./swap/transaction":"./swap/transaction.js","./utils/events":"./utils/events.js","./utils/feedId":"./utils/feedId.js","./utils":"./utils/index.js","./utils/obligation":"./utils/obligation.js","./utils/simulate":"./utils/simulate.js","./_generated/_framework/reified":"./_generated/_framework/reified.js","./_generated/_framework/util":"./_generated/_framework/util.js","./_generated/_framework/vector":"./_generated/_framework/vector.js","./_generated/suilend":"./_generated/suilend/index.js","./margin/margin/admin_cap":"./margin/margin/admin_cap.js","./margin/margin/market":"./margin/margin/market.js","./margin/margin/permissions":"./margin/margin/permissions.js","./margin/margin/position":"./margin/margin/position.js","./margin/margin/router":"./margin/margin/router.js","./margin/margin/version":"./margin/margin/version.js","./margin/utils":"./margin/utils/index.js","./_generated/suilend/cell/structs":"./_generated/suilend/cell/structs.js","./_generated/suilend/decimal/structs":"./_generated/suilend/decimal/structs.js","./_generated/suilend/lending-market/functions":"./_generated/suilend/lending-market/functions.js","./_generated/suilend/lending-market/structs":"./_generated/suilend/lending-market/structs.js","./_generated/suilend/lending-market-registry/functions":"./_generated/suilend/lending-market-registry/functions.js","./_generated/suilend/liquidity-mining/structs":"./_generated/suilend/liquidity-mining/structs.js","./_generated/suilend/obligation/structs":"./_generated/suilend/obligation/structs.js","./_generated/suilend/rate-limiter/functions":"./_generated/suilend/rate-limiter/functions.js","./_generated/suilend/rate-limiter/structs":"./_generated/suilend/rate-limiter/structs.js","./_generated/suilend/reserve/structs":"./_generated/suilend/reserve/structs.js","./_generated/suilend/reserve-config/functions":"./_generated/suilend/reserve-config/functions.js","./_generated/suilend/reserve-config/structs":"./_generated/suilend/reserve-config/structs.js","./_generated/_dependencies/source/0x1":"./_generated/_dependencies/source/0x1/index.js","./_generated/_dependencies/source/0x2":"./_generated/_dependencies/source/0x2/index.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/index.js","./margin/margin/deps/std/type_name":"./margin/margin/deps/std/type_name.js","./margin/margin/deps/sui/vec_set":"./margin/margin/deps/sui/vec_set.js","./margin/margin/deps/suilend/lending_market":"./margin/margin/deps/suilend/lending_market.js","./_generated/_dependencies/source/0x1/ascii/structs":"./_generated/_dependencies/source/0x1/ascii/structs.js","./_generated/_dependencies/source/0x1/option/structs":"./_generated/_dependencies/source/0x1/option/structs.js","./_generated/_dependencies/source/0x1/type-name/structs":"./_generated/_dependencies/source/0x1/type-name/structs.js","./_generated/_dependencies/source/0x2/bag/structs":"./_generated/_dependencies/source/0x2/bag/structs.js","./_generated/_dependencies/source/0x2/balance/structs":"./_generated/_dependencies/source/0x2/balance/structs.js","./_generated/_dependencies/source/0x2/object/structs":"./_generated/_dependencies/source/0x2/object/structs.js","./_generated/_dependencies/source/0x2/object-table/structs":"./_generated/_dependencies/source/0x2/object-table/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-identifier/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-identifier/structs.js"},"types":"./index.d.ts","scripts":{"build":"rm -rf ./dist && tsc && node ./fix-esm-imports.js","typecheck":"tsc --noEmit && tsc --noEmit -p tsconfig.test.json","test":"vitest run","lint:ci":"yarn run typecheck","prettier":"prettier --write src/ tests/","release":"yarn run build && node ./release.js && cd ./dist && npm publish --access public"},"repository":{"type":"git","url":"git+https://github.com/fireflyprotocol/lending-mono.git","directory":"ts/sdks/sdk"},"dependencies":{"@bluefin-exchange/bluefin7k-aggregator-sdk":"7.6.3","@cetusprotocol/aggregator-sdk":"1.7.2","@flowx-finance/sdk":"2.1.0","@pythnetwork/hermes-client":"3.1.0","@pythnetwork/pyth-sui-js":"4.0.0","@suilend/springsui-sdk":"4.1.0","bignumber.js":"11.1.5","bn.js":"5.2.5","crypto-js":"4.2.0","lodash":"4.18.1","p-limit":"7.3.2","uuid":"14.0.2"},"devDependencies":{"@mysten/bcs":"2.1.1","@mysten/sui":"2.29.0","@suilend/sui-core":"2.1.0","@tsconfig/recommended":"1.0.13","@types/bn.js":"5.2.0","@types/lodash":"4.17.25","@types/node":"26.5.1","fast-check":"4.10.0","prettier":"3.9.6","ts-node":"10.9.2","typescript":"6.0.3","vite":"8.3.0","vitest":"5.0.0"},"peerDependencies":{"@mysten/bcs":"^2.1.1","@mysten/sui":">=2.22.1 <3","@suilend/sui-core":"^2.0.1"},"type":"module"}
|
package/strategies.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { StrategyType } from "./lib/strategyOwnerCap";
|
|
|
12
12
|
import { ParsedObligation, ParsedReserve } from "./parsers";
|
|
13
13
|
export declare const STRATEGY_E: number;
|
|
14
14
|
export declare const STRATEGY_FLASH_REPAY_MAX_RESIDUAL_USD = 0.1;
|
|
15
|
+
export declare const STRATEGY_RATE_LIMITED_ERROR_MESSAGE = "This withdrawal exceeds the lending market's outflow limit for now. Withdraw a smaller amount, or wait and try again.";
|
|
15
16
|
/**
|
|
16
17
|
* Below this, a levered position is uneconomic no matter what the slippage
|
|
17
18
|
* tolerance says. The aggregator's dust regime dominates: routes go multi-hop
|
|
@@ -360,7 +361,7 @@ export declare const strategyWithdrawTx: (reserveMap: Record<string, ParsedReser
|
|
|
360
361
|
transaction: Transaction;
|
|
361
362
|
withdrawnCoin?: TransactionArgument;
|
|
362
363
|
}>;
|
|
363
|
-
export declare const strategyMaxWithdrawTx: (reserveMap: Record<string, ParsedReserve>, rewardsMap: RewardsMap, lstMap: StrategyLstMap, strategyType: StrategyType, suiGrpcClient: SuiGrpcClient, suilendClient: SuilendClient, cetusSdk: CetusSdk, cetusPartnerId: string, _address: string, strategyOwnerCapId: TransactionObjectInput, obligationId: string, _deposits: StrategyDeposit[], _borrowedAmount: BigNumber, withdrawCoinType: string, transaction: Transaction,
|
|
364
|
+
export declare const strategyMaxWithdrawTx: (reserveMap: Record<string, ParsedReserve>, rewardsMap: RewardsMap, lstMap: StrategyLstMap, strategyType: StrategyType, suiGrpcClient: SuiGrpcClient, suilendClient: SuilendClient, cetusSdk: CetusSdk, cetusPartnerId: string, _address: string, strategyOwnerCapId: TransactionObjectInput, obligationId: string, _deposits: StrategyDeposit[], _borrowedAmount: BigNumber, withdrawCoinType: string, transaction: Transaction, _dryRunTransaction: (transaction: Transaction, setGasBudget?: boolean) => Promise<SuiClientTypes.SimulateTransactionResult<{
|
|
364
365
|
commandResults: true;
|
|
365
366
|
}>>) => Promise<{
|
|
366
367
|
deposits: StrategyDeposit[];
|
|
@@ -381,7 +382,7 @@ export declare const strategyDepositAdjustWithdrawTx: (reserveMap: Record<string
|
|
|
381
382
|
borrowedAmount: BigNumber;
|
|
382
383
|
transaction: Transaction;
|
|
383
384
|
}>;
|
|
384
|
-
export declare const strategyAdjustTx: (reserveMap: Record<string, ParsedReserve>, lstMap: StrategyLstMap, strategyType: StrategyType, suiGrpcClient: SuiGrpcClient, suilendClient: SuilendClient, cetusSdk: CetusSdk, cetusPartnerId: string, _address: string, strategyOwnerCapId: TransactionObjectInput, obligation: ParsedObligation, _deposits: StrategyDeposit[], _borrowedAmount: BigNumber, targetExposure: BigNumber, transaction: Transaction,
|
|
385
|
+
export declare const strategyAdjustTx: (reserveMap: Record<string, ParsedReserve>, lstMap: StrategyLstMap, strategyType: StrategyType, suiGrpcClient: SuiGrpcClient, suilendClient: SuilendClient, cetusSdk: CetusSdk, cetusPartnerId: string, _address: string, strategyOwnerCapId: TransactionObjectInput, obligation: ParsedObligation, _deposits: StrategyDeposit[], _borrowedAmount: BigNumber, targetExposure: BigNumber, transaction: Transaction, _dryRunTransaction: (transaction: Transaction, setGasBudget?: boolean) => Promise<SuiClientTypes.SimulateTransactionResult<{
|
|
385
386
|
commandResults: true;
|
|
386
387
|
}>>) => Promise<{
|
|
387
388
|
deposits: StrategyDeposit[];
|
package/strategies.js
CHANGED
|
@@ -13,6 +13,25 @@ import { MMT_CONTRACT_PACKAGE_ID, MMT_VERSION_OBJECT_ID } from "./mmt.js";
|
|
|
13
13
|
import { bisectionMethod, getWeightedBorrowsUsd } from "./utils/index.js";
|
|
14
14
|
export const STRATEGY_E = 10 ** -7;
|
|
15
15
|
export const STRATEGY_FLASH_REPAY_MAX_RESIDUAL_USD = 0.1;
|
|
16
|
+
export const STRATEGY_RATE_LIMITED_ERROR_MESSAGE = "This withdrawal exceeds the lending market's outflow limit for now. Withdraw a smaller amount, or wait and try again.";
|
|
17
|
+
const isRateLimitExceeded = (err) => /abort code: 2, in '[^']*::rate_limiter::process_qty'/.test(err instanceof Error ? err.message : String(err));
|
|
18
|
+
// Every step dry-runs and rolls back on failure, so the builders only see that
|
|
19
|
+
// no step landed. Recording why lets them name the market's outflow limit
|
|
20
|
+
// instead of reporting a generic failure.
|
|
21
|
+
const trackRateLimit = (dryRunTransaction) => {
|
|
22
|
+
const state = { exceeded: false };
|
|
23
|
+
const tracked = (async (...args) => {
|
|
24
|
+
try {
|
|
25
|
+
return await dryRunTransaction(...args);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
if (isRateLimitExceeded(err))
|
|
29
|
+
state.exceeded = true;
|
|
30
|
+
throw err;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return { rateLimit: state, dryRunTransaction: tracked };
|
|
34
|
+
};
|
|
16
35
|
/**
|
|
17
36
|
* Cetus applies its slippage check against its OWN quote, so a wrong quote yields
|
|
18
37
|
* a wrong floor. Measured on a mainnet unwind of a sub-dollar position: the
|
|
@@ -620,20 +639,32 @@ reserveMap,
|
|
|
620
639
|
// Strategy
|
|
621
640
|
lstMap, strategyType, deposits, borrowedAmount) => {
|
|
622
641
|
const depositReserves = getStrategyDepositReserves(reserveMap, strategyType);
|
|
642
|
+
const borrowReserve = getStrategyBorrowReserve(reserveMap, strategyType);
|
|
623
643
|
const depositReserve = (depositReserves.base ?? depositReserves.lst); // Must have LST if no base
|
|
624
|
-
const
|
|
625
|
-
?.depositedAmount ?? new BigNumber(0);
|
|
626
|
-
if (depositedAmount.lte(0))
|
|
627
|
-
return new BigNumber(0);
|
|
628
|
-
const simulateWith = (newDepositedAmount) => getStrategySimulatedObligation(reserveMap, lstMap, strategyType, addOrInsertStrategyDeposit(deposits, {
|
|
644
|
+
const simulateWith = (additionalAmount) => getStrategySimulatedObligation(reserveMap, lstMap, strategyType, addOrInsertStrategyDeposit(deposits, {
|
|
629
645
|
coinType: depositReserve.coinType,
|
|
630
|
-
depositedAmount:
|
|
646
|
+
depositedAmount: additionalAmount,
|
|
631
647
|
}), borrowedAmount);
|
|
632
|
-
const
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
648
|
+
const isRebalanced = (additionalAmount) => {
|
|
649
|
+
const obligation = simulateWith(additionalAmount);
|
|
650
|
+
return (getStrategyHealthPercent(reserveMap, lstMap, strategyType, obligation).eq(100) &&
|
|
651
|
+
getStrategyExposure(reserveMap, lstMap, strategyType, obligation).lte(STRATEGY_TYPE_EXPOSURE_MAP[strategyType].max));
|
|
652
|
+
};
|
|
653
|
+
if (isRebalanced(new BigNumber(0)))
|
|
654
|
+
return new BigNumber(0);
|
|
655
|
+
// Both conditions only get easier as base is added, so a doubled bound
|
|
656
|
+
// that satisfies them brackets the smallest amount that does.
|
|
657
|
+
let upperBound = BigNumber.max(deposits.find((d) => d.coinType === depositReserve.coinType)
|
|
658
|
+
?.depositedAmount ?? new BigNumber(0), borrowedAmount.times(borrowReserve.price).div(depositReserve.price));
|
|
659
|
+
let upperBoundRebalances = isRebalanced(upperBound);
|
|
660
|
+
for (let i = 0; i < 30 && !upperBoundRebalances; i++) {
|
|
661
|
+
upperBound = upperBound.times(2);
|
|
662
|
+
upperBoundRebalances = isRebalanced(upperBound);
|
|
663
|
+
}
|
|
664
|
+
if (!upperBoundRebalances)
|
|
665
|
+
throw new Error("No deposit brings the position back within its borrow limit");
|
|
666
|
+
const smallest = bisectionMethod(new BigNumber(0), upperBound, isRebalanced);
|
|
667
|
+
return (smallest.gt(0) ? smallest : upperBound).decimalPlaces(depositReserve.token.decimals, BigNumber.ROUND_UP);
|
|
637
668
|
};
|
|
638
669
|
// Simulate
|
|
639
670
|
export const strategySimulateLoopToExposure = (
|
|
@@ -2354,7 +2385,8 @@ export const strategyMaxWithdrawTx = async (
|
|
|
2354
2385
|
// AppContext
|
|
2355
2386
|
reserveMap, rewardsMap,
|
|
2356
2387
|
// Strategy
|
|
2357
|
-
lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, withdrawCoinType, transaction,
|
|
2388
|
+
lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, _deposits, _borrowedAmount, withdrawCoinType, transaction, _dryRunTransaction) => {
|
|
2389
|
+
const { rateLimit, dryRunTransaction } = trackRateLimit(_dryRunTransaction);
|
|
2358
2390
|
const strategyInfo = STRATEGY_TYPE_INFO_MAP[strategyType];
|
|
2359
2391
|
const lst = strategyInfo.depositLstCoinType !== undefined
|
|
2360
2392
|
? lstMap[strategyInfo.depositLstCoinType]
|
|
@@ -2380,25 +2412,37 @@ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _a
|
|
|
2380
2412
|
let borrowedAmount = _borrowedAmount;
|
|
2381
2413
|
// 1) Unloop to 1x (base+LST: no LST and no borrows, LST: no borrows)
|
|
2382
2414
|
if (borrowedAmount.gt(0)) {
|
|
2383
|
-
|
|
2384
|
-
|
|
2415
|
+
const unloopToOne = (fromDeposits, fromBorrowedAmount, fromTransaction) => strategyUnloopToExposureTx(reserveMap, lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, fromDeposits, fromBorrowedAmount, undefined, // Don't pass targetBorrowedAmount
|
|
2416
|
+
new BigNumber(1), // Pass targetExposure
|
|
2417
|
+
fromTransaction, dryRunTransaction);
|
|
2418
|
+
// 1.1) Unloop
|
|
2419
|
+
let unlooped;
|
|
2420
|
+
let plainError;
|
|
2421
|
+
try {
|
|
2422
|
+
unlooped = await unloopToOne(deposits, borrowedAmount, Transaction.from(transaction));
|
|
2423
|
+
}
|
|
2424
|
+
catch (err) {
|
|
2425
|
+
plainError = err;
|
|
2426
|
+
}
|
|
2427
|
+
// 1.1b) Above the borrow limit no stepwise withdraw can land, so rebalance and retry
|
|
2428
|
+
if ((unlooped === undefined || unlooped.borrowedAmount.gt(STRATEGY_E)) &&
|
|
2429
|
+
!isStrategyWithinBorrowLimit(reserveMap, lstMap, strategyType, deposits, borrowedAmount)) {
|
|
2385
2430
|
try {
|
|
2386
|
-
(
|
|
2387
|
-
|
|
2431
|
+
const rebalanced = await strategyRebalanceWithinBorrowLimitTx(reserveMap, lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligationId, deposits, borrowedAmount, Transaction.from(transaction), dryRunTransaction);
|
|
2432
|
+
unlooped = await unloopToOne(rebalanced.deposits, rebalanced.borrowedAmount, rebalanced.transaction);
|
|
2388
2433
|
}
|
|
2389
2434
|
catch (err) {
|
|
2390
2435
|
console.error(err);
|
|
2391
|
-
throw new Error("Failed to repay borrows before withdrawing");
|
|
2392
2436
|
}
|
|
2393
2437
|
}
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2438
|
+
if (unlooped === undefined)
|
|
2439
|
+
throw rateLimit.exceeded
|
|
2440
|
+
? new Error(STRATEGY_RATE_LIMITED_ERROR_MESSAGE)
|
|
2441
|
+
: plainError;
|
|
2398
2442
|
// 1.2) Update state
|
|
2399
|
-
deposits =
|
|
2400
|
-
borrowedAmount =
|
|
2401
|
-
transaction =
|
|
2443
|
+
deposits = unlooped.deposits;
|
|
2444
|
+
borrowedAmount = unlooped.borrowedAmount;
|
|
2445
|
+
transaction = unlooped.transaction;
|
|
2402
2446
|
console.log(`[strategyMaxWithdraw] unloop.update_state |`, JSON.stringify({
|
|
2403
2447
|
deposits: deposits.map((d) => ({
|
|
2404
2448
|
coinType: d.coinType,
|
|
@@ -2433,7 +2477,9 @@ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _a
|
|
|
2433
2477
|
}
|
|
2434
2478
|
catch (err) {
|
|
2435
2479
|
console.error(err);
|
|
2436
|
-
throw new Error(
|
|
2480
|
+
throw new Error(rateLimit.exceeded
|
|
2481
|
+
? STRATEGY_RATE_LIMITED_ERROR_MESSAGE
|
|
2482
|
+
: "Failed to repay borrows before withdrawing");
|
|
2437
2483
|
}
|
|
2438
2484
|
repaidByAdjustRepay = true;
|
|
2439
2485
|
}
|
|
@@ -2449,7 +2495,9 @@ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _a
|
|
|
2449
2495
|
borrowedAmount
|
|
2450
2496
|
.times(borrowReserve.price)
|
|
2451
2497
|
.gte(STRATEGY_FLASH_REPAY_MAX_RESIDUAL_USD))
|
|
2452
|
-
throw new Error(
|
|
2498
|
+
throw new Error(rateLimit.exceeded
|
|
2499
|
+
? STRATEGY_RATE_LIMITED_ERROR_MESSAGE
|
|
2500
|
+
: "Failed to repay borrows before withdrawing");
|
|
2453
2501
|
const flashLoanBorrowedAmount = borrowedAmount
|
|
2454
2502
|
.times(1.1)
|
|
2455
2503
|
.decimalPlaces(borrowReserve.token.decimals, BigNumber.ROUND_UP);
|
|
@@ -2595,7 +2643,9 @@ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _a
|
|
|
2595
2643
|
}
|
|
2596
2644
|
catch (err) {
|
|
2597
2645
|
console.error(err);
|
|
2598
|
-
throw new Error(
|
|
2646
|
+
throw new Error(rateLimit.exceeded
|
|
2647
|
+
? STRATEGY_RATE_LIMITED_ERROR_MESSAGE
|
|
2648
|
+
: "Failed to repay borrows before withdrawing");
|
|
2599
2649
|
}
|
|
2600
2650
|
}
|
|
2601
2651
|
return { deposits, borrowedAmount, transaction };
|
|
@@ -3041,7 +3091,8 @@ export const strategyAdjustTx = async (
|
|
|
3041
3091
|
// AppContext
|
|
3042
3092
|
reserveMap,
|
|
3043
3093
|
// Strategy
|
|
3044
|
-
lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligation, _deposits, _borrowedAmount, targetExposure, transaction,
|
|
3094
|
+
lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligation, _deposits, _borrowedAmount, targetExposure, transaction, _dryRunTransaction) => {
|
|
3095
|
+
const { rateLimit, dryRunTransaction } = trackRateLimit(_dryRunTransaction);
|
|
3045
3096
|
const strategyInfo = STRATEGY_TYPE_INFO_MAP[strategyType];
|
|
3046
3097
|
const lst = strategyInfo.depositLstCoinType !== undefined
|
|
3047
3098
|
? lstMap[strategyInfo.depositLstCoinType]
|
|
@@ -3049,7 +3100,7 @@ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _a
|
|
|
3049
3100
|
const depositReserves = getStrategyDepositReserves(reserveMap, strategyType);
|
|
3050
3101
|
const borrowReserve = getStrategyBorrowReserve(reserveMap, strategyType);
|
|
3051
3102
|
const defaultCurrencyReserve = getStrategyDefaultCurrencyReserve(reserveMap, strategyType);
|
|
3052
|
-
|
|
3103
|
+
const exposure = getStrategyExposure(reserveMap, lstMap, strategyType, obligation);
|
|
3053
3104
|
console.log(`[strategyAdjust] args |`, JSON.stringify({
|
|
3054
3105
|
_address,
|
|
3055
3106
|
strategyOwnerCapId,
|
|
@@ -3062,31 +3113,56 @@ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _a
|
|
|
3062
3113
|
targetExposure: targetExposure.toFixed(20),
|
|
3063
3114
|
}, null, 2));
|
|
3064
3115
|
//
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
(
|
|
3071
|
-
await strategyRebalanceWithinBorrowLimitTx(reserveMap, lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligation.id, deposits, borrowedAmount, transaction, dryRunTransaction));
|
|
3072
|
-
exposure = getStrategyExposure(reserveMap, lstMap, strategyType, getStrategySimulatedObligation(reserveMap, lstMap, strategyType, deposits, borrowedAmount));
|
|
3073
|
-
}
|
|
3074
|
-
// 2) Loop or unloop to target exposure
|
|
3075
|
-
let result;
|
|
3076
|
-
if (targetExposure.gt(exposure))
|
|
3077
|
-
result = await strategyLoopToExposureTx(reserveMap, lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligation.id, deposits, borrowedAmount, undefined, // Don't pass targetBorrowedAmount
|
|
3116
|
+
const deposits = cloneDeep(_deposits);
|
|
3117
|
+
const borrowedAmount = _borrowedAmount;
|
|
3118
|
+
if (targetExposure.eq(exposure))
|
|
3119
|
+
return { deposits, borrowedAmount, transaction };
|
|
3120
|
+
const loopOrUnloop = (fromDeposits, fromBorrowedAmount, fromExposure, fromTransaction) => targetExposure.gt(fromExposure)
|
|
3121
|
+
? strategyLoopToExposureTx(reserveMap, lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligation.id, fromDeposits, fromBorrowedAmount, undefined, // Don't pass targetBorrowedAmount
|
|
3078
3122
|
targetExposure, // Pass targetExposure
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
result = await strategyUnloopToExposureTx(reserveMap, lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligation.id, deposits, borrowedAmount, undefined, // Don't pass targetBorrowedAmount
|
|
3123
|
+
fromTransaction)
|
|
3124
|
+
: strategyUnloopToExposureTx(reserveMap, lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligation.id, fromDeposits, fromBorrowedAmount, undefined, // Don't pass targetBorrowedAmount
|
|
3082
3125
|
targetExposure, // Pass targetExposure
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3126
|
+
fromTransaction, dryRunTransaction);
|
|
3127
|
+
// 1) Loop or unloop to target exposure
|
|
3128
|
+
let plainError;
|
|
3129
|
+
try {
|
|
3130
|
+
const result = await loopOrUnloop(deposits, borrowedAmount, exposure, Transaction.from(transaction));
|
|
3131
|
+
if (!result.borrowedAmount.eq(borrowedAmount))
|
|
3132
|
+
return result;
|
|
3090
3133
|
}
|
|
3091
|
-
|
|
3134
|
+
catch (err) {
|
|
3135
|
+
plainError = err;
|
|
3136
|
+
}
|
|
3137
|
+
// 2) Above the borrow limit no stepwise withdraw can land, so rebalance and retry
|
|
3138
|
+
if (borrowedAmount.gt(0) &&
|
|
3139
|
+
!isStrategyWithinBorrowLimit(reserveMap, lstMap, strategyType, deposits, borrowedAmount)) {
|
|
3140
|
+
let rebalanced;
|
|
3141
|
+
try {
|
|
3142
|
+
rebalanced = await strategyRebalanceWithinBorrowLimitTx(reserveMap, lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _address, strategyOwnerCapId, obligation.id, deposits, borrowedAmount, Transaction.from(transaction), dryRunTransaction);
|
|
3143
|
+
}
|
|
3144
|
+
catch (err) {
|
|
3145
|
+
console.error(err);
|
|
3146
|
+
}
|
|
3147
|
+
if (rebalanced !== undefined) {
|
|
3148
|
+
const rebalancedExposure = getStrategyExposure(reserveMap, lstMap, strategyType, getStrategySimulatedObligation(reserveMap, lstMap, strategyType, rebalanced.deposits, rebalanced.borrowedAmount));
|
|
3149
|
+
if (targetExposure.eq(rebalancedExposure))
|
|
3150
|
+
return rebalanced;
|
|
3151
|
+
try {
|
|
3152
|
+
const result = await loopOrUnloop(rebalanced.deposits, rebalanced.borrowedAmount, rebalancedExposure, Transaction.from(rebalanced.transaction));
|
|
3153
|
+
return result.borrowedAmount.eq(rebalanced.borrowedAmount)
|
|
3154
|
+
? rebalanced
|
|
3155
|
+
: result;
|
|
3156
|
+
}
|
|
3157
|
+
catch (err) {
|
|
3158
|
+
console.error(err);
|
|
3159
|
+
return rebalanced;
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
}
|
|
3163
|
+
if (rateLimit.exceeded)
|
|
3164
|
+
throw new Error(STRATEGY_RATE_LIMITED_ERROR_MESSAGE);
|
|
3165
|
+
if (plainError !== undefined)
|
|
3166
|
+
throw plainError;
|
|
3167
|
+
throw new Error("Failed to adjust leverage");
|
|
3092
3168
|
};
|