Development of Crypto Donation System
The task seems simple on the surface: accept crypto from a donor. But this flow immediately raises several non-trivial questions — how to show status in real time, how to work with different networks and tokens, what to do with dust after gas fees, and how not to lose a donation during network reorg.
Minimal viable scheme
For single or low-volume donation streams, complex infrastructure is unnecessary. Scheme with one address:
- Publish one address (ETH/BTC/SOL) on the page
- Webhook monitoring via provider (Alchemy Notify, Moralis Streams, QuickNode Streams)
- Webhook triggers backend → updates donor UI in real-time
// Alchemy Notify webhook handler
app.post('/webhook/donations', express.raw({type: 'application/json'}), async (req, res) => {
const isValid = verifyAlchemySignature(req.body, req.headers['x-alchemy-signature'], WEBHOOK_SECRET)
if (!isValid) return res.sendStatus(401)
const payload = JSON.parse(req.body.toString())
for (const activity of payload.event?.activity || []) {
if (activity.toAddress.toLowerCase() === DONATION_ADDRESS.toLowerCase() && activity.value > 0) {
await db.donations.create({
txHash: activity.hash,
fromAddress: activity.fromAddress,
amount: activity.value,
asset: activity.asset,
status: 'pending'
})
io.emit('new_donation', { amount: activity.value, asset: activity.asset })
}
}
res.sendStatus(200)
})
Webhooks are more reliable than polling: Alchemy/QuickNode retry delivery on failure, and you won't miss a transaction.
Confirmations: when to count a donation as received
Don't count a donation as final on first notification. For ETH mainnet — minimum 6 confirmations, for L2 (Arbitrum, Base, Optimism) — 1–2 is sufficient (L2 finality is faster, reorgs rare). For BTC — 1 confirmation for small amounts, 3+ for large.
Status machine for donation:
-
detected— transaction in mempool -
confirming— included in block, waiting for confirmations -
confirmed— reached required confirmations, donation counted -
failed— reorg or dropped transaction
Widget for streamers / real-time alerts
Most common scenario: streamer wants to receive crypto donations with pop-up alert in OBS. Architecture:
Blockchain → Webhook Provider → Backend API → WebSocket (Socket.io) → OBS Browser Source
Widget — HTML page with WebSocket connection:
<!-- OBS Browser Source URL: https://yourapp.com/widget?streamer_id=123 -->
<script>
const socket = io('wss://yourapp.com')
socket.on('donation', (data) => {
showDonationAlert(data.sender, data.amount, data.currency, data.message)
})
</script>
Multi-currency without extra complexity
For a small system — accept USDC/USDT on multiple networks plus native ETH. This covers 90% of audience. Give donors choice of network — ETH mainnet, Arbitrum, Base, Polygon — this lowers barrier (gas on L2 is cheaper).
Identify donation by network + address + token:
def identify_donation(network: str, token: str, amount: float, tx_hash: str) -> Donation:
usd_value = convert_to_usd(token, amount, network)
return Donation(
tx_hash=tx_hash,
network=network,
token=token,
raw_amount=amount,
usd_value=usd_value,
confirmed=False
)
Complete system with real-time widget, multi-network receipt and dashboard: 3–5 days development.







