@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.
- package/_generated/suilend/reserve-config/functions.d.ts +19 -0
- package/_generated/suilend/reserve-config/functions.js +23 -0
- package/client.d.ts +5 -2
- package/client.js +15 -5
- package/package.json +1 -1
- package/parsers/apiReserveAssetDataEvent.js +2 -2
- package/parsers/reserve.d.ts +2 -1
- package/parsers/reserve.js +5 -3
- package/utils/simulate.d.ts +20 -10
- package/utils/simulate.js +37 -30
|
@@ -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
|
|
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
|
|
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.
|
|
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,
|
|
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)
|
package/parsers/reserve.d.ts
CHANGED
|
@@ -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>,
|
|
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;
|
package/parsers/reserve.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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 } =
|
|
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);
|
package/utils/simulate.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
170
|
-
* `k * conf / spot
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
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,
|
|
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,
|
|
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
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
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
|
|
365
|
-
: `No conf for reserve ${reserve.coinType}: refresh it from a feed that carries conf, or supply
|
|
366
|
-
return {
|
|
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. `
|
|
380
|
-
//
|
|
381
|
-
//
|
|
382
|
-
//
|
|
383
|
-
//
|
|
384
|
-
//
|
|
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?.
|
|
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.
|
|
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
|
|
499
|
-
* `k * conf / spot
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
*
|
|
504
|
-
*
|
|
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,
|
|
507
|
-
if (kBps.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(
|
|
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
|
|
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
|
-
|
|
532
|
+
share, kBps) => {
|
|
525
533
|
const liquidityAmount = depositedCTokenAmount.multipliedBy(cTokenRatio(reserve));
|
|
526
534
|
const { low, high } = priceRange(reserve);
|
|
527
|
-
const lowerBoundPrice =
|
|
528
|
-
? applyConfidenceMargin(low, high,
|
|
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)
|