@cetusprotocol/dlmm-sdk 0.0.1

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.
Files changed (44) hide show
  1. package/.turbo/turbo-build.log +10423 -0
  2. package/README.md +646 -0
  3. package/dist/index.d.mts +1015 -0
  4. package/dist/index.d.ts +1015 -0
  5. package/dist/index.js +13 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/index.mjs +13 -0
  8. package/dist/index.mjs.map +1 -0
  9. package/package.json +35 -0
  10. package/src/config/index.ts +2 -0
  11. package/src/config/mainnet.ts +25 -0
  12. package/src/config/testnet.ts +30 -0
  13. package/src/errors/errors.ts +40 -0
  14. package/src/index.ts +8 -0
  15. package/src/modules/configModule.ts +184 -0
  16. package/src/modules/index.ts +1 -0
  17. package/src/modules/partnerModule.ts +302 -0
  18. package/src/modules/poolModule.ts +578 -0
  19. package/src/modules/positionModule.ts +888 -0
  20. package/src/modules/rewardModule.ts +175 -0
  21. package/src/modules/swapModule.ts +129 -0
  22. package/src/sdk.ts +88 -0
  23. package/src/types/constants.ts +23 -0
  24. package/src/types/dlmm.ts +445 -0
  25. package/src/types/index.ts +2 -0
  26. package/src/utils/binUtils.ts +552 -0
  27. package/src/utils/feeUtils.ts +92 -0
  28. package/src/utils/index.ts +5 -0
  29. package/src/utils/parseData.ts +519 -0
  30. package/src/utils/strategyUtils.ts +121 -0
  31. package/src/utils/weightUtils.ts +510 -0
  32. package/tests/add_liquidity_bidask.test.ts +180 -0
  33. package/tests/add_liquidity_curve.test.ts +244 -0
  34. package/tests/add_liquidity_spot.test.ts +262 -0
  35. package/tests/bin.test.ts +80 -0
  36. package/tests/config.test.ts +51 -0
  37. package/tests/partner.test.ts +74 -0
  38. package/tests/pool.test.ts +174 -0
  39. package/tests/position.test.ts +76 -0
  40. package/tests/remove_liquidity.test.ts +137 -0
  41. package/tests/swap.test.ts +96 -0
  42. package/tests/tsconfig.json +26 -0
  43. package/tsconfig.json +5 -0
  44. package/tsup.config.ts +9 -0
