@scallop-io/sui-scallop-sdk 0.46.40 → 0.46.42
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/dist/builders/loyaltyProgramBuilder.d.ts +1 -1
- package/dist/builders/sCoinBuilder.d.ts +4 -0
- package/dist/constants/common.d.ts +3 -1
- package/dist/constants/enum.d.ts +12 -10
- package/dist/index.js +660 -97
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +658 -92
- package/dist/index.mjs.map +1 -1
- package/dist/models/scallopBuilder.d.ts +16 -1
- package/dist/models/scallopClient.d.ts +5 -0
- package/dist/models/scallopQuery.d.ts +21 -2
- package/dist/models/scallopUtils.d.ts +32 -2
- package/dist/queries/portfolioQuery.d.ts +1 -1
- package/dist/queries/sCoinQuery.d.ts +27 -0
- package/dist/test.d.ts +1 -0
- package/dist/types/address.d.ts +8 -1
- package/dist/types/builder/core.d.ts +12 -4
- package/dist/types/builder/index.d.ts +6 -1
- package/dist/types/builder/sCoin.d.ts +37 -0
- package/dist/types/builder/spool.d.ts +2 -1
- package/dist/types/constant/common.d.ts +3 -2
- package/dist/types/constant/enum.d.ts +13 -1
- package/dist/types/query/core.d.ts +2 -1
- package/dist/types/query/index.d.ts +1 -0
- package/dist/types/query/portfolio.d.ts +1 -0
- package/dist/types/query/sCoin.d.ts +1 -0
- package/package.json +3 -3
- package/src/builders/coreBuilder.ts +72 -17
- package/src/builders/index.ts +5 -1
- package/src/builders/loyaltyProgramBuilder.ts +1 -1
- package/src/builders/referralBuilder.ts +1 -1
- package/src/builders/sCoinBuilder.ts +119 -0
- package/src/builders/spoolBuilder.ts +1 -1
- package/src/builders/vescaBuilder.ts +3 -3
- package/src/constants/common.ts +19 -5
- package/src/constants/enum.ts +98 -20
- package/src/constants/testAddress.ts +115 -21
- package/src/models/scallopAddress.ts +44 -3
- package/src/models/scallopBuilder.ts +43 -7
- package/src/models/scallopCache.ts +32 -4
- package/src/models/scallopClient.ts +121 -0
- package/src/models/scallopQuery.ts +46 -0
- package/src/models/scallopUtils.ts +56 -2
- package/src/queries/coreQuery.ts +10 -4
- package/src/queries/portfolioQuery.ts +26 -4
- package/src/queries/sCoinQuery.ts +94 -0
- package/src/queries/vescaQuery.ts +0 -1
- package/src/test.ts +19 -0
- package/src/types/address.ts +13 -0
- package/src/types/builder/core.ts +19 -4
- package/src/types/builder/index.ts +11 -3
- package/src/types/builder/sCoin.ts +61 -0
- package/src/types/builder/spool.ts +2 -0
- package/src/types/constant/common.ts +4 -1
- package/src/types/constant/enum.ts +17 -0
- package/src/types/query/core.ts +3 -0
- package/src/types/query/index.ts +1 -0
- package/src/types/query/portfolio.ts +1 -0
- package/src/types/query/sCoin.ts +1 -0
- package/src/utils/builder.ts +1 -1
- package/src/utils/util.ts +13 -17
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
ScallopTxBlock,
|
|
15
15
|
SupportMarketCoins,
|
|
16
16
|
SupportAssetCoins,
|
|
17
|
+
SupportSCoin,
|
|
17
18
|
} from '../types';
|
|
18
19
|
import { ScallopCache } from './scallopCache';
|
|
19
20
|
import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
|
|
@@ -124,7 +125,7 @@ export class ScallopBuilder {
|
|
|
124
125
|
sender: string
|
|
125
126
|
) {
|
|
126
127
|
const coinType = this.utils.parseCoinType(assetCoinName);
|
|
127
|
-
const coins = await this.utils.
|
|
128
|
+
const coins = await this.utils.selectCoins(amount, coinType, sender);
|
|
128
129
|
const [takeCoin, leftCoin] = txBlock.takeAmountFromCoins(coins, amount);
|
|
129
130
|
return { takeCoin, leftCoin };
|
|
130
131
|
}
|
|
@@ -145,13 +146,48 @@ export class ScallopBuilder {
|
|
|
145
146
|
sender: string
|
|
146
147
|
) {
|
|
147
148
|
const marketCoinType = this.utils.parseMarketCoinType(marketCoinName);
|
|
148
|
-
const coins = await this.utils.
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
149
|
+
const coins = await this.utils.selectCoins(amount, marketCoinType, sender);
|
|
150
|
+
const totalAmount = coins.reduce((prev, coin) => {
|
|
151
|
+
prev += Number(coin.balance);
|
|
152
|
+
return prev;
|
|
153
|
+
}, 0);
|
|
154
|
+
const [takeCoin, leftCoin] = txBlock.takeAmountFromCoins(
|
|
155
|
+
coins,
|
|
156
|
+
Math.min(amount, totalAmount)
|
|
152
157
|
);
|
|
153
|
-
|
|
154
|
-
|
|
158
|
+
return { takeCoin, leftCoin, totalAmount };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Specifying the sender's amount of sCoins to get coins args from transaction result.
|
|
163
|
+
*
|
|
164
|
+
* @param txBlock - Scallop txBlock or txBlock created by SuiKit .
|
|
165
|
+
* @param marketCoinName - Specific support sCoin name.
|
|
166
|
+
* @param amount - Amount of coins to be selected.
|
|
167
|
+
* @param sender - Sender address.
|
|
168
|
+
* @return Take coin and left coin.
|
|
169
|
+
*/
|
|
170
|
+
public async selectSCoin(
|
|
171
|
+
txBlock: ScallopTxBlock | SuiKitTxBlock,
|
|
172
|
+
sCoinName: SupportSCoin,
|
|
173
|
+
amount: number,
|
|
174
|
+
sender: string
|
|
175
|
+
) {
|
|
176
|
+
const sCoinType = this.utils.parseSCoinType(sCoinName);
|
|
177
|
+
const coins = await this.utils.selectCoins(amount, sCoinType, sender);
|
|
178
|
+
const totalAmount = coins.reduce((prev, coin) => {
|
|
179
|
+
prev += Number(coin.balance);
|
|
180
|
+
return prev;
|
|
181
|
+
}, 0);
|
|
182
|
+
const [takeCoin, leftCoin] = txBlock.takeAmountFromCoins(
|
|
183
|
+
coins,
|
|
184
|
+
Math.min(totalAmount, amount)
|
|
185
|
+
);
|
|
186
|
+
return {
|
|
187
|
+
takeCoin,
|
|
188
|
+
leftCoin,
|
|
189
|
+
totalAmount,
|
|
190
|
+
};
|
|
155
191
|
}
|
|
156
192
|
|
|
157
193
|
/**
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { QueryClient, QueryClientConfig } from '@tanstack/query-core';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
SuiTxArg,
|
|
4
|
+
SuiTxBlock,
|
|
5
|
+
normalizeStructTag,
|
|
6
|
+
normalizeSuiAddress,
|
|
7
|
+
} from '@scallop-io/sui-kit';
|
|
3
8
|
import { SuiKit } from '@scallop-io/sui-kit';
|
|
4
9
|
import type {
|
|
5
10
|
SuiObjectResponse,
|
|
@@ -162,6 +167,7 @@ export class ScallopCache {
|
|
|
162
167
|
objectIds: string[],
|
|
163
168
|
options?: SuiObjectDataOptions
|
|
164
169
|
): Promise<SuiObjectData[]> {
|
|
170
|
+
if (objectIds.length === 0) return [];
|
|
165
171
|
const queryKey = [
|
|
166
172
|
'getObjects',
|
|
167
173
|
JSON.stringify(objectIds),
|
|
@@ -171,7 +177,7 @@ export class ScallopCache {
|
|
|
171
177
|
queryKey.push(JSON.stringify(options));
|
|
172
178
|
}
|
|
173
179
|
return this.queryClient.fetchQuery({
|
|
174
|
-
queryKey,
|
|
180
|
+
queryKey: queryKey,
|
|
175
181
|
queryFn: async () => {
|
|
176
182
|
return await this.suiKit.getObjects(objectIds, options);
|
|
177
183
|
},
|
|
@@ -254,7 +260,7 @@ export class ScallopCache {
|
|
|
254
260
|
const allBalances = await this.suiKit
|
|
255
261
|
.client()
|
|
256
262
|
.getAllBalances({ owner });
|
|
257
|
-
|
|
263
|
+
const balances = allBalances.reduce(
|
|
258
264
|
(acc, coinBalance) => {
|
|
259
265
|
if (coinBalance.totalBalance !== '0') {
|
|
260
266
|
acc[normalizeStructTag(coinBalance.coinType)] =
|
|
@@ -264,12 +270,34 @@ export class ScallopCache {
|
|
|
264
270
|
},
|
|
265
271
|
{} as { [k: string]: string }
|
|
266
272
|
);
|
|
273
|
+
|
|
274
|
+
// Set query data for each coin balance
|
|
275
|
+
for (const coinType in balances) {
|
|
276
|
+
const coinBalanceQueryKey = [
|
|
277
|
+
'getCoinBalance',
|
|
278
|
+
normalizeSuiAddress(owner),
|
|
279
|
+
normalizeStructTag(coinType),
|
|
280
|
+
];
|
|
281
|
+
this.queryClient.setQueryData(
|
|
282
|
+
coinBalanceQueryKey,
|
|
283
|
+
balances[coinType]
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return balances;
|
|
267
288
|
},
|
|
289
|
+
staleTime: 5000,
|
|
268
290
|
});
|
|
269
291
|
}
|
|
270
292
|
|
|
271
293
|
public async queryGetCoinBalance(input: GetBalanceParams): Promise<string> {
|
|
272
|
-
|
|
294
|
+
if (!input.coinType) return '0';
|
|
295
|
+
|
|
296
|
+
const queryKey = [
|
|
297
|
+
'getCoinBalance',
|
|
298
|
+
normalizeSuiAddress(input.owner),
|
|
299
|
+
normalizeStructTag(input.coinType),
|
|
300
|
+
];
|
|
273
301
|
return this.queryClient.fetchQuery({
|
|
274
302
|
queryKey,
|
|
275
303
|
queryFn: async () => {
|
|
@@ -4,6 +4,8 @@ import {
|
|
|
4
4
|
ADDRESSES_ID,
|
|
5
5
|
SUPPORT_BORROW_INCENTIVE_POOLS,
|
|
6
6
|
SUPPORT_BORROW_INCENTIVE_REWARDS,
|
|
7
|
+
SUPPORT_SCOIN,
|
|
8
|
+
SUPPORT_SPOOLS,
|
|
7
9
|
} from '../constants';
|
|
8
10
|
import { ScallopAddress } from './scallopAddress';
|
|
9
11
|
import { ScallopUtils } from './scallopUtils';
|
|
@@ -23,6 +25,7 @@ import type {
|
|
|
23
25
|
SupportStakeMarketCoins,
|
|
24
26
|
SupportBorrowIncentiveCoins,
|
|
25
27
|
ScallopTxBlock,
|
|
28
|
+
SupportSCoin,
|
|
26
29
|
} from '../types';
|
|
27
30
|
import { ScallopCache } from './scallopCache';
|
|
28
31
|
import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
|
|
@@ -959,6 +962,124 @@ export class ScallopClient {
|
|
|
959
962
|
}
|
|
960
963
|
}
|
|
961
964
|
|
|
965
|
+
/* ==================== Migrate market coin to sCoin method ==================== */
|
|
966
|
+
/**
|
|
967
|
+
* Function to migrate all market coin in user wallet into sCoin
|
|
968
|
+
* @returns Transaction response
|
|
969
|
+
*/
|
|
970
|
+
public async migrateAllMarketCoin<S extends boolean>(
|
|
971
|
+
sign: S = true as S
|
|
972
|
+
): Promise<ScallopClientFnReturnType<S>> {
|
|
973
|
+
const txBlock = this.builder.createTxBlock();
|
|
974
|
+
txBlock.setSender(this.walletAddress);
|
|
975
|
+
|
|
976
|
+
const toTransfer: SuiObjectArg[] = [];
|
|
977
|
+
await Promise.all(
|
|
978
|
+
SUPPORT_SCOIN.map(async (sCoinName) => {
|
|
979
|
+
/**
|
|
980
|
+
* First check marketCoin inside mini wallet
|
|
981
|
+
* Then check stakedMarketCoin inside spool
|
|
982
|
+
*/
|
|
983
|
+
let toDestroyMarketCoin: SuiObjectArg | undefined;
|
|
984
|
+
|
|
985
|
+
// check market coin in mini wallet
|
|
986
|
+
try {
|
|
987
|
+
const marketCoins = await this.utils.selectCoins(
|
|
988
|
+
Number.MAX_SAFE_INTEGER,
|
|
989
|
+
this.utils.parseMarketCoinType(sCoinName as SupportSCoin),
|
|
990
|
+
this.walletAddress
|
|
991
|
+
); // throw error no coins found
|
|
992
|
+
|
|
993
|
+
const mergedMarketCoin = marketCoins[0];
|
|
994
|
+
if (marketCoins.length > 1) {
|
|
995
|
+
txBlock.mergeCoins(mergedMarketCoin, marketCoins.slice(1));
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
toDestroyMarketCoin = mergedMarketCoin;
|
|
999
|
+
} catch (e: any) {
|
|
1000
|
+
// Ignore
|
|
1001
|
+
const errMsg = e.toString() as String;
|
|
1002
|
+
if (!errMsg.includes('No valid coins found for the transaction'))
|
|
1003
|
+
throw e;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
// check for staked market coin in spool
|
|
1007
|
+
if (SUPPORT_SPOOLS.includes(sCoinName as SupportStakeMarketCoins)) {
|
|
1008
|
+
try {
|
|
1009
|
+
const stakedMarketCoins = await txBlock.unstakeQuick(
|
|
1010
|
+
Number.MAX_SAFE_INTEGER,
|
|
1011
|
+
sCoinName as SupportStakeMarketCoins
|
|
1012
|
+
);
|
|
1013
|
+
if (stakedMarketCoins.length > 0) {
|
|
1014
|
+
const mergedStakedMarketCoin = stakedMarketCoins[0];
|
|
1015
|
+
if (stakedMarketCoins.length > 1) {
|
|
1016
|
+
txBlock.mergeCoins(
|
|
1017
|
+
mergedStakedMarketCoin,
|
|
1018
|
+
stakedMarketCoins.slice(1)
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
// merge with takeMarketCoin
|
|
1022
|
+
if (toDestroyMarketCoin) {
|
|
1023
|
+
txBlock.mergeCoins(toDestroyMarketCoin, [
|
|
1024
|
+
mergedStakedMarketCoin,
|
|
1025
|
+
]);
|
|
1026
|
+
} else {
|
|
1027
|
+
toDestroyMarketCoin = mergedStakedMarketCoin;
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
} catch (e: any) {
|
|
1031
|
+
// ignore
|
|
1032
|
+
const errMsg = e.toString();
|
|
1033
|
+
if (!errMsg.includes('No stake account found')) throw e;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
// if market coin found, mint sCoin
|
|
1038
|
+
if (toDestroyMarketCoin) {
|
|
1039
|
+
// mint new sCoin
|
|
1040
|
+
const sCoin = txBlock.mintSCoin(
|
|
1041
|
+
sCoinName as SupportSCoin,
|
|
1042
|
+
toDestroyMarketCoin
|
|
1043
|
+
);
|
|
1044
|
+
|
|
1045
|
+
// check if current sCoin exist
|
|
1046
|
+
try {
|
|
1047
|
+
const existSCoins = await this.utils.selectCoins(
|
|
1048
|
+
Number.MAX_SAFE_INTEGER,
|
|
1049
|
+
this.utils.parseSCoinType(sCoinName as SupportSCoin),
|
|
1050
|
+
this.walletAddress
|
|
1051
|
+
); // throw error on no coins found
|
|
1052
|
+
const mergedSCoin = existSCoins[0];
|
|
1053
|
+
if (existSCoins.length > 1) {
|
|
1054
|
+
txBlock.mergeCoins(mergedSCoin, existSCoins.slice(1));
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
// merge existing sCoin to new sCoin
|
|
1058
|
+
txBlock.mergeCoins(sCoin, [mergedSCoin]);
|
|
1059
|
+
} catch (e: any) {
|
|
1060
|
+
// ignore
|
|
1061
|
+
const errMsg = e.toString() as String;
|
|
1062
|
+
if (!errMsg.includes('No valid coins found for the transaction'))
|
|
1063
|
+
throw e;
|
|
1064
|
+
}
|
|
1065
|
+
toTransfer.push(sCoin);
|
|
1066
|
+
}
|
|
1067
|
+
})
|
|
1068
|
+
);
|
|
1069
|
+
|
|
1070
|
+
if (toTransfer.length > 0) {
|
|
1071
|
+
txBlock.transferObjects(toTransfer, this.walletAddress);
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
if (sign) {
|
|
1075
|
+
return (await this.suiKit.signAndSendTxn(
|
|
1076
|
+
txBlock
|
|
1077
|
+
)) as ScallopClientFnReturnType<S>;
|
|
1078
|
+
} else {
|
|
1079
|
+
return txBlock.txBlock as ScallopClientFnReturnType<S>;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
|
|
962
1083
|
/* ==================== Other Method ==================== */
|
|
963
1084
|
|
|
964
1085
|
/**
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
StakePools,
|
|
46
46
|
StakeRewardPools,
|
|
47
47
|
SupportBorrowIncentiveCoins,
|
|
48
|
+
SupportSCoin,
|
|
48
49
|
} from '../types';
|
|
49
50
|
import { ScallopAddress } from './scallopAddress';
|
|
50
51
|
import { ScallopUtils } from './scallopUtils';
|
|
@@ -52,6 +53,11 @@ import { ScallopIndexer } from './scallopIndexer';
|
|
|
52
53
|
import { ScallopCache } from './scallopCache';
|
|
53
54
|
import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
|
|
54
55
|
import { SuiObjectData } from '@mysten/sui.js/src/client';
|
|
56
|
+
import {
|
|
57
|
+
getSCoinAmount,
|
|
58
|
+
getSCoinAmounts,
|
|
59
|
+
getSCoinTotalSupply,
|
|
60
|
+
} from 'src/queries/sCoinQuery';
|
|
55
61
|
|
|
56
62
|
/**
|
|
57
63
|
* @description
|
|
@@ -596,6 +602,46 @@ export class ScallopQuery {
|
|
|
596
602
|
}
|
|
597
603
|
|
|
598
604
|
/**
|
|
605
|
+
* Get total supply of sCoin
|
|
606
|
+
* @param sCoinName - Supported sCoin name
|
|
607
|
+
* @returns Total Supply
|
|
608
|
+
*/
|
|
609
|
+
public async getSCoinTotalSupply(sCoinName: SupportSCoin) {
|
|
610
|
+
return await getSCoinTotalSupply(this, sCoinName);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Get all sCoin amounts.
|
|
615
|
+
*
|
|
616
|
+
* @param sCoinNames - Specific an array of support sCoin name.
|
|
617
|
+
* @param ownerAddress - The owner address.
|
|
618
|
+
* @return All market sCoin amounts.
|
|
619
|
+
*/
|
|
620
|
+
public async getSCoinAmounts(
|
|
621
|
+
sCoinNames?: SupportSCoin[],
|
|
622
|
+
ownerAddress?: string
|
|
623
|
+
) {
|
|
624
|
+
return await getSCoinAmounts(this, sCoinNames, ownerAddress);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Get sCoin amount.
|
|
629
|
+
*
|
|
630
|
+
* @param coinNames - Specific support sCoin name.
|
|
631
|
+
* @param ownerAddress - The owner address.
|
|
632
|
+
* @return sCoin amount.
|
|
633
|
+
*/
|
|
634
|
+
public async getSCoinAmount(
|
|
635
|
+
sCoinName: SupportSCoin | SupportMarketCoins,
|
|
636
|
+
ownerAddress?: string
|
|
637
|
+
) {
|
|
638
|
+
const parsedSCoinName = this.utils.parseSCoinName(sCoinName);
|
|
639
|
+
return parsedSCoinName
|
|
640
|
+
? await getSCoinAmount(this, parsedSCoinName, ownerAddress)
|
|
641
|
+
: 0;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/*
|
|
599
645
|
* Get flashloan fee for specified assets
|
|
600
646
|
*/
|
|
601
647
|
public async getFlashLoanFees(
|
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
coinIds,
|
|
17
17
|
UNLOCK_ROUND_DURATION,
|
|
18
18
|
MAX_LOCK_DURATION,
|
|
19
|
+
SUPPORT_SCOIN,
|
|
20
|
+
sCoinIds,
|
|
19
21
|
} from '../constants';
|
|
20
22
|
import { queryObligation } from '../queries';
|
|
21
23
|
import {
|
|
@@ -35,6 +37,7 @@ import type {
|
|
|
35
37
|
CoinPrices,
|
|
36
38
|
PriceMap,
|
|
37
39
|
CoinWrappedType,
|
|
40
|
+
SupportSCoin,
|
|
38
41
|
} from '../types';
|
|
39
42
|
import { PYTH_ENDPOINTS } from 'src/constants/pyth';
|
|
40
43
|
import { ScallopCache } from './scallopCache';
|
|
@@ -170,6 +173,57 @@ export class ScallopUtils {
|
|
|
170
173
|
}
|
|
171
174
|
}
|
|
172
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Convert coin name to sCoin name.
|
|
178
|
+
*
|
|
179
|
+
* @param coinName - Specific support coin name.
|
|
180
|
+
* @return sCoin name.
|
|
181
|
+
*/
|
|
182
|
+
public parseSCoinName<T extends SupportSCoin>(
|
|
183
|
+
coinName: SupportCoins | SupportMarketCoins
|
|
184
|
+
) {
|
|
185
|
+
// need more check because sbtc, ssol and sapt has no sCoin type
|
|
186
|
+
if (
|
|
187
|
+
isMarketCoin(coinName) &&
|
|
188
|
+
SUPPORT_SCOIN.includes(coinName as SupportSCoin)
|
|
189
|
+
) {
|
|
190
|
+
return coinName as T;
|
|
191
|
+
} else {
|
|
192
|
+
const marketCoinName = `s${coinName}`;
|
|
193
|
+
if (SUPPORT_SCOIN.includes(marketCoinName as SupportSCoin)) {
|
|
194
|
+
return marketCoinName as T;
|
|
195
|
+
}
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Convert sCoin name into sCoin type
|
|
201
|
+
* @param sCoinName
|
|
202
|
+
* @returns sCoin type
|
|
203
|
+
*/
|
|
204
|
+
public parseSCoinType(sCoinName: SupportSCoin) {
|
|
205
|
+
return sCoinIds[sCoinName];
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Convert sCoin name into its underlying coin type
|
|
210
|
+
* @param sCoinName
|
|
211
|
+
* @returns coin type
|
|
212
|
+
*/
|
|
213
|
+
public parseUnderlyingSCoinType(sCoinName: SupportSCoin) {
|
|
214
|
+
const coinName = this.parseCoinName(sCoinName);
|
|
215
|
+
return this.parseCoinType(coinName);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Get sCoin treasury id from sCoin name
|
|
220
|
+
* @param sCoinName
|
|
221
|
+
* @returns sCoin treasury id
|
|
222
|
+
*/
|
|
223
|
+
public getSCoinTreasury(sCoinName: SupportSCoin) {
|
|
224
|
+
return this._address.get(`scoin.coins.${sCoinName}.treasury`);
|
|
225
|
+
}
|
|
226
|
+
|
|
173
227
|
/**
|
|
174
228
|
* Convert coin name to market coin type.
|
|
175
229
|
*
|
|
@@ -328,7 +382,7 @@ export class ScallopUtils {
|
|
|
328
382
|
* @param coinType - The coin type, default is 0x2::SUI::SUI.
|
|
329
383
|
* @return The selected transaction coin arguments.
|
|
330
384
|
*/
|
|
331
|
-
public async
|
|
385
|
+
public async selectCoins(
|
|
332
386
|
amount: number,
|
|
333
387
|
coinType: string = SUI_TYPE_ARG,
|
|
334
388
|
ownerAddress?: string
|
|
@@ -339,7 +393,7 @@ export class ScallopUtils {
|
|
|
339
393
|
amount,
|
|
340
394
|
coinType
|
|
341
395
|
);
|
|
342
|
-
return coins
|
|
396
|
+
return coins;
|
|
343
397
|
}
|
|
344
398
|
|
|
345
399
|
/**
|
package/src/queries/coreQuery.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
PROTOCOL_OBJECT_ID,
|
|
5
5
|
SUPPORT_COLLATERALS,
|
|
6
6
|
BORROW_FEE_PROTOCOL_ID,
|
|
7
|
+
USE_TEST_ADDRESS,
|
|
7
8
|
FlashLoanFeeObjectMap,
|
|
8
9
|
} from '../constants';
|
|
9
10
|
import {
|
|
@@ -405,7 +406,12 @@ export const getMarketPool = async (
|
|
|
405
406
|
}
|
|
406
407
|
}
|
|
407
408
|
|
|
408
|
-
if (
|
|
409
|
+
if (
|
|
410
|
+
balanceSheet &&
|
|
411
|
+
borrowIndex &&
|
|
412
|
+
interestModel &&
|
|
413
|
+
(USE_TEST_ADDRESS || borrowFeeRate)
|
|
414
|
+
) {
|
|
409
415
|
const parsedMarketPoolData = parseOriginMarketPoolData({
|
|
410
416
|
type: interestModel.type.fields,
|
|
411
417
|
maxBorrowRate: interestModel.max_borrow_rate.fields,
|
|
@@ -419,7 +425,7 @@ export const getMarketPool = async (
|
|
|
419
425
|
reserve: balanceSheet.revenue,
|
|
420
426
|
reserveFactor: interestModel.revenue_factor.fields,
|
|
421
427
|
borrowWeight: interestModel.borrow_weight.fields,
|
|
422
|
-
borrowFeeRate: borrowFeeRate,
|
|
428
|
+
borrowFeeRate: borrowFeeRate || { value: '0' },
|
|
423
429
|
baseBorrowRatePerSec: interestModel.base_borrow_rate_per_sec.fields,
|
|
424
430
|
borrowRateOnHighKink: interestModel.borrow_rate_on_high_kink.fields,
|
|
425
431
|
borrowRateOnMidKink: interestModel.borrow_rate_on_mid_kink.fields,
|
|
@@ -475,10 +481,10 @@ export const getMarketCollaterals = async (
|
|
|
475
481
|
collateralCoinNames = collateralCoinNames || [...SUPPORT_COLLATERALS];
|
|
476
482
|
const marketId = query.address.get('core.market');
|
|
477
483
|
const [marketObjectResponse, coinPrices] = await Promise.all([
|
|
478
|
-
query.cache.queryGetObject(marketId, {
|
|
484
|
+
await query.cache.queryGetObject(marketId, {
|
|
479
485
|
showContent: true,
|
|
480
486
|
}),
|
|
481
|
-
query.utils.getCoinPrices(collateralCoinNames ?? []),
|
|
487
|
+
await query.utils.getCoinPrices(collateralCoinNames ?? []),
|
|
482
488
|
]);
|
|
483
489
|
const marketCollaterals: MarketCollaterals = {};
|
|
484
490
|
|
|
@@ -24,6 +24,7 @@ import type {
|
|
|
24
24
|
TotalValueLocked,
|
|
25
25
|
SupportBorrowIncentiveCoins,
|
|
26
26
|
ObligationBorrowIcentiveReward,
|
|
27
|
+
SupportBorrowIncentiveRewardCoins,
|
|
27
28
|
} from '../types';
|
|
28
29
|
|
|
29
30
|
/**
|
|
@@ -118,7 +119,8 @@ export const getLending = async (
|
|
|
118
119
|
stakeAccounts?: StakeAccount[],
|
|
119
120
|
coinAmount?: number,
|
|
120
121
|
marketCoinAmount?: number,
|
|
121
|
-
coinPrice?: number
|
|
122
|
+
coinPrice?: number,
|
|
123
|
+
sCoinAmount?: number
|
|
122
124
|
) => {
|
|
123
125
|
const marketCoinName = query.utils.parseMarketCoinName(poolCoinName);
|
|
124
126
|
marketPool = marketPool || (await query.getMarketPool(poolCoinName, indexer));
|
|
@@ -140,6 +142,8 @@ export const getLending = async (
|
|
|
140
142
|
marketCoinAmount =
|
|
141
143
|
marketCoinAmount ||
|
|
142
144
|
(await query.getMarketCoinAmount(marketCoinName, ownerAddress));
|
|
145
|
+
sCoinAmount =
|
|
146
|
+
sCoinAmount || (await query.getSCoinAmount(marketCoinName, ownerAddress));
|
|
143
147
|
coinPrice =
|
|
144
148
|
coinPrice ||
|
|
145
149
|
(await query.utils.getCoinPrices([poolCoinName]))?.[poolCoinName];
|
|
@@ -206,9 +210,9 @@ export const getLending = async (
|
|
|
206
210
|
}
|
|
207
211
|
|
|
208
212
|
// Handle supplied coin
|
|
209
|
-
const suppliedAmount = BigNumber(marketCoinAmount)
|
|
210
|
-
|
|
211
|
-
|
|
213
|
+
const suppliedAmount = BigNumber(marketCoinAmount)
|
|
214
|
+
.plus(BigNumber(sCoinAmount))
|
|
215
|
+
.multipliedBy(marketPool?.conversionRate ?? 1);
|
|
212
216
|
const suppliedCoin = suppliedAmount.shiftedBy(-1 * coinDecimal);
|
|
213
217
|
const suppliedValue = suppliedCoin.multipliedBy(coinPrice ?? 0);
|
|
214
218
|
|
|
@@ -351,6 +355,7 @@ export const getObligationAccount = async (
|
|
|
351
355
|
let totalBorrowCapacityValue = BigNumber(0);
|
|
352
356
|
let totalRequiredCollateralValue = BigNumber(0);
|
|
353
357
|
let totalBorrowedPools = 0;
|
|
358
|
+
let totalRewardedPools = 0;
|
|
354
359
|
let totalBorrowedValue = BigNumber(0);
|
|
355
360
|
let totalBorrowedValueWithWeight = BigNumber(0);
|
|
356
361
|
|
|
@@ -555,6 +560,22 @@ export const getObligationAccount = async (
|
|
|
555
560
|
}
|
|
556
561
|
}
|
|
557
562
|
|
|
563
|
+
if (
|
|
564
|
+
Object.keys(borrowIncentivePool.points).some((coinName: any) => {
|
|
565
|
+
const rewardApr =
|
|
566
|
+
borrowIncentivePool.points[
|
|
567
|
+
coinName as SupportBorrowIncentiveRewardCoins
|
|
568
|
+
]?.rewardApr;
|
|
569
|
+
return (
|
|
570
|
+
rewardApr !== Infinity &&
|
|
571
|
+
typeof rewardApr == 'number' &&
|
|
572
|
+
rewardApr > 0
|
|
573
|
+
);
|
|
574
|
+
}) &&
|
|
575
|
+
borrowIncentiveAccount.debtAmount > 0
|
|
576
|
+
) {
|
|
577
|
+
totalRewardedPools++;
|
|
578
|
+
}
|
|
558
579
|
borrowIncentives[coinName] = {
|
|
559
580
|
coinName: borrowIncentivePool.coinName,
|
|
560
581
|
coinType: borrowIncentivePool.coinType,
|
|
@@ -612,6 +633,7 @@ export const getObligationAccount = async (
|
|
|
612
633
|
totalRiskLevel: riskLevel.toNumber(),
|
|
613
634
|
totalDepositedPools,
|
|
614
635
|
totalBorrowedPools,
|
|
636
|
+
totalRewardedPools,
|
|
615
637
|
collaterals,
|
|
616
638
|
debts,
|
|
617
639
|
borrowIncentives,
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { bcs } from '@mysten/sui.js/bcs';
|
|
2
|
+
import assert from 'assert';
|
|
3
|
+
import BigNumber from 'bignumber.js';
|
|
4
|
+
import { SUPPORT_SCOIN } from 'src/constants';
|
|
5
|
+
import { ScallopQuery } from 'src/models';
|
|
6
|
+
import { OptionalKeys, SupportSCoin, sCoinBalance } from 'src/types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Get total supply of sCoin
|
|
10
|
+
* @param query
|
|
11
|
+
* @param sCoinName
|
|
12
|
+
* @returns `number`
|
|
13
|
+
*/
|
|
14
|
+
export const getSCoinTotalSupply = async (
|
|
15
|
+
query: ScallopQuery,
|
|
16
|
+
sCoinName: SupportSCoin
|
|
17
|
+
): Promise<sCoinBalance> => {
|
|
18
|
+
const sCoinPkgId = query.address.get('scoin.id');
|
|
19
|
+
// get treasury
|
|
20
|
+
const args = [query.utils.getSCoinTreasury(sCoinName)];
|
|
21
|
+
const typeArgs = [
|
|
22
|
+
query.utils.parseSCoinType(sCoinName),
|
|
23
|
+
query.utils.parseUnderlyingSCoinType(sCoinName),
|
|
24
|
+
];
|
|
25
|
+
const queryTarget = `${sCoinPkgId}::s_coin_converter::total_supply`;
|
|
26
|
+
const queryResults = await query.cache.queryInspectTxn({
|
|
27
|
+
queryTarget,
|
|
28
|
+
args,
|
|
29
|
+
typeArgs,
|
|
30
|
+
});
|
|
31
|
+
const results = queryResults.results;
|
|
32
|
+
if (results && results[0].returnValues) {
|
|
33
|
+
const value = Uint8Array.from(results[0].returnValues[0][0]);
|
|
34
|
+
const type = results[0].returnValues[0][1]; // should be u64
|
|
35
|
+
assert(type === 'u64', 'Result type is not u64');
|
|
36
|
+
|
|
37
|
+
return BigNumber(bcs.de(type, value))
|
|
38
|
+
.shiftedBy(
|
|
39
|
+
query.utils.getCoinDecimal(query.utils.parseCoinName(sCoinName))
|
|
40
|
+
)
|
|
41
|
+
.toNumber();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return 0;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Query all owned sCoin amount.
|
|
49
|
+
*
|
|
50
|
+
* @param query - The Scallop query instance.
|
|
51
|
+
* @param sCoinNames - Specific an array of support sCoin name.
|
|
52
|
+
* @param ownerAddress - The owner address.
|
|
53
|
+
* @return All owned sCoins amount.
|
|
54
|
+
*/
|
|
55
|
+
export const getSCoinAmounts = async (
|
|
56
|
+
query: ScallopQuery,
|
|
57
|
+
sCoinNames?: SupportSCoin[],
|
|
58
|
+
ownerAddress?: string
|
|
59
|
+
) => {
|
|
60
|
+
sCoinNames = sCoinNames || [...SUPPORT_SCOIN];
|
|
61
|
+
const owner = ownerAddress || query.suiKit.currentAddress();
|
|
62
|
+
const sCoins = {} as OptionalKeys<Record<SupportSCoin, number>>;
|
|
63
|
+
|
|
64
|
+
await Promise.allSettled(
|
|
65
|
+
sCoinNames.map(async (sCoinName) => {
|
|
66
|
+
const sCoin = await getSCoinAmount(query, sCoinName, owner);
|
|
67
|
+
sCoins[sCoinName] = sCoin;
|
|
68
|
+
})
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
return sCoins;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Query owned sCoin amount.
|
|
76
|
+
*
|
|
77
|
+
* @param query - The Scallop query instance.
|
|
78
|
+
* @param sCoinNames - Specific support sCoin name.
|
|
79
|
+
* @param ownerAddress - The owner address.
|
|
80
|
+
* @return Owned sCoin amount.
|
|
81
|
+
*/
|
|
82
|
+
export const getSCoinAmount = async (
|
|
83
|
+
query: ScallopQuery,
|
|
84
|
+
sCoinName: SupportSCoin,
|
|
85
|
+
ownerAddress?: string
|
|
86
|
+
) => {
|
|
87
|
+
const owner = ownerAddress || query.suiKit.currentAddress();
|
|
88
|
+
const sCoinType = query.utils.parseSCoinType(sCoinName);
|
|
89
|
+
const amount = await query.cache.queryGetCoinBalance({
|
|
90
|
+
owner,
|
|
91
|
+
coinType: sCoinType,
|
|
92
|
+
});
|
|
93
|
+
return BigNumber(amount).toNumber();
|
|
94
|
+
};
|
|
@@ -244,7 +244,6 @@ export const getVeScaTreasuryInfo = async (
|
|
|
244
244
|
const treasuryFields = veScaTreasury.data.content
|
|
245
245
|
.fields as VeScaTreasuryFields;
|
|
246
246
|
|
|
247
|
-
console.log(treasuryFields);
|
|
248
247
|
const totalLockedSca = BigNumber(
|
|
249
248
|
treasuryFields.unlock_schedule.fields.locked_sca_amount
|
|
250
249
|
)
|
package/src/test.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Scallop } from './models';
|
|
2
|
+
import * as dotenv from 'dotenv';
|
|
3
|
+
dotenv.config();
|
|
4
|
+
const scallop = new Scallop({
|
|
5
|
+
secretKey: process.env.SECRET_KEY as string,
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
const main = async () => {
|
|
9
|
+
const query = await scallop.createScallopQuery();
|
|
10
|
+
|
|
11
|
+
const res = await query.getVeScas(
|
|
12
|
+
'0xd1a70cfe7332e994a950b9c570e93def4b6d2ec53b34ff5c0cc9946226a7cf3d'
|
|
13
|
+
);
|
|
14
|
+
console.dir(res, { depth: null });
|
|
15
|
+
};
|
|
16
|
+
main()
|
|
17
|
+
.then()
|
|
18
|
+
.catch(console.error)
|
|
19
|
+
.finally(() => process.exit(0));
|