Restaking Policy
In one sentence: governance declares the desired per-Canopy-committee allocation of canoLiq's stake; the protocol reports the actual observed exposure and flags drift so operators can react.
Whitepaper §7 ("Restaking Optimization") commits canoLiq to a multi-committee strategy: identify high-yield committees, diversify slashing risk, keep enough exposure to canoLiq's own committee for redemptions, all under a governance-controlled allocation policy with min/max per committee.
Scope (today vs. eventually)
What's implemented now:
- Policy declaration — governance can store a list of
(committee_id, target_weight_bps, min_stake_ucnpy, max_stake_ucnpy)entries. - Per-committee observation — the protocol reads each registered operator's
lib.Validator.committees[]+staked_amountand sums by committee to derive canoLiq's actual exposure. - Drift reporting —
/v1/restakingsurfaces observed weight vs target, plusunder_min/over_maxflags, plus an aggregatepolicy_compliantboolean.
What's deferred:
- Active rebalancing. The protocol does not currently re-route delegations
in response to drift; that requires a delegation-routing primitive (a way for
canoLiq to atomically shift its pool's delegation between operators) that
isn't defined in the codebase yet. The compliance signals are designed so
operators can act manually in the meantime — by adjusting which operators
canoLiq's
ValidatorRegistryfavours, or by ejecting operators via the existingACTION_VALIDATOR_EJECTgovernance tier.
Restaking semantics
Canopy lets one validator serve multiple committees with the same surety bond
("restaking"). So if operator A bonds 1_000_000 uCNPY and lists
committees = [2, 7], A's full 1_000_000 counts toward canoLiq's exposure on
both committees 2 and 7 — not split between them. Per-committee exposure is
therefore:
exposure[c] = Σ operator.staked_amount for operators whose committees[] contains c
The plugin reads each registered operator's Canopy Validator record (via
KeyForValidator) and computes this sum at each snapshot.
The "registered operator" set is canoLiq's ValidatorRegistry — seeded at
genesis (plugin/go/canoliq/genesis.{localnet,testnet}.json's
validatorRegistry block). Each entry is an (address, stake) pair where
stake is the relative weight used in per-validator pro-rata reward
distribution; the committee membership comes from the operator's own Canopy
Validator.committees[] (not from canoLiq's registry). An empty registry
falls back to a single committee-aggregator key and surfaces an empty
allocations list at /v1/restaking. Mutating the registry post-genesis
is not currently exposed as a governance action — that would be a future
addition to the per-action governance matrix.
Policy validation
When governance updates restaking_policy:
- An empty list is valid — it means "no policy declared; observation only".
- A non-empty list must have
target_weight_bpssumming to exactly10_000across all entries. - Each
committee_idmay appear at most once. - Per entry, if both
min_stake_ucnpyandmax_stake_ucnpyare set,min ≤ max. 0for either bound means "no constraint".
A policy that fails any check is rejected by ValidateParams and the
param-change proposal does not pass.
/v1/restaking
GET /v1/restaking
{
"totalExposureUcnpy": 1500000,
"policy": [
{ "committeeId": 2, "targetWeightBps": 6000, "minStakeUcnpy": 500000, "maxStakeUcnpy": 0 },
{ "committeeId": 7, "targetWeightBps": 4000, "minStakeUcnpy": 0, "maxStakeUcnpy": 0 }
],
"allocations": [
{ "committeeId": 2, "stakeUcnpy": 1000000, "weightBps": 6666, "targetBps": 6000, "driftBps": 666 },
{ "committeeId": 7, "stakeUcnpy": 500000, "weightBps": 3333, "targetBps": 4000, "driftBps": -667 }
],
"policyCompliant": true
}
totalExposureUcnpy— Σ acrossallocations[].stakeUcnpy.policy— the governance-set declaration; empty when none configured.allocations— sorted by committee id; the union of observed committees and policy-listed committees so a 0-exposure committee with a policy entry still appears (asunder_minwhen applicable).driftBps— signed: positive = over target, negative = under.policyCompliant—falsewhen any allocation reportsunder_minorover_max. Pure weight drift does not flip this flag; it's informational until active rebalancing lands.
Tuning the policy
Restaking policy changes go through ACTION_PROTOCOL_UPGRADE — the highest
governance tier (10% quorum, 67% approval, 7-day timelock) because they affect
the protocol's stake distribution. Smaller adjustments to existing entries
(e.g. shifting weight bps between two committees) follow the same path.
Related
- Governance Tiers — the
ACTION_PROTOCOL_UPGRADEtier used for policy changes. - API Endpoints —
/v1/restaking.