Skip to content

Commit

Permalink
feat(pools): speed up cmd by only querying relevant zrc20 pools (#143)
Browse files Browse the repository at this point in the history
  • Loading branch information
fadeev authored May 30, 2024
1 parent d4407e7 commit 8cf5f61
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 58 deletions.
114 changes: 88 additions & 26 deletions packages/client/src/getPools.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,115 @@
import UniswapV2Factory from "@uniswap/v2-core/build/UniswapV2Factory.json";
import UniswapV2Pair from "@uniswap/v2-core/build/UniswapV2Pair.json";
import { getAddress, ParamChainName } from "@zetachain/protocol-contracts";
import SystemContract from "@zetachain/protocol-contracts/abi/zevm/SystemContract.sol/SystemContract.json";
import { ethers } from "ethers";

import { ZetaChainClient } from "./client";

export const getPools = async function (this: ZetaChainClient) {
const rpc = this.getEndpoint("evm", `zeta_${this.network}`);
const provider = new ethers.providers.StaticJsonRpcProvider(rpc);

const uniswapV2FactoryAddress = getAddress(
"uniswapV2Factory",
`zeta_${this.network}` as ParamChainName
);
const zetaNetwork = `zeta_${this.network}` as ParamChainName;
const uniswapV2FactoryAddress = getAddress("uniswapV2Factory", zetaNetwork);

if (!uniswapV2FactoryAddress) {
throw new Error("uniswapV2Factory is not defined");
}

const UniswapV2FactoryContract = new ethers.Contract(
uniswapV2FactoryAddress,
UniswapV2Factory.abi,
const systemContractAddress = getAddress("systemContract", zetaNetwork);
if (!systemContractAddress) {
throw new Error("System contract is not defined");
}

const systemContract = new ethers.Contract(
systemContractAddress,
SystemContract.abi,
provider
);

const totalPairs = await UniswapV2FactoryContract.allPairsLength();
let pairs = [];
for (let i = 0; i < totalPairs; i++) {
pairs.push(await UniswapV2FactoryContract.allPairs(i));
const zetaTokenAddress = getAddress("zetaToken", zetaNetwork);
if (!zetaTokenAddress) {
throw new Error("ZETA token address is not defined");
}

const poolPromises = pairs.map(async (pair: any) => {
let pool = {
pair,
t0: {},
t1: {},
} as any;
const pairContract = new ethers.Contract(pair, UniswapV2Pair.abi, provider);
const foreignCoins = await this.getForeignCoins();
const tokenAddresses = foreignCoins.map(
(coin: any) => coin.zrc20_contract_address
);
tokenAddresses.push(zetaTokenAddress);

const uniquePairs = tokenAddresses.reduce(
(pairs: any, tokenA: string, i: any) => {
tokenAddresses.slice(i + 1).forEach((tokenB: any) => {
const pairKey = [tokenA, tokenB].sort().join("-");
if (!pairs.some((p: any) => p.key === pairKey)) {
pairs.push({ key: pairKey, tokenA, tokenB });
}
});
return pairs;
},
[]
);

const poolPromises = uniquePairs.map(async ({ tokenA, tokenB }: any) => {
const pair = await systemContract.uniswapv2PairFor(
uniswapV2FactoryAddress,
tokenA,
tokenB
);

if (pair === ethers.constants.AddressZero) return null;

try {
const pairContract = new ethers.Contract(
pair,
UniswapV2Pair.abi,
provider
);
const [token0, token1] = await Promise.all([
pairContract.token0(),
pairContract.token1(),
]);
const reserves = await pairContract.getReserves();

return {
pair,
t0: { address: token0, reserve: reserves[0] },
t1: { address: token1, reserve: reserves[1] },
};
} catch (error) {
return null;
}
});

pool.t0.address = await pairContract.token0();
pool.t1.address = await pairContract.token1();
let pools = (await Promise.all(poolPromises)).filter((pool) => pool !== null);

const reserves = await pairContract.getReserves();
pool.t0.reserve = reserves[0];
pool.t1.reserve = reserves[1];
const zrc20Details = foreignCoins.reduce((acc: any, coin: any) => {
acc[coin.zrc20_contract_address.toLowerCase()] = {
decimals: coin.decimals,
symbol: coin.symbol,
};
return acc;
}, {});

return pool;
pools = pools.map((t: any) => {
const zeta = { decimals: 18, symbol: "WZETA" };
const t0 = t.t0.address.toLowerCase();
const t1 = t.t1.address.toLowerCase();
const t0ZETA = t0 === zetaTokenAddress.toLowerCase() && zeta;
const t1ZETA = t1 === zetaTokenAddress.toLowerCase() && zeta;
return {
...t,
t0: {
...t.t0,
...(zrc20Details[t0] || t0ZETA),
},
t1: {
...t.t1,
...(zrc20Details[t1] || t1ZETA),
},
};
});

const pools = await Promise.all(poolPromises);
return pools;
};
45 changes: 13 additions & 32 deletions packages/tasks/src/pools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,45 +10,26 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
network: args.mainnet ? "mainnet" : "testnet",
});

const foreignCoins = await client.getForeignCoins();
const pools = await client.getPools();

const addressToInfo = foreignCoins.reduce((acc: any, coin: any) => {
acc[coin.zrc20_contract_address.toLowerCase()] = {
decimals: coin.decimals,
symbol: coin.symbol,
};
return acc;
}, {});

const wzeta = getAddress(
"zetaToken",
`zeta_${client.network}` as ParamChainName
);
if (!wzeta) {
throw new Error("Could not find the WZETA address");
}
const WZETA_ADDRESS = wzeta.toLowerCase();
addressToInfo[WZETA_ADDRESS] = { decimals: 18, symbol: "WZETA" };

const poolsWithSymbolsAndDecimals = pools.map((pool: any) => {
const placeholder = { decimals: 18, symbol: "Unknown" };
const t0Info = addressToInfo[pool.t0.address.toLowerCase()] || placeholder;
const t1Info = addressToInfo[pool.t1.address.toLowerCase()] || placeholder;
pool.t0.reserve = formatUnits(pool.t0.reserve, t0Info.decimals);
pool.t1.reserve = formatUnits(pool.t1.reserve, t1Info.decimals);

const poolsDisplay = pools.map((pool: any) => {
return {
...pool,
t0: { ...pool.t0, ...t0Info },
t1: { ...pool.t1, ...t1Info },
t0: {
...pool.t0,
reserve: formatUnits(pool.t0.reserve, pool.t0.decimals),
},
t1: {
...pool.t1,
reserve: formatUnits(pool.t1.reserve, pool.t1.decimals),
},
};
});

const tableData = {} as any;
poolsWithSymbolsAndDecimals.forEach((pool: any) => {
const r0 = parseFloat(pool.t0.reserve).toFixed(2);
const r1 = parseFloat(pool.t1.reserve).toFixed(2);
poolsDisplay.forEach((pool: any) => {
const r0 = parseFloat(pool.t0.reserve);
const r1 = parseFloat(pool.t1.reserve);

tableData[pool.pair] = {
Pool: `${pool.t0.symbol} / ${pool.t1.symbol}`,
Expand All @@ -57,7 +38,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
});

if (args.json) {
console.log(poolsWithSymbolsAndDecimals);
console.log(pools);
} else {
console.table(tableData);
}
Expand Down

0 comments on commit 8cf5f61

Please sign in to comment.