Skip to main content

Analyze a Token ICO with the Transfers API: Mint, Distributor, Investors

A token sale leaves a clean trail in transfer data. The token is minted to a distributor contract, the contract sends tokens to each buyer as the sale's conditions are met, and the set of receivers is the investor list. Three Transfers queries on the combined dataset rebuild that trail for any ERC-20 sale: the mint from the zero address tells you where the supply went, transfers from that address list the buyers, and count with uniq size the sale. The worked example is the PEPU token, 0x906cc2ad139eb6637e28605f908903c8adce566a, whose sale ran in 2024; put another token contract in its place for a current one. Every query runs in the IDE on a free account.

Step 1: find where the supply was minted

A mint is a transfer from the zero address. The Receiver of the mint is the contract that distributes the sale. Saved query here.

query MyQuery {
EVM(network: eth, dataset: combined) {
Transfers(
where: {Transfer: {Currency: {SmartContract: {is: "0x906cc2ad139eb6637e28605f908903c8adce566a"}}, Success: true, Sender: {is: "0x0000000000000000000000000000000000000000"}}}
) {
Transfer {
Amount
Currency {
Name
Symbol
SmartContract
}
Receiver
Sender
}
}
}
}

For PEPU the mint went to 0xf0163c18f8d3fc8d5b4ca15e07d0f9f75460335f, the distributor used in the next two queries.

Step 2: list the buyers

Every transfer sent by the distributor is a delivery to a buyer. The Receiver column is the investor list, with the amount each one received. Saved query here.

query MyQuery {
EVM(network: eth, dataset: combined) {
Transfers(
where: {Transfer: {Currency: {SmartContract: {is: "0x906cc2ad139eb6637e28605f908903c8adce566a"}}, Success: true, Sender: {is: "0xf0163c18f8d3fc8d5b4ca15e07d0f9f75460335f"}}}
) {
Transfer {
Amount
Currency {
Name
Symbol
SmartContract
}
Receiver
Sender
}
count
}
}
}

Step 3: size the sale

The same filter with count and uniq gives the number of deliveries and the number of distinct buyers in one row. Saved query here.

query MyQuery {
EVM(network: eth, dataset: combined) {
Transfers(
where: {Transfer: {Amount: {gt: "0"}, Currency: {SmartContract: {is: "0x906cc2ad139eb6637e28605f908903c8adce566a"}}, Sender: {is: "0xf0163c18f8d3fc8d5b4ca15e07d0f9f75460335f"}}}
) {
count
buyers: uniq(of: Transfer_Receiver)
Transfer {
Currency {
Name
Symbol
SmartContract
}
}
}
}
}

Where to go from here

  • Did buyers hold or sell? Run the Balances and Holders cubes on the buyer list, or filter DEXTrades on the token to see the first sells.
  • What did the sale raise? The ETH or stablecoin transfers into the distributor, or the Calls into it with Value, give the other side of each purchase.
  • Watching a live sale: change query to subscription, drop the dataset argument, and keep the distributor as Sender to see each delivery as it happens.

Video tutorial on analyzing the PEPU sale

Frequently Asked Questions

How do I find the addresses that bought a token in its ICO?

Find the mint (a transfer from the zero address) to get the distributor contract, then list transfers sent by that contract on the combined dataset. The receivers are the buyers and the amounts are what each received.

How do I count unique ICO participants?

Use count and uniq(of: Transfer_Receiver) on the transfers sent by the distributor. count is deliveries, uniq is distinct buyers, since one address can buy several times.

Why use dataset combined?

A sale is usually weeks or months old. The realtime window holds only recent hours, while combined reaches back through the archive and includes the latest rows.

Can I do this for a token on BSC or Base?

Yes. Change the network name in EVM(network: ...). The Transfers cube has the same fields on every EVM chain Bitquery indexes.

Build with Bitquery

Ready to run this in production?

Get an API key and run these queries in minutes, or talk to us about plans and enterprise delivery.