Last active
January 29, 2023 20:40
-
-
Save zlargon/1546fa261b450aa0b4df0adb19861515 to your computer and use it in GitHub Desktop.
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
#!/usr/bin/env node | |
const { Alchemy, Network } = require('alchemy-sdk'); | |
const ethers = require('ethers'); | |
const EthDater = require('ethereum-block-by-date'); | |
const config = { | |
apiKey: '3zNbANvcjr5yUHtnGKxXGdnX3dUYxL2X', | |
network: Network.ETH_MAINNET, | |
}; | |
const alchemy = new Alchemy(config); | |
const dater = new EthDater( | |
alchemy.core // Ethers provider, required. | |
); | |
async function delay(ms) { | |
return new Promise((resolve) => { | |
setTimeout(resolve, ms); | |
}); | |
} | |
async function getBalance(timestamp) { | |
/** | |
* Etherscan links for validation | |
* | |
* contractAddress tx filtered by tokenHolder=walletAddress | |
* https://etherscan.io/token/0xdac17f958d2ee523a2206206994597c13d831ec7?a=0x8ffa85a0c59cf23967eb31c060b2ca3a920276e1 | |
* | |
* example tx for blockNum=14305741 | |
* https://etherscan.io/tx/0x40f3b35603de4c268a065210c4a0ad143236ba36d8163e94eb2a6739fc351fa0 | |
* | |
*/ | |
// Wallet address | |
const walletAddress = '0x8ffa85a0c59Cf23967eb31C060B2ca3A920276E1'; | |
// USDT contract address | |
const contractAddress = '0xdAC17F958D2ee523a2206206994597C13D831ec7'; | |
// Get blocknumber | |
const { block: blockNum } = await dater.getDate(timestamp); | |
// ABI | |
const abi = ['function balanceOf(address account)']; | |
// Create function call data | |
const iface = new ethers.utils.Interface(abi); | |
const data = iface.encodeFunctionData('balanceOf', [walletAddress]); | |
// Get balance at a particular block -- usage of eth_call | |
const NUM_DECIMALS = 6; | |
const balance = await alchemy.core.call({ to: contractAddress, data }, blockNum); | |
return (parseInt(balance) / 10 ** NUM_DECIMALS).toFixed(2); | |
} | |
async function setBalanceAtLastHour(balances, now, hours) { | |
const timestamp = new Date(now - hours * 60 * 60 * 1000).toISOString(); | |
const RETRY_TIMES = 3; | |
for (let i = 0; i < RETRY_TIMES; i++) { | |
try { | |
const balance = await getBalance(timestamp); | |
balances[hours] = balance; | |
console.log(`Balance in last ${hours} hours: ${balance} USDT`); | |
return; | |
} catch (e) { | |
console.log(e); | |
console.log(`Retry ${i} times after 2000 ms...`); | |
await delay(2000); | |
} | |
} | |
} | |
async function main() { | |
// set Date to now | |
const now = new Date(); | |
const balances = []; | |
// get 720 timestamps starting from now, going back an hour each | |
let promises = []; | |
for (let hr = 0; hr < 720; hr++) { | |
promises.push(setBalanceAtLastHour(balances, now, hr)); | |
if (promises.length === 10) { | |
await Promise.all(promises); | |
promises = []; | |
} | |
} | |
if (promises.length > 0) { | |
await Promise.all(promises); | |
promises = []; | |
} | |
console.log(balances); | |
} | |
const runMain = async () => { | |
try { | |
await main(); | |
process.exit(0); | |
} catch (error) { | |
console.log(error); | |
process.exit(1); | |
} | |
}; | |
runMain(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment