@kasufinance/kasu-sdk 1.0.4 → 2.1.0
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/.claude/settings.local.json +15 -0
- package/CLAUDE.md +410 -0
- package/README.md +179 -12
- package/dist/bundle.cjs.js +616 -67
- package/dist/bundle.esm.js +612 -69
- package/dist/facade/chain-configs.d.ts +11 -0
- package/dist/facade/chain-configs.js +84 -0
- package/dist/facade/chain-configs.js.map +1 -0
- package/dist/facade/deposits.d.ts +56 -0
- package/dist/facade/deposits.js +87 -0
- package/dist/facade/deposits.js.map +1 -0
- package/dist/facade/index.d.ts +6 -0
- package/dist/facade/index.js +9 -0
- package/dist/facade/index.js.map +1 -0
- package/dist/facade/kasu.d.ts +71 -0
- package/dist/facade/kasu.js +101 -0
- package/dist/facade/kasu.js.map +1 -0
- package/dist/facade/strategies.d.ts +37 -0
- package/dist/facade/strategies.js +112 -0
- package/dist/facade/strategies.js.map +1 -0
- package/dist/facade/types.d.ts +127 -0
- package/dist/facade/types.js +2 -0
- package/dist/facade/types.js.map +1 -0
- package/dist/facade/user-portfolio.d.ts +35 -0
- package/dist/facade/user-portfolio.js +53 -0
- package/dist/facade/user-portfolio.js.map +1 -0
- package/dist/index.d.ts +9 -17
- package/dist/index.js +9 -16
- package/dist/index.js.map +1 -1
- package/dist/kasu-sdk.d.ts +17 -0
- package/dist/kasu-sdk.js +17 -0
- package/dist/kasu-sdk.js.map +1 -0
- package/dist/sdk-config.d.ts +28 -4
- package/dist/sdk-config.js +8 -6
- package/dist/sdk-config.js.map +1 -1
- package/dist/services/DataService/data-service.d.ts +9 -2
- package/dist/services/DataService/data-service.js +90 -52
- package/dist/services/DataService/data-service.js.map +1 -1
- package/dist/services/DataService/queries.d.ts +0 -1
- package/dist/services/DataService/queries.js +0 -8
- package/dist/services/DataService/queries.js.map +1 -1
- package/dist/services/DataService/subgraph-types.d.ts +0 -6
- package/dist/services/DataService/types.d.ts +0 -1
- package/dist/services/Locking/locking.d.ts +4 -2
- package/dist/services/Locking/locking.js +89 -7
- package/dist/services/Locking/locking.js.map +1 -1
- package/dist/services/Portfolio/portfolio.d.ts +1 -0
- package/dist/services/Portfolio/portfolio.js +9 -1
- package/dist/services/Portfolio/portfolio.js.map +1 -1
- package/dist/tests/facade.test.d.ts +1 -0
- package/dist/tests/facade.test.js +196 -0
- package/dist/tests/facade.test.js.map +1 -0
- package/dist/tests/sample.test.js +19 -14
- package/dist/tests/sample.test.js.map +1 -1
- package/dist/utils/deployment-mode.d.ts +6 -0
- package/dist/utils/deployment-mode.js +8 -0
- package/dist/utils/deployment-mode.js.map +1 -0
- package/package.json +2 -2
- package/src/facade/chain-configs.ts +93 -0
- package/src/facade/deposits.ts +102 -0
- package/src/facade/index.ts +26 -0
- package/src/facade/kasu.ts +144 -0
- package/src/facade/strategies.ts +119 -0
- package/src/facade/types.ts +168 -0
- package/src/facade/user-portfolio.ts +73 -0
- package/src/index.ts +59 -25
- package/src/kasu-sdk.ts +27 -0
- package/src/sdk-config.ts +36 -15
- package/src/services/DataService/data-service.ts +105 -65
- package/src/services/DataService/queries.ts +0 -9
- package/src/services/DataService/subgraph-types.ts +0 -7
- package/src/services/DataService/types.ts +0 -1
- package/src/services/Locking/locking.ts +113 -12
- package/src/services/Portfolio/portfolio.ts +15 -5
- package/src/tests/facade.test.ts +245 -0
- package/src/tests/sample.test.ts +7 -9
- package/src/utils/deployment-mode.ts +9 -0
|
@@ -38,7 +38,6 @@ import {
|
|
|
38
38
|
getAllTrancheConfigurationsQuery,
|
|
39
39
|
getAllTranchesQuery,
|
|
40
40
|
getLendingPoolWithdrawalAndDepositsQuery,
|
|
41
|
-
getPlumeTvl,
|
|
42
41
|
getPoolNameQuery,
|
|
43
42
|
getPoolOverviewQuery,
|
|
44
43
|
} from './queries';
|
|
@@ -47,7 +46,6 @@ import {
|
|
|
47
46
|
LendingPoolSubgraph,
|
|
48
47
|
LendingPoolSubgraphReturn,
|
|
49
48
|
LendingPoolWithdrawalAndDepositSubgraph,
|
|
50
|
-
PlumeSubgraphReturn,
|
|
51
49
|
TrancheConfigurationSubgraphResult,
|
|
52
50
|
TrancheSubgraphResult,
|
|
53
51
|
} from './subgraph-types';
|
|
@@ -67,13 +65,11 @@ import {
|
|
|
67
65
|
|
|
68
66
|
export class DataService {
|
|
69
67
|
private readonly _graph: GraphQLClient;
|
|
70
|
-
private readonly _plumeGraph: GraphQLClient;
|
|
71
68
|
private readonly _externalTvlAbi: KasuPoolExternalTVLAbi;
|
|
72
69
|
private readonly _directus: DirectusClient<DirectusSchema> &
|
|
73
70
|
AuthenticationClient<DirectusSchema> &
|
|
74
71
|
RestClient<DirectusSchema>;
|
|
75
72
|
private _directusPoolOverview: PoolOverviewDirectus[] | undefined;
|
|
76
|
-
private _plumeTvl = new Map<string, string>();
|
|
77
73
|
|
|
78
74
|
constructor(
|
|
79
75
|
private _kasuConfig: SdkConfig,
|
|
@@ -84,17 +80,39 @@ export class DataService {
|
|
|
84
80
|
signerOrProvider,
|
|
85
81
|
);
|
|
86
82
|
this._graph = new GraphQLClient(_kasuConfig.subgraphUrl);
|
|
87
|
-
this._plumeGraph = new GraphQLClient(_kasuConfig.plumeSubgraphUrl);
|
|
88
83
|
|
|
89
|
-
|
|
90
|
-
.
|
|
91
|
-
|
|
84
|
+
if (_kasuConfig.directusUrl) {
|
|
85
|
+
this._directus = createDirectus<DirectusSchema>(
|
|
86
|
+
_kasuConfig.directusUrl,
|
|
87
|
+
)
|
|
88
|
+
.with(authentication())
|
|
89
|
+
.with(rest());
|
|
90
|
+
} else {
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
|
|
92
|
+
this._directus = null as any;
|
|
93
|
+
}
|
|
92
94
|
}
|
|
93
95
|
|
|
94
96
|
private getUrlFromFile(fileName: string): string {
|
|
95
97
|
return `${this._kasuConfig.directusUrl}assets/${fileName}`;
|
|
96
98
|
}
|
|
97
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Maps a pool ID to its metadata source pool ID.
|
|
102
|
+
* Used for chains (XDC, Plume) that share Directus metadata with Base pools.
|
|
103
|
+
*/
|
|
104
|
+
private getMetadataPoolId(poolId: string): string {
|
|
105
|
+
const normalizedId = poolId.toLowerCase();
|
|
106
|
+
return this._kasuConfig.poolMetadataMapping[normalizedId] ?? normalizedId;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Maps an array of pool IDs to their metadata source pool IDs.
|
|
111
|
+
*/
|
|
112
|
+
private getMetadataPoolIds(poolIds: string[]): string[] {
|
|
113
|
+
return poolIds.map((id) => this.getMetadataPoolId(id));
|
|
114
|
+
}
|
|
115
|
+
|
|
98
116
|
calculatePoolCapacity(
|
|
99
117
|
poolCapacities: number[],
|
|
100
118
|
poolCapacityPercentages: number[],
|
|
@@ -206,25 +224,28 @@ export class DataService {
|
|
|
206
224
|
epochId,
|
|
207
225
|
});
|
|
208
226
|
|
|
209
|
-
if (!this._plumeTvl.size) {
|
|
210
|
-
const plumeResults: PlumeSubgraphReturn =
|
|
211
|
-
await this._plumeGraph.request(getPlumeTvl);
|
|
212
|
-
|
|
213
|
-
for (const pool of plumeResults.lendingPools) {
|
|
214
|
-
this._plumeTvl.set(pool.id, pool.balance);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
227
|
if (!this._directusPoolOverview) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
+
if (this._kasuConfig.directusUrl) {
|
|
229
|
+
try {
|
|
230
|
+
this._directusPoolOverview = await this._directus.request(
|
|
231
|
+
readItems('PoolOverview', {
|
|
232
|
+
filter: {
|
|
233
|
+
enabled: {
|
|
234
|
+
_eq: true,
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
}),
|
|
238
|
+
);
|
|
239
|
+
} catch (error) {
|
|
240
|
+
console.warn(
|
|
241
|
+
'Directus fetch failed, falling back to on-chain data only:',
|
|
242
|
+
error,
|
|
243
|
+
);
|
|
244
|
+
this._directusPoolOverview = [];
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
this._directusPoolOverview = [];
|
|
248
|
+
}
|
|
228
249
|
}
|
|
229
250
|
|
|
230
251
|
const offchainTvlMap = await this.getOffChainTvl(
|
|
@@ -233,9 +254,14 @@ export class DataService {
|
|
|
233
254
|
|
|
234
255
|
const retn: PoolOverview[] = [];
|
|
235
256
|
for (const lendingPoolSubgraph of poolOverviewResults.lendingPools) {
|
|
257
|
+
// Use metadata mapping if available (for XDC/Plume pools that share metadata with Base)
|
|
258
|
+
const metadataPoolId =
|
|
259
|
+
this._kasuConfig.poolMetadataMapping[lendingPoolSubgraph.id] ??
|
|
260
|
+
lendingPoolSubgraph.id;
|
|
261
|
+
|
|
236
262
|
const lendingPoolDirectus: PoolOverviewDirectus | undefined =
|
|
237
263
|
this._directusPoolOverview.find(
|
|
238
|
-
(r) => r.id.toLowerCase()
|
|
264
|
+
(r) => r.id.toLowerCase() === metadataPoolId,
|
|
239
265
|
);
|
|
240
266
|
|
|
241
267
|
const lendingPoolConfig = lendingPoolSubgraph.configuration;
|
|
@@ -244,8 +270,12 @@ export class DataService {
|
|
|
244
270
|
console.warn(
|
|
245
271
|
"Couldn't find directus pool for id: ",
|
|
246
272
|
lendingPoolSubgraph.id,
|
|
273
|
+
metadataPoolId !== lendingPoolSubgraph.id
|
|
274
|
+
? `(mapped from ${metadataPoolId})`
|
|
275
|
+
: '',
|
|
247
276
|
);
|
|
248
|
-
|
|
277
|
+
// When Directus is unavailable or pool has no CMS entry,
|
|
278
|
+
// use a fallback so the pool is still returned with on-chain data.
|
|
249
279
|
}
|
|
250
280
|
const poolCapacities = this.calculatePoolCapacity(
|
|
251
281
|
[],
|
|
@@ -380,57 +410,56 @@ export class DataService {
|
|
|
380
410
|
averageApy += parseFloat(trancheData.averageApy) * weight;
|
|
381
411
|
}
|
|
382
412
|
|
|
383
|
-
const plumeTvl =
|
|
384
|
-
lendingPoolDirectus.plumeStrategy &&
|
|
385
|
-
this._plumeTvl.has(lendingPoolDirectus.plumeStrategy)
|
|
386
|
-
? this._plumeTvl.get(lendingPoolDirectus.plumeStrategy) ??
|
|
387
|
-
'0'
|
|
388
|
-
: '0';
|
|
389
|
-
|
|
390
413
|
const offChainTvl =
|
|
391
414
|
offchainTvlMap.get(lendingPoolSubgraph.id) ?? '0';
|
|
392
415
|
|
|
393
416
|
const poolOverview: PoolOverview = {
|
|
394
417
|
id: lendingPoolSubgraph.id,
|
|
395
|
-
security: lendingPoolDirectus
|
|
396
|
-
enabled: lendingPoolDirectus
|
|
397
|
-
isOversubscribed:
|
|
418
|
+
security: lendingPoolDirectus?.security ?? [],
|
|
419
|
+
enabled: lendingPoolDirectus?.enabled ?? true,
|
|
420
|
+
isOversubscribed:
|
|
421
|
+
lendingPoolDirectus?.oversubscribed ?? false,
|
|
398
422
|
apy: averageApy,
|
|
399
|
-
description: lendingPoolDirectus
|
|
400
|
-
liteDescription: lendingPoolDirectus
|
|
401
|
-
thumbnailImageUrl:
|
|
402
|
-
lendingPoolDirectus.thumbnailImage
|
|
403
|
-
|
|
404
|
-
bannerImageUrl:
|
|
405
|
-
lendingPoolDirectus.bannerImage
|
|
406
|
-
|
|
407
|
-
strategyDeckUrl:
|
|
408
|
-
lendingPoolDirectus.strategyDeck
|
|
409
|
-
|
|
410
|
-
assetClass: lendingPoolDirectus
|
|
411
|
-
industryExposure:
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
423
|
+
description: lendingPoolDirectus?.description ?? '',
|
|
424
|
+
liteDescription: lendingPoolDirectus?.liteDescription ?? '',
|
|
425
|
+
thumbnailImageUrl: lendingPoolDirectus?.thumbnailImage
|
|
426
|
+
? this.getUrlFromFile(lendingPoolDirectus.thumbnailImage)
|
|
427
|
+
: '',
|
|
428
|
+
bannerImageUrl: lendingPoolDirectus?.bannerImage
|
|
429
|
+
? this.getUrlFromFile(lendingPoolDirectus.bannerImage)
|
|
430
|
+
: '',
|
|
431
|
+
strategyDeckUrl: lendingPoolDirectus?.strategyDeck
|
|
432
|
+
? this.getUrlFromFile(lendingPoolDirectus.strategyDeck)
|
|
433
|
+
: '',
|
|
434
|
+
assetClass: lendingPoolDirectus?.assetClass ?? '',
|
|
435
|
+
industryExposure:
|
|
436
|
+
lendingPoolDirectus?.industryExposure ?? '',
|
|
437
|
+
poolApyStructure:
|
|
438
|
+
lendingPoolDirectus?.poolApyStructure ?? 'Variable',
|
|
439
|
+
apyExpiryDate:
|
|
440
|
+
lendingPoolDirectus?.apyExpiryDate ?? null,
|
|
441
|
+
poolInvestmentTerm:
|
|
442
|
+
lendingPoolDirectus?.poolInvestmentTerm ?? '',
|
|
443
|
+
loanStructure: lendingPoolDirectus?.loanStructure ?? '',
|
|
416
444
|
poolName:
|
|
417
|
-
lendingPoolDirectus
|
|
418
|
-
|
|
445
|
+
lendingPoolDirectus?.poolName ??
|
|
446
|
+
lendingPoolSubgraph.name,
|
|
447
|
+
subheading: lendingPoolDirectus?.subheading,
|
|
419
448
|
totalValueLocked: {
|
|
420
449
|
total: (
|
|
421
450
|
parseFloat(lendingPoolSubgraph.balance) +
|
|
422
|
-
parseFloat(plumeTvl) +
|
|
423
451
|
parseFloat(offChainTvl)
|
|
424
452
|
).toString(),
|
|
425
453
|
offchain: offChainTvl,
|
|
426
|
-
plume: plumeTvl,
|
|
427
454
|
},
|
|
428
|
-
loansUnderManagement:
|
|
455
|
+
loansUnderManagement:
|
|
456
|
+
lendingPoolDirectus?.loansUnderManagement ?? '0',
|
|
429
457
|
yieldEarned: lendingPoolSubgraph.totalUserInterestAmount,
|
|
430
458
|
poolCapacity: poolCapacitySum.toString(),
|
|
431
459
|
poolCapacityPercentage: poolCapacityPercentageSum.toString(),
|
|
432
|
-
activeLoans: lendingPoolDirectus
|
|
433
|
-
loanFundsOriginated:
|
|
460
|
+
activeLoans: lendingPoolDirectus?.activeLoans ?? '0',
|
|
461
|
+
loanFundsOriginated:
|
|
462
|
+
lendingPoolDirectus?.loanFundsOriginated ?? '0',
|
|
434
463
|
tranches: tranches,
|
|
435
464
|
isActive: !lendingPoolSubgraph.isStopped,
|
|
436
465
|
requestEpochsInAdvance:
|
|
@@ -438,7 +467,8 @@ export class DataService {
|
|
|
438
467
|
.lendingPoolWithdrawalConfig.requestEpochsInAdvance,
|
|
439
468
|
};
|
|
440
469
|
|
|
441
|
-
// show only enabled pools
|
|
470
|
+
// When Directus is available, show only enabled pools.
|
|
471
|
+
// When Directus is unavailable, include all pools.
|
|
442
472
|
if (poolOverview.enabled) {
|
|
443
473
|
retn.push(poolOverview);
|
|
444
474
|
}
|
|
@@ -797,9 +827,14 @@ export class DataService {
|
|
|
797
827
|
);
|
|
798
828
|
const retn: PoolRepayment[] = [];
|
|
799
829
|
for (const data of poolRepaymentDirectus) {
|
|
830
|
+
// Find subgraph pool that maps to this Directus pool
|
|
831
|
+
// On non-Base chains, subgraph pool IDs are different from Directus poolIdFK
|
|
832
|
+
// Use getMetadataPoolId to map subgraph pool ID -> Directus/Base pool ID
|
|
800
833
|
const lendingPoolSubgraph =
|
|
801
834
|
lendingPoolsWithdrawalsAndDepositsSubgraph.lendingPools.find(
|
|
802
|
-
(pool) =>
|
|
835
|
+
(pool) =>
|
|
836
|
+
this.getMetadataPoolId(pool.id) ===
|
|
837
|
+
data.poolIdFK.toLowerCase(),
|
|
803
838
|
);
|
|
804
839
|
|
|
805
840
|
if (lendingPoolSubgraph === undefined) {
|
|
@@ -949,14 +984,19 @@ export class DataService {
|
|
|
949
984
|
retn.totalYieldEarned += parseFloat(poolOverview.yieldEarned);
|
|
950
985
|
}
|
|
951
986
|
for (const poolOverview of poolOverviews) {
|
|
987
|
+
// Map to metadata pool ID for Directus lookup (XDC pools → Base pools)
|
|
988
|
+
const metadataPoolId = this.getMetadataPoolId(poolOverview.id);
|
|
952
989
|
const riskManagement = riskManagements.find(
|
|
953
990
|
(rm) =>
|
|
954
|
-
rm.poolIdFK.toLowerCase() ===
|
|
991
|
+
rm.poolIdFK.toLowerCase() === metadataPoolId.toLowerCase(),
|
|
955
992
|
);
|
|
956
993
|
if (!riskManagement) {
|
|
957
994
|
console.warn(
|
|
958
995
|
"Couldn't find risk management for id: ",
|
|
959
996
|
poolOverview.id,
|
|
997
|
+
metadataPoolId !== poolOverview.id
|
|
998
|
+
? `(mapped to ${metadataPoolId})`
|
|
999
|
+
: '',
|
|
960
1000
|
);
|
|
961
1001
|
continue;
|
|
962
1002
|
}
|
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
import { gql } from 'graphql-request';
|
|
2
2
|
|
|
3
|
-
export const getPlumeTvl = gql`
|
|
4
|
-
{
|
|
5
|
-
lendingPools {
|
|
6
|
-
id
|
|
7
|
-
balance
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
`;
|
|
11
|
-
|
|
12
3
|
export const getPoolOverviewQuery = (ids?: string[]): string => gql`
|
|
13
4
|
query getAllPoolOverview($epochId: String!, $unusedPools: [String]!) {
|
|
14
5
|
lendingPools(
|
|
@@ -16,13 +16,6 @@ export interface LendingPoolSubgraph {
|
|
|
16
16
|
configuration: LendingPoolConfigurationSubgraph;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export interface PlumeSubgraphReturn {
|
|
20
|
-
lendingPools: {
|
|
21
|
-
id: string;
|
|
22
|
-
balance: string;
|
|
23
|
-
}[];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
19
|
export interface LendingPoolSubgraphReturn {
|
|
27
20
|
lendingPools: LendingPoolSubgraph[];
|
|
28
21
|
}
|
|
@@ -57,29 +57,37 @@ import {
|
|
|
57
57
|
|
|
58
58
|
export class KSULocking {
|
|
59
59
|
private readonly _contractAbi: IKSULockingAbi;
|
|
60
|
-
private readonly _kasuToken: IERC20MetadataAbi;
|
|
60
|
+
private readonly _kasuToken: IERC20MetadataAbi | null;
|
|
61
61
|
private readonly _kasuBonusAddress: string;
|
|
62
62
|
private readonly _graph: GraphQLClient;
|
|
63
63
|
private readonly _userManagerAbi: IUserManagerAbi;
|
|
64
64
|
private readonly _systemVariablesAbi: ISystemVariablesAbi;
|
|
65
65
|
private readonly _ksuPriceAbi: IKsuPriceAbi;
|
|
66
66
|
private readonly _userLoyaltyRewardsAbi: IUserLoyaltyRewardsAbi;
|
|
67
|
+
private readonly _isLiteDeployment: boolean;
|
|
67
68
|
private readonly apyBonuses: number[] = [0, 0.001, 0.002];
|
|
68
|
-
|
|
69
|
-
*
|
|
70
|
-
*/
|
|
69
|
+
|
|
71
70
|
constructor(
|
|
72
71
|
private _kasuConfig: SdkConfig,
|
|
73
72
|
signerOrProvider: Signer | Provider,
|
|
74
73
|
) {
|
|
74
|
+
this._isLiteDeployment = _kasuConfig.isLiteDeployment;
|
|
75
|
+
|
|
75
76
|
this._contractAbi = IKSULockingAbi__factory.connect(
|
|
76
77
|
_kasuConfig.contracts.IKSULocking,
|
|
77
78
|
signerOrProvider,
|
|
78
79
|
);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
|
|
81
|
+
// Only initialize KSU token contract if not a Lite deployment and address is provided
|
|
82
|
+
if (!this._isLiteDeployment && _kasuConfig.contracts.KSUToken) {
|
|
83
|
+
this._kasuToken = IERC20MetadataAbi__factory.connect(
|
|
84
|
+
_kasuConfig.contracts.KSUToken,
|
|
85
|
+
signerOrProvider,
|
|
86
|
+
);
|
|
87
|
+
} else {
|
|
88
|
+
this._kasuToken = null;
|
|
89
|
+
}
|
|
90
|
+
|
|
83
91
|
this._userManagerAbi = IUserManagerAbi__factory.connect(
|
|
84
92
|
_kasuConfig.contracts.UserManager,
|
|
85
93
|
signerOrProvider,
|
|
@@ -100,10 +108,20 @@ export class KSULocking {
|
|
|
100
108
|
);
|
|
101
109
|
}
|
|
102
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Check if this is a Lite deployment (no KSU token functionality)
|
|
113
|
+
*/
|
|
114
|
+
get isLiteDeployment(): boolean {
|
|
115
|
+
return this._isLiteDeployment;
|
|
116
|
+
}
|
|
117
|
+
|
|
103
118
|
async lockKSUTokens(
|
|
104
119
|
amount: BigNumber,
|
|
105
120
|
lockPeriod: BigNumber,
|
|
106
121
|
): Promise<ContractTransaction> {
|
|
122
|
+
if (this._isLiteDeployment) {
|
|
123
|
+
throw new Error('Locking is not available on Lite deployments');
|
|
124
|
+
}
|
|
107
125
|
return this._contractAbi.lock(amount, lockPeriod);
|
|
108
126
|
}
|
|
109
127
|
|
|
@@ -112,6 +130,10 @@ export class KSULocking {
|
|
|
112
130
|
lockPeriod: number,
|
|
113
131
|
permit: RSVDeadlineValue,
|
|
114
132
|
): Promise<ContractTransaction> {
|
|
133
|
+
if (this._isLiteDeployment) {
|
|
134
|
+
throw new Error('Locking is not available on Lite deployments');
|
|
135
|
+
}
|
|
136
|
+
|
|
115
137
|
const amountBN = BigNumber.from(amount);
|
|
116
138
|
const lockPeriodBN = BigNumber.from(lockPeriod);
|
|
117
139
|
|
|
@@ -134,13 +156,27 @@ export class KSULocking {
|
|
|
134
156
|
amount: BigNumber,
|
|
135
157
|
userLockId: BigNumber,
|
|
136
158
|
): Promise<ContractTransaction> {
|
|
159
|
+
if (this._isLiteDeployment) {
|
|
160
|
+
throw new Error('Locking is not available on Lite deployments');
|
|
161
|
+
}
|
|
137
162
|
return this._contractAbi.unlock(amount, userLockId);
|
|
138
163
|
}
|
|
139
164
|
|
|
140
165
|
async claimFees(): Promise<ContractTransaction> {
|
|
166
|
+
if (this._isLiteDeployment) {
|
|
167
|
+
throw new Error('Fee claiming is not available on Lite deployments');
|
|
168
|
+
}
|
|
141
169
|
return await this._contractAbi.claimFees();
|
|
142
170
|
}
|
|
171
|
+
|
|
143
172
|
async lockDetails(lockPeriod: BigNumber): Promise<LockPeriodInterface> {
|
|
173
|
+
if (this._isLiteDeployment) {
|
|
174
|
+
return {
|
|
175
|
+
rKsuMultiplier: 0,
|
|
176
|
+
ksuBonusMultiplier: 0,
|
|
177
|
+
isActive: false,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
144
180
|
const result = await this._contractAbi.lockDetails(lockPeriod);
|
|
145
181
|
return {
|
|
146
182
|
rKsuMultiplier: result[0].toNumber(),
|
|
@@ -150,6 +186,9 @@ export class KSULocking {
|
|
|
150
186
|
}
|
|
151
187
|
|
|
152
188
|
async userTotalDeposits(userAddress: string): Promise<BigNumber> {
|
|
189
|
+
if (this._isLiteDeployment) {
|
|
190
|
+
return BigNumber.from(0);
|
|
191
|
+
}
|
|
153
192
|
return await this._contractAbi.userTotalDeposits(userAddress);
|
|
154
193
|
}
|
|
155
194
|
|
|
@@ -158,7 +197,7 @@ export class KSULocking {
|
|
|
158
197
|
KSULocked: number,
|
|
159
198
|
lockPeriod: BigNumber,
|
|
160
199
|
): Promise<number> {
|
|
161
|
-
if (KSULocked === 0) {
|
|
200
|
+
if (this._isLiteDeployment || KSULocked === 0) {
|
|
162
201
|
return 0;
|
|
163
202
|
}
|
|
164
203
|
|
|
@@ -232,6 +271,10 @@ export class KSULocking {
|
|
|
232
271
|
}
|
|
233
272
|
|
|
234
273
|
async getUserLocks(userAddress: string): Promise<UserLock[]> {
|
|
274
|
+
if (this._isLiteDeployment) {
|
|
275
|
+
return [];
|
|
276
|
+
}
|
|
277
|
+
|
|
235
278
|
const result: GQLUserLocks = await this._graph.request(userLocksQuery, {
|
|
236
279
|
userAddress: userAddress.toLowerCase(),
|
|
237
280
|
});
|
|
@@ -261,8 +304,14 @@ export class KSULocking {
|
|
|
261
304
|
}
|
|
262
305
|
|
|
263
306
|
async getUserBonusData(userAddress: string): Promise<UserBonusData> {
|
|
264
|
-
|
|
265
|
-
|
|
307
|
+
if (this._isLiteDeployment) {
|
|
308
|
+
return {
|
|
309
|
+
ksuBonusAndRewards: '0',
|
|
310
|
+
ksuBonusAndRewardsLifetime: '0',
|
|
311
|
+
protocolFeesEarned: '0',
|
|
312
|
+
totalLockedAmount: '0',
|
|
313
|
+
};
|
|
314
|
+
}
|
|
266
315
|
|
|
267
316
|
const DECIMALS = 18;
|
|
268
317
|
|
|
@@ -322,6 +371,11 @@ export class KSULocking {
|
|
|
322
371
|
loyaltyLevel: number;
|
|
323
372
|
apyBonus: number;
|
|
324
373
|
} {
|
|
374
|
+
// On Lite deployments, always return level 0 with no bonus
|
|
375
|
+
if (this._isLiteDeployment) {
|
|
376
|
+
return { loyaltyLevel: 0, apyBonus: 0 };
|
|
377
|
+
}
|
|
378
|
+
|
|
325
379
|
if (rKSUtoUSDCRatio < 0.01) {
|
|
326
380
|
return { loyaltyLevel: 0, apyBonus: this.apyBonuses[0] };
|
|
327
381
|
} else if (rKSUtoUSDCRatio < 0.05) {
|
|
@@ -334,6 +388,10 @@ export class KSULocking {
|
|
|
334
388
|
rKSUAmount: string,
|
|
335
389
|
userAddress: string,
|
|
336
390
|
): Promise<number> {
|
|
391
|
+
if (this._isLiteDeployment) {
|
|
392
|
+
return 0;
|
|
393
|
+
}
|
|
394
|
+
|
|
337
395
|
const [depositedAmount, pendingAmount]: [BigNumber, BigNumber] =
|
|
338
396
|
await this._userManagerAbi.userTotalPendingAndActiveDepositedAmountForCurrentEpoch(
|
|
339
397
|
userAddress,
|
|
@@ -357,6 +415,9 @@ export class KSULocking {
|
|
|
357
415
|
}
|
|
358
416
|
|
|
359
417
|
async getClaimableRewards(userAddress: string): Promise<BigNumber> {
|
|
418
|
+
if (this._isLiteDeployment) {
|
|
419
|
+
return BigNumber.from(0);
|
|
420
|
+
}
|
|
360
421
|
const result = await this._contractAbi.rewards(userAddress);
|
|
361
422
|
return result;
|
|
362
423
|
}
|
|
@@ -364,6 +425,7 @@ export class KSULocking {
|
|
|
364
425
|
async getKasuTokenPrice(): Promise<{ price: BigNumber; decimals: number }> {
|
|
365
426
|
const decimals = 18;
|
|
366
427
|
|
|
428
|
+
// Price can still be queried on Lite deployments (set to 0 or configured value)
|
|
367
429
|
return Promise.resolve({
|
|
368
430
|
price: await this._ksuPriceAbi.ksuTokenPrice(),
|
|
369
431
|
decimals,
|
|
@@ -387,6 +449,10 @@ export class KSULocking {
|
|
|
387
449
|
rewardDecimals: number,
|
|
388
450
|
claimableRewards?: BigNumber,
|
|
389
451
|
): Promise<BigNumber> {
|
|
452
|
+
if (this._isLiteDeployment) {
|
|
453
|
+
return BigNumber.from(0);
|
|
454
|
+
}
|
|
455
|
+
|
|
390
456
|
const result: GQLClaimedFeesForAddress = await this._graph.request(
|
|
391
457
|
claimedFeesQuery,
|
|
392
458
|
{
|
|
@@ -408,6 +474,10 @@ export class KSULocking {
|
|
|
408
474
|
bonusMultiplier: number,
|
|
409
475
|
bonusTokensLeft: BigNumber,
|
|
410
476
|
): BigNumber {
|
|
477
|
+
if (this._isLiteDeployment) {
|
|
478
|
+
return BigNumber.from(0);
|
|
479
|
+
}
|
|
480
|
+
|
|
411
481
|
const bonusMultiplierBN = ethers.utils.parseUnits(
|
|
412
482
|
bonusMultiplier.toFixed(2),
|
|
413
483
|
2,
|
|
@@ -422,6 +492,10 @@ export class KSULocking {
|
|
|
422
492
|
}
|
|
423
493
|
|
|
424
494
|
async getUserStakedKsu(userAddress: string): Promise<string> {
|
|
495
|
+
if (this._isLiteDeployment) {
|
|
496
|
+
return '0';
|
|
497
|
+
}
|
|
498
|
+
|
|
425
499
|
const result: GQLStakedAmountForAddress = await this._graph.request(
|
|
426
500
|
userStakedKsuQuery,
|
|
427
501
|
{
|
|
@@ -435,6 +509,10 @@ export class KSULocking {
|
|
|
435
509
|
}
|
|
436
510
|
|
|
437
511
|
async getUserEarnedrKsu(userAddress: string): Promise<string> {
|
|
512
|
+
if (this._isLiteDeployment) {
|
|
513
|
+
return '0';
|
|
514
|
+
}
|
|
515
|
+
|
|
438
516
|
const result: GQLEarnedRKsuForAddress = await this._graph.request(
|
|
439
517
|
userEarnedrKsuQuery,
|
|
440
518
|
{
|
|
@@ -449,6 +527,10 @@ export class KSULocking {
|
|
|
449
527
|
}
|
|
450
528
|
|
|
451
529
|
async getUserTotalBonusAmount(userAddress: string): Promise<string> {
|
|
530
|
+
if (this._isLiteDeployment) {
|
|
531
|
+
return '0';
|
|
532
|
+
}
|
|
533
|
+
|
|
452
534
|
const result: GQLTotalBonusAmountForAddress = await this._graph.request(
|
|
453
535
|
userTotalBonusAmountQuery,
|
|
454
536
|
{
|
|
@@ -465,6 +547,13 @@ export class KSULocking {
|
|
|
465
547
|
async getLockingRewards(
|
|
466
548
|
userAddress: string,
|
|
467
549
|
): Promise<{ claimableRewards: string; lifeTimeRewards: string }> {
|
|
550
|
+
if (this._isLiteDeployment) {
|
|
551
|
+
return {
|
|
552
|
+
claimableRewards: '0',
|
|
553
|
+
lifeTimeRewards: '0',
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
|
|
468
557
|
const rewardDecimals = 6;
|
|
469
558
|
|
|
470
559
|
const claimableRewards = await this.getClaimableRewards(userAddress);
|
|
@@ -486,18 +575,26 @@ export class KSULocking {
|
|
|
486
575
|
}
|
|
487
576
|
|
|
488
577
|
async getAvailableKsuBonus(): Promise<string> {
|
|
489
|
-
|
|
578
|
+
if (this._isLiteDeployment || !this._kasuToken) {
|
|
579
|
+
return '0';
|
|
580
|
+
}
|
|
490
581
|
|
|
582
|
+
const amount = await this._kasuToken.balanceOf(this._kasuBonusAddress);
|
|
491
583
|
return formatEther(amount);
|
|
492
584
|
}
|
|
493
585
|
|
|
494
586
|
async getUserKsuBalance(userAddress: string): Promise<string> {
|
|
587
|
+
if (this._isLiteDeployment || !this._kasuToken) {
|
|
588
|
+
return '0';
|
|
589
|
+
}
|
|
590
|
+
|
|
495
591
|
const balance = await this._kasuToken.balanceOf(
|
|
496
592
|
userAddress.toLowerCase(),
|
|
497
593
|
);
|
|
498
594
|
|
|
499
595
|
return formatEther(balance);
|
|
500
596
|
}
|
|
597
|
+
|
|
501
598
|
async getNextEpochDate(): Promise<EpochTimeStamp> {
|
|
502
599
|
return (
|
|
503
600
|
await this._systemVariablesAbi.nextEpochStartTimestamp()
|
|
@@ -526,6 +623,10 @@ export class KSULocking {
|
|
|
526
623
|
}
|
|
527
624
|
|
|
528
625
|
async getActiveLockPeriods(): Promise<LockPeriod[]> {
|
|
626
|
+
if (this._isLiteDeployment) {
|
|
627
|
+
return [];
|
|
628
|
+
}
|
|
629
|
+
|
|
529
630
|
const data: GQLGetLockingPeriods =
|
|
530
631
|
await this._graph.request(lockingPeriodsQuery);
|
|
531
632
|
return data.lockPeriods;
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
IUserLoyaltyRewardsAbi__factory,
|
|
12
12
|
} from '../../contracts';
|
|
13
13
|
import { SdkConfig } from '../../sdk-config';
|
|
14
|
+
import { isLiteDeployment } from '../../utils/deployment-mode';
|
|
14
15
|
import { DataService } from '../DataService/data-service';
|
|
15
16
|
import {
|
|
16
17
|
getAllTrancheConfigurationsQuery,
|
|
@@ -53,8 +54,9 @@ export class Portfolio {
|
|
|
53
54
|
private _userLoyaltyRewardsAbi: ReturnType<
|
|
54
55
|
typeof IUserLoyaltyRewardsAbi__factory.connect
|
|
55
56
|
>;
|
|
56
|
-
private _kasuNftContract: IKasuNFTsAbi;
|
|
57
|
+
private _kasuNftContract: IKasuNFTsAbi | null;
|
|
57
58
|
readonly _signerOrProvider: Signer | Provider;
|
|
59
|
+
private _isLiteDeployment: boolean;
|
|
58
60
|
|
|
59
61
|
constructor(
|
|
60
62
|
private _kasuConfig: SdkConfig,
|
|
@@ -75,10 +77,13 @@ export class Portfolio {
|
|
|
75
77
|
_kasuConfig,
|
|
76
78
|
signerOrProvider,
|
|
77
79
|
);
|
|
78
|
-
this.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
this._isLiteDeployment = isLiteDeployment(_kasuConfig);
|
|
81
|
+
this._kasuNftContract = _kasuConfig.contracts.KasuNFTs
|
|
82
|
+
? IKasuNFTsAbi__factory.connect(
|
|
83
|
+
_kasuConfig.contracts.KasuNFTs,
|
|
84
|
+
signerOrProvider,
|
|
85
|
+
)
|
|
86
|
+
: null;
|
|
82
87
|
this._graph = new GraphQLClient(_kasuConfig.subgraphUrl);
|
|
83
88
|
}
|
|
84
89
|
|
|
@@ -293,6 +298,11 @@ export class Portfolio {
|
|
|
293
298
|
}
|
|
294
299
|
|
|
295
300
|
async getUserNfts(userAddress: string): Promise<number[]> {
|
|
301
|
+
// NFTs are not available on Lite deployments
|
|
302
|
+
if (this._isLiteDeployment || !this._kasuNftContract) {
|
|
303
|
+
return [];
|
|
304
|
+
}
|
|
305
|
+
|
|
296
306
|
const usernfts = await this._kasuNftContract.tokensOfOwner(userAddress);
|
|
297
307
|
|
|
298
308
|
return usernfts.map((nft) => nft.toNumber());
|