Skip to content

Commit

Permalink
Merge pull request #96 from invariant-labs/export-missing-math
Browse files Browse the repository at this point in the history
Missing math exports
  • Loading branch information
Sniezka1927 authored Jul 11, 2024
2 parents 5daec3f + c58aadd commit 84cbd1b
Show file tree
Hide file tree
Showing 6 changed files with 461 additions and 192 deletions.
8 changes: 8 additions & 0 deletions contracts/collections/tickmap.ral
Original file line number Diff line number Diff line change
Expand Up @@ -267,4 +267,12 @@ Abstract Contract Tickmap() extends Decimal(), BatchHelper() {
let (upperChunk, _) = tickToPosition(upperTick, tickSpacing)
return lowerChunk, upperChunk
}

@using(checkExternalCaller = false)
pub fn getMaxChunk(tickSpacing: U256) -> (U256) {
let maxTick = getMaxTick(tickSpacing)
let maxBitmapIndex = maxTick + GlobalMaxTick / toI256!(tickSpacing)
let maxChunkIndex = toU256!(maxBitmapIndex) / ChunkSize
return maxChunkIndex
}
}
12 changes: 7 additions & 5 deletions contracts/math/decimal.ral
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@ Abstract Contract Decimal() {
return GlobalMinTick
}

