@scallop-io/sui-scallop-sdk 2.3.11 → 2.3.12
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/README.md +7 -7
- package/dist/index.d.mts +13 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +20 -20
- package/dist/index.mjs +2 -2
- package/package.json +1 -1
- package/src/models/scallopAddress.ts +1 -1
- package/src/models/scallopQuery.ts +7 -6
- package/src/models/scallopUtils.ts +9 -7
- package/src/queries/borrowIncentiveQuery.ts +21 -14
- package/src/queries/coreQuery.ts +9 -3
- package/src/queries/isolatedAssetQuery.ts +5 -2
- package/src/queries/portfolioQuery.ts +123 -109
- package/src/queries/priceQuery.ts +2 -130
- package/src/queries/vescaQuery.ts +9 -4
- package/src/types/query/portfolio.ts +10 -0
- package/src/utils/query.ts +5 -10
package/package.json
CHANGED
|
@@ -442,7 +442,7 @@ class ScallopAddress {
|
|
|
442
442
|
public readonly scallopAxios: ScallopAxios;
|
|
443
443
|
private readonly addressMap = new Map<NetworkType, AddressesInterface>();
|
|
444
444
|
private readonly defaultParamValues = {
|
|
445
|
-
addressId: '
|
|
445
|
+
addressId: '695fcdc084f790c04eb068dc',
|
|
446
446
|
network: 'mainnet' as NetworkType,
|
|
447
447
|
} as const;
|
|
448
448
|
|
|
@@ -37,8 +37,6 @@ import {
|
|
|
37
37
|
getOnDemandAggObjectIds,
|
|
38
38
|
getPoolAddresses,
|
|
39
39
|
getPriceUpdatePolicies,
|
|
40
|
-
getPythPrice,
|
|
41
|
-
getPythPrices,
|
|
42
40
|
getSCoinAmount,
|
|
43
41
|
getSCoinAmounts,
|
|
44
42
|
getSCoinSwapRate,
|
|
@@ -321,7 +319,7 @@ class ScallopQuery implements ScallopQueryInterface {
|
|
|
321
319
|
* @return Asset coin price.
|
|
322
320
|
*/
|
|
323
321
|
async getPriceFromPyth(assetCoinName: string) {
|
|
324
|
-
return await getPythPrice(
|
|
322
|
+
return await this.utils.getPythPrice(assetCoinName);
|
|
325
323
|
}
|
|
326
324
|
|
|
327
325
|
/**
|
|
@@ -331,7 +329,7 @@ class ScallopQuery implements ScallopQueryInterface {
|
|
|
331
329
|
* @return Array of asset coin prices.
|
|
332
330
|
*/
|
|
333
331
|
async getPricesFromPyth(assetCoinNames: string[]) {
|
|
334
|
-
return await getPythPrices(
|
|
332
|
+
return await this.utils.getPythPrices(assetCoinNames);
|
|
335
333
|
}
|
|
336
334
|
|
|
337
335
|
/* ==================== Spool Query Methods ==================== */
|
|
@@ -855,8 +853,11 @@ class ScallopQuery implements ScallopQueryInterface {
|
|
|
855
853
|
/**
|
|
856
854
|
* Check if asset is an isolated asset
|
|
857
855
|
*/
|
|
858
|
-
async isIsolatedAsset(
|
|
859
|
-
|
|
856
|
+
async isIsolatedAsset(
|
|
857
|
+
assetCoinName: string,
|
|
858
|
+
useOnChainQuery: boolean = false
|
|
859
|
+
) {
|
|
860
|
+
return isIsolatedAsset(this.utils, assetCoinName, useOnChainQuery);
|
|
860
861
|
}
|
|
861
862
|
|
|
862
863
|
/**
|
|
@@ -483,13 +483,15 @@ class ScallopUtils implements ScallopUtilsInterface {
|
|
|
483
483
|
return (
|
|
484
484
|
await Promise.all(
|
|
485
485
|
Object.entries(assetToPriceFeedMapping).map(
|
|
486
|
-
async ([
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
486
|
+
async ([coinName, feed]) => {
|
|
487
|
+
try {
|
|
488
|
+
const price = await this.getPythPrice(coinName, feed);
|
|
489
|
+
return { coinName, price };
|
|
490
|
+
} catch (e) {
|
|
491
|
+
console.error(e);
|
|
492
|
+
return { coinName, price: 0 };
|
|
493
|
+
}
|
|
494
|
+
}
|
|
493
495
|
)
|
|
494
496
|
)
|
|
495
497
|
).reduce(
|
|
@@ -31,7 +31,7 @@ import { queryKeys } from 'src/constants';
|
|
|
31
31
|
* @param address
|
|
32
32
|
* @returns
|
|
33
33
|
*/
|
|
34
|
-
|
|
34
|
+
const queryBorrowIncentivePools = async ({
|
|
35
35
|
address,
|
|
36
36
|
scallopSuiKit,
|
|
37
37
|
}: {
|
|
@@ -135,17 +135,19 @@ export const getBorrowIncentivePools = async (
|
|
|
135
135
|
poolCoinDecimal
|
|
136
136
|
);
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
138
|
+
if (poolPoint.points > calculatedPoolPoint.accumulatedPoints) {
|
|
139
|
+
borrowIncentivePoolPoints[coinName as string] = {
|
|
140
|
+
symbol,
|
|
141
|
+
coinName: rewardCoinName,
|
|
142
|
+
coinType: rewardCoinType,
|
|
143
|
+
coinDecimal,
|
|
144
|
+
coinPrice: rewardCoinPrice,
|
|
145
|
+
points: poolPoint.points,
|
|
146
|
+
distributedPoint: poolPoint.distributedPoint,
|
|
147
|
+
weightedAmount: poolPoint.weightedAmount,
|
|
148
|
+
...calculatedPoolPoint,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
149
151
|
}
|
|
150
152
|
|
|
151
153
|
const stakedAmount = BigNumber(parsedBorrowIncentivePoolData.staked);
|
|
@@ -186,13 +188,18 @@ export const queryBorrowIncentiveAccounts = async (
|
|
|
186
188
|
'borrowIncentive.incentiveAccounts'
|
|
187
189
|
);
|
|
188
190
|
const queryTarget = `${queryPkgId}::incentive_account_query::incentive_account_data`;
|
|
191
|
+
const [incentiveAccountVersion, obligationDataVersion] = await Promise.all([
|
|
192
|
+
getSharedObjectData(incentiveAccountsId, utils.scallopSuiKit),
|
|
193
|
+
getSharedObjectData(obligationId, utils.scallopSuiKit),
|
|
194
|
+
]);
|
|
195
|
+
|
|
189
196
|
const args = [
|
|
190
197
|
txBlock.sharedObjectRef({
|
|
191
|
-
...
|
|
198
|
+
...incentiveAccountVersion,
|
|
192
199
|
mutable: true,
|
|
193
200
|
}),
|
|
194
201
|
txBlock.sharedObjectRef({
|
|
195
|
-
...
|
|
202
|
+
...obligationDataVersion,
|
|
196
203
|
mutable: true,
|
|
197
204
|
}),
|
|
198
205
|
];
|
package/src/queries/coreQuery.ts
CHANGED
|
@@ -956,17 +956,23 @@ export const queryObligation = async (
|
|
|
956
956
|
const market = address.get('core.market');
|
|
957
957
|
const queryTarget = `${packageId}::obligation_query::obligation_data`;
|
|
958
958
|
|
|
959
|
+
const [versionData, marketData, obligationData] = await Promise.all([
|
|
960
|
+
getSharedObjectData(version, scallopSuiKit),
|
|
961
|
+
getSharedObjectData(market, scallopSuiKit),
|
|
962
|
+
getSharedObjectData(obligationId, scallopSuiKit),
|
|
963
|
+
]);
|
|
964
|
+
|
|
959
965
|
const args = [
|
|
960
966
|
txBlock.sharedObjectRef({
|
|
961
|
-
...
|
|
967
|
+
...versionData,
|
|
962
968
|
mutable: false,
|
|
963
969
|
}),
|
|
964
970
|
txBlock.sharedObjectRef({
|
|
965
|
-
...
|
|
971
|
+
...marketData,
|
|
966
972
|
mutable: true,
|
|
967
973
|
}),
|
|
968
974
|
txBlock.sharedObjectRef({
|
|
969
|
-
...
|
|
975
|
+
...obligationData,
|
|
970
976
|
mutable: true,
|
|
971
977
|
}),
|
|
972
978
|
{
|
|
@@ -81,15 +81,18 @@ export const getIsolatedAssets = async (
|
|
|
81
81
|
|
|
82
82
|
/**
|
|
83
83
|
* Check if the coin type is an isolated asset
|
|
84
|
+
* @param utils ScallopUtils
|
|
84
85
|
* @param coinName coin name
|
|
86
|
+
* @param useOnChainQuery whether to use on-chain query
|
|
85
87
|
* @returns true if the coin type is an isolated asset
|
|
86
88
|
*/
|
|
87
89
|
export const isIsolatedAsset = async (
|
|
88
90
|
utils: ScallopUtils,
|
|
89
|
-
coinName: string
|
|
91
|
+
coinName: string,
|
|
92
|
+
useOnChainQuery?: boolean
|
|
90
93
|
): Promise<boolean> => {
|
|
91
94
|
const assetInPoolAddresses = utils.constants.poolAddresses[coinName];
|
|
92
|
-
if (assetInPoolAddresses) {
|
|
95
|
+
if (assetInPoolAddresses && !useOnChainQuery) {
|
|
93
96
|
return assetInPoolAddresses.isIsolated;
|
|
94
97
|
}
|
|
95
98
|
|
|
@@ -512,69 +512,6 @@ export const getObligationAccount = async (
|
|
|
512
512
|
]),
|
|
513
513
|
];
|
|
514
514
|
|
|
515
|
-
for (const assetCoinName of borrowAssetCoinNames) {
|
|
516
|
-
const debt = obligationQuery?.debts.find((debt) => {
|
|
517
|
-
const poolCoinName = query.utils.parseCoinNameFromType(debt.type.name);
|
|
518
|
-
return assetCoinName === poolCoinName;
|
|
519
|
-
});
|
|
520
|
-
|
|
521
|
-
const marketPool = market.pools[assetCoinName];
|
|
522
|
-
const coinDecimal = query.utils.getCoinDecimal(assetCoinName);
|
|
523
|
-
const coinPrice = coinPrices?.[assetCoinName] ?? 0;
|
|
524
|
-
const coinAmount = coinAmounts?.[assetCoinName] ?? 0;
|
|
525
|
-
|
|
526
|
-
if (marketPool) {
|
|
527
|
-
const increasedRate = debt?.borrowIndex
|
|
528
|
-
? marketPool.borrowIndex / Number(debt.borrowIndex) - 1
|
|
529
|
-
: 0;
|
|
530
|
-
const borrowedAmount = BigNumber(debt?.amount ?? 0).multipliedBy(
|
|
531
|
-
increasedRate + 1
|
|
532
|
-
);
|
|
533
|
-
const borrowedCoin = borrowedAmount.shiftedBy(-1 * coinDecimal);
|
|
534
|
-
|
|
535
|
-
const requiredRepayAmount = borrowedAmount;
|
|
536
|
-
const requiredRepayCoin = requiredRepayAmount.shiftedBy(-1 * coinDecimal);
|
|
537
|
-
|
|
538
|
-
const availableRepayAmount = BigNumber(coinAmount);
|
|
539
|
-
const availableRepayCoin = availableRepayAmount.shiftedBy(
|
|
540
|
-
-1 * coinDecimal
|
|
541
|
-
);
|
|
542
|
-
|
|
543
|
-
const borrowedValue = requiredRepayCoin.multipliedBy(coinPrice);
|
|
544
|
-
const borrowedValueWithWeight = borrowedValue.multipliedBy(
|
|
545
|
-
marketPool.borrowWeight
|
|
546
|
-
);
|
|
547
|
-
|
|
548
|
-
totalBorrowedValue = totalBorrowedValue.plus(borrowedValue);
|
|
549
|
-
totalBorrowedValueWithWeight = totalBorrowedValueWithWeight.plus(
|
|
550
|
-
borrowedValueWithWeight
|
|
551
|
-
);
|
|
552
|
-
|
|
553
|
-
if (borrowedAmount.isGreaterThan(0)) {
|
|
554
|
-
totalBorrowedPools++;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
debts[assetCoinName] = {
|
|
558
|
-
coinName: assetCoinName,
|
|
559
|
-
coinType: query.utils.parseCoinType(assetCoinName),
|
|
560
|
-
symbol: query.utils.parseSymbol(assetCoinName),
|
|
561
|
-
coinDecimal: coinDecimal,
|
|
562
|
-
coinPrice: coinPrice,
|
|
563
|
-
borrowedAmount: borrowedAmount.toNumber(),
|
|
564
|
-
borrowedCoin: borrowedCoin.toNumber(),
|
|
565
|
-
borrowedValue: borrowedValue.toNumber(),
|
|
566
|
-
borrowedValueWithWeight: borrowedValueWithWeight.toNumber(),
|
|
567
|
-
borrowIndex: Number(debt?.borrowIndex ?? 0),
|
|
568
|
-
requiredRepayAmount: requiredRepayAmount.toNumber(),
|
|
569
|
-
requiredRepayCoin: requiredRepayCoin.toNumber(),
|
|
570
|
-
availableBorrowAmount: 0,
|
|
571
|
-
availableBorrowCoin: 0,
|
|
572
|
-
availableRepayAmount: availableRepayAmount.toNumber(),
|
|
573
|
-
availableRepayCoin: availableRepayCoin.toNumber(),
|
|
574
|
-
};
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
|
|
578
515
|
for (const [poolCoinName, borrowIncentiveAccount] of Object.entries(
|
|
579
516
|
borrowIncentiveAccounts
|
|
580
517
|
)) {
|
|
@@ -616,22 +553,29 @@ export const getObligationAccount = async (
|
|
|
616
553
|
|
|
617
554
|
// for veSCA
|
|
618
555
|
const weightScale = BigNumber(1_000_000_000_000);
|
|
556
|
+
const boostScale = BigNumber(poolPoint.baseWeight).dividedBy(
|
|
557
|
+
weightScale
|
|
558
|
+
);
|
|
619
559
|
const boostValue = BigNumber(accountPoint.weightedAmount)
|
|
620
560
|
.div(
|
|
621
|
-
BigNumber(borrowIncentiveAccount.debtAmount)
|
|
622
|
-
|
|
623
|
-
|
|
561
|
+
BigNumber(borrowIncentiveAccount.debtAmount).multipliedBy(
|
|
562
|
+
boostScale
|
|
563
|
+
)
|
|
624
564
|
)
|
|
625
565
|
.isFinite()
|
|
626
566
|
? BigNumber(accountPoint.weightedAmount)
|
|
627
567
|
.div(
|
|
628
|
-
BigNumber(borrowIncentiveAccount.debtAmount)
|
|
629
|
-
|
|
630
|
-
|
|
568
|
+
BigNumber(borrowIncentiveAccount.debtAmount).multipliedBy(
|
|
569
|
+
boostScale
|
|
570
|
+
)
|
|
631
571
|
)
|
|
632
572
|
.toNumber()
|
|
633
573
|
: 1;
|
|
634
574
|
|
|
575
|
+
const rewardApr = isFinite(poolPoint.rewardApr)
|
|
576
|
+
? poolPoint.rewardApr
|
|
577
|
+
: 0;
|
|
578
|
+
|
|
635
579
|
if (availableClaimAmount.isGreaterThanOrEqualTo(0)) {
|
|
636
580
|
rewards.push({
|
|
637
581
|
coinName: poolPoint.coinName,
|
|
@@ -642,6 +586,9 @@ export const getObligationAccount = async (
|
|
|
642
586
|
weightedBorrowAmount: accountBorrowedAmount.toNumber(),
|
|
643
587
|
availableClaimAmount: availableClaimAmount.toNumber(),
|
|
644
588
|
availableClaimCoin: availableClaimCoin.toNumber(),
|
|
589
|
+
baseRewardApr: rewardApr,
|
|
590
|
+
boostedRewardApr: rewardApr * boostValue,
|
|
591
|
+
maxBoost: 1 / boostScale.toNumber(),
|
|
645
592
|
boostValue,
|
|
646
593
|
});
|
|
647
594
|
}
|
|
@@ -674,6 +621,72 @@ export const getObligationAccount = async (
|
|
|
674
621
|
}
|
|
675
622
|
}
|
|
676
623
|
|
|
624
|
+
for (const assetCoinName of borrowAssetCoinNames) {
|
|
625
|
+
const debt = obligationQuery?.debts.find((debt) => {
|
|
626
|
+
const poolCoinName = query.utils.parseCoinNameFromType(debt.type.name);
|
|
627
|
+
return assetCoinName === poolCoinName;
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
const marketPool = market.pools[assetCoinName];
|
|
631
|
+
const coinDecimal = query.utils.getCoinDecimal(assetCoinName);
|
|
632
|
+
const coinPrice = coinPrices?.[assetCoinName] ?? 0;
|
|
633
|
+
const coinAmount = coinAmounts?.[assetCoinName] ?? 0;
|
|
634
|
+
|
|
635
|
+
if (marketPool) {
|
|
636
|
+
const increasedRate = debt?.borrowIndex
|
|
637
|
+
? marketPool.borrowIndex / Number(debt.borrowIndex) - 1
|
|
638
|
+
: 0;
|
|
639
|
+
const borrowedAmount = BigNumber(debt?.amount ?? 0).multipliedBy(
|
|
640
|
+
increasedRate + 1
|
|
641
|
+
);
|
|
642
|
+
const borrowedCoin = borrowedAmount.shiftedBy(-1 * coinDecimal);
|
|
643
|
+
|
|
644
|
+
const requiredRepayAmount = borrowedAmount;
|
|
645
|
+
const requiredRepayCoin = requiredRepayAmount.shiftedBy(-1 * coinDecimal);
|
|
646
|
+
|
|
647
|
+
const availableRepayAmount = BigNumber(coinAmount);
|
|
648
|
+
const availableRepayCoin = availableRepayAmount.shiftedBy(
|
|
649
|
+
-1 * coinDecimal
|
|
650
|
+
);
|
|
651
|
+
|
|
652
|
+
const borrowedValue = requiredRepayCoin.multipliedBy(coinPrice);
|
|
653
|
+
const borrowedValueWithWeight = borrowedValue.multipliedBy(
|
|
654
|
+
marketPool.borrowWeight
|
|
655
|
+
);
|
|
656
|
+
|
|
657
|
+
totalBorrowedValue = totalBorrowedValue.plus(borrowedValue);
|
|
658
|
+
totalBorrowedValueWithWeight = totalBorrowedValueWithWeight.plus(
|
|
659
|
+
borrowedValueWithWeight
|
|
660
|
+
);
|
|
661
|
+
|
|
662
|
+
if (borrowedAmount.isGreaterThan(0)) {
|
|
663
|
+
totalBorrowedPools++;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
debts[assetCoinName] = {
|
|
667
|
+
coinName: assetCoinName,
|
|
668
|
+
coinType: query.utils.parseCoinType(assetCoinName),
|
|
669
|
+
symbol: query.utils.parseSymbol(assetCoinName),
|
|
670
|
+
coinDecimal: coinDecimal,
|
|
671
|
+
coinPrice: coinPrice,
|
|
672
|
+
borrowedAmount: borrowedAmount.toNumber(),
|
|
673
|
+
borrowedCoin: borrowedCoin.toNumber(),
|
|
674
|
+
borrowedValue: borrowedValue.toNumber(),
|
|
675
|
+
borrowedValueWithWeight: borrowedValueWithWeight.toNumber(),
|
|
676
|
+
borrowIndex: Number(debt?.borrowIndex ?? 0),
|
|
677
|
+
requiredRepayAmount: requiredRepayAmount.toNumber(),
|
|
678
|
+
requiredRepayCoin: requiredRepayCoin.toNumber(),
|
|
679
|
+
availableBorrowAmount: 0,
|
|
680
|
+
availableBorrowCoin: 0,
|
|
681
|
+
availableRepayAmount: availableRepayAmount.toNumber(),
|
|
682
|
+
availableRepayCoin: availableRepayCoin.toNumber(),
|
|
683
|
+
rewards: (borrowIncentives[assetCoinName]?.rewards ?? []).filter(
|
|
684
|
+
({ weightedBorrowAmount }) => weightedBorrowAmount > 0
|
|
685
|
+
),
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
677
690
|
let riskLevel = totalRequiredCollateralValue.isZero()
|
|
678
691
|
? // Note: when there is no collateral and debt is not zero, then it's a bad-debt situation.
|
|
679
692
|
totalBorrowedValueWithWeight.isGreaterThan(0)
|
|
@@ -905,24 +918,19 @@ export const getUserPortfolio = async (
|
|
|
905
918
|
const coinPrices = await query.getAllCoinPrices({ indexer });
|
|
906
919
|
const market = await query.getMarketPools(undefined, { indexer, coinPrices });
|
|
907
920
|
|
|
908
|
-
const [lendings, obligationAccounts,
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
marketPools: market.pools,
|
|
922
|
-
coinPrices,
|
|
923
|
-
}),
|
|
924
|
-
query.getVeScas({ walletAddress, excludeEmpty: true }),
|
|
925
|
-
]);
|
|
921
|
+
const [lendings, obligationAccounts, veScas] = await Promise.all([
|
|
922
|
+
query.getLendings(undefined, walletAddress, {
|
|
923
|
+
indexer,
|
|
924
|
+
marketPools: market.pools,
|
|
925
|
+
coinPrices,
|
|
926
|
+
}),
|
|
927
|
+
query.getObligationAccounts(walletAddress, {
|
|
928
|
+
indexer,
|
|
929
|
+
market: market,
|
|
930
|
+
coinPrices,
|
|
931
|
+
}),
|
|
932
|
+
query.getVeScas({ walletAddress, excludeEmpty: true }),
|
|
933
|
+
]);
|
|
926
934
|
|
|
927
935
|
// get pending rewards (spool and borrow incentive)
|
|
928
936
|
const parsedLendings = Object.values(lendings)
|
|
@@ -977,29 +985,35 @@ export const getUserPortfolio = async (
|
|
|
977
985
|
(debt): debt is NonNullable<typeof debt> =>
|
|
978
986
|
!!debt && debt.borrowedCoin > 0
|
|
979
987
|
)
|
|
980
|
-
.map((debt) =>
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
.filter(
|
|
994
|
-
(t): t is NonNullable<typeof t> => !!t && isFinite(t.rewardApr)
|
|
988
|
+
.map((debt) => {
|
|
989
|
+
return {
|
|
990
|
+
coinName: debt.coinName,
|
|
991
|
+
symbol: debt.symbol,
|
|
992
|
+
coinDecimals: debt.coinDecimal,
|
|
993
|
+
coinType: debt.coinType,
|
|
994
|
+
coinPrice: debt.coinPrice,
|
|
995
|
+
borrowedCoin: debt.borrowedCoin,
|
|
996
|
+
borrowedValueInUsd: debt.borrowedValueWithWeight,
|
|
997
|
+
borrowApr: market.pools[debt.coinName]?.borrowApr,
|
|
998
|
+
borrowApy: market.pools[debt.coinName]?.borrowApy,
|
|
999
|
+
incentiveInfos: (
|
|
1000
|
+
obligationAccount.borrowIncentives[debt.coinName]?.rewards ?? []
|
|
995
1001
|
)
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1002
|
+
.filter(
|
|
1003
|
+
(t): t is NonNullable<typeof t> =>
|
|
1004
|
+
!!t && isFinite(t.baseRewardApr)
|
|
1005
|
+
)
|
|
1006
|
+
.map((t) => ({
|
|
1007
|
+
coinName: t.coinName,
|
|
1008
|
+
symbol: t.symbol,
|
|
1009
|
+
coinType: t.coinType,
|
|
1010
|
+
boostValue: t.boostValue,
|
|
1011
|
+
maxBoost: t.maxBoost,
|
|
1012
|
+
incentiveApr: t.baseRewardApr,
|
|
1013
|
+
boostedIncentiveApr: t.boostedRewardApr,
|
|
1014
|
+
})),
|
|
1015
|
+
};
|
|
1016
|
+
}),
|
|
1003
1017
|
};
|
|
1004
1018
|
});
|
|
1005
1019
|
|
|
@@ -1,134 +1,6 @@
|
|
|
1
|
-
import { SuiObjectData } from '@mysten/sui/client';
|
|
2
|
-
import type { ScallopAddress, ScallopQuery, ScallopSuiKit } from 'src/models';
|
|
3
|
-
import type { CoinPrices, MarketPools, OptionalKeys } from '../types';
|
|
4
1
|
import BigNumber from 'bignumber.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* Get price from pyth fee object.
|
|
8
|
-
*
|
|
9
|
-
* @param query - The Scallop query instance.
|
|
10
|
-
* @param assetCoinName - Specific support asset coin name.
|
|
11
|
-
* @return Asset coin price.
|
|
12
|
-
*/
|
|
13
|
-
export const getPythPrice = async (
|
|
14
|
-
{
|
|
15
|
-
address,
|
|
16
|
-
scallopSuiKit,
|
|
17
|
-
}: {
|
|
18
|
-
address: ScallopAddress;
|
|
19
|
-
scallopSuiKit: ScallopSuiKit;
|
|
20
|
-
},
|
|
21
|
-
assetCoinName: string,
|
|
22
|
-
priceFeedObject?: SuiObjectData | null
|
|
23
|
-
) => {
|
|
24
|
-
const pythFeedObjectId = address.get(
|
|
25
|
-
`core.coins.${assetCoinName}.oracle.pyth.feedObject`
|
|
26
|
-
);
|
|
27
|
-
priceFeedObject =
|
|
28
|
-
priceFeedObject ||
|
|
29
|
-
(await scallopSuiKit.queryGetObject(pythFeedObjectId))?.data;
|
|
30
|
-
|
|
31
|
-
if (priceFeedObject) {
|
|
32
|
-
const priceFeedPoolObject = priceFeedObject;
|
|
33
|
-
if (
|
|
34
|
-
priceFeedPoolObject.content &&
|
|
35
|
-
'fields' in priceFeedPoolObject.content
|
|
36
|
-
) {
|
|
37
|
-
const fields = priceFeedPoolObject.content.fields as any;
|
|
38
|
-
const expoMagnitude = Number(
|
|
39
|
-
fields.price_info.fields.price_feed.fields.price.fields.expo.fields
|
|
40
|
-
.magnitude
|
|
41
|
-
);
|
|
42
|
-
const expoNegative = Number(
|
|
43
|
-
fields.price_info.fields.price_feed.fields.price.fields.expo.fields
|
|
44
|
-
.negative
|
|
45
|
-
);
|
|
46
|
-
const priceMagnitude = Number(
|
|
47
|
-
fields.price_info.fields.price_feed.fields.price.fields.price.fields
|
|
48
|
-
.magnitude
|
|
49
|
-
);
|
|
50
|
-
const priceNegative = Number(
|
|
51
|
-
fields.price_info.fields.price_feed.fields.price.fields.price.fields
|
|
52
|
-
.negative
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
return (
|
|
56
|
-
priceMagnitude *
|
|
57
|
-
10 ** ((expoNegative ? -1 : 1) * expoMagnitude) *
|
|
58
|
-
(priceNegative ? -1 : 1)
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return 0;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
export const getPythPrices = async (
|
|
67
|
-
{
|
|
68
|
-
address,
|
|
69
|
-
scallopSuiKit,
|
|
70
|
-
}: {
|
|
71
|
-
address: ScallopAddress;
|
|
72
|
-
scallopSuiKit: ScallopSuiKit;
|
|
73
|
-
},
|
|
74
|
-
assetCoinNames: string[]
|
|
75
|
-
) => {
|
|
76
|
-
const pythPriceFeedIds = assetCoinNames.reduce(
|
|
77
|
-
(prev, assetCoinName) => {
|
|
78
|
-
const pythPriceFeed = address.get(
|
|
79
|
-
`core.coins.${assetCoinName}.oracle.pyth.feedObject`
|
|
80
|
-
);
|
|
81
|
-
if (pythPriceFeed) {
|
|
82
|
-
if (!prev[pythPriceFeed]) {
|
|
83
|
-
prev[pythPriceFeed] = [assetCoinName];
|
|
84
|
-
} else {
|
|
85
|
-
prev[pythPriceFeed].push(assetCoinName);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
return prev;
|
|
89
|
-
},
|
|
90
|
-
{} as Record<string, string[]>
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
// Fetch multiple objects at once to save rpc calls
|
|
94
|
-
const priceFeedObjects = await scallopSuiKit.queryGetObjects(
|
|
95
|
-
Object.keys(pythPriceFeedIds)
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
const assetToPriceFeedMapping = priceFeedObjects.reduce(
|
|
99
|
-
(prev, priceFeedObject) => {
|
|
100
|
-
pythPriceFeedIds[priceFeedObject.objectId].forEach((assetCoinName) => {
|
|
101
|
-
prev[assetCoinName] = priceFeedObject;
|
|
102
|
-
});
|
|
103
|
-
return prev;
|
|
104
|
-
},
|
|
105
|
-
{} as Record<string, SuiObjectData>
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
return (
|
|
109
|
-
await Promise.all(
|
|
110
|
-
Object.entries(assetToPriceFeedMapping).map(
|
|
111
|
-
async ([assetCoinName, priceFeedObject]) => ({
|
|
112
|
-
coinName: assetCoinName,
|
|
113
|
-
price: await getPythPrice(
|
|
114
|
-
{
|
|
115
|
-
address,
|
|
116
|
-
scallopSuiKit,
|
|
117
|
-
},
|
|
118
|
-
assetCoinName as string,
|
|
119
|
-
priceFeedObject
|
|
120
|
-
),
|
|
121
|
-
})
|
|
122
|
-
)
|
|
123
|
-
)
|
|
124
|
-
).reduce(
|
|
125
|
-
(prev, curr) => {
|
|
126
|
-
prev[curr.coinName as string] = curr.price;
|
|
127
|
-
return prev;
|
|
128
|
-
},
|
|
129
|
-
{} as Record<string, number>
|
|
130
|
-
);
|
|
131
|
-
};
|
|
2
|
+
import type { ScallopQuery } from 'src/models';
|
|
3
|
+
import type { CoinPrices, MarketPools, OptionalKeys } from '../types';
|
|
132
4
|
|
|
133
5
|
export const getAllCoinPrices = async (
|
|
134
6
|
query: ScallopQuery,
|
|
@@ -192,13 +192,18 @@ const getTotalVeScaTreasuryAmount = async (
|
|
|
192
192
|
initialSharedVersion: '1',
|
|
193
193
|
});
|
|
194
194
|
|
|
195
|
-
const
|
|
196
|
-
|
|
195
|
+
const [treasuryVersion, veScaConfigVersion] = await Promise.all([
|
|
196
|
+
getSharedObjectData(
|
|
197
197
|
typeof veScaTreasury === 'string'
|
|
198
198
|
? veScaTreasury
|
|
199
199
|
: veScaTreasury.objectId,
|
|
200
200
|
utils.scallopSuiKit
|
|
201
|
-
)
|
|
201
|
+
),
|
|
202
|
+
getSharedObjectData(veScaConfig, utils.scallopSuiKit),
|
|
203
|
+
]);
|
|
204
|
+
|
|
205
|
+
const treasuryRef = txb.sharedObjectRef({
|
|
206
|
+
...treasuryVersion,
|
|
202
207
|
mutable: true,
|
|
203
208
|
});
|
|
204
209
|
|
|
@@ -206,7 +211,7 @@ const getTotalVeScaTreasuryAmount = async (
|
|
|
206
211
|
const refreshQueryTarget = `${veScaPkgId}::treasury::refresh`;
|
|
207
212
|
const refreshArgs = [
|
|
208
213
|
txb.sharedObjectRef({
|
|
209
|
-
...
|
|
214
|
+
...veScaConfigVersion,
|
|
210
215
|
mutable: false,
|
|
211
216
|
}),
|
|
212
217
|
treasuryRef,
|
|
@@ -69,6 +69,7 @@ export type ObligationAccount = {
|
|
|
69
69
|
totalRewardedPools: number;
|
|
70
70
|
collaterals: OptionalKeys<Record<string, ObligationCollateral>>;
|
|
71
71
|
debts: OptionalKeys<Record<string, ObligationDebt>>;
|
|
72
|
+
// @deprecated: incentive info moved to 'debts' field
|
|
72
73
|
borrowIncentives: OptionalKeys<Record<string, ObligationBorrowIncentive>>;
|
|
73
74
|
};
|
|
74
75
|
|
|
@@ -106,6 +107,12 @@ export type ObligationDebt = {
|
|
|
106
107
|
availableBorrowCoin: number;
|
|
107
108
|
availableRepayAmount: number;
|
|
108
109
|
availableRepayCoin: number;
|
|
110
|
+
rewards: {
|
|
111
|
+
boostValue: number;
|
|
112
|
+
maxBoost: number;
|
|
113
|
+
baseRewardApr: number;
|
|
114
|
+
boostedRewardApr: number;
|
|
115
|
+
}[];
|
|
109
116
|
};
|
|
110
117
|
|
|
111
118
|
export type ObligationBorrowIncentiveReward = {
|
|
@@ -117,7 +124,10 @@ export type ObligationBorrowIncentiveReward = {
|
|
|
117
124
|
weightedBorrowAmount: number;
|
|
118
125
|
availableClaimCoin: number;
|
|
119
126
|
availableClaimAmount: number;
|
|
127
|
+
baseRewardApr: number;
|
|
120
128
|
boostValue: number;
|
|
129
|
+
boostedRewardApr: number;
|
|
130
|
+
maxBoost: number;
|
|
121
131
|
};
|
|
122
132
|
|
|
123
133
|
export type ObligationBorrowIncentive = {
|