@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
package/README.md
ADDED
|
@@ -0,0 +1,646 @@
|
|
|
1
|
+
# @cetusprotocol/dlmm-sdk
|
|
2
|
+
|
|
3
|
+
The SDK provides a DLMM (Dynamic Liquidity Market Maker) module for specialized liquidity operations with different modes to suit various trading strategies. This module enables users to perform complex liquidity operations with flexibility in how they want to manage their positions.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
## How to Use the DLMM SDK?
|
|
8
|
+
|
|
9
|
+
### Installation
|
|
10
|
+
|
|
11
|
+
To start using the `DLMM SDK`, you first need to install it in your TypeScript project:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @cetusprotocol/dlmm-sdk
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Setup
|
|
18
|
+
|
|
19
|
+
Import the SDK into the TypeScript file where you intend to use it:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { CetusDlmmSDK } from '@cetusprotocol/dlmm-sdk'
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Initializing the SDK
|
|
26
|
+
|
|
27
|
+
Initialize the SDK with the required configuration parameters. This typically includes setting up the network if needed.
|
|
28
|
+
|
|
29
|
+
If you would like to use the mainnet network and the official Sui rpc url, you can do so as follows:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
const sdk = CetusDlmmSDK.createSDK()
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
If you wish to set your own full node URL or network (You have the option to select either 'mainnet' or 'testnet' for the network), you can do so as follows:
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
const env = 'mainnet'
|
|
39
|
+
const full_rpc_url = 'YOUR_FULL_NODE_URL'
|
|
40
|
+
|
|
41
|
+
const sdk = CetusDlmmSDK.createSDK({ env })
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
If you wish to set your own full node URL or SuiClient, you can do so as follows:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
const sdk = CetusDlmmSDK.createSDK({ env, sui_client })
|
|
48
|
+
// or
|
|
49
|
+
const sdk = CetusDlmmSDK.createSDK({ env, full_rpc_url })
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Usage
|
|
53
|
+
|
|
54
|
+
After linking your wallet, if you need use your wallet address to do something, you should set it by `sdk.setSenderAddress`.
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
const wallet = 'YOUR_WALLET_ADDRESS'
|
|
58
|
+
|
|
59
|
+
sdk.setSenderAddress(wallet)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
if you need to change your rpc url, you can do so as follows:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
const new_rpc_url = 'YOUR_NEW_FULL_NODE_URL'
|
|
66
|
+
|
|
67
|
+
sdk.updateFullRpcUrl(new_rpc_url)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Common Parameters
|
|
71
|
+
|
|
72
|
+
- `pool_id`: The ID of the liquidity pool
|
|
73
|
+
- `bin_id`: The ID of the bin in the pool
|
|
74
|
+
- `bin_step`: The step size between bins
|
|
75
|
+
- `coin_type_a` & `coin_type_b`: Coin type identifiers for the trading pair
|
|
76
|
+
- `coin_decimal_a` & `coin_decimal_b`: Decimal places for each coin type
|
|
77
|
+
|
|
78
|
+
### 1. Pool Operations
|
|
79
|
+
|
|
80
|
+
#### Get Pool Information
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// Get all pools
|
|
84
|
+
const pools = await sdk.Pool.getPools()
|
|
85
|
+
|
|
86
|
+
// Get specific pool
|
|
87
|
+
const pool = await sdk.Pool.getPool(pool_id)
|
|
88
|
+
|
|
89
|
+
// Get specific pools by their IDs
|
|
90
|
+
const assign_pools = await sdk.Pool.getAssignPoolList([
|
|
91
|
+
'0x...',
|
|
92
|
+
// Add more pool IDs as needed
|
|
93
|
+
])
|
|
94
|
+
|
|
95
|
+
// Get bin information
|
|
96
|
+
const bin_info = await sdk.Pool.getBinInfo(pool_id, bin_id, bin_step)
|
|
97
|
+
|
|
98
|
+
// Get pool bin information
|
|
99
|
+
const pool_bin_info = await sdk.Pool.getPoolBinInfo(pool_id)
|
|
100
|
+
|
|
101
|
+
// Get bin step configurations
|
|
102
|
+
const bin_step_configs = await sdk.Pool.getBinStepConfigs()
|
|
103
|
+
|
|
104
|
+
// Get pool transaction list
|
|
105
|
+
const pool_transactions = await sdk.Pool.getPoolTransactionList({
|
|
106
|
+
pool_id: '0x...',
|
|
107
|
+
pagination_args: { limit: 10 }
|
|
108
|
+
})
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
#### Create Pool
|
|
112
|
+
|
|
113
|
+
There are two ways to create a pool:
|
|
114
|
+
|
|
115
|
+
**Method 1: Create Pool Only**
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
// Create a new pool without adding liquidity
|
|
119
|
+
const bin_step = 2
|
|
120
|
+
const base_factor = 10000
|
|
121
|
+
const price = '1.1'
|
|
122
|
+
const active_id = BinUtils.getBinIdFromPrice(price, bin_step, true, 6, 6)
|
|
123
|
+
|
|
124
|
+
const tx = new Transaction()
|
|
125
|
+
await sdk.Pool.createPoolPayload({
|
|
126
|
+
active_id,
|
|
127
|
+
bin_step,
|
|
128
|
+
coin_type_a: '0x...::usdc::USDC',
|
|
129
|
+
coin_type_b: '0x...::usdt::USDT',
|
|
130
|
+
base_factor,
|
|
131
|
+
}, tx)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Method 2: Create Pool and Add Liquidity in One Transaction**
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
// Create pool and add liquidity in one transaction
|
|
138
|
+
const bin_step = 2
|
|
139
|
+
const base_factor = 10000
|
|
140
|
+
const price = '1.1'
|
|
141
|
+
const active_id = BinUtils.getBinIdFromPrice(price, bin_step, true, 6, 6)
|
|
142
|
+
|
|
143
|
+
// Calculate liquidity distribution
|
|
144
|
+
const bin_infos = sdk.Position.calculateAddLiquidityInfo({
|
|
145
|
+
active_id,
|
|
146
|
+
bin_step,
|
|
147
|
+
lower_bin_id: active_id - 10,
|
|
148
|
+
upper_bin_id: active_id + 10,
|
|
149
|
+
amount_a_in_active_bin: '0',
|
|
150
|
+
amount_b_in_active_bin: '0',
|
|
151
|
+
strategy_type: StrategyType.Spot,
|
|
152
|
+
coin_amount: '10000000',
|
|
153
|
+
fix_amount_a: true,
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
const createAndAddTx = await sdk.Pool.createPoolAndAddLiquidityPayload({
|
|
157
|
+
active_id,
|
|
158
|
+
lower_bin_id: active_id - 10,
|
|
159
|
+
upper_bin_id: active_id + 10,
|
|
160
|
+
bin_step,
|
|
161
|
+
bin_infos,
|
|
162
|
+
coin_type_a: '0x14a71d857b34677a7d57e0feb303df1adb515a37780645ab763d42ce8d1a5e48::usdc::USDC',
|
|
163
|
+
coin_type_b: '0x14a71d857b34677a7d57e0feb303df1adb515a37780645ab763d42ce8d1a5e48::eth::ETH',
|
|
164
|
+
strategy_type: StrategyType.Spot,
|
|
165
|
+
use_bin_infos: false,
|
|
166
|
+
base_factor,
|
|
167
|
+
})
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### 2. Position Operations
|
|
171
|
+
|
|
172
|
+
#### Get Position Information
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
// Get owner's position list
|
|
176
|
+
const positions = await sdk.Position.getOwnerPositionList(wallet)
|
|
177
|
+
|
|
178
|
+
// Get specific position
|
|
179
|
+
const position = await sdk.Position.getPosition(position_id)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### 3. Fee Operations
|
|
183
|
+
|
|
184
|
+
#### Fee and Reward Calculation
|
|
185
|
+
|
|
186
|
+
To calculate fees and rewards for a position, you can use the `fetchPositionFeeAndReward` method. This method allows you to get both fee and reward data for one or multiple positions:
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
// First get the pool information
|
|
190
|
+
const pool = await sdk.Pool.getPool(pool_id)
|
|
191
|
+
const { id, coin_type_a, coin_type_b, reward_manager } = pool
|
|
192
|
+
|
|
193
|
+
// Fetch fee and reward data
|
|
194
|
+
const { feeData, rewardData } = await sdk.Position.fetchPositionFeeAndReward([
|
|
195
|
+
{
|
|
196
|
+
pool_id: id,
|
|
197
|
+
position_id: position_id,
|
|
198
|
+
reward_coins: reward_manager.rewards.map((reward) => reward.reward_coin),
|
|
199
|
+
coin_type_a,
|
|
200
|
+
coin_type_b,
|
|
201
|
+
},
|
|
202
|
+
])
|
|
203
|
+
|
|
204
|
+
// feeData structure
|
|
205
|
+
// {
|
|
206
|
+
// [position_id]: {
|
|
207
|
+
// position_id: string,
|
|
208
|
+
// fee_owned_a: string, // Amount of token A fees owned
|
|
209
|
+
// fee_owned_b: string // Amount of token B fees owned
|
|
210
|
+
// }
|
|
211
|
+
// }
|
|
212
|
+
|
|
213
|
+
// rewardData structure
|
|
214
|
+
// {
|
|
215
|
+
// [position_id]: {
|
|
216
|
+
// position_id: string,
|
|
217
|
+
// rewards: {
|
|
218
|
+
// [coin_type]: string // Amount of reward tokens owned
|
|
219
|
+
// }
|
|
220
|
+
// }
|
|
221
|
+
// }
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
#### Fee Collection
|
|
225
|
+
|
|
226
|
+
You can collect fees from your positions in several ways:
|
|
227
|
+
|
|
228
|
+
1. **Collect Fees and Rewards Together**:
|
|
229
|
+
```typescript
|
|
230
|
+
// Build collect fee and reward transaction
|
|
231
|
+
const tx = await sdk.Position.collectRewardAndFeePayload([{
|
|
232
|
+
pool_id,
|
|
233
|
+
position_id,
|
|
234
|
+
reward_coins: reward_manager.rewards.map((reward) => reward.reward_coin),
|
|
235
|
+
coin_type_a,
|
|
236
|
+
coin_type_b
|
|
237
|
+
}])
|
|
238
|
+
|
|
239
|
+
// Simulate or send the transaction
|
|
240
|
+
const sim_result = await sdk.FullClient.sendSimulationTransaction(tx, wallet)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### 4. Liquidity Operations
|
|
244
|
+
|
|
245
|
+
#### Add Liquidity
|
|
246
|
+
|
|
247
|
+
There are three strategies for adding liquidity: Spot, BidAsk, and Curve. Here's how to use each:
|
|
248
|
+
|
|
249
|
+
1. **Spot Strategy**:
|
|
250
|
+
```typescript
|
|
251
|
+
// Get pool information
|
|
252
|
+
const pool = await sdk.Pool.getPool(pool_id)
|
|
253
|
+
const { active_id, bin_step, bin_manager } = pool
|
|
254
|
+
|
|
255
|
+
// Get amounts in active bin if it's within the range
|
|
256
|
+
const amounts_in_active_bin = await sdk.Position.getActiveBinIfInRange(
|
|
257
|
+
bin_manager.bin_manager_handle,
|
|
258
|
+
lower_bin_id,
|
|
259
|
+
upper_bin_id,
|
|
260
|
+
active_id,
|
|
261
|
+
bin_step
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
// Calculate liquidity distribution
|
|
265
|
+
const calculateOption = {
|
|
266
|
+
amount_a: '1000000',
|
|
267
|
+
amount_b: '1200000',
|
|
268
|
+
active_id,
|
|
269
|
+
bin_step,
|
|
270
|
+
lower_bin_id: -10,
|
|
271
|
+
upper_bin_id: 10,
|
|
272
|
+
amount_a_in_active_bin: amounts_in_active_bin?.amount_a || '0',
|
|
273
|
+
amount_b_in_active_bin: amounts_in_active_bin?.amount_b || '0',
|
|
274
|
+
strategy_type: StrategyType.Spot
|
|
275
|
+
}
|
|
276
|
+
const bin_infos = sdk.Position.calculateAddLiquidityInfo(calculateOption)
|
|
277
|
+
|
|
278
|
+
// For new position
|
|
279
|
+
const addOption = {
|
|
280
|
+
pool_id,
|
|
281
|
+
bin_infos,
|
|
282
|
+
coin_type_a: pool.coin_type_a,
|
|
283
|
+
coin_type_b: pool.coin_type_b,
|
|
284
|
+
lower_bin_id: -10,
|
|
285
|
+
upper_bin_id: 10,
|
|
286
|
+
active_id
|
|
287
|
+
}
|
|
288
|
+
const tx = sdk.Position.addLiquidityPayload(addOption)
|
|
289
|
+
|
|
290
|
+
// For existing position
|
|
291
|
+
const addOption = {
|
|
292
|
+
pool_id,
|
|
293
|
+
bin_infos,
|
|
294
|
+
coin_type_a: pool.coin_type_a,
|
|
295
|
+
coin_type_b: pool.coin_type_b,
|
|
296
|
+
active_id,
|
|
297
|
+
position_id,
|
|
298
|
+
collect_fee: true,
|
|
299
|
+
reward_coins: []
|
|
300
|
+
}
|
|
301
|
+
const tx = sdk.Position.addLiquidityPayload(addOption)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Note: The `amount_a_in_active_bin` and `amount_b_in_active_bin` parameters are used to calculate the correct liquidity distribution when the active bin is within your position's range. These values are obtained using the `getActiveBinIfInRange` method, which:
|
|
305
|
+
1. Checks if the active bin is within your specified range
|
|
306
|
+
2. Returns the amounts of both tokens in the active bin if it is within range
|
|
307
|
+
3. Returns undefined if the active bin is outside the range
|
|
308
|
+
|
|
309
|
+
2. **BidAsk Strategy**:
|
|
310
|
+
```typescript
|
|
311
|
+
// Similar to Spot strategy but with different strategy_type
|
|
312
|
+
const calculateOption = {
|
|
313
|
+
amount_a: '1000000',
|
|
314
|
+
amount_b: '1200000',
|
|
315
|
+
active_id,
|
|
316
|
+
bin_step,
|
|
317
|
+
lower_bin_id: -10,
|
|
318
|
+
upper_bin_id: 10,
|
|
319
|
+
amount_a_in_active_bin: '0',
|
|
320
|
+
amount_b_in_active_bin: '0',
|
|
321
|
+
strategy_type: StrategyType.BidAsk
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
3. **Curve Strategy**:
|
|
326
|
+
```typescript
|
|
327
|
+
// Similar to Spot strategy but with different strategy_type
|
|
328
|
+
const calculateOption = {
|
|
329
|
+
amount_a: '1000000',
|
|
330
|
+
amount_b: '1200000',
|
|
331
|
+
active_id,
|
|
332
|
+
bin_step,
|
|
333
|
+
lower_bin_id: -10,
|
|
334
|
+
upper_bin_id: 10,
|
|
335
|
+
amount_a_in_active_bin: '0',
|
|
336
|
+
amount_b_in_active_bin: '0',
|
|
337
|
+
strategy_type: StrategyType.Curve
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
4. **Fixed Amount Strategy**:
|
|
342
|
+
```typescript
|
|
343
|
+
// Calculate with fixed amount of one token
|
|
344
|
+
const calculateOption = {
|
|
345
|
+
coin_amount: '1000000',
|
|
346
|
+
fix_amount_a: true, // true for token A, false for token B
|
|
347
|
+
active_id,
|
|
348
|
+
bin_step,
|
|
349
|
+
lower_bin_id: -10,
|
|
350
|
+
upper_bin_id: 10,
|
|
351
|
+
amount_a_in_active_bin: '0',
|
|
352
|
+
amount_b_in_active_bin: '0',
|
|
353
|
+
strategy_type: StrategyType.Spot // or BidAsk or Curve
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
5. **Add Liquidity with Price**:
|
|
358
|
+
```typescript
|
|
359
|
+
// Add liquidity with specific price range
|
|
360
|
+
const addOption = {
|
|
361
|
+
pool_id,
|
|
362
|
+
bin_infos,
|
|
363
|
+
coin_type_a: pool.coin_type_a,
|
|
364
|
+
coin_type_b: pool.coin_type_b,
|
|
365
|
+
price_base_coin: 'coin_a',
|
|
366
|
+
price: price.toString(),
|
|
367
|
+
lower_price,
|
|
368
|
+
upper_price,
|
|
369
|
+
bin_step,
|
|
370
|
+
amount_a_in_active_bin: amounts_in_active_bin?.amount_a || '0',
|
|
371
|
+
amount_b_in_active_bin: amounts_in_active_bin?.amount_b || '0',
|
|
372
|
+
strategy_type: StrategyType.Spot,
|
|
373
|
+
decimals_a: 6,
|
|
374
|
+
decimals_b: 6,
|
|
375
|
+
max_bin_slippage: 0.01,
|
|
376
|
+
}
|
|
377
|
+
const tx = sdk.Position.addLiquidityWithPricePayload(addOption)
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
#### Remove Liquidity
|
|
381
|
+
|
|
382
|
+
There are two ways to remove liquidity:
|
|
383
|
+
|
|
384
|
+
1. **Remove with Both Amounts**:
|
|
385
|
+
```typescript
|
|
386
|
+
// Get position and pool information
|
|
387
|
+
const pool = await sdk.Pool.getPool(pool_id)
|
|
388
|
+
const position = await sdk.Position.getPosition(position_id)
|
|
389
|
+
const { active_id, bin_step, bin_manager } = pool
|
|
390
|
+
|
|
391
|
+
// Get active bin information
|
|
392
|
+
const active_bin = await sdk.Pool.getBinInfo(bin_manager.bin_manager_handle, active_id, bin_step)
|
|
393
|
+
const liquidity_shares_data = parseLiquidityShares(position.liquidity_shares, bin_step, position.lower_bin_id, active_bin)
|
|
394
|
+
|
|
395
|
+
// Calculate removal amounts
|
|
396
|
+
const calculateOption = {
|
|
397
|
+
bins: liquidity_shares_data.bins,
|
|
398
|
+
active_id,
|
|
399
|
+
fix_amount_a: true,
|
|
400
|
+
coin_amount: '100000'
|
|
401
|
+
}
|
|
402
|
+
const bin_infos = sdk.Position.calculateRemoveLiquidityInfo(calculateOption)
|
|
403
|
+
|
|
404
|
+
// Build and send transaction
|
|
405
|
+
const removeOption = {
|
|
406
|
+
pool_id,
|
|
407
|
+
bin_infos,
|
|
408
|
+
coin_type_a: pool.coin_type_a,
|
|
409
|
+
coin_type_b: pool.coin_type_b,
|
|
410
|
+
position_id,
|
|
411
|
+
slippage: 0.01,
|
|
412
|
+
reward_coins: []
|
|
413
|
+
}
|
|
414
|
+
const tx = sdk.Position.removeLiquidityPayload(removeOption)
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
2. **Remove Only One Token**:
|
|
418
|
+
```typescript
|
|
419
|
+
const calculateOption = {
|
|
420
|
+
bins: liquidity_shares_data.bins,
|
|
421
|
+
active_id,
|
|
422
|
+
is_only_a: true, // true for token A, false for token B
|
|
423
|
+
coin_amount: '100000'
|
|
424
|
+
}
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
#### Close Position
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
// Close position (This will collect all fees, rewards and remove all liquidity)
|
|
431
|
+
const tx = sdk.Position.closePositionPayload({
|
|
432
|
+
pool_id,
|
|
433
|
+
position_id,
|
|
434
|
+
coin_type_a,
|
|
435
|
+
coin_type_b,
|
|
436
|
+
reward_coins: pool.reward_manager.rewards.map(reward => reward.reward_coin) // Required: Must include all reward coin types from the pool
|
|
437
|
+
})
|
|
438
|
+
|
|
439
|
+
// Simulate or send the transaction
|
|
440
|
+
const sim_result = await sdk.FullClient.sendSimulationTransaction(tx, wallet)
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
Note: Closing a position will:
|
|
444
|
+
1. Collect all accumulated fees
|
|
445
|
+
2. Collect all pending rewards (must include all reward coins from the pool)
|
|
446
|
+
3. Remove all liquidity from the position
|
|
447
|
+
4. Delete the position
|
|
448
|
+
|
|
449
|
+
### 5. Swap Operations
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
// Get pool information
|
|
453
|
+
const pool = await sdk.Pool.getPool(pool_id)
|
|
454
|
+
const { coin_type_a, coin_type_b } = pool
|
|
455
|
+
|
|
456
|
+
// Get swap quote
|
|
457
|
+
const quote_obj = await sdk.Swap.preSwapQuote({
|
|
458
|
+
pool_id,
|
|
459
|
+
a2b: true, // true for A to B, false for B to A
|
|
460
|
+
by_amount_in: true, // true for exact input, false for exact output
|
|
461
|
+
in_amount: '2000000',
|
|
462
|
+
coin_type_a,
|
|
463
|
+
coin_type_b
|
|
464
|
+
})
|
|
465
|
+
|
|
466
|
+
// Build and send swap transaction
|
|
467
|
+
const tx = sdk.Swap.swapPayload({
|
|
468
|
+
coin_type_a,
|
|
469
|
+
coin_type_b,
|
|
470
|
+
quote_obj,
|
|
471
|
+
by_amount_in: true,
|
|
472
|
+
slippage: 0.01
|
|
473
|
+
})
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### 6. Partner Operations
|
|
477
|
+
|
|
478
|
+
#### Partner Management
|
|
479
|
+
|
|
480
|
+
```typescript
|
|
481
|
+
// Get partner list
|
|
482
|
+
const partnerList = await sdk.Partner.getPartnerList()
|
|
483
|
+
|
|
484
|
+
// Get specific partner
|
|
485
|
+
const partner = await sdk.Partner.getPartner(partner_id)
|
|
486
|
+
|
|
487
|
+
// Get partner capability ID
|
|
488
|
+
const partnerCapId = await sdk.Partner.getPartnerCapId(account, partner_id)
|
|
489
|
+
|
|
490
|
+
// Get partner balance
|
|
491
|
+
const partnerBalance = await sdk.Partner.getPartnerBalance(partner_id)
|
|
492
|
+
|
|
493
|
+
// Create partner
|
|
494
|
+
const start_time = Math.floor(Date.now() / 1000) + 5000
|
|
495
|
+
const tx = sdk.Partner.createPartnerPayload({
|
|
496
|
+
name: 'test partner',
|
|
497
|
+
ref_fee_rate: 0.01,
|
|
498
|
+
start_time,
|
|
499
|
+
end_time: start_time + 9 * 24 * 3600,
|
|
500
|
+
recipient: account,
|
|
501
|
+
})
|
|
502
|
+
|
|
503
|
+
// Update referral fee rate
|
|
504
|
+
const updateFeeTx = await sdk.Partner.updateRefFeeRatePayload({
|
|
505
|
+
partner_id: '0x9d171399393e3cbedffc24269eb606e735fb56fee17c15153eb5e2d5274a3677',
|
|
506
|
+
ref_fee_rate: 0.02,
|
|
507
|
+
})
|
|
508
|
+
|
|
509
|
+
// Update time range
|
|
510
|
+
const start_time = Math.floor(Date.now() / 1000)
|
|
511
|
+
const updateTimeTx = await sdk.Partner.updateTimeRangePayload({
|
|
512
|
+
partner_id: '0x9d171399393e3cbedffc24269eb606e735fb56fee17c15153eb5e2d5274a3677',
|
|
513
|
+
start_time,
|
|
514
|
+
end_time: start_time + 10 * 7 * 24 * 3600,
|
|
515
|
+
})
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### 7. Reward Operations
|
|
519
|
+
|
|
520
|
+
#### Reward Management
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
// Initialize rewards for a pool
|
|
524
|
+
const initTx = sdk.Reward.initRewardPayload({
|
|
525
|
+
pool_id,
|
|
526
|
+
reward_coin_types: ['0x2::sui::SUI', '0x5::usdc::USDC']
|
|
527
|
+
})
|
|
528
|
+
|
|
529
|
+
// Add reward to a pool
|
|
530
|
+
const addRewardTx = sdk.Reward.addRewardPayload({
|
|
531
|
+
pool_id,
|
|
532
|
+
reward_coin_type: '0x2::sui::SUI',
|
|
533
|
+
reward_amount: '1000000',
|
|
534
|
+
end_time_seconds: Math.floor(Date.now() / 1000) + 30 * 24 * 3600, // 30 days
|
|
535
|
+
start_time_seconds: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
|
|
536
|
+
})
|
|
537
|
+
|
|
538
|
+
// Update reward access (public/private)
|
|
539
|
+
const accessTx = sdk.Reward.updateRewardAccessPayload({
|
|
540
|
+
pool_id,
|
|
541
|
+
type: 'to_public', // or 'to_private'
|
|
542
|
+
})
|
|
543
|
+
|
|
544
|
+
// Manage reward whitelist
|
|
545
|
+
const whitelistTx = sdk.Reward.updateRewardWhiteListPayload({
|
|
546
|
+
reward_coin_types: ['0x2::sui::SUI'],
|
|
547
|
+
type: 'add' // or 'remove'
|
|
548
|
+
})
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
### 8. Bin Operations
|
|
552
|
+
|
|
553
|
+
The SDK provides utility functions for working with bins and prices through the `BinUtils` class:
|
|
554
|
+
|
|
555
|
+
```typescript
|
|
556
|
+
import { BinUtils } from '@cetusprotocol/dlmm-sdk'
|
|
557
|
+
|
|
558
|
+
// Convert price to bin ID
|
|
559
|
+
const binId = BinUtils.getBinIdFromPrice(
|
|
560
|
+
'1040.07', // price
|
|
561
|
+
2, // bin step
|
|
562
|
+
true, // is base coin A
|
|
563
|
+
6, // decimals for coin A
|
|
564
|
+
9 // decimals for coin B
|
|
565
|
+
)
|
|
566
|
+
|
|
567
|
+
// Convert bin ID to price
|
|
568
|
+
const price = BinUtils.getPriceFromBinId(
|
|
569
|
+
-4787, // bin ID
|
|
570
|
+
2, // bin step
|
|
571
|
+
6, // decimals for coin A
|
|
572
|
+
9 // decimals for coin B
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
// Get Q price from bin ID
|
|
576
|
+
const q_price = BinUtils.getQPriceFromId(
|
|
577
|
+
-4400, // bin ID
|
|
578
|
+
100 // bin step
|
|
579
|
+
)
|
|
580
|
+
|
|
581
|
+
// Get price per lamport from Q price
|
|
582
|
+
const price_per_lamport = BinUtils.getPricePerLamportFromQPrice(q_price)
|
|
583
|
+
|
|
584
|
+
// Get liquidity from amounts
|
|
585
|
+
const liquidity = BinUtils.getLiquidity('0', '266666', '18431994054197767090')
|
|
586
|
+
|
|
587
|
+
// Get amount A from liquidity
|
|
588
|
+
const amountA = BinUtils.getAmountAFromLiquidity('4101094304427826916657468', '18461505896777422276')
|
|
589
|
+
|
|
590
|
+
// Get amount B from liquidity
|
|
591
|
+
const amountB = BinUtils.getAmountBFromLiquidity('4919119455159831291232256')
|
|
592
|
+
|
|
593
|
+
// Get amounts from liquidity with ratio
|
|
594
|
+
const [amountA, amountB] = BinUtils.getAmountsFromLiquidityWithRatio(
|
|
595
|
+
'4510099798813469403250688',
|
|
596
|
+
'18446744073709551616',
|
|
597
|
+
0.9 // ratio
|
|
598
|
+
)
|
|
599
|
+
|
|
600
|
+
// Split bin liquidity info
|
|
601
|
+
const split_bin_infos = BinUtils.splitBinLiquidityInfo(bin_infos, 0, 70)
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
These utility functions are particularly useful when:
|
|
605
|
+
- Setting up price ranges for liquidity positions
|
|
606
|
+
- Calculating optimal bin ranges for trading strategies
|
|
607
|
+
- Converting between different price representations
|
|
608
|
+
- Managing liquidity distributions across bins
|
|
609
|
+
|
|
610
|
+
### 9. Advanced Operations
|
|
611
|
+
|
|
612
|
+
#### Validate Active ID Slippage
|
|
613
|
+
|
|
614
|
+
```typescript
|
|
615
|
+
// Validate that the active ID hasn't moved too much
|
|
616
|
+
const isValid = await sdk.Position.validateActiveIdSlippage({
|
|
617
|
+
pool_id,
|
|
618
|
+
active_id,
|
|
619
|
+
max_bin_slippage: 0.01
|
|
620
|
+
})
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
#### Update Position Fee and Rewards
|
|
624
|
+
|
|
625
|
+
```typescript
|
|
626
|
+
// Update position fee and reward information
|
|
627
|
+
await sdk.Position.updatePositionFeeAndRewards({
|
|
628
|
+
pool_id,
|
|
629
|
+
position_id,
|
|
630
|
+
coin_type_a,
|
|
631
|
+
coin_type_b
|
|
632
|
+
})
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
## More About Cetus
|
|
636
|
+
|
|
637
|
+
Use the following links to learn more about Cetus:
|
|
638
|
+
|
|
639
|
+
Learn more about working with Cetus in the [Cetus Documentation](https://cetus-1.gitbook.io/cetus-docs).
|
|
640
|
+
|
|
641
|
+
Join the Cetus community on [Cetus Discord](https://discord.com/channels/1009749448022315008/1009751382783447072).
|
|
642
|
+
|
|
643
|
+
## License
|
|
644
|
+
|
|
645
|
+
MIT
|
|
646
|
+
|