Source Code
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
EchoAccessControl
Compiler Version
v0.8.30+commit.73712a01
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
// ███████╗ ██████╗██╗ ██╗ ██████╗ ███╗ ███╗ █████╗ ██████╗ ██╗ ██╗███████╗████████╗
// ██╔════╝██╔════╝██║ ██║██╔═══██╗ ████╗ ████║██╔══██╗██╔══██╗██║ ██╔╝██╔════╝╚══██╔══╝
// █████╗ ██║ ███████║██║ ██║ ██╔████╔██║███████║██████╔╝█████╔╝ █████╗ ██║
// ██╔══╝ ██║ ██╔══██║██║ ██║ ██║╚██╔╝██║██╔══██║██╔══██╗██╔═██╗ ██╔══╝ ██║
// ███████╗╚██████╗██║ ██║╚██████╔╝ ██║ ╚═╝ ██║██║ ██║██║ ██║██║ ██╗███████╗ ██║
// ╚══════╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ ╚═╝
// ================================ EchoAccessControl V2 ===============================
// ===================================== Fall 2025 =====================================
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {
AccessControl,
AccessControlEnumerable
} from "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol";
/**
* @title EchoAccessControl
* @author Dynabits.org
* @notice A centralized, extensible role-based access control system for the Echo Protocol.
* @dev Built on OpenZeppelin’s {AccessControlEnumerable}, this contract manages and registers
* all operational roles used across Echo modules, including Administration, Campaign Factory,
* RouterController, and Contents. It provides an efficient, standardized way to:
* - Register new roles dynamically.
* - Manage role-based permissions.
* - Enforce hierarchical role control through a Super Admin and restricted roles.
*
* ### Features
* - Dynamic role registration with keccak256-based identifiers.
* - Role restriction toggling (only Super Admin can toggle).
* - Safe grant and revoke mechanisms using role names instead of raw bytes32 roles.
* - Prevents unauthorized access or role revocation from Super Admin.
*/
contract EchoAccessControl is AccessControlEnumerable {
/***************************\
|*-*-*-* TYPES *-*-*-*|
\***************************/
/// @notice Struct representing metadata for each registered role.
/// @param role The keccak256 hash identifier of the role.
/// @param restricted Whether the role is restricted to the Super Admin only.
struct RoleStat {
bytes32 role;
bool restricted;
}
/********************************\
|-*-*-*-*-* STATES *-*-*-*-*-|
\********************************/
/// @notice Mapping of human-readable role names to their corresponding metadata.
mapping(string => RoleStat) public roleStat;
/*******************************\
|-*-*-*-* CONSTANTS *-*-*-*-|
\*******************************/
/// @notice The Super Admin address, set once at deployment.
/// @dev The first address provided in the constructor is designated as Super Admin.
address immutable SUPER_ADMIN;
/********************************\
|-*-*-*-*-* ERRORS *-*-*-*-*-|
\********************************/
/// @dev Thrown when a non-Super Admin tries to execute a restricted operation.
error ONLY_SUPER_ADMIN();
/// @dev Thrown when attempting to register an already existing role.
error ROLE_REGISTERED_BEFORE(string roleName);
/// @dev Thrown when attempting to interact with a non-existent role.
error ROLE_NOT_EXISTS(string roleName);
/// @dev Thrown when a restricted role can only be modified by the Super Admin.
error ROLE_RESTRICTED_TO_SUPER_ADMIN(string roleName);
/// @dev Thrown when attempting to revoke the Super Admin’s privileges.
error CANT_REVOKE_ROLE_FROM_SUPER_ADMIN();
/// @dev Thrown when the developer mistakenly calls the bytes32-based grant function.
error USE_GRANT_ROLE_WITH_ROLE_NAME();
/// @dev Thrown when the developer mistakenly calls the bytes32-based revoke function.
error USE_REVOKE_ROLE_WITH_ROLE_NAME();
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
/**
* @notice Initializes the contract and assigns initial admins with predefined roles.
* @param admins An array of admin addresses. The first address becomes the Super Admin.
* @dev Pre-registers all predefined roles (administrative, content, campaign-related)
* and assigns each to all provided admins. The Super Admin gets additional restricted roles.
*/
constructor(address[] memory admins) {
/*//////////////////////////////////////////////////////////////
ROLE REGISTRATION
//////////////////////////////////////////////////////////////*/
// === ADMINISTRATION ===
roleStat["ADMINISTRATION_CHANGE_PROTOCOL_ADMIN"] = RoleStat(
keccak256("ADMINISTRATION_CHANGE_PROTOCOL_ADMIN"),
true
);
roleStat["ADMINISTRATION_CHANGE_CAMPAIGN_FEE_RATE"].role = keccak256(
"ADMINISTRATION_CHANGE_CAMPAIGN_FEE_RATE"
);
roleStat["ADMINISTRATION_CHANGE_MAX_CAMPAIGN_TIME"].role = keccak256(
"ADMINISTRATION_CHANGE_MAX_CAMPAIGN_TIME"
);
roleStat["ADMINISTRATION_WHITELIST_TOKEN"].role = keccak256(
"ADMINISTRATION_WHITELIST_TOKEN"
);
roleStat["ADMINISTRATION_REMOVE_WHITELISTED_TOKEN"].role = keccak256(
"ADMINISTRATION_REMOVE_WHITELISTED_TOKEN"
);
roleStat["ADMINISTRATION_DISALLOW_ORACLE_ACCESS"].role = keccak256(
"ADMINISTRATION_DISALLOW_ORACLE_ACCESS"
);
roleStat["ADMINISTRATION_ALLOW_ORACLE_ACCESS"].role = keccak256(
"ADMINISTRATION_ALLOW_ORACLE_ACCESS"
);
roleStat["ADMINISTRATION_SET_MODEL"].role = keccak256(
"ADMINISTRATION_SET_MODEL"
);
// === CONTENTS ===
roleStat["CONTENTS_SET_CONFIGS"].role = keccak256(
"CONTENTS_SET_CONFIGS"
);
roleStat["CONTENTS_SET_QUALIFICATIONS"].role = keccak256(
"CONTENTS_SET_QUALIFICATIONS"
);
roleStat["CONTENTS_UPDATE_KPIS"].role = keccak256(
"CONTENTS_UPDATE_KPIS"
);
// === CAMPAIGN FACTORY ===
roleStat["CAMPAIGN_FACTORY_CHANGE_IMPLEMENTATION"].role = keccak256(
"CAMPAIGN_FACTORY_CHANGE_IMPLEMENTATION"
);
// === CAMPAIGNS ===
roleStat["CAMPAIGN_RECOVER_ERC20"] = RoleStat(
keccak256("CAMPAIGN_RECOVER_ERC20"),
true
);
roleStat["CAMPAIGN_PAUSE"].role = keccak256("CAMPAIGN_PAUSE");
roleStat["CAMPAIGN_UNPAUSE"].role = keccak256("CAMPAIGN_UNPAUSE");
roleStat["CAMPAIGN_FINALIZE_IN_PROGRESS"].role = keccak256(
"CAMPAIGN_FINALIZE_IN_PROGRESS"
);
roleStat["CAMPAIGN_FINALIZE_FINISHED"].role = keccak256(
"CAMPAIGN_FINALIZE_FINISHED"
);
/*//////////////////////////////////////////////////////////////
ROLE ADMIN ASSIGNMENT
//////////////////////////////////////////////////////////////*/
_setRoleAdmin(
roleStat["ADMINISTRATION_CHANGE_PROTOCOL_ADMIN"].role,
DEFAULT_ADMIN_ROLE
);
_setRoleAdmin(
roleStat["ADMINISTRATION_CHANGE_CAMPAIGN_FEE_RATE"].role,
DEFAULT_ADMIN_ROLE
);
_setRoleAdmin(
roleStat["ADMINISTRATION_CHANGE_MAX_CAMPAIGN_TIME"].role,
DEFAULT_ADMIN_ROLE
);
_setRoleAdmin(
roleStat["ADMINISTRATION_WHITELIST_TOKEN"].role,
DEFAULT_ADMIN_ROLE
);
_setRoleAdmin(
roleStat["ADMINISTRATION_REMOVE_WHITELISTED_TOKEN"].role,
DEFAULT_ADMIN_ROLE
);
_setRoleAdmin(
roleStat["ADMINISTRATION_DISALLOW_ORACLE_ACCESS"].role,
DEFAULT_ADMIN_ROLE
);
_setRoleAdmin(
roleStat["ADMINISTRATION_ALLOW_ORACLE_ACCESS"].role,
DEFAULT_ADMIN_ROLE
);
_setRoleAdmin(
roleStat["ADMINISTRATION_SET_MODEL"].role,
DEFAULT_ADMIN_ROLE
);
_setRoleAdmin(
roleStat["CONTENTS_SET_CONFIGS"].role,
DEFAULT_ADMIN_ROLE
);
_setRoleAdmin(
roleStat["CONTENTS_SET_QUALIFICATIONS"].role,
DEFAULT_ADMIN_ROLE
);
_setRoleAdmin(
roleStat["CONTENTS_UPDATE_KPIS"].role,
DEFAULT_ADMIN_ROLE
);
_setRoleAdmin(
roleStat["CAMPAIGN_FACTORY_CHANGE_IMPLEMENTATION"].role,
DEFAULT_ADMIN_ROLE
);
_setRoleAdmin(
roleStat["CAMPAIGN_RECOVER_ERC20"].role,
DEFAULT_ADMIN_ROLE
);
_setRoleAdmin(roleStat["CAMPAIGN_PAUSE"].role, DEFAULT_ADMIN_ROLE);
_setRoleAdmin(roleStat["CAMPAIGN_UNPAUSE"].role, DEFAULT_ADMIN_ROLE);
_setRoleAdmin(
roleStat["CAMPAIGN_FINALIZE_IN_PROGRESS"].role,
DEFAULT_ADMIN_ROLE
);
_setRoleAdmin(
roleStat["CAMPAIGN_FINALIZE_FINISHED"].role,
DEFAULT_ADMIN_ROLE
);
for (uint i; i < admins.length; i++) {
require(admins[i] != address(0), "ZERO ADDRESS PROVIDED");
_grantRole(DEFAULT_ADMIN_ROLE, admins[i]);
if (i == 0) {
SUPER_ADMIN = admins[0];
_grantRole(
roleStat["ADMINISTRATION_CHANGE_PROTOCOL_ADMIN"].role,
admins[i]
);
_grantRole(roleStat["CAMPAIGN_RECOVER_ERC20"].role, admins[i]);
}
_grantRole(
roleStat["ADMINISTRATION_CHANGE_CAMPAIGN_FEE_RATE"].role,
admins[i]
);
_grantRole(
roleStat["ADMINISTRATION_CHANGE_MAX_CAMPAIGN_TIME"].role,
admins[i]
);
_grantRole(
roleStat["ADMINISTRATION_WHITELIST_TOKEN"].role,
admins[i]
);
_grantRole(
roleStat["ADMINISTRATION_REMOVE_WHITELISTED_TOKEN"].role,
admins[i]
);
_grantRole(
roleStat["ADMINISTRATION_DISALLOW_ORACLE_ACCESS"].role,
admins[i]
);
_grantRole(
roleStat["ADMINISTRATION_ALLOW_ORACLE_ACCESS"].role,
admins[i]
);
_grantRole(roleStat["ADMINISTRATION_SET_MODEL"].role, admins[i]);
_grantRole(roleStat["CONTENTS_SET_CONFIGS"].role, admins[i]);
_grantRole(roleStat["CONTENTS_SET_QUALIFICATIONS"].role, admins[i]);
_grantRole(roleStat["CONTENTS_UPDATE_KPIS"].role, admins[i]);
_grantRole(
roleStat["CAMPAIGN_FACTORY_CHANGE_IMPLEMENTATION"].role,
admins[i]
);
_grantRole(roleStat["CAMPAIGN_PAUSE"].role, admins[i]);
_grantRole(roleStat["CAMPAIGN_UNPAUSE"].role, admins[i]);
_grantRole(
roleStat["CAMPAIGN_FINALIZE_IN_PROGRESS"].role,
admins[i]
);
_grantRole(roleStat["CAMPAIGN_FINALIZE_FINISHED"].role, admins[i]);
}
}
/********************************\
|-*-*-* ADMINISTRATION *-*-*-|
\********************************/
/**
* @notice Dynamically registers a new role using its string name.
* @dev Only callable by the protocol’s `DEFAULT_ADMIN_ROLE`.
* @param roleName The unique string identifier of the role (e.g., "ORACLE_OPERATOR").
*
* Emits no events, but stores the new role metadata in `roleStat`.
*
* Reverts if:
* - The role name is already registered.
*/
function registerRole(
string calldata roleName
) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (roleStat[roleName].role != 0x00)
revert ROLE_REGISTERED_BEFORE(roleName);
roleStat[roleName].role = keccak256(abi.encodePacked(roleName));
_setRoleAdmin(roleStat[roleName].role, DEFAULT_ADMIN_ROLE);
}
/**
* @notice Toggles the restriction status of a role.
* @dev Only the Super Admin can call this function.
* @param roleName The string name of the role whose restriction status will be toggled.
*
* Reverts if:
* - The caller is not the Super Admin.
* - The role does not exist.
*/
function toggleRoleRestriction(string calldata roleName) external {
if (msg.sender != SUPER_ADMIN) revert ONLY_SUPER_ADMIN();
if (roleStat[roleName].role == 0x00) revert ROLE_NOT_EXISTS(roleName);
roleStat[roleName].restricted = !roleStat[roleName].restricted;
}
/**
* @notice Grants a role to a specific account using the role’s string name.
* @dev Prevents direct granting of restricted roles unless called by Super Admin.
* @param roleName The name of the role to grant.
* @param account The address to which the role will be granted.
*
* Reverts if:
* - The role does not exist.
* - The role is restricted and the caller is not Super Admin.
*/
function grantRole(string calldata roleName, address account) external {
if (roleStat[roleName].role == 0x00) revert ROLE_NOT_EXISTS(roleName);
if (roleStat[roleName].restricted && msg.sender != SUPER_ADMIN)
revert ROLE_RESTRICTED_TO_SUPER_ADMIN(roleName);
super.grantRole(roleStat[roleName].role, account);
}
/**
* @notice Revokes a role from an account using the role’s string name.
* @param roleName The name of the role to revoke.
* @param account The address whose role will be revoked.
*
* Reverts if:
* - The role does not exist.
* - Attempting to revoke the Super Admin’s privileges.
*/
function revokeRole(string calldata roleName, address account) external {
if (roleStat[roleName].role == 0x00) revert ROLE_NOT_EXISTS(roleName);
if (account == SUPER_ADMIN) revert CANT_REVOKE_ROLE_FROM_SUPER_ADMIN();
super.revokeRole(roleStat[roleName].role, account);
}
/**
* @notice Disabled raw `grantRole` override from OpenZeppelin to enforce string-based API.
* @dev Calling this function will always revert. Use the string-based version instead.
*/
function grantRole(
bytes32 role,
address account
) public pure override(AccessControl, IAccessControl) {
(role, account);
revert USE_GRANT_ROLE_WITH_ROLE_NAME();
}
/**
* @notice Disabled raw `revokeRole` override from OpenZeppelin to enforce string-based API.
* @dev Calling this function will always revert. Use the string-based version instead.
*/
function revokeRole(
bytes32 role,
address account
) public pure override(AccessControl, IAccessControl) {
(role, account);
revert USE_REVOKE_ROLE_WITH_ROLE_NAME();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/extensions/AccessControlEnumerable.sol)
pragma solidity ^0.8.20;
import {IAccessControlEnumerable} from "./IAccessControlEnumerable.sol";
import {AccessControl} from "../AccessControl.sol";
import {EnumerableSet} from "../../utils/structs/EnumerableSet.sol";
/**
* @dev Extension of {AccessControl} that allows enumerating the members of each role.
*/
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
using EnumerableSet for EnumerableSet.AddressSet;
mapping(bytes32 role => EnumerableSet.AddressSet) private _roleMembers;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {
return _roleMembers[role].at(index);
}
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {
return _roleMembers[role].length();
}
/**
* @dev Return all accounts that have `role`
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function getRoleMembers(bytes32 role) public view virtual returns (address[] memory) {
return _roleMembers[role].values();
}
/**
* @dev Overload {AccessControl-_grantRole} to track enumerable memberships
*/
function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {
bool granted = super._grantRole(role, account);
if (granted) {
_roleMembers[role].add(account);
}
return granted;
}
/**
* @dev Overload {AccessControl-_revokeRole} to track enumerable memberships
*/
function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {
bool revoked = super._revokeRole(role, account);
if (revoked) {
_roleMembers[role].remove(account);
}
return revoked;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @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 signaling 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.1.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.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 AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @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);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
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) {
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) {
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 {
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) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` to `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) {
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.1.0) (access/extensions/IAccessControlEnumerable.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "../IAccessControl.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC-165 detection.
*/
interface IAccessControlEnumerable is IAccessControl {
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.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 ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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 Context {
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.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @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);
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": [
"forge-std/=lib/forge-std/src/",
"@prb/math/=lib/prb-math/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/"
]
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address[]","name":"admins","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"CANT_REVOKE_ROLE_FROM_SUPER_ADMIN","type":"error"},{"inputs":[],"name":"ONLY_SUPER_ADMIN","type":"error"},{"inputs":[{"internalType":"string","name":"roleName","type":"string"}],"name":"ROLE_NOT_EXISTS","type":"error"},{"inputs":[{"internalType":"string","name":"roleName","type":"string"}],"name":"ROLE_REGISTERED_BEFORE","type":"error"},{"inputs":[{"internalType":"string","name":"roleName","type":"string"}],"name":"ROLE_RESTRICTED_TO_SUPER_ADMIN","type":"error"},{"inputs":[],"name":"USE_GRANT_ROLE_WITH_ROLE_NAME","type":"error"},{"inputs":[],"name":"USE_REVOKE_ROLE_WITH_ROLE_NAME","type":"error"},{"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"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"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":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMembers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"string","name":"roleName","type":"string"},{"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":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"roleName","type":"string"}],"name":"registerRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"roleName","type":"string"},{"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":"revokeRole","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"roleStat","outputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"bool","name":"restricted","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"roleName","type":"string"}],"name":"toggleRoleRestriction","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a060405234801561000f575f5ffd5b50604051611fcf380380611fcf83398101604081905261002e91610e38565b6040805180820182527f0e15e64db8793c7886d0948f3cd014699587487d51a4d46d0a006373829c60db815260016020820152905160029061008d905f516020611ecf5f395f51905f528152632226a4a760e11b602082015260240190565b908152604080516020928190038301812084518155938301516001909401805460ff1916941515949094179093555f516020611f2f5f395f51905f5283526645455f5241544560c81b8284015260026027808501829052825194859003604790810186207f9daa750d761db6bf0b8252e9a79d69920d7e8174b31cb430305b6b89680a480c90555f516020611eef5f395f51905f52865266474e5f54494d4560c81b94860194909452840181905290519283900390910182207f4685d170ad15729309a0d63172972ea66f2fb21eae5e1cd2f5b0a8e382b3b47690555f516020611f6f5f395f51905f5282527fba715a05089bb51046b57a9329efb3817620ab0bee8bbc16eb6c43c4176b23fa91601e019081526040805160209281900383018120939093555f516020611def5f395f51905f52835266222faa27a5a2a760c91b8284015260026027840181905281519384900360470184207fbc2eee5aea135f8bc8a046420aafe85662fc0bd2db1a4c92faac91a4106f649090555f516020611e4f5f395f51905f52845264434345535360d81b848401526025840181905281519384900360450184207f8a5616bd0e7363193fc41fe3c9fea9123f13bf149012c67a38fa3afd32a306c590555f516020611e0f5f395f51905f52845261535360f01b9284019290925260228301829052519182900360420182207f87b0b85a48ef2cdb8c70273283903cdb3cb4d4010a7c6c8983436e0d9b17567c90555f516020611e2f5f395f51905f5282527f85c974a4a88259bc08070785002b6b416ad3c1d7cf6b5eb531e5b558ba3fffa891601801908152604051908190036020018120919091557f97fbf146e9c670352d80301abd7cde75ccfbcdf08ab75e279750732622d9d8d090600290610333905f516020611f4f5f395f51905f52815260140190565b908152604051908190036020018120919091557f6c6a373dfc1c5553f9acb5ba3cb2a89e181be32c73979c72505a7815d507b6ee90600290610385905f516020611f8f5f395f51905f528152601b0190565b908152604051908190036020018120919091557f9f4f94b6b3b840a08f85f3123c8c939368d4549b232d21a6fefeb9dc636649d9906002906103d7905f516020611faf5f395f51905f52815260140190565b9081526040805160209281900383018120939093555f516020611e6f5f395f51905f528352652a20aa24a7a760d11b8284015260026026840181905281519384900360460184207fcac0f88fc6ffb8c20072384bdbe3891b98fd745fb45563b2e2bd38b1587d5efa905583820182527f3f760137932ea6e95f1be1d2d173067f3d5fc02cf4b1f1388393ab65855362dc8452600192840183815282515f516020611f0f5f395f51905f52815260168101839052835190819003603601812095518655905194909301805460ff1916941515949094179093556d43414d504149474e5f504155534560901b8252600e82018390525190819003602e0181207f78e294b129638ed22e0f04d1112287ac0c9a136ff08550d5a5170c08c0d418d290556f43414d504149474e5f554e504155534560801b81527fc1945483820ee01d1b624365e29c94e52b173c14dc0f4ab675e6ecb36989fc0b9190601001908152604051908190036020018120919091557f5862bfc8f7700f9fe893f27ffb3e7fd32911673c2afa890fefd9a5f91cea3b0e90600290610585905f516020611e8f5f395f51905f528152601d0190565b908152604051908190036020018120919091557fcd2473051e89a6c4c126c020fb90ec534987e73d6606764391a756809c27bed7906002906105d7905f516020611eaf5f395f51905f528152601a0190565b90815260405160209181900382018120929092555f516020611ecf5f395f51905f528252632226a4a760e11b90820152610628906002906024015b908152604051908190036020019020545f610c8e565b61065a6002604051610612905f516020611f2f5f395f51905f5281526645455f5241544560c81b602082015260270190565b61068c6002604051610612905f516020611eef5f395f51905f52815266474e5f54494d4560c81b602082015260270190565b6106ae6002604051610612905f516020611f6f5f395f51905f528152601e0190565b6106e06002604051610612905f516020611def5f395f51905f52815266222faa27a5a2a760c91b602082015260270190565b6107106002604051610612905f516020611e4f5f395f51905f52815264434345535360d81b602082015260250190565b61073d6002604051610612905f516020611e0f5f395f51905f52815261535360f01b602082015260220190565b61075f6002604051610612905f516020611e2f5f395f51905f52815260180190565b6107816002604051610612905f516020611f4f5f395f51905f52815260140190565b6107a36002604051610612905f516020611f8f5f395f51905f528152601b0190565b6107c56002604051610612905f516020611faf5f395f51905f52815260140190565b6107f66002604051610612905f516020611e6f5f395f51905f528152652a20aa24a7a760d11b602082015260260190565b6108186002604051610612905f516020611f0f5f395f51905f52815260160190565b61083e6002604051610612906d43414d504149474e5f504155534560901b8152600e0190565b6108666002604051610612906f43414d504149474e5f554e504155534560801b815260100190565b6108886002604051610612905f516020611e8f5f395f51905f528152601d0190565b6108aa6002604051610612905f516020611eaf5f395f51905f528152601a0190565b5f5b8151811015610c87575f6001600160a01b03168282815181106108d1576108d1610f02565b60200260200101516001600160a01b0316036109335760405162461bcd60e51b815260206004820152601560248201527f5a45524f20414444524553532050524f56494445440000000000000000000000604482015260640160405180910390fd5b61095e5f5f1b83838151811061094b5761094b610f02565b6020026020010151610cd860201b60201c565b50805f03610a1057815f8151811061097857610978610f02565b60200260200101516001600160a01b03166080816001600160a01b0316815250506109eb60026040516109c8905f516020611ecf5f395f51905f528152632226a4a760e11b602082015260240190565b90815260200160405180910390205f015483838151811061094b5761094b610f02565b50610a0e60026040516109c8905f516020611f0f5f395f51905f52815260160190565b505b610a4260026040516109c8905f516020611f2f5f395f51905f5281526645455f5241544560c81b602082015260270190565b50610a7560026040516109c8905f516020611eef5f395f51905f52815266474e5f54494d4560c81b602082015260270190565b50610a9860026040516109c8905f516020611f6f5f395f51905f528152601e0190565b50610acb60026040516109c8905f516020611def5f395f51905f52815266222faa27a5a2a760c91b602082015260270190565b50610afc60026040516109c8905f516020611e4f5f395f51905f52815264434345535360d81b602082015260250190565b50610b2a60026040516109c8905f516020611e0f5f395f51905f52815261535360f01b602082015260220190565b50610b4d60026040516109c8905f516020611e2f5f395f51905f52815260180190565b50610b7060026040516109c8905f516020611f4f5f395f51905f52815260140190565b50610b9360026040516109c8905f516020611f8f5f395f51905f528152601b0190565b50610bb660026040516109c8905f516020611faf5f395f51905f52815260140190565b50610be860026040516109c8905f516020611e6f5f395f51905f528152652a20aa24a7a760d11b602082015260260190565b50610c0f60026040516109c8906d43414d504149474e5f504155534560901b8152600e0190565b50610c3860026040516109c8906f43414d504149474e5f554e504155534560801b815260100190565b50610c5b60026040516109c8905f516020611e8f5f395f51905f528152601d0190565b50610c7e60026040516109c8905f516020611eaf5f395f51905f528152601a0190565b506001016108ac565b5050610f16565b5f82815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b5f80610ce48484610d0e565b90508015610d05575f848152600160205260409020610d039084610db5565b505b90505b92915050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff16610dae575f838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055610d663390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610d08565b505f610d08565b5f610d05836001600160a01b0384165f818152600183016020526040812054610dae57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610d08565b634e487b7160e01b5f52604160045260245ffd5b80516001600160a01b0381168114610e33575f5ffd5b919050565b5f60208284031215610e48575f5ffd5b81516001600160401b03811115610e5d575f5ffd5b8201601f81018413610e6d575f5ffd5b80516001600160401b03811115610e8657610e86610e09565b604051600582901b90603f8201601f191681016001600160401b0381118282101715610eb457610eb4610e09565b604052918252602081840181019290810187841115610ed1575f5ffd5b6020850194505b83851015610ef757610ee985610e1d565b815260209485019401610ed8565b509695505050505050565b634e487b7160e01b5f52603260045260245ffd5b608051610eb3610f3c5f395f81816104260152818161050b015261066e0152610eb35ff3fe608060405234801561000f575f5ffd5b50600436106100f0575f3560e01c80639010d07c11610093578063afadb63911610063578063afadb63914610249578063c19ae2ed1461025c578063ca15c8731461026f578063d547741f14610282575f5ffd5b80639010d07c146101e457806391d148541461020f578063a217fddf14610222578063a3246ad314610229575f5ffd5b80632f2ff15d116100ce5780632f2ff15d1461019657806336568abe146101ab57806357087597146101be578063731f21a0146101d1575f5ffd5b806301ffc9a7146100f4578063159bdf951461011c578063248a9ca314610166575b5f5ffd5b610107610102366004610b70565b610295565b60405190151581526020015b60405180910390f35b61015161012a366004610bab565b80516020818301810180516002825292820191909301209152805460019091015460ff1682565b60408051928352901515602083015201610113565b610188610174366004610c5e565b5f9081526020819052604090206001015490565b604051908152602001610113565b6101a96101a4366004610c90565b6102bf565b005b6101a96101b9366004610c90565b6102d8565b6101a96101cc366004610cff565b610310565b6101a96101df366004610d3e565b6103df565b6101f76101f2366004610d8e565b6104a1565b6040516001600160a01b039091168152602001610113565b61010761021d366004610c90565b6104bf565b6101885f81565b61023c610237366004610c5e565b6104e7565b6040516101139190610dae565b6101a9610257366004610cff565b610500565b6101a961026a366004610d3e565b6105ef565b61018861027d366004610c5e565b6106de565b6101a9610290366004610c90565b6106f4565b5f6001600160e01b03198216635a05180f60e01b14806102b957506102b98261070d565b92915050565b604051631a8b050760e01b815260040160405180910390fd5b6001600160a01b03811633146103015760405163334bd91960e11b815260040160405180910390fd5b61030b8282610741565b505050565b5f61031a81610774565b6002838360405161032c929190610df9565b9081526040519081900360200190205415610367578282604051636c71ae2f60e11b815260040161035e929190610e08565b60405180910390fd5b828260405160200161037a929190610df9565b60405160208183030381529060405280519060200120600284846040516103a2929190610df9565b9081526040519081900360200181209190915561030b906002906103c99086908690610df9565b908152604051908190036020019020545f610781565b600283836040516103f1929190610df9565b908152604051908190036020019020545f036104245782826040516323e0a34160e11b815260040161035e929190610e08565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031603610476576040516337e337b760e21b815260040160405180910390fd5b61030b6002848460405161048b929190610df9565b90815260405190819003602001902054826107cb565b5f8281526001602052604081206104b890836107f5565b9392505050565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b5f8181526001602052604090206060906102b990610800565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146105495760405163158c031560e01b815260040160405180910390fd5b6002828260405161055b929190610df9565b908152604051908190036020019020545f0361058e5781816040516323e0a34160e11b815260040161035e929190610e08565b600282826040516105a0929190610df9565b9081526040519081900360200181206001015460ff1615906002906105c89085908590610df9565b908152604051908190036020019020600101805491151560ff199092169190911790555050565b60028383604051610601929190610df9565b908152604051908190036020019020545f036106345782826040516323e0a34160e11b815260040161035e929190610e08565b60028383604051610646929190610df9565b9081526040519081900360200190206001015460ff1680156106915750336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614155b156106b357828260405163ba0fac0b60e01b815260040161035e929190610e08565b61030b600284846040516106c8929190610df9565b908152604051908190036020019020548261080c565b5f8181526001602052604081206102b990610830565b60405163022c333960e21b815260040160405180910390fd5b5f6001600160e01b03198216637965db0b60e01b14806102b957506301ffc9a760e01b6001600160e01b03198316146102b9565b5f5f61074d8484610839565b905080156104b8575f84815260016020526040902061076c90846108a9565b509392505050565b61077e81336108bd565b50565b5f82815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b5f828152602081905260409020600101546107e581610774565b6107ef8383610741565b50505050565b5f6104b883836108fa565b60605f6104b883610920565b5f8281526020819052604090206001015461082681610774565b6107ef8383610979565b5f6102b9825490565b5f61084483836104bf565b156108a2575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016102b9565b505f6102b9565b5f6104b8836001600160a01b0384166109a4565b6108c782826104bf565b6108f65760405163e2517d3f60e01b81526001600160a01b03821660048201526024810183905260440161035e565b5050565b5f825f01828154811061090f5761090f610e36565b905f5260205f200154905092915050565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561096d57602002820191905f5260205f20905b815481526020019060010190808311610959575b50505050509050919050565b5f5f6109858484610a87565b905080156104b8575f84815260016020526040902061076c9084610b0f565b5f8181526001830160205260408120548015610a7e575f6109c6600183610e4a565b85549091505f906109d990600190610e4a565b9050808214610a38575f865f0182815481106109f7576109f7610e36565b905f5260205f200154905080875f018481548110610a1757610a17610e36565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080610a4957610a49610e69565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506102b9565b5f9150506102b9565b5f610a9283836104bf565b6108a2575f838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055610ac73390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016102b9565b5f6104b8836001600160a01b0384165f610b3b83835f9081526001919091016020526040902054151590565b6108a257508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556102b9565b5f60208284031215610b80575f5ffd5b81356001600160e01b0319811681146104b8575f5ffd5b634e487b7160e01b5f52604160045260245ffd5b5f60208284031215610bbb575f5ffd5b813567ffffffffffffffff811115610bd1575f5ffd5b8201601f81018413610be1575f5ffd5b803567ffffffffffffffff811115610bfb57610bfb610b97565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610c2a57610c2a610b97565b604052818152828201602001861015610c41575f5ffd5b816020840160208301375f91810160200191909152949350505050565b5f60208284031215610c6e575f5ffd5b5035919050565b80356001600160a01b0381168114610c8b575f5ffd5b919050565b5f5f60408385031215610ca1575f5ffd5b82359150610cb160208401610c75565b90509250929050565b5f5f83601f840112610cca575f5ffd5b50813567ffffffffffffffff811115610ce1575f5ffd5b602083019150836020828501011115610cf8575f5ffd5b9250929050565b5f5f60208385031215610d10575f5ffd5b823567ffffffffffffffff811115610d26575f5ffd5b610d3285828601610cba565b90969095509350505050565b5f5f5f60408486031215610d50575f5ffd5b833567ffffffffffffffff811115610d66575f5ffd5b610d7286828701610cba565b9094509250610d85905060208501610c75565b90509250925092565b5f5f60408385031215610d9f575f5ffd5b50508035926020909101359150565b602080825282518282018190525f918401906040840190835b81811015610dee5783516001600160a01b0316835260209384019390920191600101610dc7565b509095945050505050565b818382375f9101908152919050565b60208152816020820152818360408301375f818301604090810191909152601f909201601f19160101919050565b634e487b7160e01b5f52603260045260245ffd5b818103818111156102b957634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603160045260245ffdfea26469706673582212209011529bc1c4326a6dd088380bc1910e0613d1fbfd7aff497cd32d3745d878cd64736f6c634300081e003341444d494e495354524154494f4e5f52454d4f56455f57484954454c4953544541444d494e495354524154494f4e5f414c4c4f575f4f5241434c455f4143434541444d494e495354524154494f4e5f5345545f4d4f44454c000000000000000041444d494e495354524154494f4e5f444953414c4c4f575f4f5241434c455f4143414d504149474e5f464143544f52595f4348414e47455f494d504c454d454e43414d504149474e5f46494e414c495a455f494e5f50524f475245535300000043414d504149474e5f46494e414c495a455f46494e495348454400000000000041444d494e495354524154494f4e5f4348414e47455f50524f544f434f4c5f4141444d494e495354524154494f4e5f4348414e47455f4d41585f43414d50414943414d504149474e5f5245434f5645525f45524332300000000000000000000041444d494e495354524154494f4e5f4348414e47455f43414d504149474e5f46434f4e54454e54535f5345545f434f4e4649475300000000000000000000000041444d494e495354524154494f4e5f57484954454c4953545f544f4b454e0000434f4e54454e54535f5345545f5155414c494649434154494f4e530000000000434f4e54454e54535f5550444154455f4b5049530000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000300000000000000000000000087df94c894983cc2977b760d1587a0cc21284edc000000000000000000000000c2f8d4b61e078160630b6c93c5c51ec6f8304e260000000000000000000000000b8772240ed58008c12514f563b0b8e27dd5fb83
Deployed Bytecode
0x608060405234801561000f575f5ffd5b50600436106100f0575f3560e01c80639010d07c11610093578063afadb63911610063578063afadb63914610249578063c19ae2ed1461025c578063ca15c8731461026f578063d547741f14610282575f5ffd5b80639010d07c146101e457806391d148541461020f578063a217fddf14610222578063a3246ad314610229575f5ffd5b80632f2ff15d116100ce5780632f2ff15d1461019657806336568abe146101ab57806357087597146101be578063731f21a0146101d1575f5ffd5b806301ffc9a7146100f4578063159bdf951461011c578063248a9ca314610166575b5f5ffd5b610107610102366004610b70565b610295565b60405190151581526020015b60405180910390f35b61015161012a366004610bab565b80516020818301810180516002825292820191909301209152805460019091015460ff1682565b60408051928352901515602083015201610113565b610188610174366004610c5e565b5f9081526020819052604090206001015490565b604051908152602001610113565b6101a96101a4366004610c90565b6102bf565b005b6101a96101b9366004610c90565b6102d8565b6101a96101cc366004610cff565b610310565b6101a96101df366004610d3e565b6103df565b6101f76101f2366004610d8e565b6104a1565b6040516001600160a01b039091168152602001610113565b61010761021d366004610c90565b6104bf565b6101885f81565b61023c610237366004610c5e565b6104e7565b6040516101139190610dae565b6101a9610257366004610cff565b610500565b6101a961026a366004610d3e565b6105ef565b61018861027d366004610c5e565b6106de565b6101a9610290366004610c90565b6106f4565b5f6001600160e01b03198216635a05180f60e01b14806102b957506102b98261070d565b92915050565b604051631a8b050760e01b815260040160405180910390fd5b6001600160a01b03811633146103015760405163334bd91960e11b815260040160405180910390fd5b61030b8282610741565b505050565b5f61031a81610774565b6002838360405161032c929190610df9565b9081526040519081900360200190205415610367578282604051636c71ae2f60e11b815260040161035e929190610e08565b60405180910390fd5b828260405160200161037a929190610df9565b60405160208183030381529060405280519060200120600284846040516103a2929190610df9565b9081526040519081900360200181209190915561030b906002906103c99086908690610df9565b908152604051908190036020019020545f610781565b600283836040516103f1929190610df9565b908152604051908190036020019020545f036104245782826040516323e0a34160e11b815260040161035e929190610e08565b7f00000000000000000000000087df94c894983cc2977b760d1587a0cc21284edc6001600160a01b0316816001600160a01b031603610476576040516337e337b760e21b815260040160405180910390fd5b61030b6002848460405161048b929190610df9565b90815260405190819003602001902054826107cb565b5f8281526001602052604081206104b890836107f5565b9392505050565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b5f8181526001602052604090206060906102b990610800565b336001600160a01b037f00000000000000000000000087df94c894983cc2977b760d1587a0cc21284edc16146105495760405163158c031560e01b815260040160405180910390fd5b6002828260405161055b929190610df9565b908152604051908190036020019020545f0361058e5781816040516323e0a34160e11b815260040161035e929190610e08565b600282826040516105a0929190610df9565b9081526040519081900360200181206001015460ff1615906002906105c89085908590610df9565b908152604051908190036020019020600101805491151560ff199092169190911790555050565b60028383604051610601929190610df9565b908152604051908190036020019020545f036106345782826040516323e0a34160e11b815260040161035e929190610e08565b60028383604051610646929190610df9565b9081526040519081900360200190206001015460ff1680156106915750336001600160a01b037f00000000000000000000000087df94c894983cc2977b760d1587a0cc21284edc1614155b156106b357828260405163ba0fac0b60e01b815260040161035e929190610e08565b61030b600284846040516106c8929190610df9565b908152604051908190036020019020548261080c565b5f8181526001602052604081206102b990610830565b60405163022c333960e21b815260040160405180910390fd5b5f6001600160e01b03198216637965db0b60e01b14806102b957506301ffc9a760e01b6001600160e01b03198316146102b9565b5f5f61074d8484610839565b905080156104b8575f84815260016020526040902061076c90846108a9565b509392505050565b61077e81336108bd565b50565b5f82815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b5f828152602081905260409020600101546107e581610774565b6107ef8383610741565b50505050565b5f6104b883836108fa565b60605f6104b883610920565b5f8281526020819052604090206001015461082681610774565b6107ef8383610979565b5f6102b9825490565b5f61084483836104bf565b156108a2575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016102b9565b505f6102b9565b5f6104b8836001600160a01b0384166109a4565b6108c782826104bf565b6108f65760405163e2517d3f60e01b81526001600160a01b03821660048201526024810183905260440161035e565b5050565b5f825f01828154811061090f5761090f610e36565b905f5260205f200154905092915050565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561096d57602002820191905f5260205f20905b815481526020019060010190808311610959575b50505050509050919050565b5f5f6109858484610a87565b905080156104b8575f84815260016020526040902061076c9084610b0f565b5f8181526001830160205260408120548015610a7e575f6109c6600183610e4a565b85549091505f906109d990600190610e4a565b9050808214610a38575f865f0182815481106109f7576109f7610e36565b905f5260205f200154905080875f018481548110610a1757610a17610e36565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080610a4957610a49610e69565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506102b9565b5f9150506102b9565b5f610a9283836104bf565b6108a2575f838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055610ac73390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016102b9565b5f6104b8836001600160a01b0384165f610b3b83835f9081526001919091016020526040902054151590565b6108a257508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556102b9565b5f60208284031215610b80575f5ffd5b81356001600160e01b0319811681146104b8575f5ffd5b634e487b7160e01b5f52604160045260245ffd5b5f60208284031215610bbb575f5ffd5b813567ffffffffffffffff811115610bd1575f5ffd5b8201601f81018413610be1575f5ffd5b803567ffffffffffffffff811115610bfb57610bfb610b97565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610c2a57610c2a610b97565b604052818152828201602001861015610c41575f5ffd5b816020840160208301375f91810160200191909152949350505050565b5f60208284031215610c6e575f5ffd5b5035919050565b80356001600160a01b0381168114610c8b575f5ffd5b919050565b5f5f60408385031215610ca1575f5ffd5b82359150610cb160208401610c75565b90509250929050565b5f5f83601f840112610cca575f5ffd5b50813567ffffffffffffffff811115610ce1575f5ffd5b602083019150836020828501011115610cf8575f5ffd5b9250929050565b5f5f60208385031215610d10575f5ffd5b823567ffffffffffffffff811115610d26575f5ffd5b610d3285828601610cba565b90969095509350505050565b5f5f5f60408486031215610d50575f5ffd5b833567ffffffffffffffff811115610d66575f5ffd5b610d7286828701610cba565b9094509250610d85905060208501610c75565b90509250925092565b5f5f60408385031215610d9f575f5ffd5b50508035926020909101359150565b602080825282518282018190525f918401906040840190835b81811015610dee5783516001600160a01b0316835260209384019390920191600101610dc7565b509095945050505050565b818382375f9101908152919050565b60208152816020820152818360408301375f818301604090810191909152601f909201601f19160101919050565b634e487b7160e01b5f52603260045260245ffd5b818103818111156102b957634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603160045260245ffdfea26469706673582212209011529bc1c4326a6dd088380bc1910e0613d1fbfd7aff497cd32d3745d878cd64736f6c634300081e0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000300000000000000000000000087df94c894983cc2977b760d1587a0cc21284edc000000000000000000000000c2f8d4b61e078160630b6c93c5c51ec6f8304e260000000000000000000000000b8772240ed58008c12514f563b0b8e27dd5fb83
-----Decoded View---------------
Arg [0] : admins (address[]): 0x87DF94c894983cC2977b760d1587A0cC21284EdC,0xc2f8D4B61E078160630b6C93c5C51EC6F8304e26,0x0B8772240ED58008C12514F563B0b8e27dD5Fb83
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [2] : 00000000000000000000000087df94c894983cc2977b760d1587a0cc21284edc
Arg [3] : 000000000000000000000000c2f8d4b61e078160630b6c93c5c51ec6f8304e26
Arg [4] : 0000000000000000000000000b8772240ed58008c12514f563b0b8e27dd5fb83
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in FRAX
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
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.