Matador Docs
Institutional Compliance

Recipe - Approvals & Segregation

Enforcing Dual Control for high-value transactions.

Recipe: Approvals & Segregation

This policy implements Dual Control: High-value transactions require a specific "Approver" role to execute, while low-value transactions can be executed by a "Trader."

The Strategy

Threshold: $100,000 USDC.

Trader: Can execute < $100k independently.

Approver: Must execute (or co-sign) >= $100k.

Dual control separates duties

Use distinct keys for initiator and approver roles to reduce single-actor risk.

The Policy

import "abis/ERC20.json" as Token;

permission DualControl -> 1.0.0 {
    parameters: {
        token: address,
        trader: address,
        approver: address,
        maxTraderAmount: uint256
    }

    fn main() -> bool {
        if (context.target != parameters.token) {
            return false;
        }

        if (context.selector == Token.transfer) {
            if (Token.transfer.amount == parameters.maxTraderAmount) {
                if (context.caller == parameters.trader) {
                    return true;
                }

                return context.caller == parameters.approver;
            }

            return context.caller == parameters.approver;
        }

        return false;
    }
}

Advanced: Async Approval

For a true "Initiator -> Approver" flow on-chain:

  1. Initiator calls queueTransaction(). Policy allows this.
  2. Approver calls executeTransaction(). Policy checks if sender == APPROVER and if the tx was queued.

This keeps keys offline until the final step.

On this page