Pair-to-earn mining is the single most contentious feature we ship. People love it (they earn for chatting). People also worry about it (so do bots). This post is the engineering answer to both: here is the full pair-mining scoring function, the weights, the clamps, and the reasoning behind every term.
We will keep this post updated as the function evolves. The current version, deployed on mainnet since 2026-04-12, is PMS v1.4.
What we are scoring
Mining doesn't reward messages. It rewards pairs — two-sided exchanges where two wallets are actively engaging each other. A DM where one side sends 300 messages and the other replies once contributes vastly less than a DM where both sides send 30 messages and respond within minutes of each other.
This is intentional. A useful unit of "real conversation" is two wallets going back and forth, not one wallet broadcasting. So the scoring function is built around the pair as the primitive and the individual score is derived from their pair scores.
The PMS v1.4 scoring function
For two wallets A and B in an epoch (a sliding 24-hour window), their pair score is:
P(A,B) = ω · R(A,B) · D(A,B) · S(A,B)
Where:
- R(A,B) is the reciprocity factor — how balanced the back-and-forth was
- D(A,B) is the duration factor — how spread out the exchange was in time
- S(A,B) is the substance factor — message length and content entropy
- ω is the wallet pair multiplier — a function of the reputation graph that decays for newly-paired wallets and saturates for long-term-paired ones
Each wallet's epoch score is the sum of their pair scores, clamped:
M(A) = min(Σ_B P(A,B), ceiling(rep(A)))
The clamp ceiling(rep(A)) is the key anti-farm term — your maximum mineable per epoch is bounded by your reputation, not by how many fake conversations you ran.
The protocol mints a fixed amount of SUDO per epoch (currently 41,096) and distributes it proportionally to M(A) across all participating wallets.
R(A,B): reciprocity
R(A,B) = min(msgs(A→B), msgs(B→A)) / max(msgs(A→B), msgs(B→A))
This is the simplest term but the most important. A pair where one side sent 100 and the other sent 100 scores 1.0. A pair where one side sent 100 and the other sent 1 scores 0.01.
This single term kills the broadcast-spam farm pattern. A bot that spams 10,000 messages to 10,000 other bots, all of whom reply once, gets a reciprocity score of 0.0001 — effectively zero. To get a non-trivial score, both bots have to actually exchange messages at scale, which makes them detectable by other terms (substance and reputation).
D(A,B): duration
A 100-message exchange that happens in 30 seconds is almost certainly a script. A 100-message exchange spread across 14 hours is almost certainly real people.
D(A,B) = clamp( spread(messages) / IDEAL_SPREAD, 0.1, 1.0 )
spread is the standard deviation of inter-message intervals across the exchange. IDEAL_SPREAD is currently 27 minutes — the empirical median spread of human conversations on Sudo measured over the past three months.
We clamp the bottom at 0.1 (rather than 0) so that legitimate burst conversations — a friend on holiday catching up over coffee — aren't completely zeroed. We clamp the top at 1.0 so that bots can't game the term by pretending to converse for two weeks.
S(A,B): substance
S(A,B) = sigmoid( avg_msg_length(A,B) - L0 ) · entropy_score(A,B)
Two sub-terms:
Length sigmoid. Below 8 characters, scores rapidly approach zero. The "k" / "lol" / "yes" exchange is real conversation but not really new information, and we don't want to mint SUDO for it. Above ~40 characters, the sigmoid saturates — once your messages carry meaningful content, more length doesn't help your mining.
Entropy score. Measures how repetitive the conversation is. If you and a buddy literally copy-paste each other's last message back and forth, the entropy is 0 and the substance score collapses. If your messages have natural variety, entropy is ~0.7-0.9. Entropy is computed on token-level n-grams, not characters, so changing word order isn't a workaround.
The substance factor is the most adversarial-tested term — it has to be cheap to compute (we run it for every active pair every minute) and still distinguish "I'm just typing more random characters" from "I'm having a real conversation". v1.4 added a transformer-based attestation that ratifies the entropy score every 24 hours on-chain, so attempts to fake substance through character generation are caught at the periodic settlement.
ω: wallet pair multiplier
This is where the reputation graph enters. The multiplier for a fresh pair (never talked before) is 0.18. It rises with conversation history, sustained engagement, and the third-party reputation of the two participating wallets.
ω(A,B) = base + age_bonus(A,B) + cross_bonus(A,B) − penalty(A,B)
base= 0.18 (the floor — even a fresh pair earns something)age_bonusrises with the number of distinct days A and B have been actively chattingcross_bonusis positive when A is connected to other wallets that B is also connected to — i.e. they share friends — measured on the graphpenaltytriggers when A or B is part of a high-suspicion cluster (more on this in the reputation graph post)
The multiplier is bounded [0.0, 2.0]. A long-running, high-trust pair on a healthy graph mines roughly 11x what a brand-new pair does for the same conversation.
Why we clamp by reputation
The ceiling min(..., ceiling(rep(A))) is the term that makes pair-mining sybil-resistant in a deeper way than the per-pair terms alone.
A naive farmer could try to:
- Run a thousand wallets
- Pair them up
- Have them exchange messages that pass reciprocity, duration and substance
If the only defence were the per-pair terms, this could theoretically succeed at small scale. The per-wallet reputation clamp makes it economically unviable: the farmer's mining ceiling depends on the external reputation graph (their wallets' on-chain activity outside Sudo, their connections to other reputable wallets, audit attestations, etc), which is hard and slow to build.
In production, the median honest wallet has a ceiling(rep) around 6.4 SUDO/epoch. A farmer wallet with zero external history has a ceiling around 0.4. So even if every fake pair on the farm scored a perfect 1.0 on every term, each farmer wallet would only earn 6% of what a real one does — and they have to pay for the gas to register and the SUDO to stake for entry into the conversation surface.
What's in the reputation function
The reputation function rep(A) is itself a weighted aggregate:
r_chain— on-chain activity outside Sudo (txn history, contract calls, token holdings, age of wallet)r_attest— explicit attestations from other reputable wallets / DAOs that vouch for this walletr_audit— sustained-good-behaviour signal from your own conversation historyr_minus— penalty for any flagged behaviour caught by the abuse system
Each of these is normalised to [0, 1] and weighted. The current weights are 0.35 / 0.30 / 0.25 / 0.10. The full breakdown is on-chain in the reputation registry; the full derivation lives in the protocol whitepaper.
We deliberately weight r_chain low enough that new wallets aren't permanently disadvantaged, but high enough that wallets with no history outside Sudo can't run wild. New honest wallets typically reach 80% of the median reputation within ~30 days of active use, mostly from r_audit.
Live tuning
We post live tuning data to the public status page. The current epoch's mining pool, the median per-wallet score, the share of mining caught by each anti-farm term — all public. The transparency is intentional: if the function is wrong in a way you can spot, we want you to spot it.
We also reserve the right to tune the weights and clamps on a 14-day-notice schedule, posted to the blog before the change goes live. We have done this 3 times since launch. Each change is announced ahead, deployed atomically, and the previous version remains queryable so honest miners can audit any change to their take.
Bottom line
Pair-mining works because:
- Spam and broadcast are killed by the reciprocity term
- Burst-and-die scripts are killed by the duration term
- Random text generation is killed by the substance term
- Sybil farms are killed by the reputation ceiling
- Coordinated farm rings are caught by the graph signal feeding
r_minus
No single term is enough. The product of all five is what makes the system honest. Drop any one and farmers find a way through.
This is what we have shipped. We will keep shipping iterations as the adversaries iterate. The function is open. The data is open. The defences are tested in public.
Earn while you chat at web.sudochat.app. The full mining math doc has worked-through examples for every term above.
— The Sudo Mining team · PMS v1.4 · May 2026