Recipe - Invariants & Guards
Enforcing protocol safety rules.
Recipe: Invariants & Guards
These recipes show callable guard helpers for "Safety Invariants"—rules that must be true for the protocol to be healthy. Bind the public helper functions to an explicit integration phase before treating them as complete enforcement.
TVL Cap: Expose a helper that rejects total assets above the approved ceiling.
Oracle Guard: Expose a helper that rejects deviating price-feed values.
Rate Limit: Scope sensitive functions to trusted callers before adding persisted counters.
Bind helpers explicitly
pub fn helpers are callable policy entry points. They do not automatically run from main() unless your integration binds them into the relevant enforcement phase.
Recipe 1: The TVL Cap
Expose a helper that can reject deposits when a new vault would exceed its approved asset ceiling.
permission TvlCapConcept -> 1.0.0 {
parameters: {
authorizer: address,
vault: address,
maxTvl: uint256
}
pub fn tvlAllowed(totalAssets: uint256) -> bool {
return totalAssets <= parameters.maxTvl;
}
pub fn authorize() -> bool {
return authorizedBy(parameters.authorizer);
}
fn main() -> bool {
return context.target == parameters.vault;
}
}Recipe 2: The Circuit Breaker (Oracle Guard)
Expose a helper that can reject operations when the oracle price is deviating wildly (a sign of manipulation or a crash).
permission OracleDeviationGuard -> 1.0.0 {
parameters: {
authorizer: address,
feed: address,
maxAnswer: uint256,
minTwap: uint256
}
pub fn oracleInBounds(answer: uint256, twap: uint256) -> bool {
if (answer > parameters.maxAnswer) {
return false;
}
return twap >= parameters.minTwap;
}
pub fn authorize() -> bool {
return authorizedBy(parameters.authorizer);
}
fn main() -> bool {
return context.target == parameters.feed;
}
}Recipe 3: Function Rate Limit
Scope a sensitive function (like harvest()) to a trusted harvester. Add
persisted counters when you need an actual time/rate limit.
permission HarvestRateLimit -> 1.0.0 {
parameters: {
harvester: address
}
pub fn authorize() -> bool {
return authorizedBy(parameters.harvester);
}
fn main() -> bool {
return true;
}
}