@suilend/sdk 12.3.0-next.g8719037 → 12.3.0-next.gcbeb44e
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/utils/simulate.d.ts +37 -1
- package/utils/simulate.js +61 -14
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@suilend/sdk","version":"12.3.0-next.
|
|
1
|
+
{"name":"@suilend/sdk","version":"12.3.0-next.gcbeb44e","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/utils/simulate.d.ts
CHANGED
|
@@ -197,6 +197,42 @@ export type ObligationHealth = {
|
|
|
197
197
|
* All math stays in BigNumber end-to-end — never construct a `Decimal` from
|
|
198
198
|
* a stored quantity; `numberToDecimal`/`stringToDecimal` round through a JS
|
|
199
199
|
* `number` (`Math.round`) and are lossy at WAD scale. `decimalToBigNumber` is
|
|
200
|
-
* only ever called on a genuine on-chain `Reserve` field
|
|
200
|
+
* only ever called on a genuine on-chain `Reserve` field, in
|
|
201
|
+
* `buildReserveHealthTable`.
|
|
202
|
+
*
|
|
203
|
+
* Per-position operation order matches `getCTokenMarketValue` and
|
|
204
|
+
* `compoundBorrowedAmount` exactly, so the result is bit-identical to
|
|
205
|
+
* recomputing every reserve value per position; reordering the divisions
|
|
206
|
+
* would round differently and can flip a verdict at the threshold.
|
|
207
|
+
*/
|
|
208
|
+
export declare function computeObligationHealth(deposits: ObligationHealthDepositInput[], borrows: ObligationHealthBorrowInput[], reserveHealth: ReserveHealthTable): ObligationHealth;
|
|
209
|
+
export type ReserveDepositHealthValues = {
|
|
210
|
+
price: BigNumber;
|
|
211
|
+
cTokenRatio: BigNumber;
|
|
212
|
+
mintScale: BigNumber;
|
|
213
|
+
closeLtv: BigNumber;
|
|
214
|
+
};
|
|
215
|
+
export type ReserveBorrowHealthValues = {
|
|
216
|
+
price: BigNumber;
|
|
217
|
+
mintScale: BigNumber;
|
|
218
|
+
cumulativeBorrowRate: BigNumber;
|
|
219
|
+
borrowWeight: BigNumber;
|
|
220
|
+
};
|
|
221
|
+
/**
|
|
222
|
+
* Each lookup throws, as `findReserveOrThrow` does, when no reserve has
|
|
223
|
+
* this coin type. The two sides are separate so a reserve is only read for
|
|
224
|
+
* the fields its positions actually use.
|
|
225
|
+
*/
|
|
226
|
+
export type ReserveHealthTable = {
|
|
227
|
+
deposit: (coinType: string) => ReserveDepositHealthValues;
|
|
228
|
+
borrow: (coinType: string) => ReserveBorrowHealthValues;
|
|
229
|
+
};
|
|
230
|
+
/**
|
|
231
|
+
* The per-reserve inputs to `computeObligationHealth`, derived once per
|
|
232
|
+
* reserve and side on first lookup instead of once per position. Build one
|
|
233
|
+
* per pass over a fixed set of priced reserves and drop it after: the values
|
|
234
|
+
* are a snapshot, and a caller that later rewrites a reserve's price in place
|
|
235
|
+
* would otherwise keep reading the old one.
|
|
201
236
|
*/
|
|
237
|
+
export declare function buildReserveHealthTable(reserves: Reserve<string>[]): ReserveHealthTable;
|
|
202
238
|
export declare function computeObligationHealthFromPositions(deposits: ObligationHealthDepositInput[], borrows: ObligationHealthBorrowInput[], refreshedReserves: Reserve<string>[]): ObligationHealth;
|
package/utils/simulate.js
CHANGED
|
@@ -507,28 +507,32 @@ export const compoundDebt = (borrow, reserve) => {
|
|
|
507
507
|
* All math stays in BigNumber end-to-end — never construct a `Decimal` from
|
|
508
508
|
* a stored quantity; `numberToDecimal`/`stringToDecimal` round through a JS
|
|
509
509
|
* `number` (`Math.round`) and are lossy at WAD scale. `decimalToBigNumber` is
|
|
510
|
-
* only ever called on a genuine on-chain `Reserve` field
|
|
510
|
+
* only ever called on a genuine on-chain `Reserve` field, in
|
|
511
|
+
* `buildReserveHealthTable`.
|
|
512
|
+
*
|
|
513
|
+
* Per-position operation order matches `getCTokenMarketValue` and
|
|
514
|
+
* `compoundBorrowedAmount` exactly, so the result is bit-identical to
|
|
515
|
+
* recomputing every reserve value per position; reordering the divisions
|
|
516
|
+
* would round differently and can flip a verdict at the threshold.
|
|
511
517
|
*/
|
|
512
|
-
export function
|
|
518
|
+
export function computeObligationHealth(deposits, borrows, reserveHealth) {
|
|
513
519
|
let depositValueUsd = new BigNumber(0);
|
|
514
520
|
let unhealthyBorrowValueUsd = new BigNumber(0);
|
|
515
521
|
for (const deposit of deposits) {
|
|
516
|
-
const reserve =
|
|
517
|
-
const
|
|
518
|
-
|
|
522
|
+
const reserve = reserveHealth.deposit(deposit.coinType);
|
|
523
|
+
const marketValue = reserve.price
|
|
524
|
+
.multipliedBy(deposit.depositedCtokenAmount.multipliedBy(reserve.cTokenRatio))
|
|
525
|
+
.dividedBy(reserve.mintScale);
|
|
519
526
|
depositValueUsd = depositValueUsd.plus(marketValue);
|
|
520
|
-
unhealthyBorrowValueUsd = unhealthyBorrowValueUsd.plus(marketValue.multipliedBy(
|
|
527
|
+
unhealthyBorrowValueUsd = unhealthyBorrowValueUsd.plus(marketValue.multipliedBy(reserve.closeLtv));
|
|
521
528
|
}
|
|
522
529
|
let weightedBorrowedValueUsd = new BigNumber(0);
|
|
523
530
|
for (const borrow of borrows) {
|
|
524
|
-
const reserve =
|
|
525
|
-
const
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
.dividedBy(new BigNumber(10 ** reserve.mintDecimals));
|
|
530
|
-
const borrowWeight = computeBorrowWeight(config);
|
|
531
|
-
weightedBorrowedValueUsd = weightedBorrowedValueUsd.plus(marketValue.multipliedBy(borrowWeight));
|
|
531
|
+
const reserve = reserveHealth.borrow(borrow.coinType);
|
|
532
|
+
const marketValue = compoundBorrowedAmount(borrow.borrowedAmountUnderlying, reserve.cumulativeBorrowRate, borrow.cumulativeBorrowRateAtSnapshot)
|
|
533
|
+
.multipliedBy(reserve.price)
|
|
534
|
+
.dividedBy(reserve.mintScale);
|
|
535
|
+
weightedBorrowedValueUsd = weightedBorrowedValueUsd.plus(marketValue.multipliedBy(reserve.borrowWeight));
|
|
532
536
|
}
|
|
533
537
|
return {
|
|
534
538
|
depositedValueUsd: depositValueUsd,
|
|
@@ -536,3 +540,46 @@ export function computeObligationHealthFromPositions(deposits, borrows, refreshe
|
|
|
536
540
|
weightedBorrowedValueUsd,
|
|
537
541
|
};
|
|
538
542
|
}
|
|
543
|
+
const memoizeByCoinType = (derive) => {
|
|
544
|
+
const byCoinType = new Map();
|
|
545
|
+
return (coinType) => {
|
|
546
|
+
let values = byCoinType.get(coinType);
|
|
547
|
+
if (values === undefined) {
|
|
548
|
+
values = derive(coinType);
|
|
549
|
+
byCoinType.set(coinType, values);
|
|
550
|
+
}
|
|
551
|
+
return values;
|
|
552
|
+
};
|
|
553
|
+
};
|
|
554
|
+
/**
|
|
555
|
+
* The per-reserve inputs to `computeObligationHealth`, derived once per
|
|
556
|
+
* reserve and side on first lookup instead of once per position. Build one
|
|
557
|
+
* per pass over a fixed set of priced reserves and drop it after: the values
|
|
558
|
+
* are a snapshot, and a caller that later rewrites a reserve's price in place
|
|
559
|
+
* would otherwise keep reading the old one.
|
|
560
|
+
*/
|
|
561
|
+
export function buildReserveHealthTable(reserves) {
|
|
562
|
+
return {
|
|
563
|
+
deposit: memoizeByCoinType((coinType) => {
|
|
564
|
+
const reserve = findReserveOrThrow(reserves, coinType);
|
|
565
|
+
return {
|
|
566
|
+
price: decimalToBigNumber(reserve.price),
|
|
567
|
+
cTokenRatio: cTokenRatio(reserve),
|
|
568
|
+
mintScale: new BigNumber(10 ** reserve.mintDecimals),
|
|
569
|
+
closeLtv: computeCloseLtv(reserve.config.element),
|
|
570
|
+
};
|
|
571
|
+
}),
|
|
572
|
+
borrow: memoizeByCoinType((coinType) => {
|
|
573
|
+
const reserve = findReserveOrThrow(reserves, coinType);
|
|
574
|
+
return {
|
|
575
|
+
price: decimalToBigNumber(reserve.price),
|
|
576
|
+
mintScale: new BigNumber(10 ** reserve.mintDecimals),
|
|
577
|
+
cumulativeBorrowRate: decimalToBigNumber(reserve.cumulativeBorrowRate),
|
|
578
|
+
borrowWeight: computeBorrowWeight(reserve.config.element),
|
|
579
|
+
};
|
|
580
|
+
}),
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
export function computeObligationHealthFromPositions(deposits, borrows, refreshedReserves) {
|
|
584
|
+
return computeObligationHealth(deposits, borrows, buildReserveHealthTable(refreshedReserves));
|
|
585
|
+
}
|