Skip to content

Commit

Permalink
Merge pull request #100 from xsteadybcgo/main
Browse files Browse the repository at this point in the history
feat: zklink nova network adapter
  • Loading branch information
0xroll authored Jun 25, 2024
2 parents 0d02e99 + 4a8c2cc commit 3e5dfee
Show file tree
Hide file tree
Showing 76 changed files with 20,113 additions and 0 deletions.
23 changes: 23 additions & 0 deletions adapters/zklink/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## Overview
This repository is dedicated to tracking the balances of users on the zklink network, a Layer 3 (L3) network that operates with Linea as its primary chain. The contract `0x5Cb18b6e4e6F3b46Ce646b0f4704D53724C5Df05` is crucial as it locks the ETH of users engaged with the zklink nova cross-chain bridge on Linea.

## Purpose
The primary purpose of this repository is to aggregate and calculate the balance of ETH held by users in various protocols on the zklink network. It ensures that users participating in liquidity staking continue to receive corresponding credit rewards, even as their ETH is staked in different protocols.

## Components
The repository utilizes a multi-source approach to gather data:

- Subgraph: Retrieves all zklink ETH holding users and their staked balances in protocols such as aqua, layerbank, linkswap, and zkdx.
- izumi SDK: A script that fetches the staking balances of users in the izumi protocol.

These data points are then consolidated to reflect the total balance of each user.

## BlockNumber

