Source Code
Overview
APE Balance
APE Value
$0.00Multichain Info
N/A
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
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);
}// 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)");
}// 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();
}{
"optimizer": {
"enabled": true,
"runs": 1000
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
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"}]Contract Creation Code
6080604052348015600f57600080fd5b506123bb8061001f6000396000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c80637f78bc43116100ee578063c0fded2411610097578063cacebadc11610071578063cacebadc1461042e578063d547741f1461044e578063dfe6b5d614610461578063f3a8c79d1461048457600080fd5b8063c0fded24146103e8578063c4d66de8146103fb578063ca15c8731461040e57600080fd5b8063a217fddf116100c8578063a217fddf146103c4578063bda21260146103cc578063bfc12c05146103df57600080fd5b80637f78bc431461033357806391d148541461035b5780639622f7bb146103a157600080fd5b80632f2ff15d1161015b57806351858e271161013557806351858e27146102af57806354fd4d50146102b75780635c975abb146102f65780636200354a1461032057600080fd5b80632f2ff15d1461028157806336568abe146102945780634a4e3bd5146102a757600080fd5b8063248a9ca31161018c578063248a9ca3146102075780632553e0aa1461023757806327a69dad1461026b57600080fd5b806301ffc9a7146101b35780630343b3b5146101db578063073dddf6146101f2575b600080fd5b6101c66101c136600461202c565b610497565b60405190151581526020015b60405180910390f35b6101e460025481565b6040519081526020016101d2565b610205610200366004612091565b610530565b005b6101e46102153660046120bd565b6000908152600080516020612346833981519152602052604090206001015490565b6101e4610245366004612091565b6000918252602082815260408084206001600160a01b0393909316845291905290205490565b6102736106be565b6040516101d292919061211c565b61020561028f366004612091565b6108d8565b6102056102a2366004612091565b610910565b610205610961565b610205610a06565b604080518082018252600581527f312e302e30000000000000000000000000000000000000000000000000000000602082015290516101d2919061218a565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff166101c6565b61020561032e3660046121e9565b610b27565b6101e4610341366004612091565b600060208181529281526040808220909352908152205481565b6101c6610369366004612091565b6000918252600080516020612346833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6101c66103af3660046120bd565b60016020526000908152604090205460ff1681565b6101e4600081565b6101c66103da36600461225a565b610dd9565b6101e460035481565b6102056103f63660046121e9565b610f20565b61020561040936600461225a565b611201565b6101e461041c3660046120bd565b60009081526004602052604090205490565b61044161043c36600461225a565b61148d565b6040516101d29190612275565b61020561045c366004612091565b611762565b610469611794565b604080519384526020840192909252908201526060016101d2565b610205610492366004612091565b6118a5565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061052a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff1661059a57604051630dcd852560e31b815233600482015260008051602061236683398151915260248201526044015b60405180910390fd5b6105a26119f6565b6001600160a01b0381166105d457604051631f5cf20560e11b81526001600160a01b0382166004820152602401610591565b600080516020612366833981519152821480156105f957506001600160a01b03811633145b1561062957604051638293991b60e01b8152600481018390526001600160a01b0382166024820152604401610591565b6106338282611a59565b6000828152602081815260408083206001600160a01b038516808552908352928190204290819055905190815233929185917ff4b4e62d80a4a1502357b01edf05f517c2fe3e4afd8b89c0418ee45fe182f4fe91015b60405180910390a46106ba60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5050565b60408051600a80825261016082019092526000916060918391816020015b60608152602001906001900390816106dc575050600080516020612366833981519152600090815260046020527f49b573c16d0a3fe96af74a58679870c9f48517274761ed80ca9ceccb8126cb7354919250908103610797576040518060400160405280601181526020017f4e6f2061646d696e206163636f756e747300000000000000000000000000000081525082828151811061077d5761077d6122c3565b60200260200101819052508080610793906122ef565b9150505b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1680156107ca57506005600254115b15610831576040518060400160405280601981526020017f546f6f206d616e7920656d657267656e63792070617573657300000000000000815250828281518110610817576108176122c3565b6020026020010181905250808061082d906122ef565b9150505b60008167ffffffffffffffff81111561084c5761084c6122ad565b60405190808252806020026020018201604052801561087f57816020015b606081526020019060019003908161086a5790505b50905060005b828110156108cc5783818151811061089f5761089f6122c3565b60200260200101518282815181106108b9576108b96122c3565b6020908102919091010152600101610885565b50901594909350915050565b6000828152600080516020612346833981519152602052604090206001015461090081611b0f565b61090a8383611b1c565b50505050565b6001600160a01b0381163314610952576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61095c8282611bd9565b505050565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff166109c657604051630dcd852560e31b81523360048201526000805160206123668339815191526024820152604401610591565b6109ce611c6d565b60405142815233907fdb5c0bc39850eb0ddb99fae67eecd7ee594120d92d1c0db6c3252252a4fc3356906020015b60405180910390a2565b3360009081527f762c7c328dd70a077c65c77b60e4c38eed3d2f6aa056d4d0fa114aeff8234b56602052604090205460ff16158015610a7457503360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff16155b15610aba57604051630dcd852560e31b81523360048201527fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b266024820152604401610591565b610ac2611cdf565b60028054906000610ad2836122ef565b9091555050600254600090815260016020818152604092839020805460ff1916909217909155905142815233917f9506e519f3e4ce17dda1136d3ba3d3465dc873c49a6191e0fd209f33959a00cd91016109fc565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff16610b8c57604051630dcd852560e31b81523360048201526000805160206123668339815191526024820152604401610591565b610b946119f6565b828114610bbe57604051631f4bb7c160e31b81526004810184905260248101829052604401610591565b6000839003610be05760405163521299a960e01b815260040160405180910390fd5b60005b83811015610daf576000838383818110610bff57610bff6122c3565b9050602002016020810190610c14919061225a565b6001600160a01b031603610c6e57828282818110610c3457610c346122c3565b9050602002016020810190610c49919061225a565b604051631f5cf20560e11b81526001600160a01b039091166004820152602401610591565b610cb6858583818110610c8357610c836122c3565b90506020020135848484818110610c9c57610c9c6122c3565b9050602002016020810190610cb1919061225a565b611a59565b42600080878785818110610ccc57610ccc6122c3565b9050602002013581526020019081526020016000206000858585818110610cf557610cf56122c3565b9050602002016020810190610d0a919061225a565b6001600160a01b0316815260208101919091526040016000205533838383818110610d3757610d376122c3565b9050602002016020810190610d4c919061225a565b6001600160a01b0316868684818110610d6757610d676122c3565b905060200201357ff4b4e62d80a4a1502357b01edf05f517c2fe3e4afd8b89c0418ee45fe182f4fe42604051610d9f91815260200190565b60405180910390a4600101610be3565b5061090a60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6001600160a01b03811660009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604081205460ff1680610e5657506001600160a01b03821660009081527f2dc5c9fd9d70e2ee51b9e4ead45cd5e8c0d85f8c9a23f31c5c0c1222dff10771602052604090205460ff165b80610e9857506001600160a01b03821660009081527f294f263e68a44628370ca7eca46e11f3043892ee36ff7375f356adc9c8117805602052604090205460ff165b80610eda57506001600160a01b03821660009081527f762c7c328dd70a077c65c77b60e4c38eed3d2f6aa056d4d0fa114aeff8234b56602052604090205460ff165b8061052a57506001600160a01b03821660009081527fab71e3f32666744d246edff3f96e4bdafee2e9867098cdd118a979a7464786a8602052604090205460ff1661052a565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff16610f8557604051630dcd852560e31b81523360048201526000805160206123668339815191526024820152604401610591565b610f8d6119f6565b828114610fb757604051631f4bb7c160e31b81526004810184905260248101829052604401610591565b6000839003610fd95760405163521299a960e01b815260040160405180910390fd5b60005b83811015610daf57600080516020612366833981519152858583818110611005576110056122c3565b90506020020135036110bf5760008051602061236683398151915260005260046020527f49b573c16d0a3fe96af74a58679870c9f48517274761ed80ca9ceccb8126cb7354600181116110bd57858583818110611064576110646122c3565b9050602002013584848481811061107d5761107d6122c3565b9050602002016020810190611092919061225a565b604051638293991b60e01b815260048101929092526001600160a01b03166024820152604401610591565b505b6111078585838181106110d4576110d46122c3565b905060200201358484848181106110ed576110ed6122c3565b9050602002016020810190611102919061225a565b611d3a565b600080600087878581811061111e5761111e6122c3565b9050602002013581526020019081526020016000206000858585818110611147576111476122c3565b905060200201602081019061115c919061225a565b6001600160a01b0316815260208101919091526040016000205533838383818110611189576111896122c3565b905060200201602081019061119e919061225a565b6001600160a01b03168686848181106111b9576111b96122c3565b905060200201357f53d12e54e6f700315abaeac32c6c176e7a16c4b913a903dc041270bf50a6cef5426040516111f191815260200190565b60405180910390a4600101610fdc565b600061120b611dd2565b805490915060ff68010000000000000000820416159067ffffffffffffffff166000811580156112385750825b905060008267ffffffffffffffff1660011480156112555750303b155b905081158015611263575080155b1561129a576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156112ce57845468ff00000000000000001916680100000000000000001785555b6001600160a01b03861661130e576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611316611dfb565b61131e611dfb565b611326611e05565b61133e60008051602061236683398151915280611e15565b6113767f52eafc11f6f81f86878bffd31109a0d92f37506527754f00788853ff9f63b130600080516020612366833981519152611e15565b6113ae7f6c0757dc3e6b28b2580c03fd9e96c274acf4f99d91fbec9b418fa1d70604ff1c600080516020612366833981519152611e15565b6113e67fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b26600080516020612366833981519152611e15565b61141e7f189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e3600080516020612366833981519152611e15565b61143660008051602061236683398151915287611a59565b42600355831561148557845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b60408051600580825260c08201909252606091600091906020820160a080368337019050509050600080516020612366833981519152816000815181106114d6576114d66122c3565b6020026020010181815250507f52eafc11f6f81f86878bffd31109a0d92f37506527754f00788853ff9f63b13081600181518110611516576115166122c3565b6020026020010181815250507f6c0757dc3e6b28b2580c03fd9e96c274acf4f99d91fbec9b418fa1d70604ff1c81600281518110611556576115566122c3565b6020026020010181815250507fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b2681600381518110611596576115966122c3565b6020026020010181815250507f189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e3816004815181106115d6576115d66122c3565b6020026020010181815250506000805b825181101561165d57611642838281518110611604576116046122c3565b6020908102919091018101516000908152600080516020612346833981519152825260408082206001600160a01b038a168352909252205460ff1690565b156116555781611651816122ef565b9250505b6001016115e6565b5060008167ffffffffffffffff811115611679576116796122ad565b6040519080825280602002602001820160405280156116a2578160200160208202803683370190505b5090506000805b8451811015611757576117058582815181106116c7576116c76122c3565b6020908102919091018101516000908152600080516020612346833981519152825260408082206001600160a01b038c168352909252205460ff1690565b1561174f5784818151811061171c5761171c6122c3565b6020026020010151838381518110611736576117366122c3565b60209081029190910101528161174b816122ef565b9250505b6001016116a9565b509095945050505050565b6000828152600080516020612346833981519152602052604090206001015461178a81611b0f565b61090a8383611bd9565b60046020527f7bc9e7a6bba5a59ca6616f4e700d2f3a4e51ca8434b2a6aec5b26336fe4d123a547fc75256a229fdd20b6fa63bf91cbbb3f0b9280a66959f4dd898c14fd291fcb191547f9c1b7d0908e3b14d43ceb18bc61be39053ce951144a163c5064b1204790f7c61547f9e3fbaa213cebb710763a0e4681162cb632cda9982e46ad66f2320625a75da3b5460008051602061236683398151915260009081527f49b573c16d0a3fe96af74a58679870c9f48517274761ed80ca9ceccb8126cb73549094859485949193909261186b9190612308565b6118759190612308565b61187f9190612308565b6118899190612308565b925060025491506003544261189e919061231b565b9050909192565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff1661190a57604051630dcd852560e31b81523360048201526000805160206123668339815191526024820152604401610591565b6119126119f6565b60008051602061236683398151915282036119955760008051602061236683398151915260005260046020527f49b573c16d0a3fe96af74a58679870c9f48517274761ed80ca9ceccb8126cb73546001811161199357604051638293991b60e01b8152600481018490526001600160a01b0383166024820152604401610591565b505b61199f8282611d3a565b6000828152602081815260408083206001600160a01b038516808552908352818420939093555142815233929185917f53d12e54e6f700315abaeac32c6c176e7a16c4b913a903dc041270bf50a6cef59101610689565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805460011901611a53576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60029055565b6000828152600080516020612346833981519152602090815260408083206001600160a01b038516845290915290205460ff16611a968383611b1c565b508061095c5760008381526005602090815260408083206001600160a01b03861684528252808320805460ff1916600117905585835260049091528120805491611adf836122ef565b9190505550505050565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b611b198133611e95565b50565b6000828152600080516020612346833981519152602081815260408084206001600160a01b038616855290915282205460ff16611bcf576000848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055611b853390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4600191505061052a565b600091505061052a565b6000828152600080516020612346833981519152602081815260408084206001600160a01b038616855290915282205460ff1615611bcf576000848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4600191505061052a565b611c75611f10565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b611ce7611f6b565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833611cc1565b6000828152600080516020612346833981519152602090815260408083206001600160a01b038516845290915290205460ff16611d778383611bd9565b50801561095c5760008381526005602090815260408083206001600160a01b03861684528252808320805460ff1916905585835260049091529020541561095c576000838152600460205260408120805491611adf8361232e565b6000807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0061052a565b611e03611fc7565b565b611e0d611fc7565b611e03612005565b6000805160206123468339815191526000611e4c846000908152600080516020612346833981519152602052604090206001015490565b600085815260208490526040808220600101869055519192508491839187917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a450505050565b6000828152600080516020612346833981519152602090815260408083206001600160a01b038516845290915290205460ff166106ba576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401610591565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16611e03576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1615611e03576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611fcf61200d565b611e03576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ae9611fc7565b6000612017611dd2565b5468010000000000000000900460ff16919050565b60006020828403121561203e57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461206e57600080fd5b9392505050565b80356001600160a01b038116811461208c57600080fd5b919050565b600080604083850312156120a457600080fd5b823591506120b460208401612075565b90509250929050565b6000602082840312156120cf57600080fd5b5035919050565b6000815180845260005b818110156120fc576020818501810151868301820152016120e0565b506000602082860101526020601f19601f83011685010191505092915050565b60006040820184151583526040602084015280845180835260608501915060608160051b86010192506020860160005b8281101561217d57605f198786030184526121688583516120d6565b9450602093840193919091019060010161214c565b5092979650505050505050565b60208152600061206e60208301846120d6565b60008083601f8401126121af57600080fd5b50813567ffffffffffffffff8111156121c757600080fd5b6020830191508360208260051b85010111156121e257600080fd5b9250929050565b600080600080604085870312156121ff57600080fd5b843567ffffffffffffffff81111561221657600080fd5b6122228782880161219d565b909550935050602085013567ffffffffffffffff81111561224257600080fd5b61224e8782880161219d565b95989497509550505050565b60006020828403121561226c57600080fd5b61206e82612075565b602080825282518282018190526000918401906040840190835b8181101561175757835183526020938401939092019160010161228f565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612301576123016122d9565b5060010190565b8082018082111561052a5761052a6122d9565b8181038181111561052a5761052a6122d9565b60008161233d5761233d6122d9565b50600019019056fe02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800a49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775a264697066735822122085938ead5ca2c9ce48e9d331c4297cc80111fda9e0d0da46e772b5b7e0d3dccc64736f6c634300081c0033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101ae5760003560e01c80637f78bc43116100ee578063c0fded2411610097578063cacebadc11610071578063cacebadc1461042e578063d547741f1461044e578063dfe6b5d614610461578063f3a8c79d1461048457600080fd5b8063c0fded24146103e8578063c4d66de8146103fb578063ca15c8731461040e57600080fd5b8063a217fddf116100c8578063a217fddf146103c4578063bda21260146103cc578063bfc12c05146103df57600080fd5b80637f78bc431461033357806391d148541461035b5780639622f7bb146103a157600080fd5b80632f2ff15d1161015b57806351858e271161013557806351858e27146102af57806354fd4d50146102b75780635c975abb146102f65780636200354a1461032057600080fd5b80632f2ff15d1461028157806336568abe146102945780634a4e3bd5146102a757600080fd5b8063248a9ca31161018c578063248a9ca3146102075780632553e0aa1461023757806327a69dad1461026b57600080fd5b806301ffc9a7146101b35780630343b3b5146101db578063073dddf6146101f2575b600080fd5b6101c66101c136600461202c565b610497565b60405190151581526020015b60405180910390f35b6101e460025481565b6040519081526020016101d2565b610205610200366004612091565b610530565b005b6101e46102153660046120bd565b6000908152600080516020612346833981519152602052604090206001015490565b6101e4610245366004612091565b6000918252602082815260408084206001600160a01b0393909316845291905290205490565b6102736106be565b6040516101d292919061211c565b61020561028f366004612091565b6108d8565b6102056102a2366004612091565b610910565b610205610961565b610205610a06565b604080518082018252600581527f312e302e30000000000000000000000000000000000000000000000000000000602082015290516101d2919061218a565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff166101c6565b61020561032e3660046121e9565b610b27565b6101e4610341366004612091565b600060208181529281526040808220909352908152205481565b6101c6610369366004612091565b6000918252600080516020612346833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6101c66103af3660046120bd565b60016020526000908152604090205460ff1681565b6101e4600081565b6101c66103da36600461225a565b610dd9565b6101e460035481565b6102056103f63660046121e9565b610f20565b61020561040936600461225a565b611201565b6101e461041c3660046120bd565b60009081526004602052604090205490565b61044161043c36600461225a565b61148d565b6040516101d29190612275565b61020561045c366004612091565b611762565b610469611794565b604080519384526020840192909252908201526060016101d2565b610205610492366004612091565b6118a5565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061052a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff1661059a57604051630dcd852560e31b815233600482015260008051602061236683398151915260248201526044015b60405180910390fd5b6105a26119f6565b6001600160a01b0381166105d457604051631f5cf20560e11b81526001600160a01b0382166004820152602401610591565b600080516020612366833981519152821480156105f957506001600160a01b03811633145b1561062957604051638293991b60e01b8152600481018390526001600160a01b0382166024820152604401610591565b6106338282611a59565b6000828152602081815260408083206001600160a01b038516808552908352928190204290819055905190815233929185917ff4b4e62d80a4a1502357b01edf05f517c2fe3e4afd8b89c0418ee45fe182f4fe91015b60405180910390a46106ba60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5050565b60408051600a80825261016082019092526000916060918391816020015b60608152602001906001900390816106dc575050600080516020612366833981519152600090815260046020527f49b573c16d0a3fe96af74a58679870c9f48517274761ed80ca9ceccb8126cb7354919250908103610797576040518060400160405280601181526020017f4e6f2061646d696e206163636f756e747300000000000000000000000000000081525082828151811061077d5761077d6122c3565b60200260200101819052508080610793906122ef565b9150505b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1680156107ca57506005600254115b15610831576040518060400160405280601981526020017f546f6f206d616e7920656d657267656e63792070617573657300000000000000815250828281518110610817576108176122c3565b6020026020010181905250808061082d906122ef565b9150505b60008167ffffffffffffffff81111561084c5761084c6122ad565b60405190808252806020026020018201604052801561087f57816020015b606081526020019060019003908161086a5790505b50905060005b828110156108cc5783818151811061089f5761089f6122c3565b60200260200101518282815181106108b9576108b96122c3565b6020908102919091010152600101610885565b50901594909350915050565b6000828152600080516020612346833981519152602052604090206001015461090081611b0f565b61090a8383611b1c565b50505050565b6001600160a01b0381163314610952576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61095c8282611bd9565b505050565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff166109c657604051630dcd852560e31b81523360048201526000805160206123668339815191526024820152604401610591565b6109ce611c6d565b60405142815233907fdb5c0bc39850eb0ddb99fae67eecd7ee594120d92d1c0db6c3252252a4fc3356906020015b60405180910390a2565b3360009081527f762c7c328dd70a077c65c77b60e4c38eed3d2f6aa056d4d0fa114aeff8234b56602052604090205460ff16158015610a7457503360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff16155b15610aba57604051630dcd852560e31b81523360048201527fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b266024820152604401610591565b610ac2611cdf565b60028054906000610ad2836122ef565b9091555050600254600090815260016020818152604092839020805460ff1916909217909155905142815233917f9506e519f3e4ce17dda1136d3ba3d3465dc873c49a6191e0fd209f33959a00cd91016109fc565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff16610b8c57604051630dcd852560e31b81523360048201526000805160206123668339815191526024820152604401610591565b610b946119f6565b828114610bbe57604051631f4bb7c160e31b81526004810184905260248101829052604401610591565b6000839003610be05760405163521299a960e01b815260040160405180910390fd5b60005b83811015610daf576000838383818110610bff57610bff6122c3565b9050602002016020810190610c14919061225a565b6001600160a01b031603610c6e57828282818110610c3457610c346122c3565b9050602002016020810190610c49919061225a565b604051631f5cf20560e11b81526001600160a01b039091166004820152602401610591565b610cb6858583818110610c8357610c836122c3565b90506020020135848484818110610c9c57610c9c6122c3565b9050602002016020810190610cb1919061225a565b611a59565b42600080878785818110610ccc57610ccc6122c3565b9050602002013581526020019081526020016000206000858585818110610cf557610cf56122c3565b9050602002016020810190610d0a919061225a565b6001600160a01b0316815260208101919091526040016000205533838383818110610d3757610d376122c3565b9050602002016020810190610d4c919061225a565b6001600160a01b0316868684818110610d6757610d676122c3565b905060200201357ff4b4e62d80a4a1502357b01edf05f517c2fe3e4afd8b89c0418ee45fe182f4fe42604051610d9f91815260200190565b60405180910390a4600101610be3565b5061090a60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6001600160a01b03811660009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604081205460ff1680610e5657506001600160a01b03821660009081527f2dc5c9fd9d70e2ee51b9e4ead45cd5e8c0d85f8c9a23f31c5c0c1222dff10771602052604090205460ff165b80610e9857506001600160a01b03821660009081527f294f263e68a44628370ca7eca46e11f3043892ee36ff7375f356adc9c8117805602052604090205460ff165b80610eda57506001600160a01b03821660009081527f762c7c328dd70a077c65c77b60e4c38eed3d2f6aa056d4d0fa114aeff8234b56602052604090205460ff165b8061052a57506001600160a01b03821660009081527fab71e3f32666744d246edff3f96e4bdafee2e9867098cdd118a979a7464786a8602052604090205460ff1661052a565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff16610f8557604051630dcd852560e31b81523360048201526000805160206123668339815191526024820152604401610591565b610f8d6119f6565b828114610fb757604051631f4bb7c160e31b81526004810184905260248101829052604401610591565b6000839003610fd95760405163521299a960e01b815260040160405180910390fd5b60005b83811015610daf57600080516020612366833981519152858583818110611005576110056122c3565b90506020020135036110bf5760008051602061236683398151915260005260046020527f49b573c16d0a3fe96af74a58679870c9f48517274761ed80ca9ceccb8126cb7354600181116110bd57858583818110611064576110646122c3565b9050602002013584848481811061107d5761107d6122c3565b9050602002016020810190611092919061225a565b604051638293991b60e01b815260048101929092526001600160a01b03166024820152604401610591565b505b6111078585838181106110d4576110d46122c3565b905060200201358484848181106110ed576110ed6122c3565b9050602002016020810190611102919061225a565b611d3a565b600080600087878581811061111e5761111e6122c3565b9050602002013581526020019081526020016000206000858585818110611147576111476122c3565b905060200201602081019061115c919061225a565b6001600160a01b0316815260208101919091526040016000205533838383818110611189576111896122c3565b905060200201602081019061119e919061225a565b6001600160a01b03168686848181106111b9576111b96122c3565b905060200201357f53d12e54e6f700315abaeac32c6c176e7a16c4b913a903dc041270bf50a6cef5426040516111f191815260200190565b60405180910390a4600101610fdc565b600061120b611dd2565b805490915060ff68010000000000000000820416159067ffffffffffffffff166000811580156112385750825b905060008267ffffffffffffffff1660011480156112555750303b155b905081158015611263575080155b1561129a576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156112ce57845468ff00000000000000001916680100000000000000001785555b6001600160a01b03861661130e576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611316611dfb565b61131e611dfb565b611326611e05565b61133e60008051602061236683398151915280611e15565b6113767f52eafc11f6f81f86878bffd31109a0d92f37506527754f00788853ff9f63b130600080516020612366833981519152611e15565b6113ae7f6c0757dc3e6b28b2580c03fd9e96c274acf4f99d91fbec9b418fa1d70604ff1c600080516020612366833981519152611e15565b6113e67fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b26600080516020612366833981519152611e15565b61141e7f189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e3600080516020612366833981519152611e15565b61143660008051602061236683398151915287611a59565b42600355831561148557845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b60408051600580825260c08201909252606091600091906020820160a080368337019050509050600080516020612366833981519152816000815181106114d6576114d66122c3565b6020026020010181815250507f52eafc11f6f81f86878bffd31109a0d92f37506527754f00788853ff9f63b13081600181518110611516576115166122c3565b6020026020010181815250507f6c0757dc3e6b28b2580c03fd9e96c274acf4f99d91fbec9b418fa1d70604ff1c81600281518110611556576115566122c3565b6020026020010181815250507fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b2681600381518110611596576115966122c3565b6020026020010181815250507f189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e3816004815181106115d6576115d66122c3565b6020026020010181815250506000805b825181101561165d57611642838281518110611604576116046122c3565b6020908102919091018101516000908152600080516020612346833981519152825260408082206001600160a01b038a168352909252205460ff1690565b156116555781611651816122ef565b9250505b6001016115e6565b5060008167ffffffffffffffff811115611679576116796122ad565b6040519080825280602002602001820160405280156116a2578160200160208202803683370190505b5090506000805b8451811015611757576117058582815181106116c7576116c76122c3565b6020908102919091018101516000908152600080516020612346833981519152825260408082206001600160a01b038c168352909252205460ff1690565b1561174f5784818151811061171c5761171c6122c3565b6020026020010151838381518110611736576117366122c3565b60209081029190910101528161174b816122ef565b9250505b6001016116a9565b509095945050505050565b6000828152600080516020612346833981519152602052604090206001015461178a81611b0f565b61090a8383611bd9565b60046020527f7bc9e7a6bba5a59ca6616f4e700d2f3a4e51ca8434b2a6aec5b26336fe4d123a547fc75256a229fdd20b6fa63bf91cbbb3f0b9280a66959f4dd898c14fd291fcb191547f9c1b7d0908e3b14d43ceb18bc61be39053ce951144a163c5064b1204790f7c61547f9e3fbaa213cebb710763a0e4681162cb632cda9982e46ad66f2320625a75da3b5460008051602061236683398151915260009081527f49b573c16d0a3fe96af74a58679870c9f48517274761ed80ca9ceccb8126cb73549094859485949193909261186b9190612308565b6118759190612308565b61187f9190612308565b6118899190612308565b925060025491506003544261189e919061231b565b9050909192565b3360009081527fb16e88c42fd4e48df2dd6a2eabd6bc9aec654ec170056b470819f8892cc6431c602052604090205460ff1661190a57604051630dcd852560e31b81523360048201526000805160206123668339815191526024820152604401610591565b6119126119f6565b60008051602061236683398151915282036119955760008051602061236683398151915260005260046020527f49b573c16d0a3fe96af74a58679870c9f48517274761ed80ca9ceccb8126cb73546001811161199357604051638293991b60e01b8152600481018490526001600160a01b0383166024820152604401610591565b505b61199f8282611d3a565b6000828152602081815260408083206001600160a01b038516808552908352818420939093555142815233929185917f53d12e54e6f700315abaeac32c6c176e7a16c4b913a903dc041270bf50a6cef59101610689565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805460011901611a53576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60029055565b6000828152600080516020612346833981519152602090815260408083206001600160a01b038516845290915290205460ff16611a968383611b1c565b508061095c5760008381526005602090815260408083206001600160a01b03861684528252808320805460ff1916600117905585835260049091528120805491611adf836122ef565b9190505550505050565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b611b198133611e95565b50565b6000828152600080516020612346833981519152602081815260408084206001600160a01b038616855290915282205460ff16611bcf576000848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055611b853390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4600191505061052a565b600091505061052a565b6000828152600080516020612346833981519152602081815260408084206001600160a01b038616855290915282205460ff1615611bcf576000848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4600191505061052a565b611c75611f10565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b611ce7611f6b565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833611cc1565b6000828152600080516020612346833981519152602090815260408083206001600160a01b038516845290915290205460ff16611d778383611bd9565b50801561095c5760008381526005602090815260408083206001600160a01b03861684528252808320805460ff1916905585835260049091529020541561095c576000838152600460205260408120805491611adf8361232e565b6000807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0061052a565b611e03611fc7565b565b611e0d611fc7565b611e03612005565b6000805160206123468339815191526000611e4c846000908152600080516020612346833981519152602052604090206001015490565b600085815260208490526040808220600101869055519192508491839187917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a450505050565b6000828152600080516020612346833981519152602090815260408083206001600160a01b038516845290915290205460ff166106ba576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401610591565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16611e03576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1615611e03576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611fcf61200d565b611e03576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ae9611fc7565b6000612017611dd2565b5468010000000000000000900460ff16919050565b60006020828403121561203e57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461206e57600080fd5b9392505050565b80356001600160a01b038116811461208c57600080fd5b919050565b600080604083850312156120a457600080fd5b823591506120b460208401612075565b90509250929050565b6000602082840312156120cf57600080fd5b5035919050565b6000815180845260005b818110156120fc576020818501810151868301820152016120e0565b506000602082860101526020601f19601f83011685010191505092915050565b60006040820184151583526040602084015280845180835260608501915060608160051b86010192506020860160005b8281101561217d57605f198786030184526121688583516120d6565b9450602093840193919091019060010161214c565b5092979650505050505050565b60208152600061206e60208301846120d6565b60008083601f8401126121af57600080fd5b50813567ffffffffffffffff8111156121c757600080fd5b6020830191508360208260051b85010111156121e257600080fd5b9250929050565b600080600080604085870312156121ff57600080fd5b843567ffffffffffffffff81111561221657600080fd5b6122228782880161219d565b909550935050602085013567ffffffffffffffff81111561224257600080fd5b61224e8782880161219d565b95989497509550505050565b60006020828403121561226c57600080fd5b61206e82612075565b602080825282518282018190526000918401906040840190835b8181101561175757835183526020938401939092019160010161228f565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612301576123016122d9565b5060010190565b8082018082111561052a5761052a6122d9565b8181038181111561052a5761052a6122d9565b60008161233d5761233d6122d9565b50600019019056fe02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800a49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775a264697066735822122085938ead5ca2c9ce48e9d331c4297cc80111fda9e0d0da46e772b5b7e0d3dccc64736f6c634300081c0033
Loading...
Loading
Loading...
Loading
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.