@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,145 @@
|
|
|
1
|
+
# Add liquidity
|
|
2
|
+
|
|
3
|
+
Once you have set a suitable tick range, you can proceed to add liquidity to this position. The quantity composition of tokens you need to add is affected by the current price of the pool and the tick interval you have chosen.
|
|
4
|
+
|
|
5
|
+
There are two situations:
|
|
6
|
+
|
|
7
|
+
1. add liquidity with a specified liquidity
|
|
8
|
+
2. add liquidity with fixed coin amount.
|
|
9
|
+
|
|
10
|
+
## 1. add liquidity with a specified liquidity
|
|
11
|
+
|
|
12
|
+
Use `sdk.Position.createAddLiquidityPayload()` method.
|
|
13
|
+
|
|
14
|
+
### Function Parameters
|
|
15
|
+
|
|
16
|
+
- `pool_id`: The object id about which pool you want to operation
|
|
17
|
+
- `pos_id`: The object id about position.
|
|
18
|
+
- `max_amount_a`: The max limit about used coin a amount.
|
|
19
|
+
- `max_amount_b`: The max limit about used coin b amount.
|
|
20
|
+
- `delta_liquidity`: The actual change in liquidity that has been added.
|
|
21
|
+
- `tick_lower`: Represents the index of the lower tick boundary
|
|
22
|
+
- `tick_upper`: Represents the index of the upper tick boundary
|
|
23
|
+
- `collect_fee`: If you already has one position, you can select collect fees while adding liquidity.
|
|
24
|
+
- `rewarder_coin_types`: If these not empty, it will collect rewarder in this position, if you already open the position.
|
|
25
|
+
|
|
26
|
+
### Important Notes
|
|
27
|
+
|
|
28
|
+
### How to Calculate `delta_liquidity`, `max_amount_a`, and `max_amount_b`
|
|
29
|
+
|
|
30
|
+
1. you can set fixed two coin amount you want to use.
|
|
31
|
+
2. use ClmmPoolUtil.estLiquidityAndCoinAmountFromOneAmounts() to calculated the delta_liquidity.
|
|
32
|
+
3. Apply price slippage adjustment to the two coin amounts(max_amount_a and max_amount_b) calculated above by method adjustForCoinSlippage
|
|
33
|
+
|
|
34
|
+
### Example
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
const pool = await sdk.Pool.getPool(pool_id)
|
|
38
|
+
const position = await sdk.Position.getPositionById(pos_id)
|
|
39
|
+
const cur_sqrt_price = new BN(pool.current_sqrt_price)
|
|
40
|
+
const lower_tick = Number(position.tick_lower_index)
|
|
41
|
+
const upper_tick = Number(position.tick_upper_index)
|
|
42
|
+
|
|
43
|
+
const lower_sqrt_price = TickMath.tickIndexToSqrtPriceX64(lower_tick)
|
|
44
|
+
const upper_sqrt_price = TickMath.tickIndexToSqrtPriceX64(upper_tick)
|
|
45
|
+
|
|
46
|
+
const slippage_tolerance = new Percentage(new BN(5), new BN(100))
|
|
47
|
+
const liquidity = 10000
|
|
48
|
+
|
|
49
|
+
const coin_amounts = ClmmPoolUtil.getCoinAmountFromLiquidity(new BN(liquidity), cur_sqrt_price, lower_sqrt_price, upper_sqrt_price, false)
|
|
50
|
+
|
|
51
|
+
const { coin_amount_limit_a, coin_amount_limit_b } = adjustForCoinSlippage(coin_amounts, slippage_tolerance, true)
|
|
52
|
+
|
|
53
|
+
const add_liquidity_payload_params: AddLiquidityParams = {
|
|
54
|
+
coin_type_a: pool.coin_type_a,
|
|
55
|
+
coin_type_b: pool.coin_type_b,
|
|
56
|
+
pool_id: pool.id,
|
|
57
|
+
tick_lower: lower_tick.toString(),
|
|
58
|
+
tick_upper: upper_tick.toString(),
|
|
59
|
+
delta_liquidity: liquidity.toString(),
|
|
60
|
+
max_amount_a: coin_amount_limit_a.toString(),
|
|
61
|
+
max_amount_b: coin_amount_limit_b.toString(),
|
|
62
|
+
pos_id: position.pos_object_id,
|
|
63
|
+
rewarder_coin_types: [],
|
|
64
|
+
collect_fee: false,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const payload = await sdk.Position.createAddLiquidityPayload(add_liquidity_payload_params)
|
|
68
|
+
|
|
69
|
+
printTransaction(payload)
|
|
70
|
+
const send_key_pair = 'The key pair generated by your private key'
|
|
71
|
+
const transfer_txn = await sdk.FullClient.executeTx(send_key_pair, payload, true)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 2. Add liquidity with a fixed coin amount
|
|
75
|
+
|
|
76
|
+
Use `sdk.Position.createAddLiquidityFixTokenPayload()` method.
|
|
77
|
+
|
|
78
|
+
### Function Parameters
|
|
79
|
+
|
|
80
|
+
- `pool_id`: The object id about which pool you want to operation
|
|
81
|
+
- `coin_type_a`: The coin type address about coinA
|
|
82
|
+
- `coin_type_b`: The coin type address about coinB
|
|
83
|
+
- `tick_lower`: Represents the index of the lower tick boundary
|
|
84
|
+
- `tick_upper`: Represents the index of the upper tick boundary
|
|
85
|
+
- `is_open`: true means if first add liquidity, so needs open one position
|
|
86
|
+
- `pos_id`: The object id about position
|
|
87
|
+
- `fix_amount_a`: true means fixed coinA amount, false means fixed coinB amount
|
|
88
|
+
- `slippage`: Price slippage point.
|
|
89
|
+
- `amount_a`: If fixed amount A, you must set amount_a, amount_b will be auto calculated by `ClmmPoolUtil.estLiquidityAndCoinAmountFromOneAmounts()`
|
|
90
|
+
- `amount_b`: If fixed amount B, you must set amount_b, amount_a will be auto calculated by `ClmmPoolUtil.estLiquidityAndCoinAmountFromOneAmounts()`
|
|
91
|
+
- `collect_fee`: If you already has one position, you can select collect fees while adding liquidity
|
|
92
|
+
- `rewarder_coin_types`: If these not empty, it will collect rewarder in this position, if you already open the position
|
|
93
|
+
|
|
94
|
+
### Important Notes
|
|
95
|
+
|
|
96
|
+
- The tick index must be an integer multiple of tickSpacing. If the provided parameter is not a multiple of tickSpacing, the contract will throw an error.
|
|
97
|
+
- `-443636 < tick_lower_index < tick_upper_index < 443636`, 443636 is a constant, derived from the maximum range representable by the Q32.62 fixed-point number format.
|
|
98
|
+
- If you know price range, you can use `TickMath.priceToTickIndex()` to transform real price to tick index.
|
|
99
|
+
- You can just open one position near the current price of the pool, use `TickMath.getPrevInitializeTickIndex()` and `TickMath.getNextInitializeTickIndex()` to find the next initialized tick.
|
|
100
|
+
- If you want to add global liquidity, you can set:
|
|
101
|
+
- `tick_lower_index = -443636 + (443636 % tick_spacing)`
|
|
102
|
+
- `tick_upper_index = 443636 - (443636 % tick_spacing)`
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
const pool = await sdk.Pool.getPool(pool_id)
|
|
106
|
+
const position = await sdk.Position.getPositionById(pos_id)
|
|
107
|
+
const tick_lower_index = position.tick_lower_index
|
|
108
|
+
const tick_upper_index = position.tick_upper_index
|
|
109
|
+
const coin_amount = new BN(500)
|
|
110
|
+
const fix_amount_a = true
|
|
111
|
+
const slippage = 0.1
|
|
112
|
+
const cur_sqrt_price = new BN(pool.current_sqrt_price)
|
|
113
|
+
|
|
114
|
+
const liquidity_input = ClmmPoolUtil.estLiquidityAndCoinAmountFromOneAmounts(
|
|
115
|
+
tick_lower_index,
|
|
116
|
+
tick_upper_index,
|
|
117
|
+
coin_amount,
|
|
118
|
+
fix_amount_a,
|
|
119
|
+
true,
|
|
120
|
+
slippage,
|
|
121
|
+
cur_sqrt_price
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
const amount_a = fix_amount_a ? coin_amount.toNumber() : Number(liquidity_input.coin_amount_limit_a)
|
|
125
|
+
const amount_b = fix_amount_a ? Number(liquidity_input.coin_amount_limit_b) : coin_amount.toNumber()
|
|
126
|
+
|
|
127
|
+
const add_liquidity_payload_params: AddLiquidityFixTokenParams = {
|
|
128
|
+
coin_type_a: pool.coin_type_a,
|
|
129
|
+
coin_type_b: pool.coin_type_b,
|
|
130
|
+
pool_id: pool.id,
|
|
131
|
+
tick_lower: tick_lower_index.toString(),
|
|
132
|
+
tick_upper: tick_upper_index.toString(),
|
|
133
|
+
fix_amount_a,
|
|
134
|
+
amount_a,
|
|
135
|
+
amount_b,
|
|
136
|
+
slippage,
|
|
137
|
+
is_open: false,
|
|
138
|
+
pos_id: position.pos_object_id,
|
|
139
|
+
rewarder_coin_types: [],
|
|
140
|
+
collect_fee: true,
|
|
141
|
+
}
|
|
142
|
+
const add_liquidity_payload = await sdk.Position.createAddLiquidityFixTokenPayload(add_liquidity_payload_params)
|
|
143
|
+
|
|
144
|
+
const transfer_txn = await sdk.FullClient.executeTx(send_key_pair, add_liquidity_payload, true)
|
|
145
|
+
```
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Close Position
|
|
2
|
+
|
|
3
|
+
When you withdraw all the liquidity from your position, you can decide whether to close the position. Please note that when closing the position, you must also withdraw all the current position's liquidity, fees, and rewards.
|
|
4
|
+
|
|
5
|
+
## 1. Close Position
|
|
6
|
+
|
|
7
|
+
Use `sdk.Position.closePositionPayload()` method.
|
|
8
|
+
|
|
9
|
+
### Function Parameters
|
|
10
|
+
|
|
11
|
+
- `pool_id`: The object id about which pool you want to operation
|
|
12
|
+
- `pos_id`: The object id about which position you want to operation
|
|
13
|
+
- `coin_type_a`: The coin type address about coinA
|
|
14
|
+
- `coin_type_b`: The coin type address about coinB
|
|
15
|
+
- `min_amount_a`: The minimum amount of coin A that a user can acquire.
|
|
16
|
+
- `min_amount_b`: The minimum amount of coin B that a user can acquire.
|
|
17
|
+
- `rewarder_coin_types`: When closing the position, all pending rewards must be collected
|
|
18
|
+
|
|
19
|
+
### Important Notes
|
|
20
|
+
|
|
21
|
+
- Because of pool price will change, the amount of coin A and coin B will change. So the min_amount_a and min_amount_a means no matter how the price moves, the amount quantity that I need to receive at least is typically obtained
|
|
22
|
+
by adding the amount potentially acquired through calculations to the slippage adjustment.
|
|
23
|
+
|
|
24
|
+
### Example
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
const pool = await sdk.Pool.getPool(pool_id)
|
|
28
|
+
const position = await sdk.Position.getPositionById(pos_id)
|
|
29
|
+
|
|
30
|
+
const lower_tick = Number(position.tick_lower_index)
|
|
31
|
+
const upper_tick = Number(position.tick_upper_index)
|
|
32
|
+
|
|
33
|
+
const lower_sqrt_price = TickMath.tickIndexToSqrtPriceX64(lower_tick)
|
|
34
|
+
const upper_sqrt_price = TickMath.tickIndexToSqrtPriceX64(upper_tick)
|
|
35
|
+
|
|
36
|
+
const liquidity = new BN(position.liquidity)
|
|
37
|
+
const slippage_tolerance = new Percentage(new BN(5), new BN(100))
|
|
38
|
+
const cur_sqrt_price = new BN(pool.current_sqrt_price)
|
|
39
|
+
|
|
40
|
+
const coin_amounts = ClmmPoolUtil.getCoinAmountFromLiquidity(liquidity, cur_sqrt_price, lower_sqrt_price, upper_sqrt_price, false)
|
|
41
|
+
const { coin_amount_limit_a, coin_amount_limit_b } = adjustForCoinSlippage(coin_amounts, slippage_tolerance, false)
|
|
42
|
+
|
|
43
|
+
const reward_coin_types = pool.rewarder_infos.map((rewarder) => rewarder.coin_type)
|
|
44
|
+
|
|
45
|
+
const close_position_payload = await sdk.Position.closePositionPayload({
|
|
46
|
+
coin_type_a: pool.coin_type_a,
|
|
47
|
+
coin_type_b: pool.coin_type_b,
|
|
48
|
+
min_amount_a: coin_amount_limit_a.toString(),
|
|
49
|
+
min_amount_b: coin_amount_limit_b.toString(),
|
|
50
|
+
rewarder_coin_types: reward_coin_types,
|
|
51
|
+
pool_id: pool.id,
|
|
52
|
+
pos_id: position_nft_id,
|
|
53
|
+
collect_fee: true,
|
|
54
|
+
})
|
|
55
|
+
const send_key_pair = 'The key pair generated by your private key'
|
|
56
|
+
const transfer_txn = await sdk.FullClient.executeTx(send_key_pair, close_position_payload, true)
|
|
57
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Collect rewards
|
|
2
|
+
|
|
3
|
+
When you provide liquidity within a valid price range, when transactions occurring within this range, the rewards will be distributed every second based on the proportional share of effective liquidity from all positions within the current range. If you intend to harvest rewards separately, please follow the method below.
|
|
4
|
+
|
|
5
|
+
## 1. Collect rewards
|
|
6
|
+
|
|
7
|
+
Use `sdk.Position.collectRewarderPayload()` method.
|
|
8
|
+
|
|
9
|
+
### Function Parameters
|
|
10
|
+
|
|
11
|
+
- `pool_id`: The object id about which pool you want to operation
|
|
12
|
+
- `pos_id`: The object id about which position you want to operation
|
|
13
|
+
- `coin_type_a`: The coin type address about coinA
|
|
14
|
+
- `coin_type_b`: The coin type address about coinB
|
|
15
|
+
- `collect_fee`: you can select weather collect fees while Collect rewards.
|
|
16
|
+
- `rewarder_coin_types`: If these not empty, it will collect rewarders in this position, if you already open the position. You can even determine which types of rewards you want to harvest by specifying the coin types you pass.
|
|
17
|
+
|
|
18
|
+
### Example
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
const pool = await sdk.Pool.getPool(pool_id)
|
|
22
|
+
|
|
23
|
+
const reward_coin_types = pool.rewarder_infos.map((rewarder) => rewarder.coin_type)
|
|
24
|
+
|
|
25
|
+
const collect_rewarder_params: CollectRewarderParams = {
|
|
26
|
+
pool_id: pool.id,
|
|
27
|
+
pos_id,
|
|
28
|
+
rewarder_coin_types: reward_coin_types,
|
|
29
|
+
coin_type_a: pool.coin_type_a,
|
|
30
|
+
coin_type_b: pool.coin_type_b,
|
|
31
|
+
collect_fee: true,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const collect_rewarder_payload = await sdk.Rewarder.collectRewarderPayload(collect_rewarder_params)
|
|
35
|
+
const send_key_pair = 'The key pair generated by your private key'
|
|
36
|
+
const transfer_txn = await sdk.FullClient.executeTx(send_key_pair, collect_rewarder_payload, true)
|
|
37
|
+
```
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Create CLMM Pool
|
|
2
|
+
|
|
3
|
+
Everyone can create Cetus CLMM pools directly.
|
|
4
|
+
|
|
5
|
+
## 1. Create a CLMM Pool with Initial Liquidity
|
|
6
|
+
|
|
7
|
+
Use `sdk.Pool.createPoolTransactionPayload()` to create a pool.
|
|
8
|
+
|
|
9
|
+
### Function Parameters
|
|
10
|
+
|
|
11
|
+
#### Required Parameters
|
|
12
|
+
|
|
13
|
+
- `tick_spacing`: Affects price precision. Different tick spacing values correspond to different fee rates:
|
|
14
|
+
|
|
15
|
+
| Tick Spacing | Fee Rate |
|
|
16
|
+
| ------------ | -------- |
|
|
17
|
+
| 2 | 0.0001 |
|
|
18
|
+
| 10 | 0.0005 |
|
|
19
|
+
| 20 | 0.001 |
|
|
20
|
+
| 60 | 0.0025 |
|
|
21
|
+
| 200 | 0.01 |
|
|
22
|
+
| 220 | 0.02 |
|
|
23
|
+
|
|
24
|
+
- `initialize_sqrt_price`: For computational convenience, we use fixed-point numbers to represent square root prices. Use `TickMath.priceToSqrtPriceX64()` to transform price to sqrtPrice.
|
|
25
|
+
- `coin_type_a`: The coin type address for coin A.
|
|
26
|
+
- `coin_type_b`: The coin type address for coin B.
|
|
27
|
+
- `amount_a`: The amount of coin A to add as liquidity.
|
|
28
|
+
- `amount_b`: The amount of coin B to add as liquidity.
|
|
29
|
+
- `fix_amount_a`: Boolean value - true means fixed coin A amount, false means fixed coin B amount.
|
|
30
|
+
- `tick_lower`: The index of the lower tick boundary.
|
|
31
|
+
- `tick_upper`: The index of the upper tick boundary.
|
|
32
|
+
- `metadata_a`: The coin metadata ID of coin A.
|
|
33
|
+
- `metadata_b`: The coin metadata ID of coin B.
|
|
34
|
+
|
|
35
|
+
#### Optional Parameters
|
|
36
|
+
|
|
37
|
+
- `uri`: The icon of the pool (can be null).
|
|
38
|
+
|
|
39
|
+
### Determining Coin Type A and B
|
|
40
|
+
|
|
41
|
+
1. Complete the Coin Type: Ensure the coin type is complete before comparing.
|
|
42
|
+
2. Character-by-Character Comparison: Compare the characters of both coin type addresses.
|
|
43
|
+
3. ASCII Value Comparison: When encountering differing characters, compare their ASCII values. The coin with the larger ASCII value becomes "coin A".
|
|
44
|
+
|
|
45
|
+
#### Examples:
|
|
46
|
+
|
|
47
|
+
1. Example 1:
|
|
48
|
+
|
|
49
|
+
- coin_type_a: `0x6864a6f921804860930db6ddbe2e16acdf8504495ea7481637a1c8b9a8fe54b::cetus::CETUS`
|
|
50
|
+
- coin_type_b: `0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI`
|
|
51
|
+
|
|
52
|
+
2. Example 2:
|
|
53
|
+
- coin_type_a: `0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC`
|
|
54
|
+
- coin_type_b: `0xc060006111016b8a020ad5b33834984a437aaa7d3c74c18e09a95d48aceab08c::coin::COIN`
|
|
55
|
+
|
|
56
|
+
### Important Notes
|
|
57
|
+
|
|
58
|
+
- The tick index must be an integer multiple of tickSpacing.
|
|
59
|
+
- Range: `-443636 < tick_lower_index < current_tick_index < tick_upper_index < 443636`
|
|
60
|
+
- Currently, creating a pool requires adding bidirectional liquidity.
|
|
61
|
+
|
|
62
|
+
## Example Code
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
const sdk = CetusClmmSDK.createSDK({ env: 'mainnet' })
|
|
66
|
+
const signer = ... // set keypair
|
|
67
|
+
sdk.senderAddress = signer.getPublicKey().toSuiAddress() // set sdk.senderAddress
|
|
68
|
+
|
|
69
|
+
// Initialize sqrt_price
|
|
70
|
+
const initialize_sqrt_price = TickMath.priceToSqrtPriceX64(d(1.2),6,6).toString()
|
|
71
|
+
const tick_spacing = 2
|
|
72
|
+
const current_tick_index = TickMath.sqrtPriceX64ToTickIndex(new BN(initialize_sqrt_price))
|
|
73
|
+
|
|
74
|
+
// Build tick range
|
|
75
|
+
const tick_lower = TickMath.getPrevInitializeTickIndex(
|
|
76
|
+
new BN(current_tick_index).toNumber(),
|
|
77
|
+
new BN(tick_spacing).toNumber()
|
|
78
|
+
)
|
|
79
|
+
const tick_upper = TickMath.getNextInitializeTickIndex(
|
|
80
|
+
new BN(current_tick_index).toNumber(),
|
|
81
|
+
new BN(tick_spacing).toNumber()
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
// Input token amount
|
|
85
|
+
const fix_coin_amount = new BN(200)
|
|
86
|
+
const fix_amount_a = true // input token amount is token a
|
|
87
|
+
const slippage = 0.05 // 5% slippage
|
|
88
|
+
const cur_sqrt_price = new BN(initialize_sqrt_price)
|
|
89
|
+
|
|
90
|
+
// Estimate liquidity and token amount from one amounts
|
|
91
|
+
const res = ClmmPoolUtil.estLiquidityAndCoinAmountFromOneAmounts(
|
|
92
|
+
lower_tick,
|
|
93
|
+
upper_tick,
|
|
94
|
+
fix_coin_amount,
|
|
95
|
+
fix_amount_a,
|
|
96
|
+
true,
|
|
97
|
+
slippage,
|
|
98
|
+
cur_sqrt_price
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
// Estimate token a and token b amount
|
|
102
|
+
const amount_a = fix_amount_a ? fix_coin_amount.toNumber() : res.coin_amount_limit_a.toNumber()
|
|
103
|
+
const amount_b = fix_amount_a ? res.coin_amount_b.toNumber() : fix_coin_amount.toNumber()
|
|
104
|
+
|
|
105
|
+
const coin_type_a = '0x3cfe7b9f6106808a8178ebd2d5ae6656cd0ccec15d33e63fd857c180bde8da75::coin:CetusUSDT'
|
|
106
|
+
const coin_type_b = '0x3cfe7b9f6106808a8178ebd2d5ae6656cd0ccec15d33e63fd857c180bde8da75::coin::CetusUSDC'
|
|
107
|
+
|
|
108
|
+
const coin_metadata_a_id = await suiClient.fetchCoinMetadata({coinType: coin_type_a}).id
|
|
109
|
+
const coin_metadata_b_id = await suiClient.fetchCoinMetadata({coinType: coin_type_b}).id
|
|
110
|
+
|
|
111
|
+
// Build createPoolPayload
|
|
112
|
+
const create_pool_payload = sdk.Pool.createPoolPayload({
|
|
113
|
+
coin_type_a,
|
|
114
|
+
coin_type_b,
|
|
115
|
+
tick_spacing: tick_spacing,
|
|
116
|
+
initialize_sqrt_price: initialize_sqrt_price,
|
|
117
|
+
uri: '',
|
|
118
|
+
amount_a,
|
|
119
|
+
amount_b,
|
|
120
|
+
fix_amount_a,
|
|
121
|
+
tick_lower,
|
|
122
|
+
tick_upper,
|
|
123
|
+
metadata_a: coin_metadata_a_id,
|
|
124
|
+
metadata_b: coin_metadata_b_id,
|
|
125
|
+
})
|
|
126
|
+
const send_key_pair = 'The key pair generated by your private key'
|
|
127
|
+
const transfer_txn = await sdk.FullClient.executeTx(send_key_pair, tx, true)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## 2. Create a CLMM Pool with Initial Liquidity by directly inputting the price range
|
|
131
|
+
|
|
132
|
+
Use `sdk.Pool.createPoolWithPricePayload()` to create a pool.
|
|
133
|
+
|
|
134
|
+
### Function Parameters
|
|
135
|
+
|
|
136
|
+
#### Required Parameters
|
|
137
|
+
|
|
138
|
+
- `tick_spacing`: Affects price precision and fee rate (see table above)
|
|
139
|
+
- `current_price`: The initial price of the pool
|
|
140
|
+
- `coin_amount`: The amount of coins to add as liquidity
|
|
141
|
+
- `fix_amount_a`: Boolean value - true means fixed coin A amount, false means fixed coin B amount
|
|
142
|
+
- `add_mode_params`: Configuration for price range:
|
|
143
|
+
- For custom range: `{ is_full_range: false, min_price: string, max_price: string }`
|
|
144
|
+
- For full range: `{ is_full_range: true }`
|
|
145
|
+
- `coin_decimals_a`: Number of decimal places for coin A
|
|
146
|
+
- `coin_decimals_b`: Number of decimal places for coin B
|
|
147
|
+
- `price_base_coin`: Base coin for price calculation ('coin_a' or 'coin_b')
|
|
148
|
+
- `slippage`: Maximum acceptable slippage (e.g., 0.05 for 5%)
|
|
149
|
+
|
|
150
|
+
### Two Ways to Create Pool
|
|
151
|
+
|
|
152
|
+
1. **Create Pool with Position Return**
|
|
153
|
+
Use `sdk.Pool.createPoolWithPriceReturnPositionPayload()` to create a pool and get the position ID and remaining coins.
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
// Custom price range example
|
|
157
|
+
const tick_spacing = 220
|
|
158
|
+
|
|
159
|
+
const mode_params: CreatePoolCustomRangeParams = {
|
|
160
|
+
is_full_range: false,
|
|
161
|
+
min_price: '0.2',
|
|
162
|
+
max_price: '0.7',
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const result = await sdk.Pool.calculateCreatePoolWithPrice({
|
|
166
|
+
tick_spacing,
|
|
167
|
+
current_price: '0.5',
|
|
168
|
+
coin_amount: '1000000',
|
|
169
|
+
fix_amount_a: true,
|
|
170
|
+
add_mode_params: mode_params,
|
|
171
|
+
coin_decimals_a: 6,
|
|
172
|
+
coin_decimals_b: 9,
|
|
173
|
+
price_base_coin: 'coin_a',
|
|
174
|
+
slippage: 0.05,
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
const { tx, pos_id, remain_coin_a, remain_coin_b, remain_coin_type_a, remain_coin_type_b } =
|
|
178
|
+
await sdk.Pool.createPoolWithPriceReturnPositionPayload({
|
|
179
|
+
tick_spacing,
|
|
180
|
+
calculate_result: result,
|
|
181
|
+
add_mode_params: mode_params,
|
|
182
|
+
coin_type_a,
|
|
183
|
+
coin_type_b,
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
// Handle remaining coins
|
|
187
|
+
buildTransferCoin(sdk, tx, remain_coin_a, remain_coin_type_a)
|
|
188
|
+
buildTransferCoin(sdk, tx, remain_coin_b, remain_coin_type_b)
|
|
189
|
+
tx.transferObjects([pos_id], sdk.getSenderAddress())
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
2. **Create Pool Directly**
|
|
193
|
+
Use `sdk.Pool.createPoolWithPricePayload()` for a simpler pool creation without position management.
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// Full range example
|
|
197
|
+
const full_range_params: FullRangeParams = {
|
|
198
|
+
is_full_range: true,
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const full_range_result = await sdk.Pool.calculateCreatePoolWithPrice({
|
|
202
|
+
tick_spacing,
|
|
203
|
+
current_price: '0.5',
|
|
204
|
+
coin_amount: '1000000',
|
|
205
|
+
fix_amount_a: true,
|
|
206
|
+
add_mode_params: full_range_params,
|
|
207
|
+
coin_decimals_a: 6,
|
|
208
|
+
coin_decimals_b: 9,
|
|
209
|
+
price_base_coin: 'coin_a',
|
|
210
|
+
slippage: 0.05,
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
const tx = await sdk.Pool.createPoolWithPricePayload({
|
|
214
|
+
tick_spacing,
|
|
215
|
+
calculate_result: full_range_result,
|
|
216
|
+
add_mode_params: full_range_params,
|
|
217
|
+
coin_type_a,
|
|
218
|
+
coin_type_b,
|
|
219
|
+
})
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Important Notes
|
|
223
|
+
|
|
224
|
+
- The price range must be valid and within acceptable bounds
|
|
225
|
+
- For custom ranges, ensure min_price < current_price < max_price
|
|
226
|
+
- The tick spacing determines the fee rate and price precision
|
|
227
|
+
- Slippage protection is important to prevent significant price impact
|
|
228
|
+
- Consider the decimal places of both coins when calculating amounts
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Contract Error Codes
|
|
2
|
+
|
|
3
|
+
the Cetus smart contract may return the following error codes:
|
|
4
|
+
|
|
5
|
+
| Module | Error Code | Description | Contract Methods |
|
|
6
|
+
| ------------------------ | ---------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| cetus_clmm::pool | 0 | Amount is incorrect | flash_swap_internal,add_liquidity_fix_coin,repay_add_liquidity,repay_flash_swap,repay_flash_swap_with_partner |
|
|
8
|
+
| cetus_clmm::pool | 1 | Liquidity overflow | add_liquidity_internal,calculate_swap_result |
|
|
9
|
+
| cetus_clmm::pool | 3 | Liquidity is zero | add_liquidity,remove_liquidity,add_liquidity_internal |
|
|
10
|
+
| cetus_clmm::pool | 4 | Not enough liquidity | swap_in_pool |
|
|
11
|
+
| cetus_clmm::pool | 5 | Remainder amount underflow | check_remainer_amount_sub |
|
|
12
|
+
| cetus_clmm::pool | 6 | Swap amount in overflow | update_swap_result |
|
|
13
|
+
| cetus_clmm::pool | 7 | Swap amount out overflow | update_swap_result |
|
|
14
|
+
| cetus_clmm::pool | 8 | Fee amount overflow | update_swap_result |
|
|
15
|
+
| cetus_clmm::pool | 9 | Invalid fee rate | update_fee_rate |
|
|
16
|
+
| cetus_clmm::pool | 10 | Invalid fixed coin type | get_liquidity_from_amount |
|
|
17
|
+
| cetus_clmm::pool | 11 | Wrong sqrt price limit | flash_swap_internal |
|
|
18
|
+
| cetus_clmm::pool | 12 | Pool ID is error | repay_add_liquidity |
|
|
19
|
+
| cetus_clmm::pool | 13 | Pool is paused | |
|
|
20
|
+
| cetus_clmm::pool | 14 | Flash swap receipt not match | repay_flash_swap_with_partner, repay_flash_swap |
|
|
21
|
+
| cetus_clmm::pool | 16 | Invalid partner ref fee rate | swap_in_pool |
|
|
22
|
+
| cetus_clmm::pool | 17 | Reward does not exist | get_position_reward ,calculate_and_update_reward,collect_reward |
|
|
23
|
+
| cetus_clmm::pool | 18 | Amount out is zero | flash_swap_internal |
|
|
24
|
+
| cetus_clmm::pool | 19 | Pool position not match | collect_reward,add_liquidity,add_liquidity_fix_coin,remove_liquidity,close_position,collect_fee |
|
|
25
|
+
| cetus_clmm::position | 1 | Fee owned overflow | update_fee_internal |
|
|
26
|
+
| cetus_clmm::position | 2 | Reward owned overflow | update_rewards_internal |
|
|
27
|
+
| cetus_clmm::position | 3 | Points owned overflow | update_points_internal |
|
|
28
|
+
| cetus_clmm::position | 5 | Invalid position tick range | check_position_tick_range |
|
|
29
|
+
| cetus_clmm::position | 6 | Position does not exist | borrow_mut_position_info,fetch_positions,borrow_position_info |
|
|
30
|
+
| cetus_clmm::position | 7 | Position is not empty | close_position |
|
|
31
|
+
| cetus_clmm::position | 8 | Liquidity change overflow | increase_liquidity |
|
|
32
|
+
| cetus_clmm::position | 9 | Liquidity change underflow | decrease_liquidity |
|
|
33
|
+
| cetus_clmm::position | 10 | Invalid reward index | update_and_reset_rewards |
|
|
34
|
+
| cetus_clmm::rewarder | 1 | Reward slot is full | add_rewarder |
|
|
35
|
+
| cetus_clmm::rewarder | 2 | Reward already exists | add_rewarder |
|
|
36
|
+
| cetus_clmm::rewarder | 3 | Invalid time | settle |
|
|
37
|
+
| cetus_clmm::rewarder | 4 | Reward amount insufficient | update_emission |
|
|
38
|
+
| cetus_clmm::rewarder | 5 | Reward does not exist | borrow_mut_rewarder,borrow_rewarder |
|
|
39
|
+
| cetus_clmm::tick | 0 | Liquidity overflow | update_by_liquidity |
|
|
40
|
+
| cetus_clmm::tick | 1 | Liquidity underflow | update_by_liquidity,cross_by_swap |
|
|
41
|
+
| cetus_clmm::tick | 2 | Invalid tick | tick_score, |
|
|
42
|
+
| cetus_clmm::tick | 3 | Tick not found | decrease_liquidity, |
|
|
43
|
+
| cetus_clmm::pool_creator | 1 | Pool is permission | create_pool_v2 |
|
|
44
|
+
| cetus_clmm::pool_creator | 4 | Cap not match with pool key | create_pool_v2_with_creation_cap |
|
|
45
|
+
| cetus_clmm::pool_creator | 5 | Init sqrt price not between lower and upper | create_pool_v2 |
|
|
46
|
+
| cetus_clmm::partner | 1 | Partner already exists | create_partner |
|
|
47
|
+
| cetus_clmm::partner | 2 | Invalid time | create_partner,update_time_range |
|
|
48
|
+
| cetus_clmm::partner | 3 | Invalid partner ref fee rate | update_ref_fee_rate,create_partner |
|
|
49
|
+
| cetus_clmm::partner | 4 | Invalid partner cap | claim_ref_fee |
|
|
50
|
+
| cetus_clmm::partner | 5 | Invalid coin type | claim_ref_fee |
|
|
51
|
+
| cetus_clmm::partner | 6 | Invalid partner name | create_partner |
|
|
52
|
+
| cetus_clmm::factory | 1 | Pool already exists | create_pool_internal |
|
|
53
|
+
| cetus_clmm::factory | 2 | Invalid sqrt price | create_pool_internal |
|
|
54
|
+
| cetus_clmm::factory | 3 | Same coin type | new_pool_key,create_pool_internal |
|
|
55
|
+
| cetus_clmm::factory | 4 | Amount in above max limit | create_pool_v2_ |
|
|
56
|
+
| cetus_clmm::factory | 5 | Amount out below min limit | create_pool_v2_ |
|
|
57
|
+
| cetus_clmm::factory | 6 | Invalid coin type sequence | new_pool_key |
|
|
58
|
+
| cetus_clmm::factory | 7 | Quote coin type not in allowed pair config | register_permission_pair_internal |
|
|
59
|
+
| cetus_clmm::factory | 8 | Tick spacing not in allowed pair config | register_permission_pair_internal |
|
|
60
|
+
| cetus_clmm::factory | 9 | Pool key already registered | register_permission_pair_internal |
|
|
61
|
+
| cetus_clmm::factory | 10 | Pool key not registered | unregister_permission_pair_internal |
|
|
62
|
+
| cetus_clmm::factory | 11 | Cap already registered | mint_pool_creation_cap_by_admin,mint_pool_creation_cap |
|
|
63
|
+
| cetus_clmm::factory | 12 | Coin type not allowed | create_pool_v2_ |
|
|
64
|
+
| cetus_clmm::factory | 13 | Cap not match with coin type | unregister_permission_pair_internal,register_permission_pair_internal |
|
|
65
|
+
| cetus_clmm::factory | 14 | Coin already exists in list | add_denied_coin, add_allowed_list |
|
|
66
|
+
| cetus_clmm::factory | 15 | Coin not exists in list | remove_denied_list,remove_allowed_list |
|
|
67
|
+
| cetus_clmm::factory | 16 | Liquidity check failed | create_pool_v2_ |
|
|
68
|
+
| cetus_clmm::factory | 17 | Tick spacing not exists in fee tier | add_allowed_pair_config |
|
|
69
|
+
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Getting CLMM Pools
|
|
2
|
+
|
|
3
|
+
## 1. Get All Pools
|
|
4
|
+
|
|
5
|
+
Use `sdk.Pool.getPoolsWithPage()` method to retrieve all pools.
|
|
6
|
+
|
|
7
|
+
### Parameters
|
|
8
|
+
|
|
9
|
+
- `pagination_args`: Default to get all pool lists, supports pagination
|
|
10
|
+
|
|
11
|
+
### Example
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
async function getAllPools() {
|
|
15
|
+
const pools = await sdk.Pool.getPoolsWithPage()
|
|
16
|
+
console.log(`pool length: ${pools.length}`)
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 2. Batch Get assign Pools
|
|
21
|
+
|
|
22
|
+
Use `sdk.Pool.getAssignPools()` method to retrieve specific pools.
|
|
23
|
+
|
|
24
|
+
### Parameters
|
|
25
|
+
|
|
26
|
+
- `assign_pools`: An array of pool ID to get.
|
|
27
|
+
|
|
28
|
+
### Example
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
const pools = await sdk.Pool.getAssignPools(['0x0...'])
|
|
32
|
+
console.log(pools)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 3. Get Single Pool
|
|
36
|
+
|
|
37
|
+
Use `sdk.Pool.getPool()` method to retrieve a specific pool.
|
|
38
|
+
|
|
39
|
+
### Parameters
|
|
40
|
+
|
|
41
|
+
- `pool_id`: Pool address
|
|
42
|
+
- `force_refresh`: Optional boolean to refresh cache
|
|
43
|
+
|
|
44
|
+
### Example
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
const pool = await sdk.Pool.getPool('0x0...')
|
|
48
|
+
console.log({ pool })
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## 4. Get Pool by Coin Types
|
|
52
|
+
|
|
53
|
+
Use `sdk.Pool.getPoolByCoins()` method to find pools by coin types.
|
|
54
|
+
|
|
55
|
+
### Parameters
|
|
56
|
+
|
|
57
|
+
- `coins`: Array of coin types
|
|
58
|
+
- `fee_rate`: Optional fee rate number
|
|
59
|
+
|
|
60
|
+
### Example
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
const coin_type_a = '0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN'
|
|
64
|
+
const coin_type_b = '0xc060006111016b8a020ad5b33834984a437aaa7d3c74c18e09a95d48aceab08c::coin::COIN'
|
|
65
|
+
|
|
66
|
+
const pools = await sdk.Pool.getPoolByCoins([coin_type_a, coin_type_b])
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## 5. Notes
|
|
70
|
+
|
|
71
|
+
Some common methods for pool
|
|
72
|
+
|
|
73
|
+
### 1. Convert SqrtPrice to Price
|
|
74
|
+
|
|
75
|
+
Use `TickMath.sqrtPriceX64ToPrice()` method to convert a given sqrtPrice to a price.
|
|
76
|
+
|
|
77
|
+
### Parameters
|
|
78
|
+
|
|
79
|
+
- `sqrt_price_x64`: The sqrtPrice value to convert.
|
|
80
|
+
- `decimals_a`: The number of decimals for coin A.
|
|
81
|
+
- `decimals_b`: The number of decimals for coin B.
|
|
82
|
+
|
|
83
|
+
### Example
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
const sqrt_price_x64 = '18446744073709551616'
|
|
87
|
+
const decimals_a = 6
|
|
88
|
+
const decimals_b = 9
|
|
89
|
+
|
|
90
|
+
const price = TickMath.sqrtPriceX64ToPrice(new BN(sqrt_price_x64), decimals_a, decimals_b)
|
|
91
|
+
console.log('Price:', price.toString())
|
|
92
|
+
```
|