@suilend/sdk 11.0.3-next.g4f0ea35 → 11.0.4
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 +102 -6
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@suilend/sdk","version":"11.0.
|
|
1
|
+
{"name":"@suilend/sdk","version":"11.0.4","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
|
|
@@ -1620,9 +1621,20 @@ transaction, dryRunTransaction) => {
|
|
|
1620
1621
|
else {
|
|
1621
1622
|
// Borrows almost fully repaid
|
|
1622
1623
|
if (pendingBorrowedAmount.lte(STRATEGY_E)) {
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
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
|
+
}
|
|
1626
1638
|
break;
|
|
1627
1639
|
}
|
|
1628
1640
|
}
|
|
@@ -2356,8 +2368,55 @@ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _a
|
|
|
2356
2368
|
// the borrows are gone. The unloop stops early if a step cannot land, so check
|
|
2357
2369
|
// rather than build a transaction that is certain to abort on the health check —
|
|
2358
2370
|
// the caller can surface this instead of asking the user to sign it.
|
|
2359
|
-
|
|
2360
|
-
|
|
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
|
+
}
|
|
2361
2420
|
const estimatedWithdrawnAmount = deposits.find((d) => d.coinType === depositReserve.coinType)
|
|
2362
2421
|
?.depositedAmount ?? new BigNumber(0);
|
|
2363
2422
|
const [withdrawnCoin] = strategyWithdraw(strategyType, depositReserve.coinType, strategyOwnerCapId, suilendClient.findReserveArrayIndex(depositReserve.coinType), BigInt(MAX_U64.toString()), transaction);
|
|
@@ -2409,7 +2468,35 @@ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _a
|
|
|
2409
2468
|
if (isSui(withdrawCoinType)) {
|
|
2410
2469
|
// 3.1) Unstake LST for SUI
|
|
2411
2470
|
const suiWithdrawnCoin = lst.client.redeem(transaction, withdrawnCoin);
|
|
2412
|
-
// 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
|
|
2413
2500
|
transaction.transferObjects([suiWithdrawnCoin], _address);
|
|
2414
2501
|
}
|
|
2415
2502
|
else {
|
|
@@ -2434,6 +2521,15 @@ lstMap, strategyType, suiGrpcClient, suilendClient, cetusSdk, cetusPartnerId, _a
|
|
|
2434
2521
|
transaction = transactionBeforeClaim;
|
|
2435
2522
|
}
|
|
2436
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
|
+
}
|
|
2437
2533
|
return { deposits, borrowedAmount, transaction };
|
|
2438
2534
|
};
|
|
2439
2535
|
export const strategyAdjustRepayTx = async (
|