Metrics & scoring
A verifier returns two raw metrics plus one reference score. The metrics are the source of truth. The score is advisory.
Raw metrics (authoritative)
sats_bonded
Sum of confirmed, unspent UTXO values at the address — or, if the bond: extension is present, exactly that value (surplus balance is ignored). Integer, satoshis.
days_unspent
Floor of days since the earliest confirmation time among the bonded UTXOs. When bond: is present, computed via the oldest-first greedy selection rule — see below. Integer, days.
Both metrics are computed from live Bitcoin chain state at verify time. Verifiers MUST NOT cache them beyond a short UX window.
Reference score (advisory)
The protocol registers one scoring algorithm, v0, for UX comparability:
score_v0 = round( ln(1 + sats_bonded) × (1 + days_unspent / 30), 2 )
Typical range 10–250.
sats_bonded | days_unspent | score_v0 (approx) |
|---|---|---|
| 10,000 | 30 | 18 |
| 100,000 | 90 | 46 |
| 1,000,000 | 365 | 182 |
| 100,000,000 | 365 | 243 |
Scores are not comparable across algorithms and SHOULD NOT be the basis of a gate decision. Gate on raw metrics (min_sats, min_days).
Tier helper (UX-only)
For badge rendering and tier labels, a thin helper is provided:
| Tier | Threshold |
|---|---|
bronze | 10k sats × 30 days |
silver | 100k sats × 90 days |
gold | 1M sats × 180 days |
platinum | 10M sats × 365 days |
These thresholds are suggestions, not protocol. A platform's "Gold" tier does not necessarily mean the same thing as another platform's.
The bond: extension — why it matters
Without bond:, sats_bonded is the sum of all confirmed UTXOs at the address. A wallet that holds 50M sats casually produces the same proof as one carefully bonding 1M — which is usually not what the signer meant.
With bond:, the signer declares their intended commitment. Verifiers then:
- Fail with
bond_insufficientif confirmed balance < bond. - Set
sats_bonded := bond(surplus ignored). - Compute
days_unspentvia oldest-first greedy selection:- Sort UTXOs by
(block_height ASC, txid ASC, vout ASC). - Greedily take UTXOs until sum ≥ bond; call this set
S_bond. first_seen := max(confirmation_time(u))foru ∈ S_bond(the youngest inS_bond).days_unspent := floor((now - first_seen) / 86,400).
- Sort UTXOs by
This rewards long-term holding while preventing rotating UTXOs from resetting age without changing bond.
Why not write your own scoring algorithm into the protocol
RPs have specialised needs:
- Forums often want a simple binary threshold (
sats >= 10k AND days >= 30). - Marketplaces weight time heavily — long commitment matters more than capital.
- Airdrops weight capital — total stake determines allocation.
- Lending may weight compound stake × time differently.
The protocol deliberately ships one reference algorithm and a tier helper. Everything else is RP policy. Don't publish app-specific scores as "registered" — they become walled gardens.
Edge cases
sats_bonded == 0→ statusbond_zero. Attestation is valid; policy layer decides what 0 means.- Unconfirmed deposits → status
bond_pending. Unconfirmed UTXOs never count. - Spent UTXOs → not counted. When the user spends, the proof's
sats_bondeddrops on the next verify. - Missing
bond:on a large wallet → confirmed balance is used. Signer should usebond:to pin intent.
Further
- Verification — the full verification algorithm.
/api/checkreference — endpoint that returns these fields.