@@ -0,0 +1,175 @@
1
+ import { Transaction } from '@mysten/sui/transactions'
2
+ import {
3
+ asIntN,
4
+ asUintN,
5
+ CLOCK_ADDRESS,
6
+ CoinAssist,
7
+ d,
8
+ getObjectFields,
9
+ getPackagerConfigs,
10
+ IModule,
11
+ MathUtil,
12
+ } from '@cetusprotocol/common-sdk'
13
+ import { CetusDlmmSDK } from '../sdk'
14
+ import { AddRewardOption, InitRewardOption, RewardAccessOption, RewardPeriodEmission, RewardWhiteListOption } from '../types/dlmm'
15
+ import BN from 'bn.js'
16
+
17
+ export class RewardModule implements IModule<CetusDlmmSDK> {
18
+ protected _sdk: CetusDlmmSDK
19
+
20
+ constructor(sdk: CetusDlmmSDK) {
21
+ this._sdk = sdk
22
+ }
23
+
24
+ get sdk() {
25
+ return this._sdk
26
+ }
27
+
28
+ async getRewardPeriodEmission(
29
+ period_emission_handle: string,
30
+ curr_emission_per_second: string,
31
+ last_updated_time: number
32
+ ): Promise<RewardPeriodEmission[]> {
33
+ const res = await this._sdk.FullClient.getDynamicFieldsByPage(period_emission_handle)
34
+ const result: RewardPeriodEmission[] = []
35
+ const warpIds = res.data.map((item) => item.objectId)
36
+ if (warpIds.length > 0) {
37
+ const warRes = await this._sdk.FullClient.batchGetObjects(warpIds, {
38
+ showContent: true,
39
+ })
40
+
41
+ warRes.forEach((item) => {
42
+ const fields = getObjectFields(item)
43
+ const emission_rate = MathUtil.u128ToI128(new BN(fields.value.fields.value.fields.bits)).toString()
44
+ const time = fields.name
45
+ const visualizedTime = new Date(Number(time) * 1000).toLocaleString()
46
+ const emissions_per = MathUtil.fromX64(new BN(emission_rate)).toString()
47
+ const rewardPeriodEmission: RewardPeriodEmission = {
48
+ emissions_per_second: '0',
49
+ emissions_per_day: '0',
50
+ emissions_per,
51
+ time,
52
+ visualized_time: visualizedTime,
53
+ }
54
+ result.push(rewardPeriodEmission)
55
+ })
56
+ }
57
+ const sortedList = result.sort((a, b) => Number(a.time) - Number(b.time))
58
+ const newNodeList: RewardPeriodEmission[] = []
59
+
60
+ newNodeList.push({
61
+ emissions_per_second: curr_emission_per_second,
62
+ emissions_per_day: d(curr_emission_per_second)
63
+ .mul(60 * 60 * 24)
64
+ .toString(),
65
+ emissions_per: '0',
66
+ time: last_updated_time.toString(),
67
+ visualized_time: new Date(last_updated_time * 1000).toLocaleString(),
68
+ })
69
+
70
+ let last_emission_rate = curr_emission_per_second
71
+ for (let i = 0; i < sortedList.length; i++) {
72
+ const item = sortedList[i]
73
+ if (d(item.time).lte(last_updated_time)) {
74
+ continue
75
+ }
76
+ last_emission_rate = d(last_emission_rate).add(d(item.emissions_per)).toString()
77
+ const emissions_per_day = d(last_emission_rate)
78
+ .mul(60 * 60 * 24)
79
+ .toString()
80
+ if (d(last_emission_rate).lt(0)) {
81
+ item.emissions_per_second = '0'
82
+ item.emissions_per_day = '0'
83
+ } else {
84
+ item.emissions_per_second = last_emission_rate
85
+ item.emissions_per_day = emissions_per_day
86
+ }
87
+ newNodeList.push(item)
88
+ }
89
+
90
+ return newNodeList
91
+ }
92
+
93
+ /**
94
+ * Add reward to a pool
95
+ * @param options - The options for adding reward
96
+ * @returns The transaction for adding reward
97
+ */
98
+ addRewardPayload(option: AddRewardOption, tx?: Transaction): Transaction {
99
+ tx = tx || new Transaction()
100
+ const { dlmm_pool } = this._sdk.sdkOptions
101
+ const { global_config_id, versioned_id } = getPackagerConfigs(dlmm_pool)
102
+
103
+ const { pool_id, reward_coin_type, reward_amount, start_time_seconds, end_time_seconds, coin_type_a, coin_type_b } = option
104
+ const reward_coin = CoinAssist.buildCoinWithBalance(BigInt(reward_amount), reward_coin_type, tx)
105
+
106
+ // const start_time_vec = tx.makeMoveVec({
107
+ // elements: start_time_seconds ? [tx.pure.u64(start_time_seconds)] : [],
108
+ // type: 'u64',
109
+ // })
110
+ tx.pure.option('u64', start_time_seconds)
111
+
112
+ tx.moveCall({
113
+ target: `${dlmm_pool.published_at}::pool::add_reward`,
114
+ arguments: [
115
+ tx.object(pool_id),
116
+ reward_coin,
117
+ tx.pure.u64(reward_amount),
118
+ tx.pure.option('u64', start_time_seconds),
119
+ tx.pure.u64(end_time_seconds),
120
+ tx.object(global_config_id),
121
+ tx.object(versioned_id),
122
+ tx.object(CLOCK_ADDRESS),
123
+ ],
124
+ typeArguments: [coin_type_a, coin_type_b, reward_coin_type],
125
+ })
126
+
127
+ return tx
128
+ }
129
+
130
+ /**
131
+ * Initialize reward for a pool
132
+ * @param option - The option for initializing reward
133
+ * @param tx - The transaction to add the reward to
134
+ * @returns The transaction for initializing reward
135
+ */
136
+ initRewardPayload(option: InitRewardOption, tx?: Transaction): Transaction {
137
+ tx = tx || new Transaction()
138
+ const { dlmm_pool } = this._sdk.sdkOptions
139
+ const { global_config_id, versioned_id } = getPackagerConfigs(dlmm_pool)
140
+
141
+ const { pool_id, reward_coin_types, coin_type_a, coin_type_b } = option
142
+
143
+ reward_coin_types.forEach((reward_coin_type) => {
144
+ tx.moveCall({
145
+ target: `${dlmm_pool.published_at}::pool::initialize_reward`,
146
+ arguments: [tx.object(pool_id), tx.object(global_config_id), tx.object(versioned_id), tx.object(CLOCK_ADDRESS)],
147
+ typeArguments: [coin_type_a, coin_type_b, reward_coin_type],
148
+ })
149
+ })
150
+
151
+ return tx
152
+ }
153
+
154
+ /**
155
+ * Build the payload for making reward public or private
156
+ * @param option - The option for making reward public or private
157
+ * @param tx - The transaction to make the reward public or private
158
+ * @returns The transaction for making reward public or private
159
+ */
160
+ buildRewardAccessPayload(option: RewardAccessOption, tx?: Transaction): Transaction {
161
+ tx = tx || new Transaction()
162
+ const { dlmm_pool } = this._sdk.sdkOptions
163
+ const { global_config_id, versioned_id } = getPackagerConfigs(dlmm_pool)
164
+
165
+ const { pool_id, type, coin_type_a, coin_type_b } = option
166
+
167
+ tx.moveCall({
168
+ target: `${dlmm_pool.published_at}::pool::${type === 'to_public' ? 'make_reward_public' : 'make_reward_private'}`,
169
+ arguments: [tx.object(pool_id), tx.object(global_config_id), tx.object(versioned_id)],
170
+ typeArguments: [coin_type_a, coin_type_b],
171
+ })
172
+
173
+ return tx
174
+ }
175
+ }
@@ -0,0 +1,129 @@
1
+ import { Transaction } from '@mysten/sui/transactions'
2
+ import { CLOCK_ADDRESS, CoinAssist, d, DETAILS_KEYS, getPackagerConfigs, IModule } from '@cetusprotocol/common-sdk'
3
+ import { DlmmErrorCode, handleError } from '../errors/errors'
4
+ import { CetusDlmmSDK } from '../sdk'
5
+ import { PreSwapOption, PreSwapQuote, SwapOption } from '../types/dlmm'
6
+ import { normalizeSuiAddress } from '@mysten/sui/utils'
7
+ import { parsedSwapQuoteData } from '../utils/parseData'
8
+
9
+ export class SwapModule implements IModule<CetusDlmmSDK> {
10
+ protected _sdk: CetusDlmmSDK
11
+
12
+ constructor(sdk: CetusDlmmSDK) {
13
+ this._sdk = sdk
14
+ }
15
+
16
+ get sdk() {
17
+ return this._sdk
18
+ }
19
+
20
+ async preSwapQuote(option: PreSwapOption): Promise<PreSwapQuote> {
21
+ const { dlmm_pool } = this._sdk.sdkOptions
22
+ const { pool_id, coin_type_a, coin_type_b, a2b, by_amount_in, in_amount } = option
23
+ const { versioned_id, global_config_id } = getPackagerConfigs(dlmm_pool)
24
+ const tx = new Transaction()
25
+
26
+ tx.moveCall({
27
+ target: `${dlmm_pool.published_at}::pool::flash_swap`,
28
+ arguments: [
29
+ tx.object(pool_id),
30
+ tx.pure.bool(a2b),
31
+ tx.pure.bool(by_amount_in),
32
+ tx.pure.u64(in_amount),
33
+ tx.object(global_config_id),
34
+ tx.object(versioned_id),
35
+ tx.object(CLOCK_ADDRESS),
36
+ ],
37
+ typeArguments: [coin_type_a, coin_type_b],
38
+ })
39
+
40
+ const simulateRes = await this.sdk.FullClient.devInspectTransactionBlock({
41
+ transactionBlock: tx,
42
+ sender: normalizeSuiAddress('0x0'),
43
+ })
44
+
45
+ if (simulateRes.error != null) {
46
+ return handleError(DlmmErrorCode.FetchError, new Error(simulateRes.error), {
47
+ [DETAILS_KEYS.METHOD_NAME]: 'fetchSwapQuote',
48
+ [DETAILS_KEYS.REQUEST_PARAMS]: option,
49
+ })
50
+ }
51
+
52
+ const quoteInfo = parsedSwapQuoteData(simulateRes, a2b)
53
+ if (quoteInfo == null) {
54
+ return handleError(DlmmErrorCode.FetchError, new Error('No quote info'), {
55
+ [DETAILS_KEYS.METHOD_NAME]: 'preSwapQuote',
56
+ [DETAILS_KEYS.REQUEST_PARAMS]: option,
57
+ })
58
+ }
59
+ quoteInfo.a2b = a2b
60
+ return quoteInfo
61
+ }
62
+
63
+ swapPayload(option: SwapOption): Transaction {
64
+ const { dlmm_pool, dlmm_router } = this._sdk.sdkOptions
65
+ const { quote_obj, coin_type_a, coin_type_b, by_amount_in, slippage, partner } = option
66
+ const { pool_id, in_amount, out_amount, a2b } = quote_obj
67
+
68
+ const tx = new Transaction()
69
+
70
+ const in_amount_limit = by_amount_in
71
+ ? in_amount
72
+ : d(in_amount)
73
+ .mul(1 + slippage)
74
+ .toFixed(0)
75
+
76
+ const out_amount_limit = by_amount_in
77
+ ? d(out_amount)
78
+ .mul(1 - slippage)
79
+ .toFixed(0)
80
+ : out_amount
81
+
82
+ const in_coin = CoinAssist.buildCoinWithBalance(BigInt(in_amount_limit), a2b ? coin_type_a : coin_type_b, tx)
83
+
84
+ const { versioned_id, global_config_id } = getPackagerConfigs(dlmm_pool)
85
+
86
+ console.log('🚀 ~ SwapModule ~ option:', {
87
+ ...option,
88
+ in_amount_limit,
89
+ out_amount_limit,
90
+ })
91
+
92
+ if (partner) {
93
+ tx.moveCall({
94
+ target: `${dlmm_router.published_at}::swap::${a2b ? 'swap_a2b_with_partner' : 'swap_b2a_with_partner'}`,
95
+ arguments: [
96
+ tx.object(pool_id),
97
+ tx.object(partner),
98
+ in_coin,
99
+ tx.pure.bool(by_amount_in),
100
+ tx.pure.u64(BigInt(by_amount_in ? in_amount : out_amount)),
101
+ tx.pure.u64(BigInt(by_amount_in ? out_amount_limit : in_amount_limit)),
102
+ tx.object(global_config_id),
103
+ tx.object(versioned_id),
104
+ tx.object(CLOCK_ADDRESS),
105
+ ],
106
+ typeArguments: [coin_type_a, coin_type_b],
107
+ })
108
+ } else {
109
+ tx.moveCall({
110
+ target: `${dlmm_router.published_at}::swap::${a2b ? 'swap_a2b' : 'swap_b2a'}`,
111
+ arguments: [
112
+ tx.object(pool_id),
113
+ in_coin,
114
+ tx.pure.bool(by_amount_in),
115
+ tx.pure.u64(BigInt(by_amount_in ? in_amount : out_amount)),
116
+ tx.pure.u64(BigInt(by_amount_in ? out_amount_limit : in_amount_limit)),
117
+ tx.object(global_config_id),
118
+ tx.object(versioned_id),
119
+ tx.object(CLOCK_ADDRESS),
120
+ ],
121
+ typeArguments: [coin_type_a, coin_type_b],
122
+ })
123
+ }
124
+
125
+ tx.transferObjects([in_coin], this.sdk.getSenderAddress())
126
+
127
+ return tx
128
+ }
129
+ }
package/src/sdk.ts ADDED
@@ -0,0 +1,88 @@
1
+ import type { BaseSdkOptions, Package } from '@cetusprotocol/common-sdk'
2
+ import { SdkWrapper } from '@cetusprotocol/common-sdk'
3
+ import type { DlmmConfigs } from './types/dlmm'
4
+ import { dlmmMainnet } from './config/mainnet'
5
+ import { PoolModule } from './modules/poolModule'
6
+ import { dlmmTestnet } from './config/testnet'
7
+ import { PositionModule } from './modules/positionModule'
8
+ import { SwapModule } from './modules/swapModule'
9
+ import { PartnerModule } from './modules/partnerModule'
10
+ import { RewardModule } from './modules/rewardModule'
11
+ import { ConfigModule } from './modules/configModule'
12
+
13
+ /**
14
+ * Represents options and configurations for an SDK.
15
+ */
16
+ export interface SdkOptions extends BaseSdkOptions {
17
+ dlmm_pool: Package<DlmmConfigs>
18
+ dlmm_router: Package
19
+ faucet?: Package
20
+ }
21
+
22
+ /**
23
+ * The entry class of CetusDcaSDK, which is almost responsible for all interactions with dca.
24
+ */
25
+ export class CetusDlmmSDK extends SdkWrapper<SdkOptions> {
26
+ protected _pool: PoolModule
27
+ protected _position: PositionModule
28
+ protected _swap: SwapModule
29
+ protected _partner: PartnerModule
30
+ protected _reward: RewardModule
31
+ protected _config: ConfigModule
32
+
33
+ constructor(options: SdkOptions) {
34
+ super(options)
35
+
36
+ this._pool = new PoolModule(this)
37
+ this._position = new PositionModule(this)
38
+ this._swap = new SwapModule(this)
39
+ this._partner = new PartnerModule(this)
40
+ this._reward = new RewardModule(this)
41
+ this._config = new ConfigModule(this)
42
+ }
43
+
44
+ get Pool(): PoolModule {
45
+ return this._pool
46
+ }
47
+
48
+ get Position(): PositionModule {
49
+ return this._position
50
+ }
51
+
52
+ get Swap(): SwapModule {
53
+ return this._swap
54
+ }
55
+
56
+ get Partner(): PartnerModule {
57
+ return this._partner
58
+ }
59
+
60
+ get Reward(): RewardModule {
61
+ return this._reward
62
+ }
63
+
64
+ get Config(): ConfigModule {
65
+ return this._config
66
+ }
67
+
68
+ /**
69
+ * Static factory method to initialize the SDK
70
+ * @param options SDK initialization options
71
+ * @returns An instance of CetusBurnDK
72
+ */
73
+ static createSDK(options: BaseSdkOptions): CetusDlmmSDK {
74
+ const { env = 'mainnet' } = options
75
+ return env === 'mainnet'
76
+ ? CetusDlmmSDK.createCustomSDK({ ...dlmmMainnet, ...options })
77
+ : CetusDlmmSDK.createCustomSDK({ ...dlmmTestnet, ...options })
78
+ }
79
+
80
+ /**
81
+ * Create a custom SDK instance with the given options
82
+ * @param options The options for the SDK
83
+ * @returns An instance of CetusBurnSDK
84
+ */
85
+ static createCustomSDK<T extends BaseSdkOptions>(options: T & SdkOptions): CetusDlmmSDK {
86
+ return new CetusDlmmSDK(options)
87
+ }
88
+ }
@@ -0,0 +1,23 @@
1
+ export const MAX_BIN_PER_POSITION = 1000
2
+
3
+ export const MIN_BIN_ID = -443636
4
+
5
+ export const MAX_BIN_ID = 443636
6
+
7
+ export const BASIS_POINT_MAX = 10000
8
+
9
+ export const DEFAULT_MAX_WEIGHT = 2000
10
+
11
+ export const DEFAULT_MIN_WEIGHT = 200
12
+
13
+ export const BIN_BOUND = 443636n
14
+
15
+ export const MAX_FEE_RATE = 100_000_000
16
+
17
+ export const FEE_PRECISION = 1_000_000_000
18
+
19
+ export const BASIS_POINT = 10000
20
+
21
+ export const REWARD_PERIOD = 7 * 24 * 60 * 60
22
+
23
+ export const REWARD_PERIOD_START_AT = 1747627200