infrastructure-upgrade/lib/v3-core/test/TickMath.spec.ts

167 lines
5.9 KiB
TypeScript
Raw Permalink Normal View History

2023-04-08 18:46:18 +00:00
import { BigNumber } from 'ethers'
import { ethers } from 'hardhat'
import { TickMathTest } from '../typechain/TickMathTest'
import { expect } from './shared/expect'
import snapshotGasCost from './shared/snapshotGasCost'
import { encodePriceSqrt, MIN_SQRT_RATIO, MAX_SQRT_RATIO } from './shared/utilities'
import Decimal from 'decimal.js'
const MIN_TICK = -887272
const MAX_TICK = 887272
Decimal.config({ toExpNeg: -500, toExpPos: 500 })
describe('TickMath', () => {
let tickMath: TickMathTest
before('deploy TickMathTest', async () => {
const factory = await ethers.getContractFactory('TickMathTest')
tickMath = (await factory.deploy()) as TickMathTest
})
describe('#getSqrtRatioAtTick', () => {
it('throws for too low', async () => {
await expect(tickMath.getSqrtRatioAtTick(MIN_TICK - 1)).to.be.revertedWith('T')
})
it('throws for too low', async () => {
await expect(tickMath.getSqrtRatioAtTick(MAX_TICK + 1)).to.be.revertedWith('T')
})
it('min tick', async () => {
expect(await tickMath.getSqrtRatioAtTick(MIN_TICK)).to.eq('4295128739')
})
it('min tick +1', async () => {
expect(await tickMath.getSqrtRatioAtTick(MIN_TICK + 1)).to.eq('4295343490')
})
it('max tick - 1', async () => {
expect(await tickMath.getSqrtRatioAtTick(MAX_TICK - 1)).to.eq('1461373636630004318706518188784493106690254656249')
})
it('min tick ratio is less than js implementation', async () => {
expect(await tickMath.getSqrtRatioAtTick(MIN_TICK)).to.be.lt(encodePriceSqrt(1, BigNumber.from(2).pow(127)))
})
it('max tick ratio is greater than js implementation', async () => {
expect(await tickMath.getSqrtRatioAtTick(MAX_TICK)).to.be.gt(encodePriceSqrt(BigNumber.from(2).pow(127), 1))
})
it('max tick', async () => {
expect(await tickMath.getSqrtRatioAtTick(MAX_TICK)).to.eq('1461446703485210103287273052203988822378723970342')
})
for (const absTick of [
50,
100,
250,
500,
1_000,
2_500,
3_000,
4_000,
5_000,
50_000,
150_000,
250_000,
500_000,
738_203,
]) {
for (const tick of [-absTick, absTick]) {
describe(`tick ${tick}`, () => {
it('is at most off by 1/100th of a bips', async () => {
const jsResult = new Decimal(1.0001).pow(tick).sqrt().mul(new Decimal(2).pow(96))
const result = await tickMath.getSqrtRatioAtTick(tick)
const absDiff = new Decimal(result.toString()).sub(jsResult).abs()
expect(absDiff.div(jsResult).toNumber()).to.be.lt(0.000001)
})
it('result', async () => {
expect((await tickMath.getSqrtRatioAtTick(tick)).toString()).to.matchSnapshot()
})
it('gas', async () => {
await snapshotGasCost(tickMath.getGasCostOfGetSqrtRatioAtTick(tick))
})
})
}
}
})
describe('#MIN_SQRT_RATIO', async () => {
it('equals #getSqrtRatioAtTick(MIN_TICK)', async () => {
const min = await tickMath.getSqrtRatioAtTick(MIN_TICK)
expect(min).to.eq(await tickMath.MIN_SQRT_RATIO())
expect(min).to.eq(MIN_SQRT_RATIO)
})
})
describe('#MAX_SQRT_RATIO', async () => {
it('equals #getSqrtRatioAtTick(MAX_TICK)', async () => {
const max = await tickMath.getSqrtRatioAtTick(MAX_TICK)
expect(max).to.eq(await tickMath.MAX_SQRT_RATIO())
expect(max).to.eq(MAX_SQRT_RATIO)
})
})
describe('#getTickAtSqrtRatio', () => {
it('throws for too low', async () => {
await expect(tickMath.getTickAtSqrtRatio(MIN_SQRT_RATIO.sub(1))).to.be.revertedWith('R')
})
it('throws for too high', async () => {
await expect(tickMath.getTickAtSqrtRatio(BigNumber.from(MAX_SQRT_RATIO))).to.be.revertedWith('R')
})
it('ratio of min tick', async () => {
expect(await tickMath.getTickAtSqrtRatio(MIN_SQRT_RATIO)).to.eq(MIN_TICK)
})
it('ratio of min tick + 1', async () => {
expect(await tickMath.getTickAtSqrtRatio('4295343490')).to.eq(MIN_TICK + 1)
})
it('ratio of max tick - 1', async () => {
expect(await tickMath.getTickAtSqrtRatio('1461373636630004318706518188784493106690254656249')).to.eq(MAX_TICK - 1)
})
it('ratio closest to max tick', async () => {
expect(await tickMath.getTickAtSqrtRatio(MAX_SQRT_RATIO.sub(1))).to.eq(MAX_TICK - 1)
})
for (const ratio of [
MIN_SQRT_RATIO,
encodePriceSqrt(BigNumber.from(10).pow(12), 1),
encodePriceSqrt(BigNumber.from(10).pow(6), 1),
encodePriceSqrt(1, 64),
encodePriceSqrt(1, 8),
encodePriceSqrt(1, 2),
encodePriceSqrt(1, 1),
encodePriceSqrt(2, 1),
encodePriceSqrt(8, 1),
encodePriceSqrt(64, 1),
encodePriceSqrt(1, BigNumber.from(10).pow(6)),
encodePriceSqrt(1, BigNumber.from(10).pow(12)),
MAX_SQRT_RATIO.sub(1),
]) {
describe(`ratio ${ratio}`, () => {
it('is at most off by 1', async () => {
const jsResult = new Decimal(ratio.toString()).div(new Decimal(2).pow(96)).pow(2).log(1.0001).floor()
const result = await tickMath.getTickAtSqrtRatio(ratio)
const absDiff = new Decimal(result.toString()).sub(jsResult).abs()
expect(absDiff.toNumber()).to.be.lte(1)
})
it('ratio is between the tick and tick+1', async () => {
const tick = await tickMath.getTickAtSqrtRatio(ratio)
const ratioOfTick = await tickMath.getSqrtRatioAtTick(tick)
const ratioOfTickPlusOne = await tickMath.getSqrtRatioAtTick(tick + 1)
expect(ratio).to.be.gte(ratioOfTick)
expect(ratio).to.be.lt(ratioOfTickPlusOne)
})
it('result', async () => {
expect(await tickMath.getTickAtSqrtRatio(ratio)).to.matchSnapshot()
})
it('gas', async () => {
await snapshotGasCost(tickMath.getGasCostOfGetTickAtSqrtRatio(ratio))
})
})
}
})
})