Action types and weights
Weights are compile-time constants in
EngagementOracle._actionWeight — changing one
requires a contract redeploy, not a governance transaction.
Decay
The contract keeps a per-action-type EMA and applies lazy decay on read: every time an action is recorded, each EMA is reduced in proportion to the seconds elapsed since that user’s last update, then the acting type’s EMA is incremented by1.0.
- The implementation is the linear approximation of exponential decay, not a true
0.5 ^ (Δt / half_life)curve. It tracks the paper’s macro behaviour, not its exact shape. - Because
1 / 0.015 ≈ 66.7, an EMA that goes more than ~67 days without an update decays to exactly zero in one step.
Formula
distinct_actions counts the action types whose EMA is above 0.1. stake is pushed in by
the slasher/oracle role (setStake), so an address with no recorded stake simply gets
stake_mult = 1.
There is no wallet-age, social-graph or device/IP quality term in the ES. The only
“quality” factor in the protocol lives in the reward path:
YCRRewards scales a claim by
0.60 + 0.40 × (activeActionTypes / 7), so a user who only ever likes claims at 60% while
one active across all seven types claims at 100%. Claims are also capped at
500 YCR per address per day (DAILY_CAP) — surface that cap in your UI, or users will
read a truncated claim as a bug.Tiers
The mobile API returns a human-readable tier alongside the raw score:Where ES is used
Leader election
PoeEngine::select_validator_index_for weights validator probabilities by
stake × (1 + β·ES) (β=0.10); on the 4-node testnet the ES term is inert.Staking Jars payout
Each “jar” redistributes rewards proportional to the ES of its stakers.
Quadratic Voting
DAO vote weight is
sqrt(ES) — prevents whales from dominating.Precompile 0x0A
Any Solidity contract can read
ES(addr) at near-zero gas via precompile.Reading ES
- JSON-RPC
- Solidity
- Mobile API