diff --git a/abis/ERC20.json b/abis/ERC20.json index 405d6b36..327c0fad 100644 --- a/abis/ERC20.json +++ b/abis/ERC20.json @@ -84,7 +84,7 @@ "outputs": [ { "name": "", - "type": "uint8" + "type": "uint32" } ], "payable": false, diff --git a/package.json b/package.json index 6c30ecac..931077f2 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,8 @@ "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-ts": "^0.20.0", + "@graphprotocol/graph-cli": "^0.64.1", + "@graphprotocol/graph-ts": "^0.32.0", "@typescript-eslint/eslint-plugin": "^2.0.0", "@typescript-eslint/parser": "^2.0.0", "eslint": "^6.2.2", diff --git a/src/mappings/core.ts b/src/mappings/core.ts index b1a0574d..2b0b4bf7 100644 --- a/src/mappings/core.ts +++ b/src/mappings/core.ts @@ -24,17 +24,17 @@ import { createTick, feeTierToTickSpacing } from '../utils/tick' export function handleInitialize(event: Initialize): void { // update pool sqrt price and tick - let pool = Pool.load(event.address.toHexString()) + let pool = Pool.load(event.address.toHexString())! pool.sqrtPrice = event.params.sqrtPriceX96 pool.tick = BigInt.fromI32(event.params.tick) pool.save() - + // update token prices let token0 = Token.load(pool.token0) let token1 = Token.load(pool.token1) // update ETH price now that prices could have changed - let bundle = Bundle.load('1') + let bundle = Bundle.load('1')! bundle.ethPriceUSD = getEthPriceInUSD() bundle.save() @@ -42,235 +42,245 @@ export function handleInitialize(event: Initialize): void { updatePoolHourData(event) // update token prices - token0.derivedETH = findEthPerToken(token0 as Token) - token1.derivedETH = findEthPerToken(token1 as Token) - token0.save() - token1.save() + if (token0 && token1) { + token0.derivedETH = findEthPerToken(token0 as Token) + token1.derivedETH = findEthPerToken(token1 as Token) + token0.save() + token1.save() + } } export function handleMint(event: MintEvent): void { - let bundle = Bundle.load('1') + let bundle = Bundle.load('1')! let poolAddress = event.address.toHexString() - let pool = Pool.load(poolAddress) - let factory = Factory.load(FACTORY_ADDRESS) + let pool = Pool.load(poolAddress)! + let factory = Factory.load(FACTORY_ADDRESS)! let token0 = Token.load(pool.token0) let token1 = Token.load(pool.token1) - let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) - let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals) - - let amountUSD = amount0 - .times(token0.derivedETH.times(bundle.ethPriceUSD)) - .plus(amount1.times(token1.derivedETH.times(bundle.ethPriceUSD))) - - // reset tvl aggregates until new amounts calculated - factory.totalValueLockedETH = factory.totalValueLockedETH.minus(pool.totalValueLockedETH) - - // update globals - factory.txCount = factory.txCount.plus(ONE_BI) - - // update token0 data - token0.txCount = token0.txCount.plus(ONE_BI) - token0.totalValueLocked = token0.totalValueLocked.plus(amount0) - token0.totalValueLockedUSD = token0.totalValueLocked.times(token0.derivedETH.times(bundle.ethPriceUSD)) - - // update token1 data - token1.txCount = token1.txCount.plus(ONE_BI) - token1.totalValueLocked = token1.totalValueLocked.plus(amount1) - token1.totalValueLockedUSD = token1.totalValueLocked.times(token1.derivedETH.times(bundle.ethPriceUSD)) - - // pool data - pool.txCount = pool.txCount.plus(ONE_BI) - - // Pools liquidity tracks the currently active liquidity given pools current tick. - // We only want to update it on mint if the new position includes the current tick. - if ( - pool.tick !== null && - BigInt.fromI32(event.params.tickLower).le(pool.tick as BigInt) && - BigInt.fromI32(event.params.tickUpper).gt(pool.tick as BigInt) - ) { - pool.liquidity = pool.liquidity.plus(event.params.amount) - } - - pool.totalValueLockedToken0 = pool.totalValueLockedToken0.plus(amount0) - pool.totalValueLockedToken1 = pool.totalValueLockedToken1.plus(amount1) - pool.totalValueLockedETH = pool.totalValueLockedToken0 - .times(token0.derivedETH) - .plus(pool.totalValueLockedToken1.times(token1.derivedETH)) - pool.totalValueLockedUSD = pool.totalValueLockedETH.times(bundle.ethPriceUSD) - - // reset aggregates with new amounts - factory.totalValueLockedETH = factory.totalValueLockedETH.plus(pool.totalValueLockedETH) - factory.totalValueLockedUSD = factory.totalValueLockedETH.times(bundle.ethPriceUSD) - - let transaction = loadTransaction(event) - let mint = new Mint(transaction.id.toString() + '#' + pool.txCount.toString()) - mint.transaction = transaction.id - mint.timestamp = transaction.timestamp - mint.pool = pool.id - mint.token0 = pool.token0 - mint.token1 = pool.token1 - mint.owner = event.params.owner - mint.sender = event.params.sender - mint.origin = event.transaction.from - mint.amount = event.params.amount - mint.amount0 = amount0 - mint.amount1 = amount1 - mint.amountUSD = amountUSD - mint.tickLower = BigInt.fromI32(event.params.tickLower) - 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. + if (token0 && token1) { + let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) + let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals) + + let amountUSD = amount0 + .times(token0.derivedETH.times(bundle.ethPriceUSD)) + .plus(amount1.times(token1.derivedETH.times(bundle.ethPriceUSD))) + + // reset tvl aggregates until new amounts calculated + factory.totalValueLockedETH = factory.totalValueLockedETH.minus(pool.totalValueLockedETH) + + // update globals + factory.txCount = factory.txCount.plus(ONE_BI) + + // update token0 data + token0.txCount = token0.txCount.plus(ONE_BI) + token0.totalValueLocked = token0.totalValueLocked.plus(amount0) + token0.totalValueLockedUSD = token0.totalValueLocked.times(token0.derivedETH.times(bundle.ethPriceUSD)) + + // update token1 data + token1.txCount = token1.txCount.plus(ONE_BI) + token1.totalValueLocked = token1.totalValueLocked.plus(amount1) + token1.totalValueLockedUSD = token1.totalValueLocked.times(token1.derivedETH.times(bundle.ethPriceUSD)) + + // pool data + pool.txCount = pool.txCount.plus(ONE_BI) + + // Pools liquidity tracks the currently active liquidity given pools current tick. + // We only want to update it on mint if the new position includes the current tick. + if ( + pool.tick !== null && + BigInt.fromI32(event.params.tickLower).le(pool.tick as BigInt) && + BigInt.fromI32(event.params.tickUpper).gt(pool.tick as BigInt) + ) { + pool.liquidity = pool.liquidity.plus(event.params.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) + pool.totalValueLockedToken0 = pool.totalValueLockedToken0.plus(amount0) + pool.totalValueLockedToken1 = pool.totalValueLockedToken1.plus(amount1) + pool.totalValueLockedETH = pool.totalValueLockedToken0 + .times(token0.derivedETH) + .plus(pool.totalValueLockedToken1.times(token1.derivedETH)) + pool.totalValueLockedUSD = pool.totalValueLockedETH.times(bundle.ethPriceUSD) + + // reset aggregates with new amounts + factory.totalValueLockedETH = factory.totalValueLockedETH.plus(pool.totalValueLockedETH) + factory.totalValueLockedUSD = factory.totalValueLockedETH.times(bundle.ethPriceUSD) + + let transaction = loadTransaction(event) + let mint = new Mint(transaction.id.toString() + '#' + pool.txCount.toString()) + mint.transaction = transaction.id + mint.timestamp = transaction.timestamp + mint.pool = pool.id + mint.token0 = pool.token0 + mint.token1 = pool.token1 + mint.owner = event.params.owner + mint.sender = event.params.sender + mint.origin = event.transaction.from + mint.amount = event.params.amount + mint.amount0 = amount0 + mint.amount1 = amount1 + mint.amountUSD = amountUSD + mint.tickLower = BigInt.fromI32(event.params.tickLower) + 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) + } - token0.save() - token1.save() - pool.save() - factory.save() - mint.save() + if (upperTick === null) { + upperTick = createTick(upperTickId, upperTickIdx, pool.id, event) + } - // Update inner tick vars and save the ticks - updateTickFeeVarsAndSave(lowerTick!, event) - updateTickFeeVarsAndSave(upperTick!, 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) + updatePoolDayData(event) + updatePoolHourData(event) + updateTokenDayData(token0 as Token, event) + updateTokenDayData(token1 as Token, event) + updateTokenHourData(token0 as Token, event) + updateTokenHourData(token1 as Token, event) + + token0.save() + token1.save() + pool.save() + factory.save() + mint.save() + + // Update inner tick vars and save the ticks + updateTickFeeVarsAndSave(lowerTick, event) + updateTickFeeVarsAndSave(upperTick, event) + } } export function handleBurn(event: BurnEvent): void { - let bundle = Bundle.load('1') + let bundle = Bundle.load('1')! let poolAddress = event.address.toHexString() - let pool = Pool.load(poolAddress) - let factory = Factory.load(FACTORY_ADDRESS) + let pool = Pool.load(poolAddress)! + let factory = Factory.load(FACTORY_ADDRESS)! let token0 = Token.load(pool.token0) let token1 = Token.load(pool.token1) - let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) - let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals) - - let amountUSD = amount0 - .times(token0.derivedETH.times(bundle.ethPriceUSD)) - .plus(amount1.times(token1.derivedETH.times(bundle.ethPriceUSD))) - - // reset tvl aggregates until new amounts calculated - factory.totalValueLockedETH = factory.totalValueLockedETH.minus(pool.totalValueLockedETH) - - // update globals - factory.txCount = factory.txCount.plus(ONE_BI) - - // update token0 data - token0.txCount = token0.txCount.plus(ONE_BI) - token0.totalValueLocked = token0.totalValueLocked.minus(amount0) - token0.totalValueLockedUSD = token0.totalValueLocked.times(token0.derivedETH.times(bundle.ethPriceUSD)) - - // update token1 data - token1.txCount = token1.txCount.plus(ONE_BI) - token1.totalValueLocked = token1.totalValueLocked.minus(amount1) - token1.totalValueLockedUSD = token1.totalValueLocked.times(token1.derivedETH.times(bundle.ethPriceUSD)) - - // pool data - pool.txCount = pool.txCount.plus(ONE_BI) - // Pools liquidity tracks the currently active liquidity given pools current tick. - // We only want to update it on burn if the position being burnt includes the current tick. - if ( - pool.tick !== null && - BigInt.fromI32(event.params.tickLower).le(pool.tick as BigInt) && - BigInt.fromI32(event.params.tickUpper).gt(pool.tick as BigInt) - ) { - pool.liquidity = pool.liquidity.minus(event.params.amount) - } - pool.totalValueLockedToken0 = pool.totalValueLockedToken0.minus(amount0) - pool.totalValueLockedToken1 = pool.totalValueLockedToken1.minus(amount1) - pool.totalValueLockedETH = pool.totalValueLockedToken0 - .times(token0.derivedETH) - .plus(pool.totalValueLockedToken1.times(token1.derivedETH)) - pool.totalValueLockedUSD = pool.totalValueLockedETH.times(bundle.ethPriceUSD) - - // reset aggregates with new amounts - factory.totalValueLockedETH = factory.totalValueLockedETH.plus(pool.totalValueLockedETH) - factory.totalValueLockedUSD = factory.totalValueLockedETH.times(bundle.ethPriceUSD) - - // burn entity - let transaction = loadTransaction(event) - let burn = new Burn(transaction.id + '#' + pool.txCount.toString()) - burn.transaction = transaction.id - burn.timestamp = transaction.timestamp - burn.pool = pool.id - burn.token0 = pool.token0 - burn.token1 = pool.token1 - burn.owner = event.params.owner - burn.origin = event.transaction.from - burn.amount = event.params.amount - burn.amount0 = amount0 - burn.amount1 = amount1 - burn.amountUSD = amountUSD - burn.tickLower = BigInt.fromI32(event.params.tickLower) - 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() - pool.save() - factory.save() - burn.save() + if (token0 && token1) { + let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) + let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals) + + let amountUSD = amount0 + .times(token0.derivedETH.times(bundle.ethPriceUSD)) + .plus(amount1.times(token1.derivedETH.times(bundle.ethPriceUSD))) + + // reset tvl aggregates until new amounts calculated + factory.totalValueLockedETH = factory.totalValueLockedETH.minus(pool.totalValueLockedETH) + + // update globals + factory.txCount = factory.txCount.plus(ONE_BI) + + // update token0 data + token0.txCount = token0.txCount.plus(ONE_BI) + token0.totalValueLocked = token0.totalValueLocked.minus(amount0) + token0.totalValueLockedUSD = token0.totalValueLocked.times(token0.derivedETH.times(bundle.ethPriceUSD)) + + // update token1 data + token1.txCount = token1.txCount.plus(ONE_BI) + token1.totalValueLocked = token1.totalValueLocked.minus(amount1) + token1.totalValueLockedUSD = token1.totalValueLocked.times(token1.derivedETH.times(bundle.ethPriceUSD)) + + // pool data + pool.txCount = pool.txCount.plus(ONE_BI) + // Pools liquidity tracks the currently active liquidity given pools current tick. + // We only want to update it on burn if the position being burnt includes the current tick. + if ( + pool.tick !== null && + BigInt.fromI32(event.params.tickLower).le(pool.tick as BigInt) && + BigInt.fromI32(event.params.tickUpper).gt(pool.tick as BigInt) + ) { + pool.liquidity = pool.liquidity.minus(event.params.amount) + } + + pool.totalValueLockedToken0 = pool.totalValueLockedToken0.minus(amount0) + pool.totalValueLockedToken1 = pool.totalValueLockedToken1.minus(amount1) + pool.totalValueLockedETH = pool.totalValueLockedToken0 + .times(token0.derivedETH) + .plus(pool.totalValueLockedToken1.times(token1.derivedETH)) + pool.totalValueLockedUSD = pool.totalValueLockedETH.times(bundle.ethPriceUSD) + + // reset aggregates with new amounts + factory.totalValueLockedETH = factory.totalValueLockedETH.plus(pool.totalValueLockedETH) + factory.totalValueLockedUSD = factory.totalValueLockedETH.times(bundle.ethPriceUSD) + + // burn entity + let transaction = loadTransaction(event) + let burn = new Burn(transaction.id + '#' + pool.txCount.toString()) + burn.transaction = transaction.id + burn.timestamp = transaction.timestamp + burn.pool = pool.id + burn.token0 = pool.token0 + burn.token1 = pool.token1 + burn.owner = event.params.owner + burn.origin = event.transaction.from + burn.amount = event.params.amount + burn.amount0 = amount0 + burn.amount1 = amount1 + burn.amountUSD = amountUSD + burn.tickLower = BigInt.fromI32(event.params.tickLower) + 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) + if (lowerTick && upperTick) { + 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) + + updateTickFeeVarsAndSave(lowerTick, event) + updateTickFeeVarsAndSave(upperTick, event) + } + 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) + + token0.save() + token1.save() + pool.save() + factory.save() + burn.save() + } } export function handleSwap(event: SwapEvent): void { - let bundle = Bundle.load('1') - let factory = Factory.load(FACTORY_ADDRESS) - let pool = Pool.load(event.address.toHexString()) + let bundle = Bundle.load('1')! + let factory = Factory.load(FACTORY_ADDRESS)! + let pool = Pool.load(event.address.toHexString())! // hot fix for bad pricing if (pool.id == '0x9663f2ca0454accad3e094448ea6f77443880454') { @@ -280,224 +290,229 @@ export function handleSwap(event: SwapEvent): void { let token0 = Token.load(pool.token0) let token1 = Token.load(pool.token1) - let oldTick = pool.tick! + if (token0 && token1) { + let oldTick = pool.tick - // amounts - 0/1 are token deltas: can be positive or negative - let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) - let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals) + // amounts - 0/1 are token deltas: can be positive or negative + let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) + let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals) - // need absolute amounts for volume - let amount0Abs = amount0 - if (amount0.lt(ZERO_BD)) { - amount0Abs = amount0.times(BigDecimal.fromString('-1')) - } - let amount1Abs = amount1 - if (amount1.lt(ZERO_BD)) { - amount1Abs = amount1.times(BigDecimal.fromString('-1')) - } - - let amount0ETH = amount0Abs.times(token0.derivedETH) - let amount1ETH = amount1Abs.times(token1.derivedETH) - let amount0USD = amount0ETH.times(bundle.ethPriceUSD) - let amount1USD = amount1ETH.times(bundle.ethPriceUSD) - - // get amount that should be tracked only - div 2 because cant count both input and output as volume - let amountTotalUSDTracked = getTrackedAmountUSD(amount0Abs, token0 as Token, amount1Abs, token1 as Token).div( - BigDecimal.fromString('2') - ) - let amountTotalETHTracked = safeDiv(amountTotalUSDTracked, bundle.ethPriceUSD) - let amountTotalUSDUntracked = amount0USD.plus(amount1USD).div(BigDecimal.fromString('2')) - - let feesETH = amountTotalETHTracked.times(pool.feeTier.toBigDecimal()).div(BigDecimal.fromString('1000000')) - let feesUSD = amountTotalUSDTracked.times(pool.feeTier.toBigDecimal()).div(BigDecimal.fromString('1000000')) - - // global updates - factory.txCount = factory.txCount.plus(ONE_BI) - factory.totalVolumeETH = factory.totalVolumeETH.plus(amountTotalETHTracked) - factory.totalVolumeUSD = factory.totalVolumeUSD.plus(amountTotalUSDTracked) - factory.untrackedVolumeUSD = factory.untrackedVolumeUSD.plus(amountTotalUSDUntracked) - factory.totalFeesETH = factory.totalFeesETH.plus(feesETH) - factory.totalFeesUSD = factory.totalFeesUSD.plus(feesUSD) - - // reset aggregate tvl before individual pool tvl updates - let currentPoolTvlETH = pool.totalValueLockedETH - factory.totalValueLockedETH = factory.totalValueLockedETH.minus(currentPoolTvlETH) - - // pool volume - pool.volumeToken0 = pool.volumeToken0.plus(amount0Abs) - pool.volumeToken1 = pool.volumeToken1.plus(amount1Abs) - pool.volumeUSD = pool.volumeUSD.plus(amountTotalUSDTracked) - pool.untrackedVolumeUSD = pool.untrackedVolumeUSD.plus(amountTotalUSDUntracked) - pool.feesUSD = pool.feesUSD.plus(feesUSD) - pool.txCount = pool.txCount.plus(ONE_BI) - - // Update the pool with the new active liquidity, price, and tick. - pool.liquidity = event.params.liquidity - pool.tick = BigInt.fromI32(event.params.tick as i32) - pool.sqrtPrice = event.params.sqrtPriceX96 - pool.totalValueLockedToken0 = pool.totalValueLockedToken0.plus(amount0) - pool.totalValueLockedToken1 = pool.totalValueLockedToken1.plus(amount1) - - // update token0 data - token0.volume = token0.volume.plus(amount0Abs) - token0.totalValueLocked = token0.totalValueLocked.plus(amount0) - token0.volumeUSD = token0.volumeUSD.plus(amountTotalUSDTracked) - token0.untrackedVolumeUSD = token0.untrackedVolumeUSD.plus(amountTotalUSDUntracked) - token0.feesUSD = token0.feesUSD.plus(feesUSD) - token0.txCount = token0.txCount.plus(ONE_BI) - - // update token1 data - token1.volume = token1.volume.plus(amount1Abs) - token1.totalValueLocked = token1.totalValueLocked.plus(amount1) - token1.volumeUSD = token1.volumeUSD.plus(amountTotalUSDTracked) - token1.untrackedVolumeUSD = token1.untrackedVolumeUSD.plus(amountTotalUSDUntracked) - token1.feesUSD = token1.feesUSD.plus(feesUSD) - token1.txCount = token1.txCount.plus(ONE_BI) - - // updated pool ratess - let prices = sqrtPriceX96ToTokenPrices(pool.sqrtPrice, token0 as Token, token1 as Token) - pool.token0Price = prices[0] - pool.token1Price = prices[1] - pool.save() - - // update USD pricing - bundle.ethPriceUSD = getEthPriceInUSD() - bundle.save() - token0.derivedETH = findEthPerToken(token0 as Token) - token1.derivedETH = findEthPerToken(token1 as Token) - - /** - * Things afffected by new USD rates - */ - pool.totalValueLockedETH = pool.totalValueLockedToken0 - .times(token0.derivedETH) - .plus(pool.totalValueLockedToken1.times(token1.derivedETH)) - pool.totalValueLockedUSD = pool.totalValueLockedETH.times(bundle.ethPriceUSD) - - factory.totalValueLockedETH = factory.totalValueLockedETH.plus(pool.totalValueLockedETH) - factory.totalValueLockedUSD = factory.totalValueLockedETH.times(bundle.ethPriceUSD) - - token0.totalValueLockedUSD = token0.totalValueLocked.times(token0.derivedETH).times(bundle.ethPriceUSD) - token1.totalValueLockedUSD = token1.totalValueLocked.times(token1.derivedETH).times(bundle.ethPriceUSD) - - // create Swap event - let transaction = loadTransaction(event) - let swap = new Swap(transaction.id + '#' + pool.txCount.toString()) - swap.transaction = transaction.id - swap.timestamp = transaction.timestamp - swap.pool = pool.id - swap.token0 = pool.token0 - swap.token1 = pool.token1 - swap.sender = event.params.sender - swap.origin = event.transaction.from - swap.recipient = event.params.recipient - swap.amount0 = amount0 - swap.amount1 = amount1 - swap.amountUSD = amountTotalUSDTracked - swap.tick = BigInt.fromI32(event.params.tick as i32) - swap.sqrtPriceX96 = event.params.sqrtPriceX96 - swap.logIndex = event.logIndex - - // update fee growth - let poolContract = PoolABI.bind(event.address) - let feeGrowthGlobal0X128 = poolContract.feeGrowthGlobal0X128() - let feeGrowthGlobal1X128 = poolContract.feeGrowthGlobal1X128() - pool.feeGrowthGlobal0X128 = feeGrowthGlobal0X128 as BigInt - pool.feeGrowthGlobal1X128 = feeGrowthGlobal1X128 as BigInt - - // interval data - let uniswapDayData = updateUniswapDayData(event) - let poolDayData = updatePoolDayData(event) - let poolHourData = updatePoolHourData(event) - let token0DayData = updateTokenDayData(token0 as Token, event) - let token1DayData = updateTokenDayData(token1 as Token, event) - let token0HourData = updateTokenHourData(token0 as Token, event) - let token1HourData = updateTokenHourData(token1 as Token, event) - - // update volume metrics - uniswapDayData.volumeETH = uniswapDayData.volumeETH.plus(amountTotalETHTracked) - uniswapDayData.volumeUSD = uniswapDayData.volumeUSD.plus(amountTotalUSDTracked) - uniswapDayData.feesUSD = uniswapDayData.feesUSD.plus(feesUSD) - - poolDayData.volumeUSD = poolDayData.volumeUSD.plus(amountTotalUSDTracked) - poolDayData.volumeToken0 = poolDayData.volumeToken0.plus(amount0Abs) - poolDayData.volumeToken1 = poolDayData.volumeToken1.plus(amount1Abs) - poolDayData.feesUSD = poolDayData.feesUSD.plus(feesUSD) - - poolHourData.volumeUSD = poolHourData.volumeUSD.plus(amountTotalUSDTracked) - poolHourData.volumeToken0 = poolHourData.volumeToken0.plus(amount0Abs) - poolHourData.volumeToken1 = poolHourData.volumeToken1.plus(amount1Abs) - poolHourData.feesUSD = poolHourData.feesUSD.plus(feesUSD) - - token0DayData.volume = token0DayData.volume.plus(amount0Abs) - token0DayData.volumeUSD = token0DayData.volumeUSD.plus(amountTotalUSDTracked) - token0DayData.untrackedVolumeUSD = token0DayData.untrackedVolumeUSD.plus(amountTotalUSDTracked) - token0DayData.feesUSD = token0DayData.feesUSD.plus(feesUSD) - - token0HourData.volume = token0HourData.volume.plus(amount0Abs) - token0HourData.volumeUSD = token0HourData.volumeUSD.plus(amountTotalUSDTracked) - token0HourData.untrackedVolumeUSD = token0HourData.untrackedVolumeUSD.plus(amountTotalUSDTracked) - token0HourData.feesUSD = token0HourData.feesUSD.plus(feesUSD) - - token1DayData.volume = token1DayData.volume.plus(amount1Abs) - token1DayData.volumeUSD = token1DayData.volumeUSD.plus(amountTotalUSDTracked) - token1DayData.untrackedVolumeUSD = token1DayData.untrackedVolumeUSD.plus(amountTotalUSDTracked) - token1DayData.feesUSD = token1DayData.feesUSD.plus(feesUSD) - - token1HourData.volume = token1HourData.volume.plus(amount1Abs) - token1HourData.volumeUSD = token1HourData.volumeUSD.plus(amountTotalUSDTracked) - token1HourData.untrackedVolumeUSD = token1HourData.untrackedVolumeUSD.plus(amountTotalUSDTracked) - token1HourData.feesUSD = token1HourData.feesUSD.plus(feesUSD) - - swap.save() - token0DayData.save() - token1DayData.save() - uniswapDayData.save() - poolDayData.save() - token0HourData.save() - token1HourData.save() - poolHourData.save() - factory.save() - pool.save() - 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) + // need absolute amounts for volume + let amount0Abs = amount0 + if (amount0.lt(ZERO_BD)) { + amount0Abs = amount0.times(BigDecimal.fromString('-1')) } - } 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) + let amount1Abs = amount1 + if (amount1.lt(ZERO_BD)) { + amount1Abs = amount1.times(BigDecimal.fromString('-1')) + } + + let amount0ETH = amount0Abs.times(token0.derivedETH) + let amount1ETH = amount1Abs.times(token1.derivedETH) + let amount0USD = amount0ETH.times(bundle.ethPriceUSD) + let amount1USD = amount1ETH.times(bundle.ethPriceUSD) + + // get amount that should be tracked only - div 2 because cant count both input and output as volume + let amountTotalUSDTracked = getTrackedAmountUSD(amount0Abs, token0 as Token, amount1Abs, token1 as Token).div( + BigDecimal.fromString('2') + ) + let amountTotalETHTracked = safeDiv(amountTotalUSDTracked, bundle.ethPriceUSD) + let amountTotalUSDUntracked = amount0USD.plus(amount1USD).div(BigDecimal.fromString('2')) + + let feesETH = amountTotalETHTracked.times(pool.feeTier.toBigDecimal()).div(BigDecimal.fromString('1000000')) + let feesUSD = amountTotalUSDTracked.times(pool.feeTier.toBigDecimal()).div(BigDecimal.fromString('1000000')) + + // global updates + factory.txCount = factory.txCount.plus(ONE_BI) + factory.totalVolumeETH = factory.totalVolumeETH.plus(amountTotalETHTracked) + factory.totalVolumeUSD = factory.totalVolumeUSD.plus(amountTotalUSDTracked) + factory.untrackedVolumeUSD = factory.untrackedVolumeUSD.plus(amountTotalUSDUntracked) + factory.totalFeesETH = factory.totalFeesETH.plus(feesETH) + factory.totalFeesUSD = factory.totalFeesUSD.plus(feesUSD) + + // reset aggregate tvl before individual pool tvl updates + let currentPoolTvlETH = pool.totalValueLockedETH + factory.totalValueLockedETH = factory.totalValueLockedETH.minus(currentPoolTvlETH) + + // pool volume + pool.volumeToken0 = pool.volumeToken0.plus(amount0Abs) + pool.volumeToken1 = pool.volumeToken1.plus(amount1Abs) + pool.volumeUSD = pool.volumeUSD.plus(amountTotalUSDTracked) + pool.untrackedVolumeUSD = pool.untrackedVolumeUSD.plus(amountTotalUSDUntracked) + pool.feesUSD = pool.feesUSD.plus(feesUSD) + pool.txCount = pool.txCount.plus(ONE_BI) + + // Update the pool with the new active liquidity, price, and tick. + pool.liquidity = event.params.liquidity + pool.tick = BigInt.fromI32(event.params.tick as i32) + pool.sqrtPrice = event.params.sqrtPriceX96 + pool.totalValueLockedToken0 = pool.totalValueLockedToken0.plus(amount0) + pool.totalValueLockedToken1 = pool.totalValueLockedToken1.plus(amount1) + + // update token0 data + token0.volume = token0.volume.plus(amount0Abs) + token0.totalValueLocked = token0.totalValueLocked.plus(amount0) + token0.volumeUSD = token0.volumeUSD.plus(amountTotalUSDTracked) + token0.untrackedVolumeUSD = token0.untrackedVolumeUSD.plus(amountTotalUSDUntracked) + token0.feesUSD = token0.feesUSD.plus(feesUSD) + token0.txCount = token0.txCount.plus(ONE_BI) + + // update token1 data + token1.volume = token1.volume.plus(amount1Abs) + token1.totalValueLocked = token1.totalValueLocked.plus(amount1) + token1.volumeUSD = token1.volumeUSD.plus(amountTotalUSDTracked) + token1.untrackedVolumeUSD = token1.untrackedVolumeUSD.plus(amountTotalUSDUntracked) + token1.feesUSD = token1.feesUSD.plus(feesUSD) + token1.txCount = token1.txCount.plus(ONE_BI) + + // updated pool ratess + let prices = sqrtPriceX96ToTokenPrices(pool.sqrtPrice, token0 as Token, token1 as Token) + pool.token0Price = prices[0] + pool.token1Price = prices[1] + pool.save() + + // update USD pricing + bundle.ethPriceUSD = getEthPriceInUSD() + bundle.save() + token0.derivedETH = findEthPerToken(token0 as Token) + token1.derivedETH = findEthPerToken(token1 as Token) + + /** + * Things afffected by new USD rates + */ + pool.totalValueLockedETH = pool.totalValueLockedToken0 + .times(token0.derivedETH) + .plus(pool.totalValueLockedToken1.times(token1.derivedETH)) + pool.totalValueLockedUSD = pool.totalValueLockedETH.times(bundle.ethPriceUSD) + + factory.totalValueLockedETH = factory.totalValueLockedETH.plus(pool.totalValueLockedETH) + factory.totalValueLockedUSD = factory.totalValueLockedETH.times(bundle.ethPriceUSD) + + token0.totalValueLockedUSD = token0.totalValueLocked.times(token0.derivedETH).times(bundle.ethPriceUSD) + token1.totalValueLockedUSD = token1.totalValueLocked.times(token1.derivedETH).times(bundle.ethPriceUSD) + + // create Swap event + let transaction = loadTransaction(event) + let swap = new Swap(transaction.id + '#' + pool.txCount.toString()) + swap.transaction = transaction.id + swap.timestamp = transaction.timestamp + swap.pool = pool.id + swap.token0 = pool.token0 + swap.token1 = pool.token1 + swap.sender = event.params.sender + swap.origin = event.transaction.from + swap.recipient = event.params.recipient + swap.amount0 = amount0 + swap.amount1 = amount1 + swap.amountUSD = amountTotalUSDTracked + swap.tick = BigInt.fromI32(event.params.tick as i32) + swap.sqrtPriceX96 = event.params.sqrtPriceX96 + swap.logIndex = event.logIndex + + // update fee growth + let poolContract = PoolABI.bind(event.address) + let feeGrowthGlobal0X128 = poolContract.feeGrowthGlobal0X128() + let feeGrowthGlobal1X128 = poolContract.feeGrowthGlobal1X128() + pool.feeGrowthGlobal0X128 = feeGrowthGlobal0X128 as BigInt + pool.feeGrowthGlobal1X128 = feeGrowthGlobal1X128 as BigInt + + // interval data + let uniswapDayData = updateUniswapDayData(event) + let poolDayData = updatePoolDayData(event) + let poolHourData = updatePoolHourData(event) + let token0DayData = updateTokenDayData(token0 as Token, event) + let token1DayData = updateTokenDayData(token1 as Token, event) + let token0HourData = updateTokenHourData(token0 as Token, event) + let token1HourData = updateTokenHourData(token1 as Token, event) + + // update volume metrics + uniswapDayData.volumeETH = uniswapDayData.volumeETH.plus(amountTotalETHTracked) + uniswapDayData.volumeUSD = uniswapDayData.volumeUSD.plus(amountTotalUSDTracked) + uniswapDayData.feesUSD = uniswapDayData.feesUSD.plus(feesUSD) + + poolDayData.volumeUSD = poolDayData.volumeUSD.plus(amountTotalUSDTracked) + poolDayData.volumeToken0 = poolDayData.volumeToken0.plus(amount0Abs) + poolDayData.volumeToken1 = poolDayData.volumeToken1.plus(amount1Abs) + poolDayData.feesUSD = poolDayData.feesUSD.plus(feesUSD) + + poolHourData.volumeUSD = poolHourData.volumeUSD.plus(amountTotalUSDTracked) + poolHourData.volumeToken0 = poolHourData.volumeToken0.plus(amount0Abs) + poolHourData.volumeToken1 = poolHourData.volumeToken1.plus(amount1Abs) + poolHourData.feesUSD = poolHourData.feesUSD.plus(feesUSD) + + token0DayData.volume = token0DayData.volume.plus(amount0Abs) + token0DayData.volumeUSD = token0DayData.volumeUSD.plus(amountTotalUSDTracked) + token0DayData.untrackedVolumeUSD = token0DayData.untrackedVolumeUSD.plus(amountTotalUSDTracked) + token0DayData.feesUSD = token0DayData.feesUSD.plus(feesUSD) + + token0HourData.volume = token0HourData.volume.plus(amount0Abs) + token0HourData.volumeUSD = token0HourData.volumeUSD.plus(amountTotalUSDTracked) + token0HourData.untrackedVolumeUSD = token0HourData.untrackedVolumeUSD.plus(amountTotalUSDTracked) + token0HourData.feesUSD = token0HourData.feesUSD.plus(feesUSD) + + token1DayData.volume = token1DayData.volume.plus(amount1Abs) + token1DayData.volumeUSD = token1DayData.volumeUSD.plus(amountTotalUSDTracked) + token1DayData.untrackedVolumeUSD = token1DayData.untrackedVolumeUSD.plus(amountTotalUSDTracked) + token1DayData.feesUSD = token1DayData.feesUSD.plus(feesUSD) + + token1HourData.volume = token1HourData.volume.plus(amount1Abs) + token1HourData.volumeUSD = token1HourData.volumeUSD.plus(amountTotalUSDTracked) + token1HourData.untrackedVolumeUSD = token1HourData.untrackedVolumeUSD.plus(amountTotalUSDTracked) + token1HourData.feesUSD = token1HourData.feesUSD.plus(feesUSD) + + swap.save() + token0DayData.save() + token1DayData.save() + uniswapDayData.save() + poolDayData.save() + poolHourData.save() + token0HourData.save() + token1HourData.save() + poolHourData.save() + factory.save() + pool.save() + token0.save() + token1.save() + + // Update inner vars of current or crossed ticks + let newTick = pool.tick + if (oldTick && newTick) { + 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 { // update fee growth - let pool = Pool.load(event.address.toHexString()) + let pool = Pool.load(event.address.toHexString())! let poolContract = PoolABI.bind(event.address) let feeGrowthGlobal0X128 = poolContract.feeGrowthGlobal0X128() let feeGrowthGlobal1X128 = poolContract.feeGrowthGlobal1X128() @@ -515,7 +530,7 @@ function updateTickFeeVarsAndSave(tick: Tick, event: ethereum.Event): void { tick.feeGrowthOutside1X128 = tickResult.value3 tick.save() - updateTickDayData(tick!, event) + updateTickDayData(tick, event) } function loadTickUpdateFeeVarsAndSave(tickId: i32, event: ethereum.Event): void { @@ -527,6 +542,6 @@ function loadTickUpdateFeeVarsAndSave(tickId: i32, event: ethereum.Event): void .concat(tickId.toString()) ) if (tick !== null) { - updateTickFeeVarsAndSave(tick!, event) + updateTickFeeVarsAndSave(tick, event) } } diff --git a/src/mappings/position-manager.ts b/src/mappings/position-manager.ts index 5eaa1520..49f5d7d1 100644 --- a/src/mappings/position-manager.ts +++ b/src/mappings/position-manager.ts @@ -100,18 +100,20 @@ export function handleIncreaseLiquidity(event: IncreaseLiquidity): void { let token0 = Token.load(position.token0) let token1 = Token.load(position.token1) - let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) - let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals) + if (token0 && token1) { + let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) + let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals) - position.liquidity = position.liquidity.plus(event.params.liquidity) - position.depositedToken0 = position.depositedToken0.plus(amount0) - position.depositedToken1 = position.depositedToken1.plus(amount1) + position.liquidity = position.liquidity.plus(event.params.liquidity) + position.depositedToken0 = position.depositedToken0.plus(amount0) + position.depositedToken1 = position.depositedToken1.plus(amount1) - updateFeeVars(position!, event, event.params.tokenId) + updateFeeVars(position, event, event.params.tokenId) - position.save() + position.save() - savePositionSnapshot(position!, event) + savePositionSnapshot(position, event) + } } export function handleDecreaseLiquidity(event: DecreaseLiquidity): void { @@ -134,16 +136,19 @@ export function handleDecreaseLiquidity(event: DecreaseLiquidity): void { let token0 = Token.load(position.token0) let token1 = Token.load(position.token1) - let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) - let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals) - position.liquidity = position.liquidity.minus(event.params.liquidity) - position.withdrawnToken0 = position.withdrawnToken0.plus(amount0) - position.withdrawnToken1 = position.withdrawnToken1.plus(amount1) + if (token0 && token1) { + let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) + let amount1 = convertTokenToDecimal(event.params.amount1, token1.decimals) - position = updateFeeVars(position!, event, event.params.tokenId) - position.save() - savePositionSnapshot(position!, event) + position.liquidity = position.liquidity.minus(event.params.liquidity) + position.withdrawnToken0 = position.withdrawnToken0.plus(amount0) + position.withdrawnToken1 = position.withdrawnToken1.plus(amount1) + + position = updateFeeVars(position, event, event.params.tokenId) + position.save() + savePositionSnapshot(position, event) + } } export function handleCollect(event: Collect): void { @@ -157,13 +162,16 @@ export function handleCollect(event: Collect): void { } let token0 = Token.load(position.token0) - let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) - position.collectedFeesToken0 = position.collectedFeesToken0.plus(amount0) - position.collectedFeesToken1 = position.collectedFeesToken1.plus(amount0) - position = updateFeeVars(position!, event, event.params.tokenId) + if (token0) { + let amount0 = convertTokenToDecimal(event.params.amount0, token0.decimals) + position.collectedFeesToken0 = position.collectedFeesToken0.plus(amount0) + position.collectedFeesToken1 = position.collectedFeesToken1.plus(amount0) + } + + position = updateFeeVars(position, event, event.params.tokenId) position.save() - savePositionSnapshot(position!, event) + savePositionSnapshot(position, event) } export function handleTransfer(event: Transfer): void { @@ -177,5 +185,5 @@ export function handleTransfer(event: Transfer): void { position.owner = event.params.to position.save() - savePositionSnapshot(position!, event) + savePositionSnapshot(position, event) } diff --git a/src/utils/index.ts b/src/utils/index.ts index d947feee..9c3d9737 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -87,7 +87,7 @@ export function loadTransaction(event: ethereum.Event): Transaction { } transaction.blockNumber = event.block.number transaction.timestamp = event.block.timestamp - transaction.gasUsed = event.transaction.gasUsed + transaction.gasUsed = BigInt.zero() //needs to be moved to transaction receipt transaction.gasPrice = event.transaction.gasPrice transaction.save() return transaction as Transaction diff --git a/src/utils/intervalUpdates.ts b/src/utils/intervalUpdates.ts index c63cd5ef..1e0c0e40 100644 --- a/src/utils/intervalUpdates.ts +++ b/src/utils/intervalUpdates.ts @@ -21,7 +21,7 @@ import { ethereum } from '@graphprotocol/graph-ts' * @param event */ export function updateUniswapDayData(event: ethereum.Event): UniswapDayData { - let uniswap = Factory.load(FACTORY_ADDRESS) + let uniswap = Factory.load(FACTORY_ADDRESS)! let timestamp = event.block.timestamp.toI32() let dayID = timestamp / 86400 // rounded let dayStartTimestamp = dayID * 86400 @@ -48,7 +48,7 @@ export function updatePoolDayData(event: ethereum.Event): PoolDayData { .toHexString() .concat('-') .concat(dayID.toString()) - let pool = Pool.load(event.address.toHexString()) + let pool = Pool.load(event.address.toHexString())! let poolDayData = PoolDayData.load(dayPoolID) if (poolDayData === null) { poolDayData = new PoolDayData(dayPoolID) @@ -97,7 +97,7 @@ export function updatePoolHourData(event: ethereum.Event): PoolHourData { .toHexString() .concat('-') .concat(hourIndex.toString()) - let pool = Pool.load(event.address.toHexString()) + let pool = Pool.load(event.address.toHexString())! let poolHourData = PoolHourData.load(hourPoolID) if (poolHourData === null) { poolHourData = new PoolHourData(hourPoolID) @@ -141,7 +141,7 @@ export function updatePoolHourData(event: ethereum.Event): PoolHourData { } export function updateTokenDayData(token: Token, event: ethereum.Event): TokenDayData { - let bundle = Bundle.load('1') + let bundle = Bundle.load('1')! let timestamp = event.block.timestamp.toI32() let dayID = timestamp / 86400 let dayStartTimestamp = dayID * 86400 @@ -184,7 +184,7 @@ export function updateTokenDayData(token: Token, event: ethereum.Event): TokenDa } export function updateTokenHourData(token: Token, event: ethereum.Event): TokenHourData { - let bundle = Bundle.load('1') + let bundle = Bundle.load('1')! let timestamp = event.block.timestamp.toI32() let hourIndex = timestamp / 3600 // get unique hour within unix history let hourStartUnix = hourIndex * 3600 // want the rounded effect diff --git a/src/utils/pricing.ts b/src/utils/pricing.ts index 1a8a19cf..f339be7b 100644 --- a/src/utils/pricing.ts +++ b/src/utils/pricing.ts @@ -44,7 +44,7 @@ let STABLE_COINS: string[] = [ let MINIMUM_ETH_LOCKED = BigDecimal.fromString('60') -let Q192 = 2 ** 192 +let Q192 = BigInt.fromI32(2).pow(192 as u8) export function sqrtPriceX96ToTokenPrices(sqrtPriceX96: BigInt, token0: Token, token1: Token): BigDecimal[] { let num = sqrtPriceX96.times(sqrtPriceX96).toBigDecimal() let denom = BigDecimal.fromString(Q192.toString()) @@ -80,7 +80,7 @@ export function findEthPerToken(token: Token): BigDecimal { // need to update this to actually detect best rate based on liquidity distribution let largestLiquidityETH = ZERO_BD let priceSoFar = ZERO_BD - let bundle = Bundle.load('1') + let bundle = Bundle.load('1')! // hardcoded fix for incorrect rates // if whitelist includes token - get the safe price @@ -91,26 +91,32 @@ export function findEthPerToken(token: Token): BigDecimal { let poolAddress = whiteList[i] let pool = Pool.load(poolAddress) - if (pool.liquidity.gt(ZERO_BI)) { - if (pool.token0 == token.id) { - // whitelist token is token1 - let token1 = Token.load(pool.token1) - // get the derived ETH in pool - let ethLocked = pool.totalValueLockedToken1.times(token1.derivedETH) - if (ethLocked.gt(largestLiquidityETH) && ethLocked.gt(MINIMUM_ETH_LOCKED)) { - largestLiquidityETH = ethLocked - // token1 per our token * Eth per token1 - priceSoFar = pool.token1Price.times(token1.derivedETH as BigDecimal) + if (pool) { + if (pool.liquidity.gt(ZERO_BI)) { + if (pool.token0 == token.id) { + // whitelist token is token1 + let token1 = Token.load(pool.token1) + // get the derived ETH in pool + if (token1) { + let ethLocked = pool.totalValueLockedToken1.times(token1.derivedETH) + if (ethLocked.gt(largestLiquidityETH) && ethLocked.gt(MINIMUM_ETH_LOCKED)) { + largestLiquidityETH = ethLocked + // token1 per our token * Eth per token1 + priceSoFar = pool.token1Price.times(token1.derivedETH as BigDecimal) + } + } } - } - if (pool.token1 == token.id) { - let token0 = Token.load(pool.token0) - // get the derived ETH in pool - let ethLocked = pool.totalValueLockedToken0.times(token0.derivedETH) - if (ethLocked.gt(largestLiquidityETH) && ethLocked.gt(MINIMUM_ETH_LOCKED)) { - largestLiquidityETH = ethLocked - // token0 per our token * ETH per token0 - priceSoFar = pool.token0Price.times(token0.derivedETH as BigDecimal) + if (pool.token1 == token.id) { + let token0 = Token.load(pool.token0) + // get the derived ETH in pool + if (token0) { + let ethLocked = pool.totalValueLockedToken0.times(token0.derivedETH) + if (ethLocked.gt(largestLiquidityETH) && ethLocked.gt(MINIMUM_ETH_LOCKED)) { + largestLiquidityETH = ethLocked + // token0 per our token * ETH per token0 + priceSoFar = pool.token0Price.times(token0.derivedETH as BigDecimal) + } + } } } } @@ -131,7 +137,7 @@ export function getTrackedAmountUSD( tokenAmount1: BigDecimal, token1: Token ): BigDecimal { - let bundle = Bundle.load('1') + let bundle = Bundle.load('1')! let price0USD = token0.derivedETH.times(bundle.ethPriceUSD) let price1USD = token1.derivedETH.times(bundle.ethPriceUSD) diff --git a/src/utils/staticTokenDefinition.ts b/src/utils/staticTokenDefinition.ts index bb805f2d..ac2f2095 100644 --- a/src/utils/staticTokenDefinition.ts +++ b/src/utils/staticTokenDefinition.ts @@ -1,93 +1,64 @@ -import { - Address, - BigInt, -} from "@graphprotocol/graph-ts" - +import { Address, BigInt } from '@graphprotocol/graph-ts' + // Initialize a Token Definition with the attributes export class StaticTokenDefinition { - address : Address + address: Address symbol: string name: string decimals: BigInt - // Initialize a Token Definition with its attributes - constructor(address: Address, symbol: string, name: string, decimals: BigInt) { - this.address = address - this.symbol = symbol - this.name = name - this.decimals = decimals - } - // Get all tokens with a static defintion static getStaticDefinitions(): Array { - let staticDefinitions = new Array(6) - - // Add DGD - let tokenDGD = new StaticTokenDefinition( - Address.fromString('0xe0b7927c4af23765cb51314a0e0521a9645f0e2a'), - 'DGD', - 'DGD', - BigInt.fromI32(9) - ) - staticDefinitions.push(tokenDGD) - - // Add AAVE - let tokenAAVE = new StaticTokenDefinition( - Address.fromString('0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9'), - 'AAVE', - 'Aave Token', - BigInt.fromI32(18) - ) - staticDefinitions.push(tokenAAVE) - - // Add LIF - let tokenLIF = new StaticTokenDefinition( - Address.fromString('0xeb9951021698b42e4399f9cbb6267aa35f82d59d'), - 'LIF', - 'Lif', - BigInt.fromI32(18) - ) - staticDefinitions.push(tokenLIF) - - // Add SVD - let tokenSVD = new StaticTokenDefinition( - Address.fromString('0xbdeb4b83251fb146687fa19d1c660f99411eefe3'), - 'SVD', - 'savedroid', - BigInt.fromI32(18) - ) - staticDefinitions.push(tokenSVD) - - // Add TheDAO - let tokenTheDAO = new StaticTokenDefinition( - Address.fromString('0xbb9bc244d798123fde783fcc1c72d3bb8c189413'), - 'TheDAO', - 'TheDAO', - BigInt.fromI32(16) - ) - staticDefinitions.push(tokenTheDAO) - - // Add HPB - let tokenHPB = new StaticTokenDefinition( - Address.fromString('0x38c6a68304cdefb9bec48bbfaaba5c5b47818bb2'), - 'HPB', - 'HPBCoin', - BigInt.fromI32(18) - ) - staticDefinitions.push(tokenHPB) - + const staticDefinitions: Array = [ + { + address: Address.fromString('0xe0b7927c4af23765cb51314a0e0521a9645f0e2a'), + symbol: 'DGD', + name: 'DGD', + decimals: BigInt.fromI32(9) + }, + { + address: Address.fromString('0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9'), + symbol: 'AAVE', + name: 'Aave Token', + decimals: BigInt.fromI32(18) + }, + { + address: Address.fromString('0xeb9951021698b42e4399f9cbb6267aa35f82d59d'), + symbol: 'LIF', + name: 'Lif', + decimals: BigInt.fromI32(18) + }, + { + address: Address.fromString('0xbdeb4b83251fb146687fa19d1c660f99411eefe3'), + symbol: 'SVD', + name: 'savedroid', + decimals: BigInt.fromI32(18) + }, + { + address: Address.fromString('0xbb9bc244d798123fde783fcc1c72d3bb8c189413'), + symbol: 'TheDAO', + name: 'TheDAO', + decimals: BigInt.fromI32(16) + }, + { + address: Address.fromString('0x38c6a68304cdefb9bec48bbfaaba5c5b47818bb2'), + symbol: 'HPB', + name: 'HPBCoin', + decimals: BigInt.fromI32(18) + } + ] return staticDefinitions } // Helper for hardcoded tokens - static fromAddress(tokenAddress: Address) : StaticTokenDefinition | null { + static fromAddress(tokenAddress: Address): StaticTokenDefinition | null { let staticDefinitions = this.getStaticDefinitions() let tokenAddressHex = tokenAddress.toHexString() // Search the definition using the address for (let i = 0; i < staticDefinitions.length; i++) { let staticDefinition = staticDefinitions[i] - if(staticDefinition.address.toHexString() == tokenAddressHex) { + if (staticDefinition.address.toHexString() == tokenAddressHex) { return staticDefinition } } @@ -95,5 +66,4 @@ export class StaticTokenDefinition { // If not found, return null return null } - -} \ No newline at end of file +} diff --git a/src/utils/token.ts b/src/utils/token.ts index db21b4e6..675d3863 100644 --- a/src/utils/token.ts +++ b/src/utils/token.ts @@ -22,7 +22,7 @@ export function fetchTokenSymbol(tokenAddress: Address): string { } else { // try with the static definition let staticTokenDefinition = StaticTokenDefinition.fromAddress(tokenAddress) - if(staticTokenDefinition != null) { + if (staticTokenDefinition != null) { symbolValue = staticTokenDefinition.symbol } } @@ -50,7 +50,7 @@ export function fetchTokenName(tokenAddress: Address): string { } else { // try with the static definition let staticTokenDefinition = StaticTokenDefinition.fromAddress(tokenAddress) - if(staticTokenDefinition != null) { + if (staticTokenDefinition != null) { nameValue = staticTokenDefinition.name } } @@ -64,28 +64,30 @@ export function fetchTokenName(tokenAddress: Address): string { export function fetchTokenTotalSupply(tokenAddress: Address): BigInt { let contract = ERC20.bind(tokenAddress) - let totalSupplyValue = null + let totalSupplyValue = BigInt.zero() let totalSupplyResult = contract.try_totalSupply() if (!totalSupplyResult.reverted) { - totalSupplyValue = totalSupplyResult as i32 + totalSupplyValue = totalSupplyResult.value } - return BigInt.fromI32(totalSupplyValue as i32) + return totalSupplyValue } -export function fetchTokenDecimals(tokenAddress: Address): BigInt { +export function fetchTokenDecimals(tokenAddress: Address): BigInt | null { let contract = ERC20.bind(tokenAddress) // try types uint8 for decimals - let decimalValue = null let decimalResult = contract.try_decimals() + if (!decimalResult.reverted) { - decimalValue = decimalResult.value + if (decimalResult.value.lt(BigInt.fromI32(255))) { + return decimalResult.value + } } else { // try with the static definition let staticTokenDefinition = StaticTokenDefinition.fromAddress(tokenAddress) - if(staticTokenDefinition != null) { + if (staticTokenDefinition) { return staticTokenDefinition.decimals } } - return BigInt.fromI32(decimalValue as i32) + return null } diff --git a/subgraph.yaml b/subgraph.yaml index ee6d649e..f8e2d3dc 100644 --- a/subgraph.yaml +++ b/subgraph.yaml @@ -1,13 +1,14 @@ -specVersion: 0.0.2 +specVersion: 0.0.4 description: Uniswap is a decentralized protocol for automated token exchange on Ethereum. repository: https://github.com/Uniswap/uniswap-v3-subgraph schema: file: ./schema.graphql graft: - base: QmPrb5mvZj3ycUugZgwLWCvK93jfXfhvfjRXrFk4tRmyCX - block: 14292820 + base: QmZeCuoZeadgHkGwLwMeguyqUKz1WPWQYKcKyMCeQqGhsF + block: 19470000 features: - nonFatalErrors + - grafting dataSources: - kind: ethereum/contract name: Factory @@ -18,7 +19,7 @@ dataSources: startBlock: 12369621 mapping: kind: ethereum/events - apiVersion: 0.0.4 + apiVersion: 0.0.7 language: wasm/assemblyscript file: ./src/mappings/factory.ts entities: @@ -47,7 +48,7 @@ dataSources: startBlock: 12369651 mapping: kind: ethereum/events - apiVersion: 0.0.4 + apiVersion: 0.0.7 language: wasm/assemblyscript file: ./src/mappings/position-manager.ts entities: @@ -79,7 +80,7 @@ templates: abi: Pool mapping: kind: ethereum/events - apiVersion: 0.0.4 + apiVersion: 0.0.7 language: wasm/assemblyscript file: ./src/mappings/core.ts entities: