Paying 500 wallets at once: what actually breaks
Batch payouts fail in boring, expensive ways: gas limits, one bad address, silent partial sends. What breaks, with the per-network limits we measured.
Paying one person on-chain is trivial. Paying five hundred is a different job, and the ways it goes wrong are rarely dramatic: no hacks, no exploits. It is a transaction too big for the network to accept, a spreadsheet with one bad address, or a batch that half-succeeded and left you reconciling by hand at midnight.
Here is what actually breaks, in the order you will meet it.
Your batch does not fit in one transaction
Every chain caps how much gas one transaction may use, and a batch is one transaction. On Ethereum, Base, Optimism and BNB Chain that cap is about 16.8 million gas. Polygon allows twice as much, and on HyperEVM the limit is the ordinary block of 3 million gas. Add recipients and you eventually cross the line: the transaction is valid, the list is fine, and the network still refuses it.
The limit is not a round number, and it is different per chain and per asset. These are the ceilings we enforce. We measured the gas against our live contract on every network in July 2026 and set each limit a little below the measured maximum:
| Network | Native coin | Token (USDC, USDT…) |
|---|---|---|
| Ethereum, Base, Optimism, BNB | 440 | 546 |
| Arbitrum | 845 | 870 |
| Polygon | 880 | 900 |
| HyperEVM | 60 | 73 |
Two things surprise people here. First, tokens are cheaper than the native coin: inside a batch, a token transfer costs less gas than sending the chain’s own currency, so the token ceiling is higher. Second, Arbitrum and Polygon are not “the same as Ethereum”: one transaction there may use about twice as much gas. A run of 800 people that takes two transactions on Ethereum goes out as one there.
If a tool lets you paste 1,000 rows without saying a word about this, it is going to fail at signing time, after you have already done the work. Cherum Send splits a long list into batches for you and shows how many signatures it will take before you sign.
One bad address takes the whole batch with it
A batch is atomic by default: if any transfer inside it reverts, everything reverts. That is the right behaviour — you do not want 300 of 500 people paid and no record of which — but it means a single typo, a contract address that rejects transfers, or a recipient that is a contract without a payable fallback, kills the run.
The fix is not clever code, it is checking before you sign: validate every row, flag duplicates, and show the total in the same units the wallet will show. Anything you discover after signing costs gas.
The quiet one: partial cross-chain delivery
A batch in one token on one network is all-or-nothing. A cross-chain batch is all-or-nothing only in the transaction you sign, which hands every transfer to its bridge or none of them. After that, each network gets its own transfer through its own bridge, and they arrive at different times. A tool that reports “sent” the moment the source transaction confirms is telling you about the easy half.
What you want to see instead: a status for each network’s transfer, and for any transfer that cannot be delivered, where its money is and who sends it back. If you cannot answer “which two of my twelve recipients have not received anything yet” from the interface, you will answer it from a block explorer.
Fees you only notice next month
Two costs hide in batch payouts.
The first is gas, and a batch saves less of it than people expect. Per recipient, a batch still pays for every transfer it makes. For a wallet that has never received anything, our measurements put it at about 36,000 gas in the native coin, more than the 21,000 a plain transfer costs. What a batch really saves is signing: 500 transfers one by one mean 500 wallet confirmations, while the same list as a batch takes one or two on most networks, and up to nine on HyperEVM, where blocks are small. When you pay in a token, your wallet may also ask you to approve the token first.
The second is the exchange rate. If you hold USDC and pay in the chain’s native coin, or the other way round, someone converts, and the spread on that conversion is often larger than every gas fee in the run. Ask what rate you are getting, not just what fee is charged.
Custody: the question nobody asks until it matters
Most “payout automation” quietly means one thing: you give a service the ability to move your money, and it does so on a schedule. That works right up until the day it doesn’t — a compromised key, a frozen account, a company that changes its terms.
The alternative is not worse automation, it is a different split of duties: the tool prepares the batch, validates it, computes the totals, and then a human signs. You keep the keys; the machine does the boring part. Scheduling still works — the difference is that at the appointed hour you have a batch ready to sign, not a transfer that already happened without you.
We built Payouts in the Cherum app this way on purpose, and it is why its scheduler never signs anything: it prepares a draft and waits. Our API also has payout endpoints, and those are custodial: they pay out of a balance we hold for you, and we switch them on per account on request.
A short checklist before your next run
- Know the recipient limit for your network and asset. Cherum Send splits a long list into batches for you; check how many signatures it will take before you sign.
- Validate every address and flag duplicates; check the total against your own arithmetic.
- For cross-chain runs, demand a status for each network’s transfer, and for any transfer that fails, where its money is and who sends it back.
- Compare the conversion rate, not only the visible fee.
- Decide consciously whether anyone other than you can move the money — and if the answer is yes, know what happens on their worst day.
None of this is exotic. It is the difference between a payout that is done when the interface says done, and one that you spend the evening reconciling.