contract MethodRegistry is Owned {
    
    event Registration(address indexed _contract, bytes4 _method);
    event Deregistration(address indexed _contract, bytes4 _method);

    mapping(address => mapping(bytes4 => bool)) public isRegistered; // [contract_addr][method_sig] => bool

    // only used by `addList()`
    struct ContractMethod {
        address addr;
        bytes4 method;
    }

    /************************ External Methods *******************************/

    function add(address _contract, bytes4 _method) external onlyOwner {
        _add(_contract, _method);
    }

    function addList(ContractMethod[] calldata _contractMethods) external onlyOwner {
        for(uint i = 0; i < _contractMethods.length; i++) {
            _add(_contractMethods[i].addr, _contractMethods[i].method);
        }
    }

    function remove(address _contract, bytes4 _method) external onlyOwner {
        require(isRegistered[_contract][_method], "MR: Not registered");
        delete isRegistered[_contract][_method];
        emit Deregistration(_contract, _method);
    }

    /************************ Internal Methods *******************************/

    function _add(address _contract, bytes4 _method) internal {
        require(!isRegistered[_contract][_method], "MR: Already registered");
        isRegistered[_contract][_method] = true;
        emit Registration(_contract, _method);
    }
}
/**
 * @title MethodRegistry
 * @dev Registry of (contract, method signature) tuples.
 * @author Olivier Vdb - <olivier@argent.xyz>
 */
function _add(address _contract, bytes4 _method) internal {
    require(!isRegistered[_contract][_method], "MR: Already registered");
    isRegistered[_contract][_method] = true;
    emit Registration(_contract, _method);
}

/************************ Internal Methods *******************************/