The block number needs to be obtained from the zklink network ([zklink explorer](https://explorer.zklink.io/blocks/))






2 changes: 2 additions & 0 deletions adapters/zklink/hourly_blocks.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
number,timestamp
5954369,1719311206
36 changes: 36 additions & 0 deletions adapters/zklink/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "zklink",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "commonjs",
"scripts": {
"postinstall": "patch-package",
"start": "node dist/index.js",
"compile": "tsc",
"watch": "tsc -w",
"clear": "rm -rf dist"
},
"keywords": [],
"author": "",
"license": "UNLICENSED",
"dependencies": {
"@real-wagmi/v3-sdk": "^1.3.8",
"big.js": "^6.2.1",
"csv-parser": "^3.0.0",
"decimal.js-light": "^2.5.1",
"ethers": "^6.12.0",
"fast-csv": "^5.0.1",
"iziswap-sdk": "^1.4.11",
"patch-package": "^8.0.0",
"tiny-invariant": "^1.3.3",
"toformat": "^2.0.0",
"web3": "^4.8.0"
},
"devDependencies": {
"@tsconfig/recommended": "^1.0.6",
"@types/big.js": "^6.2.2",
"@types/node": "^20.11.17",
"typescript": "^5.3.3"
}
}
75 changes: 75 additions & 0 deletions adapters/zklink/patches/iziswap-sdk+1.4.11.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
diff --git a/node_modules/iziswap-sdk/lib/base/token/token.d.ts b/node_modules/iziswap-sdk/lib/base/token/token.d.ts
index 27292e4..0080beb 100644
--- a/node_modules/iziswap-sdk/lib/base/token/token.d.ts
+++ b/node_modules/iziswap-sdk/lib/base/token/token.d.ts
@@ -2,7 +2,7 @@ import { BaseChain, ChainId, TokenInfoFormatted } from "../types";
import { BigNumber } from 'bignumber.js';
import Web3 from "web3";
import { Contract } from 'web3-eth-contract';
-export declare const amount2Decimal: (amount: BigNumber, token: TokenInfoFormatted) => number;
+export declare const amount2Decimal: (amount: BigNumber, token: TokenInfoFormatted) => string;
export declare const decimal2Amount: (amountDecimal: number, token: TokenInfoFormatted) => BigNumber;
export declare const getErc20TokenContract: (address: string, web3: Web3) => Contract;
export declare const getContract: (abi: any, address: string, web3: Web3) => Contract;
diff --git a/node_modules/iziswap-sdk/lib/base/token/token.js b/node_modules/iziswap-sdk/lib/base/token/token.js
index 1a0330f..237aad7 100644
--- a/node_modules/iziswap-sdk/lib/base/token/token.js
+++ b/node_modules/iziswap-sdk/lib/base/token/token.js
@@ -18,7 +18,7 @@ const bignumber_js_1 = require("bignumber.js");
// const memoizeOne = require('memoize-one')
const erc20_json_1 = __importDefault(require("./erc20.json"));
const amount2Decimal = (amount, token) => {
- return Number(amount.div(Math.pow(10, token.decimal)));
+ return Number(amount.div(Math.pow(10, Number(token.decimal))));
};
exports.amount2Decimal = amount2Decimal;
const decimal2Amount = (amountDecimal, token) => {
diff --git a/node_modules/iziswap-sdk/src/base/token/token.ts b/node_modules/iziswap-sdk/src/base/token/token.ts
index 8f9d9a5..9b834aa 100644
--- a/node_modules/iziswap-sdk/src/base/token/token.ts
+++ b/node_modules/iziswap-sdk/src/base/token/token.ts
@@ -8,11 +8,11 @@ import { AbiItem } from 'web3-utils'
import abi from './erc20.json'

export const amount2Decimal = (amount: BigNumber, token: TokenInfoFormatted): number => {
- return Number(amount.div(10 ** token.decimal))
+ return Number(amount.div(10 ** Number(token.decimal)))
}

export const decimal2Amount = (amountDecimal: number, token: TokenInfoFormatted): BigNumber => {
- return new BigNumber(amountDecimal).times(10 ** token.decimal)
+ return new BigNumber(amountDecimal).times(10 ** Number(token.decimal))
}

export const getErc20TokenContract = (address: string, web3: Web3) => {
@@ -39,7 +39,7 @@ export const getContract = (abi: any, address: string, web3: Web3) => {
// return memoizedGetContract<Contract>(abi, address, web3)
// }

-export const fetchToken = async(tokenAddr: string, chain: BaseChain, web3: Web3): Promise<TokenInfoFormatted> => {
+export const fetchToken = async (tokenAddr: string, chain: BaseChain, web3: Web3): Promise<TokenInfoFormatted> => {
const contract = getContract(abi, tokenAddr, web3);
const decimal = Number(await contract.methods.decimals().call());
const symbol = await contract.methods.symbol().call();
diff --git a/node_modules/iziswap-sdk/src/base/types.ts b/node_modules/iziswap-sdk/src/base/types.ts
index c4bb9fd..1396e0e 100644
--- a/node_modules/iziswap-sdk/src/base/types.ts
+++ b/node_modules/iziswap-sdk/src/base/types.ts
@@ -13,7 +13,7 @@ export interface TokenInfoFormatted {
icon?: string;
address: string;
wrapTokenAddress?: string;
- decimal: number;
+ decimal: bigint;
addTime?: Date;
custom?: boolean;
}
@@ -1302,7 +1302,7 @@ const lookupTableReducer = (

export const initialChainTable = initialChains.reduce(lookupTableReducer, {})

-export const getChain = (chainId: ChainId):BaseChain => {
+export const getChain = (chainId: ChainId): BaseChain => {
return initialChainTable[chainId]
}

100 changes: 100 additions & 0 deletions adapters/zklink/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { getUserBalanceSnapshotAtBlock } from "./sdk/lib";
import fs from 'fs';
import csv from 'csv-parser';
import { write } from 'fast-csv';


export type OutputSchemaRow = {
block_number: number;
timestamp: number;
user_address: string;
token_address: string;
token_balance: bigint;
token_symbol?: string;
usd_price?: number;
};

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

export const getUserTVLByBlock = async (blocks: BlockData) => {
const { blockNumber, blockTimestamp } = blocks;
const snapshotBlocks: number[] = [blockNumber];

const csvRows: OutputSchemaRow[] = [];

for (const block of snapshotBlocks) {
let snapshots = await getUserBalanceSnapshotAtBlock(block);

for (const snapshot of snapshots) {
const csvRow: OutputSchemaRow = {
block_number: block,
timestamp: blockTimestamp,
user_address: snapshot.userAddress,
token_address: snapshot.tokenAddress,
token_balance: BigInt(snapshot.balance),
};
csvRows.push(csvRow);
}
}

console.log("Total rows:", csvRows.length);

return csvRows;
};

const readBlocksFromCSV = async (filePath: string): Promise<BlockData[]> => {
const blocks: BlockData[] = [];

await new Promise<void>((resolve, reject) => {
fs.createReadStream(filePath)
.pipe(csv()) // Specify the separator as '\t' for TSV files
.on('data', (row) => {

const blockNumber = parseInt(row.number, 10);
const blockTimestamp = parseInt(row.timestamp, 10);
if (!isNaN(blockNumber) && blockTimestamp) {
blocks.push({ blockNumber: blockNumber, blockTimestamp });
}
})
.on('end', () => {
resolve();
})
.on('error', (err) => {
reject(err);
});
});

return blocks;
};

readBlocksFromCSV('hourly_blocks.csv').then(async (blocks: any[]) => {
const result = await getUserTVLByBlock(blocks[0]);
const groupByTokenAddress = (rows: OutputSchemaRow[]): { [key: string]: bigint } => {
return rows.reduce((acc, row) => {
if (!acc[row.token_address]) {
acc[row.token_address] = BigInt(0);
}
acc[row.token_address] += row.token_balance;
return acc;
}, {} as { [key: string]: bigint });
};

const groupedBalances = groupByTokenAddress(result);
console.log(groupedBalances);

await new Promise((resolve) => {
const ws = fs.createWriteStream(`outputData.csv`, { flags: 'w' });
write(result, { headers: true })
.pipe(ws)
.on("finish", () => {
console.log(`CSV file has been written.`);
resolve(true);
});
});

}).catch((err) => {
console.error('Error reading CSV file:', err);
});
Loading

0 comments on commit 3e5dfee

Please sign in to comment.