Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config/arbitrum-one/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ export class TokenDefinition {
export const STATIC_TOKEN_DEFINITIONS: TokenDefinition[] = []

export const SKIP_TOTAL_SUPPLY: string[] = []

export const UNTRACKED_PAIRS: string[] = []
2 changes: 2 additions & 0 deletions config/avalanche/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ export class TokenDefinition {
export const STATIC_TOKEN_DEFINITIONS: TokenDefinition[] = []

export const SKIP_TOTAL_SUPPLY: string[] = []

export const UNTRACKED_PAIRS: string[] = []
3 changes: 3 additions & 0 deletions config/base/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const WHITELIST: string[] = [
'0x4200000000000000000000000000000000000006', // WETH
'0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', // USDC
'0xd9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca', // USDbCC
'0x0b3e328455c4059eeb9e3f84b5543f74e24e7e1b', // VIRTUAL
]

export const STABLECOINS = [
Expand All @@ -33,3 +34,5 @@ export class TokenDefinition {
export const STATIC_TOKEN_DEFINITIONS: TokenDefinition[] = []

export const SKIP_TOTAL_SUPPLY: string[] = []

export const UNTRACKED_PAIRS: string[] = []
2 changes: 2 additions & 0 deletions config/blast-mainnet/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ export class TokenDefinition {
export const STATIC_TOKEN_DEFINITIONS: TokenDefinition[] = []

export const SKIP_TOTAL_SUPPLY: string[] = []

export const UNTRACKED_PAIRS: string[] = []
2 changes: 2 additions & 0 deletions config/bsc/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ export class TokenDefinition {
export const STATIC_TOKEN_DEFINITIONS: TokenDefinition[] = []

export const SKIP_TOTAL_SUPPLY: string[] = []

export const UNTRACKED_PAIRS: string[] = []
3 changes: 3 additions & 0 deletions config/ethereum/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const WHITELIST: string[] = [
'0x1f9840a85d5af5bf1d1762f925bdaddc4201f984', // UNI
'0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', // WBTC
'0x956f47f50a910163d8bf957cf5846d573e7f87ca', // FEI
'0x44ff8620b8ca30902395a7bd3f2407e1a091bf73', // VIRTUAL
]

export const STABLECOINS = []
Expand Down Expand Up @@ -89,3 +90,5 @@ export const STATIC_TOKEN_DEFINITIONS: TokenDefinition[] = [
]

export const SKIP_TOTAL_SUPPLY: string[] = ['0x0000000000bf2686748e1c0255036e7617e7e8a5']

export const UNTRACKED_PAIRS: string[] = ['0x9ea3b5b4ec044b70375236a281986106457b20ef']
2 changes: 2 additions & 0 deletions config/matic/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ export class TokenDefinition {
export const STATIC_TOKEN_DEFINITIONS: TokenDefinition[] = []

export const SKIP_TOTAL_SUPPLY: string[] = []

export const UNTRACKED_PAIRS: string[] = []
2 changes: 2 additions & 0 deletions config/optimism/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ export class TokenDefinition {
export const STATIC_TOKEN_DEFINITIONS: TokenDefinition[] = []

export const SKIP_TOTAL_SUPPLY: string[] = []

export const UNTRACKED_PAIRS: string[] = []
2 changes: 2 additions & 0 deletions config/soneium-mainnet/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ export class TokenDefinition {
export const STATIC_TOKEN_DEFINITIONS: TokenDefinition[] = []

export const SKIP_TOTAL_SUPPLY: string[] = []

export const UNTRACKED_PAIRS: string[] = []
2 changes: 2 additions & 0 deletions config/unichain-mainnet/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ export class TokenDefinition {
export const STATIC_TOKEN_DEFINITIONS: TokenDefinition[] = []

export const SKIP_TOTAL_SUPPLY: string[] = []

export const UNTRACKED_PAIRS: string[] = []
2 changes: 2 additions & 0 deletions config/worldchain-mainnet/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ export class TokenDefinition {
export const STATIC_TOKEN_DEFINITIONS: TokenDefinition[] = []

export const SKIP_TOTAL_SUPPLY: string[] = []

export const UNTRACKED_PAIRS: string[] = []
179 changes: 179 additions & 0 deletions src/mappings/pricing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/* eslint-disable prefer-const */
import { BigDecimal, BigInt } from '@graphprotocol/graph-ts/index'

import { UNTRACKED_PAIRS, WHITELIST } from '../common/chain'
import { ONE_BD, ZERO_BD } from '../common/constants'
import { Bundle, Pair, Token } from '../types/schema'

const WETH_ADDRESS = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'
const USDC_WETH_PAIR = '0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc' // created 10008355
const DAI_WETH_PAIR = '0xa478c2975ab1ea89e8196811f51a7b7ade33eb11' // created block 10042267
const USDT_WETH_PAIR = '0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852' // created block 10093341

export function getEthPriceInUSD(): BigDecimal {
// fetch eth prices for each stablecoin
let daiPair = Pair.load(DAI_WETH_PAIR) // dai is token0
let usdcPair = Pair.load(USDC_WETH_PAIR) // usdc is token0
let usdtPair = Pair.load(USDT_WETH_PAIR) // usdt is token1

// all 3 have been created
if (daiPair !== null && usdcPair !== null && usdtPair !== null) {
let totalLiquidityETH = daiPair.reserve1.plus(usdcPair.reserve1).plus(usdtPair.reserve0)
let daiWeight = daiPair.reserve1.div(totalLiquidityETH)
let usdcWeight = usdcPair.reserve1.div(totalLiquidityETH)
let usdtWeight = usdtPair.reserve0.div(totalLiquidityETH)
return daiPair.token0Price
.times(daiWeight)
.plus(usdcPair.token0Price.times(usdcWeight))
.plus(usdtPair.token1Price.times(usdtWeight))
// dai and USDC have been created
} else if (daiPair !== null && usdcPair !== null) {
let totalLiquidityETH = daiPair.reserve1.plus(usdcPair.reserve1)
let daiWeight = daiPair.reserve1.div(totalLiquidityETH)
let usdcWeight = usdcPair.reserve1.div(totalLiquidityETH)
return daiPair.token0Price.times(daiWeight).plus(usdcPair.token0Price.times(usdcWeight))
// USDC is the only pair so far
} else if (usdcPair !== null) {
return usdcPair.token0Price
} else {
return ZERO_BD
}
}

// minimum liquidity required to count towards tracked volume for pairs with small # of Lps
let MINIMUM_USD_THRESHOLD_NEW_PAIRS = BigDecimal.fromString('400000')

// minimum liquidity for price to get tracked
let MINIMUM_LIQUIDITY_THRESHOLD_ETH = BigDecimal.fromString('2')

/**
* Search through graph to find derived Eth per token.
* @todo update to be derived ETH (add stablecoin estimates)
**/
export function findEthPerToken(token: Token): BigDecimal {
if (token.id == WETH_ADDRESS) {
return ONE_BD
}
const priceTrackingPairs = token.priceTrackingPairs
for (let i = 0; i < priceTrackingPairs.length; i++) {
const pairAddress = priceTrackingPairs[i]
const pair = Pair.load(pairAddress)

if (pair === null) {
continue
}
if (pair.token0 == token.id && pair.reserveETH.gt(MINIMUM_LIQUIDITY_THRESHOLD_ETH)) {
let token1 = Token.load(pair.token1)
if (token1 === null) {
continue
}
return pair.token1Price.times(token1.derivedETH as BigDecimal) // return token1 per our token * Eth per token 1
}
if (pair.token1 == token.id && pair.reserveETH.gt(MINIMUM_LIQUIDITY_THRESHOLD_ETH)) {
let token0 = Token.load(pair.token0)
if (token0 === null) {
continue
}
return pair.token0Price.times(token0.derivedETH as BigDecimal) // return token0 per our token * ETH per token 0
}
}

return ZERO_BD // nothing was found return 0
}

/**
* Accepts tokens and amounts, return tracked amount based on price tracking tokens
* If one token is a price tracking token, return amount in that token converted to USD.
* If both are, return average of two amounts
* If neither is, return 0
*/
export function getTrackedVolumeUSD(
tokenAmount0: BigDecimal,
token0: Token,
tokenAmount1: BigDecimal,
token1: Token,
pair: Pair
): BigDecimal {
let bundle = Bundle.load('1')!
let price0 = token0.derivedETH.times(bundle.ethPrice)
let price1 = token1.derivedETH.times(bundle.ethPrice)

// dont count tracked volume on these pairs - usually rebass tokens
if (UNTRACKED_PAIRS.includes(pair.id)) {
return ZERO_BD
}

// if less than 5 LPs, require high minimum reserve amount amount or return 0
if (pair.liquidityProviderCount.lt(BigInt.fromI32(5))) {
let reserve0USD = pair.reserve0.times(price0)
let reserve1USD = pair.reserve1.times(price1)
if (WHITELIST.includes(token0.id) && WHITELIST.includes(token1.id)) {
if (reserve0USD.plus(reserve1USD).lt(MINIMUM_USD_THRESHOLD_NEW_PAIRS)) {
return ZERO_BD
}
}
if (WHITELIST.includes(token0.id) && !WHITELIST.includes(token1.id)) {
if (reserve0USD.times(BigDecimal.fromString('2')).lt(MINIMUM_USD_THRESHOLD_NEW_PAIRS)) {
return ZERO_BD
}
}
if (!WHITELIST.includes(token0.id) && WHITELIST.includes(token1.id)) {
if (reserve1USD.times(BigDecimal.fromString('2')).lt(MINIMUM_USD_THRESHOLD_NEW_PAIRS)) {
return ZERO_BD
}
}
}

// both are price tracking tokens, take average of both amounts
if (WHITELIST.includes(token0.id) && WHITELIST.includes(token1.id)) {
return tokenAmount0.times(price0).plus(tokenAmount1.times(price1)).div(BigDecimal.fromString('2'))
}

// take full value of the price tracking token amount
if (WHITELIST.includes(token0.id) && !WHITELIST.includes(token1.id)) {
return tokenAmount0.times(price0)
}

// take full value of the price tracking token amount
if (!WHITELIST.includes(token0.id) && WHITELIST.includes(token1.id)) {
return tokenAmount1.times(price1)
}

// neither token is a price tracking token, tracked volume is 0
return ZERO_BD
}

/**
* Accepts tokens and amounts, return tracked amount based on price tracking token list
* If one token is a price tracking token, return amount in that token converted to USD * 2.
* If both are, return sum of two amounts
* If neither is, return 0
*/
export function getTrackedLiquidityUSD(
tokenAmount0: BigDecimal,
token0: Token,
tokenAmount1: BigDecimal,
token1: Token
): BigDecimal {
let bundle = Bundle.load('1')!
let price0 = token0.derivedETH.times(bundle.ethPrice)
let price1 = token1.derivedETH.times(bundle.ethPrice)

// both are price tracking tokens, take average of both amounts
if (WHITELIST.includes(token0.id) && WHITELIST.includes(token1.id)) {
return tokenAmount0.times(price0).plus(tokenAmount1.times(price1))
}

// take double value of the price tracking token amount
if (WHITELIST.includes(token0.id) && !WHITELIST.includes(token1.id)) {
return tokenAmount0.times(price0).times(BigDecimal.fromString('2'))
}

// take double value of the price tracking token amount
if (!WHITELIST.includes(token0.id) && WHITELIST.includes(token1.id)) {
return tokenAmount1.times(price1).times(BigDecimal.fromString('2'))
}

// neither token is a price tracking token, tracked volume is 0
return ZERO_BD
}
4 changes: 2 additions & 2 deletions src/v2/mappings/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ export function handleSync(event: Sync): void {
token0.save()
token1.save()

// get tracked liquidity - will be 0 if neither is in whitelist
// get tracked liquidity - will be 0 if neither is a price tracking token
let trackedLiquidityETH: BigDecimal
if (bundle.ethPrice.notEqual(ZERO_BD)) {
trackedLiquidityETH = getTrackedLiquidityUSD(pair.reserve0, token0 as Token, pair.reserve1, token1 as Token).div(
Expand Down Expand Up @@ -428,7 +428,7 @@ export function handleSwap(event: Swap): void {

let derivedAmountUSD = derivedAmountETH.times(bundle.ethPrice)

// only accounts for volume through white listed tokens
// only accounts for volume through price tracking tokens
let trackedAmountUSD = getTrackedVolumeUSD(amount0Total, token0 as Token, amount1Total, token1 as Token, pair as Pair)

let trackedAmountETH: BigDecimal
Expand Down
37 changes: 27 additions & 10 deletions src/v2/mappings/factory.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
/* eslint-disable prefer-const */
import { log } from '@graphprotocol/graph-ts'

import { PairCreated } from '../../../generated/Factory/Factory'
import { Bundle, Pair, PairTokenLookup, Token, UniswapFactory } from '../../../generated/schema'
import { Pair as PairTemplate } from '../../../generated/templates'
import { FACTORY_ADDRESS } from '../../common/chain'
import { ZERO_BD, ZERO_BI } from '../../common/constants'
import { fetchTokenDecimals, fetchTokenName, fetchTokenSymbol, fetchTokenTotalSupply } from '../../common/helpers'
import { PairCreated } from '../types/Factory/Factory'
import { Bundle, Pair, PairTokenLookup, Token, UniswapFactory } from '../types/schema'
import { Pair as PairTemplate } from '../types/templates'
import {
FACTORY_ADDRESS,
fetchTokenDecimals,
fetchTokenName,
fetchTokenSymbol,
fetchTokenTotalSupply,
ZERO_BD,
ZERO_BI,
} from './helpers'
import { PRICE_TRACKING_TOKENS } from './pricing'

export function handleNewPair(event: PairCreated): void {
// load factory (create if first exchange)
Expand All @@ -29,7 +36,7 @@ export function handleNewPair(event: PairCreated): void {
factory.pairCount = factory.pairCount + 1
factory.save()

// create the tokens
let pair = new Pair(event.params.pair.toHexString()) as Pair
let token0 = Token.load(event.params.token0.toHexString())
let token1 = Token.load(event.params.token1.toHexString())

Expand All @@ -53,8 +60,8 @@ export function handleNewPair(event: PairCreated): void {
token0.tradeVolumeUSD = ZERO_BD
token0.untrackedVolumeUSD = ZERO_BD
token0.totalLiquidity = ZERO_BD
// token0.allPairs = []
token0.txCount = ZERO_BI
token0.priceTrackingPairs = []
}

// fetch info if null
Expand All @@ -75,11 +82,21 @@ export function handleNewPair(event: PairCreated): void {
token1.tradeVolumeUSD = ZERO_BD
token1.untrackedVolumeUSD = ZERO_BD
token1.totalLiquidity = ZERO_BD
// token1.allPairs = []
token1.txCount = ZERO_BI
token1.priceTrackingPairs = []
}

if (PRICE_TRACKING_TOKENS.includes(token0.id)) {
const priceTrackingPairs = token1.priceTrackingPairs
priceTrackingPairs.push(pair.id)
token1.priceTrackingPairs = priceTrackingPairs
}
if (PRICE_TRACKING_TOKENS.includes(token1.id)) {
const priceTrackingPairs = token0.priceTrackingPairs
priceTrackingPairs.push(pair.id)
token0.priceTrackingPairs = priceTrackingPairs
}

let pair = new Pair(event.params.pair.toHexString()) as Pair
pair.token0 = token0.id
pair.token1 = token1.id
pair.liquidityProviderCount = ZERO_BI
Expand Down
3 changes: 3 additions & 0 deletions src/v2/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ type Token @entity {
pairDayDataQuote: [PairDayData!]! @derivedFrom(field: "token1")
pairBase: [Pair!]! @derivedFrom(field: "token0")
pairQuote: [Pair!]! @derivedFrom(field: "token1")

# pairs used for USD pricing
priceTrackingPairs: [Pair!]!
}

type Pair @entity {
Expand Down