-
Notifications
You must be signed in to change notification settings - Fork 85
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 #231 from helgaxdev/main
zkdx: fix usdc balances
- Loading branch information
Showing
5 changed files
with
2,365 additions
and
8,228 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 |
---|---|---|
@@ -1,2 +1,2 @@ | ||
number,timestamp | ||
4243360,1714773599 | ||
5941671,1719285809 |
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
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,130 @@ | ||
import {gql} from "graphql-request"; | ||
import {batchSize, EXCHANGER, graphClient, usdcContract, zusdContract} from "./utils"; | ||
|
||
const getBalanceShots = gql` | ||
query getBalanceShots($block_number: Int) { | ||
tokenBalanceShots( | ||
first: 1000 | ||
orderBy: block_number | ||
orderDirection: desc | ||
where: { | ||
block_number_lte: $block_number | ||
}) | ||
{ | ||
user_address | ||
token_address | ||
token_balance | ||
block_number | ||
} | ||
}` | ||
|
||
const getHolders = gql` | ||
query getHolders($lastId: ID) { | ||
zusdholders( | ||
first: 1000 | ||
where:{id_gt: $lastId} | ||
){ | ||
id | ||
} | ||
}` | ||
|
||
export const getBalanceMap = async (blockNumber: number) => { | ||
let balanceMap = new Map<string, Map<string, string>>(); // user => token => balance | ||
let hasNext = true; | ||
while (hasNext) { | ||
console.log(`Processing staking balances before block: ${blockNumber} ...`); | ||
let data: any = await graphClient.request(getBalanceShots, {block_number: blockNumber}); | ||
let tokenBalanceShots = data["tokenBalanceShots"]; | ||
|
||
for (let tokenBalanceShot of tokenBalanceShots) { | ||
let user_address = tokenBalanceShot["user_address"]; | ||
let token_address = tokenBalanceShot["token_address"]; | ||
let token_balance = tokenBalanceShot["token_balance"]; | ||
token_balance = BigInt(token_balance) < 0 ? BigInt(0) : BigInt(token_balance); | ||
|
||
let tokenBalance = balanceMap.get(user_address); | ||
if (tokenBalance == undefined) { | ||
let newBalance = new Map<string, string>(); | ||
newBalance.set(token_address, token_balance); | ||
balanceMap.set(user_address, newBalance); | ||
} else { | ||
let balance = tokenBalance.get(token_address); | ||
if (balance == undefined) | ||
tokenBalance.set(token_address, token_balance); | ||
} | ||
} | ||
if (tokenBalanceShots.length < 1000) { | ||
hasNext = false; | ||
} else { | ||
blockNumber = parseInt(data["tokenBalanceShots"][999]["block_number"]); | ||
} | ||
} | ||
|
||
return balanceMap; | ||
} | ||
|
||
async function getZusdHolders(): Promise<string[]> { | ||
let hasNext = true; | ||
let page = 1; | ||
let lastId = "" | ||
let holders = []; | ||
while (hasNext) { | ||
console.log(`Getting holders page: ${page} ...`); | ||
let data: any = await graphClient.request(getHolders, {lastId: lastId}); | ||
let result = data["zusdholders"]; | ||
for (let i = 0; i < result.length; i++) | ||
holders.push(result[i]["id"]); | ||
|
||
if (result.length < 1000) | ||
hasNext = false; | ||
else | ||
lastId = data["zusdholders"][999]["id"]; | ||
page++; | ||
} | ||
return holders; | ||
} | ||
|
||
|
||
|
||
export async function getExchangerBalanceMap(blockNumber: number): Promise<Map<string, string>> { | ||
|
||
let usdcBalance = await usdcContract.balanceOf(EXCHANGER, {blockTag: blockNumber}); | ||
let zusdTotal = await zusdContract.totalSupply({blockTag: blockNumber}); | ||
let holders = await getZusdHolders(); | ||
let manager = "0x709b9146219e61dc811f7a469943ada60e013475"; | ||
let managerBalance = await zusdContract.balanceOf(manager, {blockTag: blockNumber}); | ||
zusdTotal = zusdTotal.sub(managerBalance); | ||
holders = holders.filter((holder) => holder != manager && holder != "0x0000000000000000000000000000000000000000") | ||
|
||
let zusdBalances = await executeInBatches(holders, blockNumber, batchSize); | ||
|
||
const usdcBalanceMap = new Map<string, string>(); | ||
for (let i = 0; i < holders.length; i++){ | ||
try { | ||
let holder = holders[i]; | ||
let balance = zusdBalances[i]; | ||
let usdcEquivalent = usdcBalance.mul(balance).div(zusdTotal); | ||
usdcBalanceMap.set(holder, usdcEquivalent.toString()); | ||
} catch (e) { | ||
console.log("Error", e) | ||
} | ||
} | ||
return usdcBalanceMap; | ||
} | ||
|
||
async function getZusdBalance(holder: string, blockNumber: number) { | ||
return await zusdContract.balanceOf(holder, {blockTag: blockNumber}); | ||
} | ||
|
||
async function executeInBatches(holders: string[], blockNumber: number, batchSize: number) { | ||
let results: any = []; | ||
|
||
for (let i = 0; i < holders.length; i += batchSize) { | ||
console.log(`Processing exchanger balances batch, left: ${holders.length - i} ...`) | ||
const batch = holders.slice(i, i + batchSize); | ||
const batchPromises = batch.map(holder => getZusdBalance(holder, blockNumber)); | ||
const batchResults = await Promise.all(batchPromises); | ||
results = results.concat(batchResults); | ||
} | ||
return results; | ||
} |
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,24 @@ | ||
import {Contract, ethers} from "ethers"; | ||
import {GraphQLClient} from "graphql-request"; | ||
|
||
export const USDC = "0x176211869ca2b568f2a7d4ee941e073a821ee1ff"; | ||
export const WETH = "0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f"; | ||
export const EXCHANGER = "0x3a85b87e81cd99d4a6670f95a4f0dedaac207da0"; | ||
export const ZUSD = "0x2167C4D5FE05A1250588F0B8AA83A599e7732eae" | ||
|
||
export const assets: { [key: string]: string } = { | ||
"0x176211869ca2b568f2a7d4ee941e073a821ee1ff": "USDC", | ||
"0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f": "WETH", | ||
}; | ||
|
||
export const providerLinea = new ethers.providers.JsonRpcProvider("https://rpc.linea.build") | ||
export const graphClient = new GraphQLClient("https://api.studio.thegraph.com/query/47302/zkdx-graph-linea/v0.1.1") | ||
|
||
const abi = [ | ||
"function balanceOf(address account) public view returns (uint256)", | ||
"function totalSupply() public view returns (uint256)" | ||
] | ||
|
||
export const usdcContract = new Contract(USDC, abi, providerLinea); | ||
export const zusdContract = new Contract(ZUSD, abi, providerLinea); | ||
export const batchSize = 50; |
Oops, something went wrong.