@cetusprotocol/sui-clmm-sdk 1.0.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/.turbo/turbo-build.log +11100 -0
- package/README.md +108 -0
- package/dist/index.d.mts +2251 -0
- package/dist/index.d.ts +2251 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +13 -0
- package/dist/index.mjs.map +1 -0
- package/docs/add_liquidity.md +145 -0
- package/docs/close_position.md +57 -0
- package/docs/collect_fees.md +37 -0
- package/docs/create_clmm_pool.md +228 -0
- package/docs/error_code.md +69 -0
- package/docs/get_clmm_pools.md +92 -0
- package/docs/get_positions.md +70 -0
- package/docs/get_reward.md +53 -0
- package/docs/get_ticks.md +39 -0
- package/docs/migrate_to_version_6.0.md +143 -0
- package/docs/open_position.md +224 -0
- package/docs/partner_swap.md +60 -0
- package/docs/pre_swap.md +136 -0
- package/docs/remove_liquidity.md +124 -0
- package/docs/swap.md +153 -0
- package/docs/utils.md +85 -0
- package/package.json +37 -0
- package/src/config/index.ts +2 -0
- package/src/config/mainnet.ts +41 -0
- package/src/config/testnet.ts +40 -0
- package/src/errors/errors.ts +93 -0
- package/src/errors/index.ts +1 -0
- package/src/index.ts +10 -0
- package/src/math/apr.ts +167 -0
- package/src/math/index.ts +1 -0
- package/src/modules/configModule.ts +540 -0
- package/src/modules/index.ts +5 -0
- package/src/modules/poolModule.ts +1066 -0
- package/src/modules/positionModule.ts +932 -0
- package/src/modules/rewarderModule.ts +430 -0
- package/src/modules/swapModule.ts +389 -0
- package/src/sdk.ts +131 -0
- package/src/types/clmm_type.ts +1002 -0
- package/src/types/clmmpool.ts +366 -0
- package/src/types/config_type.ts +241 -0
- package/src/types/index.ts +8 -0
- package/src/types/sui.ts +124 -0
- package/src/types/token_type.ts +189 -0
- package/src/utils/common.ts +426 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/positionUtils.ts +434 -0
- package/src/utils/swapUtils.ts +499 -0
- package/tests/add_liquidity.test.ts +121 -0
- package/tests/add_liquidity_fix_token.test.ts +182 -0
- package/tests/apr.test.ts +71 -0
- package/tests/cetus_config.test.ts +26 -0
- package/tests/collect_fees.test.ts +11 -0
- package/tests/pool.test.ts +267 -0
- package/tests/position.test.ts +145 -0
- package/tests/remove_liquidity.test.ts +119 -0
- package/tests/rewarder.test.ts +60 -0
- package/tests/sdk_config.test.ts +49 -0
- package/tests/swap.test.ts +254 -0
- package/tests/tsconfig.json +26 -0
- package/tsconfig.json +5 -0
- package/tsup.config.ts +10 -0
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
import type { SuiObjectResponse } from '@mysten/sui/client'
|
|
2
|
+
import { normalizeSuiObjectId } from '@mysten/sui/utils'
|
|
3
|
+
import type { SuiAddressType, SuiResource } from '@cetusprotocol/common-sdk'
|
|
4
|
+
import {
|
|
5
|
+
CACHE_TIME_24H,
|
|
6
|
+
CACHE_TIME_5MIN,
|
|
7
|
+
CachedContent,
|
|
8
|
+
DETAILS_KEYS,
|
|
9
|
+
extractStructTagFromType,
|
|
10
|
+
fixCoinType,
|
|
11
|
+
getFutureTime,
|
|
12
|
+
getObjectFields,
|
|
13
|
+
getObjectId,
|
|
14
|
+
getObjectPreviousTransactionDigest,
|
|
15
|
+
getObjectType,
|
|
16
|
+
getPackagerConfigs,
|
|
17
|
+
IModule,
|
|
18
|
+
normalizeCoinType,
|
|
19
|
+
} from '@cetusprotocol/common-sdk'
|
|
20
|
+
import { Base64 } from 'js-base64'
|
|
21
|
+
import { ConfigErrorCode, handleMessageError, PoolErrorCode } from '../errors/errors'
|
|
22
|
+
import type { CetusClmmSDK } from '../sdk'
|
|
23
|
+
import type { CetusConfigs, ClmmPoolConfig, CoinConfig, LaunchpadPoolConfig } from '../types'
|
|
24
|
+
/**
|
|
25
|
+
* Helper class to help interact with clmm pool and coin and launchpad pool config.
|
|
26
|
+
*/
|
|
27
|
+
export class ConfigModule implements IModule<CetusClmmSDK> {
|
|
28
|
+
protected _sdk: CetusClmmSDK
|
|
29
|
+
|
|
30
|
+
private readonly _cache: Record<string, CachedContent> = {}
|
|
31
|
+
|
|
32
|
+
constructor(sdk: CetusClmmSDK) {
|
|
33
|
+
this._sdk = sdk
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get sdk() {
|
|
37
|
+
return this._sdk
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Set default token list cache.
|
|
42
|
+
* @param {CoinConfig[]}coin_list
|
|
43
|
+
*/
|
|
44
|
+
setTokenListCache(coin_list: CoinConfig[]) {
|
|
45
|
+
const { coin_list_handle } = getPackagerConfigs(this.sdk.sdkOptions.cetus_config)
|
|
46
|
+
const cacheKey = `${coin_list_handle}_getCoinConfigs`
|
|
47
|
+
const cacheData = this.getCache<CoinConfig[]>(cacheKey)
|
|
48
|
+
const updatedCacheData = cacheData ? [...cacheData, ...coin_list] : coin_list
|
|
49
|
+
this.updateCache(cacheKey, updatedCacheData)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get token config list by coin type list.
|
|
54
|
+
* @param {SuiAddressType[]} coin_types Coin type list.
|
|
55
|
+
* @returns {Promise<Record<string, CoinConfig>>} Token config map.
|
|
56
|
+
*/
|
|
57
|
+
async getTokenListByCoinTypes(coin_types: SuiAddressType[]): Promise<Record<string, CoinConfig>> {
|
|
58
|
+
const tokenMap: Record<string, CoinConfig> = {}
|
|
59
|
+
const { coin_list_handle } = getPackagerConfigs(this.sdk.sdkOptions.cetus_config)
|
|
60
|
+
const cacheKey = `${coin_list_handle}_getCoinConfigs`
|
|
61
|
+
const cacheData = this.getCache<CoinConfig[]>(cacheKey)
|
|
62
|
+
|
|
63
|
+
if (cacheData !== undefined) {
|
|
64
|
+
const tokenList = cacheData
|
|
65
|
+
for (const coinType of coin_types) {
|
|
66
|
+
for (const token of tokenList) {
|
|
67
|
+
if (normalizeCoinType(coinType) === normalizeCoinType(token.address)) {
|
|
68
|
+
tokenMap[coinType] = token
|
|
69
|
+
continue
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const unFoundArray = coin_types.filter((coinType: string) => {
|
|
76
|
+
return tokenMap[coinType] === undefined
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
for (const coinType of unFoundArray) {
|
|
80
|
+
const metadataKey = `${coinType}_metadata`
|
|
81
|
+
const metadata = this.getCache<CoinConfig>(metadataKey)
|
|
82
|
+
if (metadata !== undefined) {
|
|
83
|
+
tokenMap[coinType] = metadata as CoinConfig
|
|
84
|
+
} else {
|
|
85
|
+
const data = await this._sdk.FullClient.getCoinMetadata({
|
|
86
|
+
coinType,
|
|
87
|
+
})
|
|
88
|
+
if (data) {
|
|
89
|
+
const token: CoinConfig = {
|
|
90
|
+
id: data.id as string,
|
|
91
|
+
pyth_id: '',
|
|
92
|
+
name: data.name,
|
|
93
|
+
symbol: data.symbol,
|
|
94
|
+
official_symbol: data.symbol,
|
|
95
|
+
coingecko_id: '',
|
|
96
|
+
decimals: data.decimals,
|
|
97
|
+
project_url: '',
|
|
98
|
+
logo_url: data.iconUrl as string,
|
|
99
|
+
address: coinType,
|
|
100
|
+
}
|
|
101
|
+
tokenMap[coinType] = token
|
|
102
|
+
|
|
103
|
+
this.updateCache(metadataKey, token, CACHE_TIME_24H)
|
|
104
|
+
} else {
|
|
105
|
+
console.log(`not found ${coinType}`)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return tokenMap
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get coin config list.
|
|
115
|
+
* @param {boolean} force_refresh Whether to force a refresh of the cache entry.
|
|
116
|
+
* @param {boolean} transform_extensions Whether to transform extensions.
|
|
117
|
+
* @returns {Promise<CoinConfig[]>} Coin config list.
|
|
118
|
+
*/
|
|
119
|
+
async getCoinConfigs(force_refresh = false, transform_extensions = true): Promise<CoinConfig[]> {
|
|
120
|
+
const { coin_list_handle } = getPackagerConfigs(this.sdk.sdkOptions.cetus_config)
|
|
121
|
+
const cacheKey = `${coin_list_handle}_getCoinConfigs`
|
|
122
|
+
const cacheData = this.getCache<CoinConfig[]>(cacheKey, force_refresh)
|
|
123
|
+
if (cacheData) {
|
|
124
|
+
return cacheData
|
|
125
|
+
}
|
|
126
|
+
const res = await this._sdk.FullClient.getDynamicFieldsByPage(coin_list_handle)
|
|
127
|
+
const warpIds = res.data.map((item: any) => {
|
|
128
|
+
return item.objectId
|
|
129
|
+
})
|
|
130
|
+
const objects = await this._sdk.FullClient.batchGetObjects(warpIds, { showContent: true })
|
|
131
|
+
const coinList: CoinConfig[] = []
|
|
132
|
+
objects.forEach((object) => {
|
|
133
|
+
if (object.error != null || object.data?.content?.dataType !== 'moveObject') {
|
|
134
|
+
handleMessageError(
|
|
135
|
+
PoolErrorCode.FetchError,
|
|
136
|
+
`when getCoinConfigs get objects error: ${object.error}, please check the rpc and contracts address config.`,
|
|
137
|
+
{
|
|
138
|
+
[DETAILS_KEYS.METHOD_NAME]: 'getCoinConfigs',
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const coin = this.buildCoinConfig(object, transform_extensions)
|
|
144
|
+
this.updateCache(`${coin_list_handle}_${coin.address}_getCoinConfig`, coin, CACHE_TIME_24H)
|
|
145
|
+
coinList.push({ ...coin })
|
|
146
|
+
})
|
|
147
|
+
this.updateCache(cacheKey, coinList, CACHE_TIME_24H)
|
|
148
|
+
return coinList
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Get coin config by coin type.
|
|
153
|
+
* @param {string} coin_type Coin type.
|
|
154
|
+
* @param {boolean} force_refresh Whether to force a refresh of the cache entry.
|
|
155
|
+
* @param {boolean} transform_extensions Whether to transform extensions.
|
|
156
|
+
* @returns {Promise<CoinConfig>} Coin config.
|
|
157
|
+
*/
|
|
158
|
+
async getCoinConfig(coin_type: string, force_refresh = false, transform_extensions = true): Promise<CoinConfig> {
|
|
159
|
+
const { coin_list_handle } = getPackagerConfigs(this.sdk.sdkOptions.cetus_config)
|
|
160
|
+
const cacheKey = `${coin_list_handle}_${coin_type}_getCoinConfig`
|
|
161
|
+
const cacheData = this.getCache<CoinConfig>(cacheKey, force_refresh)
|
|
162
|
+
if (cacheData) {
|
|
163
|
+
return cacheData
|
|
164
|
+
}
|
|
165
|
+
const object = await this._sdk.FullClient.getDynamicFieldObject({
|
|
166
|
+
parentId: coin_list_handle,
|
|
167
|
+
name: {
|
|
168
|
+
type: '0x1::type_name::TypeName',
|
|
169
|
+
value: {
|
|
170
|
+
name: fixCoinType(coin_type),
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
if (object.error != null || object.data?.content?.dataType !== 'moveObject') {
|
|
176
|
+
handleMessageError(
|
|
177
|
+
PoolErrorCode.FetchError,
|
|
178
|
+
`when getCoinConfig get object error: ${object.error}, please check the rpc and contracts address config.`,
|
|
179
|
+
{
|
|
180
|
+
[DETAILS_KEYS.METHOD_NAME]: 'getCoinConfig',
|
|
181
|
+
}
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const coin = this.buildCoinConfig(object, transform_extensions)
|
|
186
|
+
this.updateCache(cacheKey, coin, CACHE_TIME_24H)
|
|
187
|
+
return coin
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Build coin config.
|
|
192
|
+
* @param {SuiObjectResponse} object Coin object.
|
|
193
|
+
* @param {boolean} transform_extensions Whether to transform extensions.
|
|
194
|
+
* @returns {CoinConfig} Coin config.
|
|
195
|
+
*/
|
|
196
|
+
private buildCoinConfig(object: SuiObjectResponse, transform_extensions = true) {
|
|
197
|
+
let fields = getObjectFields(object)
|
|
198
|
+
|
|
199
|
+
fields = fields.value.fields
|
|
200
|
+
const coin: any = { ...fields }
|
|
201
|
+
|
|
202
|
+
coin.id = getObjectId(object)
|
|
203
|
+
coin.address = extractStructTagFromType(fields.coin_type.fields.name).full_address
|
|
204
|
+
if (fields.pyth_id) {
|
|
205
|
+
coin.pyth_id = normalizeSuiObjectId(fields.pyth_id)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
this.transformExtensions(coin, fields.extension_fields.fields.contents, transform_extensions)
|
|
209
|
+
|
|
210
|
+
delete coin.coin_type
|
|
211
|
+
return coin
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Get clmm pool config list.
|
|
216
|
+
* @param force_refresh
|
|
217
|
+
* @param transform_extensions
|
|
218
|
+
* @returns
|
|
219
|
+
*/
|
|
220
|
+
async getClmmPoolConfigs(force_refresh = false, transform_extensions = true): Promise<ClmmPoolConfig[]> {
|
|
221
|
+
const { clmm_pools_handle } = getPackagerConfigs(this.sdk.sdkOptions.cetus_config)
|
|
222
|
+
const cacheKey = `${clmm_pools_handle}_getClmmPoolConfigs`
|
|
223
|
+
const cacheData = this.getCache<ClmmPoolConfig[]>(cacheKey, force_refresh)
|
|
224
|
+
if (cacheData) {
|
|
225
|
+
return cacheData
|
|
226
|
+
}
|
|
227
|
+
const res = await this._sdk.FullClient.getDynamicFieldsByPage(clmm_pools_handle)
|
|
228
|
+
const warpIds = res.data.map((item: any) => {
|
|
229
|
+
return item.objectId
|
|
230
|
+
})
|
|
231
|
+
const objects = await this._sdk.FullClient.batchGetObjects(warpIds, { showContent: true })
|
|
232
|
+
const poolList: ClmmPoolConfig[] = []
|
|
233
|
+
objects.forEach((object) => {
|
|
234
|
+
if (object.error != null || object.data?.content?.dataType !== 'moveObject') {
|
|
235
|
+
handleMessageError(
|
|
236
|
+
PoolErrorCode.FetchError,
|
|
237
|
+
`when getClmmPoolsConfigs get objects error: ${object.error}, please check the rpc and contracts address config.`,
|
|
238
|
+
{
|
|
239
|
+
[DETAILS_KEYS.METHOD_NAME]: 'getClmmPoolConfigs',
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const pool = this.buildClmmPoolConfig(object, transform_extensions)
|
|
245
|
+
this.updateCache(`${pool.pool_address}_getClmmPoolConfig`, pool, CACHE_TIME_24H)
|
|
246
|
+
poolList.push({ ...pool })
|
|
247
|
+
})
|
|
248
|
+
this.updateCache(cacheKey, poolList, CACHE_TIME_24H)
|
|
249
|
+
return poolList
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async getClmmPoolConfig(pool_id: string, force_refresh = false, transform_extensions = true): Promise<ClmmPoolConfig> {
|
|
253
|
+
const { clmm_pools_handle } = getPackagerConfigs(this.sdk.sdkOptions.cetus_config)
|
|
254
|
+
const cacheKey = `${pool_id}_getClmmPoolConfig`
|
|
255
|
+
const cacheData = this.getCache<ClmmPoolConfig>(cacheKey, force_refresh)
|
|
256
|
+
if (cacheData) {
|
|
257
|
+
return cacheData
|
|
258
|
+
}
|
|
259
|
+
const object = await this._sdk.FullClient.getDynamicFieldObject({
|
|
260
|
+
parentId: clmm_pools_handle,
|
|
261
|
+
name: {
|
|
262
|
+
type: 'address',
|
|
263
|
+
value: pool_id,
|
|
264
|
+
},
|
|
265
|
+
})
|
|
266
|
+
const pool = this.buildClmmPoolConfig(object, transform_extensions)
|
|
267
|
+
this.updateCache(cacheKey, pool, CACHE_TIME_24H)
|
|
268
|
+
return pool
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private buildClmmPoolConfig(object: SuiObjectResponse, transform_extensions = true) {
|
|
272
|
+
let fields = getObjectFields(object)
|
|
273
|
+
fields = fields.value.fields
|
|
274
|
+
const pool: any = { ...fields }
|
|
275
|
+
|
|
276
|
+
pool.id = getObjectId(object)
|
|
277
|
+
pool.pool_address = normalizeSuiObjectId(fields.pool_address)
|
|
278
|
+
|
|
279
|
+
this.transformExtensions(pool, fields.extension_fields.fields.contents, transform_extensions)
|
|
280
|
+
return pool
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Get launchpad pool config list.
|
|
285
|
+
* @param force_refresh
|
|
286
|
+
* @returns
|
|
287
|
+
*/
|
|
288
|
+
async getLaunchpadPoolConfigs(force_refresh = false, transform_extensions = true): Promise<LaunchpadPoolConfig[]> {
|
|
289
|
+
const { launchpad_pools_handle } = getPackagerConfigs(this.sdk.sdkOptions.cetus_config)
|
|
290
|
+
const cacheKey = `${launchpad_pools_handle}_getLaunchpadPoolConfigs`
|
|
291
|
+
const cacheData = this.getCache<LaunchpadPoolConfig[]>(cacheKey, force_refresh)
|
|
292
|
+
if (cacheData) {
|
|
293
|
+
return cacheData
|
|
294
|
+
}
|
|
295
|
+
const res = await this._sdk.FullClient.getDynamicFieldsByPage(launchpad_pools_handle)
|
|
296
|
+
const warpIds = res.data.map((item: any) => {
|
|
297
|
+
return item.objectId
|
|
298
|
+
})
|
|
299
|
+
const objects = await this._sdk.FullClient.batchGetObjects(warpIds, { showContent: true })
|
|
300
|
+
const poolList: LaunchpadPoolConfig[] = []
|
|
301
|
+
objects.forEach((object) => {
|
|
302
|
+
if (object.error != null || object.data?.content?.dataType !== 'moveObject') {
|
|
303
|
+
handleMessageError(
|
|
304
|
+
PoolErrorCode.FetchError,
|
|
305
|
+
`when getCoinConfigs get objects error: ${object.error}, please check the rpc and contracts address config.`,
|
|
306
|
+
{
|
|
307
|
+
[DETAILS_KEYS.METHOD_NAME]: 'getLaunchpadPoolConfigs',
|
|
308
|
+
}
|
|
309
|
+
)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const pool = this.buildLaunchpadPoolConfig(object, transform_extensions)
|
|
313
|
+
this.updateCache(`${pool.pool_address}_getLaunchpadPoolConfig`, pool, CACHE_TIME_24H)
|
|
314
|
+
poolList.push({ ...pool })
|
|
315
|
+
})
|
|
316
|
+
this.updateCache(cacheKey, poolList, CACHE_TIME_24H)
|
|
317
|
+
return poolList
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
async getLaunchpadPoolConfig(pool_id: string, force_refresh = false, transform_extensions = true): Promise<LaunchpadPoolConfig> {
|
|
321
|
+
const { launchpad_pools_handle } = getPackagerConfigs(this.sdk.sdkOptions.cetus_config)
|
|
322
|
+
const cacheKey = `${pool_id}_getLaunchpadPoolConfig`
|
|
323
|
+
const cacheData = this.getCache<LaunchpadPoolConfig>(cacheKey, force_refresh)
|
|
324
|
+
if (cacheData) {
|
|
325
|
+
return cacheData
|
|
326
|
+
}
|
|
327
|
+
const object = await this._sdk.FullClient.getDynamicFieldObject({
|
|
328
|
+
parentId: launchpad_pools_handle,
|
|
329
|
+
name: {
|
|
330
|
+
type: 'address',
|
|
331
|
+
value: pool_id,
|
|
332
|
+
},
|
|
333
|
+
})
|
|
334
|
+
const pool = this.buildLaunchpadPoolConfig(object, transform_extensions)
|
|
335
|
+
this.updateCache(cacheKey, pool, CACHE_TIME_24H)
|
|
336
|
+
return pool
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
private buildLaunchpadPoolConfig(object: SuiObjectResponse, transform_extensions = true) {
|
|
340
|
+
let fields = getObjectFields(object)
|
|
341
|
+
fields = fields.value.fields
|
|
342
|
+
const pool: any = { ...fields }
|
|
343
|
+
|
|
344
|
+
pool.id = getObjectId(object)
|
|
345
|
+
pool.pool_address = normalizeSuiObjectId(fields.pool_address)
|
|
346
|
+
|
|
347
|
+
this.transformExtensions(pool, fields.extension_fields.fields.contents, transform_extensions)
|
|
348
|
+
const social_medias: {
|
|
349
|
+
name: string
|
|
350
|
+
link: string
|
|
351
|
+
}[] = []
|
|
352
|
+
fields.social_media.fields.contents.forEach((item: any) => {
|
|
353
|
+
social_medias.push({
|
|
354
|
+
name: item.fields.value.fields.name,
|
|
355
|
+
link: item.fields.value.fields.link,
|
|
356
|
+
})
|
|
357
|
+
})
|
|
358
|
+
pool.social_media = social_medias
|
|
359
|
+
try {
|
|
360
|
+
pool.regulation = decodeURIComponent(Base64.decode(pool.regulation).replace(/%/g, '%25'))
|
|
361
|
+
} catch (error) {
|
|
362
|
+
pool.regulation = Base64.decode(pool.regulation)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return pool
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
private transformExtensions(coin: any, data_array: any[], transform_extensions = true) {
|
|
369
|
+
const extensions: any[] = []
|
|
370
|
+
for (const item of data_array) {
|
|
371
|
+
const { key } = item.fields
|
|
372
|
+
let { value } = item.fields
|
|
373
|
+
if (key === 'labels') {
|
|
374
|
+
try {
|
|
375
|
+
const decodedValue = decodeURIComponent(Base64.decode(value))
|
|
376
|
+
try {
|
|
377
|
+
value = JSON.parse(decodedValue)
|
|
378
|
+
} catch {
|
|
379
|
+
value = decodedValue
|
|
380
|
+
}
|
|
381
|
+
} catch (error) {}
|
|
382
|
+
}
|
|
383
|
+
if (transform_extensions) {
|
|
384
|
+
coin[key] = value
|
|
385
|
+
}
|
|
386
|
+
extensions.push({
|
|
387
|
+
key,
|
|
388
|
+
value,
|
|
389
|
+
})
|
|
390
|
+
}
|
|
391
|
+
delete coin.extension_fields
|
|
392
|
+
|
|
393
|
+
if (!transform_extensions) {
|
|
394
|
+
coin.extensions = extensions
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Get the token config event.
|
|
400
|
+
*
|
|
401
|
+
* @param force_refresh Whether to force a refresh of the event.
|
|
402
|
+
* @returns The token config event.
|
|
403
|
+
*/
|
|
404
|
+
async getCetusConfig(force_refresh = false): Promise<CetusConfigs> {
|
|
405
|
+
const packageObjectId = this._sdk.sdkOptions.cetus_config.package_id
|
|
406
|
+
const cacheKey = `${packageObjectId}_getCetusConfig`
|
|
407
|
+
|
|
408
|
+
const cacheData = this.getCache<CetusConfigs>(cacheKey, force_refresh)
|
|
409
|
+
|
|
410
|
+
if (cacheData !== undefined) {
|
|
411
|
+
return cacheData
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const packageObject = await this._sdk.FullClient.getObject({
|
|
415
|
+
id: packageObjectId,
|
|
416
|
+
options: {
|
|
417
|
+
showPreviousTransaction: true,
|
|
418
|
+
},
|
|
419
|
+
})
|
|
420
|
+
|
|
421
|
+
const previousTx = getObjectPreviousTransactionDigest(packageObject) as string
|
|
422
|
+
const objects = await this._sdk.FullClient.queryEventsByPage({ Transaction: previousTx })
|
|
423
|
+
let tokenConfig: CetusConfigs = {
|
|
424
|
+
coin_list_id: '',
|
|
425
|
+
launchpad_pools_id: '',
|
|
426
|
+
clmm_pools_id: '',
|
|
427
|
+
admin_cap_id: '',
|
|
428
|
+
global_config_id: '',
|
|
429
|
+
coin_list_handle: '',
|
|
430
|
+
launchpad_pools_handle: '',
|
|
431
|
+
clmm_pools_handle: '',
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if (objects.data.length > 0) {
|
|
435
|
+
for (const item of objects.data) {
|
|
436
|
+
const formatType = extractStructTagFromType(item.type)
|
|
437
|
+
switch (formatType.name) {
|
|
438
|
+
case `InitCoinListEvent`:
|
|
439
|
+
tokenConfig.coin_list_id = item.parsedJson.coin_list_id
|
|
440
|
+
break
|
|
441
|
+
case `InitLaunchpadPoolsEvent`:
|
|
442
|
+
tokenConfig.launchpad_pools_id = item.parsedJson.launchpad_pools_id
|
|
443
|
+
break
|
|
444
|
+
case `InitClmmPoolsEvent`:
|
|
445
|
+
tokenConfig.clmm_pools_id = item.parsedJson.pools_id
|
|
446
|
+
break
|
|
447
|
+
case `InitConfigEvent`:
|
|
448
|
+
tokenConfig.global_config_id = item.parsedJson.global_config_id
|
|
449
|
+
tokenConfig.admin_cap_id = item.parsedJson.admin_cap_id
|
|
450
|
+
break
|
|
451
|
+
default:
|
|
452
|
+
break
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
tokenConfig = await this.getCetusConfigHandle(tokenConfig)
|
|
457
|
+
if (tokenConfig.clmm_pools_id.length > 0) {
|
|
458
|
+
this.updateCache(cacheKey, tokenConfig, CACHE_TIME_24H)
|
|
459
|
+
}
|
|
460
|
+
return tokenConfig
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
private async getCetusConfigHandle(token_config: CetusConfigs): Promise<CetusConfigs> {
|
|
464
|
+
const warpIds = [token_config.clmm_pools_id, token_config.coin_list_id, token_config.launchpad_pools_id]
|
|
465
|
+
|
|
466
|
+
const res = await this._sdk.FullClient.multiGetObjects({ ids: warpIds, options: { showContent: true } })
|
|
467
|
+
|
|
468
|
+
res.forEach((item) => {
|
|
469
|
+
if (item.error != null || item.data?.content?.dataType !== 'moveObject') {
|
|
470
|
+
handleMessageError(
|
|
471
|
+
ConfigErrorCode.InvalidConfigHandle,
|
|
472
|
+
`when getCetusConfigHandle get objects error: ${item.error}, please check the rpc and contracts address config.`,
|
|
473
|
+
{
|
|
474
|
+
[DETAILS_KEYS.METHOD_NAME]: 'getCetusConfigHandle',
|
|
475
|
+
}
|
|
476
|
+
)
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const fields = getObjectFields(item)
|
|
480
|
+
const type = getObjectType(item) as string
|
|
481
|
+
switch (extractStructTagFromType(type).name) {
|
|
482
|
+
case 'ClmmPools':
|
|
483
|
+
token_config.clmm_pools_handle = fields.pools.fields.id.id
|
|
484
|
+
break
|
|
485
|
+
case 'CoinList':
|
|
486
|
+
token_config.coin_list_handle = fields.coins.fields.id.id
|
|
487
|
+
break
|
|
488
|
+
case 'LaunchpadPools':
|
|
489
|
+
token_config.launchpad_pools_handle = fields.pools.fields.id.id
|
|
490
|
+
break
|
|
491
|
+
default:
|
|
492
|
+
break
|
|
493
|
+
}
|
|
494
|
+
})
|
|
495
|
+
|
|
496
|
+
return token_config
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Updates the cache for the given key.
|
|
501
|
+
* @param key The key of the cache entry to update.
|
|
502
|
+
* @param data The data to store in the cache.
|
|
503
|
+
* @param time The time in minutes after which the cache entry should expire.
|
|
504
|
+
*/
|
|
505
|
+
updateCache(key: string, data: SuiResource, time = CACHE_TIME_5MIN) {
|
|
506
|
+
let cacheData = this._cache[key]
|
|
507
|
+
if (cacheData) {
|
|
508
|
+
cacheData.overdue_time = getFutureTime(time)
|
|
509
|
+
cacheData.value = data
|
|
510
|
+
} else {
|
|
511
|
+
cacheData = new CachedContent(data, getFutureTime(time))
|
|
512
|
+
}
|
|
513
|
+
this._cache[key] = cacheData
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Gets the cache entry for the given key.
|
|
518
|
+
* @param key The key of the cache entry to get.
|
|
519
|
+
* @param force_refresh Whether to force a refresh of the cache entry.
|
|
520
|
+
* @returns The cache entry for the given key, or undefined if the cache entry does not exist or is expired.
|
|
521
|
+
*/
|
|
522
|
+
getCache<T>(key: string, force_refresh = false): T | undefined {
|
|
523
|
+
try {
|
|
524
|
+
const cacheData = this._cache[key]
|
|
525
|
+
if (!cacheData) {
|
|
526
|
+
return undefined // No cache data available
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (force_refresh || !cacheData.isValid()) {
|
|
530
|
+
delete this._cache[key]
|
|
531
|
+
return undefined
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
return cacheData.value as T
|
|
535
|
+
} catch (error) {
|
|
536
|
+
console.error(`Error accessing cache for key ${key}:`, error)
|
|
537
|
+
return undefined
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|