Skip to content

status-im/karma-faucet.status.network

Repository files navigation

Testnet Karma Faucet

Mint Karma soulbound tokens on Status Network Hoodi Testnet. Developers enter an EVM address, select a tier, and receive Karma to test gasless transactions via RLN.

Built with Next.js, ethers.js, Prisma (SQLite), and Tailwind CSS.

Deployment

Service is deployed via infra-role-compose-repo Ansible role in the infra-sites repository from two branches:

Changes are picked up via GitHub webhooks.

Prerequisites

  • Node.js v22+
  • An admin/operator wallet with DEFAULT_ADMIN_ROLE or OPERATOR_ROLE on the SimpleKarmaDistributor (the on-chain safety layer through which this faucet mints — mints never touch the Karma ERC20 directly)
  • The wallet must have enough KARMA to be at least a High-Throughput tier user on the Status Network testnet.

Setup

npm install
cp .env.example .env

Edit .env with your values. Especially don't forget to fill in MINTER_PRIVATE_KEY, KARMA_CONTRACT_ADDRESS, and KARMA_DISTRIBUTOR_ADDRESS. Then create the SQLite database from the committed migrations:

npx prisma generate
npx prisma migrate deploy

The *.db file is not in git. migrate deploy applies everything under prisma/migrations/ and creates the database file on disk.

For ongoing schema changes, use npx prisma migrate dev --name <description> and commit the new folder under prisma/migrations/. In CI or production, run npx prisma migrate deploy with DATABASE_URL pointing at your database.

.env reference

Variable Required Default Description
MINTER_PRIVATE_KEY Yes Private key of admin/operator wallet
KARMA_CONTRACT_ADDRESS Yes Karma ERC20 address (used for minter balance reads only)
KARMA_DISTRIBUTOR_ADDRESS Yes SimpleKarmaDistributor address — all faucet mints go through this contract
RPC_URL No https://public.hoodi.rpc.status.network RPC endpoint
CHAIN_ID No 374 Chain ID
TOKEN_DECIMALS No 18 Karma token decimals
COOLDOWN_SECONDS No 86400 Per-address cooldown (24h)
DATABASE_URL No file:./dev.db SQLite file: URL, path relative to prisma/prisma/dev.db (gitignored)
NEXT_PUBLIC_EXPLORER_URL No https://hoodiscan.status.network Block explorer URL
NEXT_PUBLIC_CHAIN_NAME No Status Network Hoodi Testnet Display name

Development

npm run dev

Open http://localhost:3000.

Production

npm run build
npm start

Deployment note: This app uses in-memory rate limiting alongside a SQLite-backed mint store, so it must run as a persistent Node.js process — not serverless (Vercel, Lambda, etc.). Per-address cooldowns are persisted in SQLite and survive restarts.

Rate Limiting

The faucet enforces cooldowns through three layered checks, evaluated concurrently where possible:

  • In-memory address throttle — Per-address cooldown held in process memory for fast rejection of repeated requests. Resets on restart.
  • Persistent address cooldown — Per-address cooldown stored in SQLite upon mint store. Survives restarts and prevents TOCTOU races by inserting a pending record before the mint transaction is sent.
  • On-chain fallback — When no in-memory or DB record exists, the faucet scans for any recent Karma mints to the target address. If a recent mint is found, the address is back-filled into the DB and in-memory stores so subsequent layers catch it immediately.

Mint records track status (pendingconfirmed / failed) and are verified on-chain in the background (via Next.js after()) once the response has been sent. Failed mints clean up the pending record so the address isn't permanently blocked.

Tiers

Tier Karma Daily Tx Quota
Entry 1 2/day
Newbie 2–49 6/day
Basic 50–499 16/day
Active 500–4.99K 96/day
Regular 5K–19.99K 480/day
Power 20K–99.99K 960/day

Higher tiers (Pro, High-Throughput, S-Tier, Legendary) are not provided through this faucet — contact the team directly to obtain them.

API

POST /api/mint

{ "address": "0x...", "tierId": "basic" }

Returns 200 with { txHash, explorerUrl, tier, karmaAmount } on success. Each request sends two transactions on the distributor — mint(account, amount) (credits a virtual balance) followed by redeemRewards(account) (transfers the Karma to the user). On the happy path txHash is the redeem tx, which is the one containing the ERC20 Transfer visible on explorers.

If the redeem call fails after a successful mint, the response additionally carries a warning field and txHash points at the mint tx instead. The user's Karma is reserved as a virtual balance on the distributor and remains redeemable later (redeemRewards is permissionless), so the rate limit still applies.

GET /api/health

Returns 200 with { status, chainId, minterEthBalance, minterKarmaBalance, contractAddress, distributorAddress, distributorAvailableSupply }. distributorAvailableSupply is the remaining pre-funded Karma on the distributor — when this reaches zero, mints will start failing until the rewards supplier tops it up.

About

Karma soulbound token faucet for Status Network Testnet V2

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors