How rules work

A rule is a condition on a market metric and a signed change to the pool's economics. Rules are written once at launch and enforced on every swap thereafter.

The format

IF  <metric> <GT|GTE|LT|LTE> <threshold>
THEN <signed deltas to holder / staker / lp / tax>

Four operators, up to sixteen rules, applied in index order from the base state. Order matters: rule 2 acts on the state rule 1 produced.

A worked example

Base 5% — holders 2%, stakers 3%:

ConditionHoldersStakersTotal
no rule active2%3%5%
1-day change < 03%2%5%
… and P/E > 504%1%5%

A rule does not have to raise the total. Moving the split between holders and stakers while the trader's cost stays the same is a normal use of the engine.

The hook never evaluates a rule

evaluatePool() collapses oracle data into a single cached EffectivePoolState. beforeSwap reads only that. Two things follow from that:

One unusable metric discards everything

If any metric a pool references is unusable, the rule engine discards the whole evaluation and the pool falls back to its high-water maximum — permanently and silently. A P/E rule on a stock with no fundamentals is not a rule that never fires; it is a pool pinned to its most expensive rate forever.

The rule builder gates on per-stock metric support to prevent this. If you write rules against the contracts directly, check supportsMetric for that specific stock first.

Inactive is not the same as unevaluated

On a pool serving its stale fallback, the active-rule bitmap reads 0 because nothing was evaluated. That is a different fact from every rule having been evaluated and found false. An interface that renders the second as the first is telling a confident lie, so ours renders them distinctly.