Skip to main content
A tier is a property of a (target, selector) pair, set by governance on TierRegistry and consumed at propose and execute. It is not a property of a guardian. There is no guardian tier ladder in the protocol: every active guardian reviews every proposal. What changes with the pair is the price of extractable value, not who is allowed to vote. TierRegistry.tierOf(target, selector) is the read. The governor takes the max tier across execute and settlement calls as the proposal’s envelope tier, and sums per-call cap × boundBps over both legs into requiredCoverage.

The three tiers

The registry recognizes exactly three tiers. Names and numbers are the protocol’s:
Tier 0 and tier 1 are the certified tiers. Certification is keyed keccak256(abi.encodePacked(target, selector)) — two selectors on the same adapter are independent pairs, each with its own bound and its own bond. A certified bound must be strictly between 0 and 10_000 exclusive: a full-notional “bound” is tier-2 economics and must not wear a 0/1 label (BoundRequired). Governance must not certify proxied adapters at tier 0/1. tierOf checks live EXTCODEHASH against the hash snapshotted at certification, which catches same-address bytecode mutation and does not catch a proxy implementation swap.

Certification is two steps

A pair, or a whole template class, is certified in two owner-gated steps with a delay between them; there is no single call that certifies. The class path (proposeClassCertification → certifyClass) certifies every ERC-1167 clone of a StrategyFactory template at once; classOf(target) reports the class a clone belongs to. The Portfolio class certification at 2,000 bps is pending at launch, so Portfolio proposals price at full notional until it lands. Demotion is instant: the owner’s demote, the challenge game’s demoteByChallenge, or the permissionless poke on a codehash mismatch. A demotion between propose and execute makes executeProposal revert TierRegressed.

The (2, 10_000) default

Uncertified, demoted, or codehash-mismatched pairs all report (2, 10_000):
That pair is the absence of a certification, not a grant. A governor always has a registry: initialize and setTierRegistry both refuse a codeless address (TierRegistryNotWired), so there is no un-wired path and no default other than this one. Coverage for a call is (cap_i * boundBps) / 10_000. Tier 0/1 uses the certified bound; tier 2 uses 10_000. See Coverage and underwriting.

Tier is not reachability

Tier is not reachability. tierOf prices a pair. It does not decide whether the vault may call that target. An uncertified pair is expensive (full-notional coverage). It is not, by that fact, unreachable — and a certified one is not, by that fact, reachable. Reachability is a structural property of the batch, checked by the vault.
The spec line the contracts implement: tiers PRICE extractable value for coverage; the batch guard bounds WHAT a governor batch may call at all. Demoting a pair back to (2, 10_000) raises the coverage price. It is a price, not a prohibition. Tier 2 does carry one hard stop, and it is a size limit rather than a target list. At propose, a call that resolves to tier 2 must declare a cap within the vault’s tier-2 ceiling, or _scanCalls reverts Tier2CallCapExceedsCeiling(i):
Certifying the (target, selector) pair is what lifts a call out of tier 2 and out of that ceiling.

The batch guard: what a governor batch may call

SyndicateVault._guardBatchCalls is structural, not reputational. There is no vault-side target list, and the registry has no callee or adapter allowlist to consult. Every call in executeCalls and settlementCalls is one of exactly two shapes: The vault resolves that factory by walking governor() → tierRegistry() → strategyFactory(). A hop that does not answer reads as zero, and an unwired factory registers nothing — fail-closed. The governor runs the same target check at propose, so a bad target fails the proposal rather than the batch. A strategy clone reaches its own venue through its own reviewed code, not through proposer calldata. That is where the remaining registry axis applies.

The counterparty axis

TierRegistry carries three allowlists that strategy templates, not the governor, consult. None of them is a tier: Owner-set with setCounterpartyAllowed(counterparty, allowed), setMorphoMarketAllowed(id, allowed) and setPriceSourceForToken(token, priceSource, allowed). They confer nothing to a governor batch: a listed counterparty is not a callable batch target, and an unlisted one is not thereby unreachable through a strategy the factory already registered. A concentrated-liquidity template still has to bind a Uniswap position manager; that is what this axis is for.

What this is not

  • Not a guardian ladder. Guardians are one cohort. Stake weights a review vote; it does not gate which (target, selector) a guardian may look at. Tiers do not rank guardians.
  • Not a permission to call. See Tier is not reachability.
  • Not an indemnity. A tighter extractableBoundBps lowers requiredCoverage. Slash proceeds are still burned.

Views

See Coverage and underwriting for how the bound becomes requiredCoverage, and Guardian Review for the Approve / Block vote that underwrites it.