Self-Provable Selector Registry

self-provable-selector-registry · discovery-registry · 1011 B runtime · registry-info

scores

source

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

/// @notice Target contract must implement this function.
interface IManifestProvable {
    function manifestProof(bytes4 selector) external returns (bytes32);
}

/// @title Self-Provable Selector Registry
/// @notice Maps a target address to allowed bytes4 selectors, each with an on-chain proof.
contract SelfProvableSelectorRegistry {
    /// @notice Proof for target+selector. A zero value means not registered.
    mapping(address => mapping(bytes4 => bytes32)) public entries;

    event SelectorRegistered(address indexed target, bytes4 indexed selector, bytes32 proof);

    error InvalidTarget(address target);
    error NonZeroEntry(address target, bytes4 selector);
    error ManifestProofFailed(address target, bytes4 selector);
    error ZeroProof(address target, bytes4 selector);
    error ProofMismatch(address target, bytes4 selector, bytes32 expected, bytes32 actual);

    /// @notice Register a selector for a target. The target must return the same proof.
    /// @param target The contract that implements manifestProof(bytes4).
    /// @param selector The function selector being registered.
    /// @param manifestRoot The 32-byte value that target.manifestProof(selector) must return.
    function register(address target, bytes4 selector, bytes32 manifestRoot) external returns (bool) {
        if (target == address(0)) revert InvalidTarget(target);
        if (target.code.length == 0) revert InvalidTarget(target);
        if (manifestRoot == bytes32(0)) revert ZeroProof(target, selector);
        if (entries[target][selector] != bytes32(0)) revert NonZeroEntry(target, selector);

        try IManifestProvable(target).manifestProof(selector) returns (bytes32 returned) {
            if (returned == bytes32(0)) revert ZeroProof(target, selector);
            if (returned != manifestRoot) revert ProofMismatch(target, selector, manifestRoot, returned);
            entries[target][selector] = manifestRoot;
            emit SelectorRegistered(target, selector, manifestRoot);
            return true;
        } catch {
            revert ManifestProofFailed(target, selector);
        }
    }
}