@suilend/sdk 13.7.0-next.ge2ee95d → 13.8.0-next.gd1e5f5b

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.
@@ -457,6 +457,25 @@ export interface SetConfidenceMultiplierBuilderArgs {
457
457
  export declare function setConfidenceMultiplierBuilder(tx: Transaction, args: SetConfidenceMultiplierBuilderArgs, options?: {
458
458
  env?: EnvConfig;
459
459
  }): TransactionResult;
460
+ export interface SetMinConfidenceRatioBuilderArgs {
461
+ builder: TransactionObjectInput;
462
+ minConfidenceRatio: bigint | TransactionArgument;
463
+ }
464
+ /**
465
+ * Seeded by `from` like the confidence multiplier. Must be non-zero, and must stay
466
+ * above the confidence multiplier `k` (see `build`).
467
+ */
468
+ export declare function setMinConfidenceRatioBuilder(tx: Transaction, args: SetMinConfidenceRatioBuilderArgs, options?: {
469
+ env?: EnvConfig;
470
+ }): TransactionResult;
471
+ export interface SetMaxStalenessSecondsBuilderArgs {
472
+ builder: TransactionObjectInput;
473
+ maxStalenessSeconds: bigint | TransactionArgument;
474
+ }
475
+ /** Seeded by `from` like the confidence multiplier. Must be non-zero. */
476
+ export declare function setMaxStalenessSecondsBuilder(tx: Transaction, args: SetMaxStalenessSecondsBuilderArgs, options?: {
477
+ env?: EnvConfig;
478
+ }): TransactionResult;
460
479
  export interface SetArgs {
461
480
  builder: TransactionObjectInput;
462
481
  field: GenericArg;
@@ -531,6 +531,29 @@ export function setConfidenceMultiplierBuilder(tx, args, options) {
531
531
  ],
532
532
  });
533
533
  }
534
+ /**
535
+ * Seeded by `from` like the confidence multiplier. Must be non-zero, and must stay
536
+ * above the confidence multiplier `k` (see `build`).
537
+ */
538
+ export function setMinConfidenceRatioBuilder(tx, args, options) {
539
+ return tx.moveCall({
540
+ target: `${getPublishedAt('suilend', options?.env)}::reserve_config::set_min_confidence_ratio_builder`,
541
+ arguments: [
542
+ obj(tx, args.builder),
543
+ pure(tx, args.minConfidenceRatio, `u64`),
544
+ ],
545
+ });
546
+ }
547
+ /** Seeded by `from` like the confidence multiplier. Must be non-zero. */
548
+ export function setMaxStalenessSecondsBuilder(tx, args, options) {
549
+ return tx.moveCall({
550
+ target: `${getPublishedAt('suilend', options?.env)}::reserve_config::set_max_staleness_seconds_builder`,
551
+ arguments: [
552
+ obj(tx, args.builder),
553
+ pure(tx, args.maxStalenessSeconds, `u64`),
554
+ ],
555
+ });
556
+ }
534
557
  /**
535
558
  * Sets a field in the reserve configuration builder.
536
559
  *
package/client.d.ts CHANGED
@@ -4,6 +4,7 @@ import { Transaction, TransactionArgument, TransactionObjectArgument, Transactio
4
4
  import { SuiPythClient } from "@pythnetwork/pyth-sui-js";
5
5
  import BigNumber from "bignumber.js";
6
6
  import { Decimal } from "./_generated/suilend/decimal/structs";
7
+ import { type ConfidenceShare } from "./utils/simulate";
7
8
  import { LendingMarket, ObligationOwnerCap } from "./_generated/suilend/lending-market/structs";
8
9
  import { Obligation } from "./_generated/suilend/obligation/structs";
9
10
  import { NewConfigArgs as CreateRateLimiterConfigArgs } from "./_generated/suilend/rate-limiter/functions";
@@ -55,6 +56,8 @@ export type ClaimRewardsReward = {
55
56
  };
56
57
  export type PatchReserveConfigArgs = Partial<CreateReserveConfigArgs> & {
57
58
  confidenceMultiplierBps?: bigint | TransactionArgument;
59
+ minConfidenceRatio?: bigint | TransactionArgument;
60
+ maxStalenessSeconds?: bigint | TransactionArgument;
58
61
  };
59
62
  export type LendingMarketObject = {
60
63
  objectId: string;
@@ -103,8 +106,8 @@ export declare class SuilendClient {
103
106
  }>;
104
107
  /** A reserve's confidence multiplier `k`, in bps; pass `parsedReserve.config.additionalFields.id`. 0 when unset. */
