M13-A shipped 2026-09-10 (linked wallets, tiers, DAWN pricing). M13-B shipped 2026-09-10 (treasury ledger, payment intents, confirmation depth, research bounties with maturing payouts). M13-C shipped 2026-09-10 (bonds). M13-E shipped 2026-09-10 (API keys, tier check, MCP key). M13-F shipped 2026-09-10 (early access). M13-D shipped 2026-09-10 (the vote). All eight mechanisms are built; each waits on its flag.
Principle unchanged: fund research, reward evidence, recycle value, never sell rankings. Nothing in this document moves money by itself. Every transfer out of the treasury is a transaction the founder sends; the worker verifies it from the receipt and the ledger records it.
Linked wallets (M13-A)
A signed-in reader links one wallet to their account on /account by signing a plain message. The
link is the identity behind every paid action: a research request or placement must be paid from
it, a bounty is paid to it, and its DAWN balance is the only balance Dawnscan ever reads for that account.
Only the address and a hash of the signature are kept. One account per address; a released address
waits a day before another account may take it.
Holder tiers (M13-A)
free, member, member_plus in code (shown as Free, Holder, Holder+). Thresholds, discounts on
DAWN prices, API quotas and early access are settings on /admin/hey. The worker sets the tier from
the linked wallet's balance (M13-E) and stores the decision, never the balance. A tier grants no
permission and touches no ranking.
Prices in Dawnscan (M13-A)
PricingService quotes every Dawnscan price server-side in base units: Request Research from the
research price setting (or REQUEST_RESEARCH_HEY_AMOUNT), placements from the sponsored settings
once the founder switches the payment token to $DAWN. A holder pays the list price less their tier's
discount; the figure is snapshotted on the row.
Treasury ledger (M13-B)
hey_treasury_ledger: one row per Dawnscan movement. IN rows are written PENDING by the flow expecting
the payment and confirmed by the worker from the receipt; OUT rows are written by the founder with
the hash of the transfer they sent and confirmed the same way; FORFEIT rows reclassify custody
money (a kept bond) to research money without a chain movement. Categories follow the treasury
policy: research, infrastructure, operations, custody. pnpm data:hey ledger YYYY-MM prints the
month's table for docs/HEY_TREASURY_LEDGER.md; /admin/treasury shows the same and records
infrastructure and operations lines.
Payment intents and confirmation depth (M13-B)
Before a deposit, the server writes a payment intent: the account's linked address, the amount, the
treasury, the purpose, ten minutes. The transfer is checked against the intent, never against the
browser. No extra signature: the linked wallet is the identity. A receipt counts only once its
block is buried under HEY_PAYMENT_CONFIRMATIONS (default 30) later blocks; the verifier retries
until then. Submit and enqueue happen in one transaction. This closes all three items of
docs/PAID_REQUESTS_LAUNCH_GATE.md.
Research bounties (M13-B)
A bounty is a Dawnscan reward attached to a Scout task. Scopes: verify GitHub ownership, trace a contract migration, document a release, verify a Robinhood Chain deployment, research a disputed identity, map project-owned sources, find an unlisted project. A brief that asks for a ranking, a status, a badge or a placement is refused at creation.
treasury bounty: founder posts on /admin/bounties → OPEN
reader bounty: reader proposes on /bounties/propose → FUNDING_SUBMITTED → funds in Dawnscan → worker confirms → OPEN
Scout claims (7 days) → hands in evidence → moderator reviews on /admin/bounties
approved: AWARDED → payout 1 DUE now, payout 2 PENDING for 90 days
founder sends each half from the treasury, records the hash → worker confirms → PAID
90 days: payout 2 → DUE if the linked ship event is not disputed/retracted and has no open flag,
else CANCELLED with the reason (the Scout is mailed)
rejected: the task reopens for another Scout
retracted: AWARDED → RETRACTED; unpaid halves cancelled; the ship event is the moderator's separate call
Internal Scout credits are untouched: they record contribution; a bounty pays for it. Reviewing is
task.review (moderator); posting, retracting and settings are bounty.manage; recording money
is treasury.manage (admin). The funder cannot review their own bounty; the Scout cannot review
their own work; the funder cannot claim their own bounty.
Bonds (M13-C)
Dawnscan put behind a claim, held by the treasury, returned when the claim checks out. Three kinds,
each switchable on /admin/bonds (offered, required, amount):
SCOUT_CLAIM claiming a bounty takes the bond; the task is reserved for an hour until the
deposit confirms, then for the seven-day claim window; review (either way)
returns it; a lapsed or cancelled claim returns it
OWNER_UPDATE optional, after a verified owner posts an update; returned once the update is
source-linked or verified, or after thirty days undisputed; a dispute or an
open flag holds it for a decision
PROJECT_SUBMISSION before the submit form (required) or beside it (offered); attached to the
project the form creates; returned on approval or an ordinary rejection;
a rejection for spam, phishing, malware, impersonation or a false claim
holds it for a decision; a bond never used is returned after a month
Tables hey_bonds (one row per bond, ledger references for the deposit, the refund and a forfeit).
Deposits are quoted as payment intents (SCOUT_BOND, OWNER_UPDATE_BOND, SUBMISSION_BOND),
posted to /api/hey/bonds, verified by VERIFY_HEY_DEPOSIT, and carried on the ledger as
BOND_DEPOSIT in the custody category. The hourly sweep returns what resolved on its own.
Forfeit is never automatic: bond.manage decides on /admin/bonds with a reason, which writes a
FORFEIT ledger row moving the amount to research money. Refunds are BOND_REFUND outflows the
founder sends and records; the worker confirms them. Nothing here changes how an update is
labelled or how a project is ranked.
API keys and the tier check (M13-E)
hey_api_keys (one active key per account, SHA-256 stored, hey_ prefix, shown once) and
hey_api_usage (requests per key per UTC month). apiAccess in apps/web/src/lib/api-auth.ts
fronts the five public read routes (/api/projects, /api/projects/[slug], /api/ships,
/api/this-week, /api/search/suggest): no key or keys closed → the per-client limit and the
shared cache as before; a key → a per-tier burst bucket, the monthly allowance from the tier
settings, private, no-store, x-hey-tier and x-hey-monthly-remaining; a bad key → 401; a spent
allowance → 429 with retry-after. The routes answer OPTIONS with the allowed headers. The MCP
server sends HEY_API_KEY as a bearer token. Keys are created and rotated on /account.
HEY_TIER_CHECK reads the linked wallet's balance once (balanceOf), decides the tier with the
keep-margin, records the decision and drops the figure; an RPC failure retries in fifteen minutes
without changing anything. It runs daily for every linked account and at once when a wallet is
linked. Flag HEY_API_CREDITS_ENABLED (needs a live token); the tier check itself runs whenever
the token is live and the admin has recorded the token's decimals on /admin/hey.
Early access to research notes (M13-F)
research_notes.public_at: an approval stamps the moment the note becomes public — now, or the
tier settings' window (default 48 hours) from now when HEY_EARLY_ACCESS_ENABLED is on with a
live token. ScoutService.listNotes hides a not-yet-public note from the plain listing and shows
it to a viewer whose tier carries early access (earlyAccessFor) and to its author; the research
queue hides its title the same way. The project page marks such a note "Early access · public in
N hours" for the readers who see it; everyone else sees nothing extra. No ranking reads any of
this.
The research-funding vote (M13-D)
hey_votes, hey_vote_options, hey_vote_ballots. The founder creates a round for a month with
two to eight options (themes, scopes, or projects to research) on /admin/votes, opens it with a
closing time, and accounts with a linked wallet cast one ballot each on /hey/vote, changeable
while the round is open. At close (on time by the scheduler, or early by the founder) the worker's
HEY_VOTE_SNAPSHOT reads each ballot's wallet balance once at the closing block, writes the weight
on the ballot, and tallies; a ballot under 1 DAWN counts as zero weight. Results show only after the
tally, and the founder publishes a decision note. Advisory only, in fixed words on the page; never a
governance right, never an entitlement, never a ranking input. Flag HEY_HOLDER_VOTE_ENABLED
(needs a live token); permission vote.manage.
Founder runbook
- After go-live:
/admin/hey→ check token → set tiers;/admin/placements→ Use $DAWN. - Set
HEY_BOUNTIES_ENABLED=true(andHEY_BONDS_ENABLED=truewhen wanted) in.env.production(both need a live token and a treasury), restart web and worker; on/admin/bountiesturn bounties on and post the first ones; on/admin/bondsset which bonds are offered or required. - Review handed-in work there. For each payout due: send the amount from the treasury wallet to the address shown, record the hash. The worker confirms it within a few minutes.
- Monthly:
pnpm data:hey ledger YYYY-MM(or/admin/treasury) intodocs/HEY_TREASURY_LEDGER.md. - Monthly, with
HEY_HOLDER_VOTE_ENABLED=true: create the next round on/admin/votesbefore the month ends, open it, and publish the decision once the worker has counted.
Neutrality
All of this lives outside the organic modules and is fenced by packages/domain/src/hey/neutrality.test.ts:
the ranking queries and pages cannot import the ledger, the intents, the bounties, the wallets or the
tiers, and the schema guard keeps holder and wallet words out of every table. A ship event is only
ever touched through ModerationService.