tarakan/docs/design/credit-economy.md
Maxfield Luke af6077b9c3
All checks were successful
CI and deploy / Test (push) Successful in 4m52s
CI and deploy / Deploy production (push) Successful in 23s
Initial commit on Forgejo
Fresh repository history for elektrine/tarakan hosted at
https://git.elektrine.com/elektrine/tarakan.
2026-07-29 04:43:40 -04:00

2.9 KiB

Credit economy

How credits are minted, spent, and settled - and the rules that keep money out of the security record's truth machinery.

Minting (earned, never bought)

Credits are minted only on verification events, by Tarakan.Credits.MintWorker, when a canonical finding's status settles. Fixed amounts (Tarakan.Credits.mint_amounts/0):

Kind Amount Paid to
mint_finding_verified 50 The finder (earliest public occurrence), first settle to verified
mint_check_correct 10 Each checker whose verdict matches the settled status
mint_fix_settled 25 Each checker who attested fixed when the finding settles fixed (on top of the correctness mint)

Every mint carries a subject ({subject_type, subject_id}) and rides a partial unique index, so minting is idempotent: replays and status oscillations return :already_minted and never double-pay. Moderators can correct balances with an audited adjustment entry.

Spending

  • spend_bounty_escrow - funding a credit bounty escrows the full amount from the sponsor at creation; cancellations and expiries refund it in full.
  • spend_priority_boost - boosts paid for with credits.
  • receive_bounty - the winning side of a settled credit bounty (see take rate).

Debits fail with :insufficient_credits and leave the balance untouched. The ledger is append-only and public; every entry records balance_after, so any balance can be replayed.

Take rate

Credit bounties settle net of the platform take rate: the configured rate (:tarakan, :market_take_rate, 0.15 at launch) is snapshotted onto the bounty at creation, so later config changes never retroactively change a live bounty. The winner receives credit_amount * (1 - take_rate); the remainder is the platform fee.

Fiat payouts are manual (for now)

Fiat bounties are funded through Stripe Checkout, but there is no automated payout rail this iteration. On settlement a fiat bounty moves to payout_pending; an admin pays the winner off-platform and records the fact with Market.mark_paid/2 (payout_pending → paid, audited as bounty_paid). Cancellation of a funded fiat bounty refunds via Stripe.

Invariants

  • Credits are never purchasable. Stripe sells subscriptions and fiat bounties; there is no way to buy a credit balance.
  • Credits are non-transferable. The only movements are mints, spends, bounty escrow/settlement, and moderator adjustments.
  • Money never influences finding status. Status is decided by independent checks and verification quorum. Credits are minted because a status settled; bounties pay for work, not for outcomes on the record. A paid feature can buy alerts, API limits, or handling - never a verified label.