@scallop-io/sui-scallop-sdk 0.46.36 → 0.46.37
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 +12 -0
- package/dist/builders/referralBuilder.d.ts +1 -1
- package/dist/constants/testAddress.d.ts +2 -0
- package/dist/index.js +567 -71
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +557 -61
- package/dist/index.mjs.map +1 -1
- package/dist/models/scallopQuery.d.ts +10 -3
- package/dist/models/scallopUtils.d.ts +1 -1
- package/dist/queries/index.d.ts +1 -0
- package/dist/queries/loyaltyProgramQuery.d.ts +10 -0
- package/dist/queries/vescaQuery.d.ts +8 -6
- package/dist/types/address.d.ts +6 -0
- package/dist/types/builder/index.d.ts +3 -1
- package/dist/types/builder/loyaltyProgram.d.ts +23 -0
- package/dist/types/builder/vesca.d.ts +16 -0
- package/dist/types/query/index.d.ts +1 -0
- package/dist/types/query/loyaltyProgram.d.ts +5 -0
- package/dist/types/query/vesca.d.ts +18 -0
- package/dist/utils/builder.d.ts +6 -5
- package/package.json +7 -6
- package/src/builders/index.ts +6 -1
- package/src/builders/loyaltyProgramBuilder.ts +115 -0
- package/src/builders/referralBuilder.ts +1 -1
- package/src/builders/vescaBuilder.ts +5 -1
- package/src/constants/testAddress.ts +383 -0
- package/src/models/scallopAddress.ts +12 -2
- package/src/models/scallopCache.ts +0 -1
- package/src/models/scallopQuery.ts +16 -5
- package/src/models/scallopUtils.ts +3 -3
- package/src/queries/index.ts +1 -0
- package/src/queries/loyaltyProgramQuery.ts +77 -0
- package/src/queries/vescaQuery.ts +70 -15
- package/src/types/address.ts +6 -0
- package/src/types/builder/index.ts +3 -0
- package/src/types/builder/loyaltyProgram.ts +35 -0
- package/src/types/builder/vesca.ts +16 -0
- package/src/types/query/index.ts +1 -0
- package/src/types/query/loyaltyProgram.ts +5 -0
- package/src/types/query/vesca.ts +21 -0
- package/src/utils/builder.ts +69 -53
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import BigNumber from 'bignumber.js';
|
|
2
|
-
import { Vesca } from '../types';
|
|
2
|
+
import { VeScaTreasuryFields, VeScaTreasuryInfo, Vesca } from '../types';
|
|
3
3
|
import {
|
|
4
4
|
type SuiObjectResponse,
|
|
5
5
|
type SuiObjectData,
|
|
@@ -9,6 +9,7 @@ import type { ScallopQuery } from '../models';
|
|
|
9
9
|
import { MAX_LOCK_DURATION } from 'src/constants';
|
|
10
10
|
import { SUI_CLOCK_OBJECT_ID, SuiTxBlock } from '@scallop-io/sui-kit';
|
|
11
11
|
import { bcs } from '@mysten/sui.js/bcs';
|
|
12
|
+
import { z as zod } from 'zod';
|
|
12
13
|
/**
|
|
13
14
|
* Query all owned veSca key.
|
|
14
15
|
*
|
|
@@ -63,11 +64,10 @@ export const getVescaKeys = async (
|
|
|
63
64
|
*/
|
|
64
65
|
export const getVeScas = async (query: ScallopQuery, ownerAddress?: string) => {
|
|
65
66
|
const keyObjectDatas = await getVescaKeys(query, ownerAddress);
|
|
66
|
-
const keyObjectId: string[] = keyObjectDatas.map((data) => data.objectId);
|
|
67
67
|
|
|
68
|
-
const veScas:
|
|
69
|
-
const tasks =
|
|
70
|
-
const veSca = await getVeSca(query,
|
|
68
|
+
const veScas: Vesca[] = Array(keyObjectDatas.length).fill(null);
|
|
69
|
+
const tasks = keyObjectDatas.map(async (veScaKey, idx) => {
|
|
70
|
+
const veSca = await getVeSca(query, veScaKey);
|
|
71
71
|
if (veSca) {
|
|
72
72
|
veScas[idx] = veSca;
|
|
73
73
|
}
|
|
@@ -79,22 +79,33 @@ export const getVeScas = async (query: ScallopQuery, ownerAddress?: string) => {
|
|
|
79
79
|
.sort((a, b) => b!.currentVeScaBalance - a!.currentVeScaBalance);
|
|
80
80
|
};
|
|
81
81
|
|
|
82
|
+
const SuiObjectRefZod = zod.object({
|
|
83
|
+
objectId: zod.string(),
|
|
84
|
+
digest: zod.string(),
|
|
85
|
+
version: zod.string(),
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
type SuiObjectRefType = zod.infer<typeof SuiObjectRefZod>;
|
|
82
89
|
/**
|
|
83
90
|
* Get veSca data.
|
|
84
91
|
*
|
|
85
92
|
* @param query - The Scallop query instance.
|
|
86
|
-
* @param
|
|
93
|
+
* @param veScaKey - The vesca key id.
|
|
87
94
|
* @param ownerAddress - The owner address.
|
|
88
95
|
* @returns Vesca data.
|
|
89
96
|
*/
|
|
90
97
|
export const getVeSca = async (
|
|
91
98
|
query: ScallopQuery,
|
|
92
|
-
|
|
99
|
+
veScaKey?: string | SuiObjectData,
|
|
93
100
|
ownerAddress?: string
|
|
94
101
|
) => {
|
|
95
102
|
const tableId = query.address.get(`vesca.tableId`);
|
|
96
|
-
|
|
97
|
-
|
|
103
|
+
veScaKey = veScaKey || (await getVescaKeys(query, ownerAddress))[0];
|
|
104
|
+
|
|
105
|
+
if (!veScaKey) return undefined;
|
|
106
|
+
if (typeof veScaKey === 'object') {
|
|
107
|
+
veScaKey = SuiObjectRefZod.parse(veScaKey) as SuiObjectRefType;
|
|
108
|
+
}
|
|
98
109
|
|
|
99
110
|
let vesca: Vesca | undefined = undefined;
|
|
100
111
|
|
|
@@ -103,7 +114,7 @@ export const getVeSca = async (
|
|
|
103
114
|
parentId: tableId,
|
|
104
115
|
name: {
|
|
105
116
|
type: '0x2::object::ID',
|
|
106
|
-
value:
|
|
117
|
+
value: typeof veScaKey === 'string' ? veScaKey : veScaKey.objectId,
|
|
107
118
|
},
|
|
108
119
|
});
|
|
109
120
|
const veScaDynamicFieldObject = veScaDynamicFieldObjectResponse.data;
|
|
@@ -131,7 +142,9 @@ export const getVeSca = async (
|
|
|
131
142
|
|
|
132
143
|
vesca = {
|
|
133
144
|
id: veScaDynamicFieldObject.objectId,
|
|
134
|
-
keyId:
|
|
145
|
+
keyId: typeof veScaKey === 'string' ? veScaKey : veScaKey.objectId,
|
|
146
|
+
keyObject: typeof veScaKey === 'string' ? undefined : veScaKey,
|
|
147
|
+
object: SuiObjectRefZod.parse(veScaDynamicFieldObjectResponse.data),
|
|
135
148
|
lockedScaAmount,
|
|
136
149
|
lockedScaCoin,
|
|
137
150
|
currentVeScaBalance,
|
|
@@ -145,12 +158,13 @@ export const getVeSca = async (
|
|
|
145
158
|
/**
|
|
146
159
|
* Get current total veSca treasury amount.
|
|
147
160
|
*/
|
|
148
|
-
|
|
149
|
-
query: ScallopQuery
|
|
161
|
+
const getTotalVeScaTreasuryAmount = async (
|
|
162
|
+
query: ScallopQuery,
|
|
163
|
+
veScaTreasury: SuiObjectData
|
|
150
164
|
): Promise<string> => {
|
|
151
165
|
const veScaPkgId = query.address.get('vesca.id');
|
|
152
166
|
const veScaConfig = query.address.get('vesca.config');
|
|
153
|
-
|
|
167
|
+
veScaTreasury = veScaTreasury ?? query.address.get('vesca.treasury');
|
|
154
168
|
|
|
155
169
|
// refresh query
|
|
156
170
|
const refreshQueryTarget = `${veScaPkgId}::treasury::refresh`;
|
|
@@ -201,7 +215,6 @@ export const getTotalVeScaTreasuryAmount = async (
|
|
|
201
215
|
queryFn: async () => {
|
|
202
216
|
return await query.suiKit.inspectTxn(txBytes);
|
|
203
217
|
},
|
|
204
|
-
staleTime: 8000,
|
|
205
218
|
});
|
|
206
219
|
|
|
207
220
|
const results = res.results;
|
|
@@ -213,3 +226,45 @@ export const getTotalVeScaTreasuryAmount = async (
|
|
|
213
226
|
|
|
214
227
|
return '0';
|
|
215
228
|
};
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Get veSCA treasury informations
|
|
232
|
+
* @param query
|
|
233
|
+
* @returns VeScaTreasuryInfo
|
|
234
|
+
*/
|
|
235
|
+
export const getVeScaTreasuryInfo = async (
|
|
236
|
+
query: ScallopQuery
|
|
237
|
+
): Promise<VeScaTreasuryInfo | null> => {
|
|
238
|
+
const veScaTreasuryId = query.address.get('vesca.treasury');
|
|
239
|
+
const veScaTreasury = await query.cache.queryGetObject(veScaTreasuryId, {
|
|
240
|
+
showContent: true,
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
if (!veScaTreasury || veScaTreasury.data?.content?.dataType !== 'moveObject')
|
|
244
|
+
return null;
|
|
245
|
+
|
|
246
|
+
const treasuryFields = veScaTreasury.data.content
|
|
247
|
+
.fields as VeScaTreasuryFields;
|
|
248
|
+
|
|
249
|
+
console.log(treasuryFields);
|
|
250
|
+
const totalLockedSca = BigNumber(
|
|
251
|
+
treasuryFields.unlock_schedule.fields.locked_sca_amount
|
|
252
|
+
)
|
|
253
|
+
.shiftedBy(-9)
|
|
254
|
+
.toNumber();
|
|
255
|
+
const totalVeSca = BigNumber(
|
|
256
|
+
(await getTotalVeScaTreasuryAmount(query, veScaTreasury.data)) ?? 0
|
|
257
|
+
)
|
|
258
|
+
.shiftedBy(-9)
|
|
259
|
+
.toNumber();
|
|
260
|
+
const averageLockingPeriod =
|
|
261
|
+
totalLockedSca > 0 ? (totalVeSca / totalLockedSca) * 4 : 0; // in years
|
|
262
|
+
|
|
263
|
+
const averageLockingPeriodUnit = 'year';
|
|
264
|
+
return {
|
|
265
|
+
totalLockedSca,
|
|
266
|
+
totalVeSca,
|
|
267
|
+
averageLockingPeriod,
|
|
268
|
+
averageLockingPeriodUnit,
|
|
269
|
+
};
|
|
270
|
+
};
|
package/src/types/address.ts
CHANGED
|
@@ -115,6 +115,12 @@ export interface AddressesInterface {
|
|
|
115
115
|
tiersTableId: string;
|
|
116
116
|
authorizedWitnessList: string;
|
|
117
117
|
};
|
|
118
|
+
loyaltyProgram: {
|
|
119
|
+
id: string;
|
|
120
|
+
object: string;
|
|
121
|
+
rewardPool: string;
|
|
122
|
+
userRewardTableId: string;
|
|
123
|
+
};
|
|
118
124
|
}
|
|
119
125
|
|
|
120
126
|
type AddressPathsProps<T> = T extends string
|
|
@@ -3,14 +3,17 @@ import type { SpoolTxBlock } from './spool';
|
|
|
3
3
|
import type { BorrowIncentiveTxBlock } from './borrowIncentive';
|
|
4
4
|
import type { VeScaTxBlock } from './vesca';
|
|
5
5
|
import type { ReferralTxBlock } from './referral';
|
|
6
|
+
import { LoyaltyProgramTxBlock } from './loyaltyProgram';
|
|
6
7
|
|
|
7
8
|
export type * from './core';
|
|
8
9
|
export type * from './spool';
|
|
9
10
|
export type * from './borrowIncentive';
|
|
10
11
|
export type * from './vesca';
|
|
12
|
+
export type * from './loyaltyProgram';
|
|
11
13
|
|
|
12
14
|
export type ScallopTxBlock = CoreTxBlock &
|
|
13
15
|
SpoolTxBlock &
|
|
14
16
|
ReferralTxBlock &
|
|
17
|
+
LoyaltyProgramTxBlock &
|
|
15
18
|
BorrowIncentiveTxBlock &
|
|
16
19
|
VeScaTxBlock;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SuiObjectArg,
|
|
3
|
+
SuiTxBlock as SuiKitTxBlock,
|
|
4
|
+
TransactionResult,
|
|
5
|
+
} from '@scallop-io/sui-kit';
|
|
6
|
+
import { type ScallopBuilder } from 'src/models';
|
|
7
|
+
|
|
8
|
+
export type LoyaltyProgramIds = {
|
|
9
|
+
loyaltyProgramPkgId: string;
|
|
10
|
+
rewardPool: string;
|
|
11
|
+
userRewardTableId: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type LoyaltyProgramNormalMethods = {
|
|
15
|
+
claimLoyaltyRevenue: (veScaKey: SuiObjectArg) => TransactionResult;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type LoyaltyProgramQuickMethods = {
|
|
19
|
+
claimLoyaltyRevenueQuick: (veScaKey?: SuiObjectArg) => Promise<void>;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type SuiTxBlockWithLoyaltyProgramNormalMethods = SuiKitTxBlock &
|
|
23
|
+
LoyaltyProgramNormalMethods;
|
|
24
|
+
export type LoyaltyProgramTxBlock = SuiTxBlockWithLoyaltyProgramNormalMethods &
|
|
25
|
+
LoyaltyProgramQuickMethods;
|
|
26
|
+
|
|
27
|
+
export type GenerateLoyaltyProgramNormalMethod = (params: {
|
|
28
|
+
builder: ScallopBuilder;
|
|
29
|
+
txBlock: SuiKitTxBlock;
|
|
30
|
+
}) => LoyaltyProgramNormalMethods;
|
|
31
|
+
|
|
32
|
+
export type GenerateLoyaltyProgramQuickMethod = (params: {
|
|
33
|
+
builder: ScallopBuilder;
|
|
34
|
+
txBlock: SuiTxBlockWithLoyaltyProgramNormalMethods;
|
|
35
|
+
}) => LoyaltyProgramQuickMethods;
|
|
@@ -33,6 +33,22 @@ export type VeScaNormalMethods = {
|
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
export type VeScaQuickMethods = {
|
|
36
|
+
/**
|
|
37
|
+
* Quick methods to automate
|
|
38
|
+
* lock initial SCA, extend lock period, lock more SCA, renew expired VeSCA, and redeem SCA
|
|
39
|
+
*
|
|
40
|
+
* **Flow:**
|
|
41
|
+
* - If only `amountOrCoin` is provided, it will lock the amount of existing not expired veSCA
|
|
42
|
+
* - If only `lockPeriodInDays` is provided, it will extend the lock period of existing not expired veSCA
|
|
43
|
+
*
|
|
44
|
+
* **Note:**
|
|
45
|
+
* - If one or both flow above is used on a expired veSCA, it will claim the unlocked SCA
|
|
46
|
+
* and renew the veSCA first, and then flow continues
|
|
47
|
+
* - If users has no veSCA yet, they need to provide both `amountOrCoin` and `lockPeriodInDays` for initial lock
|
|
48
|
+
* @param amountOrCoin
|
|
49
|
+
* @param lockPeriodInDays
|
|
50
|
+
* @param autoCheck
|
|
51
|
+
*/
|
|
36
52
|
lockScaQuick(
|
|
37
53
|
amountOrCoin?: SuiObjectArg | number,
|
|
38
54
|
lockPeriodInDays?: number,
|
package/src/types/query/index.ts
CHANGED
package/src/types/query/vesca.ts
CHANGED
|
@@ -1,8 +1,29 @@
|
|
|
1
|
+
import type { SuiObjectRef } from '@mysten/sui.js/client';
|
|
2
|
+
|
|
1
3
|
export type Vesca = {
|
|
2
4
|
id: string;
|
|
3
5
|
keyId: string;
|
|
6
|
+
keyObject?: SuiObjectRef;
|
|
7
|
+
object?: SuiObjectRef;
|
|
4
8
|
lockedScaAmount: string;
|
|
5
9
|
lockedScaCoin: number;
|
|
6
10
|
currentVeScaBalance: number;
|
|
7
11
|
unlockAt: number;
|
|
8
12
|
};
|
|
13
|
+
|
|
14
|
+
export type VeScaTreasuryFields = {
|
|
15
|
+
total_ve_sca_amount: string;
|
|
16
|
+
sca_balance: string;
|
|
17
|
+
unlock_schedule: {
|
|
18
|
+
fields: {
|
|
19
|
+
locked_sca_amount: string;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type VeScaTreasuryInfo = {
|
|
25
|
+
totalLockedSca: number;
|
|
26
|
+
totalVeSca: number;
|
|
27
|
+
averageLockingPeriod: number;
|
|
28
|
+
averageLockingPeriodUnit: string;
|
|
29
|
+
};
|
package/src/utils/builder.ts
CHANGED
|
@@ -22,16 +22,61 @@ export const requireSender = (txBlock: SuiKitTxBlock) => {
|
|
|
22
22
|
return sender;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
+
export const checkVesca = (prevUnlockAtInMillisTimestamp?: number) => {
|
|
26
|
+
if (prevUnlockAtInMillisTimestamp === undefined) {
|
|
27
|
+
throw new Error('veSca not found');
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const checkVescaExpired = (prevUnlockAtInMillisTimestamp: number) => {
|
|
32
|
+
if (prevUnlockAtInMillisTimestamp <= new Date().getTime()) {
|
|
33
|
+
throw new Error('veSca is expired, use renewExpiredVeScaQuick instead');
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const checkExtendLockPeriod = (
|
|
38
|
+
lockPeriodInDays: number,
|
|
39
|
+
newUnlockAtInSecondTimestamp: number,
|
|
40
|
+
prevUnlockAtInMillisTimestamp?: number
|
|
41
|
+
) => {
|
|
42
|
+
checkVesca(prevUnlockAtInMillisTimestamp);
|
|
43
|
+
checkVescaExpired(prevUnlockAtInMillisTimestamp!);
|
|
44
|
+
const prevUnlockAtInSecondTimestamp = Math.floor(
|
|
45
|
+
prevUnlockAtInMillisTimestamp! / 1000
|
|
46
|
+
);
|
|
47
|
+
if (lockPeriodInDays < 1) {
|
|
48
|
+
throw new Error('Minimum lock period is 1 day');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const availableLockPeriodInDays = Math.floor(
|
|
52
|
+
(newUnlockAtInSecondTimestamp - prevUnlockAtInSecondTimestamp) /
|
|
53
|
+
UNLOCK_ROUND_DURATION
|
|
54
|
+
);
|
|
55
|
+
console.log('availableLockPeriodInDays', availableLockPeriodInDays);
|
|
56
|
+
if (lockPeriodInDays > availableLockPeriodInDays) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`Cannot extend lock period by ${lockPeriodInDays} days, maximum lock period is ~4 years (${MAX_LOCK_ROUNDS} days), remaining lock period is ${
|
|
59
|
+
MAX_LOCK_ROUNDS - availableLockPeriodInDays
|
|
60
|
+
}`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
25
65
|
export const checkLockSca = (
|
|
26
|
-
scaAmountOrCoin
|
|
66
|
+
scaAmountOrCoin: number | SuiObjectArg | undefined,
|
|
27
67
|
lockPeriodInDays?: number,
|
|
28
68
|
newUnlockAtInSecondTimestamp?: number,
|
|
29
|
-
|
|
69
|
+
prevUnlockAtInMillisTimestamp?: number
|
|
30
70
|
) => {
|
|
71
|
+
const prevUnlockAtInSecondTimestamp = prevUnlockAtInMillisTimestamp
|
|
72
|
+
? Math.floor(prevUnlockAtInMillisTimestamp / 1000)
|
|
73
|
+
: undefined;
|
|
31
74
|
const isInitialLock = !prevUnlockAtInSecondTimestamp;
|
|
32
75
|
const isLockExpired =
|
|
33
76
|
!isInitialLock &&
|
|
34
77
|
prevUnlockAtInSecondTimestamp * 1000 <= new Date().getTime();
|
|
78
|
+
|
|
79
|
+
// handle for initial lock / renewing expired veSca
|
|
35
80
|
if (isInitialLock || isLockExpired) {
|
|
36
81
|
if (scaAmountOrCoin !== undefined && lockPeriodInDays !== undefined) {
|
|
37
82
|
if (lockPeriodInDays <= 0) {
|
|
@@ -61,7 +106,9 @@ export const checkLockSca = (
|
|
|
61
106
|
);
|
|
62
107
|
}
|
|
63
108
|
} else {
|
|
64
|
-
|
|
109
|
+
// handle for extending lock period / top up / both
|
|
110
|
+
checkVesca(prevUnlockAtInMillisTimestamp);
|
|
111
|
+
checkVescaExpired(prevUnlockAtInMillisTimestamp!);
|
|
65
112
|
if (
|
|
66
113
|
typeof scaAmountOrCoin === 'number' &&
|
|
67
114
|
scaAmountOrCoin < MIN_TOP_UP_AMOUNT
|
|
@@ -69,43 +116,12 @@ export const checkLockSca = (
|
|
|
69
116
|
throw new Error('Minimum top up amount is 1 SCA');
|
|
70
117
|
}
|
|
71
118
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
export const checkExtendLockPeriod = (
|
|
85
|
-
lockPeriodInDays: number,
|
|
86
|
-
newUnlockAtInSecondTimestamp: number,
|
|
87
|
-
prevUnlockAtInSecondTimestamp?: number
|
|
88
|
-
) => {
|
|
89
|
-
checkVesca(prevUnlockAtInSecondTimestamp);
|
|
90
|
-
|
|
91
|
-
if (lockPeriodInDays <= 0) {
|
|
92
|
-
throw new Error('Lock period must be greater than 0');
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const isInitialLock = !prevUnlockAtInSecondTimestamp;
|
|
96
|
-
const isLockExpired =
|
|
97
|
-
!isInitialLock &&
|
|
98
|
-
prevUnlockAtInSecondTimestamp * 1000 <= new Date().getTime();
|
|
99
|
-
if (isLockExpired) {
|
|
100
|
-
throw new Error('veSca is expired, use renewExpiredVeScaQuick instead');
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (prevUnlockAtInSecondTimestamp) {
|
|
104
|
-
const totalLockDuration =
|
|
105
|
-
newUnlockAtInSecondTimestamp - prevUnlockAtInSecondTimestamp!;
|
|
106
|
-
if (totalLockDuration > MAX_LOCK_DURATION - UNLOCK_ROUND_DURATION) {
|
|
107
|
-
throw new Error(
|
|
108
|
-
`Maximum lock period is ~4 years (${MAX_LOCK_ROUNDS - 1} days)`
|
|
119
|
+
// for topup and extend lock period
|
|
120
|
+
if (newUnlockAtInSecondTimestamp && lockPeriodInDays) {
|
|
121
|
+
checkExtendLockPeriod(
|
|
122
|
+
lockPeriodInDays,
|
|
123
|
+
newUnlockAtInSecondTimestamp,
|
|
124
|
+
prevUnlockAtInMillisTimestamp
|
|
109
125
|
);
|
|
110
126
|
}
|
|
111
127
|
}
|
|
@@ -113,18 +129,19 @@ export const checkExtendLockPeriod = (
|
|
|
113
129
|
|
|
114
130
|
export const checkExtendLockAmount = (
|
|
115
131
|
scaAmount: number,
|
|
116
|
-
|
|
132
|
+
prevUnlockAtInMillisTimestamp?: number
|
|
117
133
|
) => {
|
|
118
|
-
checkVesca(
|
|
134
|
+
checkVesca(prevUnlockAtInMillisTimestamp);
|
|
135
|
+
checkVescaExpired(prevUnlockAtInMillisTimestamp!);
|
|
119
136
|
|
|
120
137
|
if (scaAmount < MIN_TOP_UP_AMOUNT) {
|
|
121
138
|
throw new Error('Minimum top up amount is 1 SCA');
|
|
122
139
|
}
|
|
123
140
|
|
|
124
|
-
const isInitialLock = !
|
|
141
|
+
const isInitialLock = !prevUnlockAtInMillisTimestamp;
|
|
125
142
|
const isLockExpired =
|
|
126
|
-
!isInitialLock &&
|
|
127
|
-
|
|
143
|
+
!isInitialLock && prevUnlockAtInMillisTimestamp <= new Date().getTime();
|
|
144
|
+
|
|
128
145
|
if (isLockExpired) {
|
|
129
146
|
throw new Error('veSca is expired, use renewExpiredVeScaQuick instead');
|
|
130
147
|
}
|
|
@@ -133,9 +150,14 @@ export const checkExtendLockAmount = (
|
|
|
133
150
|
export const checkRenewExpiredVeSca = (
|
|
134
151
|
scaAmount: number,
|
|
135
152
|
lockPeriodInDays: number,
|
|
136
|
-
|
|
153
|
+
prevUnlockAtInMillisTimestamp?: number
|
|
137
154
|
) => {
|
|
138
|
-
|
|
155
|
+
if (
|
|
156
|
+
!prevUnlockAtInMillisTimestamp ||
|
|
157
|
+
prevUnlockAtInMillisTimestamp > new Date().getTime()
|
|
158
|
+
) {
|
|
159
|
+
throw new Error('Renew method can only be used for expired veSca');
|
|
160
|
+
}
|
|
139
161
|
|
|
140
162
|
if (scaAmount < MIN_INITIAL_LOCK_AMOUNT) {
|
|
141
163
|
throw new Error('Minimum lock amount for renewing expired vesca 10 SCA');
|
|
@@ -148,9 +170,3 @@ export const checkRenewExpiredVeSca = (
|
|
|
148
170
|
);
|
|
149
171
|
}
|
|
150
172
|
};
|
|
151
|
-
|
|
152
|
-
export const checkVesca = (prevUnlockAtInSecondTimestamp?: number) => {
|
|
153
|
-
if (prevUnlockAtInSecondTimestamp === undefined) {
|
|
154
|
-
throw new Error('veSca not found');
|
|
155
|
-
}
|
|
156
|
-
};
|