Skip to content

Commit

Permalink
add xfai
Browse files Browse the repository at this point in the history
  • Loading branch information
notdian committed Apr 11, 2024
1 parent 6520ee1 commit b4a4c04
Show file tree
Hide file tree
Showing 10 changed files with 2,596 additions and 0 deletions.
37 changes: 37 additions & 0 deletions adapters/xfai/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "xfai",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "../dist/xfai/src/index.js",
"compile": "tsc",
"watch": "tsc -w",
"clear": "rm -rf dist"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@ethersproject/providers": "^5.7.2",
"@types/big.js": "^6.2.2",
"@types/lodash": "^4.17.0",
"@types/pg": "^8.11.5",
"big.js": "^6.2.1",
"bignumber.js": "^9.1.2",
"csv-parser": "^3.0.0",
"decimal.js-light": "^2.5.1",
"ethers": "^5.7.2",
"fast-csv": "^5.0.1",
"jsbi": "^4.3.0",
"lodash": "^4.17.21",
"pg": "^8.11.5",
"tiny-invariant": "^1.3.1",
"toformat": "^2.0.0"
},
"devDependencies": {
"@types/node": "^20.11.17",
"typescript": "^5.3.3"
}
}
9 changes: 9 additions & 0 deletions adapters/xfai/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const CHAIN_ID = 59144;
export const RPC_URL = "https://rpc.linea.build";
export const LIQUIDITY_EVENTS_DB =
"postgres://mobula_readonly:[email protected]:5432/xfai-logs?sslmode=no-verify";
export const XFAI_FACTORY = "0xa5136eAd459F0E61C99Cec70fe8F5C24cF3ecA26";
export const XFAI_POOL_INIT =
"0xd29425d309539268aa2f934062f86ea332822e787dafc6baba7cfda029630330";
export const MULTICALL = "0xca11bde05977b3631167028862be2a173976ca11";
export const WETH = "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f";
188 changes: 188 additions & 0 deletions adapters/xfai/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import { Client } from "pg";
import {
CHAIN_ID,
LIQUIDITY_EVENTS_DB,
RPC_URL,
WETH,
XFAI_FACTORY,
XFAI_POOL_INIT,
} from "./config";
import { keccak256, pack } from "@ethersproject/solidity";
import { uniq } from "lodash";
import { multicall } from "./sdk/mutlicall";
import { IXfaiPool__factory } from "./sdk/factories/IXfaiPool__factory";
import { getCreate2Address } from "ethers/lib/utils";
import { Block, StaticJsonRpcProvider } from "@ethersproject/providers";
import { format, write } from "@fast-csv/format";
import { time } from "console";
import { createWriteStream } from "fs";
function getPoolAddressFromTokenAddress(tokenAddress: string): string {
return getCreate2Address(
XFAI_FACTORY,
keccak256(["bytes"], [pack(["address"], [tokenAddress])]),
XFAI_POOL_INIT
);
}

interface BlockData {
blockNumber: number;
blockTimestamp: number;
}

type OutputDataSchemaRow = {
block_number: number;
timestamp: number;
user_address: string;
token_address: string;
token_balance: bigint;
token_symbol: string; //token symbol should be empty string if it is not available
usd_price: number; //assign 0 if not available
};

async function getDBConnection() {
const client = new Client(LIQUIDITY_EVENTS_DB);
await client.connect();
return client;
}

async function getProvider() {
const provider = new StaticJsonRpcProvider(RPC_URL, CHAIN_ID);
await provider.ready;
return provider;
}

type ChangedLiquidity = {
owner: string;
token: string;
liquidity: number;
timestamp: number;
blockNumber: bigint;
};

async function getUserTVLByBlock(
block: BlockData
): Promise<OutputDataSchemaRow[]> {
const client = await getDBConnection();
const provider = await getProvider();

const liquidities = await client.query<ChangedLiquidity>({
text: `
SELECT owner,
token,
max("blockNumber") as "blockNumber",
(max("date") / 1000) as "timestamp",
sum(liquidity) as liquidity
FROM "LiquidityTrace"
WHERE "blockNumber" <= $1
AND LOWER("token") != LOWER($2)
GROUP BY "owner", "token"
HAVING sum(liquidity) > 0;`,
values: [block.blockNumber, WETH],
});
const pgSqlShutdown = client.end();

const liquiditiesRows = liquidities.rows.map((r) => ({
...r,
pool: getPoolAddressFromTokenAddress(r.token),
liquidity: BigInt(r.liquidity),
}));

const pools: string[] = uniq(liquiditiesRows.map(({ pool }) => pool));

const poolReserves = await multicall(
provider,
IXfaiPool__factory,
pools.map((p) => ({
arguments: [],
contractAddress: p,
function_name: "getStates",
})),
{
allowFailure: false,
callOverrides: {
blockTag: block.blockNumber,
},
}
);
const poolSupplies = await multicall(
provider,
IXfaiPool__factory,
pools.map((p) => ({
arguments: [],
contractAddress: p,
function_name: "totalSupply",
})),
{
allowFailure: false,
callOverrides: {
blockTag: block.blockNumber,
},
}
);

const poolRes = Object.fromEntries(
Object.entries(poolReserves).map(([pool, [reserve, ethReserve]]) => [
pool,
{
reserve,
ethReserve,
},
])
);

const result: OutputDataSchemaRow[] = liquiditiesRows.flatMap(
({
owner,
token,
pool: poolAddress,
liquidity,
blockNumber: block_number,
timestamp,
}) => {
const poolSupply = poolSupplies[poolAddress];
const poolReserve = poolRes[poolAddress];
const tokenBalance =
(liquidity * poolReserve.reserve.toBigInt()) / poolSupply.toBigInt();
const ethBalance =
(liquidity * poolReserve.ethReserve.toBigInt()) / poolSupply.toBigInt();
return [
// Token reserve
{
block_number: Number(block_number),
timestamp,
user_address: owner,
token_address: token,
token_balance: tokenBalance,
token_symbol: "",
usd_price: 0,
},
// WETH Reserve
{
block_number: Number(block_number),
timestamp,
user_address: owner,
token_address: WETH,
token_balance: ethBalance,
token_symbol: "WETH",
usd_price: 0,
},
];
}
);
await Promise.all([pgSqlShutdown]);

return result;
}

const ws = createWriteStream("outputData.csv");

getUserTVLByBlock({ blockNumber: 1140957, blockTimestamp: 1140957 })
.then((r) => {
write(r, { headers: true })
.pipe(ws)
.on("finish", () => {
ws.close();
console.log("CSV file has been written.");
});
})
.catch((e) => console.error(e));
Loading

0 comments on commit b4a4c04

Please sign in to comment.