Skip to content

Commit

Permalink
Merge branch 'master' into revert-48-revert-42-refactor-get-delta-y
Browse files Browse the repository at this point in the history
  • Loading branch information
zielvna committed Apr 8, 2024
2 parents 202a642 + fe10f9f commit fa48f94
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 20 deletions.
6 changes: 4 additions & 2 deletions contracts/collections/positions.ral
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ Contract Positions(
positionTemplateContractId: ByteVec,
positionsCounterContractId: ByteVec,
mut invariantId: Address,
mut areAdminsSet: Bool
mut areAdminsSet: Bool,
clammContract: CLAMM
) {
enum PositionsError {
NotAdmin = 500
Expand Down Expand Up @@ -56,7 +57,8 @@ Contract Positions(
tokensOwedY: tokensOwedY,
owner: originalCaller
},
true
true,
clammContract
)
let _ = copyCreateSubContract!{originalCaller -> ALPH: 1 alph}(
toByteVec!(length + 1),
Expand Down
10 changes: 10 additions & 0 deletions contracts/math/clamm.ral
Original file line number Diff line number Diff line change
Expand Up @@ -334,4 +334,14 @@ Contract CLAMM(uints: Uints) extends Log() {

return true
}

pub fn toFee(feeGrowth: U256, liquidity: U256) -> U256 {
let fee = uints.bigMulDiv256(feeGrowth, liquidity, one(FeeGrowthScale + LiquidityScale))
return uints.toU256(fee)
}

pub fn feeGrowthFromFee(liquidity: U256, fee: U256) -> U256 {
let feeGrowth = uints.bigMulDiv256(fee, one(LiquidityScale + FeeGrowthScale), liquidity)
return uints.toU256(feeGrowth)
}
}
8 changes: 1 addition & 7 deletions contracts/math/decimal.ral
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,7 @@ Abstract Contract Decimal() {
}
}

pub fn feeGrowthFromFee(liquidity: U256, fee: U256) -> U256 {
return fee * one(FeeGrowthScale) * one(LiquidityScale) / liquidity
}


pub fn wrappingAdd(a: U256, b: U256) -> U256 {
let u256Max = u256Max!()
Expand Down Expand Up @@ -246,8 +244,4 @@ Abstract Contract Decimal() {

return feeGrowthInsideX, feeGrowthInsideY
}

pub fn toFee(feeGrowth: U256, liquidity: U256) -> U256 {
return feeGrowth * liquidity / (10 ** (FeeGrowthScale + LiquidityScale))
}
}
2 changes: 1 addition & 1 deletion contracts/storage/pool.ral
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ Contract Pool(
return
}

let feeGrowth = feeGrowthFromFee(pool.liquidity, poolFee)
let feeGrowth = clamm.feeGrowthFromFee(pool.liquidity, poolFee)

