contract CancellationRegistry is Ownable {

    mapping(address => bool) private registrants;
    mapping(bytes32 => uint256) private orderCancellationBlockNumber;
    mapping(bytes => bool) private orderDeactivations;

    modifier onlyRegistrants {
        require(registrants[msg.sender], "The caller is not a registrant.");
        _;
    }

    function addRegistrant(address registrant) external onlyOwner {
        registrants[registrant] = true;
    }

    function removeRegistrant(address registrant) external onlyOwner {
        registrants[registrant] = false;
    }

    /*
    * @dev Cancels an order.
    */
    function cancelPreviousSellOrders(
        address seller,
        address tokenAddr,
        uint256 tokenId
    ) external onlyRegistrants {
        bytes32 cancellationDigest = keccak256(abi.encode(seller, tokenAddr, tokenId));
        orderCancellationBlockNumber[cancellationDigest] = block.number;
    }

    /*
    * @dev Check if an order has been cancelled.
    */
    function getSellOrderCancellationBlockNumber(
        address addr,
        address tokenAddr,
        uint256 tokenId
    ) external view returns (uint256) {
        bytes32 cancellationDigest = keccak256(abi.encode(addr, tokenAddr, tokenId));
        return orderCancellationBlockNumber[cancellationDigest];
    }

    /*
    * @dev Cancels an order.
    */
    function cancelOrder(bytes memory signature) external onlyRegistrants {
        orderDeactivations[signature] = true;
    }

    /*
    * @dev Check if an order has been cancelled.
    */
    function isOrderCancelled(bytes memory signature) external view returns (bool) {
        return orderDeactivations[signature];
    }

}
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address","name":"registrant","type":"address"}],"name":"addRegistrant","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"seller","type":"address"},{"internalType":"address","name":"tokenAddr","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"cancelPreviousSellOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"address","name":"tokenAddr","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getSellOrderCancellationBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"isOrderCancelled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"registrant","type":"address"}],"name":"removeRegistrant","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]