Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor get delta y and add tests #42

Merged
merged 3 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions contracts/math/clamm.ral
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Contract CLAMM() extends Log(){
Contract CLAMM(uints: Uints) extends Log() {
enum CLAMMError {
InvalidTickIndex = 800
InvalidTickSpacing = 801
Expand Down Expand Up @@ -133,10 +133,17 @@ Contract CLAMM() extends Log(){
deltaSqrtPrice = sqrtPriceB - sqrtPriceA
}

let mut result = U512 { lower: 0, higher: 0 }

if (roundingUp) {
return (mulUp(deltaSqrtPrice, liquidity, LiquidityScale) + almostOne(SqrtPriceScale)) / one(SqrtPriceScale)
result = uints.bigMulDiv256(deltaSqrtPrice, liquidity, one(LiquidityScale))
result = uints.bigAdd512(result, uints.toU512(almostOne(SqrtPriceScale)))
result = uints.bigDiv(result, one(SqrtPriceScale), 1)
return uints.toU256(result)
} else {
return mul(deltaSqrtPrice, liquidity, LiquidityScale) / one(SqrtPriceScale)
result = uints.bigMulDiv256(deltaSqrtPrice, liquidity, one(LiquidityScale))
result = uints.bigDiv(result, one(SqrtPriceScale), 1)
return uints.toU256(result)
zielvna marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
52 changes: 47 additions & 5 deletions contracts/math/uints.ral
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,52 @@ Contract Uints () {
}
}

pub fn div(a: U512, b: U256, bDenominator: U256, up: Bool) -> U512 {
assert!(b > 0, ArithmeticErrors.NotPositiveDivisor)

if (b == 1) {
return a
}

// Calculate new higher
let newHigher = a.higher * bDenominator
let higher = newHigher / b
let higherRemainder = newHigher % b
// calculate higher remainder
let maxDiv = MaxU256 / b
let deltaHigherRemainder = higherRemainder * maxDiv
// Calculate lower
let newLower = a.lower * bDenominator
let lower = newLower / b
let mut deltaLower = deltaHigherRemainder + lower

if (up) {
let lowerRemainder = newLower % b

let higherDecimal = deltaHigherRemainder % b
if (higherDecimal + lowerRemainder != 0) {
deltaLower = deltaLower + 1
}
}

return U512 {
higher: higher,
lower: deltaLower
}
}

pub fn bigDiv(a: U512, b: U256, bDenominator: U256) -> U512 {
return div(a, b, bDenominator, false)
}

pub fn bigDivUp(a: U512, b: U256, bDenominator: U256) -> U512 {
return div(a, b, bDenominator, true)
}

pub fn bigAdd512(a: U512, b: U512) -> U512 {
let (aLowerBLower, overflow) = overflowingAdd(a.lower, b.lower)
let aHigherBHigherOverflow = wrappingAdd(wrappingAdd(a.higher, b.higher), overflow)
return U512 { lower: aLowerBLower, higher: aHigherBHigherOverflow }
let (aLowerB, overflow) = overflowingAdd(a.lower, b.lower)
let aHigherOverflow = wrappingAdd(wrappingAdd(a.higher, b.higher), overflow)
return U512 { lower: aLowerB, higher: aHigherOverflow }
}

pub fn bigDivWrapper(a: U512, b: U256, bDenominator: U256, up: Bool) -> U512 {
Expand Down Expand Up @@ -127,8 +169,8 @@ Contract Uints () {
pub fn bigMulDivUp256(a: U256, b: U256, bDenominator: U256) -> U512 {
let mut result = bigMul256(a, b)

result = bigAdd512(result, U512 { higher: 0, lower: bDenominator - 1 })
result = bigDiv512(result, bDenominator, 1)
result = bigAdd512(result, toU512(bDenominator - 1))
result = bigDiv(result, bDenominator, 1)

return result
}
Expand Down
6 changes: 5 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,9 +319,13 @@ export async function deployPositionsCounter(signer: SignerProvider) {
}

export async function deployCLAMM(signer: SignerProvider) {
const uints = await deployUints(signer)

return await waitTxConfirmed(
CLAMM.deploy(signer, {
initialFields: {}
initialFields: {
uints: uints.contractInstance.contractId
}
})
)
}
Expand Down
150 changes: 137 additions & 13 deletions test/clamm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getSigner } from '@alephium/web3-test'
import { PrivateKeyWallet } from '@alephium/web3-wallet'
import { assert } from 'console'
import { CLAMMInstance } from '../artifacts/ts'
import { deployCLAMM } from '../src/utils'
import { deployCLAMM, expectError } from '../src/utils'

web3.setCurrentNodeProvider('http://127.0.0.1:22973')

Expand Down Expand Up @@ -212,19 +212,143 @@ describe('math tests', () => {
expect(resultUp).toEqual(70109n)
expect(resultDown).toEqual(70108n)
})
test('get delta y', async () => {
const clamm = await deployCLAMM(sender)
const sqrtPriceA = 234878324943782000000000000n
const sqrtPriceB = 87854456421658000000000000n
const liquidity = 983983249092n
const paramsUp = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: true } }
const paramsDown = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: false } }
const resultUp = (await clamm.contractInstance.methods.getDeltaY(paramsUp)).returns
const resultDown = (await clamm.contractInstance.methods.getDeltaY(paramsDown)).returns
// 144669023.842474597804911408
expect(resultUp).toEqual(1446690239n)
expect(resultDown).toEqual(1446690238n)

describe('get delta y', () => {
let clamm: CLAMMInstance

beforeEach(async () => {
clamm = (await deployCLAMM(sender)).contractInstance
})

test('zero at zero liquidity', async () => {
const sqrtPriceA = 1_000000000000000000000000n
const sqrtPriceB = 1_000000000000000000000000n
const liquidity = 0n

const params = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: false } }
const result = await clamm.methods.getDeltaY(params)

expect(result.returns).toEqual(0n)
})

test('equal at equal liquidity', async () => {
const sqrtPriceA = 1_000000000000000000000000n
const sqrtPriceB = 2_000000000000000000000000n
const liquidity = 2_00000n

const params = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: false } }
const result = await clamm.methods.getDeltaY(params)

expect(result.returns).toEqual(2n)
})

test('big numbers', async () => {
const sqrtPriceA = 234_878324943782000000000000n
const sqrtPriceB = 87_854456421658000000000000n
const liquidity = 9839832_49092n

const paramsUp = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: true } }
const paramsDown = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: false } }
const resultUp = await clamm.methods.getDeltaY(paramsUp)
const resultDown = await clamm.methods.getDeltaY(paramsDown)

expect(resultUp.returns).toEqual(1446690239n)
expect(resultDown.returns).toEqual(1446690238n)
})

test('big', async () => {
const sqrtPriceA = 1_000000000000000000000000n
const sqrtPriceB = 2_000000000000000000000000n
const liquidity = (2n ** 64n - 1n) * 1_00000n

const paramsUp = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: true } }
const paramsDown = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: false } }
const resultUp = await clamm.methods.getDeltaY(paramsUp)
const resultDown = await clamm.methods.getDeltaY(paramsDown)

expect(resultUp.returns).toEqual(liquidity / 1_00000n)
expect(resultDown.returns).toEqual(liquidity / 1_00000n)
})

test('overflow', async () => {
const sqrtPriceA = 1_000000000000000000000000n
const sqrtPriceB = 2n ** 256n - 1n
const liquidity = 2n ** 256n - 1n

const paramsUp = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: true } }
const paramsDown = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: false } }
await expectError(clamm.methods.getDeltaY(paramsUp))
await expectError(clamm.methods.getDeltaY(paramsDown))
})

test('huge liquidity', async () => {
const sqrtPriceA = 1_000000000000000000000000n
const sqrtPriceB = 1_000000000000000001000000n
const liquidity = 2n ** 256n - 1n

const paramsUp = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: true } }
const paramsDown = { args: { sqrtPriceA, sqrtPriceB, liquidity, roundingUp: false } }
const resultUp = await clamm.methods.getDeltaY(paramsUp)
const resultDown = await clamm.methods.getDeltaY(paramsDown)

expect(resultUp.returns).toEqual(1157920892373161954235709850086879078532699846656405641n)
expect(resultDown.returns).toEqual(1157920892373161954235709850086879078532699846656405640n)
})
})

describe('get delta y - domain', () => {
let clamm: CLAMMInstance
const minSqrtPrice = 15258932000000000000n
const maxSqrtPrice = 65535_383934512647000000000000n
const minLiquidity = 1n
const maxLiquidity = 2n ** 256n - 1n

beforeEach(async () => {
clamm = (await deployCLAMM(sender)).contractInstance
})

it('maximize delta sqrt price and liquidity', async () => {
const paramsUp = {
args: { sqrtPriceA: maxSqrtPrice, sqrtPriceB: minSqrtPrice, liquidity: maxLiquidity, roundingUp: true }
}
const paramsDown = {
args: { sqrtPriceA: maxSqrtPrice, sqrtPriceB: minSqrtPrice, liquidity: maxLiquidity, roundingUp: false }
}
const resultUp = await clamm.methods.getDeltaY(paramsUp)
const resultDown = await clamm.methods.getDeltaY(paramsDown)

expect(resultUp.returns).toEqual(75884790229800029582010010030152469040784228171629896039591333116952600000001n)
expect(resultDown.returns).toEqual(75884790229800029582010010030152469040784228171629896039591333116952599999999n)
})

it('can be zero', async () => {
const params = {
args: { sqrtPriceA: maxSqrtPrice, sqrtPriceB: maxSqrtPrice - 1n, liquidity: minLiquidity, roundingUp: false }
}
const result = await clamm.methods.getDeltaY(params)

expect(result.returns).toEqual(0n)
})

it('liquidity is zero', async () => {
const params = {
args: { sqrtPriceA: maxSqrtPrice, sqrtPriceB: minSqrtPrice, liquidity: 0n, roundingUp: true }
}
const result = await clamm.methods.getDeltaY(params)

expect(result.returns).toEqual(0n)
})

it('all max', async () => {
const params = {
args: { sqrtPriceA: maxSqrtPrice, sqrtPriceB: maxSqrtPrice, liquidity: maxLiquidity, roundingUp: true }
}
const result = await clamm.methods.getDeltaY(params)

expect(result.returns).toEqual(0n)
})
})

test('get next sqrt price x up', async () => {
const clamm = await deployCLAMM(sender)
{
Expand Down
Loading