@meteora-ag/dynamic-bonding-curve-sdk 1.2.2 → 1.2.4

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/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  // src/services/pool.ts
2
2
  import {
3
3
  PublicKey as PublicKey9,
4
- Transaction as Transaction2
4
+ Transaction as Transaction2,
5
+ SYSVAR_INSTRUCTIONS_PUBKEY
5
6
  } from "@solana/web3.js";
6
7
 
7
8
  // src/types.ts
@@ -30,11 +31,12 @@ var GetFeeMode = /* @__PURE__ */ ((GetFeeMode2) => {
30
31
  GetFeeMode2[GetFeeMode2["OutputToken"] = 1] = "OutputToken";
31
32
  return GetFeeMode2;
32
33
  })(GetFeeMode || {});
33
- var FeeSchedulerMode = /* @__PURE__ */ ((FeeSchedulerMode2) => {
34
- FeeSchedulerMode2[FeeSchedulerMode2["Linear"] = 0] = "Linear";
35
- FeeSchedulerMode2[FeeSchedulerMode2["Exponential"] = 1] = "Exponential";
36
- return FeeSchedulerMode2;
37
- })(FeeSchedulerMode || {});
34
+ var BaseFeeMode = /* @__PURE__ */ ((BaseFeeMode3) => {
35
+ BaseFeeMode3[BaseFeeMode3["FeeSchedulerLinear"] = 0] = "FeeSchedulerLinear";
36
+ BaseFeeMode3[BaseFeeMode3["FeeSchedulerExponential"] = 1] = "FeeSchedulerExponential";
37
+ BaseFeeMode3[BaseFeeMode3["RateLimiter"] = 2] = "RateLimiter";
38
+ return BaseFeeMode3;
39
+ })(BaseFeeMode || {});
38
40
  var MigrationFeeOption = /* @__PURE__ */ ((MigrationFeeOption2) => {
39
41
  MigrationFeeOption2[MigrationFeeOption2["FixedBps25"] = 0] = "FixedBps25";
40
42
  MigrationFeeOption2[MigrationFeeOption2["FixedBps30"] = 1] = "FixedBps30";
@@ -77,12 +79,17 @@ var MAX_SQRT_PRICE = new BN("79226673521066979257578248091");
77
79
  var RESOLUTION = 64;
78
80
  var ONE_Q64 = new BN(1).shln(RESOLUTION);
79
81
  var FEE_DENOMINATOR = 1e9;
80
- var MAX_FEE_NUMERATOR = 5e8;
82
+ var MAX_FEE_BPS = 9900;
83
+ var MIN_FEE_BPS = 1;
84
+ var MIN_FEE_NUMERATOR = 1e5;
85
+ var MAX_FEE_NUMERATOR = 99e7;
81
86
  var BASIS_POINT_MAX = 1e4;
82
87
  var MAX_CURVE_POINT = 16;
83
88
  var PARTNER_SURPLUS_SHARE = 80;
84
89
  var SWAP_BUFFER_PERCENTAGE = 25;
85
90
  var MAX_SWALLOW_PERCENTAGE = 20;
91
+ var MAX_RATE_LIMITER_DURATION_IN_SECONDS = 43200;
92
+ var MAX_RATE_LIMITER_DURATION_IN_SLOTS = 108e3;
86
93
  var SLOT_DURATION = 400;
87
94
  var TIMESTAMP_DURATION = 1e3;
88
95
  var DYNAMIC_BONDING_CURVE_PROGRAM_ID = new PublicKey(
@@ -696,7 +703,7 @@ var getPercentageSupplyOnMigration = (initialMarketCap, migrationMarketCap, lock
696
703
  var getMigrationQuoteAmount = (migrationMarketCap, percentageSupplyOnMigration) => {
697
704
  return migrationMarketCap.mul(percentageSupplyOnMigration).div(new Decimal2(100));
698
705
  };
699
- function getBaseFeeParams(startingBaseFeeBps, endingBaseFeeBps, feeSchedulerMode, numberOfPeriod, totalDuration) {
706
+ function getFeeSchedulerParams(startingBaseFeeBps, endingBaseFeeBps, baseFeeMode, numberOfPeriod, totalDuration) {
700
707
  if (startingBaseFeeBps == endingBaseFeeBps) {
701
708
  if (numberOfPeriod != 0 || totalDuration != 0) {
702
709
  throw new Error(
@@ -705,20 +712,18 @@ function getBaseFeeParams(startingBaseFeeBps, endingBaseFeeBps, feeSchedulerMode
705
712
  }
706
713
  return {
707
714
  cliffFeeNumerator: bpsToFeeNumerator(startingBaseFeeBps),
708
- numberOfPeriod: 0,
709
- periodFrequency: new BN6(0),
710
- reductionFactor: new BN6(0),
711
- feeSchedulerMode: 0 /* Linear */
715
+ firstFactor: 0,
716
+ secondFactor: new BN6(0),
717
+ thirdFactor: new BN6(0),
718
+ baseFeeMode: 0 /* FeeSchedulerLinear */
712
719
  };
713
720
  }
714
721
  if (numberOfPeriod <= 0) {
715
722
  throw new Error("Total periods must be greater than zero");
716
723
  }
717
- if (startingBaseFeeBps > feeNumeratorToBps(new BN6(MAX_FEE_NUMERATOR))) {
724
+ if (startingBaseFeeBps > MAX_FEE_BPS) {
718
725
  throw new Error(
719
- `startingBaseFeeBps (${startingBaseFeeBps} bps) exceeds maximum allowed value of ${feeNumeratorToBps(
720
- new BN6(MAX_FEE_NUMERATOR)
721
- )} bps`
726
+ `startingBaseFeeBps (${startingBaseFeeBps} bps) exceeds maximum allowed value of ${MAX_FEE_BPS} bps`
722
727
  );
723
728
  }
724
729
  if (endingBaseFeeBps > startingBaseFeeBps) {
@@ -735,7 +740,7 @@ function getBaseFeeParams(startingBaseFeeBps, endingBaseFeeBps, feeSchedulerMode
735
740
  const minBaseFeeNumerator = bpsToFeeNumerator(endingBaseFeeBps);
736
741
  const periodFrequency = new BN6(totalDuration / numberOfPeriod);
737
742
  let reductionFactor;
738
- if (feeSchedulerMode == 0 /* Linear */) {
743
+ if (baseFeeMode == 0 /* FeeSchedulerLinear */) {
739
744
  const totalReduction = maxBaseFeeNumerator.sub(minBaseFeeNumerator);
740
745
  reductionFactor = totalReduction.divn(numberOfPeriod);
741
746
  } else {
@@ -745,15 +750,15 @@ function getBaseFeeParams(startingBaseFeeBps, endingBaseFeeBps, feeSchedulerMode
745
750
  }
746
751
  return {
747
752
  cliffFeeNumerator: maxBaseFeeNumerator,
748
- numberOfPeriod,
749
- periodFrequency,
750
- reductionFactor,
751
- feeSchedulerMode
753
+ firstFactor: numberOfPeriod,
754
+ secondFactor: periodFrequency,
755
+ thirdFactor: reductionFactor,
756
+ baseFeeMode
752
757
  };
753
758
  }
754
- function getMinBaseFeeBps(cliffFeeNumerator, numberOfPeriod, reductionFactor, feeSchedulerMode) {
759
+ function calculateFeeSchedulerEndingBaseFeeBps(cliffFeeNumerator, numberOfPeriod, reductionFactor, baseFeeMode) {
755
760
  let baseFeeNumerator;
756
- if (feeSchedulerMode == 0 /* Linear */) {
761
+ if (baseFeeMode == 0 /* FeeSchedulerLinear */) {
757
762
  baseFeeNumerator = cliffFeeNumerator - numberOfPeriod * reductionFactor;
758
763
  } else {
759
764
  const decayRate = 1 - reductionFactor / BASIS_POINT_MAX;
@@ -761,6 +766,53 @@ function getMinBaseFeeBps(cliffFeeNumerator, numberOfPeriod, reductionFactor, fe
761
766
  }
762
767
  return Math.max(0, baseFeeNumerator / FEE_DENOMINATOR * BASIS_POINT_MAX);
763
768
  }
769
+ function getRateLimiterParams(baseFeeBps, feeIncrementBps, referenceAmount, maxLimiterDuration, tokenQuoteDecimal, activationType) {
770
+ const cliffFeeNumerator = bpsToFeeNumerator(baseFeeBps);
771
+ const feeIncrementNumerator = bpsToFeeNumerator(feeIncrementBps);
772
+ if (baseFeeBps <= 0 || feeIncrementBps <= 0 || referenceAmount <= 0 || maxLimiterDuration <= 0) {
773
+ throw new Error("All rate limiter parameters must be greater than zero");
774
+ }
775
+ if (baseFeeBps > MAX_FEE_BPS) {
776
+ throw new Error(
777
+ `Base fee (${baseFeeBps} bps) exceeds maximum allowed value of ${MAX_FEE_BPS} bps`
778
+ );
779
+ }
780
+ if (feeIncrementBps > MAX_FEE_BPS) {
781
+ throw new Error(
782
+ `Fee increment (${feeIncrementBps} bps) exceeds maximum allowed value of ${MAX_FEE_BPS} bps`
783
+ );
784
+ }
785
+ if (feeIncrementNumerator.gte(new BN6(FEE_DENOMINATOR))) {
786
+ throw new Error(
787
+ "Fee increment numerator must be less than FEE_DENOMINATOR"
788
+ );
789
+ }
790
+ const deltaNumerator = new BN6(MAX_FEE_NUMERATOR).sub(cliffFeeNumerator);
791
+ const maxIndex = deltaNumerator.div(feeIncrementNumerator);
792
+ if (maxIndex.lt(new BN6(1))) {
793
+ throw new Error("Fee increment is too large for the given base fee");
794
+ }
795
+ if (cliffFeeNumerator.lt(new BN6(MIN_FEE_NUMERATOR)) || cliffFeeNumerator.gt(new BN6(MAX_FEE_NUMERATOR))) {
796
+ throw new Error("Base fee must be between 0.01% and 99%");
797
+ }
798
+ const maxDuration = activationType === 0 /* Slot */ ? MAX_RATE_LIMITER_DURATION_IN_SLOTS : MAX_RATE_LIMITER_DURATION_IN_SECONDS;
799
+ if (maxLimiterDuration > maxDuration) {
800
+ throw new Error(
801
+ `Max duration exceeds maximum allowed value of ${maxDuration}`
802
+ );
803
+ }
804
+ const referenceAmountInLamports = convertToLamports(
805
+ referenceAmount,
806
+ tokenQuoteDecimal
807
+ );
808
+ return {
809
+ cliffFeeNumerator,
810
+ firstFactor: feeIncrementBps,
811
+ secondFactor: new BN6(maxLimiterDuration),
812
+ thirdFactor: new BN6(referenceAmountInLamports),
813
+ baseFeeMode: 2 /* RateLimiter */
814
+ };
815
+ }
764
816
  function getDynamicFeeParams(baseFeeBps, maxPriceChangeBps = MAX_PRICE_CHANGE_BPS_DEFAULT) {
765
817
  if (maxPriceChangeBps > MAX_PRICE_CHANGE_BPS_DEFAULT) {
766
818
  throw new Error(
@@ -881,6 +933,46 @@ var getTwoCurve = (migrationSqrtPrice, midSqrtPrice, initialSqrtPrice, swapAmoun
881
933
  ]
882
934
  };
883
935
  };
936
+ function checkRateLimiterApplied(baseFeeMode, swapBaseForQuote, currentPoint, activationPoint, maxLimiterDuration) {
937
+ return baseFeeMode === 2 /* RateLimiter */ && !swapBaseForQuote && currentPoint.gte(activationPoint) && currentPoint.lte(activationPoint.add(maxLimiterDuration));
938
+ }
939
+ function getBaseFeeParams(baseFeeParams, tokenQuoteDecimal, activationType) {
940
+ if (baseFeeParams.baseFeeMode === 2 /* RateLimiter */) {
941
+ if (!baseFeeParams.rateLimiterParam) {
942
+ throw new Error(
943
+ "Rate limiter parameters are required for RateLimiter mode"
944
+ );
945
+ }
946
+ const {
947
+ baseFeeBps,
948
+ feeIncrementBps,
949
+ referenceAmount,
950
+ maxLimiterDuration
951
+ } = baseFeeParams.rateLimiterParam;
952
+ return getRateLimiterParams(
953
+ baseFeeBps,
954
+ feeIncrementBps,
955
+ referenceAmount,
956
+ maxLimiterDuration,
957
+ tokenQuoteDecimal,
958
+ activationType
959
+ );
960
+ } else {
961
+ if (!baseFeeParams.feeSchedulerParam) {
962
+ throw new Error(
963
+ "Fee scheduler parameters are required for FeeScheduler mode"
964
+ );
965
+ }
966
+ const { startingFeeBps, endingFeeBps, numberOfPeriod, totalDuration } = baseFeeParams.feeSchedulerParam;
967
+ return getFeeSchedulerParams(
968
+ startingFeeBps,
969
+ endingFeeBps,
970
+ baseFeeParams.baseFeeMode,
971
+ numberOfPeriod,
972
+ totalDuration
973
+ );
974
+ }
975
+ }
884
976
 
885
977
  // src/helpers/accounts.ts
886
978
  import { PublicKey as PublicKey4 } from "@solana/web3.js";
@@ -1143,15 +1235,160 @@ function deriveBaseKeyForLocker(virtualPool) {
1143
1235
  }
1144
1236
 
1145
1237
  // src/helpers/validation.ts
1146
- import BN7 from "bn.js";
1238
+ import BN8 from "bn.js";
1147
1239
  import { PublicKey as PublicKey5 } from "@solana/web3.js";
1148
1240
  import Decimal3 from "decimal.js";
1149
- function validatePoolFees(poolFees) {
1241
+
1242
+ // src/math/rateLimiter.ts
1243
+ import BN7 from "bn.js";
1244
+ function getMaxIndex(cliffFeeNumerator, feeIncrementBps) {
1245
+ const deltaNumerator = new BN7(MAX_FEE_NUMERATOR).sub(cliffFeeNumerator);
1246
+ const feeIncrementNumerator = mulDiv(
1247
+ new BN7(feeIncrementBps),
1248
+ new BN7(FEE_DENOMINATOR),
1249
+ new BN7(BASIS_POINT_MAX),
1250
+ 1 /* Down */
1251
+ );
1252
+ return deltaNumerator.div(feeIncrementNumerator);
1253
+ }
1254
+ function getFeeNumeratorOnRateLimiter(cliffFeeNumerator, referenceAmount, feeIncrementBps, inputAmount) {
1255
+ if (inputAmount.lte(referenceAmount)) {
1256
+ return cliffFeeNumerator;
1257
+ }
1258
+ const c = new BN7(cliffFeeNumerator);
1259
+ const diff = inputAmount.sub(referenceAmount);
1260
+ const a = new BN7(diff.div(referenceAmount));
1261
+ const b = new BN7(diff.mod(referenceAmount));
1262
+ const maxIndex = new BN7(getMaxIndex(cliffFeeNumerator, feeIncrementBps));
1263
+ const i = mulDiv(
1264
+ new BN7(feeIncrementBps),
1265
+ new BN7(FEE_DENOMINATOR),
1266
+ new BN7(BASIS_POINT_MAX),
1267
+ 1 /* Down */
1268
+ );
1269
+ const x0 = new BN7(referenceAmount);
1270
+ const one = new BN7(1);
1271
+ const two = new BN7(2);
1272
+ let tradingFeeNumerator;
1273
+ if (a.lt(maxIndex)) {
1274
+ let numerator1 = c.add(c.mul(a)).add(i.mul(a).mul(a.add(one)).div(two));
1275
+ let numerator2 = c.add(i.mul(a.add(one)));
1276
+ let firstFee = x0.mul(numerator1);
1277
+ let secondFee = b.mul(numerator2);
1278
+ tradingFeeNumerator = firstFee.add(secondFee);
1279
+ } else {
1280
+ let numerator1 = c.add(c.mul(maxIndex)).add(i.mul(maxIndex).mul(maxIndex.add(one)).div(two));
1281
+ let numerator2 = new BN7(MAX_FEE_NUMERATOR);
1282
+ let firstFee = x0.mul(numerator1);
1283
+ let d = a.sub(maxIndex);
1284
+ let leftAmount = d.mul(x0).add(b);
1285
+ let secondFee = leftAmount.mul(numerator2);
1286
+ tradingFeeNumerator = firstFee.add(secondFee);
1287
+ }
1288
+ const denominator = new BN7(FEE_DENOMINATOR);
1289
+ const tradingFee = tradingFeeNumerator.add(denominator).sub(one).div(denominator);
1290
+ const feeNumerator = mulDiv(
1291
+ tradingFee,
1292
+ new BN7(FEE_DENOMINATOR),
1293
+ inputAmount,
1294
+ 0 /* Up */
1295
+ );
1296
+ return BN7.min(feeNumerator, new BN7(MAX_FEE_NUMERATOR));
1297
+ }
1298
+
1299
+ // src/helpers/validation.ts
1300
+ function validatePoolFees(poolFees, collectFeeMode, activationType) {
1150
1301
  if (!poolFees) return false;
1151
1302
  if (poolFees.baseFee) {
1152
- if (poolFees.baseFee.cliffFeeNumerator.lte(new BN7(0))) {
1303
+ if (poolFees.baseFee.cliffFeeNumerator.lte(new BN8(0))) {
1153
1304
  return false;
1154
1305
  }
1306
+ if (poolFees.baseFee.baseFeeMode === 0 /* FeeSchedulerLinear */ || poolFees.baseFee.baseFeeMode === 1 /* FeeSchedulerExponential */) {
1307
+ if (!validateFeeScheduler(poolFees.baseFee)) {
1308
+ return false;
1309
+ }
1310
+ }
1311
+ if (poolFees.baseFee.baseFeeMode === 2 /* RateLimiter */) {
1312
+ if (!validateFeeRateLimiter(
1313
+ poolFees.baseFee,
1314
+ collectFeeMode,
1315
+ activationType
1316
+ )) {
1317
+ return false;
1318
+ }
1319
+ }
1320
+ }
1321
+ return true;
1322
+ }
1323
+ function validateFeeScheduler(feeScheduler) {
1324
+ if (!feeScheduler) return true;
1325
+ if (feeScheduler.firstFactor !== 0 || feeScheduler.secondFactor.gt(new BN8(0)) || feeScheduler.thirdFactor.gt(new BN8(0))) {
1326
+ if (feeScheduler.firstFactor === 0 || feeScheduler.secondFactor.eq(new BN8(0)) || feeScheduler.thirdFactor.eq(new BN8(0))) {
1327
+ return false;
1328
+ }
1329
+ }
1330
+ if (feeScheduler.cliffFeeNumerator.lte(new BN8(0))) {
1331
+ return false;
1332
+ }
1333
+ if (feeScheduler.baseFeeMode !== 0 /* FeeSchedulerLinear */ && feeScheduler.baseFeeMode !== 1 /* FeeSchedulerExponential */) {
1334
+ return false;
1335
+ }
1336
+ if (feeScheduler.baseFeeMode === 0 /* FeeSchedulerLinear */) {
1337
+ const finalFee = feeScheduler.cliffFeeNumerator.sub(
1338
+ feeScheduler.secondFactor.mul(new BN8(feeScheduler.firstFactor))
1339
+ );
1340
+ if (finalFee.lt(new BN8(0))) {
1341
+ return false;
1342
+ }
1343
+ }
1344
+ const minFeeNumerator = feeScheduler.cliffFeeNumerator.sub(
1345
+ feeScheduler.secondFactor.mul(new BN8(feeScheduler.firstFactor))
1346
+ );
1347
+ const maxFeeNumerator = feeScheduler.cliffFeeNumerator;
1348
+ if (minFeeNumerator.gte(new BN8(FEE_DENOMINATOR)) || maxFeeNumerator.gte(new BN8(FEE_DENOMINATOR))) {
1349
+ return false;
1350
+ }
1351
+ if (minFeeNumerator.lt(new BN8(MIN_FEE_NUMERATOR)) || maxFeeNumerator.gt(new BN8(MAX_FEE_NUMERATOR))) {
1352
+ return false;
1353
+ }
1354
+ return true;
1355
+ }
1356
+ function validateFeeRateLimiter(feeRateLimiter, collectFeeMode, activationType) {
1357
+ if (!feeRateLimiter) return true;
1358
+ if (collectFeeMode !== 0 /* OnlyQuote */) {
1359
+ return false;
1360
+ }
1361
+ if (!feeRateLimiter.firstFactor && !feeRateLimiter.secondFactor && !feeRateLimiter.thirdFactor) {
1362
+ return true;
1363
+ }
1364
+ if (!feeRateLimiter.firstFactor || !feeRateLimiter.secondFactor || !feeRateLimiter.thirdFactor) {
1365
+ return false;
1366
+ }
1367
+ const maxDuration = activationType === 0 /* Slot */ ? MAX_RATE_LIMITER_DURATION_IN_SLOTS : MAX_RATE_LIMITER_DURATION_IN_SECONDS;
1368
+ if (feeRateLimiter.secondFactor.gt(new BN8(maxDuration))) {
1369
+ return false;
1370
+ }
1371
+ const feeIncrementNumerator = bpsToFeeNumerator(feeRateLimiter.firstFactor);
1372
+ if (feeIncrementNumerator.gte(new BN8(FEE_DENOMINATOR))) {
1373
+ return false;
1374
+ }
1375
+ if (feeRateLimiter.cliffFeeNumerator.lt(new BN8(MIN_FEE_NUMERATOR)) || feeRateLimiter.cliffFeeNumerator.gt(new BN8(MAX_FEE_NUMERATOR))) {
1376
+ return false;
1377
+ }
1378
+ const minFeeNumerator = getFeeNumeratorOnRateLimiter(
1379
+ feeRateLimiter.cliffFeeNumerator,
1380
+ feeRateLimiter.thirdFactor,
1381
+ new BN8(feeRateLimiter.firstFactor),
1382
+ new BN8(0)
1383
+ );
1384
+ const maxFeeNumerator = getFeeNumeratorOnRateLimiter(
1385
+ feeRateLimiter.cliffFeeNumerator,
1386
+ feeRateLimiter.thirdFactor,
1387
+ new BN8(feeRateLimiter.firstFactor),
1388
+ new BN8(Number.MAX_SAFE_INTEGER)
1389
+ );
1390
+ if (minFeeNumerator.lt(new BN8(MIN_FEE_NUMERATOR)) || maxFeeNumerator.gt(new BN8(MAX_FEE_NUMERATOR))) {
1391
+ return false;
1155
1392
  }
1156
1393
  return true;
1157
1394
  }
@@ -1192,7 +1429,7 @@ function validateCurve(curve, sqrtStartPrice) {
1192
1429
  if (!curve || curve.length === 0 || curve.length > MAX_CURVE_POINT) {
1193
1430
  return false;
1194
1431
  }
1195
- if (curve[0]?.sqrtPrice.lte(sqrtStartPrice) || curve[0]?.liquidity.lte(new BN7(0)) || curve[0]?.sqrtPrice.gt(new BN7(MAX_SQRT_PRICE))) {
1432
+ if (curve[0]?.sqrtPrice.lte(sqrtStartPrice) || curve[0]?.liquidity.lte(new BN8(0)) || curve[0]?.sqrtPrice.gt(new BN8(MAX_SQRT_PRICE))) {
1196
1433
  return false;
1197
1434
  }
1198
1435
  for (let i = 1; i < curve.length; i++) {
@@ -1201,11 +1438,11 @@ function validateCurve(curve, sqrtStartPrice) {
1201
1438
  if (!currentPoint || !previousPoint) {
1202
1439
  return false;
1203
1440
  }
1204
- if (currentPoint.sqrtPrice.lte(previousPoint.sqrtPrice) || currentPoint.liquidity.lte(new BN7(0))) {
1441
+ if (currentPoint.sqrtPrice.lte(previousPoint.sqrtPrice) || currentPoint.liquidity.lte(new BN8(0))) {
1205
1442
  return false;
1206
1443
  }
1207
1444
  }
1208
- return !curve[curve.length - 1]?.sqrtPrice.gt(new BN7(MAX_SQRT_PRICE));
1445
+ return !curve[curve.length - 1]?.sqrtPrice.gt(new BN8(MAX_SQRT_PRICE));
1209
1446
  }
1210
1447
  function validateTokenSupply(tokenSupply, leftoverReceiver, swapBaseAmount, migrationBaseAmount, lockedVesting, swapBaseAmountBuffer) {
1211
1448
  if (!tokenSupply) return true;
@@ -1229,11 +1466,11 @@ function validateTokenSupply(tokenSupply, leftoverReceiver, swapBaseAmount, migr
1229
1466
  lockedVesting
1230
1467
  );
1231
1468
  return !(minimumBaseSupplyWithoutBuffer.gt(
1232
- new BN7(tokenSupply.postMigrationTokenSupply)
1233
- ) || new BN7(tokenSupply.postMigrationTokenSupply).gt(
1234
- new BN7(tokenSupply.preMigrationTokenSupply)
1469
+ new BN8(tokenSupply.postMigrationTokenSupply)
1470
+ ) || new BN8(tokenSupply.postMigrationTokenSupply).gt(
1471
+ new BN8(tokenSupply.preMigrationTokenSupply)
1235
1472
  ) || minimumBaseSupplyWithBuffer.gt(
1236
- new BN7(tokenSupply.preMigrationTokenSupply)
1473
+ new BN8(tokenSupply.preMigrationTokenSupply)
1237
1474
  ));
1238
1475
  }
1239
1476
  function validateTokenUpdateAuthorityOptions(option) {
@@ -1246,7 +1483,11 @@ function validateConfigParameters(configParam) {
1246
1483
  if (!configParam.poolFees) {
1247
1484
  throw new Error("Pool fees are required");
1248
1485
  }
1249
- if (!validatePoolFees(configParam.poolFees)) {
1486
+ if (!validatePoolFees(
1487
+ configParam.poolFees,
1488
+ configParam.collectFeeMode,
1489
+ configParam.activationType
1490
+ )) {
1250
1491
  throw new Error("Invalid pool fees");
1251
1492
  }
1252
1493
  if (!validateCollectFeeMode(configParam.collectFeeMode)) {
@@ -1284,10 +1525,10 @@ function validateConfigParameters(configParam) {
1284
1525
  )) {
1285
1526
  throw new Error("Sum of LP percentages must equal 100");
1286
1527
  }
1287
- if (configParam.migrationQuoteThreshold.lte(new BN7(0))) {
1528
+ if (configParam.migrationQuoteThreshold.lte(new BN8(0))) {
1288
1529
  throw new Error("Migration quote threshold must be greater than 0");
1289
1530
  }
1290
- if (new BN7(configParam.sqrtStartPrice).lt(new BN7(MIN_SQRT_PRICE)) || new BN7(configParam.sqrtStartPrice).gte(new BN7(MAX_SQRT_PRICE))) {
1531
+ if (new BN8(configParam.sqrtStartPrice).lt(new BN8(MIN_SQRT_PRICE)) || new BN8(configParam.sqrtStartPrice).gte(new BN8(MAX_SQRT_PRICE))) {
1291
1532
  throw new Error("Invalid sqrt start price");
1292
1533
  }
1293
1534
  if (!validateCurve(configParam.curve, configParam.sqrtStartPrice)) {
@@ -1297,10 +1538,10 @@ function validateConfigParameters(configParam) {
1297
1538
  try {
1298
1539
  const totalAmount = configParam.lockedVesting.cliffUnlockAmount.add(
1299
1540
  configParam.lockedVesting.amountPerPeriod.mul(
1300
- new BN7(configParam.lockedVesting.numberOfPeriod)
1541
+ new BN8(configParam.lockedVesting.numberOfPeriod)
1301
1542
  )
1302
1543
  );
1303
- if (configParam.lockedVesting.frequency.eq(new BN7(0)) || totalAmount.eq(new BN7(0))) {
1544
+ if (configParam.lockedVesting.frequency.eq(new BN8(0)) || totalAmount.eq(new BN8(0))) {
1304
1545
  throw new Error("Invalid vesting parameters");
1305
1546
  }
1306
1547
  } catch (error) {
@@ -1361,7 +1602,7 @@ async function validateBalance(connection, owner, inputMint, amountIn, inputToke
1361
1602
  } else {
1362
1603
  try {
1363
1604
  const tokenBalance = await connection.getTokenAccountBalance(inputTokenAccount);
1364
- const balance = new BN7(tokenBalance.value.amount);
1605
+ const balance = new BN8(tokenBalance.value.amount);
1365
1606
  if (balance.lt(amountIn)) {
1366
1607
  throw new Error(
1367
1608
  `Insufficient token balance. Required: ${amountIn.toString()}, Found: ${balance.toString()}`
@@ -1376,7 +1617,7 @@ async function validateBalance(connection, owner, inputMint, amountIn, inputToke
1376
1617
  return true;
1377
1618
  }
1378
1619
  function validateSwapAmount(amountIn) {
1379
- if (amountIn.lte(new BN7(0))) {
1620
+ if (amountIn.lte(new BN8(0))) {
1380
1621
  throw new Error("Swap amount must be greater than 0");
1381
1622
  }
1382
1623
  return true;
@@ -1384,7 +1625,7 @@ function validateSwapAmount(amountIn) {
1384
1625
 
1385
1626
  // src/helpers/buildCurve.ts
1386
1627
  import Decimal4 from "decimal.js";
1387
- import BN8 from "bn.js";
1628
+ import BN9 from "bn.js";
1388
1629
  function buildCurve(buildCurveParam) {
1389
1630
  let {
1390
1631
  totalTokenSupply,
@@ -1405,21 +1646,13 @@ function buildCurve(buildCurveParam) {
1405
1646
  creatorTradingFeePercentage,
1406
1647
  leftover,
1407
1648
  tokenUpdateAuthority,
1408
- migrationFee
1649
+ migrationFee,
1650
+ baseFeeParams
1409
1651
  } = buildCurveParam;
1410
- const {
1411
- startingFeeBps,
1412
- endingFeeBps,
1413
- numberOfPeriod,
1414
- feeSchedulerMode,
1415
- totalDuration
1416
- } = buildCurveParam.feeSchedulerParam;
1417
- const baseFeeParams = getBaseFeeParams(
1418
- startingFeeBps,
1419
- endingFeeBps,
1420
- feeSchedulerMode,
1421
- numberOfPeriod,
1422
- totalDuration
1652
+ const baseFee = getBaseFeeParams(
1653
+ baseFeeParams,
1654
+ tokenQuoteDecimal,
1655
+ activationType
1423
1656
  );
1424
1657
  const {
1425
1658
  totalLockedVestingAmount,
@@ -1436,7 +1669,7 @@ function buildCurve(buildCurveParam) {
1436
1669
  cliffDurationFromMigrationTime,
1437
1670
  tokenBaseDecimal
1438
1671
  );
1439
- const migrationBaseSupply = new BN8(totalTokenSupply).mul(new BN8(percentageSupplyOnMigration)).div(new BN8(100));
1672
+ const migrationBaseSupply = new BN9(totalTokenSupply).mul(new BN9(percentageSupplyOnMigration)).div(new BN9(100));
1440
1673
  const totalSupply = convertToLamports(totalTokenSupply, tokenBaseDecimal);
1441
1674
  const migrationQuoteAmount = getMigrationQuoteAmountFromMigrationQuoteThreshold(
1442
1675
  new Decimal4(migrationQuoteThreshold),
@@ -1496,9 +1729,11 @@ function buildCurve(buildCurveParam) {
1496
1729
  const instructionParams = {
1497
1730
  poolFees: {
1498
1731
  baseFee: {
1499
- ...baseFeeParams
1732
+ ...baseFee
1500
1733
  },
1501
- dynamicFee: dynamicFeeEnabled ? getDynamicFeeParams(endingFeeBps) : null
1734
+ dynamicFee: dynamicFeeEnabled ? getDynamicFeeParams(
1735
+ baseFeeParams.baseFeeMode === 2 /* RateLimiter */ ? baseFeeParams.rateLimiterParam.baseFeeBps : baseFeeParams.feeSchedulerParam.endingFeeBps
1736
+ ) : null
1502
1737
  },
1503
1738
  activationType,
1504
1739
  collectFeeMode,
@@ -1591,21 +1826,13 @@ function buildCurveWithTwoSegments(buildCurveWithTwoSegmentsParam) {
1591
1826
  dynamicFeeEnabled,
1592
1827
  migrationFeeOption,
1593
1828
  migrationFee,
1594
- tokenUpdateAuthority
1829
+ tokenUpdateAuthority,
1830
+ baseFeeParams
1595
1831
  } = buildCurveWithTwoSegmentsParam;
1596
- const {
1597
- startingFeeBps,
1598
- endingFeeBps,
1599
- numberOfPeriod,
1600
- feeSchedulerMode,
1601
- totalDuration
1602
- } = buildCurveWithTwoSegmentsParam.feeSchedulerParam;
1603
- const baseFeeParams = getBaseFeeParams(
1604
- startingFeeBps,
1605
- endingFeeBps,
1606
- feeSchedulerMode,
1607
- numberOfPeriod,
1608
- totalDuration
1832
+ const baseFee = getBaseFeeParams(
1833
+ baseFeeParams,
1834
+ tokenQuoteDecimal,
1835
+ activationType
1609
1836
  );
1610
1837
  const {
1611
1838
  totalLockedVestingAmount,
@@ -1622,7 +1849,7 @@ function buildCurveWithTwoSegments(buildCurveWithTwoSegmentsParam) {
1622
1849
  cliffDurationFromMigrationTime,
1623
1850
  tokenBaseDecimal
1624
1851
  );
1625
- let migrationBaseSupply = new BN8(totalTokenSupply).mul(new BN8(percentageSupplyOnMigration)).div(new BN8(100));
1852
+ let migrationBaseSupply = new BN9(totalTokenSupply).mul(new BN9(percentageSupplyOnMigration)).div(new BN9(100));
1626
1853
  let totalSupply = convertToLamports(totalTokenSupply, tokenBaseDecimal);
1627
1854
  let migrationQuoteAmount = getMigrationQuoteAmount(
1628
1855
  new Decimal4(migrationMarketCap),
@@ -1661,19 +1888,19 @@ function buildCurveWithTwoSegments(buildCurveWithTwoSegmentsParam) {
1661
1888
  tokenQuoteDecimal
1662
1889
  );
1663
1890
  let midSqrtPriceDecimal1 = new Decimal4(migrateSqrtPrice.toString()).mul(new Decimal4(initialSqrtPrice.toString())).sqrt();
1664
- let midSqrtPrice1 = new BN8(midSqrtPriceDecimal1.floor().toFixed());
1891
+ let midSqrtPrice1 = new BN9(midSqrtPriceDecimal1.floor().toFixed());
1665
1892
  let numerator1 = new Decimal4(initialSqrtPrice.toString());
1666
1893
  let numerator2 = Decimal4.pow(migrateSqrtPrice.toString(), 3);
1667
1894
  let product1 = numerator1.mul(numerator2);
1668
1895
  let midSqrtPriceDecimal2 = Decimal4.pow(product1, 0.25);
1669
- let midSqrtPrice2 = new BN8(midSqrtPriceDecimal2.floor().toFixed());
1896
+ let midSqrtPrice2 = new BN9(midSqrtPriceDecimal2.floor().toFixed());
1670
1897
  let numerator3 = Decimal4.pow(initialSqrtPrice.toString(), 3);
1671
1898
  let numerator4 = new Decimal4(migrateSqrtPrice.toString());
1672
1899
  let product2 = numerator3.mul(numerator4);
1673
1900
  let midSqrtPriceDecimal3 = Decimal4.pow(product2, 0.25);
1674
- let midSqrtPrice3 = new BN8(midSqrtPriceDecimal3.floor().toFixed());
1901
+ let midSqrtPrice3 = new BN9(midSqrtPriceDecimal3.floor().toFixed());
1675
1902
  let midPrices = [midSqrtPrice1, midSqrtPrice2, midSqrtPrice3];
1676
- let sqrtStartPrice = new BN8(0);
1903
+ let sqrtStartPrice = new BN9(0);
1677
1904
  let curve = [];
1678
1905
  for (let i = 0; i < midPrices.length; i++) {
1679
1906
  const result = getTwoCurve(
@@ -1707,9 +1934,11 @@ function buildCurveWithTwoSegments(buildCurveWithTwoSegmentsParam) {
1707
1934
  const instructionParams = {
1708
1935
  poolFees: {
1709
1936
  baseFee: {
1710
- ...baseFeeParams
1937
+ ...baseFee
1711
1938
  },
1712
- dynamicFee: dynamicFeeEnabled ? getDynamicFeeParams(endingFeeBps) : null
1939
+ dynamicFee: dynamicFeeEnabled ? getDynamicFeeParams(
1940
+ baseFeeParams.baseFeeMode === 2 /* RateLimiter */ ? baseFeeParams.rateLimiterParam.baseFeeBps : baseFeeParams.feeSchedulerParam.endingFeeBps
1941
+ ) : null
1713
1942
  },
1714
1943
  activationType,
1715
1944
  collectFeeMode,
@@ -1758,21 +1987,13 @@ function buildCurveWithLiquidityWeights(buildCurveWithLiquidityWeightsParam) {
1758
1987
  migrationMarketCap,
1759
1988
  liquidityWeights,
1760
1989
  migrationFee,
1761
- tokenUpdateAuthority
1990
+ tokenUpdateAuthority,
1991
+ baseFeeParams
1762
1992
  } = buildCurveWithLiquidityWeightsParam;
1763
- const {
1764
- startingFeeBps,
1765
- endingFeeBps,
1766
- numberOfPeriod,
1767
- feeSchedulerMode,
1768
- totalDuration
1769
- } = buildCurveWithLiquidityWeightsParam.feeSchedulerParam;
1770
- const baseFeeParams = getBaseFeeParams(
1771
- startingFeeBps,
1772
- endingFeeBps,
1773
- feeSchedulerMode,
1774
- numberOfPeriod,
1775
- totalDuration
1993
+ const baseFee = getBaseFeeParams(
1994
+ baseFeeParams,
1995
+ tokenQuoteDecimal,
1996
+ activationType
1776
1997
  );
1777
1998
  const {
1778
1999
  totalLockedVestingAmount,
@@ -1873,9 +2094,11 @@ function buildCurveWithLiquidityWeights(buildCurveWithLiquidityWeightsParam) {
1873
2094
  const instructionParams = {
1874
2095
  poolFees: {
1875
2096
  baseFee: {
1876
- ...baseFeeParams
2097
+ ...baseFee
1877
2098
  },
1878
- dynamicFee: dynamicFeeEnabled ? getDynamicFeeParams(endingFeeBps) : null
2099
+ dynamicFee: dynamicFeeEnabled ? getDynamicFeeParams(
2100
+ baseFeeParams.baseFeeMode === 2 /* RateLimiter */ ? baseFeeParams.rateLimiterParam.baseFeeBps : baseFeeParams.feeSchedulerParam.endingFeeBps
2101
+ ) : null
1879
2102
  },
1880
2103
  activationType,
1881
2104
  collectFeeMode,
@@ -5820,6 +6043,21 @@ var idl_default = {
5820
6043
  code: 6040,
5821
6044
  name: "MigrationFeeHasBeenWithdraw",
5822
6045
  msg: "Migration fee has been withdraw"
6046
+ },
6047
+ {
6048
+ code: 6041,
6049
+ name: "InvalidBaseFeeMode",
6050
+ msg: "Invalid base fee mode"
6051
+ },
6052
+ {
6053
+ code: 6042,
6054
+ name: "InvalidFeeRateLimiter",
6055
+ msg: "Invalid fee rate limiter"
6056
+ },
6057
+ {
6058
+ code: 6043,
6059
+ name: "FailToValidateSingleSwapInstruction",
6060
+ msg: "Fail to validate single swap instruction in rate limiter"
5823
6061
  }
5824
6062
  ],
5825
6063
  types: [
@@ -5837,19 +6075,19 @@ var idl_default = {
5837
6075
  type: "u64"
5838
6076
  },
5839
6077
  {
5840
- name: "period_frequency",
6078
+ name: "second_factor",
5841
6079
  type: "u64"
5842
6080
  },
5843
6081
  {
5844
- name: "reduction_factor",
6082
+ name: "third_factor",
5845
6083
  type: "u64"
5846
6084
  },
5847
6085
  {
5848
- name: "number_of_period",
6086
+ name: "first_factor",
5849
6087
  type: "u16"
5850
6088
  },
5851
6089
  {
5852
- name: "fee_scheduler_mode",
6090
+ name: "base_fee_mode",
5853
6091
  type: "u8"
5854
6092
  },
5855
6093
  {
@@ -5874,19 +6112,19 @@ var idl_default = {
5874
6112
  type: "u64"
5875
6113
  },
5876
6114
  {
5877
- name: "number_of_period",
6115
+ name: "first_factor",
5878
6116
  type: "u16"
5879
6117
  },
5880
6118
  {
5881
- name: "period_frequency",
6119
+ name: "second_factor",
5882
6120
  type: "u64"
5883
6121
  },
5884
6122
  {
5885
- name: "reduction_factor",
6123
+ name: "third_factor",
5886
6124
  type: "u64"
5887
6125
  },
5888
6126
  {
5889
- name: "fee_scheduler_mode",
6127
+ name: "base_fee_mode",
5890
6128
  type: "u8"
5891
6129
  }
5892
6130
  ]
@@ -20886,16 +21124,26 @@ import { NATIVE_MINT as NATIVE_MINT3, TOKEN_2022_PROGRAM_ID as TOKEN_2022_PROGRA
20886
21124
  import { TOKEN_PROGRAM_ID as TOKEN_PROGRAM_ID3 } from "@solana/spl-token";
20887
21125
 
20888
21126
  // src/math/swapQuote.ts
20889
- import BN10 from "bn.js";
21127
+ import BN12 from "bn.js";
20890
21128
 
20891
21129
  // src/math/feeMath.ts
20892
- import BN9 from "bn.js";
20893
- function getFeeInPeriod(cliffFeeNumerator, reductionFactor, period) {
21130
+ import BN11 from "bn.js";
21131
+
21132
+ // src/math/feeScheduler.ts
21133
+ import BN10 from "bn.js";
21134
+ function getFeeNumeratorOnLinearFeeScheduler(cliffFeeNumerator, reductionFactor, period) {
21135
+ const reduction = SafeMath.mul(new BN10(period), reductionFactor);
21136
+ if (reduction.gt(cliffFeeNumerator)) {
21137
+ return new BN10(0);
21138
+ }
21139
+ return SafeMath.sub(cliffFeeNumerator, reduction);
21140
+ }
21141
+ function getFeeNumeratorOnExponentialFeeScheduler(cliffFeeNumerator, reductionFactor, period) {
20894
21142
  if (period === 0) {
20895
21143
  return cliffFeeNumerator;
20896
21144
  }
20897
21145
  if (period === 1) {
20898
- const basisPointMax2 = new BN9(BASIS_POINT_MAX);
21146
+ const basisPointMax2 = new BN10(BASIS_POINT_MAX);
20899
21147
  return mulDiv(
20900
21148
  cliffFeeNumerator,
20901
21149
  basisPointMax2.sub(reductionFactor),
@@ -20903,53 +21151,106 @@ function getFeeInPeriod(cliffFeeNumerator, reductionFactor, period) {
20903
21151
  1 /* Down */
20904
21152
  );
20905
21153
  }
20906
- const basisPointMax = new BN9(BASIS_POINT_MAX);
20907
- const ONE_Q642 = new BN9(1).shln(64);
21154
+ const basisPointMax = new BN10(BASIS_POINT_MAX);
21155
+ const ONE_Q642 = new BN10(1).shln(64);
20908
21156
  const reductionFactorScaled = SafeMath.div(
20909
21157
  SafeMath.shl(reductionFactor, 64),
20910
21158
  basisPointMax
20911
21159
  );
20912
21160
  let base = SafeMath.sub(ONE_Q642, reductionFactorScaled);
20913
- const result = pow(base, new BN9(period));
21161
+ const result = pow(base, new BN10(period));
20914
21162
  return SafeMath.div(SafeMath.mul(cliffFeeNumerator, result), ONE_Q642);
20915
21163
  }
20916
- function getCurrentBaseFeeNumerator(baseFee, currentPoint, activationPoint) {
20917
- if (baseFee.periodFrequency.isZero()) {
20918
- return baseFee.cliffFeeNumerator;
20919
- }
20920
- let period;
20921
- if (currentPoint.lt(activationPoint)) {
20922
- period = baseFee.numberOfPeriod;
20923
- } else {
20924
- const elapsedPoints = SafeMath.sub(currentPoint, activationPoint);
20925
- const periodCount = SafeMath.div(elapsedPoints, baseFee.periodFrequency);
20926
- period = Math.min(
20927
- parseInt(periodCount.toString()),
20928
- baseFee.numberOfPeriod
21164
+
21165
+ // src/math/feeMath.ts
21166
+ function getBaseFeeNumerator(baseFee, tradeDirection, currentPoint, activationPoint, inputAmount) {
21167
+ const baseFeeMode = baseFee.baseFeeMode;
21168
+ if (baseFeeMode === 2 /* RateLimiter */) {
21169
+ const feeIncrementBps = baseFee.firstFactor;
21170
+ const maxLimiterDuration = baseFee.secondFactor;
21171
+ const referenceAmount = baseFee.thirdFactor;
21172
+ const isBaseToQuote = tradeDirection === 0 /* BaseToQuote */;
21173
+ const isRateLimiterApplied = checkRateLimiterApplied(
21174
+ baseFeeMode,
21175
+ isBaseToQuote,
21176
+ currentPoint,
21177
+ activationPoint,
21178
+ baseFee.secondFactor
20929
21179
  );
20930
- }
20931
- const feeSchedulerMode = baseFee.feeSchedulerMode;
20932
- if (feeSchedulerMode === 0 /* Linear */) {
20933
- const reduction = SafeMath.mul(new BN9(period), baseFee.reductionFactor);
20934
- if (reduction.gt(baseFee.cliffFeeNumerator)) {
20935
- return new BN9(0);
21180
+ if (currentPoint.lt(activationPoint)) {
21181
+ return baseFee.cliffFeeNumerator;
21182
+ }
21183
+ const lastEffectivePoint = activationPoint.add(maxLimiterDuration);
21184
+ if (currentPoint.gt(lastEffectivePoint)) {
21185
+ return baseFee.cliffFeeNumerator;
21186
+ }
21187
+ if (!inputAmount) {
21188
+ return baseFee.cliffFeeNumerator;
21189
+ }
21190
+ if (isRateLimiterApplied) {
21191
+ return getFeeNumeratorOnRateLimiter(
21192
+ baseFee.cliffFeeNumerator,
21193
+ referenceAmount,
21194
+ new BN11(feeIncrementBps),
21195
+ inputAmount
21196
+ );
21197
+ } else {
21198
+ return baseFee.cliffFeeNumerator;
20936
21199
  }
20937
- return SafeMath.sub(baseFee.cliffFeeNumerator, reduction);
20938
- } else if (feeSchedulerMode === 1 /* Exponential */) {
20939
- return getFeeInPeriod(
20940
- baseFee.cliffFeeNumerator,
20941
- baseFee.reductionFactor,
20942
- period
20943
- );
20944
21200
  } else {
20945
- throw new Error("Invalid fee scheduler mode");
21201
+ const numberOfPeriod = baseFee.firstFactor;
21202
+ const periodFrequency = baseFee.secondFactor;
21203
+ const reductionFactor = baseFee.thirdFactor;
21204
+ if (periodFrequency.isZero()) {
21205
+ return baseFee.cliffFeeNumerator;
21206
+ }
21207
+ let period;
21208
+ if (currentPoint.lt(activationPoint)) {
21209
+ period = numberOfPeriod;
21210
+ } else {
21211
+ const elapsedPoints = SafeMath.sub(currentPoint, activationPoint);
21212
+ const periodCount = SafeMath.div(elapsedPoints, periodFrequency);
21213
+ period = Math.min(parseInt(periodCount.toString()), numberOfPeriod);
21214
+ }
21215
+ if (baseFeeMode === 0 /* FeeSchedulerLinear */) {
21216
+ return getFeeNumeratorOnLinearFeeScheduler(
21217
+ baseFee.cliffFeeNumerator,
21218
+ reductionFactor,
21219
+ period
21220
+ );
21221
+ } else {
21222
+ return getFeeNumeratorOnExponentialFeeScheduler(
21223
+ baseFee.cliffFeeNumerator,
21224
+ reductionFactor,
21225
+ period
21226
+ );
21227
+ }
21228
+ }
21229
+ }
21230
+ function getVariableFee(dynamicFee, volatilityTracker) {
21231
+ if (dynamicFee.initialized === 0) {
21232
+ return new BN11(0);
21233
+ }
21234
+ if (volatilityTracker.volatilityAccumulator.isZero()) {
21235
+ return new BN11(0);
20946
21236
  }
21237
+ const volatilityTimesBinStep = SafeMath.mul(
21238
+ volatilityTracker.volatilityAccumulator,
21239
+ new BN11(dynamicFee.binStep)
21240
+ );
21241
+ const squared = SafeMath.mul(volatilityTimesBinStep, volatilityTimesBinStep);
21242
+ const vFee = SafeMath.mul(squared, new BN11(dynamicFee.variableFeeControl));
21243
+ const scaleFactor = new BN11(1e11);
21244
+ const numerator = SafeMath.add(vFee, SafeMath.sub(scaleFactor, new BN11(1)));
21245
+ return SafeMath.div(numerator, scaleFactor);
20947
21246
  }
20948
- function getFeeOnAmount(amount, poolFees, isReferral, currentPoint, activationPoint, volatilityTracker) {
20949
- const baseFeeNumerator = getCurrentBaseFeeNumerator(
21247
+ function getFeeOnAmount(amount, poolFees, isReferral, currentPoint, activationPoint, volatilityTracker, tradeDirection) {
21248
+ const baseFeeNumerator = getBaseFeeNumerator(
20950
21249
  poolFees.baseFee,
21250
+ tradeDirection,
20951
21251
  currentPoint,
20952
- activationPoint
21252
+ activationPoint,
21253
+ poolFees.baseFee.baseFeeMode === 2 /* RateLimiter */ ? amount : void 0
20953
21254
  );
20954
21255
  let totalFeeNumerator = baseFeeNumerator;
20955
21256
  if (poolFees.dynamicFee.initialized !== 0) {
@@ -20959,29 +21260,29 @@ function getFeeOnAmount(amount, poolFees, isReferral, currentPoint, activationPo
20959
21260
  );
20960
21261
  totalFeeNumerator = SafeMath.add(totalFeeNumerator, variableFee);
20961
21262
  }
20962
- if (totalFeeNumerator.gt(new BN9(MAX_FEE_NUMERATOR))) {
20963
- totalFeeNumerator = new BN9(MAX_FEE_NUMERATOR);
21263
+ if (totalFeeNumerator.gt(new BN11(MAX_FEE_NUMERATOR))) {
21264
+ totalFeeNumerator = new BN11(MAX_FEE_NUMERATOR);
20964
21265
  }
20965
21266
  const tradingFee = mulDiv(
20966
21267
  amount,
20967
21268
  totalFeeNumerator,
20968
- new BN9(FEE_DENOMINATOR),
21269
+ new BN11(FEE_DENOMINATOR),
20969
21270
  0 /* Up */
20970
21271
  );
20971
21272
  const amountAfterFee = SafeMath.sub(amount, tradingFee);
20972
21273
  const protocolFee = mulDiv(
20973
21274
  tradingFee,
20974
- new BN9(poolFees.protocolFeePercent),
20975
- new BN9(100),
21275
+ new BN11(poolFees.protocolFeePercent),
21276
+ new BN11(100),
20976
21277
  1 /* Down */
20977
21278
  );
20978
21279
  const tradingFeeAfterProtocol = SafeMath.sub(tradingFee, protocolFee);
20979
- let referralFee = new BN9(0);
21280
+ let referralFee = new BN11(0);
20980
21281
  if (isReferral) {
20981
21282
  referralFee = mulDiv(
20982
21283
  protocolFee,
20983
- new BN9(poolFees.referralFeePercent),
20984
- new BN9(100),
21284
+ new BN11(poolFees.referralFeePercent),
21285
+ new BN11(100),
20985
21286
  1 /* Down */
20986
21287
  );
20987
21288
  }
@@ -20993,29 +21294,12 @@ function getFeeOnAmount(amount, poolFees, isReferral, currentPoint, activationPo
20993
21294
  referralFee
20994
21295
  };
20995
21296
  }
20996
- function getVariableFee(dynamicFee, volatilityTracker) {
20997
- if (dynamicFee.initialized === 0) {
20998
- return new BN9(0);
20999
- }
21000
- if (volatilityTracker.volatilityAccumulator.isZero()) {
21001
- return new BN9(0);
21002
- }
21003
- const volatilityTimesBinStep = SafeMath.mul(
21004
- volatilityTracker.volatilityAccumulator,
21005
- new BN9(dynamicFee.binStep)
21006
- );
21007
- const squared = SafeMath.mul(volatilityTimesBinStep, volatilityTimesBinStep);
21008
- const vFee = SafeMath.mul(squared, new BN9(dynamicFee.variableFeeControl));
21009
- const scaleFactor = new BN9(1e11);
21010
- const numerator = SafeMath.add(vFee, SafeMath.sub(scaleFactor, new BN9(1)));
21011
- return SafeMath.div(numerator, scaleFactor);
21012
- }
21013
21297
 
21014
21298
  // src/math/swapQuote.ts
21015
21299
  function getSwapResult(poolState, configState, amountIn, feeMode, tradeDirection, currentPoint) {
21016
- let actualProtocolFee = new BN10(0);
21017
- let actualTradingFee = new BN10(0);
21018
- let actualReferralFee = new BN10(0);
21300
+ let actualProtocolFee = new BN12(0);
21301
+ let actualTradingFee = new BN12(0);
21302
+ let actualReferralFee = new BN12(0);
21019
21303
  let actualAmountIn;
21020
21304
  if (feeMode.feesOnInput) {
21021
21305
  const feeResult = getFeeOnAmount(
@@ -21024,7 +21308,8 @@ function getSwapResult(poolState, configState, amountIn, feeMode, tradeDirection
21024
21308
  feeMode.hasReferral,
21025
21309
  currentPoint,
21026
21310
  poolState.activationPoint,
21027
- poolState.volatilityTracker
21311
+ poolState.volatilityTracker,
21312
+ tradeDirection
21028
21313
  );
21029
21314
  actualProtocolFee = feeResult.protocolFee;
21030
21315
  actualTradingFee = feeResult.tradingFee;
@@ -21052,7 +21337,8 @@ function getSwapResult(poolState, configState, amountIn, feeMode, tradeDirection
21052
21337
  feeMode.hasReferral,
21053
21338
  currentPoint,
21054
21339
  poolState.activationPoint,
21055
- poolState.volatilityTracker
21340
+ poolState.volatilityTracker,
21341
+ tradeDirection
21056
21342
  );
21057
21343
  actualProtocolFee = feeResult.protocolFee;
21058
21344
  actualTradingFee = feeResult.tradingFee;
@@ -21077,11 +21363,11 @@ function getSwapResult(poolState, configState, amountIn, feeMode, tradeDirection
21077
21363
  function getSwapAmountFromBaseToQuote(configState, currentSqrtPrice, amountIn) {
21078
21364
  if (amountIn.isZero()) {
21079
21365
  return {
21080
- outputAmount: new BN10(0),
21366
+ outputAmount: new BN12(0),
21081
21367
  nextSqrtPrice: currentSqrtPrice
21082
21368
  };
21083
21369
  }
21084
- let totalOutputAmount = new BN10(0);
21370
+ let totalOutputAmount = new BN12(0);
21085
21371
  let sqrtPrice = currentSqrtPrice;
21086
21372
  let amountLeft = amountIn;
21087
21373
  for (let i = configState.curve.length - 1; i >= 0; i--) {
@@ -21115,7 +21401,7 @@ function getSwapAmountFromBaseToQuote(configState, currentSqrtPrice, amountIn) {
21115
21401
  outputAmount
21116
21402
  );
21117
21403
  sqrtPrice = nextSqrtPrice;
21118
- amountLeft = new BN10(0);
21404
+ amountLeft = new BN12(0);
21119
21405
  break;
21120
21406
  } else {
21121
21407
  const nextSqrtPrice = configState.curve[i].sqrtPrice;
@@ -21158,11 +21444,11 @@ function getSwapAmountFromBaseToQuote(configState, currentSqrtPrice, amountIn) {
21158
21444
  function getSwapAmountFromQuoteToBase(configState, currentSqrtPrice, amountIn) {
21159
21445
  if (amountIn.isZero()) {
21160
21446
  return {
21161
- outputAmount: new BN10(0),
21447
+ outputAmount: new BN12(0),
21162
21448
  nextSqrtPrice: currentSqrtPrice
21163
21449
  };
21164
21450
  }
21165
- let totalOutputAmount = new BN10(0);
21451
+ let totalOutputAmount = new BN12(0);
21166
21452
  let sqrtPrice = currentSqrtPrice;
21167
21453
  let amountLeft = amountIn;
21168
21454
  for (let i = 0; i < configState.curve.length; i++) {
@@ -21195,7 +21481,7 @@ function getSwapAmountFromQuoteToBase(configState, currentSqrtPrice, amountIn) {
21195
21481
  outputAmount
21196
21482
  );
21197
21483
  sqrtPrice = nextSqrtPrice;
21198
- amountLeft = new BN10(0);
21484
+ amountLeft = new BN12(0);
21199
21485
  break;
21200
21486
  } else {
21201
21487
  const nextSqrtPrice = configState.curve[i].sqrtPrice;
@@ -21254,8 +21540,8 @@ async function swapQuote(virtualPool, config, swapBaseForQuote, amountIn, slippa
21254
21540
  currentPoint
21255
21541
  );
21256
21542
  if (slippageBps > 0) {
21257
- const slippageFactor = new BN10(1e4 - slippageBps);
21258
- const denominator = new BN10(1e4);
21543
+ const slippageFactor = new BN12(1e4 - slippageBps);
21544
+ const denominator = new BN12(1e4);
21259
21545
  const minimumAmountOut = result.amountOut.mul(slippageFactor).div(denominator);
21260
21546
  return {
21261
21547
  ...result,
@@ -21264,6 +21550,40 @@ async function swapQuote(virtualPool, config, swapBaseForQuote, amountIn, slippa
21264
21550
  }
21265
21551
  return result;
21266
21552
  }
21553
+ function calculateQuoteExactInAmount(config, virtualPool, currentPoint) {
21554
+ if (virtualPool.quoteReserve.gte(config.migrationQuoteThreshold)) {
21555
+ return new BN12(0);
21556
+ }
21557
+ const amountInAfterFee = config.migrationQuoteThreshold.sub(
21558
+ virtualPool.quoteReserve
21559
+ );
21560
+ if (config.collectFeeMode === 0 /* OnlyQuote */) {
21561
+ const baseFeeNumerator = getBaseFeeNumerator(
21562
+ config.poolFees.baseFee,
21563
+ 1 /* QuoteToBase */,
21564
+ currentPoint,
21565
+ virtualPool.activationPoint
21566
+ );
21567
+ let totalFeeNumerator = baseFeeNumerator;
21568
+ if (config.poolFees.dynamicFee.initialized !== 0) {
21569
+ const variableFee = getVariableFee(
21570
+ config.poolFees.dynamicFee,
21571
+ virtualPool.volatilityTracker
21572
+ );
21573
+ totalFeeNumerator = SafeMath.add(totalFeeNumerator, variableFee);
21574
+ }
21575
+ totalFeeNumerator = BN12.min(totalFeeNumerator, new BN12(MAX_FEE_NUMERATOR));
21576
+ const denominator = new BN12(FEE_DENOMINATOR).sub(totalFeeNumerator);
21577
+ return mulDiv(
21578
+ amountInAfterFee,
21579
+ new BN12(FEE_DENOMINATOR),
21580
+ denominator,
21581
+ 0 /* Up */
21582
+ );
21583
+ } else {
21584
+ return amountInAfterFee;
21585
+ }
21586
+ }
21267
21587
 
21268
21588
  // src/services/state.ts
21269
21589
  import { PublicKey as PublicKey8 } from "@solana/web3.js";
@@ -21508,6 +21828,7 @@ var StateService = class extends DynamicBondingCurveProgram {
21508
21828
  };
21509
21829
 
21510
21830
  // src/services/pool.ts
21831
+ import BN13 from "bn.js";
21511
21832
  var PoolService = class extends DynamicBondingCurveProgram {
21512
21833
  constructor(connection, commitment) {
21513
21834
  super(connection, commitment);
@@ -21682,6 +22003,22 @@ var PoolService = class extends DynamicBondingCurveProgram {
21682
22003
  const { baseMint, poolCreator } = createConfigAndPoolWithFirstBuyParam.createPoolParam;
21683
22004
  const { buyAmount, minimumAmountOut, referralTokenAccount } = createConfigAndPoolWithFirstBuyParam.swapBuyParam;
21684
22005
  validateSwapAmount(buyAmount);
22006
+ let currentPoint;
22007
+ if (createConfigAndPoolWithFirstBuyParam.activationType === 0 /* Slot */) {
22008
+ const currentSlot = await this.connection.getSlot();
22009
+ currentPoint = currentSlot;
22010
+ } else {
22011
+ const currentSlot = await this.connection.getSlot();
22012
+ const currentTime = await this.connection.getBlockTime(currentSlot);
22013
+ currentPoint = currentTime;
22014
+ }
22015
+ const isRateLimiterApplied = checkRateLimiterApplied(
22016
+ createConfigAndPoolWithFirstBuyParam.poolFees.baseFee.baseFeeMode,
22017
+ false,
22018
+ new BN13(0),
22019
+ new BN13(0),
22020
+ new BN13(0)
22021
+ );
21685
22022
  const quoteTokenFlag = await getTokenType(this.connection, quoteMint);
21686
22023
  const { inputMint, outputMint, inputTokenProgram, outputTokenProgram } = this.prepareSwapParams(
21687
22024
  false,
@@ -21725,6 +22062,13 @@ var PoolService = class extends DynamicBondingCurveProgram {
21725
22062
  const unwrapIx = unwrapSOLInstruction(poolCreator, poolCreator);
21726
22063
  unwrapIx && postInstructions.push(unwrapIx);
21727
22064
  }
22065
+ const remainingAccounts = isRateLimiterApplied ? [
22066
+ {
22067
+ isSigner: false,
22068
+ isWritable: false,
22069
+ pubkey: SYSVAR_INSTRUCTIONS_PUBKEY
22070
+ }
22071
+ ] : [];
21728
22072
  return this.program.methods.swap({
21729
22073
  amountIn: buyAmount,
21730
22074
  minimumAmountOut
@@ -21742,7 +22086,7 @@ var PoolService = class extends DynamicBondingCurveProgram {
21742
22086
  payer: poolCreator,
21743
22087
  tokenBaseProgram: outputTokenProgram,
21744
22088
  tokenQuoteProgram: inputTokenProgram
21745
- }).preInstructions(preInstructions).postInstructions(postInstructions).transaction();
22089
+ }).remainingAccounts(remainingAccounts).preInstructions(preInstructions).postInstructions(postInstructions).transaction();
21746
22090
  }
21747
22091
  /**
21748
22092
  * Create a new pool
@@ -21915,6 +22259,22 @@ var PoolService = class extends DynamicBondingCurveProgram {
21915
22259
  tx = await this.initializeToken2022Pool(baseParams);
21916
22260
  }
21917
22261
  validateSwapAmount(buyAmount);
22262
+ let currentPoint;
22263
+ if (poolConfigState.activationType === 0 /* Slot */) {
22264
+ const currentSlot = await this.connection.getSlot();
22265
+ currentPoint = new BN13(currentSlot);
22266
+ } else {
22267
+ const currentSlot = await this.connection.getSlot();
22268
+ const currentTime = await this.connection.getBlockTime(currentSlot);
22269
+ currentPoint = new BN13(currentTime);
22270
+ }
22271
+ const isRateLimiterApplied = checkRateLimiterApplied(
22272
+ poolConfigState.poolFees.baseFee.baseFeeMode,
22273
+ false,
22274
+ new BN13(0),
22275
+ new BN13(0),
22276
+ new BN13(0)
22277
+ );
21918
22278
  const { inputMint, outputMint, inputTokenProgram, outputTokenProgram } = this.prepareSwapParams(
21919
22279
  false,
21920
22280
  { baseMint, poolType: tokenType },
@@ -21948,7 +22308,14 @@ var PoolService = class extends DynamicBondingCurveProgram {
21948
22308
  const unwrapIx = unwrapSOLInstruction(poolCreator, poolCreator);
21949
22309
  unwrapIx && postInstructions.push(unwrapIx);
21950
22310
  }
21951
- const swapTx = await this.program.methods.swap({
22311
+ const remainingAccounts = isRateLimiterApplied ? [
22312
+ {
22313
+ isSigner: false,
22314
+ isWritable: false,
22315
+ pubkey: SYSVAR_INSTRUCTIONS_PUBKEY
22316
+ }
22317
+ ] : [];
22318
+ const firstBuyTx = await this.program.methods.swap({
21952
22319
  amountIn: buyAmount,
21953
22320
  minimumAmountOut
21954
22321
  }).accountsPartial({
@@ -21965,8 +22332,8 @@ var PoolService = class extends DynamicBondingCurveProgram {
21965
22332
  payer: poolCreator,
21966
22333
  tokenBaseProgram: outputTokenProgram,
21967
22334
  tokenQuoteProgram: inputTokenProgram
21968
- }).preInstructions(preInstructions).postInstructions(postInstructions).transaction();
21969
- tx.add(...swapTx.instructions);
22335
+ }).remainingAccounts(remainingAccounts).preInstructions(preInstructions).postInstructions(postInstructions).transaction();
22336
+ tx.add(...firstBuyTx.instructions);
21970
22337
  return tx;
21971
22338
  }
21972
22339
  /**
@@ -21983,6 +22350,22 @@ var PoolService = class extends DynamicBondingCurveProgram {
21983
22350
  const poolConfigState = await this.state.getPoolConfig(poolState.config);
21984
22351
  const { amountIn, minimumAmountOut, swapBaseForQuote, owner } = swapParam;
21985
22352
  validateSwapAmount(amountIn);
22353
+ let currentPoint;
22354
+ if (poolConfigState.activationType === 0 /* Slot */) {
22355
+ const currentSlot = await this.connection.getSlot();
22356
+ currentPoint = new BN13(currentSlot);
22357
+ } else {
22358
+ const currentSlot = await this.connection.getSlot();
22359
+ const currentTime = await this.connection.getBlockTime(currentSlot);
22360
+ currentPoint = new BN13(currentTime);
22361
+ }
22362
+ const isRateLimiterApplied = checkRateLimiterApplied(
22363
+ poolConfigState.poolFees.baseFee.baseFeeMode,
22364
+ swapBaseForQuote,
22365
+ currentPoint,
22366
+ poolState.activationPoint,
22367
+ poolConfigState.poolFees.baseFee.secondFactor
22368
+ );
21986
22369
  const { inputMint, outputMint, inputTokenProgram, outputTokenProgram } = this.prepareSwapParams(swapBaseForQuote, poolState, poolConfigState);
21987
22370
  const {
21988
22371
  ataTokenA: inputTokenAccount,
@@ -22012,6 +22395,13 @@ var PoolService = class extends DynamicBondingCurveProgram {
22012
22395
  const unwrapIx = unwrapSOLInstruction(owner, owner);
22013
22396
  unwrapIx && postInstructions.push(unwrapIx);
22014
22397
  }
22398
+ const remainingAccounts = isRateLimiterApplied ? [
22399
+ {
22400
+ isSigner: false,
22401
+ isWritable: false,
22402
+ pubkey: SYSVAR_INSTRUCTIONS_PUBKEY
22403
+ }
22404
+ ] : [];
22015
22405
  return this.program.methods.swap({
22016
22406
  amountIn,
22017
22407
  minimumAmountOut
@@ -22029,7 +22419,7 @@ var PoolService = class extends DynamicBondingCurveProgram {
22029
22419
  payer: owner,
22030
22420
  tokenBaseProgram: swapBaseForQuote ? inputTokenProgram : outputTokenProgram,
22031
22421
  tokenQuoteProgram: swapBaseForQuote ? outputTokenProgram : inputTokenProgram
22032
- }).preInstructions(preInstructions).postInstructions(postInstructions).transaction();
22422
+ }).remainingAccounts(remainingAccounts).preInstructions(preInstructions).postInstructions(postInstructions).transaction();
22033
22423
  }
22034
22424
  /**
22035
22425
  * Calculate the amount out for a swap (quote)
@@ -22062,6 +22452,17 @@ var PoolService = class extends DynamicBondingCurveProgram {
22062
22452
  currentPoint
22063
22453
  );
22064
22454
  }
22455
+ swapQuoteExactIn(swapQuoteExactInParam) {
22456
+ const { virtualPool, config, currentPoint } = swapQuoteExactInParam;
22457
+ const requiredQuoteAmount = calculateQuoteExactInAmount(
22458
+ config,
22459
+ virtualPool,
22460
+ currentPoint
22461
+ );
22462
+ return {
22463
+ exactAmountIn: requiredQuoteAmount
22464
+ };
22465
+ }
22065
22466
  };
22066
22467
 
22067
22468
  // src/services/migration.ts
@@ -23478,6 +23879,7 @@ export {
23478
23879
  BASIS_POINT_MAX,
23479
23880
  BIN_STEP_BPS_DEFAULT,
23480
23881
  BIN_STEP_BPS_U128_DEFAULT,
23882
+ BaseFeeMode,
23481
23883
  CollectFeeMode,
23482
23884
  CreatorService,
23483
23885
  DAMM_V1_MIGRATION_FEE_ADDRESS,
@@ -23491,15 +23893,19 @@ export {
23491
23893
  DynamicBondingCurveClient,
23492
23894
  DynamicBondingCurveProgram,
23493
23895
  FEE_DENOMINATOR,
23494
- FeeSchedulerMode,
23495
23896
  GetFeeMode,
23496
23897
  LOCKER_PROGRAM_ID,
23497
23898
  MAX_CURVE_POINT,
23899
+ MAX_FEE_BPS,
23498
23900
  MAX_FEE_NUMERATOR,
23499
23901
  MAX_PRICE_CHANGE_BPS_DEFAULT,
23902
+ MAX_RATE_LIMITER_DURATION_IN_SECONDS,
23903
+ MAX_RATE_LIMITER_DURATION_IN_SLOTS,
23500
23904
  MAX_SQRT_PRICE,
23501
23905
  MAX_SWALLOW_PERCENTAGE,
23502
23906
  METAPLEX_PROGRAM_ID,
23907
+ MIN_FEE_BPS,
23908
+ MIN_FEE_NUMERATOR,
23503
23909
  MIN_SQRT_PRICE,
23504
23910
  MigrationFeeOption,
23505
23911
  MigrationOption,
@@ -23525,6 +23931,9 @@ export {
23525
23931
  buildCurveWithLiquidityWeights,
23526
23932
  buildCurveWithMarketCap,
23527
23933
  buildCurveWithTwoSegments,
23934
+ calculateFeeSchedulerEndingBaseFeeBps,
23935
+ calculateQuoteExactInAmount,
23936
+ checkRateLimiterApplied,
23528
23937
  cleanUpTokenAccountTx,
23529
23938
  convertDecimalToBN,
23530
23939
  convertToLamports,
@@ -23571,16 +23980,19 @@ export {
23571
23980
  getAccountCreationTimestamp,
23572
23981
  getAccountCreationTimestamps,
23573
23982
  getAccountData,
23983
+ getBaseFeeNumerator,
23574
23984
  getBaseFeeParams,
23575
23985
  getBaseTokenForSwap,
23576
- getCurrentBaseFeeNumerator,
23577
23986
  getDeltaAmountBase,
23578
23987
  getDeltaAmountBaseUnsigned,
23579
23988
  getDeltaAmountQuoteUnsigned,
23580
23989
  getDynamicFeeParams,
23581
- getFeeInPeriod,
23582
23990
  getFeeMode,
23991
+ getFeeNumeratorOnExponentialFeeScheduler,
23992
+ getFeeNumeratorOnLinearFeeScheduler,
23993
+ getFeeNumeratorOnRateLimiter,
23583
23994
  getFeeOnAmount,
23995
+ getFeeSchedulerParams,
23584
23996
  getFirstCurve,
23585
23997
  getFirstKey,
23586
23998
  getInitialLiquidityFromDeltaBase,
@@ -23593,13 +24005,13 @@ export {
23593
24005
  getMigrationQuoteAmountFromMigrationQuoteThreshold,
23594
24006
  getMigrationQuoteThresholdFromMigrationQuoteAmount,
23595
24007
  getMigrationThresholdPrice,
23596
- getMinBaseFeeBps,
23597
24008
  getNextSqrtPriceFromAmountBaseRoundingUp,
23598
24009
  getNextSqrtPriceFromAmountQuoteRoundingDown,
23599
24010
  getNextSqrtPriceFromInput,
23600
24011
  getOrCreateATAInstruction,
23601
24012
  getPercentageSupplyOnMigration,
23602
24013
  getPriceFromSqrtPrice,
24014
+ getRateLimiterParams,
23603
24015
  getSecondKey,
23604
24016
  getSqrtPriceFromMarketCap,
23605
24017
  getSqrtPriceFromPrice,
@@ -23626,6 +24038,8 @@ export {
23626
24038
  validateCollectFeeMode,
23627
24039
  validateConfigParameters,
23628
24040
  validateCurve,
24041
+ validateFeeRateLimiter,
24042
+ validateFeeScheduler,
23629
24043
  validateLPPercentages,
23630
24044
  validateMigrationAndTokenType,
23631
24045
  validateMigrationFeeOption,