feat(faucet): testnet faucet via taps wallet daemon#9
Conversation
👷 Deploy request for cipherscan pending review.Visit the deploys page to approve it
|
👷 Deploy request for cipherscan-crosslink pending review.Visit the deploys page to approve it
|
…ses, use bg token
This reverts commit 50cbd58.
|
couple things before we merge: need to fix: add a per-IP rate limit on /api/faucet/dispense, right now the only gate is turnstile + the 1 TAZ cap + our global express limiter. turnstile is bypassable with effort and the global limiter isn't faucet-specific. a simple in-memory map (5 req/IP/hour, no redis needed) would stop someone draining the wallet in a few minutes. it's testnet so not critical but good practice enforce max amount server-side, the slider caps at maxSpendTaz on the client but the server forwards whatever amountTaz comes in. taps probably validates too but we should reject amountTaz > 1 (or whatever the cap is) before proxying. defense in depth should check: balanceTaz unit, you divide max_dispensable_zat by 1e8 to get TAZ, but balanceTaz uses taps.balances.orchard raw. if taps returns that in zatoshis the wallet stats card will show 450M instead of 4.5. just verify which unit taps sends confirm trust proxy is set correctly on express so req.ip in the turnstile verify is the real client IP not the LB overall this is good to merge with the rate limit + server-side max. |
|
addressed all four, pushed in
also slipped a memo into every dispense plugging zipher (in beta) — testnet recipients should know:
|
finally got the testnet faucet wired up. lives at /faucet on testnet, with a "Get TAZ" CTA in the navbar (testnet-only) pointing at it so people can actually find it.
drag a slider (anywhere from 0.001 to 1 TAZ), drop in a
utest1…orchard unified address, hit send — a few seconds later there's a confirmed tx and a "view tx →" link straight back into the explorer. wallet stats card up top shows live balance + how much is actually spendable right now, and there's a donate QR + address at the bottom for refills (pulled live from the wallet, so it'll always be the right one).the actual sends are handled by taps — a small rust wallet daemon i wrote for exactly this. cipherscan-express never holds a key; it just sits in front of taps and does the captcha. taps takes the request, builds a shielded orchard tx, signs it, broadcasts via lightwalletd. clean separation — keys can rotate, wallet implementations can swap, none of it touches cipherscan.
defenses on the dispense path are turnstile + the 1 TAZ per-tx cap + the global express rate limiter. no per-address cooldown / no redis dependency — kept it simple, can always add a daily-volume cap later if abuse becomes a thing.
new dep
one runtime dep added:
@marsidev/react-turnstile(^1.5.2) — thin react wrapper around cloudflare's turnstile widget script. only thing pulled in for this PR.wiring it up
taps already runs on our infra at
https://light.zcash.me/taps— no docker / wallet setup on your end. two env vars on the express side:i'll DM the api key separately so it doesn't end up in a screenshot. the wallet's already funded and synced; donations from the /faucet donate card go straight to it.
captcha
cloudflare turnstile is wired up but stays off until both keys are set. two pieces, both from the same widget config:
testnet.cipherscan.appNEXT_PUBLIC_TURNSTILE_SITE_KEYTURNSTILE_SECRET_KEYboth or neither. the UI now drives its captcha gate off
/api/faucet/status(which mirrors the server's secret-key presence), so if the server enforces but the site key is missing in the build, you get a loud "captcha misconfigured" banner instead of a silent 400 loop.gotcha
if our taps daemon is briefly out of sync with the chain tip (after a restart, say), dispenses 503 with
wallet still syncingand the UI shows a "wallet syncing" notice up top (kicks in when a single dispense can fulfill less than 20% of the per-tx cap). usually clears in under a minute. on our end the container hasrestart: unless-stoppedso it survives reboots.oh —
/swapand/faucetboth have network-gating now (/swap404s outside mainnet,/faucet404s outside testnet) so neither shows up on the wrong network.test plan