if (inX) {
pool.feeGrowthGlobalX = wrappingAdd(pool.feeGrowthGlobalX, feeGrowth)
Expand Down
7 changes: 4 additions & 3 deletions contracts/storage/position.ral
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ struct PositionState {
Contract Position(
admin: Address,
mut position: PositionState,
mut isActive: Bool
mut isActive: Bool,
clammContractInstance: CLAMM
) extends Decimal() {
enum PositionError {
NotAdmin = 900
Expand Down Expand Up @@ -134,8 +135,8 @@ Contract Position(

assert!(liquidityDelta != 0 || position.liquidity != 0, PositionError.EmptyPositionPokes)

let tokensOwedX = toFee(wrappingSub(feeGrowthInsideX, position.feeGrowthInsideX), position.liquidity)
let tokensOwedY = toFee(wrappingSub(feeGrowthInsideY, position.feeGrowthInsideY), position.liquidity)
let tokensOwedX = clammContractInstance.toFee(wrappingSub(feeGrowthInsideX, position.feeGrowthInsideX), position.liquidity)
let tokensOwedY = clammContractInstance.toFee(wrappingSub(feeGrowthInsideY, position.feeGrowthInsideY), position.liquidity)

position.liquidity = calculateNewLiquidity(sign, liquidityDelta)
position.feeGrowthInsideX = feeGrowthInsideX
Expand Down
21 changes: 14 additions & 7 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,13 @@ export async function deployInvariant(signer: SignerProvider, protocolFee: bigin
const pools = await deployPools(signer, pool.contractInstance.contractId, clamm.contractInstance.contractId)
const tick = await deployTick(signer)
const ticks = await deployTicks(signer, tick.contractInstance.contractId)
const position = await deployPosition(signer)
const position = await deployPosition(signer, clamm.contractInstance.contractId)
const positionsCounter = await deployPositionsCounter(signer)
const positions = await deployPositions(
signer,
position.contractInstance.contractId,
positionsCounter.contractInstance.contractId
positionsCounter.contractInstance.contractId,
clamm.contractInstance.contractId
)
const chunk = await deployChunk(signer)
const tickmap = await deployTickmap(signer, chunk.contractInstance.contractId)
Expand Down Expand Up @@ -149,20 +150,26 @@ export async function deployFeeTiers(signer: SignerProvider, feeTier: string) {
)
}

export async function deployPositions(signer: SignerProvider, positionId: string, positionsCounterContractId: string) {
export async function deployPositions(
signer: SignerProvider,
positionId: string,
positionsCounterContractId: string,
clammId: string
) {
return await waitTxConfirmed(
Positions.deploy(signer, {
initialFields: {
positionTemplateContractId: positionId,
positionsCounterContractId,
invariantId: ZERO_ADDRESS,
areAdminsSet: false
areAdminsSet: false,
clammContract: clammId
}
})
)
}

export async function deployPosition(signer: SignerProvider) {
export async function deployPosition(signer: SignerProvider, clammId: string) {
return await waitTxConfirmed(
Position.deploy(signer, {
initialFields: {
Expand All @@ -179,7 +186,8 @@ export async function deployPosition(signer: SignerProvider) {
tokensOwedY: 0n,
owner: ZERO_ADDRESS
},
isActive: false
isActive: false,
clammContractInstance: clammId
}
})
)
Expand Down Expand Up @@ -320,7 +328,6 @@ export async function deployPositionsCounter(signer: SignerProvider) {

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

return await waitTxConfirmed(
CLAMM.deploy(signer, {
initialFields: {
Expand Down
142 changes: 142 additions & 0 deletions test/clamm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,148 @@ describe('math tests', () => {
expect(result).toBe(10000n * 10n ** 28n)
}
})
test('fee growth from fee - domain', async () => {
const clamm = await deployCLAMM(sender)

const liquidityDenominator = 10n ** 5n
const sqrtPriceDenominator = 10n ** 24n
const feeGrowthDenominator = 10n ** 28n
// max FeeGrowth case inside of domain
{
const maxTickSpacing = 100n
const tickSearchRange = 256n
const sqrtPriceUpper = 65535383934512647000000000000n
const sqrtPriceLowerIndex = 221818n - maxTickSpacing * tickSearchRange
const sqrtPriceLower = (
await clamm.contractInstance.methods.calculateSqrtPrice({ args: { tickIndex: sqrtPriceLowerIndex } })
).returns

const maxDeltaSqrtPrice = sqrtPriceUpper - sqrtPriceLower
const maxLiquidity = (1n << 256n) - 1n

const maxToken = (maxLiquidity * maxDeltaSqrtPrice) / liquidityDenominator / sqrtPriceDenominator
const feeGrowth = (
await clamm.contractInstance.methods.feeGrowthFromFee({ args: { liquidity: maxLiquidity, fee: maxToken } })
).returns
expect(feeGrowth).toBe(473129365723326089999999999999999n)
}
// min FeeGrowth case inside of domain
{
const basisPoint = 10000n
const minToken = 1n
const maxLiquidity = minToken * feeGrowthDenominator * liquidityDenominator * basisPoint
const feeGrowth = (
await clamm.contractInstance.methods.feeGrowthFromFee({
args: { liquidity: maxLiquidity, fee: minToken + basisPoint }
})
).returns
expect(feeGrowth).toBe(1n)
}
// outside of domain trigger overflow due to result not fit into FeeGrowth
{
const liquidity = 1n
const fee = (1n << 256n) - 1n

await expectError(
clamm.contractInstance.methods.feeGrowthFromFee({
args: { liquidity, fee }
})
)
}
// amount = 0
{
const liquidity = 1000n * 10n ** 5n
const fee = 0n
const feeGrowth = (await clamm.contractInstance.methods.feeGrowthFromFee({ args: { liquidity, fee } })).returns
expect(feeGrowth).toBe(0n)
}
// L = 0
{
const liquidity = 0n
const fee = 1100n
await expectError(clamm.contractInstance.methods.feeGrowthFromFee({ args: { liquidity, fee } }))
}
})
test('fee growth to fee', async () => {
const clamm = await deployCLAMM(sender)
// Equal
{
const amount = 100n
const liquidity = 1000000n * 10n ** 5n
const params = { args: { liquidity, fee: amount } }
const feeGrowth = (await clamm.contractInstance.methods.feeGrowthFromFee(params)).returns
const outParams = { args: { liquidity, feeGrowth } }
const out = (await clamm.contractInstance.methods.toFee(outParams)).returns
expect(out).toBe(amount)
}
// Greater Liquidity
{
const amount = 100n
const liquidityBefore = 1000000n * 10n ** 5n
const liquidityAfter = 10000000n * 10n ** 5n
const params = { args: { liquidity: liquidityBefore, fee: amount } }
const feeGrowth = (await clamm.contractInstance.methods.feeGrowthFromFee(params)).returns
const outParams = { args: { liquidity: liquidityAfter, feeGrowth } }
const out = (await clamm.contractInstance.methods.toFee(outParams)).returns
expect(out).toBe(1000n)
}
// huge liquidity
{
const amount = 100000000000000n
const liquidity = (1n << 77n) * 10n ** 5n
const params = { args: { liquidity, fee: amount } }
const feeGrowth = (await clamm.contractInstance.methods.feeGrowthFromFee(params)).returns
// real 6.61744490042422139897126953655970282852649688720703125 × 10^-10
// expected 6617444900424221398
expect(feeGrowth).toBe(6617444900424221398n)
const outParams = { args: { liquidity, feeGrowth } }
const out = (await clamm.contractInstance.methods.toFee(outParams)).returns
// real 9.99999999999999999853225897430980027744256 × 10^13
// expected 99999999999999
expect(out).toBe(99_999_999_999_999n)
}
})
test('fee growth to fee - domain', async () => {
const clamm = await deployCLAMM(sender)
// overflowing mul
{
const amount = 600000000000000000n
const liquidity = 10000000000000000000n * 10n ** 5n
const params = { args: { liquidity, fee: amount } }
const feeGrowth = (await clamm.contractInstance.methods.feeGrowthFromFee(params)).returns
expect(feeGrowth).toBe(600000000000000000000000000n)
const outParams = { args: { liquidity, feeGrowth } }
const out = (await clamm.contractInstance.methods.toFee(outParams)).returns
expect(out).toBe(amount)
}
// max value inside domain
{
const liquidity = (1n << 256n) - 1n
const feeGrowth = 100000n * 10n ** 28n
const out = (await clamm.contractInstance.methods.toFee({ args: { liquidity, feeGrowth } })).returns
expect(out).toBe(115792089237316195423570985008687907853269983999999999999999999999999999999999n)
}
// Overflow
{
const liquidity = (1n << 256n) - 1n
const feeGrowth = (1n << 256n) - 1n
await expectError(clamm.contractInstance.methods.toFee({ args: { liquidity, feeGrowth } }))
}
// FeeGrowth = 0
{
const liquidity = 1000n * 10n ** 5n
const feeGrowth = 0n
const out = (await clamm.contractInstance.methods.toFee({ args: { liquidity, feeGrowth } })).returns
expect(out).toBe(0n)
}
// Liquidity = 0
{
const liquidity = 0n
const feeGrowth = 1000n * 10n ** 28n
const out = (await clamm.contractInstance.methods.toFee({ args: { liquidity, feeGrowth } })).returns
expect(out).toBe(0n)
}
})
test('tick from sqrt price', async () => {
const clamm = await deployCLAMM(sender)
{
Expand Down

0 comments on commit fa48f94

Please sign in to comment.