pub fn getMaxSqrtPrice() -> U256 {
return MaxSqrtPrice
pub fn getMaxSqrtPrice(tickSpacing: U256) -> U256 {
let maxTick = getMaxTick(tickSpacing)
return calculateSqrtPrice(maxTick)
}

pub fn getMinSqrtPrice() -> U256 {
return MinSqrtPrice
pub fn getMinSqrtPrice(tickSpacing: U256) -> U256 {
let minTick = getMinTick(tickSpacing)
return calculateSqrtPrice(minTick)
}

pub fn getMaxTick(tickSpacing: U256) -> I256 {
Expand Down Expand Up @@ -208,7 +210,7 @@ Abstract Contract Decimal() {
} else {
return a - b
}
}
}

pub fn calculateFeeGrowthInside(
tickLowerIndex: I256,
Expand Down
85 changes: 84 additions & 1 deletion contracts/math/utils.ral
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,47 @@ struct LiquidityResult {
l: U256
}

Contract Utils() extends Uints(), Decimal(), Log(), PoolKeyHelper(), FeeTierHelper() {
Contract Utils() extends Uints(), Decimal(), Log(), PoolKeyHelper(), FeeTierHelper(), Tickmap() {
// Placeholder to allow exporting tickmap methods
// Key: poolKey ++ subcontract index
mapping[ByteVec, TickmapBatch] bitmap

enum UtilsError {
InvalidTickIndex = 900
UpperLTCurrentSqrtPrice = 901
CurrentLTLowerSqrtPrice = 902
}

enum InvariantError {
// NotAdmin = 0
// InsufficientLiquidity = 1
InvalidTickSpacing = 2
InvalidFee = 3
// FeeTierNotFound = 4
TokensAreSame = 5
// PoolKeyAlreadyExist = 6
// TickAndSqrtPriceMismatch = 7
// NotFeeReceiver = 8
// InvalidTickLiquidity = 9
// ZeroLiquidity = 10
// PriceLimitReached = 11
// InvalidProtocolFee = 12
// NotOwner = 13
// ZeroAmount = 14
// WrongPriceLimit = 15
// NoGainSwap = 16
// PositionDoesNotExist = 17
// FeeTierAlreadyExist = 18
// PoolDoesNotExist = 19
// PoolAlreadyExist = 20
// TickAlreadyExist = 21
InvalidTickIndex = 22
TickAndTickSpacingMismatch = 23
TickLimitReached = 24
ChunkNotFound = 25
TickInitialized = 26
// PositionNotFound = 27
// EmptyPositionPokes = 28
}

pub fn getLiquidityByX(x: U256, lowerTick: I256, upperTick: I256, currentSqrtPrice: U256, roundingUp: Bool) -> SingleTokenLiquidity {
Expand Down Expand Up @@ -124,4 +154,57 @@ Contract Utils() extends Uints(), Decimal(), Log(), PoolKeyHelper(), FeeTierHelp
return LiquidityResult { x: resultByY.amount, y: resultByX.amount, l: resultByX.l }
}
}

pub fn isTokenX(candidate: Address, compareTo: Address) -> Bool {
let candidateBytes = toByteVec!(candidate)
let compareToBytes = toByteVec!(compareTo)

assert!(candidateBytes != compareToBytes, InvariantError.TokensAreSame)

for (let mut i = 0; i <= size!(candidateBytes); i = i + 1) {
if (u256From1Byte!(byteVecSlice!(candidateBytes, i, i + 1)) < u256From1Byte!(byteVecSlice!(compareToBytes, i, i + 1))) {
return true
} else {
return false
}
}

return true
}

pub fn calculateFee(
tickLowerIndex: I256,
tickLowerFeeGrowthOutsideX: U256,
tickLowerFeeGrowthOutsideY: U256,
tickUpperIndex: I256,
tickUpperFeeGrowthOutsideX: U256,
tickUpperFeeGrowthOutsideY: U256,
tickCurrent: I256,
globalFeeGrowthX: U256,
globalFeeGrowthY: U256,
positionFeeGrowthInsideX: U256,
positionFeeGrowthInsideY: U256,
positionLiquidity: U256
) -> (U256, U256) {
let (feeGrowthInsideX, feeGrowthInsideY) = calculateFeeGrowthInside(
tickLowerIndex,
tickLowerFeeGrowthOutsideX,
tickLowerFeeGrowthOutsideY,
tickUpperIndex,
tickUpperFeeGrowthOutsideX,
tickUpperFeeGrowthOutsideY,
tickCurrent,
globalFeeGrowthX,
globalFeeGrowthY
)

let tokensOwedX = toFee(wrappingSub(feeGrowthInsideX, positionFeeGrowthInsideX), positionLiquidity)
let tokensOwedY = toFee(wrappingSub(feeGrowthInsideY, positionFeeGrowthInsideY), positionLiquidity)

return tokensOwedX, tokensOwedY
}

pub fn toFee(feeGrowth: U256, liquidity: U256) -> U256 {
return toU256(bigMulDiv256(feeGrowth, liquidity, one(FeeGrowthScale + LiquidityScale)))
}
}
119 changes: 113 additions & 6 deletions src/math.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { CLAMM, Utils } from '../artifacts/ts'
import { LiquidityResult, Pool, Position, SingleTokenLiquidity, Tick } from '../artifacts/ts/types'

export const calculateSqrtPrice = async (tickIndex: bigint) => {
export const calculateSqrtPrice = async (tickIndex: bigint): Promise<bigint> => {
return (
await Utils.tests.calculateSqrtPrice({
testArgs: { tickIndex }
Expand All @@ -14,7 +15,7 @@ export const getLiquidityByX = async (
upperTick: bigint,
currentSqrtPrice: bigint,
roundingUp: boolean
) => {
): Promise<SingleTokenLiquidity> => {
return (
await Utils.tests.getLiquidityByX({
testArgs: {
Expand All @@ -34,7 +35,7 @@ export const getLiquidityByY = async (
upperTick: bigint,
currentSqrtPrice: bigint,
roundingUp: boolean
) => {
): Promise<SingleTokenLiquidity> => {
return (
await Utils.tests.getLiquidityByY({
testArgs: {
Expand All @@ -55,7 +56,7 @@ export const getLiquidity = async (
upperTick: bigint,
currentSqrtPrice: bigint,
roundingUp: boolean
) => {
): Promise<LiquidityResult> => {
return (
await Utils.tests.getLiquidity({
testArgs: {
Expand All @@ -75,7 +76,7 @@ export const getDeltaY = async (
sqrtPriceB: bigint,
liquidity: bigint,
roundingUp: boolean
) => {
): Promise<bigint> => {
return (
await CLAMM.tests.getDeltaY({
testArgs: {
Expand All @@ -88,7 +89,7 @@ export const getDeltaY = async (
).returns
}

export const getMaxTick = async (tickSpacing: bigint) => {
export const getMaxTick = async (tickSpacing: bigint): Promise<bigint> => {
return (
await Utils.tests.getMaxTick({
testArgs: {
Expand All @@ -97,3 +98,109 @@ export const getMaxTick = async (tickSpacing: bigint) => {
})
).returns
}

export const getMinTick = async (tickSpacing: bigint): Promise<bigint> => {
return (
await Utils.tests.getMinTick({
testArgs: {
tickSpacing
}
})
).returns
}

export const getMaxChunk = async (tickSpacing: bigint): Promise<bigint> => {
return (
await Utils.tests.getMaxChunk({
testArgs: {
tickSpacing
}
})
).returns
}

export const calculateTick = async (sqrtPrice: bigint, tickSpacing: bigint): Promise<bigint> => {
return (
await Utils.tests.getTickAtSqrtPrice({
testArgs: {
sqrtPrice,
tickSpacing
}
})
).returns
}

export const getMaxSqrtPrice = async (tickSpacing: bigint): Promise<bigint> => {
return (
await Utils.tests.getMaxSqrtPrice({
testArgs: {
tickSpacing
}
})
).returns
}

export const getMinSqrtPrice = async (tickSpacing: bigint): Promise<bigint> => {
return (
await Utils.tests.getMinSqrtPrice({
testArgs: {
tickSpacing
}
})
).returns
}

export const isTokenX = async (candidate: string, compareTo: string): Promise<boolean> => {
return (
await Utils.tests.isTokenX({
testArgs: {
candidate,
compareTo
}
})
).returns
}

export const calculateFee = async (
pool: Pool,
position: Position,
lowerTick: Tick,
upperTick: Tick
): Promise<[bigint, bigint]> => {
return (
await Utils.tests.calculateFee({
testArgs: {
tickLowerIndex: lowerTick.index,
tickLowerFeeGrowthOutsideX: lowerTick.feeGrowthOutsideX,
tickLowerFeeGrowthOutsideY: lowerTick.feeGrowthOutsideY,
tickUpperIndex: upperTick.index,
tickUpperFeeGrowthOutsideX: upperTick.feeGrowthOutsideX,
tickUpperFeeGrowthOutsideY: upperTick.feeGrowthOutsideY,
tickCurrent: pool.currentTickIndex,
globalFeeGrowthX: pool.feeGrowthGlobalX,
globalFeeGrowthY: pool.feeGrowthGlobalY,
positionFeeGrowthInsideX: position.feeGrowthInsideX,
positionFeeGrowthInsideY: position.feeGrowthInsideY,
positionLiquidity: position.liquidity
}
})
).returns
}

export const calculateTokenAmounts = async (
pool: Pool,
position: Position
): Promise<[bigint, bigint, boolean]> => {
return (
await CLAMM.tests.calculateAmountDelta({
testArgs: {
currentTickIndex: pool.currentTickIndex,
currentSqrtPrice: pool.sqrtPrice,
liquidityDelta: position.liquidity,
liquiditySign: false,
upperTick: position.upperTickIndex,
lowerTick: position.lowerTickIndex
}
})
).returns
}
1 change: 1 addition & 0 deletions test/clamm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ describe('math tests', () => {
})
test('fee growth to fee', async () => {
const clamm = await deployCLAMM(sender)

// Equal
{
const amount = 100n
Expand Down
Loading

0 comments on commit 84cbd1b

Please sign in to comment.