Skip to content

Commit

Permalink
Merge pull request #150 from vintageplayer/arbitrum-minimal-hack-bogota
Browse files Browse the repository at this point in the history
fix: Added Tracking of Ticks and Optmized Exponent Calculation
  • Loading branch information
ianlapham authored Nov 15, 2022
2 parents 0ca4e03 + 514caac commit b22ec90
Show file tree
Hide file tree
Showing 6 changed files with 3,679 additions and 3,495 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"watch-local": "graph deploy ianlapham/uniswap-v3 --watch --debug --node http://127.0.0.1:8020/ --ipfs http://localhost:5001"
},
"devDependencies": {
"@graphprotocol/graph-cli": "^0.20.0",
"@graphprotocol/graph-cli": "^0.20.1",
"@graphprotocol/graph-ts": "^0.20.0",
"@typescript-eslint/eslint-plugin": "^2.0.0",
"@typescript-eslint/parser": "^2.0.0",
Expand Down
105 changes: 102 additions & 3 deletions src/mappings/core.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable prefer-const */
import { Bundle, Burn, Factory, Mint, Pool, Swap, Token } from '../types/schema'
import { BigDecimal, BigInt, } from '@graphprotocol/graph-ts'
import { Bundle, Burn, Factory, Mint, Pool, Swap, Tick, Token } from '../types/schema'
import { Pool as PoolABI } from '../types/Factory/Pool'
import { BigDecimal, BigInt, ethereum, } from '@graphprotocol/graph-ts'
import {
Burn as BurnEvent,
Flash as FlashEvent,
Expand All @@ -9,15 +10,17 @@ import {
Swap as SwapEvent
} from '../types/templates/Pool/Pool'
import { convertTokenToDecimal, loadTransaction, safeDiv } from '../utils'
import { FACTORY_ADDRESS, ONE_BI, ZERO_BD } from '../utils/constants'
import { FACTORY_ADDRESS, ONE_BI, ZERO_BD, ZERO_BI } from '../utils/constants'
import { findEthPerToken, getEthPriceInUSD, getTrackedAmountUSD, sqrtPriceX96ToTokenPrices } from '../utils/pricing'
import {
updatePoolDayData,
updatePoolHourData,
updateTickDayData,
updateTokenDayData,
updateTokenHourData,
updateUniswapDayData
} from '../utils/intervalUpdates'
import { createTick, feeTierToTickSpacing } from '../utils/tick'

export function handleInitialize(event: Initialize): void {
let pool = Pool.load(event.address.toHexString())
Expand Down Expand Up @@ -102,6 +105,30 @@ export function handleMint(event: MintEvent): void {
mint.tickUpper = BigInt.fromI32(event.params.tickUpper)
mint.logIndex = event.logIndex

// tick entities
let lowerTickIdx = event.params.tickLower
let upperTickIdx = event.params.tickUpper

let lowerTickId = poolAddress + '#' + BigInt.fromI32(event.params.tickLower).toString()
let upperTickId = poolAddress + '#' + BigInt.fromI32(event.params.tickUpper).toString()

let lowerTick = Tick.load(lowerTickId)
let upperTick = Tick.load(upperTickId)

if (lowerTick === null) {
lowerTick = createTick(lowerTickId, lowerTickIdx, pool.id, event)
}

if (upperTick === null) {
upperTick = createTick(upperTickId, upperTickIdx, pool.id, event)
}

let amount = event.params.amount
lowerTick.liquidityGross = lowerTick.liquidityGross.plus(amount)
lowerTick.liquidityNet = lowerTick.liquidityNet.plus(amount)
upperTick.liquidityGross = upperTick.liquidityGross.plus(amount)
upperTick.liquidityNet = upperTick.liquidityNet.minus(amount)

// TODO: Update Tick's volume, fees, and liquidity provider count. Computing these on the tick
// level requires reimplementing some of the swapping code from v3-core.
updateUniswapDayData(event)
Expand All @@ -118,6 +145,8 @@ export function handleMint(event: MintEvent): void {
factory.save()
mint.save()

updateTickFeeVarsAndSave(lowerTick!, event)
updateTickFeeVarsAndSave(upperTick!, event)
}

export function handleBurn(event: BurnEvent): void {
Expand Down Expand Up @@ -192,13 +221,26 @@ export function handleBurn(event: BurnEvent): void {
burn.tickUpper = BigInt.fromI32(event.params.tickUpper)
burn.logIndex = event.logIndex

// tick entities
let lowerTickId = poolAddress + '#' + BigInt.fromI32(event.params.tickLower).toString()
let upperTickId = poolAddress + '#' + BigInt.fromI32(event.params.tickUpper).toString()
let lowerTick = Tick.load(lowerTickId)
let upperTick = Tick.load(upperTickId)
let amount = event.params.amount
lowerTick.liquidityGross = lowerTick.liquidityGross.minus(amount)
lowerTick.liquidityNet = lowerTick.liquidityNet.minus(amount)
upperTick.liquidityGross = upperTick.liquidityGross.minus(amount)
upperTick.liquidityNet = upperTick.liquidityNet.plus(amount)

updateUniswapDayData(event)
updatePoolDayData(event)
updatePoolHourData(event)
updateTokenDayData(token0 as Token, event)
updateTokenDayData(token1 as Token, event)
updateTokenHourData(token0 as Token, event)
updateTokenHourData(token1 as Token, event)
updateTickFeeVarsAndSave(lowerTick!, event)
updateTickFeeVarsAndSave(upperTick!, event)

token0.save()
token1.save()
Expand All @@ -224,6 +266,8 @@ export function handleSwap(event: SwapEvent): void {
let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals)
let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals)

let oldTick = pool.tick!

// need absolute amounts for volume
let amount0Abs = amount0
if (amount0.lt(ZERO_BD)) {
Expand Down Expand Up @@ -390,6 +434,37 @@ export function handleSwap(event: SwapEvent): void {
token0.save()
token1.save()

// Update inner vars of current or crossed ticks
let newTick = pool.tick!
let tickSpacing = feeTierToTickSpacing(pool.feeTier)
let modulo = newTick.mod(tickSpacing)
if (modulo.equals(ZERO_BI)) {
// Current tick is initialized and needs to be updated
loadTickUpdateFeeVarsAndSave(newTick.toI32(), event)
}

let numIters = oldTick
.minus(newTick)
.abs()
.div(tickSpacing)

if (numIters.gt(BigInt.fromI32(100))) {
// In case more than 100 ticks need to be updated ignore the update in
// order to avoid timeouts. From testing this behavior occurs only upon
// pool initialization. This should not be a big issue as the ticks get
// updated later. For early users this error also disappears when calling
// collect
} else if (newTick.gt(oldTick)) {
let firstInitialized = oldTick.plus(tickSpacing.minus(modulo))
for (let i = firstInitialized; i.le(newTick); i = i.plus(tickSpacing)) {
loadTickUpdateFeeVarsAndSave(i.toI32(), event)
}
} else if (newTick.lt(oldTick)) {
let firstInitialized = oldTick.minus(modulo)
for (let i = firstInitialized; i.ge(newTick); i = i.minus(tickSpacing)) {
loadTickUpdateFeeVarsAndSave(i.toI32(), event)
}
}
}

export function handleFlash(event: FlashEvent): void {
Expand All @@ -398,3 +473,27 @@ export function handleFlash(event: FlashEvent): void {
pool.save()
}

function updateTickFeeVarsAndSave(tick: Tick, event: ethereum.Event): void {
let poolAddress = event.address
// not all ticks are initialized so obtaining null is expected behavior
let poolContract = PoolABI.bind(poolAddress)
let tickResult = poolContract.ticks(tick.tickIdx.toI32())
// tick.feeGrowthOutside0X128 = tickResult.value2
// tick.feeGrowthOutside1X128 = tickResult.value3
tick.save()

updateTickDayData(tick!, event)
}

function loadTickUpdateFeeVarsAndSave(tickId: i32, event: ethereum.Event): void {
let poolAddress = event.address
let tick = Tick.load(
poolAddress
.toHexString()
.concat('#')
.concat(tickId.toString())
)
if (tick !== null) {
updateTickFeeVarsAndSave(tick!, event)
}
}
1 change: 1 addition & 0 deletions src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const FACTORY_ADDRESS = '0x1F98431c8aD98523631AE4a59f267346ea31F984'

export let ZERO_BI = BigInt.fromI32(0)
export let ONE_BI = BigInt.fromI32(1)
export let TWO_BI = BigInt.fromI32(2)
export let ZERO_BD = BigDecimal.fromString('0')
export let ONE_BD = BigDecimal.fromString('1')
export let BI_18 = BigInt.fromI32(18)
Expand Down
20 changes: 16 additions & 4 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable prefer-const */
import { BigInt, BigDecimal, ethereum } from '@graphprotocol/graph-ts'
import { Transaction } from '../types/schema'
import { ONE_BI, ZERO_BI, ZERO_BD, ONE_BD } from '../utils/constants'
import { ONE_BI, ZERO_BI, ZERO_BD, ONE_BD, TWO_BI, } from '../utils/constants'

export function exponentToBigDecimal(decimals: BigInt): BigDecimal {
let bd = BigDecimal.fromString('1')
Expand All @@ -24,13 +24,25 @@ export function bigDecimalExponated(value: BigDecimal, power: BigInt): BigDecima
if (power.equals(ZERO_BI)) {
return ONE_BD
}

let negativePower = power.lt(ZERO_BI)
let result = ZERO_BD.plus(value)
let evenPower = ZERO_BD.plus(value)
let powerAbs = power.abs()
for (let i = ONE_BI; i.lt(powerAbs); i = i.plus(ONE_BI)) {
result = result.times(value)
let oddPower = ONE_BD

while (powerAbs.lt(ONE_BI)) {
if (powerAbs % TWO_BI == ZERO_BI) {
evenPower = evenPower * evenPower
powerAbs = powerAbs/TWO_BI
} else {
oddPower = evenPower * oddPower
evenPower = evenPower * evenPower
powerAbs = (powerAbs - ONE_BI) / TWO_BI
}
}

let result = evenPower * oddPower

if (negativePower) {
result = safeDiv(ONE_BD, result)
}
Expand Down
2 changes: 1 addition & 1 deletion subgraph.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: A copy of Uniswap's Arbitrum subgraph
# graft:
# base: QmYrooNJpZZkpsMxG44wJgkbnSbEsT9B8wbStADdrydewT
# block: 5363973
repository: https://github.com/Uniswap/uniswap-v3-subgraph
repository: https://github.com/vintageplayer/v3-subgraph
schema:
file: ./schema.graphql
features:
Expand Down
Loading

0 comments on commit b22ec90

Please sign in to comment.