Skip to content

Commit

Permalink
add subgraph unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mzywang committed May 21, 2024
1 parent 1b15d50 commit 87cfa3d
Show file tree
Hide file tree
Showing 12 changed files with 500 additions and 71 deletions.
15 changes: 14 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,18 @@ module.exports = {
}
}
]
}
},
overrides: [
{
files: ['tests/**/*.ts'],
settings: {
jest: {
version: 26
},
// jest is added as a plugin in our org's eslint config, but we use
// matchstick, and this would crash when linting matchstick files.
'disable/plugins': ['jest']
}
}
]
}
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ build/
node_modules/
src/types/
.DS_STORE
yarn-error.log
yarn-error.log
tests/.bin/
tests/.docker/
tests/.latest.json
21 changes: 21 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# copied from https://github.com/LimeChain/demo-subgraph/blob/main/Dockerfile

FROM --platform=linux/x86_64 ubuntu:22.04

ARG DEBIAN_FRONTEND=noninteractive

ENV ARGS=""

RUN apt update \
&& apt install -y sudo curl postgresql postgresql-contrib

RUN curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - \
&& sudo apt-get install -y nodejs

RUN curl -OL https://github.com/LimeChain/matchstick/releases/download/0.6.0/binary-linux-22 \
&& chmod a+x binary-linux-22

RUN mkdir matchstick
WORKDIR /matchstick

CMD ../binary-linux-22 ${ARGS}
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
# Uniswap V3 Subgraph

### Subgraph Endpoint
### Subgraph Endpoint

Synced at: https://thegraph.com/hosted-service/subgraph/ianlapham/uniswap-v3-subgraph?selected=playground

Pending Changes at same URL

### Running Unit Tests

