Batch-send the native coin and ERC-20 tokens to many recipients in one transaction — a payroll, an airdrop, a splits payout. Stateless and non-custodial: it never holds funds across calls. The disperse.app pattern, hardened. ~55 lines, MIT.
disperseEther(recipients, values)payable — sendsvalues[i]native coin to each recipient;msg.valuemust cover the sum and any excess is refunded to the caller.disperseToken(token, recipients, values)— pulls the summed amount in onetransferFrom, then pushes to each recipient (gas-efficient for long lists; assumes a standard, non-fee-on-transfer token).disperseTokenSimple(token, recipients, values)— directtransferFrom(caller → recipient)per entry; correct for fee-on-transfer / rebasing tokens (each recipient gets whatever that token delivers).
All revert on length mismatch or an empty list; the ether path reverts if a recipient rejects the
transfer (nothing is half-sent) or if msg.value doesn't cover the sum.
- Holds no value — after any disperse (ether / token / token-simple, any amounts), the contract's native balance and token balance are both zero (12,800 calls, 0 reverts). It is a pass-through, not a vault. Mutation-checked: skipping a distribution (retaining tokens) fails the invariant and a unit test.
- Stateless singleton — deploy once, anyone uses it. No owner, no fee.
- Use
disperseTokenSimplefor fee-on-transfer tokens;disperseTokenpools and assumes exact transfers. - Very long lists are bounded by the block gas limit (chunk if needed). Unaudited reference.
forge test # 11 tests: ether distribute+refund, token pooled, token-simple (FoT), reverts, no-value invariant