@suilend/sdk 1.1.83 → 1.1.85
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/client.js +1 -2
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/lib/initialize.js +0 -2
- package/lib/strategyOwnerCap.d.ts +3 -2
- package/lib/strategyOwnerCap.js +31 -10
- package/package.json +1 -1
- package/parsers/apiReserveAssetDataEvent.d.ts +2 -0
- package/parsers/apiReserveAssetDataEvent.js +1 -0
- package/strategies.d.ts +263 -0
- package/strategies.js +402 -0
package/client.js
CHANGED
|
@@ -638,8 +638,7 @@ class SuilendClient {
|
|
|
638
638
|
for (const ctokenCoinType of ctokenCoinTypes) {
|
|
639
639
|
const coins = yield (0, sui_fe_1.getAllCoins)(this.client, ownerId, ctokenCoinType);
|
|
640
640
|
const mergeCoin = (0, sui_fe_1.mergeAllCoins)(ctokenCoinType, transaction, coins);
|
|
641
|
-
|
|
642
|
-
mergeCoinMap[ctokenCoinType] = mergeCoin;
|
|
641
|
+
mergeCoinMap[ctokenCoinType] = mergeCoin;
|
|
643
642
|
}
|
|
644
643
|
for (const [ctokenCoinType, mergeCoin] of Object.entries(mergeCoinMap)) {
|
|
645
644
|
const coinType = (0, sui_fe_1.extractCTokenCoinType)(ctokenCoinType);
|
package/index.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -17,6 +17,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
__exportStar(require("./api"), exports);
|
|
18
18
|
__exportStar(require("./lib"), exports);
|
|
19
19
|
__exportStar(require("./parsers"), exports);
|
|
20
|
+
__exportStar(require("./strategies"), exports);
|
|
20
21
|
__exportStar(require("./swap"), exports);
|
|
21
22
|
__exportStar(require("./utils"), exports);
|
|
22
23
|
__exportStar(require("./client"), exports);
|
package/lib/initialize.js
CHANGED
|
@@ -92,12 +92,10 @@ exports.RESERVES_CUSTOM_ORDER = [
|
|
|
92
92
|
sui_fe_1.NORMALIZED_NS_COINTYPE,
|
|
93
93
|
sui_fe_1.NORMALIZED_UP_COINTYPE,
|
|
94
94
|
sui_fe_1.NORMALIZED_DMC_COINTYPE,
|
|
95
|
-
sui_fe_1.NORMALIZED_STRAT_COINTYPE,
|
|
96
95
|
sui_fe_1.NORMALIZED_ALKIMI_COINTYPE,
|
|
97
96
|
sui_fe_1.NORMALIZED_KOBAN_COINTYPE,
|
|
98
97
|
sui_fe_1.NORMALIZED_mUSD_COINTYPE,
|
|
99
98
|
sui_fe_1.NORMALIZED_BUCK_COINTYPE,
|
|
100
|
-
// ISOLATED ASSETS - Memecoins
|
|
101
99
|
sui_fe_1.NORMALIZED_HIPPO_COINTYPE,
|
|
102
100
|
sui_fe_1.NORMALIZED_FUD_COINTYPE,
|
|
103
101
|
];
|
|
@@ -10,7 +10,8 @@ export declare enum StrategyType {
|
|
|
10
10
|
USDC_sSUI_SUI_LOOPING = "3",
|
|
11
11
|
AUSD_sSUI_SUI_LOOPING = "4",
|
|
12
12
|
xBTC_sSUI_SUI_LOOPING = "100",// Used to be for Slush Strategies #0
|
|
13
|
-
xBTC_wBTC_LOOPING = "101"
|
|
13
|
+
xBTC_wBTC_LOOPING = "101",// Used to be for Slush Strategies #1
|
|
14
|
+
suiUSDT_sSUI_SUI_LOOPING = "5"
|
|
14
15
|
}
|
|
15
16
|
export declare const STRATEGY_TYPE_INFO_MAP: Record<StrategyType, {
|
|
16
17
|
queryParam: string;
|
|
@@ -29,7 +30,7 @@ export declare const STRATEGY_TYPE_INFO_MAP: Record<StrategyType, {
|
|
|
29
30
|
export declare const strategyDeposit: (coin: TransactionObjectInput, coinType: string, strategyOwnerCap: TransactionObjectInput, reserveArrayIndex: bigint, transaction: Transaction) => TransactionResult;
|
|
30
31
|
export declare const strategyBorrow: (coinType: string, strategyOwnerCap: TransactionObjectInput, reserveArrayIndex: bigint, value: bigint, transaction: Transaction) => TransactionResult;
|
|
31
32
|
export declare const strategyWithdraw: (coinType: string, strategyOwnerCap: TransactionObjectInput, reserveArrayIndex: bigint, value: bigint, transaction: Transaction) => TransactionResult;
|
|
32
|
-
export declare const strategyClaimRewardsAndSwapForCoinType: (address: string, cetusSdk: CetusSdk, cetusPartnerId: string, rewardsMap: RewardsMap, depositReserve: ParsedReserve, strategyOwnerCap: TransactionObjectInput, isDepositing: boolean, transaction: Transaction) => Promise<void>;
|
|
33
|
+
export declare const strategyClaimRewardsAndSwapForCoinType: (address: string, cetusSdk: CetusSdk, cetusPartnerId: string, rewardsMap: RewardsMap, rewardPriceMap: Record<string, BigNumber | undefined>, depositReserve: ParsedReserve, strategyOwnerCap: TransactionObjectInput, isDepositing: boolean, transaction: Transaction) => Promise<void>;
|
|
33
34
|
export declare const strategySwapSomeDepositsForCoinType: (strategyType: StrategyType, cetusSdk: CetusSdk, cetusPartnerId: string, obligation: ParsedObligation, noSwapCoinTypes: string[], // coinTypes to not swap for depositReserve.coinType
|
|
34
35
|
swapPercent: BigNumber, // percent of deposit to swap for depositReserve.coinType (0-100)
|
|
35
36
|
depositReserve: ParsedReserve, strategyOwnerCap: TransactionObjectInput, transaction: Transaction) => Promise<void>;
|
package/lib/strategyOwnerCap.js
CHANGED
|
@@ -20,7 +20,7 @@ const sui_fe_1 = require("@suilend/sui-fe");
|
|
|
20
20
|
const client_1 = require("../client");
|
|
21
21
|
const types_1 = require("./types");
|
|
22
22
|
exports.STRATEGY_WRAPPER_PACKAGE_ID_V1 = "0xba97dc73a07638d03d77ad2161484eb21db577edc9cadcd7035fef4b4f2f6fa1";
|
|
23
|
-
const
|
|
23
|
+
const STRATEGY_WRAPPER_PACKAGE_ID_V7 = "0x864b66441e95323c320ee7584592769930a2d236b45d731011ee7a98eb785b35";
|
|
24
24
|
var StrategyType;
|
|
25
25
|
(function (StrategyType) {
|
|
26
26
|
StrategyType["sSUI_SUI_LOOPING"] = "1";
|
|
@@ -29,6 +29,7 @@ var StrategyType;
|
|
|
29
29
|
StrategyType["AUSD_sSUI_SUI_LOOPING"] = "4";
|
|
30
30
|
StrategyType["xBTC_sSUI_SUI_LOOPING"] = "100";
|
|
31
31
|
StrategyType["xBTC_wBTC_LOOPING"] = "101";
|
|
32
|
+
StrategyType["suiUSDT_sSUI_SUI_LOOPING"] = "5";
|
|
32
33
|
})(StrategyType || (exports.StrategyType = StrategyType = {}));
|
|
33
34
|
exports.STRATEGY_TYPE_INFO_MAP = {
|
|
34
35
|
[StrategyType.sSUI_SUI_LOOPING]: {
|
|
@@ -115,9 +116,23 @@ exports.STRATEGY_TYPE_INFO_MAP = {
|
|
|
115
116
|
currencyCoinTypes: [sui_fe_1.NORMALIZED_xBTC_COINTYPE, sui_fe_1.NORMALIZED_wBTC_COINTYPE],
|
|
116
117
|
defaultCurrencyCoinType: sui_fe_1.NORMALIZED_xBTC_COINTYPE,
|
|
117
118
|
},
|
|
119
|
+
[StrategyType.suiUSDT_sSUI_SUI_LOOPING]: {
|
|
120
|
+
queryParam: "suiUSDT-sSUI-SUI-looping",
|
|
121
|
+
header: {
|
|
122
|
+
coinTypes: [sui_fe_1.NORMALIZED_suiUSDT_COINTYPE],
|
|
123
|
+
title: "suiUSDT sSUI/SUI",
|
|
124
|
+
tooltip: "Sets up a suiUSDT sSUI/SUI Looping strategy by depositing suiUSDT and looping sSUI/SUI to the desired leverage",
|
|
125
|
+
type: "Looping",
|
|
126
|
+
},
|
|
127
|
+
depositBaseCoinType: sui_fe_1.NORMALIZED_suiUSDT_COINTYPE,
|
|
128
|
+
depositLstCoinType: sui_fe_1.NORMALIZED_sSUI_COINTYPE,
|
|
129
|
+
borrowCoinType: sui_fe_1.NORMALIZED_SUI_COINTYPE,
|
|
130
|
+
currencyCoinTypes: [sui_fe_1.NORMALIZED_suiUSDT_COINTYPE],
|
|
131
|
+
defaultCurrencyCoinType: sui_fe_1.NORMALIZED_suiUSDT_COINTYPE,
|
|
132
|
+
},
|
|
118
133
|
};
|
|
119
134
|
const strategyDeposit = (coin, coinType, strategyOwnerCap, reserveArrayIndex, transaction) => transaction.moveCall({
|
|
120
|
-
target: `${
|
|
135
|
+
target: `${STRATEGY_WRAPPER_PACKAGE_ID_V7}::strategy_wrapper::deposit_liquidity_and_deposit_into_obligation`,
|
|
121
136
|
typeArguments: [client_1.LENDING_MARKET_TYPE, coinType],
|
|
122
137
|
arguments: [
|
|
123
138
|
transaction.object(strategyOwnerCap),
|
|
@@ -130,7 +145,7 @@ const strategyDeposit = (coin, coinType, strategyOwnerCap, reserveArrayIndex, tr
|
|
|
130
145
|
exports.strategyDeposit = strategyDeposit;
|
|
131
146
|
const strategyBorrow = (coinType, strategyOwnerCap, reserveArrayIndex, value, transaction) => (0, sui_fe_1.isSui)(coinType)
|
|
132
147
|
? transaction.moveCall({
|
|
133
|
-
target: `${
|
|
148
|
+
target: `${STRATEGY_WRAPPER_PACKAGE_ID_V7}::strategy_wrapper::borrow_sui_from_obligation`,
|
|
134
149
|
typeArguments: [client_1.LENDING_MARKET_TYPE],
|
|
135
150
|
arguments: [
|
|
136
151
|
transaction.object(strategyOwnerCap),
|
|
@@ -142,7 +157,7 @@ const strategyBorrow = (coinType, strategyOwnerCap, reserveArrayIndex, value, tr
|
|
|
142
157
|
],
|
|
143
158
|
})
|
|
144
159
|
: transaction.moveCall({
|
|
145
|
-
target: `${
|
|
160
|
+
target: `${STRATEGY_WRAPPER_PACKAGE_ID_V7}::strategy_wrapper::borrow_from_obligation`,
|
|
146
161
|
typeArguments: [client_1.LENDING_MARKET_TYPE, coinType],
|
|
147
162
|
arguments: [
|
|
148
163
|
transaction.object(strategyOwnerCap),
|
|
@@ -154,7 +169,7 @@ const strategyBorrow = (coinType, strategyOwnerCap, reserveArrayIndex, value, tr
|
|
|
154
169
|
});
|
|
155
170
|
exports.strategyBorrow = strategyBorrow;
|
|
156
171
|
const strategyWithdraw = (coinType, strategyOwnerCap, reserveArrayIndex, value, transaction) => transaction.moveCall({
|
|
157
|
-
target: `${
|
|
172
|
+
target: `${STRATEGY_WRAPPER_PACKAGE_ID_V7}::strategy_wrapper::withdraw_from_obligation_and_redeem`,
|
|
158
173
|
typeArguments: [client_1.LENDING_MARKET_TYPE, coinType],
|
|
159
174
|
arguments: [
|
|
160
175
|
transaction.object(strategyOwnerCap),
|
|
@@ -166,7 +181,7 @@ const strategyWithdraw = (coinType, strategyOwnerCap, reserveArrayIndex, value,
|
|
|
166
181
|
});
|
|
167
182
|
exports.strategyWithdraw = strategyWithdraw;
|
|
168
183
|
const strategyClaimRewards = (coinType, strategyOwnerCap, reserveArrayIndex, rewardIndex, side, transaction) => transaction.moveCall({
|
|
169
|
-
target: `${
|
|
184
|
+
target: `${STRATEGY_WRAPPER_PACKAGE_ID_V7}::strategy_wrapper::claim_rewards`,
|
|
170
185
|
typeArguments: [client_1.LENDING_MARKET_TYPE, coinType],
|
|
171
186
|
arguments: [
|
|
172
187
|
transaction.object(strategyOwnerCap),
|
|
@@ -204,9 +219,15 @@ const strategyClaimRewardsAndMergeCoins = (rewardsMap, strategyOwnerCap, transac
|
|
|
204
219
|
}
|
|
205
220
|
return mergedCoinsMap;
|
|
206
221
|
};
|
|
207
|
-
const strategyClaimRewardsAndSwapForCoinType = (address, cetusSdk, cetusPartnerId, rewardsMap, depositReserve, strategyOwnerCap, isDepositing, transaction) => __awaiter(void 0, void 0, void 0, function* () {
|
|
222
|
+
const strategyClaimRewardsAndSwapForCoinType = (address, cetusSdk, cetusPartnerId, rewardsMap, rewardPriceMap, depositReserve, strategyOwnerCap, isDepositing, transaction) => __awaiter(void 0, void 0, void 0, function* () {
|
|
223
|
+
const filteredRewardsMap = Object.fromEntries(Object.entries(rewardsMap).filter(([coinType]) => {
|
|
224
|
+
var _a;
|
|
225
|
+
return ((_a = rewardPriceMap[coinType]) !== null && _a !== void 0 ? _a : new bignumber_js_1.default(0))
|
|
226
|
+
.times(rewardsMap[coinType].amount)
|
|
227
|
+
.gte(0.01);
|
|
228
|
+
}));
|
|
208
229
|
// 1) Claim rewards and merge coins
|
|
209
|
-
const mergedCoinsMap = strategyClaimRewardsAndMergeCoins(
|
|
230
|
+
const mergedCoinsMap = strategyClaimRewardsAndMergeCoins(filteredRewardsMap, strategyOwnerCap, transaction);
|
|
210
231
|
// 2) Prepare
|
|
211
232
|
const nonSwappedCoinTypes = Object.keys(mergedCoinsMap).filter((coinType) => coinType === depositReserve.coinType);
|
|
212
233
|
const swappedCoinTypes = Object.keys(mergedCoinsMap).filter((coinType) => coinType !== depositReserve.coinType);
|
|
@@ -224,7 +245,7 @@ const strategyClaimRewardsAndSwapForCoinType = (address, cetusSdk, cetusPartnerI
|
|
|
224
245
|
.filter(([coinType]) => swappedCoinTypes.includes(coinType))
|
|
225
246
|
.map(([coinType, coin]) => (() => __awaiter(void 0, void 0, void 0, function* () {
|
|
226
247
|
// Get amount
|
|
227
|
-
const { rawAmount: amount } =
|
|
248
|
+
const { rawAmount: amount } = filteredRewardsMap[coinType]; // Use underestimate (rewards keep accruing)
|
|
228
249
|
// Get routes
|
|
229
250
|
const routers = yield cetusSdk.findRouters({
|
|
230
251
|
from: coinType,
|
|
@@ -355,7 +376,7 @@ const createStrategyOwnerCapIfNoneExists = (strategyType, strategyOwnerCap, tran
|
|
|
355
376
|
strategyOwnerCapId = strategyOwnerCap.id;
|
|
356
377
|
else {
|
|
357
378
|
strategyOwnerCapId = transaction.moveCall({
|
|
358
|
-
target: `${
|
|
379
|
+
target: `${STRATEGY_WRAPPER_PACKAGE_ID_V7}::strategy_wrapper::create_strategy_owner_cap`,
|
|
359
380
|
typeArguments: [client_1.LENDING_MARKET_TYPE],
|
|
360
381
|
arguments: [
|
|
361
382
|
transaction.object(client_1.LENDING_MARKET_ID),
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@suilend/sdk","version":"1.1.
|
|
1
|
+
{"name":"@suilend/sdk","version":"1.1.85","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","./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/strategyOwnerCap":"./lib/strategyOwnerCap.js","./lib/transactions":"./lib/transactions.js","./lib/types":"./lib/types.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":"./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","./_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","./_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/i64/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/i64/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-feed/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-feed/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-identifier/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-identifier/structs.js","./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-info/structs":"./_generated/_dependencies/source/0x8d97f1cd6ac663735be08d1d2b6d02a159e711586461306ce60a2b7a6a565a9e/price-info/structs.js"},"types":"./index.js","scripts":{"build":"rm -rf ./dist && bun tsc","eslint":"eslint --fix \"./src/**/*.ts\"","prettier":"prettier --write \"./src/**/*\"","lint":"bun eslint && bun prettier && bun tsc --noEmit","release":"bun run build && bun ts-node ./release.ts && cd ./dist && npm publish --access public"},"repository":{"type":"git","url":"git+https://github.com/suilend/suilend-fe-public.git"},"bugs":{"url":"https://github.com/suilend/suilend-fe-public/issues"},"dependencies":{"@7kprotocol/sdk-ts":"^3.4.1","@cetusprotocol/aggregator-sdk":"^1.2.1","@flowx-finance/sdk":"^1.13.5","@pythnetwork/pyth-sui-js":"^2.2.0","@suilend/springsui-sdk":"^1.0.26","aftermath-ts-sdk":"^1.3.22","bignumber.js":"^9.1.2","bn.js":"^5.2.2","crypto-js":"^4.2.0","lodash":"^4.17.21","p-limit":"3.1.0","uuid":"^11.0.3"},"devDependencies":{"@types/bn.js":"^5.2.0","@types/lodash":"^4.17.20","ts-node":"^10.9.2"},"peerDependencies":{"@mysten/bcs":"1.6.0","@mysten/sui":"1.28.2","@suilend/sui-fe":"^0.3.32"},"overrides":{"chalk":"5.3.0","strip-ansi":"7.1.0","color-convert":"2.0.1","color-name":"1.1.4","is-core-module":"2.13.1","error-ex":"1.3.2","has-ansi":"5.0.1"}}
|
|
@@ -27,6 +27,7 @@ export declare const parseReserveAssetDataEvent: (event: ApiReserveAssetDataEven
|
|
|
27
27
|
eventIndex: number;
|
|
28
28
|
sender: string;
|
|
29
29
|
utilizationPercent: BigNumber;
|
|
30
|
+
original: ApiReserveAssetDataEvent;
|
|
30
31
|
};
|
|
31
32
|
export type ParsedDownsampledApiReserveAssetDataEvent = ReturnType<typeof parseDownsampledApiReserveAssetDataEvent>;
|
|
32
33
|
export declare const parseDownsampledApiReserveAssetDataEvent: (event: DownsampledApiReserveAssetDataEvent, reserve: ParsedReserve) => {
|
|
@@ -55,4 +56,5 @@ export declare const parseDownsampledApiReserveAssetDataEvent: (event: Downsampl
|
|
|
55
56
|
eventIndex: number;
|
|
56
57
|
sender: string;
|
|
57
58
|
utilizationPercent: BigNumber;
|
|
59
|
+
original: ApiReserveAssetDataEvent;
|
|
58
60
|
};
|
package/strategies.d.ts
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { CoinMetadata, SuiClient } from "@mysten/sui/client";
|
|
2
|
+
import BigNumber from "bignumber.js";
|
|
3
|
+
import { LstClient } from "@suilend/springsui-sdk";
|
|
4
|
+
import { LiquidStakingInfo } from "@suilend/springsui-sdk/_generated/liquid_staking/liquid-staking/structs";
|
|
5
|
+
import { RewardMap } from "./lib/liquidityMining";
|
|
6
|
+
import { StrategyType } from "./lib/strategyOwnerCap";
|
|
7
|
+
import { ParsedObligation, ParsedReserve } from "./parsers";
|
|
8
|
+
export declare const STRATEGY_E: number;
|
|
9
|
+
export declare const LST_DECIMALS = 9;
|
|
10
|
+
export type StrategyDeposit = {
|
|
11
|
+
coinType: string;
|
|
12
|
+
depositedAmount: BigNumber;
|
|
13
|
+
};
|
|
14
|
+
export type StrategyWithdraw = {
|
|
15
|
+
coinType: string;
|
|
16
|
+
withdrawnAmount: BigNumber;
|
|
17
|
+
};
|
|
18
|
+
export declare const addOrInsertStrategyDeposit: (_deposits: StrategyDeposit[], deposit: StrategyDeposit) => StrategyDeposit[];
|
|
19
|
+
export declare const hasStrategyPosition: (obligation: ParsedObligation) => boolean;
|
|
20
|
+
export declare const getStrategySuiReserve: (reserveMap: Record<string, ParsedReserve>) => {
|
|
21
|
+
config: {
|
|
22
|
+
$typeName: string;
|
|
23
|
+
openLtvPct: number;
|
|
24
|
+
closeLtvPct: number;
|
|
25
|
+
maxCloseLtvPct: number;
|
|
26
|
+
borrowWeightBps: BigNumber;
|
|
27
|
+
depositLimit: BigNumber;
|
|
28
|
+
borrowLimit: BigNumber;
|
|
29
|
+
liquidationBonusBps: number;
|
|
30
|
+
maxLiquidationBonusBps: number;
|
|
31
|
+
depositLimitUsd: BigNumber;
|
|
32
|
+
borrowLimitUsd: BigNumber;
|
|
33
|
+
borrowFeeBps: number;
|
|
34
|
+
spreadFeeBps: number;
|
|
35
|
+
protocolLiquidationFeeBps: number;
|
|
36
|
+
isolated: boolean;
|
|
37
|
+
openAttributedBorrowLimitUsd: number;
|
|
38
|
+
closeAttributedBorrowLimitUsd: number;
|
|
39
|
+
interestRate: {
|
|
40
|
+
id: string;
|
|
41
|
+
utilPercent: BigNumber;
|
|
42
|
+
aprPercent: BigNumber;
|
|
43
|
+
}[];
|
|
44
|
+
};
|
|
45
|
+
$typeName: string;
|
|
46
|
+
id: string;
|
|
47
|
+
arrayIndex: bigint;
|
|
48
|
+
coinType: string;
|
|
49
|
+
mintDecimals: number;
|
|
50
|
+
priceIdentifier: string;
|
|
51
|
+
price: BigNumber;
|
|
52
|
+
smoothedPrice: BigNumber;
|
|
53
|
+
minPrice: BigNumber;
|
|
54
|
+
maxPrice: BigNumber;
|
|
55
|
+
priceLastUpdateTimestampS: bigint;
|
|
56
|
+
availableAmount: BigNumber;
|
|
57
|
+
ctokenSupply: BigNumber;
|
|
58
|
+
borrowedAmount: BigNumber;
|
|
59
|
+
cumulativeBorrowRate: BigNumber;
|
|
60
|
+
interestLastUpdateTimestampS: bigint;
|
|
61
|
+
unclaimedSpreadFees: BigNumber;
|
|
62
|
+
attributedBorrowValue: BigNumber;
|
|
63
|
+
depositsPoolRewardManager: {
|
|
64
|
+
$typeName: string;
|
|
65
|
+
id: string;
|
|
66
|
+
totalShares: bigint;
|
|
67
|
+
poolRewards: {
|
|
68
|
+
$typeName: string;
|
|
69
|
+
id: string;
|
|
70
|
+
poolRewardManagerId: string;
|
|
71
|
+
coinType: string;
|
|
72
|
+
startTimeMs: number;
|
|
73
|
+
endTimeMs: number;
|
|
74
|
+
totalRewards: BigNumber;
|
|
75
|
+
allocatedRewards: BigNumber;
|
|
76
|
+
cumulativeRewardsPerShare: BigNumber;
|
|
77
|
+
numUserRewardManagers: bigint;
|
|
78
|
+
rewardIndex: number;
|
|
79
|
+
symbol: string;
|
|
80
|
+
mintDecimals: number;
|
|
81
|
+
}[];
|
|
82
|
+
lastUpdateTimeMs: bigint;
|
|
83
|
+
};
|
|
84
|
+
borrowsPoolRewardManager: {
|
|
85
|
+
$typeName: string;
|
|
86
|
+
id: string;
|
|
87
|
+
totalShares: bigint;
|
|
88
|
+
poolRewards: {
|
|
89
|
+
$typeName: string;
|
|
90
|
+
id: string;
|
|
91
|
+
poolRewardManagerId: string;
|
|
92
|
+
coinType: string;
|
|
93
|
+
startTimeMs: number;
|
|
94
|
+
endTimeMs: number;
|
|
95
|
+
totalRewards: BigNumber;
|
|
96
|
+
allocatedRewards: BigNumber;
|
|
97
|
+
cumulativeRewardsPerShare: BigNumber;
|
|
98
|
+
numUserRewardManagers: bigint;
|
|
99
|
+
rewardIndex: number;
|
|
100
|
+
symbol: string;
|
|
101
|
+
mintDecimals: number;
|
|
102
|
+
}[];
|
|
103
|
+
lastUpdateTimeMs: bigint;
|
|
104
|
+
};
|
|
105
|
+
availableAmountUsd: BigNumber;
|
|
106
|
+
borrowedAmountUsd: BigNumber;
|
|
107
|
+
depositedAmount: BigNumber;
|
|
108
|
+
depositedAmountUsd: BigNumber;
|
|
109
|
+
cTokenExchangeRate: BigNumber;
|
|
110
|
+
borrowAprPercent: BigNumber;
|
|
111
|
+
depositAprPercent: BigNumber;
|
|
112
|
+
utilizationPercent: BigNumber;
|
|
113
|
+
token: {
|
|
114
|
+
decimals: number;
|
|
115
|
+
description: string;
|
|
116
|
+
iconUrl?: string | null;
|
|
117
|
+
id?: string | null;
|
|
118
|
+
name: string;
|
|
119
|
+
symbol: string;
|
|
120
|
+
coinType: string;
|
|
121
|
+
};
|
|
122
|
+
symbol: string;
|
|
123
|
+
name: string;
|
|
124
|
+
iconUrl: string | null | undefined;
|
|
125
|
+
description: string;
|
|
126
|
+
totalDeposits: BigNumber;
|
|
127
|
+
};
|
|
128
|
+
export type StrategyLstMap = Record<string, {
|
|
129
|
+
client: LstClient;
|
|
130
|
+
liquidStakingInfo: LiquidStakingInfo<string>;
|
|
131
|
+
mintFeePercent: BigNumber;
|
|
132
|
+
redeemFeePercent: BigNumber;
|
|
133
|
+
suiToLstExchangeRate: BigNumber;
|
|
134
|
+
lstToSuiExchangeRate: BigNumber;
|
|
135
|
+
}>;
|
|
136
|
+
export declare const fetchStrategyLstMap: (suiClient: SuiClient) => Promise<StrategyLstMap | undefined>;
|
|
137
|
+
export declare const getStrategyLstMintFee: (lstMap: StrategyLstMap, lstCoinType: string, suiAmount: BigNumber) => BigNumber;
|
|
138
|
+
export declare const getStrategyLstRedeemFee: (lstMap: StrategyLstMap, lstCoinType: string, lstAmount: BigNumber) => BigNumber;
|
|
139
|
+
export declare const STRATEGY_TYPE_EXPOSURE_MAP: Record<StrategyType, {
|
|
140
|
+
min: BigNumber;
|
|
141
|
+
max: BigNumber;
|
|
142
|
+
default: BigNumber;
|
|
143
|
+
}>;
|
|
144
|
+
export declare const getStrategyDepositReserves: (reserveMap: Record<string, ParsedReserve>, strategyType: StrategyType) => {
|
|
145
|
+
base?: ParsedReserve;
|
|
146
|
+
lst?: ParsedReserve;
|
|
147
|
+
};
|
|
148
|
+
export declare const getStrategyBorrowReserve: (reserveMap: Record<string, ParsedReserve>, strategyType: StrategyType) => ParsedReserve;
|
|
149
|
+
export declare const getStrategyDefaultCurrencyReserve: (reserveMap: Record<string, ParsedReserve>, strategyType: StrategyType) => {
|
|
150
|
+
config: {
|
|
151
|
+
$typeName: string;
|
|
152
|
+
openLtvPct: number;
|
|
153
|
+
closeLtvPct: number;
|
|
154
|
+
maxCloseLtvPct: number;
|
|
155
|
+
borrowWeightBps: BigNumber;
|
|
156
|
+
depositLimit: BigNumber;
|
|
157
|
+
borrowLimit: BigNumber;
|
|
158
|
+
liquidationBonusBps: number;
|
|
159
|
+
maxLiquidationBonusBps: number;
|
|
160
|
+
depositLimitUsd: BigNumber;
|
|
161
|
+
borrowLimitUsd: BigNumber;
|
|
162
|
+
borrowFeeBps: number;
|
|
163
|
+
spreadFeeBps: number;
|
|
164
|
+
protocolLiquidationFeeBps: number;
|
|
165
|
+
isolated: boolean;
|
|
166
|
+
openAttributedBorrowLimitUsd: number;
|
|
167
|
+
closeAttributedBorrowLimitUsd: number;
|
|
168
|
+
interestRate: {
|
|
169
|
+
id: string;
|
|
170
|
+
utilPercent: BigNumber;
|
|
171
|
+
aprPercent: BigNumber;
|
|
172
|
+
}[];
|
|
173
|
+
};
|
|
174
|
+
$typeName: string;
|
|
175
|
+
id: string;
|
|
176
|
+
arrayIndex: bigint;
|
|
177
|
+
coinType: string;
|
|
178
|
+
mintDecimals: number;
|
|
179
|
+
priceIdentifier: string;
|
|
180
|
+
price: BigNumber;
|
|
181
|
+
smoothedPrice: BigNumber;
|
|
182
|
+
minPrice: BigNumber;
|
|
183
|
+
maxPrice: BigNumber;
|
|
184
|
+
priceLastUpdateTimestampS: bigint;
|
|
185
|
+
availableAmount: BigNumber;
|
|
186
|
+
ctokenSupply: BigNumber;
|
|
187
|
+
borrowedAmount: BigNumber;
|
|
188
|
+
cumulativeBorrowRate: BigNumber;
|
|
189
|
+
interestLastUpdateTimestampS: bigint;
|
|
190
|
+
unclaimedSpreadFees: BigNumber;
|
|
191
|
+
attributedBorrowValue: BigNumber;
|
|
192
|
+
depositsPoolRewardManager: {
|
|
193
|
+
$typeName: string;
|
|
194
|
+
id: string;
|
|
195
|
+
totalShares: bigint;
|
|
196
|
+
poolRewards: {
|
|
197
|
+
$typeName: string;
|
|
198
|
+
id: string;
|
|
199
|
+
poolRewardManagerId: string;
|
|
200
|
+
coinType: string;
|
|
201
|
+
startTimeMs: number;
|
|
202
|
+
endTimeMs: number;
|
|
203
|
+
totalRewards: BigNumber;
|
|
204
|
+
allocatedRewards: BigNumber;
|
|
205
|
+
cumulativeRewardsPerShare: BigNumber;
|
|
206
|
+
numUserRewardManagers: bigint;
|
|
207
|
+
rewardIndex: number;
|
|
208
|
+
symbol: string;
|
|
209
|
+
mintDecimals: number;
|
|
210
|
+
}[];
|
|
211
|
+
lastUpdateTimeMs: bigint;
|
|
212
|
+
};
|
|
213
|
+
borrowsPoolRewardManager: {
|
|
214
|
+
$typeName: string;
|
|
215
|
+
id: string;
|
|
216
|
+
totalShares: bigint;
|
|
217
|
+
poolRewards: {
|
|
218
|
+
$typeName: string;
|
|
219
|
+
id: string;
|
|
220
|
+
poolRewardManagerId: string;
|
|
221
|
+
coinType: string;
|
|
222
|
+
startTimeMs: number;
|
|
223
|
+
endTimeMs: number;
|
|
224
|
+
totalRewards: BigNumber;
|
|
225
|
+
allocatedRewards: BigNumber;
|
|
226
|
+
cumulativeRewardsPerShare: BigNumber;
|
|
227
|
+
numUserRewardManagers: bigint;
|
|
228
|
+
rewardIndex: number;
|
|
229
|
+
symbol: string;
|
|
230
|
+
mintDecimals: number;
|
|
231
|
+
}[];
|
|
232
|
+
lastUpdateTimeMs: bigint;
|
|
233
|
+
};
|
|
234
|
+
availableAmountUsd: BigNumber;
|
|
235
|
+
borrowedAmountUsd: BigNumber;
|
|
236
|
+
depositedAmount: BigNumber;
|
|
237
|
+
depositedAmountUsd: BigNumber;
|
|
238
|
+
cTokenExchangeRate: BigNumber;
|
|
239
|
+
borrowAprPercent: BigNumber;
|
|
240
|
+
depositAprPercent: BigNumber;
|
|
241
|
+
utilizationPercent: BigNumber;
|
|
242
|
+
token: {
|
|
243
|
+
decimals: number;
|
|
244
|
+
description: string;
|
|
245
|
+
iconUrl?: string | null;
|
|
246
|
+
id?: string | null;
|
|
247
|
+
name: string;
|
|
248
|
+
symbol: string;
|
|
249
|
+
coinType: string;
|
|
250
|
+
};
|
|
251
|
+
symbol: string;
|
|
252
|
+
name: string;
|
|
253
|
+
iconUrl: string | null | undefined;
|
|
254
|
+
description: string;
|
|
255
|
+
totalDeposits: BigNumber;
|
|
256
|
+
};
|
|
257
|
+
export declare const getStrategySimulatedObligation: (reserveMap: Record<string, ParsedReserve>, lstMap: StrategyLstMap, strategyType: StrategyType, deposits: StrategyDeposit[], _borrowedAmount: BigNumber) => ParsedObligation;
|
|
258
|
+
export declare const getStrategyDepositedAmount: (reserveMap: Record<string, ParsedReserve>, lstMap: StrategyLstMap, strategyType: StrategyType, obligation?: ParsedObligation) => BigNumber;
|
|
259
|
+
export declare const getStrategyBorrowedAmount: (reserveMap: Record<string, ParsedReserve>, lstMap: StrategyLstMap, strategyType: StrategyType, obligation?: ParsedObligation) => BigNumber;
|
|
260
|
+
export declare const getStrategyTvlAmount: (reserveMap: Record<string, ParsedReserve>, lstMap: StrategyLstMap, strategyType: StrategyType, obligation?: ParsedObligation) => BigNumber;
|
|
261
|
+
export declare const getStrategyExposure: (reserveMap: Record<string, ParsedReserve>, lstMap: StrategyLstMap, strategyType: StrategyType, obligation?: ParsedObligation) => BigNumber;
|
|
262
|
+
export declare const fetchStrategyGlobalTvlAmountUsdMap: () => Promise<Record<StrategyType, BigNumber | null> | undefined>;
|
|
263
|
+
export declare const getStrategyUnclaimedRewardsAmount: (reserveMap: Record<string, ParsedReserve>, rewardPriceMap: Record<string, BigNumber | undefined>, rewardCoinMetadataMap: Record<string, CoinMetadata>, rewardMap: RewardMap, lstMap: StrategyLstMap, strategyType: StrategyType, obligation?: ParsedObligation) => BigNumber;
|
package/strategies.js
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.getStrategyUnclaimedRewardsAmount = exports.fetchStrategyGlobalTvlAmountUsdMap = exports.getStrategyExposure = exports.getStrategyTvlAmount = exports.getStrategyBorrowedAmount = exports.getStrategyDepositedAmount = exports.getStrategySimulatedObligation = exports.getStrategyDefaultCurrencyReserve = exports.getStrategyBorrowReserve = exports.getStrategyDepositReserves = exports.STRATEGY_TYPE_EXPOSURE_MAP = exports.getStrategyLstRedeemFee = exports.getStrategyLstMintFee = exports.fetchStrategyLstMap = exports.getStrategySuiReserve = exports.hasStrategyPosition = exports.addOrInsertStrategyDeposit = exports.LST_DECIMALS = exports.STRATEGY_E = void 0;
|
|
16
|
+
const utils_1 = require("@mysten/sui/utils");
|
|
17
|
+
const bignumber_js_1 = __importDefault(require("bignumber.js"));
|
|
18
|
+
const lodash_1 = require("lodash");
|
|
19
|
+
const springsui_sdk_1 = require("@suilend/springsui-sdk");
|
|
20
|
+
const sui_fe_1 = require("@suilend/sui-fe");
|
|
21
|
+
const liquidityMining_1 = require("./lib/liquidityMining");
|
|
22
|
+
const strategyOwnerCap_1 = require("./lib/strategyOwnerCap");
|
|
23
|
+
exports.STRATEGY_E = 10 ** -7;
|
|
24
|
+
exports.LST_DECIMALS = 9;
|
|
25
|
+
const addOrInsertStrategyDeposit = (_deposits, deposit) => {
|
|
26
|
+
const deposits = (0, lodash_1.cloneDeep)(_deposits);
|
|
27
|
+
const existingDeposit = deposits.find((d) => d.coinType === deposit.coinType);
|
|
28
|
+
if (existingDeposit)
|
|
29
|
+
existingDeposit.depositedAmount = existingDeposit.depositedAmount.plus(deposit.depositedAmount);
|
|
30
|
+
else
|
|
31
|
+
deposits.push(deposit);
|
|
32
|
+
return deposits;
|
|
33
|
+
};
|
|
34
|
+
exports.addOrInsertStrategyDeposit = addOrInsertStrategyDeposit;
|
|
35
|
+
// Obligations
|
|
36
|
+
const hasStrategyPosition = (obligation) => obligation.deposits.length > 0;
|
|
37
|
+
exports.hasStrategyPosition = hasStrategyPosition;
|
|
38
|
+
// SUI
|
|
39
|
+
const getStrategySuiReserve = (
|
|
40
|
+
// AppContext
|
|
41
|
+
reserveMap) => reserveMap[sui_fe_1.NORMALIZED_SUI_COINTYPE];
|
|
42
|
+
exports.getStrategySuiReserve = getStrategySuiReserve;
|
|
43
|
+
const fetchStrategyLstMap = (suiClient) => __awaiter(void 0, void 0, void 0, function* () {
|
|
44
|
+
try {
|
|
45
|
+
const lstCoinTypes = Array.from(new Set([
|
|
46
|
+
...Object.values(strategyOwnerCap_1.STRATEGY_TYPE_INFO_MAP)
|
|
47
|
+
.map(({ depositLstCoinType }) => depositLstCoinType)
|
|
48
|
+
.filter(Boolean),
|
|
49
|
+
// LSTs that will be/are/have been used as rewards
|
|
50
|
+
sui_fe_1.NORMALIZED_sSUI_COINTYPE,
|
|
51
|
+
]));
|
|
52
|
+
const publishedAt = yield (0, springsui_sdk_1.getLatestPackageId)(suiClient, springsui_sdk_1.SPRING_SUI_UPGRADE_CAP_ID);
|
|
53
|
+
const lstInfoUrl = `${sui_fe_1.API_URL}/springsui/lst-info?${new URLSearchParams({
|
|
54
|
+
coinTypes: lstCoinTypes.join(","),
|
|
55
|
+
})}`;
|
|
56
|
+
const lstInfoRes = yield fetch(lstInfoUrl);
|
|
57
|
+
const lstInfoJson = yield lstInfoRes.json();
|
|
58
|
+
if ((lstInfoRes === null || lstInfoRes === void 0 ? void 0 : lstInfoRes.statusCode) === 500)
|
|
59
|
+
throw new Error("Failed to fetch LST info");
|
|
60
|
+
const lstInfoMap = Object.fromEntries(Object.entries(lstInfoJson).map(([lstCoinType, lstInfo]) => {
|
|
61
|
+
return [lstCoinType, lstInfo];
|
|
62
|
+
}));
|
|
63
|
+
const result = Object.fromEntries(yield Promise.all(lstCoinTypes.map((lstCoinType) => __awaiter(void 0, void 0, void 0, function* () {
|
|
64
|
+
var _a, _b, _c, _d;
|
|
65
|
+
const lstInfo = lstInfoMap[lstCoinType];
|
|
66
|
+
const lstClient = yield springsui_sdk_1.LstClient.initialize(suiClient, lstInfo.LIQUID_STAKING_INFO, publishedAt);
|
|
67
|
+
const mintFeePercent = new bignumber_js_1.default((_b = (_a = lstInfo.liquidStakingInfo.feeConfig.element) === null || _a === void 0 ? void 0 : _a.suiMintFeeBps.toString()) !== null && _b !== void 0 ? _b : 0).div(100);
|
|
68
|
+
const redeemFeePercent = new bignumber_js_1.default((_d = (_c = lstInfo.liquidStakingInfo.feeConfig.element) === null || _c === void 0 ? void 0 : _c.redeemFeeBps.toString()) !== null && _d !== void 0 ? _d : 0).div(100);
|
|
69
|
+
const res = yield fetch(`${sui_fe_1.API_URL}/springsui/historical-rates?coinType=${lstCoinType}×tamps=${Math.floor(Date.now() / 1000)}`);
|
|
70
|
+
const json = yield res.json();
|
|
71
|
+
if ((json === null || json === void 0 ? void 0 : json.statusCode) === 500)
|
|
72
|
+
throw new Error(`Failed to fetch historical LST to SUI exchange rates for ${lstCoinType}`);
|
|
73
|
+
const suiToLstExchangeRate = !new bignumber_js_1.default(json[0].value).eq(0)
|
|
74
|
+
? new bignumber_js_1.default(1).div(new bignumber_js_1.default(json[0].value))
|
|
75
|
+
: new bignumber_js_1.default(1);
|
|
76
|
+
const lstToSuiExchangeRate = new bignumber_js_1.default(json[0].value);
|
|
77
|
+
return [
|
|
78
|
+
lstCoinType,
|
|
79
|
+
{
|
|
80
|
+
client: lstClient,
|
|
81
|
+
liquidStakingInfo: lstInfo.liquidStakingInfo,
|
|
82
|
+
mintFeePercent,
|
|
83
|
+
redeemFeePercent,
|
|
84
|
+
suiToLstExchangeRate,
|
|
85
|
+
lstToSuiExchangeRate,
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
}))));
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
console.error(err);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
exports.fetchStrategyLstMap = fetchStrategyLstMap;
|
|
96
|
+
const getStrategyLstMintFee = (
|
|
97
|
+
// Strategy
|
|
98
|
+
lstMap, lstCoinType, suiAmount) => {
|
|
99
|
+
var _a, _b;
|
|
100
|
+
const mintFeePercent = (_b = (_a = lstMap === null || lstMap === void 0 ? void 0 : lstMap[lstCoinType]) === null || _a === void 0 ? void 0 : _a.mintFeePercent) !== null && _b !== void 0 ? _b : new bignumber_js_1.default(0);
|
|
101
|
+
return suiAmount
|
|
102
|
+
.times(mintFeePercent.div(100))
|
|
103
|
+
.decimalPlaces(utils_1.SUI_DECIMALS, bignumber_js_1.default.ROUND_UP);
|
|
104
|
+
};
|
|
105
|
+
exports.getStrategyLstMintFee = getStrategyLstMintFee;
|
|
106
|
+
const getStrategyLstRedeemFee = (
|
|
107
|
+
// Strategy
|
|
108
|
+
lstMap, lstCoinType, lstAmount) => {
|
|
109
|
+
var _a, _b, _c, _d;
|
|
110
|
+
const lstToSuiExchangeRate = (_b = (_a = lstMap === null || lstMap === void 0 ? void 0 : lstMap[lstCoinType]) === null || _a === void 0 ? void 0 : _a.lstToSuiExchangeRate) !== null && _b !== void 0 ? _b : new bignumber_js_1.default(1);
|
|
111
|
+
const redeemFeePercent = (_d = (_c = lstMap === null || lstMap === void 0 ? void 0 : lstMap[lstCoinType]) === null || _c === void 0 ? void 0 : _c.redeemFeePercent) !== null && _d !== void 0 ? _d : new bignumber_js_1.default(0);
|
|
112
|
+
const suiAmount = lstAmount.times(lstToSuiExchangeRate);
|
|
113
|
+
return suiAmount
|
|
114
|
+
.times(redeemFeePercent.div(100))
|
|
115
|
+
.decimalPlaces(utils_1.SUI_DECIMALS, bignumber_js_1.default.ROUND_UP);
|
|
116
|
+
};
|
|
117
|
+
exports.getStrategyLstRedeemFee = getStrategyLstRedeemFee;
|
|
118
|
+
// Exposure map
|
|
119
|
+
exports.STRATEGY_TYPE_EXPOSURE_MAP = {
|
|
120
|
+
[strategyOwnerCap_1.StrategyType.sSUI_SUI_LOOPING]: {
|
|
121
|
+
min: new bignumber_js_1.default(1),
|
|
122
|
+
max: new bignumber_js_1.default(3), // Actual max: 1 / (1 - (sSUI Open LTV %)) = 3.333x, where sSUI Open LTV % = 70%
|
|
123
|
+
default: new bignumber_js_1.default(3),
|
|
124
|
+
},
|
|
125
|
+
[strategyOwnerCap_1.StrategyType.stratSUI_SUI_LOOPING]: {
|
|
126
|
+
min: new bignumber_js_1.default(1),
|
|
127
|
+
max: new bignumber_js_1.default(3), // Actual max: 1 / (1 - (sSUI Open LTV %)) = 3.333x, where sSUI Open LTV % = 70%
|
|
128
|
+
default: new bignumber_js_1.default(3),
|
|
129
|
+
},
|
|
130
|
+
[strategyOwnerCap_1.StrategyType.USDC_sSUI_SUI_LOOPING]: {
|
|
131
|
+
min: new bignumber_js_1.default(1),
|
|
132
|
+
max: new bignumber_js_1.default(3), // Actual max: 1 + (USDC Open LTV %) * (1 / (1 - (sSUI Open LTV %))) = 3.5666x, where USDC Open LTV % = 77% and sSUI Open LTV % = 70%
|
|
133
|
+
default: new bignumber_js_1.default(3),
|
|
134
|
+
},
|
|
135
|
+
[strategyOwnerCap_1.StrategyType.AUSD_sSUI_SUI_LOOPING]: {
|
|
136
|
+
min: new bignumber_js_1.default(1),
|
|
137
|
+
max: new bignumber_js_1.default(3), // Actual max: 1 + (AUSD Open LTV %) * (1 / (1 - (sSUI Open LTV %))) = 3.5666x, where AUSD Open LTV % = 77% and sSUI Open LTV % = 70%
|
|
138
|
+
default: new bignumber_js_1.default(3),
|
|
139
|
+
},
|
|
140
|
+
[strategyOwnerCap_1.StrategyType.xBTC_sSUI_SUI_LOOPING]: {
|
|
141
|
+
min: new bignumber_js_1.default(1),
|
|
142
|
+
max: new bignumber_js_1.default(2.5), // Actual max: 1 + (xBTC Open LTV %) * (1 / (1 - (sSUI Open LTV %))) = 3x, where xBTC Open LTV % = 60% and sSUI Open LTV % = 70%
|
|
143
|
+
default: new bignumber_js_1.default(2.5),
|
|
144
|
+
},
|
|
145
|
+
[strategyOwnerCap_1.StrategyType.xBTC_wBTC_LOOPING]: {
|
|
146
|
+
min: new bignumber_js_1.default(1),
|
|
147
|
+
max: new bignumber_js_1.default(2.2), // Actual max: 1 / (1 - (xBTC Open LTV %)) = 2.5x, where xBTC Open LTV % = 60%
|
|
148
|
+
default: new bignumber_js_1.default(2.2),
|
|
149
|
+
},
|
|
150
|
+
[strategyOwnerCap_1.StrategyType.suiUSDT_sSUI_SUI_LOOPING]: {
|
|
151
|
+
min: new bignumber_js_1.default(1),
|
|
152
|
+
max: new bignumber_js_1.default(3), // Actual max: 1 + (suiUSDT Open LTV %) * (1 / (1 - (sSUI Open LTV %))) = 3.5666x, where suiUSDT Open LTV % = 77% and sSUI Open LTV % = 70%
|
|
153
|
+
default: new bignumber_js_1.default(3),
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
// Reserves
|
|
157
|
+
const getStrategyDepositReserves = (
|
|
158
|
+
// AppContext
|
|
159
|
+
reserveMap,
|
|
160
|
+
// Strategy
|
|
161
|
+
strategyType) => {
|
|
162
|
+
const strategyTypeInfo = strategyOwnerCap_1.STRATEGY_TYPE_INFO_MAP[strategyType];
|
|
163
|
+
return {
|
|
164
|
+
base: strategyTypeInfo.depositBaseCoinType
|
|
165
|
+
? reserveMap[strategyTypeInfo.depositBaseCoinType]
|
|
166
|
+
: undefined,
|
|
167
|
+
lst: strategyTypeInfo.depositLstCoinType
|
|
168
|
+
? reserveMap[strategyTypeInfo.depositLstCoinType]
|
|
169
|
+
: undefined,
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
exports.getStrategyDepositReserves = getStrategyDepositReserves;
|
|
173
|
+
const getStrategyBorrowReserve = (
|
|
174
|
+
// AppContext
|
|
175
|
+
reserveMap,
|
|
176
|
+
// Strategy
|
|
177
|
+
strategyType) => {
|
|
178
|
+
const strategyTypeInfo = strategyOwnerCap_1.STRATEGY_TYPE_INFO_MAP[strategyType];
|
|
179
|
+
return reserveMap[strategyTypeInfo.borrowCoinType];
|
|
180
|
+
};
|
|
181
|
+
exports.getStrategyBorrowReserve = getStrategyBorrowReserve;
|
|
182
|
+
const getStrategyDefaultCurrencyReserve = (
|
|
183
|
+
// AppContext
|
|
184
|
+
reserveMap,
|
|
185
|
+
// Strategy
|
|
186
|
+
strategyType) => {
|
|
187
|
+
const defaultCurrencyCoinType = strategyOwnerCap_1.STRATEGY_TYPE_INFO_MAP[strategyType].defaultCurrencyCoinType;
|
|
188
|
+
return reserveMap[defaultCurrencyCoinType];
|
|
189
|
+
};
|
|
190
|
+
exports.getStrategyDefaultCurrencyReserve = getStrategyDefaultCurrencyReserve;
|
|
191
|
+
// Calculations
|
|
192
|
+
const getStrategySimulatedObligation = (
|
|
193
|
+
// AppContext
|
|
194
|
+
reserveMap,
|
|
195
|
+
// Strategy
|
|
196
|
+
lstMap, strategyType, deposits, _borrowedAmount) => {
|
|
197
|
+
const depositReserves = (0, exports.getStrategyDepositReserves)(reserveMap, strategyType);
|
|
198
|
+
const borrowReserve = (0, exports.getStrategyBorrowReserve)(reserveMap, strategyType);
|
|
199
|
+
const defaultCurrencyReserve = (0, exports.getStrategyDefaultCurrencyReserve)(reserveMap, strategyType);
|
|
200
|
+
//
|
|
201
|
+
const borrowedAmount = bignumber_js_1.default.max(new bignumber_js_1.default(0), _borrowedAmount); // Can't be negative
|
|
202
|
+
const obligation = {
|
|
203
|
+
deposits: deposits.reduce((acc, deposit) => {
|
|
204
|
+
const depositReserve = reserveMap[deposit.coinType];
|
|
205
|
+
return [
|
|
206
|
+
...acc,
|
|
207
|
+
{
|
|
208
|
+
depositedAmount: deposit.depositedAmount,
|
|
209
|
+
depositedAmountUsd: deposit.depositedAmount.times(depositReserve.price),
|
|
210
|
+
reserve: depositReserve,
|
|
211
|
+
coinType: depositReserve.coinType,
|
|
212
|
+
},
|
|
213
|
+
];
|
|
214
|
+
}, []),
|
|
215
|
+
borrows: [
|
|
216
|
+
{
|
|
217
|
+
borrowedAmount: borrowedAmount,
|
|
218
|
+
borrowedAmountUsd: borrowedAmount.times(borrowReserve.price),
|
|
219
|
+
reserve: borrowReserve,
|
|
220
|
+
coinType: borrowReserve.coinType,
|
|
221
|
+
},
|
|
222
|
+
],
|
|
223
|
+
netValueUsd: deposits
|
|
224
|
+
.reduce((acc, deposit) => {
|
|
225
|
+
const depositReserve = reserveMap[deposit.coinType];
|
|
226
|
+
return acc.plus(deposit.depositedAmount.times(depositReserve.price));
|
|
227
|
+
}, new bignumber_js_1.default(0))
|
|
228
|
+
.minus(borrowedAmount.times(borrowReserve.price)),
|
|
229
|
+
weightedBorrowsUsd: new bignumber_js_1.default(borrowedAmount.times(borrowReserve.price)).times(borrowReserve.config.borrowWeightBps.div(10000)),
|
|
230
|
+
maxPriceWeightedBorrowsUsd: new bignumber_js_1.default(borrowedAmount.times(borrowReserve.maxPrice)).times(borrowReserve.config.borrowWeightBps.div(10000)),
|
|
231
|
+
minPriceBorrowLimitUsd: bignumber_js_1.default.min(deposits.reduce((acc, deposit) => {
|
|
232
|
+
const depositReserve = reserveMap[deposit.coinType];
|
|
233
|
+
return acc.plus(deposit.depositedAmount
|
|
234
|
+
.times(depositReserve.minPrice)
|
|
235
|
+
.times(depositReserve.config.openLtvPct / 100));
|
|
236
|
+
}, new bignumber_js_1.default(0)), 30 * 10 ** 6),
|
|
237
|
+
unhealthyBorrowValueUsd: deposits.reduce((acc, deposit) => {
|
|
238
|
+
const depositReserve = reserveMap[deposit.coinType];
|
|
239
|
+
return acc.plus(deposit.depositedAmount
|
|
240
|
+
.times(depositReserve.price)
|
|
241
|
+
.times(depositReserve.config.closeLtvPct / 100));
|
|
242
|
+
}, new bignumber_js_1.default(0)),
|
|
243
|
+
};
|
|
244
|
+
return obligation;
|
|
245
|
+
};
|
|
246
|
+
exports.getStrategySimulatedObligation = getStrategySimulatedObligation;
|
|
247
|
+
const getStrategyDepositedAmount = (
|
|
248
|
+
// AppContext
|
|
249
|
+
reserveMap,
|
|
250
|
+
// Strategy
|
|
251
|
+
lstMap, strategyType, obligation) => {
|
|
252
|
+
var _a, _b;
|
|
253
|
+
const depositReserves = (0, exports.getStrategyDepositReserves)(reserveMap, strategyType);
|
|
254
|
+
const borrowReserve = (0, exports.getStrategyBorrowReserve)(reserveMap, strategyType);
|
|
255
|
+
const defaultCurrencyReserve = (0, exports.getStrategyDefaultCurrencyReserve)(reserveMap, strategyType);
|
|
256
|
+
//
|
|
257
|
+
if (!obligation || !(0, exports.hasStrategyPosition)(obligation))
|
|
258
|
+
return new bignumber_js_1.default(0);
|
|
259
|
+
let resultSui = new bignumber_js_1.default(0);
|
|
260
|
+
for (const deposit of obligation.deposits) {
|
|
261
|
+
if ((0, sui_fe_1.isSui)(deposit.coinType)) {
|
|
262
|
+
resultSui = resultSui.plus(deposit.depositedAmount);
|
|
263
|
+
}
|
|
264
|
+
else if (Object.keys(lstMap).includes(deposit.coinType)) {
|
|
265
|
+
const lstToSuiExchangeRate = (_b = (_a = lstMap === null || lstMap === void 0 ? void 0 : lstMap[deposit.coinType]) === null || _a === void 0 ? void 0 : _a.lstToSuiExchangeRate) !== null && _b !== void 0 ? _b : new bignumber_js_1.default(1);
|
|
266
|
+
// const redeemFeePercent =
|
|
267
|
+
// lstMap?.[deposit.coinType]?.redeemFeePercent ?? new BigNumber(0);
|
|
268
|
+
resultSui = resultSui.plus(deposit.depositedAmount.times(lstToSuiExchangeRate));
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
const depositReserve = reserveMap[deposit.coinType];
|
|
272
|
+
const priceSui = depositReserve.price.div((0, exports.getStrategySuiReserve)(reserveMap).price);
|
|
273
|
+
resultSui = resultSui.plus(deposit.depositedAmount.times(priceSui));
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
const resultUsd = resultSui.times((0, exports.getStrategySuiReserve)(reserveMap).price);
|
|
277
|
+
const resultDefaultCurrency = new bignumber_js_1.default(resultUsd.div(defaultCurrencyReserve.price)).decimalPlaces(defaultCurrencyReserve.token.decimals, bignumber_js_1.default.ROUND_DOWN);
|
|
278
|
+
return resultDefaultCurrency;
|
|
279
|
+
};
|
|
280
|
+
exports.getStrategyDepositedAmount = getStrategyDepositedAmount;
|
|
281
|
+
const getStrategyBorrowedAmount = (
|
|
282
|
+
// AppContext
|
|
283
|
+
reserveMap,
|
|
284
|
+
// Strategy
|
|
285
|
+
lstMap, strategyType, obligation) => {
|
|
286
|
+
const depositReserves = (0, exports.getStrategyDepositReserves)(reserveMap, strategyType);
|
|
287
|
+
const borrowReserve = (0, exports.getStrategyBorrowReserve)(reserveMap, strategyType);
|
|
288
|
+
const defaultCurrencyReserve = (0, exports.getStrategyDefaultCurrencyReserve)(reserveMap, strategyType);
|
|
289
|
+
//
|
|
290
|
+
if (!obligation || !(0, exports.hasStrategyPosition)(obligation))
|
|
291
|
+
return new bignumber_js_1.default(0);
|
|
292
|
+
let resultSui = new bignumber_js_1.default(0);
|
|
293
|
+
for (const borrow of obligation.borrows) {
|
|
294
|
+
if ((0, sui_fe_1.isSui)(borrow.coinType)) {
|
|
295
|
+
resultSui = resultSui.plus(borrow.borrowedAmount);
|
|
296
|
+
}
|
|
297
|
+
else if (Object.keys(lstMap).includes(borrow.coinType)) {
|
|
298
|
+
// Can't borrow LSTs
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
const priceSui = borrowReserve.price.div((0, exports.getStrategySuiReserve)(reserveMap).price);
|
|
303
|
+
resultSui = resultSui.plus(borrow.borrowedAmount.times(priceSui));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
const resultUsd = resultSui.times((0, exports.getStrategySuiReserve)(reserveMap).price);
|
|
307
|
+
const resultDefaultCurrency = new bignumber_js_1.default(resultUsd.div(defaultCurrencyReserve.price)).decimalPlaces(defaultCurrencyReserve.token.decimals, bignumber_js_1.default.ROUND_DOWN);
|
|
308
|
+
return resultDefaultCurrency;
|
|
309
|
+
};
|
|
310
|
+
exports.getStrategyBorrowedAmount = getStrategyBorrowedAmount;
|
|
311
|
+
const getStrategyTvlAmount = (
|
|
312
|
+
// AppContext
|
|
313
|
+
reserveMap,
|
|
314
|
+
// Strategy
|
|
315
|
+
lstMap, strategyType, obligation) => {
|
|
316
|
+
if (!obligation || !(0, exports.hasStrategyPosition)(obligation))
|
|
317
|
+
return new bignumber_js_1.default(0);
|
|
318
|
+
return (0, exports.getStrategyDepositedAmount)(reserveMap, lstMap, strategyType, obligation).minus((0, exports.getStrategyBorrowedAmount)(reserveMap, lstMap, strategyType, obligation));
|
|
319
|
+
};
|
|
320
|
+
exports.getStrategyTvlAmount = getStrategyTvlAmount;
|
|
321
|
+
const getStrategyExposure = (
|
|
322
|
+
// AppContext
|
|
323
|
+
reserveMap,
|
|
324
|
+
// StrategyContext
|
|
325
|
+
lstMap, strategyType, obligation) => {
|
|
326
|
+
const depositReserves = (0, exports.getStrategyDepositReserves)(reserveMap, strategyType);
|
|
327
|
+
const borrowReserve = (0, exports.getStrategyBorrowReserve)(reserveMap, strategyType);
|
|
328
|
+
const defaultCurrencyReserve = (0, exports.getStrategyDefaultCurrencyReserve)(reserveMap, strategyType);
|
|
329
|
+
//
|
|
330
|
+
if (!obligation || !(0, exports.hasStrategyPosition)(obligation))
|
|
331
|
+
return new bignumber_js_1.default(0);
|
|
332
|
+
const depositedAmountUsd = (0, exports.getStrategyDepositedAmount)(reserveMap, lstMap, strategyType, obligation).times(defaultCurrencyReserve.price);
|
|
333
|
+
const borrowedAmountUsd = (0, exports.getStrategyBorrowedAmount)(reserveMap, lstMap, strategyType, obligation).times(defaultCurrencyReserve.price);
|
|
334
|
+
return depositedAmountUsd.eq(0)
|
|
335
|
+
? new bignumber_js_1.default(0)
|
|
336
|
+
: depositedAmountUsd.div(depositedAmountUsd.minus(borrowedAmountUsd));
|
|
337
|
+
};
|
|
338
|
+
exports.getStrategyExposure = getStrategyExposure;
|
|
339
|
+
// Simulate
|
|
340
|
+
// Stats
|
|
341
|
+
// Stats - Global TVL
|
|
342
|
+
const fetchStrategyGlobalTvlAmountUsdMap = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
343
|
+
try {
|
|
344
|
+
const url = `${sui_fe_1.API_URL}/strategies/tvl`;
|
|
345
|
+
const res = yield fetch(url);
|
|
346
|
+
const json = yield res.json();
|
|
347
|
+
if ((json === null || json === void 0 ? void 0 : json.statusCode) === 500)
|
|
348
|
+
throw new Error("Failed to fetch Strategies TVL");
|
|
349
|
+
const result = Object.values(strategyOwnerCap_1.StrategyType).reduce((acc, strategyType) => {
|
|
350
|
+
const entry = json.strategies.find((s) => `${s.strategyType}` === strategyType);
|
|
351
|
+
const tvlUsd = entry
|
|
352
|
+
? new bignumber_js_1.default(entry.tvlUsd)
|
|
353
|
+
: null;
|
|
354
|
+
return Object.assign(Object.assign({}, acc), { [strategyType]: tvlUsd });
|
|
355
|
+
}, {});
|
|
356
|
+
return result;
|
|
357
|
+
}
|
|
358
|
+
catch (err) {
|
|
359
|
+
console.error(err);
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
exports.fetchStrategyGlobalTvlAmountUsdMap = fetchStrategyGlobalTvlAmountUsdMap;
|
|
363
|
+
// Stats - Unclaimed rewards
|
|
364
|
+
const getStrategyUnclaimedRewardsAmount = (
|
|
365
|
+
// AppContext
|
|
366
|
+
reserveMap, rewardPriceMap, rewardCoinMetadataMap,
|
|
367
|
+
// UserContext
|
|
368
|
+
rewardMap,
|
|
369
|
+
// Strategy
|
|
370
|
+
lstMap, strategyType, obligation) => {
|
|
371
|
+
const depositReserves = (0, exports.getStrategyDepositReserves)(reserveMap, strategyType);
|
|
372
|
+
const borrowReserve = (0, exports.getStrategyBorrowReserve)(reserveMap, strategyType);
|
|
373
|
+
const defaultCurrencyReserve = (0, exports.getStrategyDefaultCurrencyReserve)(reserveMap, strategyType);
|
|
374
|
+
//
|
|
375
|
+
if (!obligation || !(0, exports.hasStrategyPosition)(obligation))
|
|
376
|
+
return new bignumber_js_1.default(0);
|
|
377
|
+
const rewardsMap = (0, liquidityMining_1.getRewardsMap)(obligation, rewardMap, rewardCoinMetadataMap);
|
|
378
|
+
const resultSui = Object.entries(rewardsMap).reduce((acc, [coinType, { amount }]) => {
|
|
379
|
+
var _a, _b, _c;
|
|
380
|
+
if ((0, sui_fe_1.isSui)(coinType)) {
|
|
381
|
+
return acc.plus(amount);
|
|
382
|
+
}
|
|
383
|
+
else if (Object.keys(lstMap).includes(coinType)) {
|
|
384
|
+
const lstToSuiExchangeRate = (_b = (_a = lstMap === null || lstMap === void 0 ? void 0 : lstMap[coinType]) === null || _a === void 0 ? void 0 : _a.lstToSuiExchangeRate) !== null && _b !== void 0 ? _b : new bignumber_js_1.default(1);
|
|
385
|
+
return acc.plus(amount.times(lstToSuiExchangeRate));
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
const price = (_c = rewardPriceMap[coinType]) !== null && _c !== void 0 ? _c : new bignumber_js_1.default(0);
|
|
389
|
+
const priceSui = price.div((0, exports.getStrategySuiReserve)(reserveMap).price);
|
|
390
|
+
return acc.plus(amount.times(priceSui));
|
|
391
|
+
}
|
|
392
|
+
}, new bignumber_js_1.default(0));
|
|
393
|
+
const resultUsd = resultSui.times((0, exports.getStrategySuiReserve)(reserveMap).price);
|
|
394
|
+
const resultDefaultCurrency = new bignumber_js_1.default(resultUsd.div(defaultCurrencyReserve.price)).decimalPlaces(defaultCurrencyReserve.token.decimals, bignumber_js_1.default.ROUND_DOWN);
|
|
395
|
+
return resultDefaultCurrency;
|
|
396
|
+
};
|
|
397
|
+
exports.getStrategyUnclaimedRewardsAmount = getStrategyUnclaimedRewardsAmount;
|
|
398
|
+
// Stats - History
|
|
399
|
+
// Stats - Historical TVL
|
|
400
|
+
// Stats - APR
|
|
401
|
+
// Stats - Health
|
|
402
|
+
// Stats - Liquidation price
|