1. Install [Docker](https://docs.docker.com/get-docker/) if you don't have it already
2. Install postgres: `brew install postgresql`
3. `yarn run build:docker`
4. `yarn run test`
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
"scripts": {
"lint": "eslint . --ext .ts --fix",
"build": "run-s codegen && graph build",
"build:docker": "docker build -t matchstick .",
"buildonly": "graph build",
"deploy:alchemy": "graph deploy --node https://subgraphs.alchemy.com/api/subgraphs/deploy --ipfs https://ipfs.satsuma.xyz",
"codegen": "graph codegen --output-dir src/types/",
"test": "graph test -d",
"create-local": "graph create ianlapham/uniswap-v3 --node http://127.0.0.1:8020",
"deploy-local": "graph deploy ianlapham/uniswap-v3 --debug --ipfs http://localhost:5001 --node http://127.0.0.1:8020",
"deploy": "graph deploy ianlapham/uniswap-v3-subgraph --ipfs https://api.thegraph.com/ipfs/ --node https://api.thegraph.com/deploy/ --debug",
Expand All @@ -24,6 +26,7 @@
"@uniswap/eslint-config": "^1.2.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^6.1.0",
"matchstick-as": "^0.6.0",
"npm-run-all": "^4.1.5",
"prettier": "^1.18.2",
"typescript": "^3.5.2"
Expand Down
19 changes: 15 additions & 4 deletions src/mappings/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,27 @@ import { fetchTokenDecimals, fetchTokenName, fetchTokenSymbol, fetchTokenTotalSu
import { ADDRESS_ZERO, FACTORY_ADDRESS, ONE_BI, ZERO_BD, ZERO_BI } from './../utils/constants'
import { WHITELIST_TOKENS } from './../utils/pricing'

// The subgraph handler must have this signature to be able to handle events,
// however, we invoke a helper in order to inject dependencies for unit tests.
export function handlePoolCreated(event: PoolCreated): void {
handlePoolCreatedHelper(event)
}

// Exported for unit tests
export function handlePoolCreatedHelper(
event: PoolCreated,
factoryAddress: string = FACTORY_ADDRESS,
whitelistTokens: string[] = WHITELIST_TOKENS,
): void {
// temp fix
if (event.params.pool == Address.fromHexString('0x8fe8d9bb8eeba3ed688069c3d6b556c9ca258248')) {
return
}

// load factory
let factory = Factory.load(FACTORY_ADDRESS)
let factory = Factory.load(factoryAddress)
if (factory === null) {
factory = new Factory(FACTORY_ADDRESS)
factory = new Factory(factoryAddress)
factory.poolCount = ZERO_BI
factory.totalVolumeETH = ZERO_BD
factory.totalVolumeUSD = ZERO_BD
Expand Down Expand Up @@ -97,12 +108,12 @@ export function handlePoolCreated(event: PoolCreated): void {
}

// update white listed pools
if (WHITELIST_TOKENS.includes(token0.id)) {
if (whitelistTokens.includes(token0.id)) {
const newPools = token1.whitelistPools
newPools.push(pool.id)
token1.whitelistPools = newPools
}
if (WHITELIST_TOKENS.includes(token1.id)) {
if (whitelistTokens.includes(token1.id)) {
const newPools = token0.whitelistPools
newPools.push(pool.id)
token0.whitelistPools = newPools
Expand Down
4 changes: 3 additions & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ export function equalToZero(value: BigDecimal): boolean {
return false
}

export const NULL_ETH_HEX_STRING = '0x0000000000000000000000000000000000000000000000000000000000000001'

export function isNullEthValue(value: string): boolean {
return value == '0x0000000000000000000000000000000000000000000000000000000000000001'
return value == NULL_ETH_HEX_STRING
}

export function bigDecimalExp18(): BigDecimal {
Expand Down
109 changes: 53 additions & 56 deletions src/utils/staticTokenDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,64 +6,61 @@ export class StaticTokenDefinition {
symbol: string
name: string
decimals: BigInt
}

// Get all tokens with a static defintion
static getStaticDefinitions(): Array<StaticTokenDefinition> {
const staticDefinitions: Array<StaticTokenDefinition> = [
{
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 {
const staticDefinitions = this.getStaticDefinitions()
const tokenAddressHex = tokenAddress.toHexString()
export const getStaticDefinition = (
tokenAddress: Address,
staticDefinitions: Array<StaticTokenDefinition>
): StaticTokenDefinition | null => {
const tokenAddressHex = tokenAddress.toHexString()

// Search the definition using the address
for (let i = 0; i < staticDefinitions.length; i++) {
const staticDefinition = staticDefinitions[i]
if (staticDefinition.address.toHexString() == tokenAddressHex) {
return staticDefinition
}
// Search the definition using the address
for (let i = 0; i < staticDefinitions.length; i++) {
const staticDefinition = staticDefinitions[i]
if (staticDefinition.address.toHexString() == tokenAddressHex) {
return staticDefinition
}

// If not found, return null
return null
}

// If not found, return null
return null
}

export const STATIC_TOKEN_DEFINITIONS: Array<StaticTokenDefinition> = [
{
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),
},
]
23 changes: 16 additions & 7 deletions src/utils/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import { ERC20 } from '../types/Factory/ERC20'
import { ERC20NameBytes } from '../types/Factory/ERC20NameBytes'
import { ERC20SymbolBytes } from '../types/Factory/ERC20SymbolBytes'
import { isNullEthValue } from '.'
import { StaticTokenDefinition } from './staticTokenDefinition'
import { getStaticDefinition, STATIC_TOKEN_DEFINITIONS, StaticTokenDefinition } from './staticTokenDefinition'

export function fetchTokenSymbol(tokenAddress: Address): string {
export function fetchTokenSymbol(
tokenAddress: Address,
staticTokenDefinitions: StaticTokenDefinition[] = STATIC_TOKEN_DEFINITIONS
): string {
const contract = ERC20.bind(tokenAddress)
const contractSymbolBytes = ERC20SymbolBytes.bind(tokenAddress)

Expand All @@ -21,7 +24,7 @@ export function fetchTokenSymbol(tokenAddress: Address): string {
symbolValue = symbolResultBytes.value.toString()
} else {
// try with the static definition
const staticTokenDefinition = StaticTokenDefinition.fromAddress(tokenAddress)
const staticTokenDefinition = getStaticDefinition(tokenAddress, staticTokenDefinitions)
if (staticTokenDefinition != null) {
symbolValue = staticTokenDefinition.symbol
}
Expand All @@ -34,7 +37,10 @@ export function fetchTokenSymbol(tokenAddress: Address): string {
return symbolValue
}

export function fetchTokenName(tokenAddress: Address): string {
export function fetchTokenName(
tokenAddress: Address,
staticTokenDefinitions: StaticTokenDefinition[] = STATIC_TOKEN_DEFINITIONS
): string {
const contract = ERC20.bind(tokenAddress)
const contractNameBytes = ERC20NameBytes.bind(tokenAddress)

Expand All @@ -49,7 +55,7 @@ export function fetchTokenName(tokenAddress: Address): string {
nameValue = nameResultBytes.value.toString()
} else {
// try with the static definition
const staticTokenDefinition = StaticTokenDefinition.fromAddress(tokenAddress)
const staticTokenDefinition = getStaticDefinition(tokenAddress, staticTokenDefinitions)
if (staticTokenDefinition != null) {
nameValue = staticTokenDefinition.name
}
Expand All @@ -72,7 +78,10 @@ export function fetchTokenTotalSupply(tokenAddress: Address): BigInt {
return totalSupplyValue
}

export function fetchTokenDecimals(tokenAddress: Address): BigInt | null {
export function fetchTokenDecimals(
tokenAddress: Address,
staticTokenDefinitions: StaticTokenDefinition[] = STATIC_TOKEN_DEFINITIONS
): BigInt | null {
const contract = ERC20.bind(tokenAddress)
// try types uint8 for decimals
const decimalResult = contract.try_decimals()
Expand All @@ -83,7 +92,7 @@ export function fetchTokenDecimals(tokenAddress: Address): BigInt | null {
}
} else {
// try with the static definition
const staticTokenDefinition = StaticTokenDefinition.fromAddress(tokenAddress)
const staticTokenDefinition = getStaticDefinition(tokenAddress, staticTokenDefinitions)
if (staticTokenDefinition) {
return staticTokenDefinition.decimals
}
Expand Down
Loading

0 comments on commit 87cfa3d

Please sign in to comment.