@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,389 @@
|
|
|
1
|
+
import { Transaction, TransactionObjectArgument } from '@mysten/sui/transactions'
|
|
2
|
+
import { normalizeSuiAddress } from '@mysten/sui/utils'
|
|
3
|
+
import BN from 'bn.js'
|
|
4
|
+
import { d, DETAILS_KEYS, extractStructTagFromType, IModule, TickMath, U64_MAX, ZERO } from '@cetusprotocol/common-sdk'
|
|
5
|
+
import Decimal from 'decimal.js'
|
|
6
|
+
import { ConfigErrorCode, handleMessageError, SwapErrorCode } from '../errors/errors'
|
|
7
|
+
import { CetusClmmSDK } from '../sdk'
|
|
8
|
+
import {
|
|
9
|
+
CalculateRatesParams,
|
|
10
|
+
CalculateRatesResult,
|
|
11
|
+
PreSwapParams,
|
|
12
|
+
PreSwapWithMultiPoolParams,
|
|
13
|
+
SwapGasEstimateArg,
|
|
14
|
+
SwapParams,
|
|
15
|
+
TransPreSwapWithMultiPoolParams,
|
|
16
|
+
} from '../types/clmm_type'
|
|
17
|
+
import { computeSwap, SplitPath, transClmmpoolDataWithoutTicks } from '../types/clmmpool'
|
|
18
|
+
import { ClmmFetcherModule } from '../types/sui'
|
|
19
|
+
import { findAdjustCoin } from '../utils/positionUtils'
|
|
20
|
+
import { SwapUtils } from '../utils/swapUtils'
|
|
21
|
+
export const AMM_SWAP_MODULE = 'amm_swap'
|
|
22
|
+
export const POOL_STRUCT = 'Pool'
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Helper class to help interact with clmm pool swap with a swap router interface.
|
|
26
|
+
*/
|
|
27
|
+
export class SwapModule implements IModule<CetusClmmSDK> {
|
|
28
|
+
protected _sdk: CetusClmmSDK
|
|
29
|
+
|
|
30
|
+
constructor(sdk: CetusClmmSDK) {
|
|
31
|
+
this._sdk = sdk
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get sdk() {
|
|
35
|
+
return this._sdk
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
calculateSwapFee(paths: SplitPath[]) {
|
|
39
|
+
let fee = d(0)
|
|
40
|
+
paths.forEach((item) => {
|
|
41
|
+
const pathCount = item.base_paths.length
|
|
42
|
+
if (pathCount > 0) {
|
|
43
|
+
const path = item.base_paths[0]
|
|
44
|
+
const fee_rate = path.label === 'Cetus' ? new Decimal(path.fee_rate).div(10 ** 6) : new Decimal(path.fee_rate).div(10 ** 9)
|
|
45
|
+
const feeAmount = d(path.input_amount)
|
|
46
|
+
.div(10 ** path.from_decimal)
|
|
47
|
+
.mul(fee_rate)
|
|
48
|
+
fee = fee.add(feeAmount)
|
|
49
|
+
if (pathCount > 1) {
|
|
50
|
+
const path2 = item.base_paths[1]
|
|
51
|
+
const price1 = path.direction ? path.current_price : new Decimal(1).div(path.current_price)
|
|
52
|
+
const price2 = path2.direction ? path2.current_price : new Decimal(1).div(path2.current_price)
|
|
53
|
+
const feeRate2 = path2.label === 'Cetus' ? new Decimal(path2.fee_rate).div(10 ** 6) : new Decimal(path2.fee_rate).div(10 ** 9)
|
|
54
|
+
|
|
55
|
+
const feeAmount2 = d(path2.output_amount)
|
|
56
|
+
.div(10 ** path2.to_decimal)
|
|
57
|
+
.mul(feeRate2)
|
|
58
|
+
const fee2 = feeAmount2.div(price1.mul(price2))
|
|
59
|
+
fee = fee.add(fee2)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
return fee.toString()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
calculateSwapPriceImpact(paths: SplitPath[]) {
|
|
68
|
+
let impactValue = d(0)
|
|
69
|
+
paths.forEach((item) => {
|
|
70
|
+
const pathCount = item.base_paths.length
|
|
71
|
+
if (pathCount === 1) {
|
|
72
|
+
const path = item.base_paths[0]
|
|
73
|
+
const output_amount = d(path.output_amount).div(10 ** path.to_decimal)
|
|
74
|
+
const input_amount = d(path.input_amount).div(10 ** path.from_decimal)
|
|
75
|
+
const rate = output_amount.div(input_amount)
|
|
76
|
+
const cprice = path.direction ? new Decimal(path.current_price) : new Decimal(1).div(path.current_price)
|
|
77
|
+
impactValue = impactValue.add(this.calculateSingleImpact(rate, cprice))
|
|
78
|
+
}
|
|
79
|
+
if (pathCount === 2) {
|
|
80
|
+
const path = item.base_paths[0]
|
|
81
|
+
const path2 = item.base_paths[1]
|
|
82
|
+
const cprice1 = path.direction ? new Decimal(path.current_price) : new Decimal(1).div(path.current_price)
|
|
83
|
+
const cprice2 = path2.direction ? new Decimal(path2.current_price) : new Decimal(1).div(path2.current_price)
|
|
84
|
+
const cprice = cprice1.mul(cprice2)
|
|
85
|
+
const output_amount = new Decimal(path2.output_amount).div(10 ** path2.to_decimal)
|
|
86
|
+
const input_amount = new Decimal(path.input_amount).div(10 ** path.from_decimal)
|
|
87
|
+
const rate = output_amount.div(input_amount)
|
|
88
|
+
impactValue = impactValue.add(this.calculateSingleImpact(rate, cprice))
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
return impactValue.toString()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private calculateSingleImpact = (rate: Decimal, c_price: Decimal) => {
|
|
96
|
+
// ((cprice - rate)/cprice)*100
|
|
97
|
+
return c_price.minus(rate).div(c_price).mul(100)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Performs a pre-swap with multiple pools.
|
|
102
|
+
*
|
|
103
|
+
* @param {PreSwapWithMultiPoolParams} params The parameters for the pre-swap.
|
|
104
|
+
* @returns {Promise<SwapWithMultiPoolData>} A promise that resolves to the swap data.
|
|
105
|
+
*/
|
|
106
|
+
async preSwapWithMultiPool(params: PreSwapWithMultiPoolParams) {
|
|
107
|
+
const { integrate } = this.sdk.sdkOptions
|
|
108
|
+
const tx = new Transaction()
|
|
109
|
+
|
|
110
|
+
const typeArguments = [params.coin_type_a, params.coin_type_b]
|
|
111
|
+
for (let i = 0; i < params.pool_ids.length; i += 1) {
|
|
112
|
+
const args = [tx.object(params.pool_ids[i]), tx.pure.bool(params.a2b), tx.pure.bool(params.by_amount_in), tx.pure.u64(params.amount)]
|
|
113
|
+
tx.moveCall({
|
|
114
|
+
target: `${integrate.published_at}::${ClmmFetcherModule}::calculate_swap_result`,
|
|
115
|
+
arguments: args,
|
|
116
|
+
typeArguments,
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const simulateRes = await this.sdk.FullClient.devInspectTransactionBlock({
|
|
121
|
+
transactionBlock: tx,
|
|
122
|
+
sender: normalizeSuiAddress('0x0'),
|
|
123
|
+
})
|
|
124
|
+
if (simulateRes.error != null) {
|
|
125
|
+
handleMessageError(
|
|
126
|
+
ConfigErrorCode.InvalidConfig,
|
|
127
|
+
`pre swap with multi pools error code: ${simulateRes.error ?? 'unknown error'}, please check config and params`,
|
|
128
|
+
{
|
|
129
|
+
[DETAILS_KEYS.METHOD_NAME]: 'preSwapWithMultiPool',
|
|
130
|
+
[DETAILS_KEYS.REQUEST_PARAMS]: {
|
|
131
|
+
params,
|
|
132
|
+
},
|
|
133
|
+
}
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const valueData: any = simulateRes.events?.filter((item: any) => {
|
|
138
|
+
return extractStructTagFromType(item.type).name === `CalculatedSwapResultEvent`
|
|
139
|
+
})
|
|
140
|
+
if (valueData.length === 0) {
|
|
141
|
+
return null
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (valueData.length !== params.pool_ids.length) {
|
|
145
|
+
handleMessageError(SwapErrorCode.ParamsLengthNotEqual, 'valueData.length !== params.pools.length', {
|
|
146
|
+
[DETAILS_KEYS.METHOD_NAME]: 'preSwapWithMultiPool',
|
|
147
|
+
[DETAILS_KEYS.REQUEST_PARAMS]: {
|
|
148
|
+
params,
|
|
149
|
+
},
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
let tempMaxAmount = params.by_amount_in ? ZERO : U64_MAX
|
|
153
|
+
let tempIndex = 0
|
|
154
|
+
for (let i = 0; i < valueData.length; i += 1) {
|
|
155
|
+
if (valueData[i].parsedJson.data.is_exceed) {
|
|
156
|
+
continue
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (params.by_amount_in) {
|
|
160
|
+
const amount = new BN(valueData[i].parsedJson.data.amount_out)
|
|
161
|
+
if (amount.gt(tempMaxAmount)) {
|
|
162
|
+
tempIndex = i
|
|
163
|
+
tempMaxAmount = amount
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
const amount = new BN(valueData[i].parsedJson.data.amount_out)
|
|
167
|
+
if (amount.lt(tempMaxAmount)) {
|
|
168
|
+
tempIndex = i
|
|
169
|
+
tempMaxAmount = amount
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return this.transformSwapWithMultiPoolData(
|
|
175
|
+
{
|
|
176
|
+
pool_address: params.pool_ids[tempIndex],
|
|
177
|
+
a2b: params.a2b,
|
|
178
|
+
by_amount_in: params.by_amount_in,
|
|
179
|
+
amount: params.amount,
|
|
180
|
+
coin_type_a: params.coin_type_a,
|
|
181
|
+
coin_type_b: params.coin_type_b,
|
|
182
|
+
},
|
|
183
|
+
valueData[tempIndex].parsedJson
|
|
184
|
+
)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Performs a pre-swap.
|
|
189
|
+
*
|
|
190
|
+
* @param {PreSwapParams} params The parameters for the pre-swap.
|
|
191
|
+
* @returns {Promise<PreSwapParams>} A promise that resolves to the swap data.
|
|
192
|
+
*/
|
|
193
|
+
async preSwap(params: PreSwapParams) {
|
|
194
|
+
const { integrate } = this.sdk.sdkOptions
|
|
195
|
+
|
|
196
|
+
const tx = new Transaction()
|
|
197
|
+
|
|
198
|
+
const typeArguments = [params.coin_type_a, params.coin_type_b]
|
|
199
|
+
const args = [tx.object(params.pool.id), tx.pure.bool(params.a2b), tx.pure.bool(params.by_amount_in), tx.pure.u64(params.amount)]
|
|
200
|
+
|
|
201
|
+
tx.moveCall({
|
|
202
|
+
target: `${integrate.published_at}::${ClmmFetcherModule}::calculate_swap_result`,
|
|
203
|
+
arguments: args,
|
|
204
|
+
typeArguments,
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
const simulateRes = await this.sdk.FullClient.devInspectTransactionBlock({
|
|
208
|
+
transactionBlock: tx,
|
|
209
|
+
sender: normalizeSuiAddress('0x0'),
|
|
210
|
+
})
|
|
211
|
+
if (simulateRes.error != null) {
|
|
212
|
+
return handleMessageError(
|
|
213
|
+
ConfigErrorCode.InvalidConfig,
|
|
214
|
+
`preSwap error code: ${simulateRes.error ?? 'unknown error'}, please check config and params`,
|
|
215
|
+
{
|
|
216
|
+
[DETAILS_KEYS.METHOD_NAME]: 'preSwap',
|
|
217
|
+
[DETAILS_KEYS.REQUEST_PARAMS]: {
|
|
218
|
+
params,
|
|
219
|
+
},
|
|
220
|
+
}
|
|
221
|
+
)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const valueData: any = simulateRes.events?.filter((item: any) => {
|
|
225
|
+
return extractStructTagFromType(item.type).name === `CalculatedSwapResultEvent`
|
|
226
|
+
})
|
|
227
|
+
if (valueData.length === 0) {
|
|
228
|
+
return handleMessageError(
|
|
229
|
+
ConfigErrorCode.InvalidConfig,
|
|
230
|
+
`preSwap error code: ${simulateRes.error ?? 'unknown error'}, please check config and params`,
|
|
231
|
+
{
|
|
232
|
+
[DETAILS_KEYS.METHOD_NAME]: 'preSwap',
|
|
233
|
+
[DETAILS_KEYS.REQUEST_PARAMS]: {
|
|
234
|
+
params,
|
|
235
|
+
},
|
|
236
|
+
}
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
return this.transformSwapData(params, valueData[0].parsedJson.data)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
private transformSwapData(params: PreSwapParams, data: any) {
|
|
243
|
+
const estimatedAmountIn = data.amount_in && data.fee_amount ? new BN(data.amount_in).add(new BN(data.fee_amount)).toString() : ''
|
|
244
|
+
return {
|
|
245
|
+
pool_address: params.pool.id,
|
|
246
|
+
current_sqrt_price: params.current_sqrt_price,
|
|
247
|
+
estimated_amount_in: estimatedAmountIn,
|
|
248
|
+
estimated_amount_out: data.amount_out,
|
|
249
|
+
estimated_end_sqrt_price: data.after_sqrt_price,
|
|
250
|
+
estimated_fee_amount: data.fee_amount,
|
|
251
|
+
is_exceed: data.is_exceed,
|
|
252
|
+
amount: params.amount,
|
|
253
|
+
a2b: params.a2b,
|
|
254
|
+
by_amount_in: params.by_amount_in,
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
private transformSwapWithMultiPoolData(params: TransPreSwapWithMultiPoolParams, json_data: any) {
|
|
259
|
+
const { data } = json_data
|
|
260
|
+
|
|
261
|
+
console.log('json data. ', data)
|
|
262
|
+
|
|
263
|
+
const estimatedAmountIn = data.amount_in && data.fee_amount ? new BN(data.amount_in).add(new BN(data.fee_amount)).toString() : ''
|
|
264
|
+
return {
|
|
265
|
+
pool_address: params.pool_address,
|
|
266
|
+
estimated_amount_in: estimatedAmountIn,
|
|
267
|
+
estimated_amount_out: data.amount_out,
|
|
268
|
+
estimated_end_sqrt_price: data.after_sqrt_price,
|
|
269
|
+
estimated_start_sqrt_price: data.step_results[0].current_sqrt_price,
|
|
270
|
+
estimated_fee_amount: data.fee_amount,
|
|
271
|
+
is_exceed: data.is_exceed,
|
|
272
|
+
amount: params.amount,
|
|
273
|
+
a2b: params.a2b,
|
|
274
|
+
by_amount_in: params.by_amount_in,
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Calculates the rates for a swap.
|
|
280
|
+
* @param {CalculateRatesParams} params The parameters for the calculation.
|
|
281
|
+
* @returns {CalculateRatesResult} The results of the calculation.
|
|
282
|
+
*/
|
|
283
|
+
calculateRates(params: CalculateRatesParams): CalculateRatesResult {
|
|
284
|
+
const { current_pool } = params
|
|
285
|
+
const poolData = transClmmpoolDataWithoutTicks(current_pool)
|
|
286
|
+
|
|
287
|
+
let ticks
|
|
288
|
+
if (params.a2b) {
|
|
289
|
+
ticks = params.swap_ticks.sort((a, b) => {
|
|
290
|
+
return b.index - a.index
|
|
291
|
+
})
|
|
292
|
+
} else {
|
|
293
|
+
ticks = params.swap_ticks.sort((a, b) => {
|
|
294
|
+
return a.index - b.index
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const swapResult = computeSwap(params.a2b, params.by_amount_in, params.amount, poolData, ticks)
|
|
299
|
+
|
|
300
|
+
let isExceed = false
|
|
301
|
+
if (params.by_amount_in) {
|
|
302
|
+
isExceed = swapResult.amount_in.lt(params.amount)
|
|
303
|
+
} else {
|
|
304
|
+
isExceed = swapResult.amount_out.lt(params.amount)
|
|
305
|
+
}
|
|
306
|
+
const sqrtPriceLimit = SwapUtils.getDefaultSqrtPriceLimit(params.a2b)
|
|
307
|
+
if (params.a2b && swapResult.next_sqrt_price.lt(sqrtPriceLimit)) {
|
|
308
|
+
isExceed = true
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (!params.a2b && swapResult.next_sqrt_price.gt(sqrtPriceLimit)) {
|
|
312
|
+
isExceed = true
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
let extraComputeLimit = 0
|
|
316
|
+
if (swapResult.cross_tick_num > 6 && swapResult.cross_tick_num < 40) {
|
|
317
|
+
extraComputeLimit = 22000 * (swapResult.cross_tick_num - 6)
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (swapResult.cross_tick_num > 40) {
|
|
321
|
+
isExceed = true
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const prePrice = TickMath.sqrtPriceX64ToPrice(poolData.current_sqrt_price, params.decimals_a, params.decimals_b).toNumber()
|
|
325
|
+
const afterPrice = TickMath.sqrtPriceX64ToPrice(swapResult.next_sqrt_price, params.decimals_a, params.decimals_b).toNumber()
|
|
326
|
+
|
|
327
|
+
const priceImpactPct = (Math.abs(prePrice - afterPrice) / prePrice) * 100
|
|
328
|
+
|
|
329
|
+
return {
|
|
330
|
+
estimated_amount_in: swapResult.amount_in,
|
|
331
|
+
estimated_amount_out: swapResult.amount_out,
|
|
332
|
+
estimated_end_sqrt_price: swapResult.next_sqrt_price,
|
|
333
|
+
estimated_fee_amount: swapResult.fee_amount,
|
|
334
|
+
is_exceed: isExceed,
|
|
335
|
+
extra_compute_limit: extraComputeLimit,
|
|
336
|
+
amount: params.amount,
|
|
337
|
+
a2b: params.a2b,
|
|
338
|
+
by_amount_in: params.by_amount_in,
|
|
339
|
+
price_impact_pct: priceImpactPct,
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* create swap transaction payload
|
|
345
|
+
* @param params
|
|
346
|
+
* @param gas_estimate_arg When the fix input amount is SUI, gasEstimateArg can control whether to recalculate the number of SUI to prevent insufficient gas.
|
|
347
|
+
* If this parameter is not passed, gas estimation is not performed
|
|
348
|
+
* @returns
|
|
349
|
+
*/
|
|
350
|
+
async createSwapPayload(params: SwapParams, gas_estimate_arg?: SwapGasEstimateArg): Promise<Transaction> {
|
|
351
|
+
const all_coin_asset = await this._sdk.FullClient.getOwnerCoinAssets(this.sdk.getSenderAddress())
|
|
352
|
+
|
|
353
|
+
if (gas_estimate_arg) {
|
|
354
|
+
const { is_adjust_coin_a, is_adjust_coin_b } = findAdjustCoin(params)
|
|
355
|
+
|
|
356
|
+
if ((params.a2b && is_adjust_coin_a) || (!params.a2b && is_adjust_coin_b)) {
|
|
357
|
+
const tx = await SwapUtils.buildSwapTransactionForGas(this._sdk, params, all_coin_asset, gas_estimate_arg)
|
|
358
|
+
return tx
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return SwapUtils.buildSwapTransaction(this.sdk, params, all_coin_asset)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* create swap transaction without transfer coins payload
|
|
367
|
+
* @param params
|
|
368
|
+
* @param gas_estimate_arg When the fix input amount is SUI, gasEstimateArg can control whether to recalculate the number of SUI to prevent insufficient gas.
|
|
369
|
+
* If this parameter is not passed, gas estimation is not performed
|
|
370
|
+
* @returns tx and coin ABs
|
|
371
|
+
*/
|
|
372
|
+
async createSwapWithoutTransferCoinsPayload(
|
|
373
|
+
params: SwapParams,
|
|
374
|
+
gas_estimate_arg?: SwapGasEstimateArg
|
|
375
|
+
): Promise<{ tx: Transaction; coin_ab_s: TransactionObjectArgument[] }> {
|
|
376
|
+
const all_coin_asset = await this._sdk.FullClient.getOwnerCoinAssets(this.sdk.getSenderAddress())
|
|
377
|
+
|
|
378
|
+
if (gas_estimate_arg) {
|
|
379
|
+
const { is_adjust_coin_a, is_adjust_coin_b } = findAdjustCoin(params)
|
|
380
|
+
|
|
381
|
+
if ((params.a2b && is_adjust_coin_a) || (!params.a2b && is_adjust_coin_b)) {
|
|
382
|
+
const res = await SwapUtils.buildSwapTransactionWithoutTransferCoinsForGas(this._sdk, params, all_coin_asset, gas_estimate_arg)
|
|
383
|
+
return res
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return SwapUtils.buildSwapTransactionWithoutTransferCoins(this.sdk, params, all_coin_asset)
|
|
388
|
+
}
|
|
389
|
+
}
|
package/src/sdk.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import type { BaseSdkOptions, Package } from '@cetusprotocol/common-sdk'
|
|
2
|
+
import { SdkWrapper } from '@cetusprotocol/common-sdk'
|
|
3
|
+
import { ConfigModule, RewarderModule } from './modules'
|
|
4
|
+
import { PoolModule } from './modules/poolModule'
|
|
5
|
+
import { PositionModule } from './modules/positionModule'
|
|
6
|
+
import { SwapModule } from './modules/swapModule'
|
|
7
|
+
import { ClmmConfig } from './types/clmm_type'
|
|
8
|
+
import { CetusConfigs } from './types/config_type'
|
|
9
|
+
import { clmmMainnet } from './config/mainnet'
|
|
10
|
+
import { clmmTestnet } from './config/testnet'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Represents options and configurations for an SDK.
|
|
14
|
+
*/
|
|
15
|
+
export interface SdkOptions extends BaseSdkOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Package containing Cetus protocol configurations.
|
|
18
|
+
*/
|
|
19
|
+
cetus_config: Package<CetusConfigs>
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Package containing Cryptocurrency Liquidity Mining Module (CLMM) pool configurations.
|
|
23
|
+
*/
|
|
24
|
+
clmm_pool: Package<ClmmConfig>
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Package containing integration-related configurations.
|
|
28
|
+
*/
|
|
29
|
+
integrate: Package
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The URL for the swap count
|
|
33
|
+
*/
|
|
34
|
+
stats_pools_url?: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The entry class of CetusClmmSDK, which is almost responsible for all interactions with CLMM.
|
|
39
|
+
*/
|
|
40
|
+
export class CetusClmmSDK extends SdkWrapper<SdkOptions> {
|
|
41
|
+
/**
|
|
42
|
+
* Provide interact with clmm pools with a pool router interface.
|
|
43
|
+
*/
|
|
44
|
+
protected _pool: PoolModule
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Provide interact with a position rewarder interface.
|
|
48
|
+
*/
|
|
49
|
+
protected _rewarder: RewarderModule
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Provide interact with a pool swap router interface.
|
|
53
|
+
*/
|
|
54
|
+
protected _swap: SwapModule
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Provide interact with clmm position with a position router interface.
|
|
58
|
+
*/
|
|
59
|
+
protected _position: PositionModule
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Provide interact with clmm pool and coin and launchpad pool config
|
|
63
|
+
*/
|
|
64
|
+
protected _config: ConfigModule
|
|
65
|
+
|
|
66
|
+
constructor(options: SdkOptions) {
|
|
67
|
+
super(options)
|
|
68
|
+
|
|
69
|
+
this._swap = new SwapModule(this)
|
|
70
|
+
this._pool = new PoolModule(this)
|
|
71
|
+
this._position = new PositionModule(this)
|
|
72
|
+
this._config = new ConfigModule(this)
|
|
73
|
+
this._rewarder = new RewarderModule(this)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Getter for the Pool property.
|
|
78
|
+
* @returns {PoolModule} The Pool property value.
|
|
79
|
+
*/
|
|
80
|
+
get Pool(): PoolModule {
|
|
81
|
+
return this._pool
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Getter for the Position property.
|
|
86
|
+
* @returns {PositionModule} The Position property value.
|
|
87
|
+
*/
|
|
88
|
+
get Position(): PositionModule {
|
|
89
|
+
return this._position
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Getter for the CetusConfig property.
|
|
94
|
+
* @returns {ConfigModule} The CetusConfig property value.
|
|
95
|
+
*/
|
|
96
|
+
get CetusConfig(): ConfigModule {
|
|
97
|
+
return this._config
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Getter for the Rewarder property.
|
|
102
|
+
* @returns {RewarderModule} The Rewarder property value.
|
|
103
|
+
*/
|
|
104
|
+
get Rewarder(): RewarderModule {
|
|
105
|
+
return this._rewarder
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Getter for the Swap property.
|
|
110
|
+
* @returns {SwapModule} The Swap property value.
|
|
111
|
+
*/
|
|
112
|
+
get Swap(): SwapModule {
|
|
113
|
+
return this._swap
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
static createSDK(options: BaseSdkOptions): CetusClmmSDK {
|
|
117
|
+
const { env = 'mainnet' } = options
|
|
118
|
+
return env === 'mainnet'
|
|
119
|
+
? CetusClmmSDK.createCustomSDK({ ...clmmMainnet, ...options })
|
|
120
|
+
: CetusClmmSDK.createCustomSDK({ ...clmmTestnet, ...options })
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Create a custom SDK instance with the given options
|
|
125
|
+
* @param options The options for the SDK
|
|
126
|
+
* @returns An instance of CetusBurnSDK
|
|
127
|
+
*/
|
|
128
|
+
static createCustomSDK<T extends BaseSdkOptions>(options: T & SdkOptions): CetusClmmSDK {
|
|
129
|
+
return new CetusClmmSDK(options)
|
|
130
|
+
}
|
|
131
|
+
}
|