735546619e
Signed-off-by: T-Hax <>
167 lines
5.9 KiB
TypeScript
167 lines
5.9 KiB
TypeScript
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))
|
|
})
|
|
})
|
|
}
|
|
})
|
|
})
|