105
108
  static getReserveConfidenceMultiplierBps(suiGrpcClient: SuiGrpcClient, additionalFieldsBagId: string): Promise<BigNumber>;
106
- /** A reserve's stored Pyth confidence (the `ConfidenceKey` dynamic field on `reserve.id` directly, not inside `config.additionalFields`). Reads as 0 until the reserve's first price update writes it. */
107
- static getReserveStoredConfidence(suiGrpcClient: SuiGrpcClient, reserveId: string): Promise<BigNumber>;
109
+ /** A reserve's stored Pyth confidence as a share of the spot it was read with, `conf / spot` (the `ConfidenceKey` dynamic field on `reserve.id` directly, not inside `config.additionalFields`). Reads as 0 until the reserve's first price update writes it. */
110
+ static getReserveConfidenceShare(suiGrpcClient: SuiGrpcClient, reserveId: string): Promise<ConfidenceShare>;
108
111
  /** The raw spot and EMA of the reserve's last refresh under a price guard (the `RawPriceKey` dynamic field on `reserve.id`). Undefined until its first refresh under a guard. Attach them with `withUnclampedPrices` only to a reserve as stored on chain, never to one a feed refresh has repriced. */
109
112
  static getReserveRawPrices(suiGrpcClient: SuiGrpcClient, reserveId: string): Promise<{
110
113
  price: Decimal;
package/client.js CHANGED
@@ -5,7 +5,7 @@ import BigNumber from "bignumber.js";
5
5
  import { extractCTokenCoinType, getAllCoins, getSpendableCoin, } from "@suilend/sui-core";
6
6
  import { phantom } from "./_generated/_framework/reified.js";
7
7
  import { Decimal } from "./_generated/suilend/decimal/structs.js";
8
- import { decimalToBigNumber } from "./utils/simulate.js";
8
+ import { confidenceShare, decimalToBigNumber, } from "./utils/simulate.js";
9
9
  import { PKG_V10, setPublishedAt } from "./_generated/suilend/index.js";
10
10
  import { getPublishedAt } from "./_generated/_envs/index.js";
11
11
  import { PACKAGE_ID } from "./_generated/suilend/index.js";
@@ -14,7 +14,7 @@ import { LendingMarket, ObligationOwnerCap, } from "./_generated/suilend/lending
14
14
  import { createLendingMarket } from "./_generated/suilend/lending-market-registry/functions.js";
15
15
  import { Obligation } from "./_generated/suilend/obligation/structs.js";
16
16
  import { newConfig as createRateLimiterConfig, } from "./_generated/suilend/rate-limiter/functions.js";
17
- import { build as buildReserveConfig, createReserveConfig, setBorrowFeeBps, setBorrowLimit, setBorrowLimitUsd, setBorrowWeightBps, setCloseAttributedBorrowLimitUsd, setCloseLtvPct, setConfidenceMultiplierBuilder, setDepositLimit, setDepositLimitUsd, setInterestRateAprs, setInterestRateUtils, setIsolated, setLiquidationBonusBps, setMaxCloseLtvPct, setMaxLiquidationBonusBps, setOpenAttributedBorrowLimitUsd, setOpenLtvPct, setProtocolLiquidationFeeBps, setSpreadFeeBps, } from "./_generated/suilend/reserve-config/functions.js";
17
+ import { build as buildReserveConfig, createReserveConfig, setBorrowFeeBps, setBorrowLimit, setBorrowLimitUsd, setBorrowWeightBps, setCloseAttributedBorrowLimitUsd, setCloseLtvPct, setConfidenceMultiplierBuilder, setDepositLimit, setDepositLimitUsd, setInterestRateAprs, setInterestRateUtils, setIsolated, setLiquidationBonusBps, setMaxCloseLtvPct, setMaxLiquidationBonusBps, setMaxStalenessSecondsBuilder, setMinConfidenceRatioBuilder, setOpenAttributedBorrowLimitUsd, setOpenLtvPct, setProtocolLiquidationFeeBps, setSpreadFeeBps, } from "./_generated/suilend/reserve-config/functions.js";
18
18
  import { addReserveProCompatible, addReserveV2ProCompatible, changeReservePriceFeedProCompatible, priceInfoPublishTime, refreshReservePriceProCompatible, } from "./lib/proCompatible.js";
19
19
  import { resolvePriceUpdateDataSource, } from "./lib/pyth.js";
20
20
  import { Side } from "./lib/types.js";
@@ -467,11 +467,11 @@ export class SuilendClient {
467
467
  });
