@cetusprotocol/dlmm-sdk 0.0.2 → 0.0.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cetusprotocol/dlmm-sdk",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "SDK for cetus dlmm",
5
5
  "typings": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
@@ -26,10 +26,12 @@
26
26
  "license": "Apache-2.0",
27
27
  "devDependencies": {
28
28
  "@cetusprotocol/common-sdk": "workspace:*",
29
- "@cetusprotocol/test-utils": "workspace:*"
29
+ "@cetusprotocol/test-utils": "workspace:*",
30
+ "blakejs": "^1.2.1"
30
31
  },
31
32
  "peerDependencies": {
32
33
  "@cetusprotocol/common-sdk": "*",
33
- "@mysten/sui": "*"
34
+ "@mysten/sui": "*",
35
+ "blakejs": "*"
34
36
  }
35
37
  }
@@ -5,21 +5,21 @@ export const dlmmMainnet: SdkOptions = {
5
5
  env: 'mainnet',
6
6
  full_rpc_url: FullRpcUrlMainnet,
7
7
  dlmm_pool: {
8
- package_id: '0x8eb878ff59ecd9326697dc80f9df55ccfb050a711bb712981b1dc509f393cbdf',
9
- published_at: '0xa0f34a9aa8cd17e92c87bd93957c8daeba7fd45c2dbbba73f45ff47a93526c6b',
8
+ package_id: '0x5664f9d3fd82c84023870cfbda8ea84e14c8dd56ce557ad2116e0668581a682b',
9
+ published_at: '0x5664f9d3fd82c84023870cfbda8ea84e14c8dd56ce557ad2116e0668581a682b',
10
10
  version: 1,
11
11
  config: {
12
- registry_id: '0xd436e82a6ef89b0ad4a1b8bd19b0e8e1c662e4a358a8dfe8221b1833abf3685b',
13
- pools_id: '0x09bb9bde6875ba06551617aec1ea7a653cda0f526ae7ce42bdc6ef4a713a3f19',
14
- global_config_id: '0xbf90603a8a7488a1440ed88e1d4c8d7b1f0c4cfd827dbb1c70655acc90258cc2',
15
- versioned_id: '0x8bdb4c81a2d507dbbf4a5762e64a3c39cae1fd201b47aae474eff8b31e1f384a',
16
- admin_cap_id: '0xec28f827eb125c80f316a0356b84eb52b98c6157bd443095843b1a3788518655',
17
- partners_id: '0x19c6643ead4b13f4066db107a8606694cff3a2d81b7f11c759da460b5ea23491',
12
+ registry_id: '0xb1d55e7d895823c65f98d99b81a69436cf7d1638629c9ccb921326039cda1f1b',
13
+ pools_id: '0xc3683b2356cac6423e9ecaea20955c7cc193998b016e5b884730ed1192174991',
14
+ global_config_id: '0xf31b605d117f959b9730e8c07b08b856cb05143c5e81d5751c90d2979e82f599',
15
+ versioned_id: '0x05370b2d656612dd5759cbe80463de301e3b94a921dfc72dd9daa2ecdeb2d0a8',
16
+ admin_cap_id: '0xc4c42bc31cb54beb679dccd547f8bdb970cb6dc989bd1f85a4fed4812ed95d6e',
17
+ partners_id: '0x5c0affc8d363b6abb1f32790c229165215f4edead89a9bc7cd95dad717b4296a',
18
18
  },
19
19
  },
20
20
  dlmm_router: {
21
- package_id: '0xb269f062e8f7fd2bd653a79405dea7c48cb0bf62b11e33c939637d52b1560a65',
22
- published_at: '0xb269f062e8f7fd2bd653a79405dea7c48cb0bf62b11e33c939637d52b1560a65',
21
+ package_id: '0xc65d59c4aa7c9d53836bdbbb2a1418b02be6a351a767c64d6e4b7e96d26356d2',
22
+ published_at: '0xda28da84b5b1fef0ca053a2373e80ddb3a75f45e891e825fb06c2a53f838067d',
23
23
  version: 1,
24
24
  },
25
25
  }
