Skip to content

Instantly share code, notes, and snippets.

@dievardump
Last active April 9, 2023 15:05
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dievardump/4880f9763d912e3eb23527a68cc547ed to your computer and use it in GitHub Desktop.
Save dievardump/4880f9763d912e3eb23527a68cc547ed to your computer and use it in GitHub Desktop.
Get any wallet tokens for a given contract using events
function getERC20Contract(address) {
return new ethers.Contract(address, [{
anonymous: false,
inputs: [
{ indexed: true, internalType: 'address', name: 'from', type: 'address' },
{ indexed: true, internalType: 'address', name: 'to', type: 'address' },
{ indexed: false, internalType: 'uint256', name: 'amount', type: 'uint256' },
],
name: 'Transfer',
type: 'event',
}], signerOrProvider);
}
async function query(contract, filter, fromBlock, toBlock) {
console.log('querying...', fromBlock, '...', toBlock);
try {
return await contract.queryFilter(filter, fromBlock, toBlock);
} catch (e) {
const step = ~~((toBlock - fromBlock) / 2);
const middle = fromBlock + step;
return [
...(await query(contract, filter, fromBlock, middle)),
...(await query(contract, filter, middle + 1, toBlock)),
];
}
}
export async function snapshot(erc20Address = '0x4d224452801aced8b2f0aebe155379bb5d594381', address = '0xdbfd76af2157dc15ee4e57f3f942bb45ba84af24') {
const contract = getERC20Contract(nftAddress);
// you can also decide to get all Transfer events without filter, and then be able to recompose
// all wallets!
const transferToFilter = contract.filters.Transfer(undefined, address);
const transferFromFilter = contract.filters.Transfer(address);
const logs = [
...(await query(contract, transferToFilter, undefined, undefined)),
...(await query(contract, transferFromFilter, undefined, undefined)),
];
logs.sort((a, b) => {
if (a.blockNumber !== b.blockNumber) {
return a.blockNumber - b.blockNumber;
}
return a.logIndex - b.logIndex;
});
let balance = 0;
logs.forEach((log) => {
const args = log.args;
const amount = args[2].toNumber();
if (args[1].toLowerCase() == address) {
balance += amount;
} else if (args[0].toLowerCase() == address) {
balance -= amount;
}
});
return balance;
}
function getNFTContract(address) {
return new ethers.Contract(address, [{
anonymous: false,
inputs: [
{ indexed: true, internalType: 'address', name: 'from', type: 'address' },
{ indexed: true, internalType: 'address', name: 'to', type: 'address' },
{ indexed: true, internalType: 'uint256', name: 'tokenId', type: 'uint256' },
],
name: 'Transfer',
type: 'event',
}], signerOrProvider);
}
async function query(contract, filter, fromBlock, toBlock) {
console.log('querying...', fromBlock, '...', toBlock);
try {
return await contract.queryFilter(filter, fromBlock, toBlock);
} catch (e) {
const step = ~~((toBlock - fromBlock) / 2);
const middle = fromBlock + step;
return [
...(await query(contract, filter, fromBlock, middle)),
...(await query(contract, filter, middle + 1, toBlock)),
];
}
}
export async function snapshot(nftAddress = '0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d', address = '0xdbfd76af2157dc15ee4e57f3f942bb45ba84af24') {
const contract = getNFTContract(nftAddress);
const transferToFilter = contract.filters.Transfer(undefined, address);
const transferFromFilter = contract.filters.Transfer(address);
const logs = [
...(await query(contract, transferToFilter, undefined, undefined)),
...(await query(contract, transferFromFilter, undefined, undefined)),
];
logs.sort((a, b) => {
if (a.blockNumber !== b.blockNumber) {
return a.blockNumber - b.blockNumber;
}
return a.logIndex - b.logIndex;
});
const holdings = [];
logs.forEach((log) => {
const args = log.args;
const id = args[2].toNumber();
if (args[1].toLowerCase() == address) {
holdings.push(id);
} else if (args[0].toLowerCase() == address) {
holdings.splice(holdings.indexOf(id), 1);
}
});
return holdings;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment