@scallop-io/sui-scallop-sdk 0.44.26 → 0.44.28

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.
@@ -382,4 +382,16 @@ export declare class ScallopQuery {
382
382
  * @return Total value locked.
383
383
  */
384
384
  getTvl(indexer?: boolean): Promise<import("../types").TotalValueLocked>;
385
+ /**
386
+ * Get binded obligationId from a veScaKey if it exists.
387
+ * @param veScaKey
388
+ * @returns obligationId
389
+ */
390
+ getBindedObligationId(veScaKey: string): Promise<string | null>;
391
+ /**
392
+ * Get binded veSCA key from a obligationId if it exists.
393
+ * @param obligationId
394
+ * @returns veScaKey
395
+ */
396
+ getBindedVeScaKey(obligationId: string): Promise<string | null>;
385
397
  }
@@ -35,3 +35,11 @@ export declare const queryBorrowIncentiveAccounts: (query: ScallopQuery, obligat
35
35
  vsui?: import("../types").ParsedBorrowIncentiveAccountData | undefined;
36
36
  sca?: import("../types").ParsedBorrowIncentiveAccountData | undefined;
37
37
  }>;
38
+ /**
39
+ * Check veSca bind status
40
+ * @param query
41
+ * @param veScaKey
42
+ * @returns
43
+ */
44
+ export declare const getBindedObligationId: (query: ScallopQuery, veScaKeyId: string) => Promise<string | null>;
45
+ export declare const getBindedVeScaKey: (query: ScallopQuery, obliationId: string) => Promise<string | null>;
@@ -1,4 +1,4 @@
1
- import type { SuiTxBlock as SuiKitTxBlock, SuiTxArg, SuiObjectArg } from '@scallop-io/sui-kit';
1
+ import type { SuiTxBlock as SuiKitTxBlock, SuiObjectArg } from '@scallop-io/sui-kit';
2
2
  import type { TransactionResult } from '@mysten/sui.js/transactions';
3
3
  import type { ScallopBuilder } from '../../models';
4
4
  import type { SupportBorrowIncentiveCoins, SupportBorrowIncentiveRewardCoins } from '../constant';
@@ -12,7 +12,7 @@ export type BorrowIncentiveIds = {
12
12
  };
13
13
  export type BorrowIncentiveNormalMethods = {
14
14
  stakeObligation: (obligation: SuiObjectArg, obligationKey: SuiObjectArg) => void;
15
- stakeObligationWithVesca: (obligation: SuiObjectArg, obligationKey: SuiObjectArg, veScaKey: SuiTxArg) => void;
15
+ stakeObligationWithVesca: (obligation: SuiObjectArg, obligationKey: SuiObjectArg, veScaKey: SuiObjectArg) => void;
16
16
  unstakeObligation: (obligation: SuiObjectArg, obligationKey: SuiObjectArg) => void;
17
17
  claimBorrowIncentive: (obligation: SuiObjectArg, obligationKey: SuiObjectArg, coinName: SupportBorrowIncentiveCoins, rewardType: SupportBorrowIncentiveRewardCoins) => TransactionResult;
18
18
  deactivateBoost: (obligation: SuiObjectArg, veScaKey: SuiObjectArg) => void;
@@ -1,7 +1,8 @@
1
1
  export type Vesca = {
2
2
  id: string;
3
3
  keyId: string;
4
- lockedScaAmount: number;
4
+ lockedScaAmount: string;
5
5
  lockedScaCoin: number;
6
+ currentVeScaBalance: number;
6
7
  unlockAt: number;
7
8
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scallop-io/sui-scallop-sdk",
3
- "version": "0.44.26",
3
+ "version": "0.44.28",
4
4
  "description": "Typescript sdk for interacting with Scallop contract on SUI",
5
5
  "keywords": [
6
6
  "sui",
@@ -2,7 +2,11 @@ import { TransactionBlock } from '@mysten/sui.js/transactions';
2
2
  import { SUI_CLOCK_OBJECT_ID } from '@mysten/sui.js/utils';
3
3
  import { SuiTxBlock as SuiKitTxBlock } from '@scallop-io/sui-kit';
4
4
  import { borrowIncentiveRewardCoins } from '../constants/enum';
5
- import { getObligations, getObligationLocked } from '../queries';
5
+ import {
6
+ getObligations,
7
+ getObligationLocked,
8
+ getBindedObligationId,
9
+ } from '../queries';
6
10
  import { requireSender } from '../utils';
7
11
  import type { SuiObjectArg } from '@scallop-io/sui-kit';
8
12
  import type { ScallopBuilder } from '../models';
@@ -61,66 +65,20 @@ const requireObligationInfo = async (
61
65
  if (obligations.length === 0) {
62
66
  throw new Error(`No obligation found for sender ${sender}`);
63
67
  }
68
+
69
+ const selectedObligation =
70
+ obligations.find(
71
+ (obligation) =>
72
+ obligation.id === obligationId || obligation.keyId === obligationKey
73
+ ) ?? obligations[0];
74
+
64
75
  return {
65
- obligationId: obligations[0].id,
66
- obligationKey: obligations[0].keyId,
67
- obligationLocked: obligations[0].locked,
76
+ obligationId: selectedObligation.id,
77
+ obligationKey: selectedObligation.keyId,
78
+ obligationLocked: selectedObligation.locked,
68
79
  };
69
80
  };
70
81
 
71
- /**
72
- * Check veSca bind status
73
- * @param query
74
- * @param veScaKey
75
- * @returns
76
- */
77
- export const getBindedObligationId = async (
78
- builder: ScallopBuilder,
79
- veScaKey: string
80
- ) => {
81
- const borrowIncentiveObjectId = builder.address.get('borrowIncentive.object');
82
- const incentivePoolsId = builder.address.get(
83
- 'borrowIncentive.incentivePools'
84
- );
85
- const veScaPkgId = IS_VE_SCA_TEST
86
- ? '0xb220d034bdf335d77ae5bfbf6daf059c2cc7a1f719b12bfed75d1736fac038c8'
87
- : builder.address.get('vesca.id');
88
-
89
- const client = builder.suiKit.client();
90
-
91
- // get incentive pools
92
- const incentivePoolsResponse = await client.getObject({
93
- id: incentivePoolsId,
94
- options: {
95
- showContent: true,
96
- },
97
- });
98
-
99
- if (incentivePoolsResponse.data?.content?.dataType !== 'moveObject')
100
- return false;
101
- const incentivePoolFields = incentivePoolsResponse.data.content.fields as any;
102
- const veScaBindTableId = incentivePoolFields.ve_sca_bind.fields.id
103
- .id as string;
104
-
105
- // check if veSca is inside the bind table
106
- const keyType = `${borrowIncentiveObjectId}::typed_id::TypedID<${veScaPkgId}::ve_sca::VeScaKey>`;
107
- const veScaBindTableResponse = await client.getDynamicFieldObject({
108
- parentId: veScaBindTableId,
109
- name: {
110
- type: keyType,
111
- value: veScaKey,
112
- },
113
- });
114
-
115
- if (veScaBindTableResponse.data?.content?.dataType !== 'moveObject')
116
- return false;
117
- const veScaBindTableFields = veScaBindTableResponse.data.content
118
- .fields as any;
119
- // get obligationId pair
120
- const obligationId = veScaBindTableFields.value.fields.id as string;
121
-
122
- return obligationId;
123
- };
124
82
  /**
125
83
  * Generate borrow incentive normal methods.
126
84
  *
@@ -315,7 +273,7 @@ const generateBorrowIncentiveQuickMethod: GenerateBorrowIncentiveQuickMethod =
315
273
  const veSca = await requireVeSca(builder, txBlock, veScaKey);
316
274
  if (veSca) {
317
275
  const bindedObligationId = await getBindedObligationId(
318
- builder,
276
+ builder.query,
319
277
  veSca.keyId
320
278
  );
321
279
  // if bindedObligationId is equal to obligationId, then use it again
@@ -65,7 +65,11 @@ export const requireVeSca = async (
65
65
  return undefined;
66
66
  }
67
67
 
68
- return veScas[0];
68
+ return veScas.reduce(
69
+ (prev, acc) =>
70
+ acc.currentVeScaBalance > prev.currentVeScaBalance ? acc : prev,
71
+ veScas[0]
72
+ ); // return veSCA with highest veSCA balance
69
73
  };
70
74
 
71
75
  /**
@@ -228,7 +232,7 @@ const generateQuickVeScaMethod: GenerateVeScaQuickMethod = ({
228
232
  transferObjects.push(veScaKey);
229
233
  } else {
230
234
  // user must withdraw current unlocked SCA first if any
231
- if (veSca.lockedScaAmount !== 0) {
235
+ if (veSca.lockedScaCoin !== 0) {
232
236
  const unlockedSca = txBlock.redeemSca(veSca.keyId);
233
237
  transferObjects.push(unlockedSca);
234
238
  }
@@ -309,7 +313,7 @@ const generateQuickVeScaMethod: GenerateVeScaQuickMethod = ({
309
313
 
310
314
  if (veSca) {
311
315
  const transferObjects = [];
312
- if (veSca.lockedScaAmount !== 0) {
316
+ if (veSca.lockedScaCoin !== 0) {
313
317
  const unlockedSca = txBlock.redeemSca(veSca.keyId);
314
318
  transferObjects.push(unlockedSca);
315
319
  }
@@ -25,6 +25,8 @@ import {
25
25
  getObligationAccounts,
26
26
  getObligationAccount,
27
27
  getTotalValueLocked,
28
+ getBindedObligationId,
29
+ getBindedVeScaKey,
28
30
  } from '../queries';
29
31
  import {
30
32
  ScallopQueryParams,
@@ -512,4 +514,22 @@ export class ScallopQuery {
512
514
  public async getTvl(indexer: boolean = false) {
513
515
  return await getTotalValueLocked(this, indexer);
514
516
  }
517
+
518
+ /**
519
+ * Get binded obligationId from a veScaKey if it exists.
520
+ * @param veScaKey
521
+ * @returns obligationId
522
+ */
523
+ public async getBindedObligationId(veScaKey: string) {
524
+ return await getBindedObligationId(this, veScaKey);
525
+ }
526
+
527
+ /**
528
+ * Get binded veSCA key from a obligationId if it exists.
529
+ * @param obligationId
530
+ * @returns veScaKey
531
+ */
532
+ public async getBindedVeScaKey(obligationId: string) {
533
+ return await getBindedVeScaKey(this, obligationId);
534
+ }
515
535
  }
@@ -1,6 +1,7 @@
1
1
  import { normalizeStructTag } from '@mysten/sui.js/utils';
2
2
  import { SuiTxBlock as SuiKitTxBlock } from '@scallop-io/sui-kit';
3
3
  import {
4
+ IS_VE_SCA_TEST,
4
5
  SUPPORT_BORROW_INCENTIVE_POOLS,
5
6
  SUPPORT_BORROW_INCENTIVE_REWARDS,
6
7
  } from '../constants';
@@ -197,3 +198,97 @@ export const queryBorrowIncentiveAccounts = async (
197
198
 
198
199
  return borrowIncentiveAccounts;
199
200
  };
201
+
202
+ /**
203
+ * Check veSca bind status
204
+ * @param query
205
+ * @param veScaKey
206
+ * @returns
207
+ */
208
+ export const getBindedObligationId = async (
209
+ query: ScallopQuery,
210
+ veScaKeyId: string
211
+ ): Promise<string | null> => {
212
+ const borrowIncentiveObjectId = query.address.get('borrowIncentive.object');
213
+ const incentivePoolsId = query.address.get('borrowIncentive.incentivePools');
214
+ const veScaPkgId = IS_VE_SCA_TEST
215
+ ? '0xb220d034bdf335d77ae5bfbf6daf059c2cc7a1f719b12bfed75d1736fac038c8'
216
+ : query.address.get('vesca.id');
217
+
218
+ const client = query.suiKit.client();
219
+
220
+ // get incentive pools
221
+ const incentivePoolsResponse = await client.getObject({
222
+ id: incentivePoolsId,
223
+ options: {
224
+ showContent: true,
225
+ },
226
+ });
227
+
228
+ if (incentivePoolsResponse.data?.content?.dataType !== 'moveObject')
229
+ return null;
230
+ const incentivePoolFields = incentivePoolsResponse.data.content.fields as any;
231
+ const veScaBindTableId = incentivePoolFields.ve_sca_bind.fields.id
232
+ .id as string;
233
+
234
+ // check if veSca is inside the bind table
235
+ const keyType = `${borrowIncentiveObjectId}::typed_id::TypedID<${veScaPkgId}::ve_sca::VeScaKey>`;
236
+ const veScaBindTableResponse = await client.getDynamicFieldObject({
237
+ parentId: veScaBindTableId,
238
+ name: {
239
+ type: keyType,
240
+ value: veScaKeyId,
241
+ },
242
+ });
243
+
244
+ if (veScaBindTableResponse.data?.content?.dataType !== 'moveObject')
245
+ return null;
246
+ const veScaBindTableFields = veScaBindTableResponse.data.content
247
+ .fields as any;
248
+ // get obligationId pair
249
+ const obligationId = veScaBindTableFields.value.fields.id as string;
250
+
251
+ return obligationId;
252
+ };
253
+
254
+ export const getBindedVeScaKey = async (
255
+ query: ScallopQuery,
256
+ obliationId: string
257
+ ): Promise<string | null> => {
258
+ const borrowIncentiveObjectId = query.address.get('borrowIncentive.object');
259
+ const incentiveAccountsId = query.address.get(
260
+ 'borrowIncentive.incentiveAccounts'
261
+ );
262
+ const corePkg = query.address.get('core.object');
263
+ const client = query.suiKit.client();
264
+
265
+ // get IncentiveAccounts object
266
+ const incentiveAccountsObject = await client.getObject({
267
+ id: incentiveAccountsId,
268
+ options: {
269
+ showContent: true,
270
+ },
271
+ });
272
+ if (incentiveAccountsObject.data?.content?.dataType !== 'moveObject')
273
+ return null;
274
+ const incentiveAccountsTableId = (
275
+ incentiveAccountsObject.data.content.fields as any
276
+ ).accounts.fields.id.id;
277
+
278
+ // Search in the table
279
+ const bindedIncentiveAcc = await client.getDynamicFieldObject({
280
+ parentId: incentiveAccountsTableId,
281
+ name: {
282
+ type: `${borrowIncentiveObjectId}::typed_id::TypedID<${corePkg}::obligation::Obligation>`,
283
+ value: obliationId,
284
+ },
285
+ });
286
+
287
+ if (bindedIncentiveAcc.data?.content?.dataType !== 'moveObject') return null;
288
+ const bindedIncentiveAccFields = bindedIncentiveAcc.data.content
289
+ .fields as any;
290
+
291
+ return (
292
+ bindedIncentiveAccFields.value.fields.binded_ve_sca_key?.fields.id ?? null
293
+ );
294
+ };
@@ -2,7 +2,7 @@ import BigNumber from 'bignumber.js';
2
2
  import { Vesca } from '../types';
3
3
  import type { SuiObjectResponse, SuiObjectData } from '@mysten/sui.js/client';
4
4
  import type { ScallopQuery } from '../models';
5
- import { IS_VE_SCA_TEST } from 'src/constants';
5
+ import { IS_VE_SCA_TEST, MAX_LOCK_DURATION } from 'src/constants';
6
6
  /**
7
7
  * Query all owned veSca key.
8
8
  *
@@ -109,13 +109,26 @@ export const getVeSca = async (
109
109
  ) {
110
110
  const dynamicFields = (veScaDynamicFieldObject.content.fields as any).value
111
111
  .fields;
112
+
113
+ const remainingLockPeriodInMilliseconds = Math.max(
114
+ +dynamicFields.unlock_at * 1000 - Date.now(),
115
+ 0
116
+ );
117
+ const lockedScaAmount = String(dynamicFields.locked_sca_amount);
118
+ const lockedScaCoin = BigNumber(dynamicFields.locked_sca_amount)
119
+ .shiftedBy(-9)
120
+ .toNumber();
121
+ const currentVeScaBalance =
122
+ lockedScaCoin *
123
+ (Math.floor(remainingLockPeriodInMilliseconds / 1000) /
124
+ MAX_LOCK_DURATION);
125
+
112
126
  vesca = {
113
127
  id: veScaDynamicFieldObject.objectId,
114
128
  keyId: veScaKeyId,
115
- lockedScaAmount: BigNumber(dynamicFields.locked_sca_amount).toNumber(),
116
- lockedScaCoin: BigNumber(dynamicFields.locked_sca_amount)
117
- .shiftedBy(-9)
118
- .toNumber(),
129
+ lockedScaAmount,
130
+ lockedScaCoin,
131
+ currentVeScaBalance,
119
132
  unlockAt: BigNumber(dynamicFields.unlock_at).toNumber(),
120
133
  } as Vesca;
121
134
  }
@@ -1,6 +1,5 @@
1
1
  import type {
2
2
  SuiTxBlock as SuiKitTxBlock,
3
- SuiTxArg,
4
3
  SuiObjectArg,
5
4
  } from '@scallop-io/sui-kit';
6
5
  import type { TransactionResult } from '@mysten/sui.js/transactions';
@@ -27,7 +26,7 @@ export type BorrowIncentiveNormalMethods = {
27
26
  stakeObligationWithVesca: (
28
27
  obligation: SuiObjectArg,
29
28
  obligationKey: SuiObjectArg,
30
- veScaKey: SuiTxArg
29
+ veScaKey: SuiObjectArg
31
30
  ) => void;
32
31
  unstakeObligation: (
33
32
  obligation: SuiObjectArg,
@@ -1,7 +1,8 @@
1
1
  export type Vesca = {
2
2
  id: string;
3
3
  keyId: string;
4
- lockedScaAmount: number;
4
+ lockedScaAmount: string;
5
5
  lockedScaCoin: number;
6
+ currentVeScaBalance: number;
6
7
  unlockAt: number;
7
8
  };