@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 CHANGED
@@ -1 +1 @@
1
- {"name":"@suilend/sdk","version":"11.0.2","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"}
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
- // 1. Withdraws LST to cover borrows
1618
- // - Leftover transferred to user as borrow coinType, e.g. SUI or suiWBTC
1619
- await fullyRepayBorrowsUsingLst(false);
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
- if (borrowedAmount.gt(STRATEGY_E))
2354
- throw new Error("Failed to repay borrows before withdrawing");
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) Transfer SUI to user
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 (