@exponent-labs/market-three-math 0.9.12 → 0.9.14
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/build/addLiquidity.d.ts +5 -1
- package/build/addLiquidity.js +84 -26
- package/build/addLiquidity.js.map +1 -1
- package/build/existingPositionEqualization.d.ts +63 -0
- package/build/existingPositionEqualization.js +241 -0
- package/build/existingPositionEqualization.js.map +1 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +5 -1
- package/build/index.js.map +1 -1
- package/build/swapLegacy.d.ts +16 -0
- package/build/swapLegacy.js +229 -0
- package/build/swapLegacy.js.map +1 -0
- package/build/swapV2.js +143 -62
- package/build/swapV2.js.map +1 -1
- package/build/utils.d.ts +2 -2
- package/build/utils.js +5 -4
- package/build/utils.js.map +1 -1
- package/jest.config.ts +9 -0
- package/package.json +2 -2
- package/src/addLiquidity.ts +109 -31
- package/src/existingPositionEqualization.test.ts +162 -0
- package/src/existingPositionEqualization.ts +367 -0
- package/src/index.ts +11 -0
- package/src/swapV2.ts +192 -110
- package/src/utils.ts +6 -4
package/src/swapV2.ts
CHANGED
|
@@ -3,23 +3,19 @@
|
|
|
3
3
|
* Closely mirrors the Rust on-chain implementation from swap.rs
|
|
4
4
|
* Uses TicksWrapper to simulate RB-tree behavior
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
SwapArgs,
|
|
9
|
-
SwapDirection,
|
|
10
|
-
SwapExactOutArgs,
|
|
11
|
-
SwapOutcomeV2,
|
|
12
|
-
} from "./types"
|
|
13
|
-
import {
|
|
14
|
-
EffSnap,
|
|
15
|
-
TicksWrapper,
|
|
16
|
-
calculateFeeRate,
|
|
17
|
-
getFeeFromAmount,
|
|
18
|
-
normalizedTimeRemaining,
|
|
19
|
-
} from "./utilsV2"
|
|
6
|
+
import { MarketThreeState, SwapArgs, SwapDirection, SwapExactOutArgs, SwapOutcomeV2 } from "./types"
|
|
7
|
+
import { EffSnap, TicksWrapper, calculateFeeRate, getFeeFromAmount, normalizedTimeRemaining } from "./utilsV2"
|
|
20
8
|
|
|
21
9
|
const BASE_POINTS = 10000
|
|
22
10
|
|
|
11
|
+
function computeFlashFeeOut(ytValue: number, grossOut: number, lpFeeRate: number): number {
|
|
12
|
+
if (grossOut === 0) {
|
|
13
|
+
return 0
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return Math.min(grossOut, Math.max(1, getFeeFromAmount(ytValue, lpFeeRate)))
|
|
17
|
+
}
|
|
18
|
+
|
|
23
19
|
/**
|
|
24
20
|
* Simulate a swap on the CLMM market (V2 - mirrors Rust closely)
|
|
25
21
|
* This is a pure function that does not mutate the market state
|
|
@@ -364,7 +360,7 @@ export function simulateSwap(marketState: MarketThreeState, args: SwapArgs): Swa
|
|
|
364
360
|
if (args.isCurrentFlashSwap) {
|
|
365
361
|
const syInBase = syInSegmentU64 * args.syExchangeRate
|
|
366
362
|
const ytValue = ptOutGrossU64 - syInBase
|
|
367
|
-
totalFeeOut =
|
|
363
|
+
totalFeeOut = computeFlashFeeOut(Math.max(0, Math.floor(ytValue)), ptOutGrossU64, lpFeeRate)
|
|
368
364
|
} else {
|
|
369
365
|
totalFeeOut = getFeeFromAmount(ptOutGrossU64, lpFeeRate)
|
|
370
366
|
}
|
|
@@ -605,6 +601,8 @@ export function simulateSwapExactOut(marketState: MarketThreeState, args: SwapEx
|
|
|
605
601
|
|
|
606
602
|
const totalFeeOutBoundary = getFeeFromAmount(ptOutGrossBoundaryU64, lpFeeRate)
|
|
607
603
|
const ptOutNetBoundary = Math.max(0, ptOutGrossBoundaryU64 - totalFeeOutBoundary)
|
|
604
|
+
let boundarySegmentSeed: ReturnType<typeof calculateSwapSegment> | null = null
|
|
605
|
+
let ptOutNetBoundaryEffectiveSeed: number | null = null
|
|
608
606
|
|
|
609
607
|
if (ptOutNetBoundary === 0) {
|
|
610
608
|
const boundarySegment = calculateSwapSegment(
|
|
@@ -619,87 +617,115 @@ export function simulateSwapExactOut(marketState: MarketThreeState, args: SwapEx
|
|
|
619
617
|
args.isCurrentFlashSwap,
|
|
620
618
|
)
|
|
621
619
|
|
|
622
|
-
|
|
623
|
-
if (
|
|
624
|
-
|
|
625
|
-
|
|
620
|
+
const ptOutNetBoundaryActual = Math.max(0, boundarySegment.ptOutGrossActual - boundarySegment.totalFeeOut)
|
|
621
|
+
if (ptOutNetBoundaryActual > 0) {
|
|
622
|
+
boundarySegmentSeed = boundarySegment
|
|
623
|
+
ptOutNetBoundaryEffectiveSeed = ptOutNetBoundaryActual
|
|
624
|
+
} else {
|
|
625
|
+
let syInBoundary = boundarySegment.syInSegmentU64
|
|
626
|
+
if (ptOutGrossBoundaryU64 > 0 && syInBoundary === 0) {
|
|
627
|
+
syInBoundary = 1
|
|
628
|
+
}
|
|
626
629
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
) {
|
|
631
|
-
throw new Error("Insufficient SY budget for exact-out trade")
|
|
632
|
-
}
|
|
630
|
+
if (amountInConstraint !== undefined && amountInConsumed + syInBoundary > amountInConstraint) {
|
|
631
|
+
throw new Error("Insufficient SY budget for exact-out trade")
|
|
632
|
+
}
|
|
633
633
|
|
|
634
|
-
|
|
634
|
+
amountInConsumed += syInBoundary
|
|
635
635
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
636
|
+
if (boundarySegment.totalFeeOut > 0) {
|
|
637
|
+
const protocolFeeOut = Math.floor((boundarySegment.totalFeeOut * protocolFeeBps) / BASE_POINTS)
|
|
638
|
+
const lpFeeOut = boundarySegment.totalFeeOut - protocolFeeOut
|
|
639
|
+
feeLpOutU64 += lpFeeOut
|
|
640
|
+
feeProtocolOutU64 += protocolFeeOut
|
|
641
|
+
}
|
|
642
642
|
|
|
643
|
-
|
|
644
|
-
|
|
643
|
+
if (syInBoundary > 0 || boundarySegment.ptOutGrossActual > 0) {
|
|
644
|
+
ticksWrapper.setPrincipals(
|
|
645
|
+
currentLeftBoundaryKey,
|
|
646
|
+
principalPt - BigInt(boundarySegment.ptOutGrossActual),
|
|
647
|
+
principalSy + BigInt(syInBoundary),
|
|
648
|
+
)
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
currentPriceSpot = boundarySegment.spotPriceNew
|
|
652
|
+
|
|
653
|
+
const crossed = crossOneBoundary(ticksWrapper, SwapDirection.SyToPt, currentLeftBoundaryKey, {
|
|
645
654
|
currentLeftBoundaryKey,
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
655
|
+
currentPriceSpot,
|
|
656
|
+
activeLiquidityU64,
|
|
657
|
+
activeLiquidityF64,
|
|
658
|
+
})
|
|
659
|
+
if (!crossed) break
|
|
660
|
+
currentLeftBoundaryKey = crossed.currentLeftBoundaryKey
|
|
661
|
+
currentPriceSpot = crossed.currentPriceSpot
|
|
662
|
+
activeLiquidityU64 = crossed.activeLiquidityU64
|
|
663
|
+
activeLiquidityF64 = crossed.activeLiquidityF64
|
|
664
|
+
continue
|
|
649
665
|
}
|
|
666
|
+
}
|
|
650
667
|
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
668
|
+
let ptOutNetBoundaryEffective = ptOutNetBoundaryEffectiveSeed ?? ptOutNetBoundary
|
|
669
|
+
let precomputedBoundarySegment: ReturnType<typeof calculateSwapSegment> | null = null
|
|
670
|
+
if (amountOutLeft >= ptOutNetBoundary) {
|
|
671
|
+
const boundarySegment =
|
|
672
|
+
boundarySegmentSeed ??
|
|
673
|
+
calculateSwapSegment(
|
|
674
|
+
ptOutGrossBoundaryU64,
|
|
675
|
+
lTradeF64,
|
|
676
|
+
currentPriceSpot,
|
|
677
|
+
duToLeft,
|
|
678
|
+
anchorULeft,
|
|
679
|
+
snapshot,
|
|
680
|
+
cEffOld,
|
|
681
|
+
lpFeeRate,
|
|
682
|
+
args.isCurrentFlashSwap,
|
|
683
|
+
)
|
|
684
|
+
const ptOutNetBoundaryActual =
|
|
685
|
+
ptOutNetBoundaryEffectiveSeed ?? Math.max(0, boundarySegment.ptOutGrossActual - boundarySegment.totalFeeOut)
|
|
686
|
+
ptOutNetBoundaryEffective = ptOutNetBoundaryActual
|
|
687
|
+
if (ptOutNetBoundaryActual > 0 && amountOutLeft >= ptOutNetBoundaryActual) {
|
|
688
|
+
precomputedBoundarySegment = boundarySegment
|
|
689
|
+
}
|
|
665
690
|
}
|
|
666
691
|
|
|
667
|
-
const targetNet = Math.min(amountOutLeft,
|
|
668
|
-
const grossCandidate =
|
|
669
|
-
|
|
670
|
-
|
|
692
|
+
const targetNet = Math.min(amountOutLeft, ptOutNetBoundaryEffective)
|
|
693
|
+
const grossCandidate = precomputedBoundarySegment
|
|
694
|
+
? ptOutGrossBoundaryU64
|
|
695
|
+
: findGrossForTargetNet(targetNet, Math.min(targetNet, ptOutGrossBoundaryU64), ptOutGrossBoundaryU64, (gross) =>
|
|
696
|
+
calculateNetPtOut(
|
|
697
|
+
gross,
|
|
698
|
+
lTradeF64,
|
|
699
|
+
currentPriceSpot,
|
|
700
|
+
duToLeft,
|
|
701
|
+
anchorULeft,
|
|
702
|
+
lpFeeRate,
|
|
703
|
+
args.isCurrentFlashSwap,
|
|
704
|
+
snapshot,
|
|
705
|
+
cEffOld,
|
|
706
|
+
),
|
|
707
|
+
)
|
|
708
|
+
|
|
709
|
+
const segment =
|
|
710
|
+
precomputedBoundarySegment ??
|
|
711
|
+
calculateSwapSegment(
|
|
712
|
+
grossCandidate,
|
|
671
713
|
lTradeF64,
|
|
672
714
|
currentPriceSpot,
|
|
673
715
|
duToLeft,
|
|
674
716
|
anchorULeft,
|
|
675
|
-
lpFeeRate,
|
|
676
|
-
args.isCurrentFlashSwap,
|
|
677
717
|
snapshot,
|
|
678
718
|
cEffOld,
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
const segment = calculateSwapSegment(
|
|
683
|
-
grossCandidate,
|
|
684
|
-
lTradeF64,
|
|
685
|
-
currentPriceSpot,
|
|
686
|
-
duToLeft,
|
|
687
|
-
anchorULeft,
|
|
688
|
-
snapshot,
|
|
689
|
-
cEffOld,
|
|
690
|
-
lpFeeRate,
|
|
691
|
-
args.isCurrentFlashSwap,
|
|
692
|
-
)
|
|
719
|
+
lpFeeRate,
|
|
720
|
+
args.isCurrentFlashSwap,
|
|
721
|
+
)
|
|
693
722
|
|
|
694
723
|
let syInSegmentU64 = segment.syInSegmentU64
|
|
695
724
|
if (grossCandidate > 0 && syInSegmentU64 === 0) {
|
|
696
725
|
syInSegmentU64 = 1
|
|
697
726
|
}
|
|
698
727
|
|
|
699
|
-
if (
|
|
700
|
-
amountInConstraint !== undefined &&
|
|
701
|
-
amountInConsumed + syInSegmentU64 > amountInConstraint
|
|
702
|
-
) {
|
|
728
|
+
if (amountInConstraint !== undefined && amountInConsumed + syInSegmentU64 > amountInConstraint) {
|
|
703
729
|
throw new Error("Insufficient SY budget for exact-out trade")
|
|
704
730
|
}
|
|
705
731
|
|
|
@@ -781,27 +807,11 @@ function computeKappaAndLTrade(
|
|
|
781
807
|
let kappaPt: number
|
|
782
808
|
|
|
783
809
|
if (direction === SwapDirection.SyToPt) {
|
|
784
|
-
kappaPt = isSyOnlyRange
|
|
785
|
-
|
|
786
|
-
: ptMaxToLeftF > 0
|
|
787
|
-
? principalPtInInterval / ptMaxToLeftF
|
|
788
|
-
: Infinity
|
|
789
|
-
kappaSy = isPtOnlyRange
|
|
790
|
-
? 1
|
|
791
|
-
: yMaxToBoundaryF > 0
|
|
792
|
-
? principalSyInInterval / yMaxToBoundaryF
|
|
793
|
-
: Infinity
|
|
810
|
+
kappaPt = isSyOnlyRange ? 0 : ptMaxToLeftF > 0 ? principalPtInInterval / ptMaxToLeftF : Infinity
|
|
811
|
+
kappaSy = isPtOnlyRange ? 1 : yMaxToBoundaryF > 0 ? principalSyInInterval / yMaxToBoundaryF : Infinity
|
|
794
812
|
} else {
|
|
795
|
-
kappaSy = isPtOnlyRange
|
|
796
|
-
|
|
797
|
-
: yMaxToBoundaryF > 0
|
|
798
|
-
? principalSyInInterval / yMaxToBoundaryF
|
|
799
|
-
: Infinity
|
|
800
|
-
kappaPt = isSyOnlyRange
|
|
801
|
-
? 1
|
|
802
|
-
: ptMaxToLeftF > 0
|
|
803
|
-
? principalPtInInterval / ptMaxToLeftF
|
|
804
|
-
: Infinity
|
|
813
|
+
kappaSy = isPtOnlyRange ? 0 : yMaxToBoundaryF > 0 ? principalSyInInterval / yMaxToBoundaryF : Infinity
|
|
814
|
+
kappaPt = isSyOnlyRange ? 1 : ptMaxToLeftF > 0 ? principalPtInInterval / ptMaxToLeftF : Infinity
|
|
805
815
|
}
|
|
806
816
|
|
|
807
817
|
const kappa = Math.min(kappaPt, kappaSy, 1)
|
|
@@ -823,16 +833,94 @@ function findGrossForTargetNet(
|
|
|
823
833
|
maxGross: number,
|
|
824
834
|
calculateNet: (gross: number) => number,
|
|
825
835
|
): number {
|
|
836
|
+
const MAX_INTERPOLATION_STEPS = 6
|
|
837
|
+
const MAX_LOCAL_ADJUST_STEPS = 24
|
|
838
|
+
const MAX_BINARY_FALLBACK_STEPS = 12
|
|
839
|
+
|
|
826
840
|
if (minGross >= maxGross) {
|
|
827
841
|
return minGross
|
|
828
842
|
}
|
|
829
843
|
|
|
830
844
|
let left = minGross
|
|
845
|
+
let leftNet = calculateNet(left)
|
|
846
|
+
if (leftNet >= targetNet) {
|
|
847
|
+
return left
|
|
848
|
+
}
|
|
849
|
+
|
|
831
850
|
let right = maxGross
|
|
832
|
-
let
|
|
851
|
+
let rightNet = calculateNet(right)
|
|
852
|
+
if (rightNet <= targetNet) {
|
|
853
|
+
return right
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
for (let i = 0; i < MAX_INTERPOLATION_STEPS; i++) {
|
|
857
|
+
if (right <= left + 1) {
|
|
858
|
+
return left
|
|
859
|
+
}
|
|
860
|
+
if (rightNet <= leftNet) {
|
|
861
|
+
break
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
const span = right - left
|
|
865
|
+
const targetDelta = Math.max(0, targetNet - leftNet)
|
|
866
|
+
const denominator = rightNet - leftNet
|
|
867
|
+
if (denominator === 0) {
|
|
868
|
+
break
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
const estimatedOffset = Number((BigInt(targetDelta) * BigInt(span)) / BigInt(denominator))
|
|
872
|
+
let estimate = left + estimatedOffset
|
|
873
|
+
if (estimate <= left) {
|
|
874
|
+
estimate = left + 1
|
|
875
|
+
}
|
|
876
|
+
if (estimate >= right) {
|
|
877
|
+
estimate = right - 1
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
const estimateNet = calculateNet(estimate)
|
|
881
|
+
if (estimateNet === targetNet) {
|
|
882
|
+
return estimate
|
|
883
|
+
}
|
|
884
|
+
if (estimateNet < targetNet) {
|
|
885
|
+
left = estimate
|
|
886
|
+
leftNet = estimateNet
|
|
887
|
+
} else {
|
|
888
|
+
right = estimate
|
|
889
|
+
rightNet = estimateNet
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
let best = left
|
|
894
|
+
for (let i = 0; i < MAX_LOCAL_ADJUST_STEPS; i++) {
|
|
895
|
+
if (best >= right) {
|
|
896
|
+
break
|
|
897
|
+
}
|
|
898
|
+
const next = best + 1
|
|
899
|
+
if (next > right) {
|
|
900
|
+
break
|
|
901
|
+
}
|
|
902
|
+
const nextNet = calculateNet(next)
|
|
903
|
+
if (nextNet > targetNet) {
|
|
904
|
+
break
|
|
905
|
+
}
|
|
906
|
+
best = next
|
|
907
|
+
if (nextNet === targetNet) {
|
|
908
|
+
return best
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
if (right <= best + 1) {
|
|
913
|
+
return best
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
let low = best
|
|
917
|
+
let high = right
|
|
918
|
+
let bestGross = best
|
|
919
|
+
let steps = 0
|
|
833
920
|
|
|
834
|
-
while (
|
|
835
|
-
|
|
921
|
+
while (low <= high && steps < MAX_BINARY_FALLBACK_STEPS) {
|
|
922
|
+
steps += 1
|
|
923
|
+
const mid = low + Math.floor((high - low) / 2)
|
|
836
924
|
const net = calculateNet(mid)
|
|
837
925
|
|
|
838
926
|
if (net === targetNet) {
|
|
@@ -841,12 +929,12 @@ function findGrossForTargetNet(
|
|
|
841
929
|
|
|
842
930
|
if (net < targetNet) {
|
|
843
931
|
bestGross = mid
|
|
844
|
-
|
|
932
|
+
low = mid + 1
|
|
845
933
|
} else {
|
|
846
934
|
if (mid === 0) {
|
|
847
935
|
break
|
|
848
936
|
}
|
|
849
|
-
|
|
937
|
+
high = mid - 1
|
|
850
938
|
}
|
|
851
939
|
}
|
|
852
940
|
|
|
@@ -871,10 +959,7 @@ function calculateNetPtOut(
|
|
|
871
959
|
spotPriceNew = anchorULeft
|
|
872
960
|
}
|
|
873
961
|
|
|
874
|
-
const ptOutGrossActual = Math.max(
|
|
875
|
-
0,
|
|
876
|
-
Math.floor(lTradeF64 * (currentPriceSpot - spotPriceNew)),
|
|
877
|
-
)
|
|
962
|
+
const ptOutGrossActual = Math.max(0, Math.floor(lTradeF64 * (currentPriceSpot - spotPriceNew)))
|
|
878
963
|
|
|
879
964
|
const totalFeeOut = isCurrentFlashSwap
|
|
880
965
|
? (() => {
|
|
@@ -882,7 +967,7 @@ function calculateNetPtOut(
|
|
|
882
967
|
const syInSegmentF = lTradeF64 * (cEffNew - cEffOld)
|
|
883
968
|
const syInBase = Math.ceil(syInSegmentF) * snapshot.syExchangeRate
|
|
884
969
|
const ytValue = ptOutGrossActual - syInBase
|
|
885
|
-
return
|
|
970
|
+
return computeFlashFeeOut(Math.max(0, Math.floor(ytValue)), ptOutGrossActual, lpFeeRate)
|
|
886
971
|
})()
|
|
887
972
|
: getFeeFromAmount(ptOutGrossActual, lpFeeRate)
|
|
888
973
|
|
|
@@ -915,15 +1000,12 @@ function calculateSwapSegment(
|
|
|
915
1000
|
const cEffNew = snapshot.getEffectivePrice(spotPriceNew)
|
|
916
1001
|
const syInSegmentF = lTradeF64 * (cEffNew - cEffOld)
|
|
917
1002
|
const syInSegmentU64 = Math.max(0, Math.ceil(syInSegmentF))
|
|
918
|
-
const ptOutGrossActual = Math.max(
|
|
919
|
-
0,
|
|
920
|
-
Math.floor(lTradeF64 * (currentPriceSpot - spotPriceNew)),
|
|
921
|
-
)
|
|
1003
|
+
const ptOutGrossActual = Math.max(0, Math.floor(lTradeF64 * (currentPriceSpot - spotPriceNew)))
|
|
922
1004
|
|
|
923
1005
|
const normalFee = getFeeFromAmount(ptOutGrossActual, lpFeeRate)
|
|
924
1006
|
const syInBase = Math.ceil(syInSegmentF) * snapshot.syExchangeRate
|
|
925
1007
|
const ytValue = ptOutGrossActual - syInBase
|
|
926
|
-
const flashFee =
|
|
1008
|
+
const flashFee = computeFlashFeeOut(Math.max(0, Math.floor(ytValue)), ptOutGrossActual, lpFeeRate)
|
|
927
1009
|
const totalFeeOut = isCurrentFlashSwap ? flashFee : normalFee
|
|
928
1010
|
|
|
929
1011
|
return {
|
package/src/utils.ts
CHANGED
|
@@ -219,18 +219,20 @@ export function findTickByIndex(ticks: Ticks, index: number): Tick {
|
|
|
219
219
|
return ticks.ticksTree.at(index - 1) ?? null
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
+
const CLMM_TICK_KEY_SCALE = 10_000
|
|
223
|
+
|
|
222
224
|
/**
|
|
223
|
-
* Convert APY percentage to
|
|
225
|
+
* Convert APY percentage to CLMM tick-key units.
|
|
224
226
|
*/
|
|
225
227
|
export function convertApyToApyBp(apyPercent: number): number {
|
|
226
|
-
return Math.round(apyPercent *
|
|
228
|
+
return Math.round(apyPercent * CLMM_TICK_KEY_SCALE)
|
|
227
229
|
}
|
|
228
230
|
|
|
229
231
|
/**
|
|
230
|
-
* Convert
|
|
232
|
+
* Convert CLMM tick-key units to APY percentage.
|
|
231
233
|
*/
|
|
232
234
|
export function convertApyBpToApy(apyBp: number): number {
|
|
233
|
-
return apyBp /
|
|
235
|
+
return apyBp / CLMM_TICK_KEY_SCALE
|
|
234
236
|
}
|
|
235
237
|
|
|
236
238
|
export function bigIntMax(...args: bigint[]): bigint {
|