Matador Docs
Protocol Security

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;
    }
}

On this page