@@ -6,7 +6,7 @@ export const dlmmTestnet: SdkOptions = {
6
6
  full_rpc_url: FullRpcUrlTestnet,
7
7
  dlmm_pool: {
8
8
  package_id: '0x17a1f5a8779461ff44e942adf33325cce112c693d6a177ed77f035ca86d1fdb6',
9
- published_at: '0x17a1f5a8779461ff44e942adf33325cce112c693d6a177ed77f035ca86d1fdb6',
9
+ published_at: '0x6d32c1be32eefcea933c03dd5cb7c783d1d83f6b30c4d1131d955933747b1701',
10
10
  version: 1,
11
11
  config: {
12
12
  registry_id: '0x319070e26a6809f439d3c4a45e63bf74939c5fe3165de7b65968ee8547f71bd0',
@@ -18,8 +18,8 @@ export const dlmmTestnet: SdkOptions = {
18
18
  },
19
19
  },
20
20
  dlmm_router: {
21
- package_id: '0x70777a78c17b550170924b4bf598fa6d883106521cc02eda798401a315b6751b',
22
- published_at: '0x70777a78c17b550170924b4bf598fa6d883106521cc02eda798401a315b6751b',
21
+ package_id: '0xba3059875c8980ac171fc2bac81b9df172fb77fa0cb5a267636df701225b93ef',
22
+ published_at: '0x59b7a2da6db8f9245a1db6169018af7124c0714fa77a84224967ead6be125127',
23
23
  version: 1,
24
24
  },
25
25
  faucet: {
@@ -14,9 +14,18 @@ import {
14
14
  isSortedSymbols,
15
15
  PageQuery,
16
16
  PaginationArgs,
17
+ printTransaction,
17
18
  } from '@cetusprotocol/common-sdk'
18
19
  import { DlmmErrorCode, handleError } from '../errors/errors'
19
- import { BinUtils, parseBinInfo, parseBinInfoList, parseDlmmBasePool, parseDlmmPool, parsePoolTransactionInfo } from '../utils'
20
+ import {
21
+ BinUtils,
22
+ buildPoolKey,
23
+ parseBinInfo,
24
+ parseBinInfoList,
25
+ parseDlmmBasePool,
26
+ parseDlmmPool,
27
+ parsePoolTransactionInfo,
28
+ } from '../utils'
20
29
  import { CetusDlmmSDK } from '../sdk'
21
30
  import {
22
31
  BinAmount,
@@ -50,6 +59,35 @@ export class PoolModule implements IModule<CetusDlmmSDK> {
50
59
  return this._sdk
51
60
  }
52
61
 
62
+ async getPoolAddress(coin_type_a: string, coin_type_b: string, bin_step: number, base_factor: number): Promise<string | undefined> {
63
+ try {
64
+ const poolKey = buildPoolKey(coin_type_a, coin_type_b, bin_step, base_factor)
65
+ const { dlmm_pool } = this._sdk.sdkOptions
66
+ const { pools_id } = getPackagerConfigs(dlmm_pool)
67
+ const res = await this._sdk.FullClient.getDynamicFieldObject({
68
+ parentId: pools_id,
69
+ name: {
70
+ type: '0x2::object::ID',
71
+ value: poolKey,
72
+ },
73
+ })
74
+ const fields = getObjectFields(res)
75
+ return fields.value.fields.value.fields.pool_id
76
+ } catch (error) {
77
+ return handleError(DlmmErrorCode.FetchError, error as Error, {
78
+ [DETAILS_KEYS.METHOD_NAME]: 'getPoolAddress',
79
+ [DETAILS_KEYS.REQUEST_PARAMS]: {
80
+ coin_type_a,
81
+ coin_type_b,
82
+ bin_step,
83
+ base_factor,
84
+ },
85
+ })
86
+ }
87
+
88
+ return undefined
89
+ }
90
+
53
91
  /**
54
92
  * Get the list of DLMM base pools
55
93
  * @param pagination_args - The pagination arguments
@@ -205,19 +243,27 @@ export class PoolModule implements IModule<CetusDlmmSDK> {
205
243
  const bin_infos: BinAmount[] = []
206
244
  let start_bin_id: number | undefined = undefined
207
245
  let hasNext = true
208
-
209
246
  while (hasNext) {
210
247
  const tx: Transaction = new Transaction()
248
+ let start_bin
249
+ if (start_bin_id !== undefined) {
250
+ start_bin = tx.moveCall({
251
+ target: `0x1::option::some`,
252
+ arguments: [tx.pure.u32(Number(asUintN(BigInt(start_bin_id))))],
253
+ typeArguments: ['u32'],
254
+ })
255
+ } else {
256
+ start_bin = tx.moveCall({
257
+ target: `0x1::option::none`,
258
+ typeArguments: ['u32'],
259
+ })
260
+ }
261
+
211
262
  tx.moveCall({
212
263
  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
- ],
264
+ arguments: [tx.object(pool_id), start_bin, tx.pure.u64(limit)],
218
265
  typeArguments: [coin_type_a, coin_type_b],
219
266
  })
220
-
221
267
  const res = await this._sdk.FullClient.devInspectTransactionBlock({
222
268
  transactionBlock: tx,
223
269
  sender: normalizeSuiAddress('0x0'),
@@ -225,7 +271,7 @@ export class PoolModule implements IModule<CetusDlmmSDK> {
225
271
 
226
272
  const list = parseBinInfoList(res)
227
273
  bin_infos.push(...list)
228
- start_bin_id = list.length > 0 ? list[list.length - 1].bin_id : undefined
274
+ start_bin_id = list.length > 0 ? list[list.length - 1].bin_id + 1 : undefined
229
275
  hasNext = list.length === limit
230
276
  }
231
277
 
@@ -381,6 +427,7 @@ export class PoolModule implements IModule<CetusDlmmSDK> {
381
427
  strategy_type,
382
428
  use_bin_infos,
383
429
  base_factor,
430
+ pool_id,
384
431
  } = option
385
432
 
386
433
  let lower_bin_id
@@ -400,18 +447,18 @@ export class PoolModule implements IModule<CetusDlmmSDK> {
400
447
  active_id = BinUtils.getBinIdFromPrice(d(1).div(price).toString(), bin_step, false, decimals_a, decimals_b)
401
448
 
402
449
  const calculateOption: CalculateAddLiquidityOption = {
450
+ pool_id,
403
451
  amount_a: bin_infos.amount_b,
404
452
  amount_b: bin_infos.amount_a,
405
453
  active_id,
406
454
  bin_step,
407
455
  lower_bin_id,
408
456
  upper_bin_id,
409
- amount_a_in_active_bin: '0',
410
- amount_b_in_active_bin: '0',
457
+ active_bin_of_pool: undefined,
411
458
  strategy_type: option.strategy_type,
412
459
  }
413
460
 
414
- new_bin_infos = this.sdk.Position.calculateAddLiquidityInfo(calculateOption)
461
+ new_bin_infos = await this.sdk.Position.calculateAddLiquidityInfo(calculateOption)
415
462
  }
416
463
 
417
464
  const createPoolAndAddOption: CreatePoolAndAddOption = {
@@ -28,6 +28,7 @@ import {
28
28
  } from '../types/dlmm'
29
29
  import {
30
30
  BinUtils,
31
+ FeeUtils,
31
32
  getRouterModule,
32
33
  parsedDlmmPosFeeData,
33
34
  parsedDlmmPosRewardData,
@@ -354,36 +355,56 @@ export class PositionModule implements IModule<CetusDlmmSDK> {
354
355
  * @param option - The option for calculating the result of adding liquidity
355
356
  * @returns The result of adding liquidity
356
357
  */
357
- calculateAddLiquidityInfo(option: CalculateAddLiquidityOption | CalculateAddLiquidityAutoFillOption): BinLiquidityInfo {
358
+ async calculateAddLiquidityInfo(option: CalculateAddLiquidityOption | CalculateAddLiquidityAutoFillOption): Promise<BinLiquidityInfo> {
358
359
  const isAutoFill = 'fix_amount_a' in option
359
- const { active_id, bin_step, lower_bin_id, upper_bin_id, amount_a_in_active_bin, amount_b_in_active_bin, strategy_type } = option
360
+ const { active_id, bin_step, lower_bin_id, upper_bin_id, active_bin_of_pool, strategy_type, pool_id } = option
360
361
 
362
+ let bin_infos
361
363
  if (isAutoFill) {
362
364
  const { coin_amount, fix_amount_a } = option
363
- return StrategyUtils.autoFillCoinByStrategy(
365
+ bin_infos = StrategyUtils.autoFillCoinByStrategyV2(
364
366
  active_id,
365
367
  bin_step,
366
368
  coin_amount,
367
369
  fix_amount_a,
368
- amount_a_in_active_bin,
369
- amount_b_in_active_bin,
370
370
  lower_bin_id,
371
371
  upper_bin_id,
372
- strategy_type
372
+ strategy_type,
373
+ active_bin_of_pool
373
374
  )
374
375
  } else {
375
- return StrategyUtils.toAmountsBothSideByStrategy(
376
+ bin_infos = StrategyUtils.toAmountsBothSideByStrategy(
376
377
  active_id,
377
378
  bin_step,
378
379
  lower_bin_id,
379
380
  upper_bin_id,
380
381
  option.amount_a,
381
382
  option.amount_b,
382
- amount_a_in_active_bin,
383
- amount_b_in_active_bin,
384
- strategy_type
383
+ strategy_type,
384
+ active_bin_of_pool
385
385
  )
386
386
  }
387
+ if (active_bin_of_pool && pool_id) {
388
+ const active_bin_index = bin_infos.bins.findIndex((bin) => bin.bin_id === active_id)
389
+ if (active_bin_index !== -1) {
390
+ const pool = await this._sdk.Pool.getPool(pool_id, false)
391
+ if (pool) {
392
+ const { fees_a, fees_b } = FeeUtils.getCompositionFees(
393
+ active_bin_of_pool,
394
+ bin_infos.bins[active_bin_index],
395
+ pool.variable_parameters
396
+ )
397
+ const active_bin = bin_infos.bins[active_bin_index]
398
+ active_bin.amount_a = d(active_bin.amount_a).sub(fees_a).toFixed(0)
399
+ active_bin.amount_b = d(active_bin.amount_b).sub(fees_b).toFixed(0)
400
+ bin_infos.bins[active_bin_index] = active_bin
401
+ console.log('🚀 ~ PositionModule ~ calculateAddLiquidityInfo ~ fees_a:', fees_a)
402
+ console.log('🚀 ~ PositionModule ~ calculateAddLiquidityInfo ~ fees_b:', fees_b)
403
+ }
404
+ }
405
+ }
406
+
407
+ return bin_infos
387
408
  }
388
409
 
389
410
  /**
@@ -480,7 +501,7 @@ export class PositionModule implements IModule<CetusDlmmSDK> {
480
501
  * @param option - The option for adding liquidity with price
481
502
  * @returns The transaction
482
503
  */
483
- addLiquidityWithPricePayload(option: OpenAndAddLiquidityWithPriceOption): Transaction {
504
+ async addLiquidityWithPricePayload(option: OpenAndAddLiquidityWithPriceOption): Promise<Transaction> {
484
505
  const {
485
506
  pool_id,
486
507
  bin_infos,
@@ -492,8 +513,7 @@ export class PositionModule implements IModule<CetusDlmmSDK> {
492
513
  upper_price,
493
514
  bin_step,
494
515
  strategy_type,
495
- amount_a_in_active_bin,
496
- amount_b_in_active_bin,
516
+ active_bin_of_pool,
497
517
  decimals_a,
498
518
  decimals_b,
499
519
  use_bin_infos,
@@ -522,12 +542,11 @@ export class PositionModule implements IModule<CetusDlmmSDK> {
522
542
  bin_step,
523
543
  lower_bin_id,
524
544
  upper_bin_id,
525
- amount_a_in_active_bin,
526
- amount_b_in_active_bin,
545
+ active_bin_of_pool,
527
546
  strategy_type: strategy_type,
528
547
  }
529
548
 
530
- new_bin_infos = this.sdk.Position.calculateAddLiquidityInfo(calculateOption)
549
+ new_bin_infos = await this.sdk.Position.calculateAddLiquidityInfo(calculateOption)
531
550
  }
532
551
 
533
552
  const openAndAddLiquidityOption: OpenAndAddLiquidityOption = {
package/src/types/dlmm.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { CoinPairType, TableHandle } from '@cetusprotocol/common-sdk'
2
2
  import { TransactionObjectArgument } from '@mysten/sui/transactions'
3
+ import Decimal from 'decimal.js'
3
4
  export type DlmmConfigs = {
4
5
  registry_id: string
5
6
  pools_id: string
@@ -152,6 +153,7 @@ export type CreatePoolOption = {
152
153
  } & BaseCreatePoolOption
153
154
 
154
155
  export type CreatePoolAndAddWithPriceOption = {
156
+ pool_id: string
155
157
  price_base_coin: 'coin_a' | 'coin_b'
156
158
  price: string
157
159
  lower_price: string
@@ -177,12 +179,12 @@ export type BaseAddLiquidityOption = {
177
179
  } & CoinPairType
178
180
 
179
181
  export type BaseCalculateAddLiquidityOption = {
182
+ pool_id?: string
180
183
  active_id: number
181
184
  bin_step: number
182
185
  lower_bin_id: number
183
186
  upper_bin_id: number
184
- amount_a_in_active_bin: string
185
- amount_b_in_active_bin: string
187
+ active_bin_of_pool?: BinAmount
186
188
  strategy_type: StrategyType
187
189
  }
188
190
 
@@ -212,8 +214,7 @@ export type OpenAndAddLiquidityWithPriceOption = BaseAddLiquidityOption & {
212
214
  price: string
213
215
  lower_price: string
214
216
  upper_price: string
215
- amount_a_in_active_bin: string
216
- amount_b_in_active_bin: string
217
+ active_bin_of_pool?: BinAmount
217
218
  strategy_type: StrategyType
218
219
  decimals_a: number
219
220
  decimals_b: number
@@ -443,3 +444,23 @@ export type FeeRate = {
443
444
  var_fee_rate: string
444
445
  total_fee_rate: string
445
446
  }
447
+
448
+ export type WeightsOptions = {
449
+ strategy_type: StrategyType
450
+ active_id: number
451
+ bin_step: number
452
+ lower_bin_id: number
453
+ upper_bin_id: number
454
+ total_amount_a: string
455
+ total_amount_b: string
456
+ active_bin_of_pool?: BinAmount
457
+ }
458
+
459
+ export type WeightsInfo = {
460
+ total_weight_a: Decimal
461
+ total_weight_b: Decimal
462
+ weights: Decimal[]
463
+ weight_per_prices: Decimal[]
464
+ active_weight_a: Decimal
465
+ active_weight_b: Decimal
466
+ } & WeightsOptions
@@ -20,7 +20,7 @@ export class FeeUtils {
20
20
  static calculateCompositionFee(amount: string, total_fee_rate: string) {
21
21
  const fee_amount = d(amount).mul(total_fee_rate)
22
22
  const composition_fee = d(fee_amount).mul(d(FEE_PRECISION).add(total_fee_rate))
23
- return composition_fee.div(d(FEE_PRECISION).pow(2)).toFixed(0)
23
+ return composition_fee.div(1000000000000000000).toFixed(0)
24
24
  }
25
25
 
26
26
  static calculateProtocolFee(fee_amount: string, protocol_fee_rate: string) {
@@ -40,31 +40,33 @@ export class FeeUtils {
40
40
  static getCompositionFees(
41
41
  active_bin: BinAmount,
42
42
  used_bin: BinAmount,
43
- binStepConfig: BinStepConfig,
44
43
  variableParameters: VariableParameters
45
44
  ): { fees_a: string; fees_b: string } {
45
+ const { bin_step_config } = variableParameters
46
46
  if (d(active_bin.liquidity || '0').eq(d(0))) {
47
47
  return {
48
48
  fees_a: '0',
49
49
  fees_b: '0',
50
50
  }
51
51
  }
52
- const { bin_step, base_factor } = binStepConfig
52
+ const { bin_step, base_factor } = bin_step_config
53
53
  const qPrice = BinUtils.getQPriceFromId(active_bin.bin_id, bin_step)
54
- const used_liquidity = BinUtils.getLiquidity(used_bin.amount_a, used_bin.amount_b, qPrice)
54
+ const bin_liquidity = BinUtils.getLiquidity(active_bin.amount_a, active_bin.amount_b, qPrice)
55
+ const delta_liquidity = BinUtils.getLiquidity(used_bin.amount_a, used_bin.amount_b, qPrice)
56
+ const delta_liquidity_share = d(active_bin.liquidity).mul(delta_liquidity).div(bin_liquidity).toFixed(0)
55
57
 
56
58
  const { amount_a: amount_a_out, amount_b: amount_b_out } = BinUtils.calculateOutByShare(
57
59
  {
58
60
  bin_id: active_bin.bin_id,
59
- liquidity: d(active_bin.liquidity).add(used_liquidity).toFixed(0),
61
+ liquidity: d(active_bin.liquidity).add(delta_liquidity_share).toFixed(0),
60
62
  amount_a: d(active_bin.amount_a).add(used_bin.amount_a).toFixed(0),
61
63
  amount_b: d(active_bin.amount_b).add(used_bin.amount_b).toFixed(0),
62
64
  price_per_lamport: active_bin.price_per_lamport,
63
65
  },
64
- used_liquidity
66
+ delta_liquidity_share
65
67
  )
66
68
 
67
- const base_fee = d(bin_step).mul(base_factor)
69
+ const base_fee = d(bin_step).mul(base_factor).mul(10)
68
70
  const variable_fee = FeeUtils.getVariableFee(variableParameters)
69
71
 
70
72
  let total_fee_rate = d(base_fee).add(variable_fee).toFixed(0)
@@ -76,12 +78,10 @@ export class FeeUtils {
76
78
  let fees_a = '0'
77
79
  let fees_b = '0'
78
80
 
79
- if (d(amount_a_out).gt(used_bin.amount_a)) {
80
- fees_a = FeeUtils.calculateCompositionFee(amount_a_out, total_fee_rate)
81
- }
82
-
83
- if (d(amount_b_out).gt(used_bin.amount_b)) {
84
- fees_b = FeeUtils.calculateCompositionFee(amount_b_out, total_fee_rate)
81
+ if (d(amount_a_out).gt(used_bin.amount_a) && d(used_bin.amount_b).gt(amount_b_out)) {
82
+ fees_b = FeeUtils.calculateCompositionFee(d(used_bin.amount_b).sub(amount_b_out).toFixed(0), total_fee_rate)
83
+ } else if (d(amount_b_out).gt(used_bin.amount_b) && d(used_bin.amount_a).gt(amount_a_out)) {
84
+ fees_a = FeeUtils.calculateCompositionFee(d(used_bin.amount_a).sub(amount_a_out).toFixed(0), total_fee_rate)
85
85
  }
86
86
 
87
87
  return {
@@ -37,6 +37,7 @@ import {
37
37
  import { BinUtils } from './binUtils'
38
38
  import { BASIS_POINT } from '../types/constants'
39
39
  import { bcs } from '@mysten/sui/bcs'
40
+ import { blake2b } from 'blakejs'
40
41
 
41
42
  /**
42
43
  * Parse the DLMM base pool data
@@ -278,7 +279,7 @@ export function parseBinInfoList(res: DevInspectResults): BinAmount[] {
278
279
  fee_b_growth_global: bcs.u128(),
279
280
  })
280
281
 
281
- const bin_amounts = bcs.vector(bcsCoinAmount).parse(Uint8Array.from(res.results![0].returnValues![0][0]))
282
+ const bin_amounts = bcs.vector(bcsCoinAmount).parse(Uint8Array.from(res.results![1].returnValues![0][0]))
282
283
 
283
284
  return bin_amounts.map((bin_amount) => {
284
285
  const bin_id = asIntN(BigInt(bin_amount.id.bits))
@@ -303,7 +304,7 @@ export function parseBinInfo(fields: any): BinAmount {
303
304
  bin_id,
304
305
  amount_a: fields.amount_a,
305
306
  amount_b: fields.amount_b,
306
- liquidity: fields.liquidity_supply,
307
+ liquidity: fields.liquidity_share,
307
308
  price_per_lamport: BinUtils.getPricePerLamportFromQPrice(fields.price),
308
309
  }
309
310
 
@@ -507,6 +508,13 @@ export function safeMulAmount(amount: Decimal, rate: Decimal): Decimal {
507
508
  return result.floor()
508
509
  }
509
510
 
511
+ export function safeAmount(amount: Decimal): Decimal {
512
+ if (amount.gt(0) && amount.lt(1)) {
513
+ throw new DlmmError(`Multiplication ${amount.toString()} is less than 1`, DlmmErrorCode.AmountTooSmall)
514
+ }
515
+ return amount.floor()
516
+ }
517
+
510
518
  export function getRouterModule(strategy_type: StrategyType) {
511
519
  switch (strategy_type) {
512
520
  case StrategyType.Spot:
@@ -517,3 +525,32 @@ export function getRouterModule(strategy_type: StrategyType) {
517
525
  return 'bid_ask'
518
526
  }
519
527
  }
528
+
529
+ export function buildPoolKey(coin_type_a: string, coin_type_b: string, bin_step: number, base_factor: number) {
530
+ // Convert coin types to bytes
531
+ let coinABytes = Buffer.from(coin_type_a, 'utf8')
532
+ const coinBBytes = Buffer.from(coin_type_b, 'utf8')
533
+
534
+ const lenB = coinBBytes.length
535
+
536
+ let i = 0
537
+
538
+ // Append coinB bytes to coinA (without validation)
539
+ while (i < lenB) {
540
+ const byteB = coinBBytes[i]
541
+ coinABytes = Buffer.concat([coinABytes, Buffer.from([byteB])])
542
+ i++
543
+ }
544
+
545
+ // Serialize bin_step and base_factor using BCS
546
+ const binStepBytes = bcs.u16().serialize(bin_step).toBytes()
547
+ const baseFactorBytes = bcs.u16().serialize(base_factor).toBytes()
548
+
549
+ // Concatenate all bytes
550
+ const combinedBytes = Buffer.concat([coinABytes, binStepBytes, baseFactorBytes])
551
+
552
+ // Hash with blake2b256
553
+ const hash = blake2b(combinedBytes, undefined, 32)
554
+
555
+ return `0x${Buffer.from(hash).toString('hex')}`
556
+ }