-
Notifications
You must be signed in to change notification settings - Fork 87
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #100 from xsteadybcgo/main
feat: zklink nova network adapter
- Loading branch information
Showing
76 changed files
with
20,113 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/)) | ||
|
||
|
||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
number,timestamp | ||
5954369,1719311206 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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] | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
}); |
Oops, something went wrong.