@meteora-ag/dynamic-bonding-curve-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/src/design.ts ADDED
@@ -0,0 +1,394 @@
1
+ import Decimal from 'decimal.js'
2
+ import BN from 'bn.js'
3
+ import {
4
+ FeeSchedulerMode,
5
+ type ConfigParameters,
6
+ type DesignConstantProductCurveWithLockVestingParam,
7
+ type DesignConstantProductCurveWithoutLockVestingParam,
8
+ type DesignCurveParam,
9
+ type DesignCurveResponse,
10
+ } from './types'
11
+ import { MAX_SQRT_PRICE } from './constants'
12
+ import {
13
+ getLiquidityBuffer,
14
+ getBaseTokenForMigration,
15
+ getBaseTokenForSwap,
16
+ getPriceFromSqrtPrice,
17
+ getSqrtPriceFromPrice,
18
+ } from './common'
19
+
20
+ /**
21
+ * Design the curve for the Constant Product curve with lock vesting
22
+ * @param designConstantProductCurveWithLockVestingParam - The parameters for the curve
23
+ * @returns The instruction parameters
24
+ */
25
+ export function designConstantProductCurveWithLockVesting(
26
+ designConstantProductCurveWithLockVestingParam: DesignConstantProductCurveWithLockVestingParam
27
+ ): ConfigParameters {
28
+ const {
29
+ totalTokenSupply,
30
+ percentageSupplyOnMigration,
31
+ lockVestingParams,
32
+ startPrice,
33
+ migrationPrice,
34
+ tokenBaseDecimal,
35
+ tokenQuoteDecimal,
36
+ baseFeeBps,
37
+ dynamicFeeEnabled,
38
+ activationType,
39
+ collectFeeMode,
40
+ migrationOption,
41
+ migrationFeeOption,
42
+ tokenType,
43
+ partnerLpPercentage,
44
+ creatorLpPercentage,
45
+ partnerLockedLpPercentage,
46
+ creatorLockedLpPercentage,
47
+ } = designConstantProductCurveWithLockVestingParam
48
+
49
+ const totalSupply = new BN(totalTokenSupply).mul(
50
+ new BN(10).pow(new BN(tokenBaseDecimal))
51
+ )
52
+ const baseDecimalFactor = new Decimal(10 ** tokenBaseDecimal)
53
+ const quoteDecimalFactor = new Decimal(10 ** tokenQuoteDecimal)
54
+ const preMigrationTokenSupply = totalSupply
55
+ const postMigrationTokenSupply = totalSupply
56
+ const migrationSupply = totalSupply
57
+ .mul(new BN(percentageSupplyOnMigration))
58
+ .div(new BN(100))
59
+
60
+ let lockedVestingAmount = totalSupply
61
+ .mul(new BN(lockVestingParams.percentageSupplyVesting))
62
+ .div(new BN(100))
63
+
64
+ const amountPerPeriod =
65
+ lockVestingParams.numberOfPeriod == 0
66
+ ? new BN(0)
67
+ : lockedVestingAmount.div(new BN(lockVestingParams.numberOfPeriod))
68
+ lockedVestingAmount = amountPerPeriod.mul(
69
+ new BN(lockVestingParams.numberOfPeriod)
70
+ )
71
+
72
+ const sqrtStartPrice = getSqrtPriceFromPrice(
73
+ startPrice.toString(),
74
+ tokenBaseDecimal,
75
+ tokenQuoteDecimal
76
+ )
77
+
78
+ const migrationSqrtPrice = getSqrtPriceFromPrice(
79
+ migrationPrice.toString(),
80
+ tokenBaseDecimal,
81
+ tokenQuoteDecimal
82
+ )
83
+
84
+ const priceDelta = migrationSqrtPrice.sub(sqrtStartPrice)
85
+
86
+ const migrationQuoteThresholdFloat = migrationPrice
87
+ .mul(new Decimal(migrationSupply.toString()))
88
+ .mul(quoteDecimalFactor)
89
+ .div(baseDecimalFactor)
90
+ .floor()
91
+
92
+ const migrationQuoteThreshold = new BN(
93
+ migrationQuoteThresholdFloat.toString()
94
+ )
95
+ const liquidity = migrationQuoteThreshold.shln(128).div(priceDelta)
96
+ const curves = [
97
+ {
98
+ sqrtPrice: migrationSqrtPrice,
99
+ liquidity,
100
+ },
101
+ {
102
+ sqrtPrice: MAX_SQRT_PRICE,
103
+ liquidity: getLiquidityBuffer(
104
+ liquidity,
105
+ migrationSqrtPrice,
106
+ MAX_SQRT_PRICE
107
+ ),
108
+ },
109
+ ]
110
+
111
+ // reverse to get amount on swap
112
+ const maxSwapAmount = getBaseTokenForSwap(
113
+ sqrtStartPrice,
114
+ MAX_SQRT_PRICE,
115
+ curves
116
+ )
117
+ const migrationAmount = getBaseTokenForMigration(
118
+ migrationSqrtPrice,
119
+ migrationQuoteThreshold
120
+ )
121
+
122
+ const cliffUnlockAmount =
123
+ lockVestingParams.cliffUnlockEnabled == false
124
+ ? new BN(0)
125
+ : totalSupply
126
+ .sub(maxSwapAmount)
127
+ .sub(lockedVestingAmount)
128
+ .sub(migrationAmount)
129
+
130
+ const config: ConfigParameters = {
131
+ poolFees: {
132
+ baseFee: {
133
+ cliffFeeNumerator: new BN((baseFeeBps * 100000).toString()),
134
+ numberOfPeriod: 0,
135
+ reductionFactor: new BN('0'),
136
+ periodFrequency: new BN('0'),
137
+ feeSchedulerMode: FeeSchedulerMode.Linear,
138
+ },
139
+ dynamicFee: dynamicFeeEnabled
140
+ ? {
141
+ binStep: 1,
142
+ binStepU128: new BN('1844674407370955'),
143
+ filterPeriod: 10,
144
+ decayPeriod: 120,
145
+ reductionFactor: 5000,
146
+ variableFeeControl: 2000000,
147
+ maxVolatilityAccumulator: 100000,
148
+ }
149
+ : null,
150
+ },
151
+ activationType: activationType,
152
+ collectFeeMode: collectFeeMode,
153
+ migrationOption: migrationOption,
154
+ tokenType: tokenType,
155
+ tokenDecimal: tokenBaseDecimal,
156
+ migrationQuoteThreshold: new BN(migrationQuoteThreshold.toString()),
157
+ partnerLpPercentage: partnerLpPercentage,
158
+ creatorLpPercentage: creatorLpPercentage,
159
+ partnerLockedLpPercentage: partnerLockedLpPercentage,
160
+ creatorLockedLpPercentage: creatorLockedLpPercentage,
161
+ sqrtStartPrice: new BN(sqrtStartPrice.toString()),
162
+ lockedVesting: {
163
+ amountPerPeriod: new BN(amountPerPeriod.toString()),
164
+ cliffDurationFromMigrationTime: new BN('0'),
165
+ frequency: new BN(lockVestingParams.frequency.toString()),
166
+ numberOfPeriod: new BN(lockVestingParams.numberOfPeriod.toString()),
167
+ cliffUnlockAmount: new BN(cliffUnlockAmount.toString()),
168
+ },
169
+ migrationFeeOption: migrationFeeOption,
170
+ tokenSupply: {
171
+ preMigrationTokenSupply: new BN(preMigrationTokenSupply.toString()),
172
+ postMigrationTokenSupply: new BN(
173
+ postMigrationTokenSupply.toString()
174
+ ),
175
+ },
176
+ padding: [
177
+ new BN(0),
178
+ new BN(0),
179
+ new BN(0),
180
+ new BN(0),
181
+ new BN(0),
182
+ new BN(0),
183
+ new BN(0),
184
+ ],
185
+ curve: curves.map((point) => ({
186
+ sqrtPrice: new BN(point.sqrtPrice.toString()),
187
+ liquidity: new BN(point.liquidity.toString()),
188
+ })),
189
+ }
190
+
191
+ return config
192
+ }
193
+
194
+ /**
195
+ * Design the curve for the Constant Product curve without lock vesting
196
+ * @param designConstantProductCurveWithoutLockVestingParam - The parameters for the curve
197
+ * @returns The instruction parameters
198
+ */
199
+ export function designConstantProductCurveWithoutLockVesting(
200
+ designConstantProductCurveWithoutLockVestingParam: DesignConstantProductCurveWithoutLockVestingParam
201
+ ): ConfigParameters {
202
+ const {
203
+ totalTokenSupply,
204
+ percentageSupplyOnMigration,
205
+ startPrice,
206
+ tokenBaseDecimal,
207
+ tokenQuoteDecimal,
208
+ baseFeeBps,
209
+ dynamicFeeEnabled,
210
+ activationType,
211
+ collectFeeMode,
212
+ migrationOption,
213
+ migrationFeeOption,
214
+ tokenType,
215
+ partnerLpPercentage,
216
+ creatorLpPercentage,
217
+ partnerLockedLpPercentage,
218
+ creatorLockedLpPercentage,
219
+ } = designConstantProductCurveWithoutLockVestingParam
220
+
221
+ const totalSupply = new BN(totalTokenSupply).mul(
222
+ new BN(10).pow(new BN(tokenBaseDecimal))
223
+ )
224
+ const baseDecimalFactor = new Decimal(10 ** tokenBaseDecimal)
225
+ const quoteDecimalFactor = new Decimal(10 ** tokenQuoteDecimal)
226
+ const preMigrationTokenSupply = totalSupply
227
+ const postMigrationTokenSupply = totalSupply
228
+ const migrationSupply = totalSupply
229
+ .mul(new BN(percentageSupplyOnMigration))
230
+ .div(new BN(100))
231
+ const swapSupply = totalSupply.sub(migrationSupply)
232
+
233
+ const sqrtStartPrice = getSqrtPriceFromPrice(
234
+ startPrice.toString(),
235
+ tokenBaseDecimal,
236
+ tokenQuoteDecimal
237
+ )
238
+ let migrationSqrtPrice = sqrtStartPrice.mul(swapSupply).div(migrationSupply)
239
+ migrationSqrtPrice = migrationSqrtPrice.sub(new BN(1))
240
+ const priceDelta = migrationSqrtPrice.sub(sqrtStartPrice)
241
+
242
+ const migrationPrice = getPriceFromSqrtPrice(
243
+ migrationSqrtPrice,
244
+ tokenBaseDecimal,
245
+ tokenQuoteDecimal
246
+ )
247
+ const migrationQuoteThresholdFloat = migrationPrice
248
+ .mul(new Decimal(migrationSupply.toString()))
249
+ .mul(quoteDecimalFactor)
250
+ .div(baseDecimalFactor)
251
+ .floor()
252
+
253
+ const migrationQuoteThreshold = new BN(
254
+ migrationQuoteThresholdFloat.toString()
255
+ )
256
+
257
+ const liquidity = migrationQuoteThreshold.shln(128).div(priceDelta)
258
+ const curves = [
259
+ {
260
+ sqrtPrice: migrationSqrtPrice,
261
+ liquidity,
262
+ },
263
+ {
264
+ sqrtPrice: MAX_SQRT_PRICE,
265
+ liquidity: getLiquidityBuffer(
266
+ liquidity,
267
+ migrationSqrtPrice,
268
+ MAX_SQRT_PRICE
269
+ ),
270
+ },
271
+ ]
272
+
273
+ const config: ConfigParameters = {
274
+ poolFees: {
275
+ baseFee: {
276
+ cliffFeeNumerator: new BN((baseFeeBps * 100000).toString()),
277
+ numberOfPeriod: 0,
278
+ reductionFactor: new BN('0'),
279
+ periodFrequency: new BN('0'),
280
+ feeSchedulerMode: FeeSchedulerMode.Linear,
281
+ },
282
+ dynamicFee: dynamicFeeEnabled
283
+ ? {
284
+ binStep: 1,
285
+ binStepU128: new BN('1844674407370955'),
286
+ filterPeriod: 10,
287
+ decayPeriod: 120,
288
+ reductionFactor: 5000,
289
+ variableFeeControl: 2000000,
290
+ maxVolatilityAccumulator: 100000,
291
+ }
292
+ : null,
293
+ },
294
+ activationType: activationType,
295
+ collectFeeMode: collectFeeMode,
296
+ migrationOption: migrationOption,
297
+ tokenType: tokenType,
298
+ tokenDecimal: tokenBaseDecimal,
299
+ migrationQuoteThreshold: new BN(migrationQuoteThreshold.toString()),
300
+ partnerLpPercentage: partnerLpPercentage,
301
+ creatorLpPercentage: creatorLpPercentage,
302
+ partnerLockedLpPercentage: partnerLockedLpPercentage,
303
+ creatorLockedLpPercentage: creatorLockedLpPercentage,
304
+ sqrtStartPrice: new BN(sqrtStartPrice.toString()),
305
+ lockedVesting: {
306
+ amountPerPeriod: new BN('0'),
307
+ cliffDurationFromMigrationTime: new BN('0'),
308
+ frequency: new BN('0'),
309
+ numberOfPeriod: new BN('0'),
310
+ cliffUnlockAmount: new BN('0'),
311
+ },
312
+ migrationFeeOption: migrationFeeOption,
313
+ tokenSupply: {
314
+ preMigrationTokenSupply: new BN(preMigrationTokenSupply.toString()),
315
+ postMigrationTokenSupply: new BN(
316
+ postMigrationTokenSupply.toString()
317
+ ),
318
+ },
319
+ padding: [
320
+ new BN(0),
321
+ new BN(0),
322
+ new BN(0),
323
+ new BN(0),
324
+ new BN(0),
325
+ new BN(0),
326
+ new BN(0),
327
+ ],
328
+ curve: curves.map((point) => ({
329
+ sqrtPrice: new BN(point.sqrtPrice.toString()),
330
+ liquidity: new BN(point.liquidity.toString()),
331
+ })),
332
+ }
333
+
334
+ return config
335
+ }
336
+
337
+ /**
338
+ * Design a Constant Product curve
339
+ * @param params - The parameters for the curve
340
+ * @returns The instruction parameters
341
+ */
342
+ export async function designCurve(
343
+ params: DesignCurveParam
344
+ ): Promise<DesignCurveResponse> {
345
+ const {
346
+ tokenDecimal,
347
+ migrationQuoteThreshold,
348
+ tokenBaseSupply,
349
+ migrationBasePercent,
350
+ } = params
351
+
352
+ const Q64 = new BN(2).pow(new BN(64))
353
+ const Q128 = Q64.mul(Q64)
354
+ const Q64_DEC = new Decimal(Q64.toString())
355
+
356
+ // Scale the base supply by the migration percent and token decimals
357
+ // baseSupplyDecimal: e.g. 1e9
358
+ // migrationBaseSupplyDecimal = 1e9 * 0.15 * 10^9 = 1.5e17
359
+ const baseSupplyDecimal = new Decimal(tokenBaseSupply.toString())
360
+ const migrationBaseSupplyDecimal = baseSupplyDecimal
361
+ .mul(migrationBasePercent / 100)
362
+ .mul(new Decimal(10).pow(tokenDecimal))
363
+
364
+ // quoteThresholdDecimal: e.g. 80 * 10^9
365
+ const quoteThresholdDecimal = new Decimal(
366
+ migrationQuoteThreshold.toString()
367
+ )
368
+
369
+ // Compute Pmax = ceil( sqrt(quote/base) * 2^64 )
370
+ const priceDecimal = quoteThresholdDecimal.div(migrationBaseSupplyDecimal)
371
+ const sqrtPriceDecimal = priceDecimal.sqrt()
372
+ const PmaxDEC = sqrtPriceDecimal.mul(Q64_DEC).ceil()
373
+ const PmaxBN = new BN(PmaxDEC.toFixed(0), 10)
374
+
375
+ // Pmin = floor((2^128 / 10_000_000) / Pmax)
376
+ const ratioBN = Q128.div(new BN(10_000_000))
377
+ const PminBN = ratioBN.div(PmaxBN)
378
+
379
+ // sqrt_start_price in Q64 is exactly Pmin
380
+ const sqrtStartPrice = PminBN
381
+
382
+ // liquidity = floor( quote * 2^128 / (Pmax – Pmin) )
383
+ const liquidity = migrationQuoteThreshold.mul(Q128).div(PmaxBN.sub(PminBN))
384
+
385
+ return {
386
+ sqrtStartPrice,
387
+ curve: [
388
+ {
389
+ sqrtPrice: MAX_SQRT_PRICE,
390
+ liquidity,
391
+ },
392
+ ],
393
+ }
394
+ }