Docs · Tools

Nobody gets quietly skipped.

One token, many recipients, from a list you paste or a file you upload. The whole tool is built around a single refusal: a line that cannot be read stops the send rather than disappearing from it.

Why that refusal is the whole design#

An airdrop that quietly drops one malformed row succeeds, reports a plausible total, and leaves one person unpaid with nothing anywhere saying so. The total still adds up, because it is computed from the rows that survived. Nobody audits what adds up.

So every rejected line comes back with its line number and its original text, and the send button stays disabled until the list has none. There is no “send anyway”.

What a list can look like#

text

0x21c9a94AF76B59b171b32fD125A4edF0e9A2Ad3e,1.5
haxixe.eth,10
0x96C37393B79aD7EABdF9Ccf82C2EDAd3d3c0eEA2;2,5

# a comment, and the blank line above, are both fine
0x8Bf5941d27176242745B716251943Ae4892a3C26	0.001

The separator is detected per line, because a comma cannot be both the column separator and the decimal point on the same line. A tab or a semicolon wins where present, which makes the comma a decimal — so addr;2,5 is two and a half. Where the line offers nothing else, addr,1,5 is ambiguous and is refused with the fix named (“write it as 1.5”) rather than with a cell count.

  • ENS names are accepted and resolved; the address each one became is shown beside it.
  • A header row is skipped. A first line that is a real payment is never mistaken for one.
  • Comments and blank lines are structure, not mistakes, and survive editing.
  • Repeated recipients warn and never block — a person can legitimately be in two cohorts, and deciding otherwise would be deciding about your money for you.

What stops a send#

BlocksWhy
A line that could not be readSending would skip that recipient in silence
More decimal places than the token hasparseUnits truncates rather than throwing — 1.234567 at 2 decimals becomes 1.23, and the total still looks right
An amount that rounds to zeroA transfer of nothing is not a payment
A name that does not resolveDistinct from a lookup that failed, which says so separately
A total larger than your balanceThe run would stop midway, paying the early rows and not the late ones
A transfer that simulates as a revertIt is going to fail; better here than after a signature

A check that could not run is not a check that passed

Every transfer is simulated first, and the simulation has three outcomes, not two: it will work, it will revert, or we could not tell. The third is shown as itself. A transfer that could not be checked riding inside a batch reported as verified is the same failure as a dropped row, one layer up.

Amounts are read from the text, never from the number#

The figure shown as a total is a float, and floats are for showing people numbers: 0.1 + 0.2 is 0.30000000000000004. What actually moves is converted from the string you typed, at the token’s real precision, which is why a token whose decimals cannot be read blocks the send instead of defaulting to 18.

The same rule governs Divide equally. Ten split three ways at two decimals is 3.33 each — which is 9.99. The shares are computed in integer base units and the remainder goes to the first row, so they sum to exactly what you asked for.

Signing, and what happens if you stop#

Transfers are grouped into batches of up to 50, one signature each. Beyond that wallets start refusing or estimating badly, and a batch that dies at the wallet is worse than two that do not.

If a batch fails or you reject a signature, the run stops and the screen says which batch it stopped at and how many recipients are still unpaid. A summary that only counts what was sent is how somebody comes to believe everyone was paid.

Keeping the record#

Export plan writes the resolved plan, not a copy of what you pasted: the address each name became, the amount in human and base units, and the batch each row lands in. Those are the two things that cannot be reconstructed afterwards from the list you typed.

text

line,recipient,resolved_address,amount,base_units,batch
1,0x21c9…Ad3e,0x21c9…Ad3e,1.5,1500000,1
2,haxixe.eth,0x21c9…Ad3e,10,10000000,1
7,ghost.eth,,,,NOT SENT: ghost.eth does not resolve to an address

Rows that will not be sent are in the same file, marked, for the same reason as everything else here.

Networks#

The network is chosen on the page, not inherited from whatever your wallet is on — the same contract address is a different token on every chain, so that is the question the token field depends on. Reading a token needs no wallet at all: you can prepare the whole list before connecting anything, and the wallet is switched at send time.

Available on Base, Ethereum, Optimism, Arbitrum, Robinhood.

One path has never been exercised

When a wallet does not support atomic batching, the sender falls back to submitting the calls one after another. That fallback has never run with airdrop-shaped calls — many transfers to many recipients, rather than many tokens to one. It is recorded as untested rather than quietly assumed to work. See the tool and try a small list first.