Ape Curtis Testnet

Contract Diff Checker

Contract Name:
AuthorizedTransferSecurityRegistryCreator

Contract Source Code:

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

import {
    ImmutableCreate2FactoryInterface
} from "seaport-types/src/interfaces/ImmutableCreate2FactoryInterface.sol";

import {
    IAuthorizedTransferSecurityRegistry
} from "./interfaces/IAuthorizedTransferSecurityRegistry.sol";

/// @title AuthorizedTransferSecurityRegistryCreator
/// @dev Deploys and configures AuthorizedTransferSecurityRegistry contracts.
contract AuthorizedTransferSecurityRegistryCreator {
    ImmutableCreate2FactoryInterface private constant factory = (
        ImmutableCreate2FactoryInterface(
            0x0000000000FFe8B47B3e2130213B802212439497
        )
    );

    error UNAUTHORIZED();

    function _canDeploy() internal view returns (bool) {
        return 
            tx.origin == address(0x939C8d89EBC11fA45e576215E2353673AD0bA18A) ||
            tx.origin == address(0xe80a65eB7a3018DedA407e621Ef5fb5B416678CA) ||
            tx.origin == address(0x86D26897267711ea4b173C8C124a0A73612001da) ||
            tx.origin == address(0xbF81D02F3Ee59E79af3D9337a186F65c9faE39F3);
    }

    function deployAndConfigure(
        address initialOwner,
        bytes32 salt,
        bytes memory initializationCode,
        address[] memory authorizers,
        address[] memory operators
    ) external returns (address registry) {
        if (!_canDeploy()) {
            revert UNAUTHORIZED();
        }

        IAuthorizedTransferSecurityRegistry registryContract = (
            IAuthorizedTransferSecurityRegistry(
                factory.safeCreate2(salt, initializationCode)
            )
        );

        // Note: in provided init code, this contract must be supplied
        // as the default owner so that it can perform configuration and
        // reassign ownership of the default list to the supplied owner.
        if (authorizers.length > 0) {
            registryContract.addAuthorizers(0, authorizers);
        }
        if (operators.length > 0) {
            registryContract.addOperators(0, operators);
        }
        registryContract.reassignOwnershipOfList(0, initialOwner);

        return address(registryContract);
    }
}

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

/**
 * @title ImmutableCreate2FactoryInterface
 * @author 0age
 * @notice This contract provides a safeCreate2 function that takes a salt value
 *         and a block of initialization code as arguments and passes them into
 *         inline assembly. The contract prevents redeploys by maintaining a
 *         mapping of all contracts that have already been deployed, and
 *         prevents frontrunning or other collisions by requiring that the first
 *         20 bytes of the salt are equal to the address of the caller (this can
 *         be bypassed by setting the first 20 bytes to the null address). There
 *         is also a view function that computes the address of the contract
 *         that will be created when submitting a given salt or nonce along with
 *         a given block of initialization code.
 */
interface ImmutableCreate2FactoryInterface {
    /**
     * @dev Create a contract using CREATE2 by submitting a given salt or nonce
     *      along with the initialization code for the contract. Note that the
     *      first 20 bytes of the salt must match those of the calling address,
     *      which prevents contract creation events from being submitted by
     *      unintended parties.
     *
     * @param salt               The nonce that will be passed into the CREATE2
     *                           call.
     * @param initializationCode The initialization code that will be passed
     *                           into the CREATE2 call.
     *
     * @return deploymentAddress Address of the contract that will be created.
     */
    function safeCreate2(
        bytes32 salt,
        bytes calldata initializationCode
    ) external payable returns (address deploymentAddress);

    /**
     * @dev Compute the address of the contract that will be created when
     *      submitting a given salt or nonce to the contract along with the
     *      contract's initialization code. The CREATE2 address is computed in
     *      accordance with EIP-1014, and adheres to the formula therein of
     *      `keccak256( 0xff ++ address ++ salt ++ keccak256(init_code)))[12:]`
     *      when performing the computation. The computed address is then
     *      checked for any existing contract code - if so, the null address
     *      will be returned instead.
     *
     * @param salt     The nonce passed into the CREATE2 address calculation.
     * @param initCode The contract initialization code to be used that will be
     *                 passed into the CREATE2 address calculation.
     *
     * @return deploymentAddress Address of the contract that will be created,
     *                           or the null address if a contract already
     *                           exists at that address.
     */
    function findCreate2Address(
        bytes32 salt,
        bytes calldata initCode
    ) external view returns (address deploymentAddress);

    /**
     * @dev Compute the address of the contract that will be created when
     *      submitting a given salt or nonce to the contract along with the
     *      keccak256 hash of the contract's initialization code. The CREATE2
     *      address is computed in accordance with EIP-1014, and adheres to the
     *      `keccak256( 0xff ++ address ++ salt ++ keccak256(init_code)))[12:]`
     *      formula when performing the computation. The computed address is
     *      then checked for any existing contract code - if so, the null
     *      address will be returned instead.
     *
     * @param salt         The nonce passed into the CREATE2 address
     *                     calculation.
     * @param initCodeHash The keccak256 hash of the initialization code that
     *                     will be passed into the CREATE2 address calculation.
     *
     * @return deploymentAddress Address of the contract that will be created,
     *                           or the null address if a contract already
     *                           exists at that address.
     */
    function findCreate2AddressViaHash(
        bytes32 salt,
        bytes32 initCodeHash
    ) external view returns (address deploymentAddress);

    /**
     * @dev Determine if a contract has already been deployed by the factory to
     *      a given address.
     *
     * @param deploymentAddress The contract address to check.
     *
     * @return True if the contract has been deployed, false otherwise.
     */
    function hasBeenDeployed(
        address deploymentAddress
    ) external view returns (bool);
}

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

enum ListTypes {
    AuthorizerList,
    OperatorList
}

/// @title IAuthorizedTransferSecurityRegistry
/// @dev Interface for the Authorized Transfer Security Registry, a simplified version of the Transfer
///      Security Registry that only supports authorizers and whitelisted operators, and assumes a
///      security level of OperatorWhitelistEnableOTC + authorizers for all collections that use it.
///      Note that a number of view functions on collections that add this validator will not work.
interface IAuthorizedTransferSecurityRegistry {
    event CreatedList(uint256 indexed id, string name);
    event AppliedListToCollection(address indexed collection, uint120 indexed id);
    event ReassignedListOwnership(uint256 indexed id, address indexed newOwner);
    event AddedAccountToList(ListTypes indexed kind, uint256 indexed id, address indexed account);
    event RemovedAccountFromList(ListTypes indexed kind, uint256 indexed id, address indexed account);

    error AuthorizedTransferSecurityRegistry__ListDoesNotExist();
    error AuthorizedTransferSecurityRegistry__CallerDoesNotOwnList();
    error AuthorizedTransferSecurityRegistry__ArrayLengthCannotBeZero();
    error AuthorizedTransferSecurityRegistry__CallerMustHaveElevatedPermissionsForSpecifiedNFT();
    error AuthorizedTransferSecurityRegistry__ListOwnershipCannotBeTransferredToZeroAddress();
    error AuthorizedTransferSecurityRegistry__ZeroAddressNotAllowed();
    error AuthorizedTransferSecurityRegistry__UnauthorizedTransfer();
    error AuthorizedTransferSecurityRegistry__CallerIsNotValidAuthorizer();

    /// Manage lists of authorizers & operators that can be applied to collections
    function createList(string calldata name) external returns (uint120);
    function createListCopy(string calldata name, uint120 sourceListId) external returns (uint120);
    function reassignOwnershipOfList(uint120 id, address newOwner) external;
    function renounceOwnershipOfList(uint120 id) external;
    function applyListToCollection(address collection, uint120 id) external;
    function listOwners(uint120 id) external view returns (address);

    /// Manage and query for authorizers on lists
    function addAuthorizers(uint120 id, address[] calldata accounts) external;
    function removeAuthorizers(uint120 id, address[] calldata accounts) external;
    function getAuthorizers(uint120 id) external view returns (address[] memory);
    function isAuthorizer(uint120 id, address account) external view returns (bool);
    function getAuthorizersByCollection(address collection) external view returns (address[] memory);
    function isAuthorizerByCollection(address collection, address account) external view returns (bool);

    /// Manage and query for operators on lists
    function addOperators(uint120 id, address[] calldata accounts) external;
    function removeOperators(uint120 id, address[] calldata accounts) external;
    function getOperators(uint120 id) external view returns (address[] memory);
    function isOperator(uint120 id, address account) external view returns (bool);
    function getOperatorsByCollection(address collection) external view returns (address[] memory);
    function isOperatorByCollection(address collection, address account) external view returns (bool);

    /// Ensure that a specific operator has been authorized to transfer tokens
    function validateTransfer(address caller, address from, address to) external view;

    /// Ensure that a transfer has been authorized for a specific tokenId
    function validateTransfer(address caller, address from, address to, uint256 tokenId) external view;

    /// Ensure that a transfer has been authorized for a specific amount of a specific tokenId, and
    /// reduce the transferable amount remaining
    function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount) external;

    /// Legacy alias for validateTransfer (address caller, address from, address to)
    function applyCollectionTransferPolicy(address caller, address from, address to) external view;

    /// Temporarily assign a specific allowed operator for a given collection
    function beforeAuthorizedTransfer(address operator, address token) external;

    /// Clear assignment of a specific allowed operator for a given collection
    function afterAuthorizedTransfer(address token) external;

    /// Temporarily allow a specific tokenId from a given collection to be transferred
    function beforeAuthorizedTransfer(address token, uint256 tokenId) external;

    /// Clear assignment of an specific tokenId's transfer allowance
    function afterAuthorizedTransfer(address token, uint256 tokenId) external;

    /// Temporarily allow a specific amount of a specific tokenId from a given collection to be transferred
    function beforeAuthorizedTransferWithAmount(address token, uint256 tokenId, uint256 amount) external;

    /// Clear assignment of a tokenId's transfer allowance for a specific amount
    function afterAuthorizedTransferWithAmount(address token, uint256 tokenId) external;
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):