Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor subgraph to support multiple chains #233

Merged
merged 2 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ Pending Changes at same URL
2. Install postgres: `brew install postgresql`
3. `yarn run build:docker`
4. `yarn run test`

### Adding New Chains

1. Create a new subgraph config in `src/utils/chains.ts`. This will require adding a new `ChainId`. Set the `SELECTED_CHAIN` in `getSubgraphConfig()` to be this new `ChainId`.
2. Add a new entry in `networks.json` for the new chain. The network name should be derived from the CLI Name in The Graph's [supported networks documenation](https://thegraph.com/docs/en/developing/supported-networks/). The factory address can be derived from Uniswap's [deployments documentation](https://docs.uniswap.org/contracts/v3/reference/deployments/ethereum-deployments).
56 changes: 56 additions & 0 deletions networks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"arbitrum-one": {
"Factory": {
"address": "0x1F98431c8aD98523631AE4a59f267346ea31F984",
"startBlock": 165
}
},
"avalanche": {
"Factory": {
"address": "0x740b1c1de25031C31FF4fC9A62f554A55cdC1baD",
"startBlock": 27832971
}
},
"base": {
"Factory": {
"address": "0x33128a8fC17869897dcE68Ed026d694621f6FDfD",
"startBlock": 2009445
}
},
"blast-mainnet": {
"Factory": {
"address": "0x792edAdE80af5fC680d96a2eD80A44247D2Cf6Fd",
"startBlock": 400903
}
},
"bsc": {
"Factory": {
"address": "0xdB1d10011AD0Ff90774D0C6Bb92e5C5c8b4461F7",
"startBlock": 12369621
}
},
"celo": {
"Factory": {
"address": "0xAfE208a311B21f13EF87E33A90049fC17A7acDEc",
"startBlock": 13916355
}
},
"mainnet": {
"Factory": {
"address": "0x1F98431c8aD98523631AE4a59f267346ea31F984",
"startBlock": 12369621
}
},
"matic": {
"Factory": {
"address": "0x1F98431c8aD98523631AE4a59f267346ea31F984",
"startBlock": 22757547
}
},
"optimism": {
"Factory": {
"address": "0x1F98431c8aD98523631AE4a59f267346ea31F984",
"startBlock": 0
}
}
}
4 changes: 3 additions & 1 deletion schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ type Token @entity {
totalValueLockedUSD: BigDecimal!
# TVL derived in USD untracked
totalValueLockedUSDUntracked: BigDecimal!
# derived price in ETH
# Note: for chains where ETH is not the native token, this will be the derived
# price of that chain's native token, effectively, this should be renamed
# derivedNative
derivedETH: BigDecimal!
# pools token is in that are white listed for USD pricing
whitelistPools: [Pool!]!
Expand Down
128 changes: 128 additions & 0 deletions src/backfill/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/* eslint-disable prefer-const */
mzywang marked this conversation as resolved.
Show resolved Hide resolved
import { Address, BigInt, ethereum } from '@graphprotocol/graph-ts'

import { ERC20 } from '../types/Factory/ERC20'
import { Pool as PoolABI } from '../types/Factory/Pool'
import { Pool, Token } from '../types/schema'
import { Pool as PoolTemplate } from '../types/templates'
import { convertTokenToDecimal } from '../utils'
import { ZERO_BD, ZERO_BI } from '../utils/constants'
import { StaticTokenDefinition } from '../utils/staticTokenDefinition'
import { fetchTokenDecimals, fetchTokenName, fetchTokenSymbol, fetchTokenTotalSupply } from '../utils/token'

function populateToken(tokenAddress: string, tokenOverrides: StaticTokenDefinition[]): void {
let token = Token.load(tokenAddress)
if (token != null) {
return
}
token = new Token(tokenAddress)
token.symbol = fetchTokenSymbol(Address.fromString(tokenAddress), tokenOverrides)
token.name = fetchTokenName(Address.fromString(tokenAddress), tokenOverrides)
token.totalSupply = fetchTokenTotalSupply(Address.fromString(tokenAddress))
let decimals = fetchTokenDecimals(Address.fromString(tokenAddress), tokenOverrides)
if (decimals === null) {
return
}
token.decimals = decimals
token.derivedETH = ZERO_BD
token.volume = ZERO_BD
token.volumeUSD = ZERO_BD
token.feesUSD = ZERO_BD
token.untrackedVolumeUSD = ZERO_BD
token.totalValueLocked = ZERO_BD
token.totalValueLockedUSD = ZERO_BD
token.totalValueLockedUSDUntracked = ZERO_BD
token.txCount = ZERO_BI
token.poolCount = ZERO_BI
token.whitelistPools = []
token.save()
}

/**
* Create entries in store for each pool and token
* before regenesis.
*/
export function populateEmptyPools(
event: ethereum.Event,
poolMappings: Array<Address[]>,
whitelistTokens: string[],
tokenOverrides: StaticTokenDefinition[],
): void {
let length = poolMappings.length
for (let i = 0; i < length; ++i) {
let poolMapping = poolMappings[i]
let newAddress = poolMapping[1]
let token0Address = poolMapping[2]
let token1Address = poolMapping[3]

let poolContract = PoolABI.bind(newAddress)
let pool = new Pool(newAddress.toHexString()) as Pool
pool.createdAtBlockNumber = event.block.number
pool.createdAtTimestamp = event.block.timestamp
pool.token0 = token0Address.toHexString()
pool.token1 = token1Address.toHexString()
pool.liquidity = poolContract.liquidity()
pool.sqrtPrice = ZERO_BI
pool.token0Price = ZERO_BD
pool.token1Price = ZERO_BD
pool.observationIndex = ZERO_BI
pool.liquidityProviderCount = ZERO_BI
pool.txCount = ZERO_BI
pool.totalValueLockedToken0 = ZERO_BD
pool.totalValueLockedToken1 = ZERO_BD
pool.totalValueLockedETH = ZERO_BD
pool.totalValueLockedUSD = ZERO_BD
pool.totalValueLockedUSDUntracked = ZERO_BD
pool.volumeToken0 = ZERO_BD
pool.volumeToken1 = ZERO_BD
pool.volumeUSD = ZERO_BD
pool.untrackedVolumeUSD = ZERO_BD
pool.feesUSD = ZERO_BD
pool.collectedFeesToken0 = ZERO_BD
pool.collectedFeesToken1 = ZERO_BD
pool.collectedFeesUSD = ZERO_BD

// need fee tier
let feeTier = poolContract.fee()
pool.feeTier = BigInt.fromI32(feeTier)

// create token entities if needed
populateToken(token0Address.toHexString(), tokenOverrides)
populateToken(token1Address.toHexString(), tokenOverrides)
let token0 = Token.load(token0Address.toHexString())
let token1 = Token.load(token1Address.toHexString())

if (token0 && token1) {
if (whitelistTokens.includes(pool.token0)) {
let newPools = token1.whitelistPools
newPools.push(pool.id)
token1.whitelistPools = newPools
}

if (whitelistTokens.includes(token1.id)) {
let newPools = token0.whitelistPools
newPools.push(pool.id)
token0.whitelistPools = newPools
}

// populate the TVL by call contract balanceOf
let token0Contract = ERC20.bind(Address.fromString(pool.token0))
let tvlToken0Raw = token0Contract.balanceOf(Address.fromString(pool.id))
let tvlToken0Adjusted = convertTokenToDecimal(tvlToken0Raw, token0.decimals)
pool.totalValueLockedToken0 = tvlToken0Adjusted
token0.totalValueLocked = tvlToken0Adjusted

let token1Contract = ERC20.bind(Address.fromString(pool.token1))
let tvlToken1Raw = token1Contract.balanceOf(Address.fromString(pool.id))
let tvlToken1Adjusted = convertTokenToDecimal(tvlToken1Raw, token1.decimals)
pool.totalValueLockedToken1 = tvlToken1Adjusted
token1.totalValueLocked = tvlToken1Adjusted

// add pool to tracked address and store entities
PoolTemplate.create(Address.fromString(pool.id))
token0.save()
token1.save()
pool.save()
}
}
}
Loading
Loading