An onchain donation page on Arc Testnet. Connect a wallet, send native USDC with an optional message, and the donation shows up in a public list.
https://arc-donation-dapp.vercel.app
| Network | Arc Testnet (5042002) |
| RPC | https://rpc.testnet.arc.network |
| Contract | 0x54834Dbc98E7B9f2bfc2aC74A784eA75cf9Ffe0E |
| Compiler | solc 0.8.34, optimizer off |
The contract has been live and in use: 74 donations totalling 220 USDC at the time of writing.
On Arc, USDC is the native gas token, not an ERC-20 the way it is on most chains. That means a donation is msg.value on a payable function, with no approve and no transferFrom. It also means the amount carries 18 decimals rather than the 6 that USDC uses elsewhere, which is the detail most likely to trip someone up when reading the numbers.
The deployed bytecode is not something you have to take on trust. Compile and compare:
cd contracts
forge build
cast code 0x54834Dbc98E7B9f2bfc2aC74A784eA75cf9Ffe0E \
--rpc-url https://rpc.testnet.arc.networkEverything before the trailing metadata matches byte for byte. The last 53 bytes differ because they encode an IPFS hash of the exact source file the deployment was compiled from, and that file had a different name and comments in Remix. The executed code is identical.
The compiler version is recoverable from the bytecode itself: the metadata ends with 736f6c6343 (solc) followed by the version, 000822 here, which is 0.8.34. Compiling with 0.8.30 produces a binary that is 34 characters shorter and diverges at offset 4020.
Foundry project under contracts/.
cd contracts
forge install foundry-rs/forge-std
forge test15 tests. The ones worth naming:
test_WithdrawDoesNotResetTheHistory — totalDonated and donationCount are cumulative history, not a balance. If withdraw reset them, the page would report that nobody had ever donated the moment the owner took the funds out.
test_RecentDonationsAreNewestFirst — getRecentDonations walks the array backwards. Getting that direction wrong would put the oldest donation at the top of the page and nobody would notice until the list grew past a screenful.
test_RecentDonationsClampsToWhatExists — asking for more donations than exist clamps rather than reverting. The frontend always requests a fixed page size, so an empty contract hits this on first load.
test_RevertsWhenTheOwnerRejectsTheTransfer — if the owner is a contract that refuses value, withdraw reverts rather than silently succeeding.
Single index.html, no build step. ethers v5 from a CDN, wallet connection, network switching to Arc Testnet, donation form, live stats, recent donations list, and a withdraw button that only renders for the owner.
Serve it locally:
python3 -m http.server 8080MIT