@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.
- package/.turbo/turbo-build.log +10423 -0
- package/README.md +646 -0
- package/dist/index.d.mts +1015 -0
- package/dist/index.d.ts +1015 -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/package.json +35 -0
- package/src/config/index.ts +2 -0
- package/src/config/mainnet.ts +25 -0
- package/src/config/testnet.ts +30 -0
- package/src/errors/errors.ts +40 -0
- package/src/index.ts +8 -0
- package/src/modules/configModule.ts +184 -0
- package/src/modules/index.ts +1 -0
- package/src/modules/partnerModule.ts +302 -0
- package/src/modules/poolModule.ts +578 -0
- package/src/modules/positionModule.ts +888 -0
- package/src/modules/rewardModule.ts +175 -0
- package/src/modules/swapModule.ts +129 -0
- package/src/sdk.ts +88 -0
- package/src/types/constants.ts +23 -0
- package/src/types/dlmm.ts +445 -0
- package/src/types/index.ts +2 -0
- package/src/utils/binUtils.ts +552 -0
- package/src/utils/feeUtils.ts +92 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/parseData.ts +519 -0
- package/src/utils/strategyUtils.ts +121 -0
- package/src/utils/weightUtils.ts +510 -0
- package/tests/add_liquidity_bidask.test.ts +180 -0
- package/tests/add_liquidity_curve.test.ts +244 -0
- package/tests/add_liquidity_spot.test.ts +262 -0
- package/tests/bin.test.ts +80 -0
- package/tests/config.test.ts +51 -0
- package/tests/partner.test.ts +74 -0
- package/tests/pool.test.ts +174 -0
- package/tests/position.test.ts +76 -0
- package/tests/remove_liquidity.test.ts +137 -0
- package/tests/swap.test.ts +96 -0
- package/tests/tsconfig.json +26 -0
- package/tsconfig.json +5 -0
- package/tsup.config.ts +9 -0
|
@@ -0,0 +1,578 @@
|
|
|
1
|
+
import { Transaction, TransactionObjectArgument } from '@mysten/sui/transactions'
|
|
2
|
+
import {
|
|
3
|
+
asUintN,
|
|
4
|
+
CLOCK_ADDRESS,
|
|
5
|
+
CoinAssist,
|
|
6
|
+
createFullClient,
|
|
7
|
+
d,
|
|
8
|
+
DataPage,
|
|
9
|
+
DETAILS_KEYS,
|
|
10
|
+
fixCoinType,
|
|
11
|
+
getObjectFields,
|
|
12
|
+
getPackagerConfigs,
|
|
13
|
+
IModule,
|
|
14
|
+
isSortedSymbols,
|
|
15
|
+
PageQuery,
|
|
16
|
+
PaginationArgs,
|
|
17
|
+
} from '@cetusprotocol/common-sdk'
|
|
18
|
+
import { DlmmErrorCode, handleError } from '../errors/errors'
|
|
19
|
+
import { BinUtils, parseBinInfo, parseBinInfoList, parseDlmmBasePool, parseDlmmPool, parsePoolTransactionInfo } from '../utils'
|
|
20
|
+
import { CetusDlmmSDK } from '../sdk'
|
|
21
|
+
import {
|
|
22
|
+
BinAmount,
|
|
23
|
+
BinLiquidityInfo,
|
|
24
|
+
CalculateAddLiquidityOption,
|
|
25
|
+
CreatePoolAndAddOption,
|
|
26
|
+
CreatePoolAndAddWithPriceOption,
|
|
27
|
+
CreatePoolOption,
|
|
28
|
+
DlmmBasePool,
|
|
29
|
+
DlmmConfigs,
|
|
30
|
+
DlmmPool,
|
|
31
|
+
FeeRate,
|
|
32
|
+
GetPoolBinInfoOption,
|
|
33
|
+
GetTotalFeeRateOption,
|
|
34
|
+
OpenAndAddLiquidityOption,
|
|
35
|
+
PoolTransactionInfo,
|
|
36
|
+
} from '../types/dlmm'
|
|
37
|
+
import { MAX_BIN_PER_POSITION } from '../types/constants'
|
|
38
|
+
import { SuiClient } from '@mysten/sui/client'
|
|
39
|
+
import { normalizeSuiAddress } from '@mysten/sui/utils'
|
|
40
|
+
import { bcs } from '@mysten/sui/bcs'
|
|
41
|
+
|
|
42
|
+
export class PoolModule implements IModule<CetusDlmmSDK> {
|
|
43
|
+
protected _sdk: CetusDlmmSDK
|
|
44
|
+
|
|
45
|
+
constructor(sdk: CetusDlmmSDK) {
|
|
46
|
+
this._sdk = sdk
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get sdk() {
|
|
50
|
+
return this._sdk
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Get the list of DLMM base pools
|
|
55
|
+
* @param pagination_args - The pagination arguments
|
|
56
|
+
* @returns The list of DLMM base pools
|
|
57
|
+
*/
|
|
58
|
+
async getBasePoolList(pagination_args: PaginationArgs = 'all', force_refresh = false): Promise<DataPage<DlmmBasePool>> {
|
|
59
|
+
const { dlmm_pool } = this._sdk.sdkOptions
|
|
60
|
+
const dataPage: DataPage<DlmmBasePool> = {
|
|
61
|
+
data: [],
|
|
62
|
+
has_next_page: false,
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const queryAll = pagination_args === 'all'
|
|
66
|
+
const cacheAllKey = `${dlmm_pool.package_id}_getBasePoolList`
|
|
67
|
+
if (queryAll) {
|
|
68
|
+
const cacheDate = this._sdk.getCache<DlmmBasePool[]>(cacheAllKey, force_refresh)
|
|
69
|
+
if (cacheDate && cacheDate.length > 0) {
|
|
70
|
+
dataPage.data.push(...cacheDate)
|
|
71
|
+
return dataPage
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const moveEventType = `${dlmm_pool.package_id}::registry::CreatePoolEvent`
|
|
77
|
+
const res = await this._sdk.FullClient.queryEventsByPage({ MoveEventType: moveEventType }, pagination_args)
|
|
78
|
+
dataPage.has_next_page = res.has_next_page
|
|
79
|
+
dataPage.next_cursor = res.next_cursor
|
|
80
|
+
res.data.forEach((object) => {
|
|
81
|
+
const pool = parseDlmmBasePool(object)
|
|
82
|
+
dataPage.data.push(pool)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
if (queryAll) {
|
|
86
|
+
this._sdk.updateCache(`${dlmm_pool.package_id}_getPoolImmutables`, dataPage.data)
|
|
87
|
+
}
|
|
88
|
+
} catch (error) {
|
|
89
|
+
return handleError(DlmmErrorCode.FetchError, error as Error, {
|
|
90
|
+
[DETAILS_KEYS.METHOD_NAME]: 'getBasePoolList',
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return dataPage
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Get the list of DLMM pools
|
|
99
|
+
* @param pagination_args - The pagination arguments
|
|
100
|
+
* @returns The list of DLMM pools
|
|
101
|
+
*/
|
|
102
|
+
async getPools(pagination_args: PaginationArgs = 'all', force_refresh = false): Promise<DataPage<DlmmPool>> {
|
|
103
|
+
const dataPage: DataPage<DlmmPool> = {
|
|
104
|
+
data: [],
|
|
105
|
+
has_next_page: false,
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const basePoolPage = await this.getBasePoolList(pagination_args, force_refresh)
|
|
109
|
+
if (basePoolPage.data.length === 0) {
|
|
110
|
+
return dataPage
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
const res = await this._sdk.FullClient.batchGetObjects(
|
|
115
|
+
basePoolPage.data.map((item) => item.id),
|
|
116
|
+
{
|
|
117
|
+
showContent: true,
|
|
118
|
+
showType: true,
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
dataPage.has_next_page = basePoolPage.has_next_page
|
|
122
|
+
dataPage.next_cursor = basePoolPage.next_cursor
|
|
123
|
+
for (const suiObj of res) {
|
|
124
|
+
const pool = parseDlmmPool(suiObj)
|
|
125
|
+
const cacheKey = `${pool.id}_getDlmmPool`
|
|
126
|
+
this._sdk.updateCache(cacheKey, pool)
|
|
127
|
+
dataPage.data.push(pool)
|
|
128
|
+
}
|
|
129
|
+
} catch (error) {
|
|
130
|
+
return handleError(DlmmErrorCode.FetchError, error as Error, {
|
|
131
|
+
[DETAILS_KEYS.METHOD_NAME]: 'getPools',
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return dataPage
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Get the bin info by bin id
|
|
140
|
+
* @param bin_manager_handle - The bin manager handle
|
|
141
|
+
* @param bin_id - The bin id
|
|
142
|
+
* @param bin_step - The bin step
|
|
143
|
+
* @param force_refresh - Whether to force a refresh of the cache
|
|
144
|
+
* @returns The bin info
|
|
145
|
+
*/
|
|
146
|
+
async getBinInfo(bin_manager_handle: string, bin_id: number, bin_step: number, force_refresh = true): Promise<BinAmount> {
|
|
147
|
+
try {
|
|
148
|
+
const cacheKey = `${bin_manager_handle}_getBinInfo_${bin_id}`
|
|
149
|
+
const cacheData = this._sdk.getCache<BinAmount>(cacheKey, force_refresh)
|
|
150
|
+
if (cacheData !== undefined) {
|
|
151
|
+
return cacheData
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const score = BinUtils.binScore(bin_id)
|
|
155
|
+
const [groupIndex, offsetInGroup] = BinUtils.resolveBinPosition(score)
|
|
156
|
+
|
|
157
|
+
const res: any = await this._sdk.FullClient.getDynamicFieldObject({
|
|
158
|
+
parentId: bin_manager_handle,
|
|
159
|
+
name: { type: 'u64', value: groupIndex },
|
|
160
|
+
})
|
|
161
|
+
const fields = res.data.content.fields.value.fields.value.fields.group.fields.bins[offsetInGroup].fields
|
|
162
|
+
const bin_info = parseBinInfo(fields)
|
|
163
|
+
this._sdk.updateCache(cacheKey, bin_info)
|
|
164
|
+
return bin_info
|
|
165
|
+
} catch (error) {
|
|
166
|
+
return {
|
|
167
|
+
bin_id,
|
|
168
|
+
amount_a: '0',
|
|
169
|
+
amount_b: '0',
|
|
170
|
+
liquidity: '0',
|
|
171
|
+
price_per_lamport: BinUtils.getPricePerLamportFromBinId(bin_id, bin_step),
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async getTotalFeeRate(option: GetTotalFeeRateOption): Promise<FeeRate> {
|
|
177
|
+
const { dlmm_pool } = this._sdk.sdkOptions
|
|
178
|
+
const { pool_id, coin_type_a, coin_type_b } = option
|
|
179
|
+
const tx: Transaction = new Transaction()
|
|
180
|
+
tx.moveCall({
|
|
181
|
+
target: `${dlmm_pool.published_at}::pool::get_total_fee_rate`,
|
|
182
|
+
arguments: [tx.object(pool_id)],
|
|
183
|
+
typeArguments: [coin_type_a, coin_type_b],
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
const res = await this._sdk.FullClient.devInspectTransactionBlock({
|
|
187
|
+
transactionBlock: tx,
|
|
188
|
+
sender: normalizeSuiAddress('0x0'),
|
|
189
|
+
})
|
|
190
|
+
const bcsFeeRate = bcs.struct('FeeRate', {
|
|
191
|
+
base_fee_rate: bcs.u64(),
|
|
192
|
+
var_fee_rate: bcs.u64(),
|
|
193
|
+
total_fee_rate: bcs.u64(),
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
const feeRate = bcsFeeRate.parse(Uint8Array.from(res.results![0].returnValues![0][0]))
|
|
197
|
+
|
|
198
|
+
return feeRate
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async getPoolBinInfo(option: GetPoolBinInfoOption): Promise<BinAmount[]> {
|
|
202
|
+
const { dlmm_pool } = this._sdk.sdkOptions
|
|
203
|
+
const { pool_id, coin_type_a, coin_type_b } = option
|
|
204
|
+
const limit = 1000
|
|
205
|
+
const bin_infos: BinAmount[] = []
|
|
206
|
+
let start_bin_id: number | undefined = undefined
|
|
207
|
+
let hasNext = true
|
|
208
|
+
|
|
209
|
+
while (hasNext) {
|
|
210
|
+
const tx: Transaction = new Transaction()
|
|
211
|
+
tx.moveCall({
|
|
212
|
+
target: `${dlmm_pool.published_at}::pool::fetch_bins`,
|
|
213
|
+
arguments: [
|
|
214
|
+
tx.object(pool_id),
|
|
215
|
+
tx.pure.vector('u32', start_bin_id ? [Number(asUintN(BigInt(start_bin_id)))] : []),
|
|
216
|
+
tx.pure.u64(limit),
|
|
217
|
+
],
|
|
218
|
+
typeArguments: [coin_type_a, coin_type_b],
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
const res = await this._sdk.FullClient.devInspectTransactionBlock({
|
|
222
|
+
transactionBlock: tx,
|
|
223
|
+
sender: normalizeSuiAddress('0x0'),
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
const list = parseBinInfoList(res)
|
|
227
|
+
bin_infos.push(...list)
|
|
228
|
+
start_bin_id = list.length > 0 ? list[list.length - 1].bin_id : undefined
|
|
229
|
+
hasNext = list.length === limit
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return bin_infos.sort((a, b) => a.bin_id - b.bin_id)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async getPoolTransactionList({
|
|
236
|
+
pool_id,
|
|
237
|
+
pagination_args,
|
|
238
|
+
order = 'descending',
|
|
239
|
+
full_rpc_url,
|
|
240
|
+
}: {
|
|
241
|
+
pool_id: string
|
|
242
|
+
full_rpc_url?: string
|
|
243
|
+
pagination_args: PageQuery
|
|
244
|
+
order?: 'ascending' | 'descending' | null | undefined
|
|
245
|
+
}): Promise<DataPage<PoolTransactionInfo>> {
|
|
246
|
+
const { FullClient: fullClient, sdkOptions } = this._sdk
|
|
247
|
+
let client
|
|
248
|
+
if (full_rpc_url) {
|
|
249
|
+
client = createFullClient(new SuiClient({ url: full_rpc_url }))
|
|
250
|
+
} else {
|
|
251
|
+
client = fullClient
|
|
252
|
+
}
|
|
253
|
+
const data: DataPage<PoolTransactionInfo> = {
|
|
254
|
+
data: [],
|
|
255
|
+
has_next_page: false,
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const limit = 50
|
|
259
|
+
const query = pagination_args
|
|
260
|
+
const user_limit = pagination_args.limit || 10
|
|
261
|
+
do {
|
|
262
|
+
const res = await client.queryTransactionBlocksByPage({ ChangedObject: pool_id }, { ...query, limit: 50 }, order)
|
|
263
|
+
res.data.forEach((item, index) => {
|
|
264
|
+
const dataList = parsePoolTransactionInfo(item, index, sdkOptions.dlmm_pool.package_id, pool_id)
|
|
265
|
+
data.data = [...data.data, ...dataList]
|
|
266
|
+
})
|
|
267
|
+
data.has_next_page = res.has_next_page
|
|
268
|
+
data.next_cursor = res.next_cursor
|
|
269
|
+
query.cursor = res.next_cursor
|
|
270
|
+
} while (data.data.length < user_limit && data.has_next_page)
|
|
271
|
+
|
|
272
|
+
if (data.data.length > user_limit) {
|
|
273
|
+
data.data = data.data.slice(0, user_limit)
|
|
274
|
+
data.has_next_page = true
|
|
275
|
+
}
|
|
276
|
+
if (data.data.length > 0) {
|
|
277
|
+
data.next_cursor = data.data[data.data.length - 1].tx
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return data
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Get the bin info by range (TODO: need to optimize this method)
|
|
285
|
+
* @param bin_manager_handle - The bin manager handle
|
|
286
|
+
* @param lower_bin_id - The lower bin id
|
|
287
|
+
* @param upper_bin_id - The upper bin id
|
|
288
|
+
* @param bin_step - The bin step
|
|
289
|
+
* @returns The bin info by range
|
|
290
|
+
*/
|
|
291
|
+
async getRangeBinInfo(bin_manager_handle: string, lower_bin_id: number, upper_bin_id: number, bin_step: number): Promise<BinAmount[]> {
|
|
292
|
+
const bin_infos: BinAmount[] = []
|
|
293
|
+
for (let bin_id = lower_bin_id; bin_id <= upper_bin_id; bin_id++) {
|
|
294
|
+
const bin_info = await Promise.all([this.getBinInfo(bin_manager_handle, bin_id, bin_step)])
|
|
295
|
+
bin_infos.push(...bin_info)
|
|
296
|
+
}
|
|
297
|
+
return bin_infos
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Get the list of DLMM pools by assign pool ids
|
|
302
|
+
* @param assign_pool_ids - The assign pool ids
|
|
303
|
+
* @returns The list of DLMM pools
|
|
304
|
+
*/
|
|
305
|
+
async getAssignPoolList(assign_pool_ids: string[]): Promise<DlmmPool[]> {
|
|
306
|
+
if (assign_pool_ids.length === 0) {
|
|
307
|
+
return []
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const allPool: DlmmPool[] = []
|
|
311
|
+
|
|
312
|
+
try {
|
|
313
|
+
const res = await this._sdk.FullClient.batchGetObjects(assign_pool_ids, {
|
|
314
|
+
showContent: true,
|
|
315
|
+
showType: true,
|
|
316
|
+
})
|
|
317
|
+
for (const suiObj of res) {
|
|
318
|
+
const pool = parseDlmmPool(suiObj)
|
|
319
|
+
const cacheKey = `${pool.id}_getDlmmPool`
|
|
320
|
+
this._sdk.updateCache(cacheKey, pool)
|
|
321
|
+
allPool.push(pool)
|
|
322
|
+
}
|
|
323
|
+
} catch (error) {
|
|
324
|
+
return handleError(DlmmErrorCode.FetchError, error as Error, {
|
|
325
|
+
[DETAILS_KEYS.METHOD_NAME]: 'getAssignPoolList',
|
|
326
|
+
})
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return allPool
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Get a DLMM pool by its object ID.
|
|
334
|
+
* @param {string} pool_id The object ID of the pool to get.
|
|
335
|
+
* @param {true} force_refresh Whether to force a refresh of the cache.
|
|
336
|
+
* @returns {Promise<DlmmPool>} A promise that resolves to a DlmmPool object.
|
|
337
|
+
*/
|
|
338
|
+
async getPool(pool_id: string, force_refresh = true): Promise<DlmmPool> {
|
|
339
|
+
try {
|
|
340
|
+
const cacheKey = `${pool_id}_getDlmmPool`
|
|
341
|
+
const cacheData = this._sdk.getCache<DlmmPool>(cacheKey, force_refresh)
|
|
342
|
+
if (cacheData !== undefined) {
|
|
343
|
+
return cacheData
|
|
344
|
+
}
|
|
345
|
+
const suiObj = await this._sdk.FullClient.getObject({
|
|
346
|
+
id: pool_id,
|
|
347
|
+
options: {
|
|
348
|
+
showType: true,
|
|
349
|
+
showContent: true,
|
|
350
|
+
},
|
|
351
|
+
})
|
|
352
|
+
const pool = parseDlmmPool(suiObj)
|
|
353
|
+
this._sdk.updateCache(cacheKey, pool)
|
|
354
|
+
return pool
|
|
355
|
+
} catch (error) {
|
|
356
|
+
return handleError(DlmmErrorCode.FetchError, error as Error, {
|
|
357
|
+
[DETAILS_KEYS.METHOD_NAME]: 'getPool',
|
|
358
|
+
[DETAILS_KEYS.REQUEST_PARAMS]: pool_id,
|
|
359
|
+
})
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Create a pool and add liquidity with a given price
|
|
365
|
+
* @param option - The option for creating a pool and adding liquidity with a given price
|
|
366
|
+
* @returns The transaction for creating a pool and adding liquidity with a given price
|
|
367
|
+
*/
|
|
368
|
+
async createPoolAndAddWithPricePayload(option: CreatePoolAndAddWithPriceOption): Promise<Transaction> {
|
|
369
|
+
const {
|
|
370
|
+
bin_step,
|
|
371
|
+
url,
|
|
372
|
+
coin_type_a,
|
|
373
|
+
coin_type_b,
|
|
374
|
+
bin_infos,
|
|
375
|
+
price_base_coin,
|
|
376
|
+
price,
|
|
377
|
+
lower_price,
|
|
378
|
+
upper_price,
|
|
379
|
+
decimals_a,
|
|
380
|
+
decimals_b,
|
|
381
|
+
strategy_type,
|
|
382
|
+
use_bin_infos,
|
|
383
|
+
base_factor,
|
|
384
|
+
} = option
|
|
385
|
+
|
|
386
|
+
let lower_bin_id
|
|
387
|
+
let upper_bin_id
|
|
388
|
+
let active_id
|
|
389
|
+
let new_bin_infos: BinLiquidityInfo = bin_infos
|
|
390
|
+
|
|
391
|
+
const is_coin_a_base = price_base_coin === 'coin_a'
|
|
392
|
+
|
|
393
|
+
if (is_coin_a_base) {
|
|
394
|
+
lower_bin_id = BinUtils.getBinIdFromPrice(lower_price, bin_step, false, decimals_a, decimals_b)
|
|
395
|
+
upper_bin_id = BinUtils.getBinIdFromPrice(upper_price, bin_step, true, decimals_a, decimals_b)
|
|
396
|
+
active_id = BinUtils.getBinIdFromPrice(price, bin_step, true, decimals_a, decimals_b)
|
|
397
|
+
} else {
|
|
398
|
+
lower_bin_id = BinUtils.getBinIdFromPrice(d(1).div(upper_price).toString(), bin_step, false, decimals_a, decimals_b)
|
|
399
|
+
upper_bin_id = BinUtils.getBinIdFromPrice(d(1).div(lower_price).toString(), bin_step, true, decimals_a, decimals_b)
|
|
400
|
+
active_id = BinUtils.getBinIdFromPrice(d(1).div(price).toString(), bin_step, false, decimals_a, decimals_b)
|
|
401
|
+
|
|
402
|
+
const calculateOption: CalculateAddLiquidityOption = {
|
|
403
|
+
amount_a: bin_infos.amount_b,
|
|
404
|
+
amount_b: bin_infos.amount_a,
|
|
405
|
+
active_id,
|
|
406
|
+
bin_step,
|
|
407
|
+
lower_bin_id,
|
|
408
|
+
upper_bin_id,
|
|
409
|
+
amount_a_in_active_bin: '0',
|
|
410
|
+
amount_b_in_active_bin: '0',
|
|
411
|
+
strategy_type: option.strategy_type,
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
new_bin_infos = this.sdk.Position.calculateAddLiquidityInfo(calculateOption)
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const createPoolAndAddOption: CreatePoolAndAddOption = {
|
|
418
|
+
bin_step,
|
|
419
|
+
url,
|
|
420
|
+
coin_type_a,
|
|
421
|
+
coin_type_b,
|
|
422
|
+
bin_infos: new_bin_infos,
|
|
423
|
+
lower_bin_id,
|
|
424
|
+
upper_bin_id,
|
|
425
|
+
active_id,
|
|
426
|
+
strategy_type,
|
|
427
|
+
use_bin_infos,
|
|
428
|
+
base_factor,
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
return this.createPoolAndAddLiquidityPayload(createPoolAndAddOption)
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Create a pool
|
|
436
|
+
* @param option - The option for creating a pool
|
|
437
|
+
* @param tx - The transaction object
|
|
438
|
+
* @returns The transaction object
|
|
439
|
+
*/
|
|
440
|
+
async createPoolPayload(option: CreatePoolOption, tx: Transaction): Promise<TransactionObjectArgument> {
|
|
441
|
+
const { dlmm_pool } = this._sdk.sdkOptions
|
|
442
|
+
const { bin_step, base_factor, url, coin_type_a, coin_type_b, active_id } = option
|
|
443
|
+
tx = tx || new Transaction()
|
|
444
|
+
|
|
445
|
+
const { registry_id, global_config_id, versioned_id } = getPackagerConfigs(dlmm_pool)
|
|
446
|
+
|
|
447
|
+
const coin_a_metadata = await this._sdk.FullClient.fetchCoinMetadata(coin_type_a)
|
|
448
|
+
if (!coin_a_metadata?.id) {
|
|
449
|
+
handleError(DlmmErrorCode.FetchError, new Error(`coin_a_metadata not found: ${coin_type_a}`), {
|
|
450
|
+
[DETAILS_KEYS.METHOD_NAME]: 'createPoolAndAddLiquidityPayload',
|
|
451
|
+
[DETAILS_KEYS.REQUEST_PARAMS]: option,
|
|
452
|
+
})
|
|
453
|
+
}
|
|
454
|
+
const coin_b_metadata = await this._sdk.FullClient.fetchCoinMetadata(coin_type_b)
|
|
455
|
+
if (!coin_b_metadata?.id) {
|
|
456
|
+
handleError(DlmmErrorCode.FetchError, new Error(`coin_b_metadata not found: ${coin_type_b}`), {
|
|
457
|
+
[DETAILS_KEYS.METHOD_NAME]: 'createPoolAndAddLiquidityPayload',
|
|
458
|
+
[DETAILS_KEYS.REQUEST_PARAMS]: option,
|
|
459
|
+
})
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const [cert, pool_id] = tx.moveCall({
|
|
463
|
+
target: `${dlmm_pool.published_at}::registry::create_pool`,
|
|
464
|
+
arguments: [
|
|
465
|
+
tx.object(registry_id),
|
|
466
|
+
tx.object(coin_a_metadata!.id!),
|
|
467
|
+
tx.object(coin_b_metadata!.id!),
|
|
468
|
+
tx.pure.u16(bin_step),
|
|
469
|
+
tx.pure.u16(base_factor),
|
|
470
|
+
tx.pure.u32(Number(asUintN(BigInt(active_id)))),
|
|
471
|
+
tx.pure.string(url || ''),
|
|
472
|
+
tx.object(global_config_id),
|
|
473
|
+
tx.object(versioned_id),
|
|
474
|
+
tx.object(CLOCK_ADDRESS),
|
|
475
|
+
],
|
|
476
|
+
typeArguments: [coin_type_a, coin_type_b],
|
|
477
|
+
})
|
|
478
|
+
|
|
479
|
+
tx.moveCall({
|
|
480
|
+
target: `${dlmm_pool.published_at}::registry::destroy_receipt`,
|
|
481
|
+
arguments: [tx.object(cert), pool_id, tx.object(versioned_id)],
|
|
482
|
+
typeArguments: [coin_type_a, coin_type_b],
|
|
483
|
+
})
|
|
484
|
+
|
|
485
|
+
return pool_id
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Create a pool and add liquidity
|
|
490
|
+
* @param option - The option for creating a pool and adding liquidity
|
|
491
|
+
* @returns The transaction for creating a pool and adding liquidity
|
|
492
|
+
*/
|
|
493
|
+
async createPoolAndAddLiquidityPayload(option: CreatePoolAndAddOption): Promise<Transaction> {
|
|
494
|
+
const { dlmm_pool } = this._sdk.sdkOptions
|
|
495
|
+
const {
|
|
496
|
+
bin_step,
|
|
497
|
+
base_factor,
|
|
498
|
+
url,
|
|
499
|
+
active_id,
|
|
500
|
+
coin_type_a,
|
|
501
|
+
coin_type_b,
|
|
502
|
+
bin_infos,
|
|
503
|
+
lower_bin_id,
|
|
504
|
+
upper_bin_id,
|
|
505
|
+
strategy_type,
|
|
506
|
+
use_bin_infos,
|
|
507
|
+
} = option
|
|
508
|
+
|
|
509
|
+
const { registry_id, global_config_id, versioned_id } = getPackagerConfigs(dlmm_pool)
|
|
510
|
+
|
|
511
|
+
const tx = new Transaction()
|
|
512
|
+
|
|
513
|
+
if (isSortedSymbols(fixCoinType(coin_type_a, false), fixCoinType(coin_type_b, false))) {
|
|
514
|
+
handleError(DlmmErrorCode.InvalidCoinTypeSequence, new Error('invalid coin type sequence'), {
|
|
515
|
+
[DETAILS_KEYS.METHOD_NAME]: 'createPoolAndAddLiquidityPayload',
|
|
516
|
+
[DETAILS_KEYS.REQUEST_PARAMS]: option,
|
|
517
|
+
})
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const width = upper_bin_id - lower_bin_id + 1
|
|
521
|
+
if (width > MAX_BIN_PER_POSITION) {
|
|
522
|
+
handleError(DlmmErrorCode.InvalidBinWidth, new Error('Width is too large'), {
|
|
523
|
+
[DETAILS_KEYS.METHOD_NAME]: 'openPosition',
|
|
524
|
+
[DETAILS_KEYS.REQUEST_PARAMS]: option,
|
|
525
|
+
})
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const coin_a_metadata = await this._sdk.FullClient.fetchCoinMetadata(coin_type_a)
|
|
529
|
+
if (!coin_a_metadata?.id) {
|
|
530
|
+
handleError(DlmmErrorCode.FetchError, new Error(`coin_a_metadata not found: ${coin_type_a}`), {
|
|
531
|
+
[DETAILS_KEYS.METHOD_NAME]: 'createPoolAndAddLiquidityPayload',
|
|
532
|
+
[DETAILS_KEYS.REQUEST_PARAMS]: option,
|
|
533
|
+
})
|
|
534
|
+
}
|
|
535
|
+
const coin_b_metadata = await this._sdk.FullClient.fetchCoinMetadata(coin_type_b)
|
|
536
|
+
if (!coin_b_metadata?.id) {
|
|
537
|
+
handleError(DlmmErrorCode.FetchError, new Error(`coin_b_metadata not found: ${coin_type_b}`), {
|
|
538
|
+
[DETAILS_KEYS.METHOD_NAME]: 'createPoolAndAddLiquidityPayload',
|
|
539
|
+
[DETAILS_KEYS.REQUEST_PARAMS]: option,
|
|
540
|
+
})
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
console.log('🚀 ~ createPoolAndAddLiquidityPayload ~ option:', {
|
|
544
|
+
...option,
|
|
545
|
+
width,
|
|
546
|
+
})
|
|
547
|
+
|
|
548
|
+
// create pool
|
|
549
|
+
const pool_id = await this.createPoolPayload(
|
|
550
|
+
{
|
|
551
|
+
active_id,
|
|
552
|
+
bin_step,
|
|
553
|
+
base_factor,
|
|
554
|
+
coin_type_a,
|
|
555
|
+
coin_type_b,
|
|
556
|
+
},
|
|
557
|
+
tx
|
|
558
|
+
)
|
|
559
|
+
|
|
560
|
+
// add liquidity
|
|
561
|
+
const addOption: OpenAndAddLiquidityOption = {
|
|
562
|
+
pool_id,
|
|
563
|
+
bin_infos,
|
|
564
|
+
coin_type_a,
|
|
565
|
+
coin_type_b,
|
|
566
|
+
lower_bin_id,
|
|
567
|
+
upper_bin_id,
|
|
568
|
+
active_id,
|
|
569
|
+
strategy_type,
|
|
570
|
+
use_bin_infos,
|
|
571
|
+
max_price_slippage: 0,
|
|
572
|
+
bin_step,
|
|
573
|
+
}
|
|
574
|
+
this.sdk.Position.addLiquidityPayload(addOption, tx)
|
|
575
|
+
|
|
576
|
+
return tx
|
|
577
|
+
}
|
|
578
|
+
}
|