APE Price: $0.17 (-4.22%)

Contract

0xf1FaC890b4ebd940fe1e19Fd31aAb8C930c66858

Overview

APE Balance

Apechain LogoApechain LogoApechain Logo0 APE

APE Value

$0.00

More Info

Private Name Tags

Multichain Info

N/A
Transaction Hash
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Cross-Chain Transactions
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x0e2CBAaE...2b24697a6
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
AccessControl

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 1000 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

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

import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "../libraries/Constants.sol";
import "../libraries/Errors.sol" ;

/**
 * @title AccessControl
 * @dev Role-based access control system for the Cross-Chain NFT Trading Platform
 * @author Blocklabs Studio
 */
contract AccessControl is 
    Initializable,
    AccessControlUpgradeable,
    PausableUpgradeable,
    ReentrancyGuardUpgradeable
{
    
    // ============ EVENTS ============
    
    /**
     * @dev Emitted when emergency pause is activated
     * @param admin The admin who activated the pause
     * @param timestamp The timestamp of activation
     */
    event EmergencyPauseActivated(address indexed admin, uint256 timestamp);
    
    /**
     * @dev Emitted when emergency pause is deactivated
     * @param admin The admin who deactivated the pause
     * @param timestamp The timestamp of deactivation
     */
    event EmergencyPauseDeactivated(address indexed admin, uint256 timestamp);
    
    /**
     * @dev Emitted when a role is granted with additional context
     * @param role The role that was granted
     * @param account The account that received the role
     * @param sender The account that granted the role
     * @param timestamp The timestamp of the grant
     */
    event RoleGrantedWithContext(
        bytes32 indexed role,
        address indexed account,
        address indexed sender,
        uint256 timestamp
    );
    
    /**
     * @dev Emitted when a role is revoked with additional context
     * @param role The role that was revoked
     * @param account The account that lost the role
     * @param sender The account that revoked the role
     * @param timestamp The timestamp of the revocation
     */
    event RoleRevokedWithContext(
        bytes32 indexed role,
        address indexed account,
        address indexed sender,
        uint256 timestamp
    );
    
    // ============ STATE VARIABLES ============
    
    /// @dev Mapping to track role assignment timestamps
    mapping(bytes32 => mapping(address => uint256)) public roleAssignmentTimestamps;
    
    /// @dev Mapping to track emergency pause history
    mapping(uint256 => bool) public emergencyPauseHistory;
    
    /// @dev Counter for emergency pause events
    uint256 public emergencyPauseCount;
    
    /// @dev Timestamp of contract deployment
    uint256 public deploymentTimestamp;
    
    /// @dev Mapping to track role member counts
    mapping(bytes32 => uint256) private _roleMemberCounts;
    
    /// @dev Mapping to track if an account has a specific role (for counting)
    mapping(bytes32 => mapping(address => bool)) private _roleMembers;
    
    // ============ MODIFIERS ============
    
    /**
     * @dev Modifier to check if caller has admin role
     */
    modifier onlyAdmin() {
        if (!hasRole(Constants.ADMIN_ROLE, msg.sender)) {
            revert CustomErrors.UnauthorizedAccess(msg.sender, Constants.ADMIN_ROLE);
        }
        _;
    }
    
    /**
     * @dev Modifier to check if caller has project admin role
     */
    modifier onlyProjectAdmin() {
        if (!hasRole(Constants.PROJECT_ADMIN_ROLE, msg.sender) && 
            !hasRole(Constants.ADMIN_ROLE, msg.sender)) {
            revert CustomErrors.UnauthorizedAccess(msg.sender, Constants.PROJECT_ADMIN_ROLE);
        }
        _;
    }
    
    /**
     * @dev Modifier to check if caller has fee manager role
     */
    modifier onlyFeeManager() {
        if (!hasRole(Constants.FEE_MANAGER_ROLE, msg.sender) && 
            !hasRole(Constants.ADMIN_ROLE, msg.sender)) {
            revert CustomErrors.UnauthorizedAccess(msg.sender, Constants.FEE_MANAGER_ROLE);
        }
        _;
    }
    
    /**
     * @dev Modifier to check if caller has emergency role
     */
    modifier onlyEmergency() {
        if (!hasRole(Constants.EMERGENCY_ROLE, msg.sender) && 
            !hasRole(Constants.ADMIN_ROLE, msg.sender)) {
            revert CustomErrors.UnauthorizedAccess(msg.sender, Constants.EMERGENCY_ROLE);
        }
        _;
    }
    
    /**
     * @dev Modifier to check if caller has upgrader role
     */
    modifier onlyUpgrader() {
        if (!hasRole(Constants.UPGRADER_ROLE, msg.sender) && 
            !hasRole(Constants.ADMIN_ROLE, msg.sender)) {
            revert CustomErrors.UnauthorizedAccess(msg.sender, Constants.UPGRADER_ROLE);
        }
        _;
    }
    
    /**
     * @dev Modifier to ensure contract is not paused
     */
    modifier whenNotPausedCustom() {
        if (paused()) {
            revert CustomErrors.ContractPaused();
        }
        _;
    }
    
    // ============ INITIALIZATION ============
    
    /**
     * @dev Initializes the AccessControl contract
     * @param initialAdmin The initial admin address
     */
    function initialize(address initialAdmin) public initializer {
        if (initialAdmin == address(0)) {
            revert CustomErrors.ZeroAddressNotAllowed();
        }
        
        __AccessControl_init();
        __Pausable_init();
        __ReentrancyGuard_init();
        
        // Set up role hierarchy
        _setRoleAdmin(Constants.ADMIN_ROLE, Constants.ADMIN_ROLE);
        _setRoleAdmin(Constants.PROJECT_ADMIN_ROLE, Constants.ADMIN_ROLE);
        _setRoleAdmin(Constants.FEE_MANAGER_ROLE, Constants.ADMIN_ROLE);
        _setRoleAdmin(Constants.EMERGENCY_ROLE, Constants.ADMIN_ROLE);
        _setRoleAdmin(Constants.UPGRADER_ROLE, Constants.ADMIN_ROLE);
        
        // Grant initial admin role
        _grantRoleWithTracking(Constants.ADMIN_ROLE, initialAdmin);
        
        // Set deployment timestamp
        deploymentTimestamp = block.timestamp;
    }
    
    // ============ ROLE MANAGEMENT FUNCTIONS ============
    
    /**
     * @dev Grants a role to an account with additional validation
     * @param role The role to grant
     * @param account The account to grant the role to
     */
    function grantRoleWithValidation(bytes32 role, address account) 
        external 
        onlyAdmin 
        nonReentrant 
    {
        if (account == address(0)) {
            revert CustomErrors.InvalidRoleRecipient(account);
        }
        
        // Additional validation for sensitive roles
        if (role == Constants.ADMIN_ROLE && account == msg.sender) {
            revert CustomErrors.RoleOperationFailed(role, account);
        }
        
        _grantRoleWithTracking(role, account);
        roleAssignmentTimestamps[role][account] = block.timestamp;
        
        emit RoleGrantedWithContext(role, account, msg.sender, block.timestamp);
    }
    
    /**
     * @dev Revokes a role from an account with additional validation
     * @param role The role to revoke
     * @param account The account to revoke the role from
     */
    function revokeRoleWithValidation(bytes32 role, address account) 
        external 
        onlyAdmin 
        nonReentrant 
    {
        // Prevent revoking admin role from the last admin
        if (role == Constants.ADMIN_ROLE) {
            uint256 adminCount = _roleMemberCounts[Constants.ADMIN_ROLE];
            if (adminCount <= 1) {
                revert CustomErrors.RoleOperationFailed(role, account);
            }
        }
        
        _revokeRoleWithTracking(role, account);
        roleAssignmentTimestamps[role][account] = 0;
        
        emit RoleRevokedWithContext(role, account, msg.sender, block.timestamp);
    }
    
    /**
     * @dev Batch grants multiple roles to multiple accounts
     * @param roles Array of roles to grant
     * @param accounts Array of accounts to grant roles to
     */
    function batchGrantRoles(bytes32[] calldata roles, address[] calldata accounts) 
        external 
        onlyAdmin 
        nonReentrant 
    {
        if (roles.length != accounts.length) {
            revert CustomErrors.ArrayLengthMismatch(roles.length, accounts.length);
        }
        
        if (roles.length == 0) {
            revert CustomErrors.EmptyArray();
        }
        
        for (uint256 i = 0; i < roles.length; i++) {
            if (accounts[i] == address(0)) {
                revert CustomErrors.InvalidRoleRecipient(accounts[i]);
            }
            
            _grantRoleWithTracking(roles[i], accounts[i]);
            roleAssignmentTimestamps[roles[i]][accounts[i]] = block.timestamp;
            
            emit RoleGrantedWithContext(roles[i], accounts[i], msg.sender, block.timestamp);
        }
    }
    
    /**
     * @dev Batch revokes multiple roles from multiple accounts
     * @param roles Array of roles to revoke
     * @param accounts Array of accounts to revoke roles from
     */
    function batchRevokeRoles(bytes32[] calldata roles, address[] calldata accounts) 
        external 
        onlyAdmin 
        nonReentrant 
    {
        if (roles.length != accounts.length) {
            revert CustomErrors.ArrayLengthMismatch(roles.length, accounts.length);
        }
        
        if (roles.length == 0) {
            revert CustomErrors.EmptyArray();
        }
        
        for (uint256 i = 0; i < roles.length; i++) {
            // Check admin role constraint
            if (roles[i] == Constants.ADMIN_ROLE) {
                uint256 adminCount = _roleMemberCounts[Constants.ADMIN_ROLE];
                if (adminCount <= 1) {
                    revert CustomErrors.RoleOperationFailed(roles[i], accounts[i]);
                }
            }
            
            _revokeRoleWithTracking(roles[i], accounts[i]);
            roleAssignmentTimestamps[roles[i]][accounts[i]] = 0;
            
            emit RoleRevokedWithContext(roles[i], accounts[i], msg.sender, block.timestamp);
        }
    }
    
    // ============ EMERGENCY FUNCTIONS ============
    
    /**
     * @dev Activates emergency pause
     */
    function emergencyPause() external onlyEmergency {
        _pause();
        emergencyPauseCount++;
        emergencyPauseHistory[emergencyPauseCount] = true;
        
        emit EmergencyPauseActivated(msg.sender, block.timestamp);
    }
    
    /**
     * @dev Deactivates emergency pause
     */
    function emergencyUnpause() external onlyAdmin {
        _unpause();
        
        emit EmergencyPauseDeactivated(msg.sender, block.timestamp);
    }
    
    // ============ VIEW FUNCTIONS ============
    
    /**
     * @dev Gets the timestamp when a role was assigned to an account
     * @param role The role to check
     * @param account The account to check
     * @return timestamp The assignment timestamp (0 if not assigned)
     */
    function getRoleAssignmentTimestamp(bytes32 role, address account) 
        external 
        view 
        returns (uint256 timestamp) 
    {
        return roleAssignmentTimestamps[role][account];
    }
    
    /**
     * @dev Checks if an account has any admin privileges
     * @param account The account to check
     * @return hasAdminPrivileges Whether the account has admin privileges
     */
    function hasAdminPrivileges(address account) external view returns (bool) {
        return hasRole(Constants.ADMIN_ROLE, account) ||
               hasRole(Constants.PROJECT_ADMIN_ROLE, account) ||
               hasRole(Constants.FEE_MANAGER_ROLE, account) ||
               hasRole(Constants.EMERGENCY_ROLE, account) ||
               hasRole(Constants.UPGRADER_ROLE, account);
    }
    
    /**
     * @dev Gets all roles assigned to an account
     * @param account The account to check
     * @return roles Array of roles assigned to the account
     */
    function getAccountRoles(address account) external view returns (bytes32[] memory roles) {
        bytes32[] memory allRoles = new bytes32[](5);
        allRoles[0] = Constants.ADMIN_ROLE;
        allRoles[1] = Constants.PROJECT_ADMIN_ROLE;
        allRoles[2] = Constants.FEE_MANAGER_ROLE;
        allRoles[3] = Constants.EMERGENCY_ROLE;
        allRoles[4] = Constants.UPGRADER_ROLE;
        
        uint256 roleCount = 0;
        for (uint256 i = 0; i < allRoles.length; i++) {
            if (hasRole(allRoles[i], account)) {
                roleCount++;
            }
        }
        
        bytes32[] memory accountRoles = new bytes32[](roleCount);
        uint256 index = 0;
        for (uint256 i = 0; i < allRoles.length; i++) {
            if (hasRole(allRoles[i], account)) {
                accountRoles[index] = allRoles[i];
                index++;
            }
        }
        
        return accountRoles;
    }
    
    /**
     * @dev Gets contract statistics
     * @return totalRoleAssignments Total number of role assignments
     * @return totalEmergencyPauses Total number of emergency pauses
     * @return contractAge Age of the contract in seconds
     */
    function getContractStats() 
        external 
        view 
        returns (
            uint256 totalRoleAssignments,
            uint256 totalEmergencyPauses,
            uint256 contractAge
        ) 
    {
        // Calculate total role assignments
        totalRoleAssignments = _roleMemberCounts[Constants.ADMIN_ROLE] +
                              _roleMemberCounts[Constants.PROJECT_ADMIN_ROLE] +
                              _roleMemberCounts[Constants.FEE_MANAGER_ROLE] +
                              _roleMemberCounts[Constants.EMERGENCY_ROLE] +
                              _roleMemberCounts[Constants.UPGRADER_ROLE];
        
        totalEmergencyPauses = emergencyPauseCount;
        contractAge = block.timestamp - deploymentTimestamp;
    }
    
    /**
     * @dev Checks if the contract is in a healthy state
     * @return isHealthy Whether the contract is healthy
     * @return issues Array of health issues (empty if healthy)
     */
    function checkContractHealth() 
        external 
        view 
        returns (bool isHealthy, string[] memory issues) 
    {
        string[] memory healthIssues = new string[](10);
        uint256 issueCount = 0;
        
        // Check if there's at least one admin
        if (_roleMemberCounts[Constants.ADMIN_ROLE] == 0) {
            healthIssues[issueCount] = "No admin accounts";
            issueCount++;
        }
        
        // Check if contract is paused for too long
        if (paused() && emergencyPauseCount > 5) {
            healthIssues[issueCount] = "Too many emergency pauses";
            issueCount++;
        }
        
        // Create result array with actual issues
        string[] memory actualIssues = new string[](issueCount);
        for (uint256 i = 0; i < issueCount; i++) {
            actualIssues[i] = healthIssues[i];
        }
        
        return (issueCount == 0, actualIssues);
    }
    
    // ============ INTERNAL FUNCTIONS ============
    
    /**
     * @dev Internal function to grant role with tracking
     */
    function _grantRoleWithTracking(bytes32 role, address account) internal {
        bool hadRole = hasRole(role, account);
        _grantRole(role, account);
        
        // Update role member tracking
        if (!hadRole) {
            _roleMembers[role][account] = true;
            _roleMemberCounts[role]++;
        }
    }
    
    /**
     * @dev Internal function to revoke role with tracking
     */
    function _revokeRoleWithTracking(bytes32 role, address account) internal {
        bool hadRole = hasRole(role, account);
        _revokeRole(role, account);
        
        // Update role member tracking
        if (hadRole) {
            _roleMembers[role][account] = false;
            if (_roleMemberCounts[role] > 0) {
                _roleMemberCounts[role]--;
            }
        }
    }
    
    /**
     * @dev Gets the number of accounts that have a specific role
     * @param role The role to count
     * @return count The number of accounts with the role
     */
    function getRoleMemberCount(bytes32 role) public view returns (uint256 count) {
        return _roleMemberCounts[role];
    }
    
    // ============ UPGRADE FUNCTIONS ============
    
    /**
     * @dev Authorizes contract upgrades (only upgraders can authorize)
     * @param newImplementation The new implementation address
     */
    function _authorizeUpgrade(address newImplementation) internal view onlyUpgrader {
        // Additional upgrade validation can be added here
        if (newImplementation == address(0)) {
            revert CustomErrors.InvalidUpgradeImplementation(newImplementation);
        }
    }
    
    /**
     * @dev Returns the version of the contract
     * @return version The contract version
     */
    function version() external pure returns (string memory) {
        return "1.0.0";
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;


    /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
    struct AccessControlStorage {
        mapping(bytes32 role => RoleData) _roles;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;

    function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
        assembly {
            $.slot := AccessControlStorageLocation
        }
    }

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    function __AccessControl_init() internal onlyInitializing {
    }

    function __AccessControl_init_unchained() internal onlyInitializing {
    }
    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        return $._roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        return $._roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual {
        if (callerConfirmation != _msgSender()) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        AccessControlStorage storage $ = _getAccessControlStorage();
        bytes32 previousAdminRole = getRoleAdmin(role);
        $._roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        if (!hasRole(role, account)) {
            $._roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        if (hasRole(role, account)) {
            $._roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reinitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._initialized = version;
        $._initializing = true;
        _;
        $._initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
     *
     * NOTE: Consider following the ERC-7201 formula to derive storage locations.
     */
    function _initializableStorageSlot() internal pure virtual returns (bytes32) {
        return INITIALIZABLE_STORAGE;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        bytes32 slot = _initializableStorageSlot();
        assembly {
            $.slot := slot
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165Upgradeable is Initializable, IERC165 {
    function __ERC165_init() internal onlyInitializing {
    }

    function __ERC165_init_unchained() internal onlyInitializing {
    }
    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Pausable.sol)

pragma solidity ^0.8.20;

import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
    /// @custom:storage-location erc7201:openzeppelin.storage.Pausable
    struct PausableStorage {
        bool _paused;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;

    function _getPausableStorage() private pure returns (PausableStorage storage $) {
        assembly {
            $.slot := PausableStorageLocation
        }
    }

    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    /**
     * @dev The operation failed because the contract is paused.
     */
    error EnforcedPause();

    /**
     * @dev The operation failed because the contract is not paused.
     */
    error ExpectedPause();

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    function __Pausable_init() internal onlyInitializing {
    }

    function __Pausable_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        PausableStorage storage $ = _getPausableStorage();
        return $._paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        if (paused()) {
            revert EnforcedPause();
        }
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert ExpectedPause();
        }
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        PausableStorage storage $ = _getPausableStorage();
        $._paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        PausableStorage storage $ = _getPausableStorage();
        $._paused = false;
        emit Unpaused(_msgSender());
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuardUpgradeable is Initializable {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
    struct ReentrancyGuardStorage {
        uint256 _status;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

    function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
        assembly {
            $.slot := ReentrancyGuardStorageLocation
        }
    }

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        $._status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if ($._status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        $._status = ENTERED;
    }

    function _nonReentrantAfter() private {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        $._status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        return $._status == ENTERED;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/IAccessControl.sol)

pragma solidity >=0.8.4;

/**
 * @dev External interface of AccessControl declared to support ERC-165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted to signal this.
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
     * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 10 of 11 : Constants.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

/**
 * @title Constants
 * @dev System constants for the Cross-Chain NFT Trading Platform
 * @author Blocklabs Studio
 */
library Constants {
    
    // ============ ROLE CONSTANTS ============
    
    /// @dev Admin role - Full platform control and role management
    bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
    
    /// @dev Project admin role - NFT project management and whitelist control
    bytes32 public constant PROJECT_ADMIN_ROLE = keccak256("PROJECT_ADMIN_ROLE");
    
    /// @dev Fee manager role - Fee configuration and collection management
    bytes32 public constant FEE_MANAGER_ROLE = keccak256("FEE_MANAGER_ROLE");
    
    /// @dev Emergency role - Pause/unpause and emergency functions
    bytes32 public constant EMERGENCY_ROLE = keccak256("EMERGENCY_ROLE");
    
    /// @dev Upgrader role - Contract upgrade authorization
    bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");
    
    // ============ TIME CONSTANTS ============
    
    /// @dev Minimum offer duration (1 hour)
    uint256 public constant MIN_OFFER_DURATION = 1 hours;
    
    /// @dev Maximum offer duration (30 days)
    uint256 public constant MAX_OFFER_DURATION = 30 days;
    
    /// @dev Same-chain settlement timeout (1 hour)
    uint256 public constant SAME_CHAIN_TIMEOUT = 1 hours;
    
    /// @dev Default cross-chain settlement timeout (24 hours)
    uint256 public constant CROSS_CHAIN_TIMEOUT = 24 hours;
    
    /// @dev Maximum cross-chain settlement timeout (72 hours)
    uint256 public constant MAX_CROSS_CHAIN_TIMEOUT = 72 hours;
    
    /// @dev Minimum cross-chain settlement timeout (1 hour)
    uint256 public constant MIN_CROSS_CHAIN_TIMEOUT = 1 hours;
    
    // ============ UPGRADE TIMELOCK CONSTANTS ============
    
    /// @dev Major upgrade timelock delay (48 hours)
    uint256 public constant MAJOR_UPGRADE_DELAY = 48 hours;
    
    /// @dev Minor upgrade timelock delay (24 hours)
    uint256 public constant MINOR_UPGRADE_DELAY = 24 hours;
    
    /// @dev Emergency upgrade delay (6 hours)
    uint256 public constant EMERGENCY_UPGRADE_DELAY = 6 hours;
    
    /// @dev Parameter change delay (12 hours)
    uint256 public constant PARAMETER_CHANGE_DELAY = 12 hours;
    
    // ============ FEE CONSTANTS ============
    
    /// @dev Maximum platform fee (10% in basis points)
    uint256 public constant MAX_PLATFORM_FEE = 1000;
    
    /// @dev Default platform fee (2.5% in basis points)
    uint256 public constant DEFAULT_PLATFORM_FEE = 250;
    
    /// @dev Basis points denominator (100% = 10000)
    uint256 public constant BASIS_POINTS = 10000;
    
    /// @dev Maximum royalty percentage (10% in basis points)
    uint256 public constant MAX_ROYALTY_PERCENT = 1000;
    
    // ============ NETWORK-SPECIFIC MINIMUM FEES ============
    
    /// @dev Ethereum minimum fee (0.001 ETH)
    uint256 public constant ETHEREUM_MIN_FEE = 0.001 ether;
    
    /// @dev Polygon minimum fee (1 MATIC)
    uint256 public constant POLYGON_MIN_FEE = 1 ether;
    
    /// @dev Arbitrum minimum fee (0.001 ETH)
    uint256 public constant ARBITRUM_MIN_FEE = 0.001 ether;
    
    /// @dev Optimism minimum fee (0.001 ETH)
    uint256 public constant OPTIMISM_MIN_FEE = 0.001 ether;
    
    /// @dev Base minimum fee (0.001 ETH)
    uint256 public constant BASE_MIN_FEE = 0.001 ether;
    
    /// @dev ApeChain minimum fee (1 APE)
    uint256 public constant APECHAIN_MIN_FEE = 1 ether;
    
    // ============ GAS CONSTANTS ============
    
    /// @dev Maximum gas limit for cross-chain operations
    uint256 public constant MAX_GAS_LIMIT = 500000;
    
    /// @dev Default gas limit for cross-chain operations
    uint256 public constant DEFAULT_GAS_LIMIT = 200000;
    
    /// @dev Minimum gas limit for cross-chain operations
    uint256 public constant MIN_GAS_LIMIT = 50000;
    
    /// @dev Gas buffer for cross-chain operations (20%)
    uint256 public constant GAS_BUFFER_PERCENT = 2000; // 20% in basis points
    
    // ============ ARRAY AND BATCH LIMITS ============
    
    /// @dev Maximum assets per offer
    uint256 public constant MAX_ASSETS_PER_OFFER = 10;
    
    /// @dev Maximum batch size for operations
    uint256 public constant MAX_BATCH_SIZE = 50;
    
    /// @dev Maximum offers per user query
    uint256 public constant MAX_USER_OFFERS_QUERY = 100;
    
    // ============ SIGNATURE CONSTANTS ============
    
    /// @dev EIP-712 domain name
    string public constant EIP712_DOMAIN_NAME = "CrossChainNFTTrading";
    
    /// @dev EIP-712 domain version
    string public constant EIP712_DOMAIN_VERSION = "1.0";
    
    /// @dev Maximum signature validity period (1 hour)
    uint256 public constant MAX_SIGNATURE_VALIDITY = 1 hours;
    
    // ============ CHAIN ID CONSTANTS ============
    
    /// @dev Ethereum mainnet chain ID
    uint256 public constant ETHEREUM_CHAIN_ID = 1;
    
    /// @dev Arbitrum mainnet chain ID
    uint256 public constant ARBITRUM_CHAIN_ID = 42161;
    
    /// @dev Polygon mainnet chain ID
    uint256 public constant POLYGON_CHAIN_ID = 137;
    
    /// @dev Optimism mainnet chain ID
    uint256 public constant OPTIMISM_CHAIN_ID = 10;
    
    /// @dev Base mainnet chain ID
    uint256 public constant BASE_CHAIN_ID = 8453;
    
    // ============ LAYERZERO CONSTANTS ============
    
    /// @dev LayerZero message gas limit buffer
    uint256 public constant LZ_GAS_BUFFER = 50000;
    
    /// @dev Maximum LayerZero message payload size
    uint256 public constant MAX_LZ_PAYLOAD_SIZE = 10000;
    
    /// @dev LayerZero message retry limit
    uint256 public constant LZ_RETRY_LIMIT = 3;
    
    // ============ SECURITY CONSTANTS ============
    
    /// @dev Maximum failed attempts before temporary ban
    uint256 public constant MAX_FAILED_ATTEMPTS = 5;
    
    /// @dev Temporary ban duration (1 hour)
    uint256 public constant TEMP_BAN_DURATION = 1 hours;
    
    /// @dev Maximum concurrent offers per user
    uint256 public constant MAX_CONCURRENT_OFFERS = 20;
    
    // ============ UPGRADE GOVERNANCE CONSTANTS ============
    
    /// @dev Required signatures for upgrades (3 out of 5)
    uint256 public constant REQUIRED_SIGNATURES = 3;
    
    /// @dev Total number of upgrade signers
    uint256 public constant TOTAL_SIGNERS = 5;
    
    /// @dev Proposal validity period (7 days)
    uint256 public constant PROPOSAL_VALIDITY_PERIOD = 7 days;
    
    // ============ ASSET VALIDATION CONSTANTS ============
    
    /// @dev Maximum token ID for validation (prevents overflow)
    uint256 public constant MAX_TOKEN_ID = type(uint128).max;
    
    /// @dev Maximum amount for ERC20/1155 transfers
    uint256 public constant MAX_ASSET_AMOUNT = type(uint128).max;
    
    /// @dev Zero address constant
    address public constant ZERO_ADDRESS = address(0);
    
    // ============ ERROR MESSAGES ============
    
    /// @dev Common error messages as constants to save gas
    string public constant ERROR_UNAUTHORIZED = "Unauthorized access";
    string public constant ERROR_INVALID_OFFER = "Invalid offer parameters";
    string public constant ERROR_EXPIRED_OFFER = "Offer has expired";
    string public constant ERROR_INSUFFICIENT_BALANCE = "Insufficient balance";
    string public constant ERROR_TRANSFER_FAILED = "Asset transfer failed";
    string public constant ERROR_INVALID_SIGNATURE = "Invalid signature";
    string public constant ERROR_ALREADY_EXECUTED = "Already executed";
    string public constant ERROR_PAUSED = "Contract is paused";
    string public constant ERROR_BLACKLISTED = "Address is blacklisted";
    string public constant ERROR_INVALID_CHAIN = "Invalid chain ID";
    string public constant ERROR_GAS_LIMIT_EXCEEDED = "Gas limit exceeded";
    
    // ============ EVENT SIGNATURE HASHES ============
    
    /// @dev Pre-computed event signature hashes for gas optimization
    bytes32 public constant OFFER_CREATED_HASH = keccak256("OfferCreated(uint256,address,address,uint256)");
    bytes32 public constant OFFER_ACCEPTED_HASH = keccak256("OfferAccepted(uint256,address,uint256)");
    bytes32 public constant OFFER_CANCELLED_HASH = keccak256("OfferCancelled(uint256,address,uint256)");
    bytes32 public constant ASSETS_SWAPPED_HASH = keccak256("AssetsSwapped(uint256,address,address,uint256)");
    bytes32 public constant CROSS_CHAIN_MESSAGE_SENT_HASH = keccak256("CrossChainMessageSent(uint256,uint256,bytes32)");
    bytes32 public constant CROSS_CHAIN_MESSAGE_RECEIVED_HASH = keccak256("CrossChainMessageReceived(uint256,uint256,bytes32)");
}

File 11 of 11 : Errors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

/**
 * @title Errors
 * @dev Custom error definitions for the Cross-Chain NFT Trading Platform
 * @author Blocklabs Studio
 */
library CustomErrors {
    
    // ============ ACCESS CONTROL ERRORS ============
    
    /// @dev Thrown when caller lacks required role
    error UnauthorizedAccess(address caller, bytes32 requiredRole);
    
    /// @dev Thrown when trying to grant role to zero address
    error InvalidRoleRecipient(address recipient);
    
    /// @dev Thrown when role operation fails
    error RoleOperationFailed(bytes32 role, address account);
    
    // ============ OFFER MANAGEMENT ERRORS ============
    
    /// @dev Thrown when offer ID doesn't exist
    error OfferNotFound(uint256 offerId);
    
    /// @dev Thrown when offer has expired
    error OfferExpired(uint256 offerId, uint256 expirationTime);
    
    /// @dev Thrown when offer is not in expected status
    error InvalidOfferStatus(uint256 offerId, uint8 currentStatus, uint8 expectedStatus);
    
    /// @dev Thrown when offer creator tries to accept their own offer
    error CannotAcceptOwnOffer(uint256 offerId, address creator);
    
    /// @dev Thrown when non-counterparty tries to accept private offer
    error UnauthorizedOfferAcceptance(uint256 offerId, address caller, address expectedCounterparty);
    
    /// @dev Thrown when offer has invalid parameters
    error InvalidOfferParameters(string reason);
    
    /// @dev Thrown when offer duration is invalid
    error InvalidOfferDuration(uint256 duration, uint256 minDuration, uint256 maxDuration);
    
    /// @dev Thrown when too many assets in offer
    error TooManyAssets(uint256 assetCount, uint256 maxAssets);
    
    /// @dev Thrown when offer has no assets
    error EmptyAssetArray();
    
    // ============ ASSET VALIDATION ERRORS ============
    
    /// @dev Thrown when asset contract doesn't exist
    error AssetContractNotFound(address tokenContract);
    
    /// @dev Thrown when asset doesn't comply with expected standard
    error AssetStandardMismatch(address tokenContract, uint8 expectedStandard);
    
    /// @dev Thrown when caller doesn't own the asset
    error AssetOwnershipMismatch(address tokenContract, uint256 tokenId, address owner, address caller);
    
    /// @dev Thrown when asset transfer is not approved
    error AssetTransferNotApproved(address tokenContract, uint256 tokenId, address owner, address spender);
    
    /// @dev Thrown when asset is blacklisted
    error AssetBlacklisted(address tokenContract, uint256 tokenId);
    
    /// @dev Thrown when asset amount is invalid
    error InvalidAssetAmount(uint256 amount, uint256 minAmount, uint256 maxAmount);
    
    /// @dev Thrown when asset type is invalid
    error InvalidAssetType(uint8 assetType);
    
    /// @dev Thrown when native asset amount doesn't match msg.value
    error NativeAssetAmountMismatch(uint256 expected, uint256 actual);
    
    // ============ CROSS-CHAIN ERRORS ============
    
    /// @dev Thrown when chain ID is not supported
    error UnsupportedChainId(uint256 chainId);
    
    /// @dev Thrown when cross-chain message fails
    error CrossChainMessageFailed(uint256 destinationChain, bytes32 messageHash);
    
    /// @dev Thrown when LayerZero endpoint is not set
    error LayerZeroEndpointNotSet(uint256 chainId);
    
    /// @dev Thrown when cross-chain settlement times out
    error CrossChainSettlementTimeout(uint256 offerId, uint256 timelock);
    
    /// @dev Thrown when hashlock doesn't match
    error HashlockMismatch(bytes32 expected, bytes32 actual);
    
    /// @dev Thrown when cross-chain settlement is in wrong state
    error InvalidSettlementState(uint256 offerId, uint8 currentState, uint8 expectedState);
    
    /// @dev Thrown when gas limit is insufficient
    error InsufficientGasLimit(uint256 provided, uint256 required);
    
    /// @dev Thrown when cross-chain fee is insufficient
    error InsufficientCrossChainFee(uint256 provided, uint256 required);
    
    // ============ FEE MANAGEMENT ERRORS ============
    
    /// @dev Thrown when fee percentage exceeds maximum
    error FeePercentageTooHigh(uint256 feePercent, uint256 maxFeePercent);
    
    /// @dev Thrown when fee recipient is zero address
    error InvalidFeeRecipient(address recipient);
    
    /// @dev Thrown when fee payment fails
    error FeePaymentFailed(address recipient, uint256 amount);
    
    /// @dev Thrown when insufficient fee provided
    error InsufficientFee(uint256 provided, uint256 required);
    
    /// @dev Thrown when fee token is not supported
    error UnsupportedFeeToken(address token);
    
    // ============ SIGNATURE VALIDATION ERRORS ============
    
    /// @dev Thrown when signature is invalid
    error InvalidSignature(address signer, bytes32 hash);
    
    /// @dev Thrown when signature has expired
    error SignatureExpired(uint256 deadline, uint256 currentTime);
    
    /// @dev Thrown when nonce has already been used
    error NonceAlreadyUsed(address signer, uint256 nonce);
    
    /// @dev Thrown when signature format is invalid
    error InvalidSignatureFormat();
    
    /// @dev Thrown when domain separator is invalid
    error InvalidDomainSeparator();
    
    // ============ ESCROW ERRORS ============
    
    /// @dev Thrown when asset deposit fails
    error AssetDepositFailed(address tokenContract, uint256 tokenId, uint256 amount);
    
    /// @dev Thrown when asset withdrawal fails
    error AssetWithdrawalFailed(address tokenContract, uint256 tokenId, uint256 amount);
    
    /// @dev Thrown when escrow balance is insufficient
    error InsufficientEscrowBalance(address tokenContract, uint256 tokenId, uint256 required, uint256 available);
    
    /// @dev Thrown when settlement fails
    error SettlementFailed(uint256 offerId, string reason);
    
    /// @dev Thrown when atomic swap fails
    error AtomicSwapFailed(uint256 offerId, string reason);
    
    // ============ UPGRADE ERRORS ============
    
    /// @dev Thrown when upgrade proposal doesn't exist
    error UpgradeProposalNotFound(uint256 proposalId);
    
    /// @dev Thrown when upgrade proposal has expired
    error UpgradeProposalExpired(uint256 proposalId, uint256 expirationTime);
    
    /// @dev Thrown when upgrade proposal is not ready for execution
    error UpgradeProposalNotReady(uint256 proposalId, uint256 executionTime);
    
    /// @dev Thrown when insufficient signatures for upgrade
    error InsufficientUpgradeSignatures(uint256 proposalId, uint256 signatures, uint256 required);
    
    /// @dev Thrown when upgrade implementation is invalid
    error InvalidUpgradeImplementation(address implementation);
    
    /// @dev Thrown when upgrade has already been executed
    error UpgradeAlreadyExecuted(uint256 proposalId);
    
    /// @dev Thrown when upgrade rollback fails
    error UpgradeRollbackFailed(uint256 proposalId, string reason);
    
    // ============ SECURITY ERRORS ============
    
    /// @dev Thrown when contract is paused
    error ContractPaused();
    
    /// @dev Thrown when address is blacklisted
    error AddressBlacklisted(address account);
    
    /// @dev Thrown when operation exceeds rate limit
    error RateLimitExceeded(address account, uint256 attempts, uint256 limit);
    
    /// @dev Thrown when reentrancy is detected
    error ReentrancyDetected();
    
    /// @dev Thrown when emergency stop is active
    error EmergencyStopActive();
    
    /// @dev Thrown when operation is not allowed during emergency
    error OperationNotAllowedDuringEmergency();
    
    // ============ GENERAL ERRORS ============
    
    /// @dev Thrown when zero address is provided where not allowed
    error ZeroAddressNotAllowed();
    
    /// @dev Thrown when array lengths don't match
    error ArrayLengthMismatch(uint256 length1, uint256 length2);
    
    /// @dev Thrown when array is empty when it shouldn't be
    error EmptyArray();
    
    /// @dev Thrown when array index is out of bounds
    error IndexOutOfBounds(uint256 index, uint256 length);
    
    /// @dev Thrown when value is out of valid range
    error ValueOutOfRange(uint256 value, uint256 min, uint256 max);
    
    /// @dev Thrown when operation times out
    error OperationTimeout(uint256 deadline, uint256 currentTime);
    
    /// @dev Thrown when duplicate entry is detected
    error DuplicateEntry(bytes32 key);
    
    /// @dev Thrown when required condition is not met
    error ConditionNotMet(string condition);
    
    /// @dev Thrown when external call fails
    error ExternalCallFailed(address target, bytes data);
    
    /// @dev Thrown when initialization fails
    error InitializationFailed(string reason);
    
    /// @dev Thrown when contract is already initialized
    error AlreadyInitialized();
    
    /// @dev Thrown when function is not implemented
    error NotImplemented();
    
    /// @dev Thrown when operation is not supported
    error OperationNotSupported(string operation);
    
    // ============ PROXY ERRORS ============
    
    /// @dev Thrown when implementation is not found
    error ImplementationNotFound(string name);
    
    /// @dev Thrown when proxy already exists
    error ProxyAlreadyExists(string name);
    
    /// @dev Thrown when proxy is not found
    error ProxyNotFound(string name);
    
    /// @dev Thrown when implementation is invalid
    error InvalidImplementation(address implementation);
    
    /// @dev Thrown when string is empty
    error EmptyString();
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1000
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"uint256","name":"length1","type":"uint256"},{"internalType":"uint256","name":"length2","type":"uint256"}],"name":"ArrayLengthMismatch","type":"error"},{"inputs":[],"name":"EmptyArray","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"InvalidRoleRecipient","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"RoleOperationFailed","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"bytes32","name":"requiredRole","type":"bytes32"}],"name":"UnauthorizedAccess","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"EmergencyPauseActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"EmergencyPauseDeactivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RoleGrantedWithContext","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RoleRevokedWithContext","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"roles","type":"bytes32[]"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"batchGrantRoles","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"roles","type":"bytes32[]"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"batchRevokeRoles","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"checkContractHealth","outputs":[{"internalType":"bool","name":"isHealthy","type":"bool"},{"internalType":"string[]","name":"issues","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deploymentTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyPauseCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"emergencyPauseHistory","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyUnpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountRoles","outputs":[{"internalType":"bytes32[]","name":"roles","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractStats","outputs":[{"internalType":"uint256","name":"totalRoleAssignments","type":"uint256"},{"internalType":"uint256","name":"totalEmergencyPauses","type":"uint256"},{"internalType":"uint256","name":"contractAge","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"getRoleAssignmentTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRoleWithValidation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"hasAdminPrivileges","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"initialAdmin","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRoleWithValidation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"roleAssignmentTimestamps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"}]

0x6080604052348015600f57600080fd5b506123bb8061001f6000396000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c80637f78bc43116100ee578063c0fded2411610097578063cacebadc11610071578063cacebadc1461042e578063d547741f1461044e578063dfe6b5d614610461578063f3a8c79d1461048457600080fd5b8063c0fded24146103e8578063c4d66de8146103fb578063ca15c8731461040e57600080fd5b8063a217fddf116100c8578063a217fddf146103c4578063bda21260146103cc578063bfc12c05146103df57600080fd5b80637f78bc431461033357806391d148541461035b5780639622f7bb146103a157600080fd5b80632f2ff15d1161015b57806351858e271161013557806351858e27146102af57806354fd4d50146102b75780635c975abb146102f65780636200354a1461032057600080fd5b80632f2ff15d1461028157806336568abe146102945780634a4e3bd5146102a757600080fd5b8063248a9ca31161018c578063248a9ca3146102075780632553e0aa1461023757806327a69dad1461026b57600080fd5b806301ffc9a7146101b35780630343b3b5146101db578063073dddf6146101f2575b600080fd5b6101c66101c136600461202c565b610497565b60405190151581526020015b60405180910390f35b6101e460025481565b6040519081526020016101d2565b610205610200366004612091565b610530565b005b6101e46102153660046120bd565b6000908152600080516020612346833981519152602052604090206001015490565b6101e4610245366004612091565b6000918252602082815260408084206001600160a01b0393909316845291905290205490565b6102736106be565b6040516101d292919061211c565b61020561028f366004612091565b6108d8565b6102056102a2366004612091565b610910565b610205610961565b610205610a06565b604080518082018252600581527f312e302e30000000000000000000000000000000000000000000000000000000602082015290516101d2919061218a565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff166101c6565b61020561032e3660046121e9565b610b27565b6101e4610341366004612091565b600060208181529281526040808220909352908152205481565b6101c6610369366004612091565b6000918252600080516020612346833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6101c66103af3660046120bd565b60016020526000908152604090205460ff1681565b6101e4600081565b6101c66103da36600461225a565b610dd9565b6101e460035481565b6102056103f63660046121e9565b610f20565b61020561040936600461225a565b611201565b6101e461041c3660046120bd565b60009081526004602052604090205490565b61044161043c36600461225a565b61148d565b6040516101d29190612275565b61020561045c366004612091565b611762565b610469611794565b604080519384526020840192909252908201526060016101d2565b610205610492366004612091565b6118a5565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061052a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff1661059a57604051630dcd852560e31b815233600482015260008051602061236683398151915260248201526044015b60405180910390fd5b6105a26119f6565b6001600160a01b0381166105d457604051631f5cf20560e11b81526001600160a01b0382166004820152602401610591565b600080516020612366833981519152821480156105f957506001600160a01b03811633145b1561062957604051638293991b60e01b8152600481018390526001600160a01b0382166024820152604401610591565b6106338282611a59565b6000828152602081815260408083206001600160a01b038516808552908352928190204290819055905190815233929185917ff4b4e62d80a4a1502357b01edf05f517c2fe3e4afd8b89c0418ee45fe182f4fe91015b60405180910390a46106ba60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5050565b60408051600a80825261016082019092526000916060918391816020015b60608152602001906001900390816106dc575050600080516020612366833981519152600090815260046020527f49b573c16d0a3fe96af74a58679870c9f48517274761ed80ca9ceccb8126cb7354919250908103610797576040518060400160405280601181526020017f4e6f2061646d696e206163636f756e747300000000000000000000000000000081525082828151811061077d5761077d6122c3565b60200260200101819052508080610793906122ef565b9150505b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1680156107ca57506005600254115b15610831576040518060400160405280601981526020017f546f6f206d616e7920656d657267656e63792070617573657300000000000000815250828281518110610817576108176122c3565b6020026020010181905250808061082d906122ef565b9150505b60008167ffffffffffffffff81111561084c5761084c6122ad565b60405190808252806020026020018201604052801561087f57816020015b606081526020019060019003908161086a5790505b50905060005b828110156108cc5783818151811061089f5761089f6122c3565b60200260200101518282815181106108b9576108b96122c3565b6020908102919091010152600101610885565b50901594909350915050565b6000828152600080516020612346833981519152602052604090206001015461090081611b0f565b61090a8383611b1c565b50505050565b6001600160a01b0381163314610952576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61095c8282611bd9565b505050565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff166109c657604051630dcd852560e31b81523360048201526000805160206123668339815191526024820152604401610591565b6109ce611c6d565b60405142815233907fdb5c0bc39850eb0ddb99fae67eecd7ee594120d92d1c0db6c3252252a4fc3356906020015b60405180910390a2565b3360009081527f762c7c328dd70a077c65c77b60e4c38eed3d2f6aa056d4d0fa114aeff8234b56602052604090205460ff16158015610a7457503360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff16155b15610aba57604051630dcd852560e31b81523360048201527fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b266024820152604401610591565b610ac2611cdf565b60028054906000610ad2836122ef565b9091555050600254600090815260016020818152604092839020805460ff1916909217909155905142815233917f9506e519f3e4ce17dda1136d3ba3d3465dc873c49a6191e0fd209f33959a00cd91016109fc565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff16610b8c57604051630dcd852560e31b81523360048201526000805160206123668339815191526024820152604401610591565b610b946119f6565b828114610bbe57604051631f4bb7c160e31b81526004810184905260248101829052604401610591565b6000839003610be05760405163521299a960e01b815260040160405180910390fd5b60005b83811015610daf576000838383818110610bff57610bff6122c3565b9050602002016020810190610c14919061225a565b6001600160a01b031603610c6e57828282818110610c3457610c346122c3565b9050602002016020810190610c49919061225a565b604051631f5cf20560e11b81526001600160a01b039091166004820152602401610591565b610cb6858583818110610c8357610c836122c3565b90506020020135848484818110610c9c57610c9c6122c3565b9050602002016020810190610cb1919061225a565b611a59565b42600080878785818110610ccc57610ccc6122c3565b9050602002013581526020019081526020016000206000858585818110610cf557610cf56122c3565b9050602002016020810190610d0a919061225a565b6001600160a01b0316815260208101919091526040016000205533838383818110610d3757610d376122c3565b9050602002016020810190610d4c919061225a565b6001600160a01b0316868684818110610d6757610d676122c3565b905060200201357ff4b4e62d80a4a1502357b01edf05f517c2fe3e4afd8b89c0418ee45fe182f4fe42604051610d9f91815260200190565b60405180910390a4600101610be3565b5061090a60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6001600160a01b03811660009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604081205460ff1680610e5657506001600160a01b03821660009081527f2dc5c9fd9d70e2ee51b9e4ead45cd5e8c0d85f8c9a23f31c5c0c1222dff10771602052604090205460ff165b80610e9857506001600160a01b03821660009081527f294f263e68a44628370ca7eca46e11f3043892ee36ff7375f356adc9c8117805602052604090205460ff165b80610eda57506001600160a01b03821660009081527f762c7c328dd70a077c65c77b60e4c38eed3d2f6aa056d4d0fa114aeff8234b56602052604090205460ff165b8061052a57506001600160a01b03821660009081527fab71e3f32666744d246edff3f96e4bdafee2e9867098cdd118a979a7464786a8602052604090205460ff1661052a565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff16610f8557604051630dcd852560e31b81523360048201526000805160206123668339815191526024820152604401610591565b610f8d6119f6565b828114610fb757604051631f4bb7c160e31b81526004810184905260248101829052604401610591565b6000839003610fd95760405163521299a960e01b815260040160405180910390fd5b60005b83811015610daf57600080516020612366833981519152858583818110611005576110056122c3565b90506020020135036110bf5760008051602061236683398151915260005260046020527f49b573c16d0a3fe96af74a58679870c9f48517274761ed80ca9ceccb8126cb7354600181116110bd57858583818110611064576110646122c3565b9050602002013584848481811061107d5761107d6122c3565b9050602002016020810190611092919061225a565b604051638293991b60e01b815260048101929092526001600160a01b03166024820152604401610591565b505b6111078585838181106110d4576110d46122c3565b905060200201358484848181106110ed576110ed6122c3565b9050602002016020810190611102919061225a565b611d3a565b600080600087878581811061111e5761111e6122c3565b9050602002013581526020019081526020016000206000858585818110611147576111476122c3565b905060200201602081019061115c919061225a565b6001600160a01b0316815260208101919091526040016000205533838383818110611189576111896122c3565b905060200201602081019061119e919061225a565b6001600160a01b03168686848181106111b9576111b96122c3565b905060200201357f53d12e54e6f700315abaeac32c6c176e7a16c4b913a903dc041270bf50a6cef5426040516111f191815260200190565b60405180910390a4600101610fdc565b600061120b611dd2565b805490915060ff68010000000000000000820416159067ffffffffffffffff166000811580156112385750825b905060008267ffffffffffffffff1660011480156112555750303b155b905081158015611263575080155b1561129a576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156112ce57845468ff00000000000000001916680100000000000000001785555b6001600160a01b03861661130e576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611316611dfb565b61131e611dfb565b611326611e05565b61133e60008051602061236683398151915280611e15565b6113767f52eafc11f6f81f86878bffd31109a0d92f37506527754f00788853ff9f63b130600080516020612366833981519152611e15565b6113ae7f6c0757dc3e6b28b2580c03fd9e96c274acf4f99d91fbec9b418fa1d70604ff1c600080516020612366833981519152611e15565b6113e67fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b26600080516020612366833981519152611e15565b61141e7f189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e3600080516020612366833981519152611e15565b61143660008051602061236683398151915287611a59565b42600355831561148557845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b60408051600580825260c08201909252606091600091906020820160a080368337019050509050600080516020612366833981519152816000815181106114d6576114d66122c3565b6020026020010181815250507f52eafc11f6f81f86878bffd31109a0d92f37506527754f00788853ff9f63b13081600181518110611516576115166122c3565b6020026020010181815250507f6c0757dc3e6b28b2580c03fd9e96c274acf4f99d91fbec9b418fa1d70604ff1c81600281518110611556576115566122c3565b6020026020010181815250507fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b2681600381518110611596576115966122c3565b6020026020010181815250507f189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e3816004815181106115d6576115d66122c3565b6020026020010181815250506000805b825181101561165d57611642838281518110611604576116046122c3565b6020908102919091018101516000908152600080516020612346833981519152825260408082206001600160a01b038a168352909252205460ff1690565b156116555781611651816122ef565b9250505b6001016115e6565b5060008167ffffffffffffffff811115611679576116796122ad565b6040519080825280602002602001820160405280156116a2578160200160208202803683370190505b5090506000805b8451811015611757576117058582815181106116c7576116c76122c3565b6020908102919091018101516000908152600080516020612346833981519152825260408082206001600160a01b038c168352909252205460ff1690565b1561174f5784818151811061171c5761171c6122c3565b6020026020010151838381518110611736576117366122c3565b60209081029190910101528161174b816122ef565b9250505b6001016116a9565b509095945050505050565b6000828152600080516020612346833981519152602052604090206001015461178a81611b0f565b61090a8383611bd9565b60046020527f7bc9e7a6bba5a59ca6616f4e700d2f3a4e51ca8434b2a6aec5b26336fe4d123a547fc75256a229fdd20b6fa63bf91cbbb3f0b9280a66959f4dd898c14fd291fcb191547f9c1b7d0908e3b14d43ceb18bc61be39053ce951144a163c5064b1204790f7c61547f9e3fbaa213cebb710763a0e4681162cb632cda9982e46ad66f2320625a75da3b5460008051602061236683398151915260009081527f49b573c16d0a3fe96af74a58679870c9f48517274761ed80ca9ceccb8126cb73549094859485949193909261186b9190612308565b6118759190612308565b61187f9190612308565b6118899190612308565b925060025491506003544261189e919061231b565b9050909192565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff1661190a57604051630dcd852560e31b81523360048201526000805160206123668339815191526024820152604401610591565b6119126119f6565b60008051602061236683398151915282036119955760008051602061236683398151915260005260046020527f49b573c16d0a3fe96af74a58679870c9f48517274761ed80ca9ceccb8126cb73546001811161199357604051638293991b60e01b8152600481018490526001600160a01b0383166024820152604401610591565b505b61199f8282611d3a565b6000828152602081815260408083206001600160a01b038516808552908352818420939093555142815233929185917f53d12e54e6f700315abaeac32c6c176e7a16c4b913a903dc041270bf50a6cef59101610689565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805460011901611a53576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60029055565b6000828152600080516020612346833981519152602090815260408083206001600160a01b038516845290915290205460ff16611a968383611b1c565b508061095c5760008381526005602090815260408083206001600160a01b03861684528252808320805460ff1916600117905585835260049091528120805491611adf836122ef565b9190505550505050565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b611b198133611e95565b50565b6000828152600080516020612346833981519152602081815260408084206001600160a01b038616855290915282205460ff16611bcf576000848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055611b853390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4600191505061052a565b600091505061052a565b6000828152600080516020612346833981519152602081815260408084206001600160a01b038616855290915282205460ff1615611bcf576000848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4600191505061052a565b611c75611f10565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b611ce7611f6b565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833611cc1565b6000828152600080516020612346833981519152602090815260408083206001600160a01b038516845290915290205460ff16611d778383611bd9565b50801561095c5760008381526005602090815260408083206001600160a01b03861684528252808320805460ff1916905585835260049091529020541561095c576000838152600460205260408120805491611adf8361232e565b6000807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0061052a565b611e03611fc7565b565b611e0d611fc7565b611e03612005565b6000805160206123468339815191526000611e4c846000908152600080516020612346833981519152602052604090206001015490565b600085815260208490526040808220600101869055519192508491839187917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a450505050565b6000828152600080516020612346833981519152602090815260408083206001600160a01b038516845290915290205460ff166106ba576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401610591565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16611e03576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1615611e03576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611fcf61200d565b611e03576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ae9611fc7565b6000612017611dd2565b5468010000000000000000900460ff16919050565b60006020828403121561203e57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461206e57600080fd5b9392505050565b80356001600160a01b038116811461208c57600080fd5b919050565b600080604083850312156120a457600080fd5b823591506120b460208401612075565b90509250929050565b6000602082840312156120cf57600080fd5b5035919050565b6000815180845260005b818110156120fc576020818501810151868301820152016120e0565b506000602082860101526020601f19601f83011685010191505092915050565b60006040820184151583526040602084015280845180835260608501915060608160051b86010192506020860160005b8281101561217d57605f198786030184526121688583516120d6565b9450602093840193919091019060010161214c565b5092979650505050505050565b60208152600061206e60208301846120d6565b60008083601f8401126121af57600080fd5b50813567ffffffffffffffff8111156121c757600080fd5b6020830191508360208260051b85010111156121e257600080fd5b9250929050565b600080600080604085870312156121ff57600080fd5b843567ffffffffffffffff81111561221657600080fd5b6122228782880161219d565b909550935050602085013567ffffffffffffffff81111561224257600080fd5b61224e8782880161219d565b95989497509550505050565b60006020828403121561226c57600080fd5b61206e82612075565b602080825282518282018190526000918401906040840190835b8181101561175757835183526020938401939092019160010161228f565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612301576123016122d9565b5060010190565b8082018082111561052a5761052a6122d9565b8181038181111561052a5761052a6122d9565b60008161233d5761233d6122d9565b50600019019056fe02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800a49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775a264697066735822122085938ead5ca2c9ce48e9d331c4297cc80111fda9e0d0da46e772b5b7e0d3dccc64736f6c634300081c0033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101ae5760003560e01c80637f78bc43116100ee578063c0fded2411610097578063cacebadc11610071578063cacebadc1461042e578063d547741f1461044e578063dfe6b5d614610461578063f3a8c79d1461048457600080fd5b8063c0fded24146103e8578063c4d66de8146103fb578063ca15c8731461040e57600080fd5b8063a217fddf116100c8578063a217fddf146103c4578063bda21260146103cc578063bfc12c05146103df57600080fd5b80637f78bc431461033357806391d148541461035b5780639622f7bb146103a157600080fd5b80632f2ff15d1161015b57806351858e271161013557806351858e27146102af57806354fd4d50146102b75780635c975abb146102f65780636200354a1461032057600080fd5b80632f2ff15d1461028157806336568abe146102945780634a4e3bd5146102a757600080fd5b8063248a9ca31161018c578063248a9ca3146102075780632553e0aa1461023757806327a69dad1461026b57600080fd5b806301ffc9a7146101b35780630343b3b5146101db578063073dddf6146101f2575b600080fd5b6101c66101c136600461202c565b610497565b60405190151581526020015b60405180910390f35b6101e460025481565b6040519081526020016101d2565b610205610200366004612091565b610530565b005b6101e46102153660046120bd565b6000908152600080516020612346833981519152602052604090206001015490565b6101e4610245366004612091565b6000918252602082815260408084206001600160a01b0393909316845291905290205490565b6102736106be565b6040516101d292919061211c565b61020561028f366004612091565b6108d8565b6102056102a2366004612091565b610910565b610205610961565b610205610a06565b604080518082018252600581527f312e302e30000000000000000000000000000000000000000000000000000000602082015290516101d2919061218a565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff166101c6565b61020561032e3660046121e9565b610b27565b6101e4610341366004612091565b600060208181529281526040808220909352908152205481565b6101c6610369366004612091565b6000918252600080516020612346833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6101c66103af3660046120bd565b60016020526000908152604090205460ff1681565b6101e4600081565b6101c66103da36600461225a565b610dd9565b6101e460035481565b6102056103f63660046121e9565b610f20565b61020561040936600461225a565b611201565b6101e461041c3660046120bd565b60009081526004602052604090205490565b61044161043c36600461225a565b61148d565b6040516101d29190612275565b61020561045c366004612091565b611762565b610469611794565b604080519384526020840192909252908201526060016101d2565b610205610492366004612091565b6118a5565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061052a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff1661059a57604051630dcd852560e31b815233600482015260008051602061236683398151915260248201526044015b60405180910390fd5b6105a26119f6565b6001600160a01b0381166105d457604051631f5cf20560e11b81526001600160a01b0382166004820152602401610591565b600080516020612366833981519152821480156105f957506001600160a01b03811633145b1561062957604051638293991b60e01b8152600481018390526001600160a01b0382166024820152604401610591565b6106338282611a59565b6000828152602081815260408083206001600160a01b038516808552908352928190204290819055905190815233929185917ff4b4e62d80a4a1502357b01edf05f517c2fe3e4afd8b89c0418ee45fe182f4fe91015b60405180910390a46106ba60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5050565b60408051600a80825261016082019092526000916060918391816020015b60608152602001906001900390816106dc575050600080516020612366833981519152600090815260046020527f49b573c16d0a3fe96af74a58679870c9f48517274761ed80ca9ceccb8126cb7354919250908103610797576040518060400160405280601181526020017f4e6f2061646d696e206163636f756e747300000000000000000000000000000081525082828151811061077d5761077d6122c3565b60200260200101819052508080610793906122ef565b9150505b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1680156107ca57506005600254115b15610831576040518060400160405280601981526020017f546f6f206d616e7920656d657267656e63792070617573657300000000000000815250828281518110610817576108176122c3565b6020026020010181905250808061082d906122ef565b9150505b60008167ffffffffffffffff81111561084c5761084c6122ad565b60405190808252806020026020018201604052801561087f57816020015b606081526020019060019003908161086a5790505b50905060005b828110156108cc5783818151811061089f5761089f6122c3565b60200260200101518282815181106108b9576108b96122c3565b6020908102919091010152600101610885565b50901594909350915050565b6000828152600080516020612346833981519152602052604090206001015461090081611b0f565b61090a8383611b1c565b50505050565b6001600160a01b0381163314610952576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61095c8282611bd9565b505050565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff166109c657604051630dcd852560e31b81523360048201526000805160206123668339815191526024820152604401610591565b6109ce611c6d565b60405142815233907fdb5c0bc39850eb0ddb99fae67eecd7ee594120d92d1c0db6c3252252a4fc3356906020015b60405180910390a2565b3360009081527f762c7c328dd70a077c65c77b60e4c38eed3d2f6aa056d4d0fa114aeff8234b56602052604090205460ff16158015610a7457503360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff16155b15610aba57604051630dcd852560e31b81523360048201527fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b266024820152604401610591565b610ac2611cdf565b60028054906000610ad2836122ef565b9091555050600254600090815260016020818152604092839020805460ff1916909217909155905142815233917f9506e519f3e4ce17dda1136d3ba3d3465dc873c49a6191e0fd209f33959a00cd91016109fc565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff16610b8c57604051630dcd852560e31b81523360048201526000805160206123668339815191526024820152604401610591565b610b946119f6565b828114610bbe57604051631f4bb7c160e31b81526004810184905260248101829052604401610591565b6000839003610be05760405163521299a960e01b815260040160405180910390fd5b60005b83811015610daf576000838383818110610bff57610bff6122c3565b9050602002016020810190610c14919061225a565b6001600160a01b031603610c6e57828282818110610c3457610c346122c3565b9050602002016020810190610c49919061225a565b604051631f5cf20560e11b81526001600160a01b039091166004820152602401610591565b610cb6858583818110610c8357610c836122c3565b90506020020135848484818110610c9c57610c9c6122c3565b9050602002016020810190610cb1919061225a565b611a59565b42600080878785818110610ccc57610ccc6122c3565b9050602002013581526020019081526020016000206000858585818110610cf557610cf56122c3565b9050602002016020810190610d0a919061225a565b6001600160a01b0316815260208101919091526040016000205533838383818110610d3757610d376122c3565b9050602002016020810190610d4c919061225a565b6001600160a01b0316868684818110610d6757610d676122c3565b905060200201357ff4b4e62d80a4a1502357b01edf05f517c2fe3e4afd8b89c0418ee45fe182f4fe42604051610d9f91815260200190565b60405180910390a4600101610be3565b5061090a60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6001600160a01b03811660009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604081205460ff1680610e5657506001600160a01b03821660009081527f2dc5c9fd9d70e2ee51b9e4ead45cd5e8c0d85f8c9a23f31c5c0c1222dff10771602052604090205460ff165b80610e9857506001600160a01b03821660009081527f294f263e68a44628370ca7eca46e11f3043892ee36ff7375f356adc9c8117805602052604090205460ff165b80610eda57506001600160a01b03821660009081527f762c7c328dd70a077c65c77b60e4c38eed3d2f6aa056d4d0fa114aeff8234b56602052604090205460ff165b8061052a57506001600160a01b03821660009081527fab71e3f32666744d246edff3f96e4bdafee2e9867098cdd118a979a7464786a8602052604090205460ff1661052a565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff16610f8557604051630dcd852560e31b81523360048201526000805160206123668339815191526024820152604401610591565b610f8d6119f6565b828114610fb757604051631f4bb7c160e31b81526004810184905260248101829052604401610591565b6000839003610fd95760405163521299a960e01b815260040160405180910390fd5b60005b83811015610daf57600080516020612366833981519152858583818110611005576110056122c3565b90506020020135036110bf5760008051602061236683398151915260005260046020527f49b573c16d0a3fe96af74a58679870c9f48517274761ed80ca9ceccb8126cb7354600181116110bd57858583818110611064576110646122c3565b9050602002013584848481811061107d5761107d6122c3565b9050602002016020810190611092919061225a565b604051638293991b60e01b815260048101929092526001600160a01b03166024820152604401610591565b505b6111078585838181106110d4576110d46122c3565b905060200201358484848181106110ed576110ed6122c3565b9050602002016020810190611102919061225a565b611d3a565b600080600087878581811061111e5761111e6122c3565b9050602002013581526020019081526020016000206000858585818110611147576111476122c3565b905060200201602081019061115c919061225a565b6001600160a01b0316815260208101919091526040016000205533838383818110611189576111896122c3565b905060200201602081019061119e919061225a565b6001600160a01b03168686848181106111b9576111b96122c3565b905060200201357f53d12e54e6f700315abaeac32c6c176e7a16c4b913a903dc041270bf50a6cef5426040516111f191815260200190565b60405180910390a4600101610fdc565b600061120b611dd2565b805490915060ff68010000000000000000820416159067ffffffffffffffff166000811580156112385750825b905060008267ffffffffffffffff1660011480156112555750303b155b905081158015611263575080155b1561129a576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156112ce57845468ff00000000000000001916680100000000000000001785555b6001600160a01b03861661130e576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611316611dfb565b61131e611dfb565b611326611e05565b61133e60008051602061236683398151915280611e15565b6113767f52eafc11f6f81f86878bffd31109a0d92f37506527754f00788853ff9f63b130600080516020612366833981519152611e15565b6113ae7f6c0757dc3e6b28b2580c03fd9e96c274acf4f99d91fbec9b418fa1d70604ff1c600080516020612366833981519152611e15565b6113e67fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b26600080516020612366833981519152611e15565b61141e7f189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e3600080516020612366833981519152611e15565b61143660008051602061236683398151915287611a59565b42600355831561148557845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b60408051600580825260c08201909252606091600091906020820160a080368337019050509050600080516020612366833981519152816000815181106114d6576114d66122c3565b6020026020010181815250507f52eafc11f6f81f86878bffd31109a0d92f37506527754f00788853ff9f63b13081600181518110611516576115166122c3565b6020026020010181815250507f6c0757dc3e6b28b2580c03fd9e96c274acf4f99d91fbec9b418fa1d70604ff1c81600281518110611556576115566122c3565b6020026020010181815250507fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b2681600381518110611596576115966122c3565b6020026020010181815250507f189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e3816004815181106115d6576115d66122c3565b6020026020010181815250506000805b825181101561165d57611642838281518110611604576116046122c3565b6020908102919091018101516000908152600080516020612346833981519152825260408082206001600160a01b038a168352909252205460ff1690565b156116555781611651816122ef565b9250505b6001016115e6565b5060008167ffffffffffffffff811115611679576116796122ad565b6040519080825280602002602001820160405280156116a2578160200160208202803683370190505b5090506000805b8451811015611757576117058582815181106116c7576116c76122c3565b6020908102919091018101516000908152600080516020612346833981519152825260408082206001600160a01b038c168352909252205460ff1690565b1561174f5784818151811061171c5761171c6122c3565b6020026020010151838381518110611736576117366122c3565b60209081029190910101528161174b816122ef565b9250505b6001016116a9565b509095945050505050565b6000828152600080516020612346833981519152602052604090206001015461178a81611b0f565b61090a8383611bd9565b60046020527f7bc9e7a6bba5a59ca6616f4e700d2f3a4e51ca8434b2a6aec5b26336fe4d123a547fc75256a229fdd20b6fa63bf91cbbb3f0b9280a66959f4dd898c14fd291fcb191547f9c1b7d0908e3b14d43ceb18bc61be39053ce951144a163c5064b1204790f7c61547f9e3fbaa213cebb710763a0e4681162cb632cda9982e46ad66f2320625a75da3b5460008051602061236683398151915260009081527f49b573c16d0a3fe96af74a58679870c9f48517274761ed80ca9ceccb8126cb73549094859485949193909261186b9190612308565b6118759190612308565b61187f9190612308565b6118899190612308565b925060025491506003544261189e919061231b565b9050909192565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff1661190a57604051630dcd852560e31b81523360048201526000805160206123668339815191526024820152604401610591565b6119126119f6565b60008051602061236683398151915282036119955760008051602061236683398151915260005260046020527f49b573c16d0a3fe96af74a58679870c9f48517274761ed80ca9ceccb8126cb73546001811161199357604051638293991b60e01b8152600481018490526001600160a01b0383166024820152604401610591565b505b61199f8282611d3a565b6000828152602081815260408083206001600160a01b038516808552908352818420939093555142815233929185917f53d12e54e6f700315abaeac32c6c176e7a16c4b913a903dc041270bf50a6cef59101610689565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805460011901611a53576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60029055565b6000828152600080516020612346833981519152602090815260408083206001600160a01b038516845290915290205460ff16611a968383611b1c565b508061095c5760008381526005602090815260408083206001600160a01b03861684528252808320805460ff1916600117905585835260049091528120805491611adf836122ef565b9190505550505050565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b611b198133611e95565b50565b6000828152600080516020612346833981519152602081815260408084206001600160a01b038616855290915282205460ff16611bcf576000848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055611b853390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4600191505061052a565b600091505061052a565b6000828152600080516020612346833981519152602081815260408084206001600160a01b038616855290915282205460ff1615611bcf576000848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4600191505061052a565b611c75611f10565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b611ce7611f6b565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833611cc1565b6000828152600080516020612346833981519152602090815260408083206001600160a01b038516845290915290205460ff16611d778383611bd9565b50801561095c5760008381526005602090815260408083206001600160a01b03861684528252808320805460ff1916905585835260049091529020541561095c576000838152600460205260408120805491611adf8361232e565b6000807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0061052a565b611e03611fc7565b565b611e0d611fc7565b611e03612005565b6000805160206123468339815191526000611e4c846000908152600080516020612346833981519152602052604090206001015490565b600085815260208490526040808220600101869055519192508491839187917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a450505050565b6000828152600080516020612346833981519152602090815260408083206001600160a01b038516845290915290205460ff166106ba576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401610591565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16611e03576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1615611e03576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611fcf61200d565b611e03576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ae9611fc7565b6000612017611dd2565b5468010000000000000000900460ff16919050565b60006020828403121561203e57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461206e57600080fd5b9392505050565b80356001600160a01b038116811461208c57600080fd5b919050565b600080604083850312156120a457600080fd5b823591506120b460208401612075565b90509250929050565b6000602082840312156120cf57600080fd5b5035919050565b6000815180845260005b818110156120fc576020818501810151868301820152016120e0565b506000602082860101526020601f19601f83011685010191505092915050565b60006040820184151583526040602084015280845180835260608501915060608160051b86010192506020860160005b8281101561217d57605f198786030184526121688583516120d6565b9450602093840193919091019060010161214c565b5092979650505050505050565b60208152600061206e60208301846120d6565b60008083601f8401126121af57600080fd5b50813567ffffffffffffffff8111156121c757600080fd5b6020830191508360208260051b85010111156121e257600080fd5b9250929050565b600080600080604085870312156121ff57600080fd5b843567ffffffffffffffff81111561221657600080fd5b6122228782880161219d565b909550935050602085013567ffffffffffffffff81111561224257600080fd5b61224e8782880161219d565b95989497509550505050565b60006020828403121561226c57600080fd5b61206e82612075565b602080825282518282018190526000918401906040840190835b8181101561175757835183526020938401939092019160010161228f565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612301576123016122d9565b5060010190565b8082018082111561052a5761052a6122d9565b8181038181111561052a5761052a6122d9565b60008161233d5761233d6122d9565b50600019019056fe02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800a49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775a264697066735822122085938ead5ca2c9ce48e9d331c4297cc80111fda9e0d0da46e772b5b7e0d3dccc64736f6c634300081c0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
0xf1FaC890b4ebd940fe1e19Fd31aAb8C930c66858
Loading...
Loading
Loading...
Loading
Loading...
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.