Matador
API Reference

Module System

Extending the interpreter with pluggable custom logic.

Matador uses a modular architecture to keep the core interpreter lightweight while enabling unlimited extensibility. Opcodes are grouped into "Modules," which are external contracts called by the interpreter when needed.

Architecture

Module Dispatch

When the interpreter encounters an opcode:

  1. It identifies the Module ID associated with that opcode (e.g., SIGNATURE_CHECK belongs to Module 1).
  2. It queries the ModuleRegistry for the address of that module.
  3. It invokes the module via staticcall (for view/pure checks) or delegatecall (for stateful checks).

IPermissionModule Interface

All modules must implement the IPermissionModule interface.

contracts/src/interfaces/IPermissionModule.sol
interface IPermissionModule {
    enum ExecutionMode { View, Mutable }

    function evaluate(
        bytes memory context,
        uint256 offset,
        address subject,
        ExecutionContext calldata exec,
        uint8 opcode,
        ExecutionMode mode
    ) external returns (uint256 newOffset, bool success);
}

Parameters

ParameterDescription
contextThe full bytecode of the policy.
offsetThe current pointer position in the bytecode (arguments start here).
subjectThe smart account being controlled.
execRuntime transaction metadata (target, value, etc.).
opcodeThe specific opcode triggering this call.
modeView (read-only) or Mutable (can write state).

Standard Modules

Matador ships with a set of verified standard modules.

IDNameFunctionality
0CoreArithmetic, context inspection, whitelists. (Built-in)
1DelegationSignature validation (SIGNATURE_CHECK), operation counting.
2StorageAdvanced storage inspection (SLOAD, SSTORE).
3ExecutionCall depth, reentrancy guards.
4CodeCode hash verification (EXTCODEHASH_CHECK).
5ConsensusBlock difficulty, coinbase, randomness.
6BlobEIP-4844 data availability checks.

Creating a Custom Module

You can build your own module to implement domain-specific logic, such as checking a Chainlink oracle or verifying a Merkle proof.

Implement the Interface

Create a contract inheriting IPermissionModule.

contract OracleModule is IPermissionModule {
    using ContextReader for bytes;

    function evaluate(
        bytes memory context,
        uint256 offset,
        address,
        ExecutionContext calldata,
        uint8 opcode,
        ExecutionMode
    ) external view returns (uint256, bool) {
        if (opcode == MY_ORACLE_OPCODE) {
            // Read args from bytecode
            (uint256 minPrice, newOffset) = context.readUint256(offset);
            
            // Perform check
            uint256 price = Oracle.latestAnswer();
            return (newOffset, price >= minPrice);
        }
        revert("Unknown Opcode");
    }
}

Register Module

Deploy your contract and register it with the ModuleRegistry under a unique ID (e.g., ID 10).

Author Policy

Use the CUSTOM_CHECK opcode or update the compiler to recognize your new opcode.

On this page