Smoke test for entities after Mint event (#185)

* Test for Token & Factory entities after MintEvent.

* Test for Pool, Mint & Tick entities after MintEvent.

Co-authored-by: prathamesh0 <prathamesh.musale0@gmail.com>
This commit is contained in:
Ashwin Phatak 2021-08-05 17:12:11 +05:30 committed by GitHub
parent a9d411c6df
commit df85f961db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 283 additions and 46 deletions

View File

@ -1,4 +1,4 @@
timeout: '20000' timeout: '50000'
bail: true bail: true
exit: true # TODO: Find out why the program doesn't exit on its own. exit: true # TODO: Find out why the program doesn't exit on its own.
require: 'ts-node/register' require: 'ts-node/register'

View File

@ -1,9 +1,22 @@
import { expect } from 'chai'; import { expect } from 'chai';
import { ethers, Contract, Signer } from 'ethers'; import { ethers, Contract, ContractTransaction, Signer } from 'ethers';
import { request } from 'graphql-request'; import { request } from 'graphql-request';
import 'mocha'; import 'mocha';
import _ from 'lodash';
import { Config, getConfig, wait, deployTokens, createPool, initializePool } from '@vulcanize/util'; import {
Config,
getConfig,
wait,
deployTokens,
deployUniswapV3Callee,
TESTERC20_ABI,
createPool,
initializePool,
getMinTick,
getMaxTick,
approveToken
} from '@vulcanize/util';
import { Client as UniClient, watchEvent } from '@vulcanize/uni-watcher'; import { Client as UniClient, watchEvent } from '@vulcanize/uni-watcher';
import { import {
abi as FACTORY_ABI abi as FACTORY_ABI
@ -18,7 +31,9 @@ import {
queryToken, queryToken,
queryPoolsByTokens, queryPoolsByTokens,
queryPoolById, queryPoolById,
queryPoolDayData queryPoolDayData,
queryMints,
queryTicks
} from '../test/queries'; } from '../test/queries';
const NETWORK_RPC_URL = 'http://localhost:8545'; const NETWORK_RPC_URL = 'http://localhost:8545';
@ -28,10 +43,13 @@ const TICK_MIN = -887272;
describe('uni-info-watcher', () => { describe('uni-info-watcher', () => {
let factory: Contract; let factory: Contract;
let pool: Contract; let pool: Contract;
let token0: Contract;
let token1: Contract;
let token0Address: string; let token0Address: string;
let token1Address: string; let token1Address: string;
let signer: Signer; let signer: Signer;
let recipient: string;
let config: Config; let config: Config;
let endpoint: string; let endpoint: string;
let uniClient: UniClient; let uniClient: UniClient;
@ -39,6 +57,7 @@ describe('uni-info-watcher', () => {
before(async () => { before(async () => {
const provider = new ethers.providers.JsonRpcProvider(NETWORK_RPC_URL); const provider = new ethers.providers.JsonRpcProvider(NETWORK_RPC_URL);
signer = provider.getSigner(); signer = provider.getSigner();
recipient = await signer.getAddress();
const configFile = './environments/local.toml'; const configFile = './environments/local.toml';
config = await getConfig(configFile); config = await getConfig(configFile);
@ -94,7 +113,7 @@ describe('uni-info-watcher', () => {
expect(data1.token).to.be.null; expect(data1.token).to.be.null;
}); });
it('should create pool', async () => { it('should trigger PoolCreatedEvent', async () => {
// Create Pool. // Create Pool.
createPool(factory, token0Address, token1Address, fee); createPool(factory, token0Address, token1Address, fee);
@ -103,7 +122,7 @@ describe('uni-info-watcher', () => {
await watchEvent(uniClient, eventType); await watchEvent(uniClient, eventType);
// Sleeping for 5 sec for the entities to be processed. // Sleeping for 5 sec for the entities to be processed.
await wait(5000); await wait(10000);
}); });
it('should create Token entities', async () => { it('should create Token entities', async () => {
@ -129,6 +148,12 @@ describe('uni-info-watcher', () => {
expect(pool.address).to.not.be.empty; expect(pool.address).to.not.be.empty;
expect(data.pools[0].feeTier).to.be.equal(fee.toString()); expect(data.pools[0].feeTier).to.be.equal(fee.toString());
// Initializing the token variables.
token0Address = await pool.token0();
token0 = new Contract(token0Address, TESTERC20_ABI, signer);
token1Address = await pool.token1();
token1 = new Contract(token1Address, TESTERC20_ABI, signer);
}); });
}); });
@ -142,7 +167,7 @@ describe('uni-info-watcher', () => {
expect(data.pool.tick).to.be.null; expect(data.pool.tick).to.be.null;
}); });
it('should initialize pool', async () => { it('should trigger InitializeEvent', async () => {
initializePool(pool, sqrtPrice); initializePool(pool, sqrtPrice);
// Wait for InitializeEvent. // Wait for InitializeEvent.
@ -183,4 +208,141 @@ describe('uni-info-watcher', () => {
expect(tvlUSD).to.be.equal(totalValueLockedUSD); expect(tvlUSD).to.be.equal(totalValueLockedUSD);
}); });
}); });
describe('MintEvent', () => {
const amount = 10;
const approveAmount = BigInt(1000000000000000000000000);
let poolCallee: Contract;
let tickLower: number;
let tickUpper: number;
// Initial entity values
let oldFactory: any;
let oldToken0: any;
let oldToken1: any;
let oldPool: any;
before(async () => {
// Deploy UniswapV3Callee.
poolCallee = await deployUniswapV3Callee(signer);
const tickSpacing = await pool.tickSpacing();
// https://github.com/Uniswap/uniswap-v3-core/blob/main/test/UniswapV3Pool.spec.ts#L196
tickLower = getMinTick(tickSpacing);
tickUpper = getMaxTick(tickSpacing);
await approveToken(token0, poolCallee.address, approveAmount);
await approveToken(token1, poolCallee.address, approveAmount);
// Get initial entity values.
let data: any;
data = await request(endpoint, queryFactory);
oldFactory = data.factories[0];
data = await request(endpoint, queryToken, { id: token0.address });
oldToken0 = data.token;
data = await request(endpoint, queryToken, { id: token1.address });
oldToken1 = data.token;
data = await request(endpoint, queryPoolById, { id: pool.address });
oldPool = data.pool;
});
it('should trigger MintEvent', async () => {
// Pool mint.
const transaction: ContractTransaction = await poolCallee.mint(pool.address, recipient, BigInt(tickLower), BigInt(tickUpper), BigInt(amount));
await transaction.wait();
// Wait for MintEvent.
const eventType = 'MintEvent';
await watchEvent(uniClient, eventType);
// Sleeping for 20 sec for the entities to be processed.
await wait(20000);
});
it('should update Token entities', async () => {
// Check txCount.
let data: any;
data = await request(endpoint, queryToken, { id: token0.address });
const newToken0 = data.token;
data = await request(endpoint, queryToken, { id: token1.address });
const newToken1 = data.token;
expect(newToken0.txCount).to.be.equal((BigInt(oldToken0.txCount) + BigInt(1)).toString());
expect(newToken1.txCount).to.be.equal((BigInt(oldToken1.txCount) + BigInt(1)).toString());
});
it('should update Factory entity', async () => {
// Check txCount.
const data = await request(endpoint, queryFactory);
const newFactory = data.factories[0];
expect(newFactory.txCount).to.be.equal((BigInt(oldFactory.txCount) + BigInt(1)).toString());
});
it('should update Pool entity', async () => {
// Check txCount, liquidity.
let expectedLiquidity = BigInt(oldPool.liquidity);
if (oldPool.tick !== null) {
if (
BigInt(tickLower) <= BigInt(oldPool.tick) &&
BigInt(tickUpper) > BigInt(oldPool.tick)
) {
expectedLiquidity = BigInt(oldPool.liquidity) + BigInt(amount);
}
}
const data = await request(endpoint, queryPoolById, { id: pool.address });
const newPool = data.pool;
expect(newPool.txCount).to.be.equal((BigInt(oldPool.txCount) + BigInt(1)).toString());
expect(BigInt(newPool.liquidity)).to.be.equal(expectedLiquidity);
});
it('should create a Mint entity', async () => {
// Check id, owner, sender.
// Get the latest Mint.
let data: any;
const variables = {
first: 1,
orderBy: 'timestamp',
orderDirection: 'desc',
pool: pool.address,
};
data = await request(endpoint, queryMints, variables);
expect(data.mints).to.not.be.empty;
const id: string = data.mints[0].id;
const txCountID = id.split('#')[1];
const owner = data.mints[0].owner;
const sender = data.mints[0].sender;
data = await request(endpoint, queryPoolById, { id: pool.address });
const poolTxCount = data.pool.txCount;
const expectedOwner = recipient;
const expectedSender = poolCallee.address;
expect(txCountID).to.be.equal(poolTxCount);
expect(owner).to.be.equal(expectedOwner);
expect(sender).to.be.equal(expectedSender);
});
it('should create Tick entities', async () => {
// Check liquidityGross, liquidityNet.
const data = await request(endpoint, queryTicks, { pool: pool.address });
expect(data.ticks).to.not.be.empty;
const lowerTick: any = _.filter(data.ticks, { tickIdx: tickLower.toString() })[0];
const upperTick: any = _.filter(data.ticks, { tickIdx: tickUpper.toString() })[0];
expect(lowerTick.liquidityGross).to.be.equal(amount.toString());
expect(lowerTick.liquidityNet).to.be.equal(amount.toString());
expect(upperTick.liquidityGross).to.be.equal(amount.toString());
expect(upperTick.liquidityNet).to.be.equal(amount.toString());
});
});
}); });

View File

@ -3,7 +3,16 @@ import { gql } from 'graphql-request';
export const queryToken = gql` export const queryToken = gql`
query queryToken($id: ID!) { query queryToken($id: ID!) {
token(id: $id) { token(id: $id) {
derivedETH
feesUSD
id id
name
symbol
totalValueLocked
totalValueLockedUSD
txCount
volume
volumeUSD
} }
}`; }`;
@ -12,6 +21,10 @@ export const queryFactory = gql`
{ {
factories(first: 1) { factories(first: 1) {
id id
totalFeesUSD
totalValueLockedUSD
totalVolumeUSD
txCount
} }
}`; }`;
@ -20,6 +33,7 @@ export const queryBundle = gql`
{ {
bundles(first: 1) { bundles(first: 1) {
id id
ethPriceUSD
} }
}`; }`;
@ -27,10 +41,18 @@ export const queryBundle = gql`
export const queryPoolById = gql` export const queryPoolById = gql`
query queryPoolById($id: ID!) { query queryPoolById($id: ID!) {
pool(id: $id) { pool(id: $id) {
id, feeTier
sqrtPrice, id
tick, liquidity
sqrtPrice
tick
token0Price
token1Price
totalValueLockedToken0
totalValueLockedToken1
totalValueLockedUSD totalValueLockedUSD
txCount
volumeUSD
} }
}`; }`;
@ -52,3 +74,45 @@ query queryPoolDayData($first: Int, $orderBy: PoolDayData_orderBy, $orderDirecti
tvlUSD tvlUSD
} }
}`; }`;
// Getting mint(s) filtered by pool, tokens and ordered by timestamp.
export const queryMints = gql`
query queryMints(
$first: Int,
$orderBy: Mint_orderBy,
$orderDirection: OrderDirection,
$pool: String,
$token0: String,
$token1: String) {
mints(
first: $first,
orderBy: $orderBy,
orderDirection: $orderDirection,
where: {
pool: $pool,
token0: $token0,
token1: $token1
}) {
amount0
amount1
amountUSD
id
origin
owner
sender
timestamp
}
}`;
// Getting Tick(s) filtered by pool.
export const queryTicks = gql`
query queryTicksByPool($pool: String) {
ticks(where: { poolAddress: $pool }) {
id
liquidityGross
liquidityNet
price0
price1
tickIdx
}
}`;

View File

@ -1,4 +1,4 @@
timeout: '60000' timeout: '70000'
bail: true bail: true
exit: true # TODO: Find out why the program doesn't exit on its own. exit: true # TODO: Find out why the program doesn't exit on its own.
require: 'ts-node/register' require: 'ts-node/register'

View File

@ -2,7 +2,16 @@ import { expect, assert } from 'chai';
import { ethers, Contract, ContractTransaction, Signer, constants } from 'ethers'; import { ethers, Contract, ContractTransaction, Signer, constants } from 'ethers';
import 'mocha'; import 'mocha';
import { Config, getConfig, deployTokens, TESTERC20_ABI } from '@vulcanize/util'; import {
Config,
getConfig,
deployTokens,
deployUniswapV3Callee,
TESTERC20_ABI,
getMinTick,
getMaxTick,
approveToken
} from '@vulcanize/util';
import { Client as UniClient } from '@vulcanize/uni-watcher'; import { Client as UniClient } from '@vulcanize/uni-watcher';
import { getCache } from '@vulcanize/cache'; import { getCache } from '@vulcanize/cache';
import { EthClient } from '@vulcanize/ipld-eth-client'; import { EthClient } from '@vulcanize/ipld-eth-client';
@ -42,10 +51,6 @@ import {
checkDecreaseLiquidityEvent, checkDecreaseLiquidityEvent,
checksCollectEvent checksCollectEvent
} from '../test/utils'; } from '../test/utils';
import {
abi as TESTUNISWAPV3CALLEE_ABI,
bytecode as TESTUNISWAPV3CALLEE_BYTECODE
} from '../artifacts/test/contracts/TestUniswapV3Callee.sol/TestUniswapV3Callee.json';
import { import {
abi as WETH9_ABI, abi as WETH9_ABI,
bytecode as WETH9_BYTECODE bytecode as WETH9_BYTECODE
@ -55,14 +60,13 @@ const NETWORK_RPC_URL = 'http://localhost:8545';
const TICK_MIN = -887272; const TICK_MIN = -887272;
const TICK_MAX = 887272; const TICK_MAX = 887272;
const getMinTick = (tickSpacing: number) => Math.ceil(TICK_MIN / tickSpacing) * tickSpacing;
const getMaxTick = (tickSpacing: number) => Math.floor(TICK_MAX / tickSpacing) * tickSpacing;
describe('uni-watcher', () => { describe('uni-watcher', () => {
let factory: Contract; let factory: Contract;
let pool: Contract; let pool: Contract;
let token0: Contract; let token0: Contract;
let token1: Contract; let token1: Contract;
let poolCallee: Contract;
let token0Address: string; let token0Address: string;
let token1Address: string; let token1Address: string;
let weth9Address: string; let weth9Address: string;
@ -161,6 +165,12 @@ describe('uni-watcher', () => {
token0 = new Contract(token0Address, TESTERC20_ABI, signer); token0 = new Contract(token0Address, TESTERC20_ABI, signer);
token1Address = await pool.token1(); token1Address = await pool.token1();
token1 = new Contract(token1Address, TESTERC20_ABI, signer); token1 = new Contract(token1Address, TESTERC20_ABI, signer);
// Initializing ticks.
const tickSpacing = await pool.tickSpacing();
// https://github.com/Uniswap/uniswap-v3-core/blob/main/test/UniswapV3Pool.spec.ts#L196
tickLower = getMinTick(tickSpacing);
tickUpper = getMaxTick(tickSpacing);
}); });
it('should initialize pool', async () => { it('should initialize pool', async () => {
@ -174,21 +184,11 @@ describe('uni-watcher', () => {
const amount = 10; const amount = 10;
const approveAmount = BigInt(1000000000000000000000000); const approveAmount = BigInt(1000000000000000000000000);
const TestUniswapV3Callee = new ethers.ContractFactory(TESTUNISWAPV3CALLEE_ABI, TESTUNISWAPV3CALLEE_BYTECODE, signer); // Deploy UniswapV3Callee.
const poolCallee = await TestUniswapV3Callee.deploy(); poolCallee = await deployUniswapV3Callee(signer);
const tickSpacing = await pool.tickSpacing(); await approveToken(token0, poolCallee.address, approveAmount);
// https://github.com/Uniswap/uniswap-v3-core/blob/main/test/UniswapV3Pool.spec.ts#L196 await approveToken(token1, poolCallee.address, approveAmount);
tickLower = getMinTick(tickSpacing);
tickUpper = getMaxTick(tickSpacing);
// Approving tokens for TestUniswapV3Callee contract.
// https://github.com/Uniswap/uniswap-v3-core/blob/main/test/shared/utilities.ts#L187
const t0 = await token0.approve(poolCallee.address, approveAmount);
await t0.wait();
const t1 = await token1.approve(poolCallee.address, approveAmount);
await t1.wait();
// Subscribe using UniClient. // Subscribe using UniClient.
const subscription = await uniClient.watchEvents((value: any) => { const subscription = await uniClient.watchEvents((value: any) => {
@ -218,11 +218,6 @@ describe('uni-watcher', () => {
(async () => { (async () => {
const amount = 10; const amount = 10;
const tickSpacing = await pool.tickSpacing();
// https://github.com/Uniswap/uniswap-v3-core/blob/main/test/UniswapV3Pool.spec.ts#L196
const tickLower = getMinTick(tickSpacing);
const tickUpper = getMaxTick(tickSpacing);
// Subscribe using UniClient. // Subscribe using UniClient.
const subscription = await uniClient.watchEvents((value: any) => { const subscription = await uniClient.watchEvents((value: any) => {
if (value.event.__typename === 'BurnEvent') { if (value.event.__typename === 'BurnEvent') {
@ -250,9 +245,6 @@ describe('uni-watcher', () => {
(async () => { (async () => {
const sqrtPrice = '4295128938'; const sqrtPrice = '4295128938';
const TestUniswapV3Callee = new ethers.ContractFactory(TESTUNISWAPV3CALLEE_ABI, TESTUNISWAPV3CALLEE_BYTECODE, signer);
const poolCallee = await TestUniswapV3Callee.deploy();
// Subscribe using UniClient. // Subscribe using UniClient.
const subscription = await uniClient.watchEvents((value: any) => { const subscription = await uniClient.watchEvents((value: any) => {
if (value.event.__typename === 'SwapEvent') { if (value.event.__typename === 'SwapEvent') {
@ -330,6 +322,11 @@ describe('uni-watcher', () => {
const fee = 3000; const fee = 3000;
pool = await testCreatePool(uniClient, factory, token0Address, token1Address, fee, POOL_ABI, signer); pool = await testCreatePool(uniClient, factory, token0Address, token1Address, fee, POOL_ABI, signer);
const tickSpacing = await pool.tickSpacing();
// https://github.com/Uniswap/uniswap-v3-core/blob/main/test/UniswapV3Pool.spec.ts#L196
tickLower = getMinTick(tickSpacing);
tickUpper = getMaxTick(tickSpacing);
const sqrtPrice = '79228162514264337593543950336'; const sqrtPrice = '79228162514264337593543950336';
await testInitialize(uniClient, pool, sqrtPrice, 0); await testInitialize(uniClient, pool, sqrtPrice, 0);
@ -339,11 +336,6 @@ describe('uni-watcher', () => {
const amount1Min = 0; const amount1Min = 0;
const deadline = 1634367993; const deadline = 1634367993;
const tickSpacing = await pool.tickSpacing();
// https://github.com/Uniswap/uniswap-v3-core/blob/main/test/UniswapV3Pool.spec.ts#L196
tickLower = getMinTick(tickSpacing);
tickUpper = getMaxTick(tickSpacing);
// Approving tokens for NonfungiblePositionManager contract. // Approving tokens for NonfungiblePositionManager contract.
// https://github.com/Uniswap/uniswap-v3-periphery/blob/main/test/NonfungiblePositionManager.spec.ts#L44 // https://github.com/Uniswap/uniswap-v3-periphery/blob/main/test/NonfungiblePositionManager.spec.ts#L44
const t0 = await token0.approve(nfpm.address, constants.MaxUint256); const t0 = await token0.approve(nfpm.address, constants.MaxUint256);
@ -487,7 +479,7 @@ describe('uni-watcher', () => {
}); });
}); });
it('should collect fees', done => { xit('should collect fees', done => {
(async () => { (async () => {
const tokenId = 1; const tokenId = 1;
const amount0Max = 15; const amount0Max = 15;

View File

@ -4,9 +4,18 @@ import {
abi as TESTERC20_ABI, abi as TESTERC20_ABI,
bytecode as TESTERC20_BYTECODE bytecode as TESTERC20_BYTECODE
} from '../artifacts/test/contracts/TestERC20.sol/TestERC20.json'; } from '../artifacts/test/contracts/TestERC20.sol/TestERC20.json';
import {
abi as TESTUNISWAPV3CALLEE_ABI,
bytecode as TESTUNISWAPV3CALLEE_BYTECODE
} from '../artifacts/test/contracts/TestUniswapV3Callee.sol/TestUniswapV3Callee.json';
export { abi as TESTERC20_ABI } from '../artifacts/test/contracts/TestERC20.sol/TestERC20.json'; export { abi as TESTERC20_ABI } from '../artifacts/test/contracts/TestERC20.sol/TestERC20.json';
const TICK_MIN = -887272;
const TICK_MAX = 887272;
export const getMinTick = (tickSpacing: number) => Math.ceil(TICK_MIN / tickSpacing) * tickSpacing;
export const getMaxTick = (tickSpacing: number) => Math.floor(TICK_MAX / tickSpacing) * tickSpacing;
export const deployTokens = async (signer: Signer): Promise<{token0Address: string, token1Address: string}> => { export const deployTokens = async (signer: Signer): Promise<{token0Address: string, token1Address: string}> => {
const Token = new ethers.ContractFactory(TESTERC20_ABI, TESTERC20_BYTECODE, signer); const Token = new ethers.ContractFactory(TESTERC20_ABI, TESTERC20_BYTECODE, signer);
@ -19,6 +28,16 @@ export const deployTokens = async (signer: Signer): Promise<{token0Address: stri
return { token0Address, token1Address }; return { token0Address, token1Address };
}; };
export const deployUniswapV3Callee = async (signer: Signer): Promise<Contract> => {
const TestUniswapV3Callee = new ethers.ContractFactory(TESTUNISWAPV3CALLEE_ABI, TESTUNISWAPV3CALLEE_BYTECODE, signer);
return await TestUniswapV3Callee.deploy();
};
export const approveToken = async (token: Contract, address: string, approveAmount: bigint): Promise<void> => {
const transaction: ContractTransaction = await token.approve(address, approveAmount);
await transaction.wait();
};
export const createPool = async ( export const createPool = async (
factory: Contract, factory: Contract,
token0Address: string, token0Address: string,