Download the CSV →
415 rows, one per wallet, 16 columns. The three the bounty asked for are
eth_paid_out, eth_earned and nfts_held; the rest are the
working behind them.
fee = amount * 25 / 1000, which holds
exactly on all 278 completed bounties — and sends the remaining 97.5% to the claimant. So an
issuer's outflow is the full bounty amount while the claimant's inflow is 97.5% of it. Across all
of v1: 3.726923002 ETH left issuers, 3.633749927 ETH reached
claimants, and 0.093173075 ETH went to the treasury at
0x1a706a29…3fef9.
The CSV carries all three as separate columns, so you can add up whichever definition you meant.
totalSupply() = 722.
Every wallet
How it was built
Five small scripts, no dependencies beyond an ABI decoder, each linked below. There is no
database and no indexer: the whole history is one eth_getLogs call.
- pull_logs.js —
eth_getLogsover the contract's full range in a single call. Arbitrum's public endpoint is not an archive node, but logs come from the receipt index, so no historical state is needed. Output: logs.json (3,466 logs, blocks 117,178,213 → 443,301,520). - decode.js — decodes them into
events.json: 496
BountyCreated, 722ClaimCreated, 278ClaimAccepted, 171BountyCancelled, 1,072Transfer. - verify.js — 22 invariants, all of which must pass before a CSV is written (output).
- build_csv.js — writes
the CSV and summary.json.
All arithmetic is in wei as
BigInt; ETH strings are exact decimal expansions, never floats. - verify_chain.js — asks the contract itself (output).
The claim NFT's metadata and its
image are generated by a sixth script,
gen_card.py, which reads every figure it prints out of
summary.json, the CSV and verify.txt at render time and refuses to draw at
all if the verification output is not clean — an image of a data pull that disagrees with the data
pull is worse than no image.
Why you can trust the numbers
This contract has no verified source — it is not on Sourcify and Arbiscan wants an API key — so the event signatures came from openchain's topic database and the ABI was reconstructed. That is exactly the situation where a plausible-looking CSV can be quietly wrong, so every assumption is pinned by something that would break loudly if it were false:
- The ETH ledger closes. Funded (6.536511134) = paid out (3.726923002) + refunded (2.591392421) + still escrowed (0.218195711), and that last figure equals the contract's live balance to the wei. Nothing is unaccounted for, and no bounty was double-counted.
- Cross-event identity. Every
ClaimAcceptednames a bounty issuer and a claimant that match the correspondingBountyCreatedandClaimCreatedrecords; every accepted claim really belongs to the bounty that accepted it. - The partition is exact. 278 completed + 169 cancelled + 49 open = 496, with no bounty in two states. (There are 171 cancel events for 169 bounties — two were cancelled twice.)
- NFT holdings were checked against the chain, not just derived. Replaying 1,072
transfers gives a balance for each wallet;
balanceOf()was then called for all 415, including the 334 the replay says hold nothing. Zero mismatches, and the column sums tototalSupply(). - The indexed parameters were established, not assumed. topic1 holds a 20-byte
address in every
BountyCreatedandClaimCreatedlog, which fixesissueras the indexed field in both.
Two invariants failed on the first run and both were real: the claim NFT is minted to the contract rather than the claimant, and the event's 7th word repeats the claim id rather than being the timestamp. Both are fixed above; the failures are why the checks exist.