468
468
  return new BigNumber(bcs.u64().parse(dynamicField.value.bcs));
469
469
  }
470
- /** A reserve's stored Pyth confidence (the `ConfidenceKey` dynamic field on `reserve.id` directly, not inside `config.additionalFields`). Reads as 0 until the reserve's first price update writes it. */
471
- static async getReserveStoredConfidence(suiGrpcClient, reserveId) {
470
+ /** A reserve's stored Pyth confidence as a share of the spot it was read with, `conf / spot` (the `ConfidenceKey` dynamic field on `reserve.id` directly, not inside `config.additionalFields`). Reads as 0 until the reserve's first price update writes it. */
471
+ static async getReserveConfidenceShare(suiGrpcClient, reserveId) {
472
472
  const match = await findBagEntryByTypeSuffix(suiGrpcClient, reserveId, "::reserve::ConfidenceKey");
473
473
  if (!match)
474
- return new BigNumber(0);
474
+ return confidenceShare(new BigNumber(0), new BigNumber(0));
475
475
  const { dynamicField } = await suiGrpcClient.getDynamicField({
476
476
  parentId: reserveId,
477
477
  name: match.name,
@@ -694,6 +694,16 @@ export class SuilendClient {
694
694
  builder,
695
695
  confidenceMultiplierBps: overrides.confidenceMultiplierBps,
696
696
  });
697
+ if (overrides.minConfidenceRatio !== undefined)
698
+ setMinConfidenceRatioBuilder(transaction, {
699
+ builder,
700
+ minConfidenceRatio: overrides.minConfidenceRatio,
701
+ });
702
+ if (overrides.maxStalenessSeconds !== undefined)
703
+ setMaxStalenessSecondsBuilder(transaction, {
704
+ builder,
705
+ maxStalenessSeconds: overrides.maxStalenessSeconds,
706
+ });
697
707
  const [config] = buildReserveConfig(transaction, builder);
698
708
  return this.submitReserveConfigUpdate(lendingMarketOwnerCapId, transaction, coinType, config);
699
709
  }
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@suilend/sdk","version":"13.7.0-next.ge2ee95d","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/interpolate":"./utils/interpolate.js","./utils/obligation":"./utils/obligation.js","./utils/priceGuard":"./utils/priceGuard.js","./utils/simulate":"./utils/simulate.js","./_generated/_envs":"./_generated/_envs/index.js","./_generated/_envs/mainnet":"./_generated/_envs/mainnet.js","./_generated/_framework/env":"./_generated/_framework/env.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/pyth-2/price-identifier/structs":"./_generated/_dependencies/pyth-2/price-identifier/structs.js","./_generated/_dependencies/std/ascii/structs":"./_generated/_dependencies/std/ascii/structs.js","./_generated/_dependencies/std/option/structs":"./_generated/_dependencies/std/option/structs.js","./_generated/_dependencies/std/type-name/structs":"./_generated/_dependencies/std/type-name/structs.js","./_generated/_dependencies/sui/bag/structs":"./_generated/_dependencies/sui/bag/structs.js","./_generated/_dependencies/sui/balance/structs":"./_generated/_dependencies/sui/balance/structs.js","./_generated/_dependencies/sui/object/structs":"./_generated/_dependencies/sui/object/structs.js","./_generated/_dependencies/sui/object-table/structs":"./_generated/_dependencies/sui/object-table/structs.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"},"types":"./index.d.ts","scripts":{"codegen":"node ./codegen.js","codegen:install":"node ./install-codegen.js","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.7.0","@cetusprotocol/aggregator-sdk":"1.7.3","@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.3","uuid":"14.0.2"},"devDependencies":{"@mysten/bcs":"2.1.2","@mysten/sui":"2.35.0","@suilend/sui-core":"2.2.0","@tsconfig/recommended":"1.0.13","@types/bn.js":"5.2.0","@types/lodash":"4.17.26","@types/node":"26.6.5","fast-check":"4.10.2","prettier":"3.9.10","ts-node":"10.9.2","typescript":"6.0.3","vite":"8.3.4","vitest":"5.0.4"},"peerDependencies":{"@mysten/bcs":"^2.1.1","@mysten/sui":">=2.31.3 <3","@suilend/sui-core":"^2.0.1"},"type":"module"}
1
+ {"name":"@suilend/sdk","version":"13.8.0-next.gd1e5f5b","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/interpolate":"./utils/interpolate.js","./utils/obligation":"./utils/obligation.js","./utils/priceGuard":"./utils/priceGuard.js","./utils/simulate":"./utils/simulate.js","./_generated/_envs":"./_generated/_envs/index.js","./_generated/_envs/mainnet":"./_generated/_envs/mainnet.js","./_generated/_framework/env":"./_generated/_framework/env.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/pyth-2/price-identifier/structs":"./_generated/_dependencies/pyth-2/price-identifier/structs.js","./_generated/_dependencies/std/ascii/structs":"./_generated/_dependencies/std/ascii/structs.js","./_generated/_dependencies/std/option/structs":"./_generated/_dependencies/std/option/structs.js","./_generated/_dependencies/std/type-name/structs":"./_generated/_dependencies/std/type-name/structs.js","./_generated/_dependencies/sui/bag/structs":"./_generated/_dependencies/sui/bag/structs.js","./_generated/_dependencies/sui/balance/structs":"./_generated/_dependencies/sui/balance/structs.js","./_generated/_dependencies/sui/object/structs":"./_generated/_dependencies/sui/object/structs.js","./_generated/_dependencies/sui/object-table/structs":"./_generated/_dependencies/sui/object-table/structs.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"},"types":"./index.d.ts","scripts":{"codegen":"node ./codegen.js","codegen:install":"node ./install-codegen.js","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.7.0","@cetusprotocol/aggregator-sdk":"1.7.3","@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.3","uuid":"14.0.2"},"devDependencies":{"@mysten/bcs":"2.1.2","@mysten/sui":"2.35.0","@suilend/sui-core":"2.2.0","@tsconfig/recommended":"1.0.13","@types/bn.js":"5.2.0","@types/lodash":"4.17.26","@types/node":"26.6.5","fast-check":"4.10.2","prettier":"3.9.10","ts-node":"10.9.2","typescript":"6.0.3","vite":"8.3.4","vitest":"5.0.4"},"peerDependencies":{"@mysten/bcs":"^2.1.1","@mysten/sui":">=2.31.3 <3","@suilend/sui-core":"^2.0.1"},"type":"module"}
@@ -1,7 +1,7 @@
1
1
  import { normalizeStructTag } from "@mysten/sui/utils";
2
2
  import BigNumber from "bignumber.js";
3
3
  import { WAD } from "../lib/constants.js";
4
- import { applyConfidenceMargin } from "../utils/simulate.js";
4
+ import { applyConfidenceMargin, confidenceShare } from "../utils/simulate.js";
5
5
  // Reproduces the exact pre-confidence-margin bounds when a caller doesn't
6
6
  // supply the reserve's current multiplier.
7
7
  const ZERO_K_BPS = new BigNumber(0);
@@ -37,7 +37,7 @@ kBps = ZERO_K_BPS) => {
37
37
  ? new BigNumber(event.unclampedSmoothedPrice).div(WAD)
38
38
  : smoothedPrice;
39
39
  const rangePrices = [price, smoothedPrice, unclampedPrice, unclampedSmoothedPrice];
40
- const { lowerBound: minPrice, upperBound: maxPrice } = applyConfidenceMargin(BigNumber.min(...rangePrices), BigNumber.max(...rangePrices), conf, kBps, unclampedPrice);
40
+ const { lowerBound: minPrice, upperBound: maxPrice } = applyConfidenceMargin(BigNumber.min(...rangePrices), BigNumber.max(...rangePrices), confidenceShare(conf, unclampedPrice), kBps);
41
41
  // Custom
42
42
  const utilizationPercent = depositedAmount.eq(0)
43
43
  ? new BigNumber(0)
@@ -2,11 +2,12 @@ import { SuiClientTypes } from "@mysten/sui/client";
2
2
  import BigNumber from "bignumber.js";
3
3
  import { PoolReward, PoolRewardManager } from "../_generated/suilend/liquidity-mining/structs";
4
4
  import { Reserve } from "../_generated/suilend/reserve/structs";
5
+ import * as simulate from "../utils/simulate";
5
6
  export type ParsedReserve = ReturnType<typeof parseReserve>;
6
7
  export type ParsedReserveConfig = ReturnType<typeof parseReserveConfig>;
7
8
  export type ParsedPoolRewardManager = ReturnType<typeof parsePoolRewardManager>;
8
9
  export type ParsedPoolReward = NonNullable<ReturnType<typeof parsePoolReward>>;
9
- export declare const parseReserve: (reserve: Reserve<string>, coinMetadataMap: Record<string, SuiClientTypes.CoinMetadata>, conf?: BigNumber, kBps?: BigNumber) => {
10
+ export declare const parseReserve: (reserve: Reserve<string>, coinMetadataMap: Record<string, SuiClientTypes.CoinMetadata>, share?: simulate.ConfidenceShare, kBps?: BigNumber) => {
10
11
  config: {
11
12
  $typeName: `${string}::reserve_config::ReserveConfig`;
12
13
  openLtvPct: number;
@@ -5,14 +5,14 @@ import { WAD } from "../lib/constants.js";
5
5
  import { toHexString } from "../utils/index.js";
6
6
  import * as simulate from "../utils/simulate.js";
7
7
  export const parseReserve = (reserve, coinMetadataMap,
8
- // The reserve's stored Pyth confidence and its CURRENT confidence
8
+ // The reserve's stored conf / spot share and its CURRENT confidence
9
9
  // multiplier (in bps) -- a ConfidenceKey dynamic field and a
10
10
  // ReserveConfig.additionalFields Bag entry respectively, neither of which
11
11
  // lives on the Reserve object's own BCS content, so this parser can't
12
12
  // fetch them itself without becoming async. Omit either (or both) for
13
13
  // plain bounds. The raw prices of a guarded reserve come attached with
14
14
  // simulate.withUnclampedPrices.
15
- conf, kBps) => {
15
+ share, kBps) => {
16
16
  const config = parseReserveConfig(reserve);
17
17
  const $typeName = reserve.$typeName;
18
18
  const id = reserve.id;
@@ -24,7 +24,9 @@ conf, kBps) => {
24
24
  const price = new BigNumber(reserve.price.value.toString()).div(WAD);
25
25
  const smoothedPrice = new BigNumber(reserve.smoothedPrice.value.toString()).div(WAD);
26
26
  const { low, high } = simulate.priceRange(reserve);
27
- const { lowerBound: minPrice, upperBound: maxPrice } = simulate.applyConfidenceMargin(low, high, conf !== undefined && kBps !== undefined ? conf : new BigNumber(0), kBps ?? new BigNumber(0), simulate.unclampedSpot(reserve));
27
+ const { lowerBound: minPrice, upperBound: maxPrice } = share !== undefined && kBps !== undefined
28
+ ? simulate.applyConfidenceMargin(low, high, share, kBps)
29
+ : { lowerBound: low, upperBound: high };
28
30
  const priceLastUpdateTimestampS = reserve.priceLastUpdateTimestampS;
29
31
  const availableAmount = new BigNumber(reserve.availableAmount.toString()).div(10 ** mintDecimals);
30
32
  const ctokenSupply = new BigNumber(reserve.ctokenSupply.toString()).div(10 ** mintDecimals);
@@ -146,6 +146,16 @@ export type ObligationRefresh = {
146
146
  weightedBorrowedValueUsd: BigNumber;
147
147
  weightedBorrowedValueUpperBoundUsd: BigNumber;
148
148
  };
149
+ /**
150
+ * `conf / spot` from a single price read: what a reserve stores in
151
+ * `ConfidenceKey`. Branded so a USD conf cannot be passed where a share is
152
+ * expected; build one with `confidenceShare`.
153
+ */
154
+ export type ConfidenceShare = BigNumber & {
155
+ readonly __brand: "ConfidenceShare";
156
+ };
157
+ /** Mirrors reserve.move's `record_confidence`: a zero spot records a zero share. */
158
+ export declare const confidenceShare: (conf: BigNumber, spot: BigNumber) => ConfidenceShare;
149
159
  /**
150
160
  * Pure computation half of `refreshObligation`: same math, but returns fresh
151
161
  * deposits/borrows/reward-manager arrays and the five USD aggregates instead
@@ -156,7 +166,7 @@ export type ObligationRefresh = {
156
166
  * holding a reference to it.
157
167
  */
158
168
  export declare function computeObligationRefresh(obligation: Obligation<string>, refreshedReserves: Reserve<string>[], nowMs: number, confidenceByCoinType?: Map<string, {
159
- conf?: BigNumber;
169
+ share: ConfidenceShare | undefined;
160
170
  kBps: BigNumber;
161
171
  }>): ObligationRefresh;
162
172
  export declare const refreshObligation: (unrefreshedObligation: Obligation<string>, refreshedReserves: Reserve<string>[]) => Obligation<string>;
@@ -166,20 +176,20 @@ export declare const decimalToBigNumber: (value: Decimal) => BigNumber;
166
176
  /**
167
177
  * Mirrors reserve.move's `price_lower_bound`/`price_upper_bound`: the one
168
178
  * off-chain place this formula lives. `low` and `high` are the ends of the
169
- * reserve's price range (`priceRange`), which the bounds widen by the share
170
- * `k * conf / spot`, where `spot` is the unclamped spot of the same update
171
- * `conf` came from. `conf` and `kBps` are the reserve's stored
172
- * Pyth confidence and its `ReserveConfig` confidence multiplier (in bps, e.g.
173
- * 30000 for a logical k=3) -- both plain human-scale BigNumbers, not
174
- * WAD-scaled Decimals. `kBps=0` or `conf=0` disables the margin entirely:
175
- * both bounds collapse to `low` and `high`.
179
+ * reserve's price range (`priceRange`), which the bounds widen by
180
+ * `k * share`. `share` is `conf / spot` from a single price read -- what the
181
+ * reserve stores in `ConfidenceKey` -- and `kBps` is its `ReserveConfig`
182
+ * confidence multiplier (in bps, e.g. 30000 for a logical k=3); both are
183
+ * plain human-scale BigNumbers, not WAD-scaled Decimals. `kBps=0` or
184
+ * `share=0` disables the margin entirely: both bounds collapse to `low` and
185
+ * `high`.
176
186
  */
177
- export declare const applyConfidenceMargin: (low: BigNumber, high: BigNumber, conf: BigNumber, kBps: BigNumber, spot: BigNumber) => {
187
+ export declare const applyConfidenceMargin: (low: BigNumber, high: BigNumber, share: ConfidenceShare, kBps: BigNumber) => {
178
188
  lowerBound: BigNumber;
179
189
  upperBound: BigNumber;
180
190
  };
181
191
  export declare const getCTokenMarketValue: (reserve: Reserve<string>, depositedCTokenAmount: BigNumber) => BigNumber;
182
- export declare const getCTokenMarketValueLowerBound: (reserve: Reserve<string>, depositedCTokenAmount: BigNumber, conf?: BigNumber, kBps?: BigNumber) => BigNumber;
192
+ export declare const getCTokenMarketValueLowerBound: (reserve: Reserve<string>, depositedCTokenAmount: BigNumber, share?: ConfidenceShare, kBps?: BigNumber) => BigNumber;
183
193
  export declare const cTokenRatio: (reserve: Reserve<string>) => BigNumber;
184
194
  export declare const totalSupply: (reserve: Reserve<string>) => BigNumber;
185
195
  export declare const compoundBorrowedAmount: (snapshotAmount: BigNumber, currentCumulativeBorrowRate: BigNumber, snapshotCumulativeBorrowRate: BigNumber) => BigNumber;
package/utils/simulate.js CHANGED
@@ -352,18 +352,24 @@ export const findReserveOrThrow = (reserves, coinType) => {
352
352
  // (`v * WAD / 10_000`); dividing in BigNumber here matches that.
353
353
  export const computeBorrowWeight = (config) => new BigNumber(config.borrowWeightBps.toString()).div(10000);
354
354
  export const computeCloseLtv = (config) => new BigNumber(config.closeLtvPct / 100);
355
+ /** Mirrors reserve.move's `record_confidence`: a zero spot records a zero share. */
356
+ export const confidenceShare = (conf, spot) => (spot.isZero() ? new BigNumber(0) : conf.dividedBy(spot));
357
+ const ZERO_SHARE = confidenceShare(new BigNumber(0), new BigNumber(0));
355
358
  const resolveConfidence = (entry, reserve) => {
356
359
  if (entry === undefined)
357
360
  return undefined;
358
361
  const refreshedFromFeed = "feedConfidence" in reserve;
359
- const conf = feedConfidenceOf(reserve) ??
360
- (refreshedFromFeed ? undefined : entry.conf) ??
361
- (entry.kBps.isZero() ? new BigNumber(0) : undefined);
362
- if (conf === undefined)
362
+ const feedConf = feedConfidenceOf(reserve);
363
+ const share = (feedConf !== undefined
364
+ ? confidenceShare(feedConf, unclampedSpot(reserve))
365
+ : undefined) ??
366
+ (refreshedFromFeed ? undefined : entry.share) ??
367
+ (entry.kBps.isZero() ? ZERO_SHARE : undefined);
368
+ if (share === undefined)
363
369
  throw new Error(refreshedFromFeed
364
- ? `Reserve ${reserve.coinType} was refreshed from a feed without conf, so the stored conf is from a different update: use a feed that carries conf`
365
- : `No conf for reserve ${reserve.coinType}: refresh it from a feed that carries conf, or supply conf in the entry`);
366
- return { conf, kBps: entry.kBps };
370
+ ? `Reserve ${reserve.coinType} was refreshed from a feed without conf, so the stored share is from a different update: use a feed that carries conf`
371
+ : `No conf for reserve ${reserve.coinType}: refresh it from a feed that carries conf, or supply the stored share in the entry`);
372
+ return { share, kBps: entry.kBps };
367
373
  };
368
374
  /**
369
375
  * Pure computation half of `refreshObligation`: same math, but returns fresh
@@ -376,12 +382,13 @@ const resolveConfidence = (entry, reserve) => {
376
382
  */
377
383
  export function computeObligationRefresh(obligation, refreshedReserves, nowMs,
378
384
  // Per-reserve CURRENT confidence multiplier, keyed by coinType in either
379
- // raw or normalized form. `conf` is the fallback for a reserve that was never
380
- // price-refreshed; a reserve refreshed from a feed without `conf` throws
381
- // instead (unless kBps is 0), because its price and the stored conf come from
382
- // different updates. A reserve's own `feedConfidence` takes precedence because
383
- // it comes from the same update as its price. A reserve with no entry here
384
- // gets plain min/max(price, smoothedPrice) bounds.
385
+ // raw or normalized form. `share` is the reserve's stored conf / spot
386
+ // (`SuilendClient.getReserveConfidenceShare`), the fallback for a reserve that
387
+ // was never price-refreshed; a reserve refreshed from a feed without `conf`
388
+ // throws instead (unless kBps is 0), because its price and the stored share
389
+ // come from different updates. A reserve's own `feedConfidence` takes
390
+ // precedence because it comes from the same update as its price. A reserve
391
+ // with no entry here gets plain min/max(price, smoothedPrice) bounds.
385
392
  confidenceByCoinType) {
386
393
  const normalizedConfidence = confidenceByCoinType &&
387
394
  new Map([...confidenceByCoinType].map(([coinType, entry]) => [
@@ -400,7 +407,7 @@ confidenceByCoinType) {
400
407
  updateUserRewardManager(reserve.depositsPoolRewardManager, userRewardManagers[Number(deposit.userRewardManagerIndex)], nowMs);
401
408
  const confidence = resolveConfidence(normalizedConfidence?.get(normalizeStructTag(deposit.coinType)), reserve);
402
409
  const marketValue = getCTokenMarketValue(reserve, new BigNumber(deposit.depositedCtokenAmount.toString()));
403
- const marketValueLowerBound = getCTokenMarketValueLowerBound(reserve, new BigNumber(deposit.depositedCtokenAmount.toString()), confidence?.conf, confidence?.kBps);
410
+ const marketValueLowerBound = getCTokenMarketValueLowerBound(reserve, new BigNumber(deposit.depositedCtokenAmount.toString()), confidence?.share, confidence?.kBps);
404
411
  deposit.marketValue = stringToDecimal(marketValue.toString());
405
412
  depositValueUsd = depositValueUsd.plus(new BigNumber(marketValue.toString()));
406
413
  allowedBorrowValueUsd = allowedBorrowValueUsd.plus(marketValueLowerBound.multipliedBy(new BigNumber(config.openLtvPct / 100)));
@@ -435,7 +442,8 @@ confidenceByCoinType) {
435
442
  const confidence = resolveConfidence(normalizedConfidence?.get(normalizeStructTag(unrefreshedBorrow.coinType)), reserve);
436
443
  const { low, high } = priceRange(reserve);
437
444
  const upperBoundPrice = confidence !== undefined
438
- ? applyConfidenceMargin(low, high, confidence.conf, confidence.kBps, unclampedSpot(reserve)).upperBound
445
+ ? applyConfidenceMargin(low, high, confidence.share, confidence.kBps)
446
+ .upperBound
439
447
  : high;
440
448
  // `exactBorrowedAmount` (this borrow's own amount), not
441
449
  // `reserve.borrowedAmount`: the reserve field is the whole reserve's
@@ -495,18 +503,18 @@ export const decimalToBigNumber = (value) => {
495
503
  /**
496
504
  * Mirrors reserve.move's `price_lower_bound`/`price_upper_bound`: the one
497
505
  * off-chain place this formula lives. `low` and `high` are the ends of the
498
- * reserve's price range (`priceRange`), which the bounds widen by the share
499
- * `k * conf / spot`, where `spot` is the unclamped spot of the same update
500
- * `conf` came from. `conf` and `kBps` are the reserve's stored
501
- * Pyth confidence and its `ReserveConfig` confidence multiplier (in bps, e.g.
502
- * 30000 for a logical k=3) -- both plain human-scale BigNumbers, not
503
- * WAD-scaled Decimals. `kBps=0` or `conf=0` disables the margin entirely:
504
- * both bounds collapse to `low` and `high`.
506
+ * reserve's price range (`priceRange`), which the bounds widen by
507
+ * `k * share`. `share` is `conf / spot` from a single price read -- what the
508
+ * reserve stores in `ConfidenceKey` -- and `kBps` is its `ReserveConfig`
509
+ * confidence multiplier (in bps, e.g. 30000 for a logical k=3); both are
510
+ * plain human-scale BigNumbers, not WAD-scaled Decimals. `kBps=0` or
511
+ * `share=0` disables the margin entirely: both bounds collapse to `low` and
512
+ * `high`.
505
513
  */
506
- export const applyConfidenceMargin = (low, high, conf, kBps, spot) => {
507
- if (kBps.isZero() || conf.isZero())
514
+ export const applyConfidenceMargin = (low, high, share, kBps) => {
515
+ if (kBps.isZero() || share.isZero())
508
516
  return { lowerBound: low, upperBound: high };
509
- const fraction = kBps.dividedBy(10_000).multipliedBy(conf).dividedBy(spot);
517
+ const fraction = kBps.dividedBy(10_000).multipliedBy(share);
510
518
  const lowerBound = BigNumber.max(low.minus(low.multipliedBy(fraction)), new BigNumber(0));
511
519
  const upperBound = high.plus(high.multipliedBy(fraction));
512
520
  return { lowerBound, upperBound };
@@ -518,15 +526,14 @@ export const getCTokenMarketValue = (reserve, depositedCTokenAmount) => {
518
526
  .dividedBy(new BigNumber(10 ** reserve.mintDecimals));
519
527
  };
520
528
  export const getCTokenMarketValueLowerBound = (reserve, depositedCTokenAmount,
521
- // The reserve's stored Pyth confidence and its CURRENT confidence
529
+ // The reserve's stored conf / spot share and its CURRENT confidence
522
530
  // multiplier (in bps). Omit either (or both) for the plain
523
531
  // min(price, smoothedPrice) lower bound.
524
- conf, kBps) => {
532
+ share, kBps) => {
525
533
  const liquidityAmount = depositedCTokenAmount.multipliedBy(cTokenRatio(reserve));
526
534
  const { low, high } = priceRange(reserve);
527
- const lowerBoundPrice = conf !== undefined && kBps !== undefined
528
- ? applyConfidenceMargin(low, high, conf, kBps, unclampedSpot(reserve))
529
- .lowerBound
535
+ const lowerBoundPrice = share !== undefined && kBps !== undefined
536
+ ? applyConfidenceMargin(low, high, share, kBps).lowerBound
530
537
  : low;
531
538
  return lowerBoundPrice
532
539
  .multipliedBy(liquidityAmount)