@suilend/sdk 11.0.2 → 11.0.4-next.g598aed2
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 +1 -0
- package/strategies.js +108 -6
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@suilend/sdk","version":"11.0.
|
|
1
|
+
{"name":"@suilend/sdk","version":"11.0.4-next.g598aed2","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.5.0","@cetusprotocol/aggregator-sdk":"^1.5.7","@flowx-finance/sdk":"^2.1.0","@pythnetwork/hermes-client":"3.1.0","@pythnetwork/pyth-sui-js":"4.0.0","@suilend/springsui-sdk":"^4.0.0","bignumber.js":"^11.1.5","bn.js":"^5.2.2","crypto-js":"^4.2.0","lodash":"^4.17.21","p-limit":"7.3.1","uuid":"^14.0.1"},"devDependencies":{"@mysten/bcs":"^2.0.5","@mysten/sui":"2.23.2","@suilend/sui-core":"^1.0.0","@tsconfig/recommended":"^1.0.8","@types/bn.js":"^5.2.0","@types/lodash":"^4.17.25","@types/node":"^26.2.0","fast-check":"^4.9.0","prettier":"^3.3.3","ts-node":"^10.9.2","typescript":"^6.0.3","vitest":"4.1.10"},"peerDependencies":{"@mysten/bcs":"^2.0.5","@mysten/sui":">=2.22.1 <3","@suilend/sui-core":"^1.0.0"},"type":"module"}
|
package/strategies.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { RewardMap } from "./lib/liquidityMining";
|
|
|
11
11
|
import { StrategyType } from "./lib/strategyOwnerCap";
|
|
12
12
|
import { ParsedObligation, ParsedReserve } from "./parsers";
|
|
13
13
|
export declare const STRATEGY_E: number;
|
|
14
|
+
export declare const STRATEGY_FLASH_REPAY_MAX_RESIDUAL_USD = 0.1;
|
|
14
15
|
/**
|
|
15
16
|
* Below this, a levered position is uneconomic no matter what the slippage
|
|
16
17
|
* tolerance says. The aggregator's dust regime dominates: routes go multi-hop
|
package/strategies.js
CHANGED
|
@@ -12,6 +12,7 @@ import { STRATEGY_TYPE_INFO_MAP, StrategyType, strategyBorrow, strategyClaimRewa
|
|
|
12
12
|
import { MMT_CONTRACT_PACKAGE_ID, MMT_VERSION_OBJECT_ID } from "./mmt.js";
|
|
13
13
|
import { getWeightedBorrowsUsd } from "./utils/index.js";
|
|
14
14
|
export const STRATEGY_E = 10 ** -7;
|
|
15
|
+
export const STRATEGY_FLASH_REPAY_MAX_RESIDUAL_USD = 0.1;
|
|
15
16
|
/**
|
|
16
17
|
* Cetus applies its slippage check against its OWN quote, so a wrong quote yields
|
|
17
18
|
* a wrong floor. Measured on a mainnet unwind of a sub-dollar position: the
|
|
@@ -1594,6 +1595,9 @@ transaction, dryRunTransaction) => {
|
|
|
1594
1595
|
}
|
|
1595
1596
|
// Borrows almost fully repaid
|
|
1596
1597
|
if (pendingBorrowedAmount.lte(STRATEGY_E)) {
|
|
1598
|
+
const transactionBeforeFullRepay = Transaction.from(transaction);
|
|
1599
|
+
const depositsBeforeFullRepay = cloneDeep(deposits);
|
|
1600
|
+
const borrowedAmountBeforeFullRepay = borrowedAmount;
|
|
1597
1601
|
try {
|
|
1598
1602
|
// 1. Withdraws LST to cover borrows
|
|
1599
1603
|
// - Leftover transferred to user as borrow coinType, e.g. SUI or suiWBTC
|
|
@@ -1603,6 +1607,9 @@ transaction, dryRunTransaction) => {
|
|
|
1603
1607
|
}
|
|
1604
1608
|
catch (err) {
|
|
1605
1609
|
console.error(err);
|
|
1610
|
+
transaction = transactionBeforeFullRepay;
|
|
1611
|
+
deposits = depositsBeforeFullRepay;
|
|
1612
|
+
borrowedAmount = borrowedAmountBeforeFullRepay;
|
|
1606
1613
|
}
|
|
1607
1614
|
// 1. MAX withdraws LST (transferred to user as SUI)
|
|
1608
1615
|
// 2. Withdraws base to cover borrows
|
|
@@ -1614,9 +1621,20 @@ transaction, dryRunTransaction) => {
|
|
|
1614
1621
|
else {
|
|
1615
1622
|
// Borrows almost fully repaid
|
|
1616
1623
|
if (pendingBorrowedAmount.lte(STRATEGY_E)) {
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1624
|
+
const transactionBeforeFullRepay = Transaction.from(transaction);
|
|
1625
|
+
const depositsBeforeFullRepay = cloneDeep(deposits);
|
|
1626
|
+
const borrowedAmountBeforeFullRepay = borrowedAmount;
|
|
1627
|
+
try {
|
|
1628
|
+
// 1. Withdraws LST to cover borrows
|
|
1629
|
+
// - Leftover transferred to user as borrow coinType, e.g. SUI or suiWBTC
|
|
1630
|
+
await fullyRepayBorrowsUsingLst(false);
|
|
1631
|
+
}
|
|
1632
|
+
catch (err) {
|
|
1633
|
+
console.error(err);
|
|
1634
|
+
transaction = transactionBeforeFullRepay;
|
|
1635
|
+
deposits = depositsBeforeFullRepay;
|
|
1636
|
+
borrowedAmount = borrowedAmountBeforeFullRepay;
|
|
1637
|
+
}
|
|
1620
1638
|
break;
|
|
1621
1639
|
}
|
|
1622
1640
|
}
|
|
@@ -2350,8 +2368,55 @@ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _a
|
|
|
2350
2368
|
// the borrows are gone. The unloop stops early if a step cannot land, so check
|
|
2351
2369
|
// rather than build a transaction that is certain to abort on the health check —
|
|
2352
2370
|
// the caller can surface this instead of asking the user to sign it.
|
|
2353
|
-
|
|
2354
|
-
|
|
2371
|
+
let flashLoan;
|
|
2372
|
+
if (borrowedAmount.gt(STRATEGY_E)) {
|
|
2373
|
+
const flashLoanObj = STRATEGY_TYPE_FLASH_LOAN_OBJ_MAP[strategyType];
|
|
2374
|
+
if (flashLoanObj.provider !== StrategyFlashLoanProvider.MMT ||
|
|
2375
|
+
flashLoanObj.borrowA ||
|
|
2376
|
+
depositReserves.base !== undefined ||
|
|
2377
|
+
depositReserves.lst === undefined ||
|
|
2378
|
+
flashLoanObj.coinTypeB !== borrowReserve.coinType ||
|
|
2379
|
+
!isSui(borrowReserve.coinType) ||
|
|
2380
|
+
!isSui(withdrawCoinType) ||
|
|
2381
|
+
borrowedAmount
|
|
2382
|
+
.times(borrowReserve.price)
|
|
2383
|
+
.gte(STRATEGY_FLASH_REPAY_MAX_RESIDUAL_USD))
|
|
2384
|
+
throw new Error("Failed to repay borrows before withdrawing");
|
|
2385
|
+
const flashLoanBorrowedAmount = borrowedAmount
|
|
2386
|
+
.times(1.1)
|
|
2387
|
+
.decimalPlaces(borrowReserve.token.decimals, BigNumber.ROUND_UP);
|
|
2388
|
+
console.log(`[strategyMaxWithdraw] flash_repay |`, JSON.stringify({
|
|
2389
|
+
borrowedAmount: borrowedAmount.toFixed(20),
|
|
2390
|
+
flashLoanBorrowedAmount: flashLoanBorrowedAmount.toFixed(20),
|
|
2391
|
+
}));
|
|
2392
|
+
const flashLoanBorrowedMist = flashLoanBorrowedAmount
|
|
2393
|
+
.times(10 ** borrowReserve.token.decimals)
|
|
2394
|
+
.integerValue(BigNumber.ROUND_UP)
|
|
2395
|
+
.toString();
|
|
2396
|
+
const [borrowedBalanceA, borrowedBalanceB, receipt] = transaction.moveCall({
|
|
2397
|
+
target: `${MMT_CONTRACT_PACKAGE_ID}::trade::flash_loan`,
|
|
2398
|
+
typeArguments: [flashLoanObj.coinTypeA, flashLoanObj.coinTypeB],
|
|
2399
|
+
arguments: [
|
|
2400
|
+
transaction.object(flashLoanObj.poolId),
|
|
2401
|
+
transaction.pure.u64(0),
|
|
2402
|
+
transaction.pure.u64(flashLoanBorrowedMist),
|
|
2403
|
+
transaction.object(MMT_VERSION_OBJECT_ID),
|
|
2404
|
+
],
|
|
2405
|
+
});
|
|
2406
|
+
const flashLoanBorrowedCoin = transaction.moveCall({
|
|
2407
|
+
target: "0x2::coin::from_balance",
|
|
2408
|
+
typeArguments: [flashLoanObj.coinTypeB],
|
|
2409
|
+
arguments: [borrowedBalanceB],
|
|
2410
|
+
});
|
|
2411
|
+
suilendClient.repay(obligationId, borrowReserve.coinType, flashLoanBorrowedCoin, transaction);
|
|
2412
|
+
borrowedAmount = new BigNumber(0);
|
|
2413
|
+
flashLoan = {
|
|
2414
|
+
obj: flashLoanObj,
|
|
2415
|
+
receipt,
|
|
2416
|
+
borrowedBalanceA,
|
|
2417
|
+
remainingCoin: flashLoanBorrowedCoin,
|
|
2418
|
+
};
|
|
2419
|
+
}
|
|
2355
2420
|
const estimatedWithdrawnAmount = deposits.find((d) => d.coinType === depositReserve.coinType)
|
|
2356
2421
|
?.depositedAmount ?? new BigNumber(0);
|
|
2357
2422
|
const [withdrawnCoin] = strategyWithdraw(strategyType, depositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserve.coinType), BigInt(MAX_U64.toString()), transaction);
|
|
@@ -2403,7 +2468,35 @@ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _a
|
|
|
2403
2468
|
if (isSui(withdrawCoinType)) {
|
|
2404
2469
|
// 3.1) Unstake LST for SUI
|
|
2405
2470
|
const suiWithdrawnCoin = lst.client.redeem(transaction, withdrawnCoin);
|
|
2406
|
-
// 3.2)
|
|
2471
|
+
// 3.2) Repay flash loan + fee
|
|
2472
|
+
if (flashLoan !== undefined) {
|
|
2473
|
+
transaction.mergeCoins(suiWithdrawnCoin, [flashLoan.remainingCoin]);
|
|
2474
|
+
const receiptDebts = transaction.moveCall({
|
|
2475
|
+
target: `${MMT_CONTRACT_PACKAGE_ID}::trade::flash_receipt_debts`,
|
|
2476
|
+
typeArguments: [],
|
|
2477
|
+
arguments: [flashLoan.receipt],
|
|
2478
|
+
});
|
|
2479
|
+
const [flashLoanRepayCoin] = transaction.splitCoins(suiWithdrawnCoin, [
|
|
2480
|
+
receiptDebts[1],
|
|
2481
|
+
]);
|
|
2482
|
+
const flashLoanRepayBalance = transaction.moveCall({
|
|
2483
|
+
target: "0x2::coin::into_balance",
|
|
2484
|
+
typeArguments: [flashLoan.obj.coinTypeB],
|
|
2485
|
+
arguments: [flashLoanRepayCoin],
|
|
2486
|
+
});
|
|
2487
|
+
transaction.moveCall({
|
|
2488
|
+
target: `${MMT_CONTRACT_PACKAGE_ID}::trade::repay_flash_loan`,
|
|
2489
|
+
typeArguments: [flashLoan.obj.coinTypeA, flashLoan.obj.coinTypeB],
|
|
2490
|
+
arguments: [
|
|
2491
|
+
transaction.object(flashLoan.obj.poolId),
|
|
2492
|
+
flashLoan.receipt,
|
|
2493
|
+
flashLoan.borrowedBalanceA,
|
|
2494
|
+
flashLoanRepayBalance,
|
|
2495
|
+
transaction.object(MMT_VERSION_OBJECT_ID),
|
|
2496
|
+
],
|
|
2497
|
+
});
|
|
2498
|
+
}
|
|
2499
|
+
// 3.3) Transfer SUI to user
|
|
2407
2500
|
transaction.transferObjects([suiWithdrawnCoin], _address);
|
|
2408
2501
|
}
|
|
2409
2502
|
else {
|
|
@@ -2428,6 +2521,15 @@ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _a
|
|
|
2428
2521
|
transaction = transactionBeforeClaim;
|
|
2429
2522
|
}
|
|
2430
2523
|
}
|
|
2524
|
+
if (flashLoan !== undefined || borrowedAmount.gt(0)) {
|
|
2525
|
+
try {
|
|
2526
|
+
await dryRunTransaction(transaction);
|
|
2527
|
+
}
|
|
2528
|
+
catch (err) {
|
|
2529
|
+
console.error(err);
|
|
2530
|
+
throw new Error("Failed to repay borrows before withdrawing");
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2431
2533
|
return { deposits, borrowedAmount, transaction };
|
|
2432
2534
|
};
|
|
2433
2535
|
export const strategyAdjustRepayTx = async (
|