Overview
APE Balance
APE Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 2 internal transactions
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
11016414 | 12 hrs ago | Contract Creation | 0 APE | |||
10564535 | 9 days ago | Contract Creation | 0 APE |
Loading...
Loading
Contract Name:
MetaAnchorFactory
Compiler Version
v0.8.18+commit.87f61d96
Contract Source Code (Solidity)
/** *Submitted for verification at apescan.io on 2025-02-25 */ // SPDX-License-Identifier: MIT AND UNLICENSED AND CC0-1.0 // // OpenZeppelin and ERC-6956 are licensed under MIT // Note ERC-6956 is authored by us (authenticvision.com) // IERC6454 is licensed under CC0-1.0 // // All other contracts are UNLICENSED, visit metaanchor.io for licensing information // // Meta Anchor (TM), Authentic Vision (TM) and Digital Soul (TM) are Registered Trademarks // and will be denoted as MetaAnchor, AuthenticVision and DigitalSoul subsequently. // Sources flattened with hardhat v2.12.6 https://hardhat.org // File @openzeppelin/contracts/access/[email protected] // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @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. * * _Available since v3.1._ */ 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, an admin role * bearer except when using {AccessControl-_setupRole}. */ 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 `account`. */ function renounceRole(bytes32 role, address account) external; } // File @openzeppelin/contracts/utils/[email protected] // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @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; } } // File @openzeppelin/contracts/utils/introspection/[email protected] // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * 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[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } // File @openzeppelin/contracts/utils/introspection/[email protected] // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 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); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } } // File @openzeppelin/contracts/utils/math/[email protected] // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } } // File @openzeppelin/contracts/utils/[email protected] // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } } // File @openzeppelin/contracts/access/[email protected] // OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol) pragma solidity ^0.8.0; /** * @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: * * ``` * 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}: * * ``` * 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. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ 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 override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(account), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @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 override 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 override 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 override 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 `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @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 Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } } // File @openzeppelin/contracts/access/[email protected] // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } } // File @openzeppelin/contracts/security/[email protected] // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; /** * @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 Pausable is Context { /** * @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); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @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(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } } // File @openzeppelin/contracts/token/ERC721/[email protected] // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); } // File @openzeppelin/contracts/token/ERC721/extensions/[email protected] // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); } // File @openzeppelin/contracts/token/ERC721/[email protected] // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); } // File @openzeppelin/contracts/utils/[email protected] // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } // File @openzeppelin/contracts/token/ERC721/[email protected] // OpenZeppelin Contracts (last updated v4.8.2) (token/ERC721/ERC721.sol) pragma solidity ^0.8.0; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including * the Metadata extension, but not including the Enumerable extension, which is available separately as * {ERC721Enumerable}. */ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { using Address for address; using Strings for uint256; // Token name string private _name; // Token symbol string private _symbol; // Mapping from token ID to owner address mapping(uint256 => address) private _owners; // Mapping owner address to token count mapping(address => uint256) private _balances; // Mapping from token ID to approved address mapping(uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; /** * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), "ERC721: address zero is not a valid owner"); return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { address owner = _ownerOf(tokenId); require(owner != address(0), "ERC721: invalid token ID"); return owner; } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireMinted(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ""; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721.ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require( _msgSender() == owner || isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not token owner or approved for all" ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { _requireMinted(tokenId); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom( address from, address to, uint256 tokenId ) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public virtual override { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory data ) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); _safeTransfer(from, to, tokenId, data); } /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * `data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer( address from, address to, uint256 tokenId, bytes memory data ) internal virtual { _transfer(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist */ function _ownerOf(uint256 tokenId) internal view virtual returns (address) { return _owners[tokenId]; } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted (`_mint`), * and stop existing when they are burned (`_burn`). */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _ownerOf(tokenId) != address(0); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { address owner = ERC721.ownerOf(tokenId); return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: * * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint( address to, uint256 tokenId, bytes memory data ) internal virtual { _mint(to, tokenId); require( _checkOnERC721Received(address(0), to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer" ); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(address(0), to, tokenId, 1); // Check that tokenId was not minted by `_beforeTokenTransfer` hook require(!_exists(tokenId), "ERC721: token already minted"); unchecked { // Will not overflow unless all 2**256 token ids are minted to the same owner. // Given that tokens are minted one by one, it is impossible in practice that // this ever happens. Might change if we allow batch minting. // The ERC fails to describe this case. _balances[to] += 1; } _owners[tokenId] = to; emit Transfer(address(0), to, tokenId); _afterTokenTransfer(address(0), to, tokenId, 1); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * This is an internal function that does not check if the sender is authorized to operate on the token. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal virtual { address owner = ERC721.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId, 1); // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook owner = ERC721.ownerOf(tokenId); // Clear approvals delete _tokenApprovals[tokenId]; unchecked { // Cannot overflow, as that would require more tokens to be burned/transferred // out than the owner initially received through minting and transferring in. _balances[owner] -= 1; } delete _owners[tokenId]; emit Transfer(owner, address(0), tokenId); _afterTokenTransfer(owner, address(0), tokenId, 1); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer( address from, address to, uint256 tokenId ) internal virtual { require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId, 1); // Check that tokenId was not transferred by `_beforeTokenTransfer` hook require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); // Clear approvals from the previous owner delete _tokenApprovals[tokenId]; unchecked { // `_balances[from]` cannot overflow for the same reason as described in `_burn`: // `from`'s balance is the number of token held, which is at least one before the current // transfer. // `_balances[to]` could overflow in the conditions described in `_mint`. That would require // all 2**256 token ids to be minted, which in practice is impossible. _balances[from] -= 1; _balances[to] += 1; } _owners[tokenId] = to; emit Transfer(from, to, tokenId); _afterTokenTransfer(from, to, tokenId, 1); } /** * @dev Approve `to` to operate on `tokenId` * * Emits an {Approval} event. */ function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721.ownerOf(tokenId), to, tokenId); } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Emits an {ApprovalForAll} event. */ function _setApprovalForAll( address owner, address operator, bool approved ) internal virtual { require(owner != operator, "ERC721: approve to caller"); _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Reverts if the `tokenId` has not been minted yet. */ function _requireMinted(uint256 tokenId) internal view virtual { require(_exists(tokenId), "ERC721: invalid token ID"); } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory data ) private returns (bool) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { return retval == IERC721Receiver.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("ERC721: transfer to non ERC721Receiver implementer"); } else { /// @solidity memory-safe-assembly assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } /** * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`. * - When `from` is zero, the tokens will be minted for `to`. * - When `to` is zero, ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * - `batchSize` is non-zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 firstTokenId, uint256 batchSize ) internal virtual {} /** * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`. * - When `from` is zero, the tokens were minted for `to`. * - When `to` is zero, ``from``'s tokens were burned. * - `from` and `to` are never both zero. * - `batchSize` is non-zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 firstTokenId, uint256 batchSize ) internal virtual {} /** * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override. * * WARNING: Anyone calling this MUST ensure that the balances remain consistent with the ownership. The invariant * being that for any address `a` the value returned by `balanceOf(a)` must be equal to the number of tokens such * that `ownerOf(tokenId)` is `a`. */ // solhint-disable-next-line func-name-mixedcase function __unsafe_increaseBalance(address account, uint256 amount) internal { _balances[account] += amount; } } // File @openzeppelin/contracts/token/ERC721/extensions/[email protected] // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Burnable.sol) pragma solidity ^0.8.0; /** * @title ERC721 Burnable Token * @dev ERC721 Token that can be burned (destroyed). */ abstract contract ERC721Burnable is Context, ERC721 { /** * @dev Burns `tokenId`. See {ERC721-_burn}. * * Requirements: * * - The caller must own `tokenId` or be an approved operator. */ function burn(uint256 tokenId) public virtual { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); _burn(tokenId); } } // File @openzeppelin/contracts/token/ERC721/extensions/[email protected] // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol) pragma solidity ^0.8.0; /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Enumerable is IERC721 { /** * @dev Returns the total amount of tokens stored by the contract. */ function totalSupply() external view returns (uint256); /** * @dev Returns a token ID owned by `owner` at a given `index` of its token list. * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. */ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); /** * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. * Use along with {totalSupply} to enumerate all tokens. */ function tokenByIndex(uint256 index) external view returns (uint256); } // File @openzeppelin/contracts/token/ERC721/extensions/[email protected] // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Enumerable.sol) pragma solidity ^0.8.0; /** * @dev This implements an optional extension of {ERC721} defined in the EIP that adds * enumerability of all the token ids in the contract as well as all token ids owned by each * account. */ abstract contract ERC721Enumerable is ERC721, IERC721Enumerable { // Mapping from owner to list of owned token IDs mapping(address => mapping(uint256 => uint256)) private _ownedTokens; // Mapping from token ID to index of the owner tokens list mapping(uint256 => uint256) private _ownedTokensIndex; // Array with all token ids, used for enumeration uint256[] private _allTokens; // Mapping from token id to position in the allTokens array mapping(uint256 => uint256) private _allTokensIndex; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. */ function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds"); return _ownedTokens[owner][index]; } /** * @dev See {IERC721Enumerable-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _allTokens.length; } /** * @dev See {IERC721Enumerable-tokenByIndex}. */ function tokenByIndex(uint256 index) public view virtual override returns (uint256) { require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds"); return _allTokens[index]; } /** * @dev See {ERC721-_beforeTokenTransfer}. */ function _beforeTokenTransfer( address from, address to, uint256 firstTokenId, uint256 batchSize ) internal virtual override { super._beforeTokenTransfer(from, to, firstTokenId, batchSize); if (batchSize > 1) { // Will only trigger during construction. Batch transferring (minting) is not available afterwards. revert("ERC721Enumerable: consecutive transfers not supported"); } uint256 tokenId = firstTokenId; if (from == address(0)) { _addTokenToAllTokensEnumeration(tokenId); } else if (from != to) { _removeTokenFromOwnerEnumeration(from, tokenId); } if (to == address(0)) { _removeTokenFromAllTokensEnumeration(tokenId); } else if (to != from) { _addTokenToOwnerEnumeration(to, tokenId); } } /** * @dev Private function to add a token to this extension's ownership-tracking data structures. * @param to address representing the new owner of the given token ID * @param tokenId uint256 ID of the token to be added to the tokens list of the given address */ function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { uint256 length = ERC721.balanceOf(to); _ownedTokens[to][length] = tokenId; _ownedTokensIndex[tokenId] = length; } /** * @dev Private function to add a token to this extension's token tracking data structures. * @param tokenId uint256 ID of the token to be added to the tokens list */ function _addTokenToAllTokensEnumeration(uint256 tokenId) private { _allTokensIndex[tokenId] = _allTokens.length; _allTokens.push(tokenId); } /** * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for * gas optimizations e.g. when performing a transfer operation (avoiding double writes). * This has O(1) time complexity, but alters the order of the _ownedTokens array. * @param from address representing the previous owner of the given token ID * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address */ function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = ERC721.balanceOf(from) - 1; uint256 tokenIndex = _ownedTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary if (tokenIndex != lastTokenIndex) { uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index } // This also deletes the contents at the last position of the array delete _ownedTokensIndex[tokenId]; delete _ownedTokens[from][lastTokenIndex]; } /** * @dev Private function to remove a token from this extension's token tracking data structures. * This has O(1) time complexity, but alters the order of the _allTokens array. * @param tokenId uint256 ID of the token to be removed from the tokens list */ function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = _allTokens.length - 1; uint256 tokenIndex = _allTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding // an 'if' statement (like in _removeTokenFromOwnerEnumeration) uint256 lastTokenId = _allTokens[lastTokenIndex]; _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index // This also deletes the contents at the last position of the array delete _allTokensIndex[tokenId]; _allTokens.pop(); } } // File @openzeppelin/contracts/utils/introspection/[email protected] // OpenZeppelin Contracts (last updated v4.8.2) (utils/introspection/ERC165Checker.sol) pragma solidity ^0.8.0; /** * @dev Library used to query support of an interface declared via {IERC165}. * * Note that these functions return the actual result of the query: they do not * `revert` if an interface is not supported. It is up to the caller to decide * what to do in these cases. */ library ERC165Checker { // As per the EIP-165 spec, no interface should ever match 0xffffffff bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff; /** * @dev Returns true if `account` supports the {IERC165} interface. */ function supportsERC165(address account) internal view returns (bool) { // Any contract that implements ERC165 must explicitly indicate support of // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid return supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) && !supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID); } /** * @dev Returns true if `account` supports the interface defined by * `interfaceId`. Support for {IERC165} itself is queried automatically. * * See {IERC165-supportsInterface}. */ function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { // query support of both ERC165 as per the spec and support of _interfaceId return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId); } /** * @dev Returns a boolean array where each value corresponds to the * interfaces passed in and whether they're supported or not. This allows * you to batch check interfaces for a contract where your expectation * is that some interfaces may not be supported. * * See {IERC165-supportsInterface}. * * _Available since v3.4._ */ function getSupportedInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool[] memory) { // an array of booleans corresponding to interfaceIds and whether they're supported or not bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length); // query support of ERC165 itself if (supportsERC165(account)) { // query support of each interface in interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]); } } return interfaceIdsSupported; } /** * @dev Returns true if `account` supports all the interfaces defined in * `interfaceIds`. Support for {IERC165} itself is queried automatically. * * Batch-querying can lead to gas savings by skipping repeated checks for * {IERC165} support. * * See {IERC165-supportsInterface}. */ function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { // query support of ERC165 itself if (!supportsERC165(account)) { return false; } // query support of each interface in interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) { return false; } } // all interfaces supported return true; } /** * @notice Query if a contract implements an interface, does not check ERC165 support * @param account The address of the contract to query for support of an interface * @param interfaceId The interface identifier, as specified in ERC-165 * @return true if the contract at account indicates support of the interface with * identifier interfaceId, false otherwise * @dev Assumes that account contains a contract that supports ERC165, otherwise * the behavior of this method is undefined. This precondition can be checked * with {supportsERC165}. * * Some precompiled contracts will falsely indicate support for a given interface, so caution * should be exercised when using this function. * * Interface identification is specified in ERC-165. */ function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) { // prepare call bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId); // perform static call bool success; uint256 returnSize; uint256 returnValue; assembly { success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20) returnSize := returndatasize() returnValue := mload(0x00) } return success && returnSize >= 0x20 && returnValue > 0; } } // File contracts/DeployerContract.sol pragma solidity ^0.8.18; /** * @title Interface for contracts featuring cascade-verification of the deployment origination * @author [email protected] * @notice Allows cascade-verification of a deployment origination across multiple DeployerContracts * @dev Contracts implementing this interface must take as the first constructor-parameter the address of the * `DeployerContract` */ interface IDeployedContract { /** * @notice Indicates whether addr has been directly or indirectly deployed by this contract * @dev Indirect deployment means e.g. by deploying through a contract that has been deployed by this contract * * @param addr Address of the deployed contract requesting initArgs * @return hasDeployedAddr abi-encoded init args */ function hasDeployed(address addr) external view returns (bool hasDeployedAddr); /** * Returns the deployer of a particular contract. Can be EOA or Contract Account */ function deployedBy() external view returns (address deployer); } /** * @title Predictable-Deployment contract of origin-verifyable contracts * @author [email protected] * @notice Deploys contracts implementing IDeployedContract based on passed bytecode and constructorArgs and allows to trace their origin * across multiple Deployercontracts * * @dev Has a static deployment salt, which shall only be changed in absolute emergencies. * The root contract is typically deployed by the Nonce=0 of an account on different blockchains. * This ensures that all contracts can be cascade-verified to originate from one well-known and trusted * source, e.g. an AppHub for a company. * */ abstract contract DeployerContract is IDeployedContract { mapping (address => address) private _deployedContractsWithOperator; IDeployedContract[] public deployedContracts; address public deployedBy; bytes32 private _salt; /** * @notice Emits when a contract is deployed through `deploy()` * @param deployedAddress Address of the just deployed contract * @param operator The operator initiating the deployment */ event ContractDeployed(address deployedAddress, address operator); /** * @notice Emits (in emergencies), when salt is updated. * @param newSalt The new salt used for new deployments * @param oldSalt The old salt, has been used for previous deployments * @param maintainer Initiator of the salt update */ event DeploymentSaltUpdate(bytes32 newSalt, bytes32 oldSalt, address maintainer); /** * @notice Indicates whether `addr` can use the `deploy()` function. * @dev To be overwritten by extending contracts, typically by only authorizing a specific role. * @param addr The address in question */ function canDeploy(address addr) public virtual returns (bool); modifier onlyDeployer() { require(canDeploy(msg.sender), "msg.sender must be deployer"); _; } /** * Returns the predicted address (with the current `_salt`) for a provided bytecode and constructorArgs * @param bytecode The bytecode to be deployed * @param constructorArgs abi-encoded constructor args, accepted by the constructor of the contract in bytecode */ function getAddress( bytes memory bytecode, bytes memory constructorArgs ) public view returns (address) { uint actualSalt = uint(_salt); bytes32 hash = keccak256( abi.encodePacked(bytes1(0xff), address(this), actualSalt, keccak256(_assembleByteCodeAndArgs(bytecode, constructorArgs))) ); // NOTE: cast last 20 bytes of hash to address return address(uint160(uint(hash))); } /** * @notice Like `getAddress(bytes,bytes)`, but for constructors not taking additional arguments (additional to deployer address) * @param bytecode Bytecode to be deployed */ function getAddress( bytes memory bytecode ) public view returns (address) { return getAddress(bytecode, abi.encode(address(this))); } /** * @notice Indicates whether a contract at `addr` directly or indirectly has been deployed through this contract * @param addr Address of the contract in question * @dev This function is typically cascade-called from parent DeployerContracts */ function hasDeployed(address addr) public view returns (bool hasDeployedAddr) { if(_deployedContractsWithOperator[addr] != address(0)) { return true; } for(uint i=0; i<deployedContracts.length; i++) { if(deployedContracts[i].hasDeployed(addr)) { return true; } } return false; } /** * @dev Internhal helper to pack bytecode and constructor args. Ensurs the first constructor argument is the deployer, i.e. address(this) * @param byteCode Bytecode excl constructor args * @param constructorArgs ABI-encoded, expected to have the address of this contract encoded as first argument */ function _assembleByteCodeAndArgs(bytes memory byteCode, bytes memory constructorArgs) internal view returns (bytes memory bytecodeWithArgs) { (address deployerAddress) = abi.decode(constructorArgs, (address)); require(deployerAddress == address(this), "First constructor arg must be address of this contract"); return abi.encodePacked(byteCode, constructorArgs); } /** * @notice Deploys bytecode of IDeployedContract-implementing contract with constructor args * @param byteCode Bytecode of contract implementing IDeployedContract * @param constructorArgs ABI-encoded constructor args, first argument must be address of this contract * @dev Emits ContractDeployed * Throws if bytecode does not implement IDeployedContract * Throws if `deployedBy()` of the deployed contract does not indicate this contract as deployer, * hence `hasDeployed()` mechanism would fail */ function deploy(bytes memory byteCode, bytes memory constructorArgs) public onlyDeployer() { // verify first argument of constructorArgs is address(this) address addr = _deployBinary(_assembleByteCodeAndArgs(byteCode, constructorArgs), _salt); // verify the contract implements IDeployedContract require(ERC165Checker.supportsInterface(addr, type(IDeployedContract).interfaceId), "Can only deploy contracts implementing IDeployedContract interface"); // verify contract claims this contract as deployer require(IDeployedContract(addr).deployedBy() == address(this), "Deployed contract must return this contract in getDeployer()"); emit ContractDeployed(addr, msg.sender); _deployedContractsWithOperator[addr] = msg.sender; deployedContracts.push(IDeployedContract(addr)); } /** * @notice Like deploy(bytes,bytes), but adds address(this) as only constructor argument * @param byteCode Bytecode of contract implementing IDeployedContract */ function deploy(bytes memory byteCode) public onlyDeployer() { deploy(byteCode, abi.encode(address(this))); } /** * @notice Updates the deployment salt - do only use in absolut emergencies! * @dev This shall not be used at all and is just for emergencies and major fuckups. As soon * as the salt is updated, it can happen that the same contract / same version / same constructorArgs * can be re-deployed to a different address. */ function updateDeploymentSalt(bytes32 newSalt) public onlyDeployer() { emit DeploymentSaltUpdate(_salt, newSalt, msg.sender); _salt = newSalt; } /** * @param bytecode Bytecode + packed constructorArgs of contract implementing IDeployedContract * @param salt The deployment salt. * @dev Isolated function to actually deploy contracts (can be used by extending contracts) * inspired by https://solidity-by-example.org/app/create2/ * Salt is taken as parameter to also allow deploying contracts with an "old" salt in case of * emergency salt-upgrade. */ function _deployBinary(bytes memory bytecode, bytes32 salt) internal virtual onlyDeployer() returns (address) { address addr; uint actualSalt = uint(salt); /* NOTE: How to call create2 create2(v, p, n, s) create new contract with code at memory p to p + n and send v wei and return the new address where new address = first 20 bytes of keccak256(0xff + address(this) + s + keccak256(mem[p…(p+n))) s = big-endian 256-bit value */ assembly { addr := create2( callvalue(), // wei sent with current call // Actual code starts after skipping the first 32 bytes add(bytecode, 0x20), mload(bytecode), // Load the size of code contained in the first 32 bytes actualSalt // Salt from function arguments ) if iszero(extcodesize(addr)) { revert(0, 0) } } return addr; } constructor() { deployedBy = msg.sender; } } // File contracts/AppHub.sol pragma solidity ^0.8.18; /** * @title AuthenticVision MetaAnchor AppHub * @author [email protected] * @notice Used to manage roles and verify a deployed contract originates directly or indirectly from this AppHub. * @dev This can be seen as the "AuthenticVision root certificate". All contracts deployed by Authentic Vision * will have `hasDeployed(address)==true`. Only these contracts originate from Authentic Vision. * * This AppHub will be deployed at the same address in all Blockchains we support. * * Visit authenticvision.com for contact and further information */ contract AppHub is AccessControl, DeployerContract { /** * @notice DEPLOYER_ROLE can deploy new MetaAnchor-Contracts from MetaAnchorFactory * @return Role hash, as should be passed to hasRole(), grantRole() */ bytes32 public constant DEPLOYER_ROLE = keccak256("DEPLOYER_ROLE"); /** * @notice FACTORY_DEPLOYER_ROLE can deploy factories (via AppHub) */ bytes32 public constant FACTORY_DEPLOYER_ROLE = keccak256("FACTORY_DEPLOYER_ROLE"); /** * @notice FACTORY_MAINTAINER_ROLE can maintain factories, e.g. add providers, remove registrations, .. */ bytes32 public constant FACTORY_MAINTAINER_ROLE = keccak256("FACTORY_MAINTAINER_ROLE"); /** * @notice MAINTAINER_ROLE can maintain MetaAnchor-Contracts, e.g. updateValidAnchors(), configurations, owners, etc. */ bytes32 public constant MAINTAINER_ROLE = keccak256("MAINTAINER_ROLE"); /** * @notice Signatures for ORACLE_ROLE will be accepted for ERC-6956 attestations */ bytes32 public constant ORACLE_ROLE = keccak256("ORACLE_ROLE"); /** * @notice PAUSER_ROLE has permission to pause contracts */ bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); /** * @notice REGISTRAR_ROLE can register (and unregister their own) contracts for deployment */ bytes32 public constant REGISTRAR_ROLE = keccak256("REGISTRAR_ROLE"); /** * @notice Overrides authorization functionality from `DeployerContract` to allow only FACTORY_DEPLOYER_ROLE accounts * @param addr Account address in equestion * @return addrIsDeployer true indicates this account can deploy contracts via `deploy()` method */ function canDeploy(address addr) public view override(DeployerContract) returns (bool addrIsDeployer) { return hasRole(FACTORY_DEPLOYER_ROLE, addr); } constructor() { _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); } } // File contracts/AppContract.sol pragma solidity ^0.8.18; /** * @title AppContract for access control. Base-class for actual contracts controlled by AppHub * @author [email protected] */ contract AppContract is AccessControl { AppHub internal _hub; constructor(address hub) { _hub = AppHub(hub); } /** * @dev Returns `true` if `account` has been granted `role`. * @notice Check whether a specific account has a certain role. This role is also set in all linked contracts. */ function hasRole(bytes32 role, address account) public view virtual override(AccessControl) returns (bool) { return (super.hasRole(role, account) || _hub.hasRole(role, account)); } /** * @dev Updates the address of app_hub. * @param hub Address of the app-hub */ function updateAppHub(address hub) public onlyRole(DEFAULT_ADMIN_ROLE) { address prevHubAddr = address(_hub); _hub = AppHub(hub); // after update, I still need to have the default admin role from appHub require(ERC165Checker.supportsInterface(hub, type(IDeployedContract).interfaceId), "AppHub must implement IDeployedContract"); require(_hub.hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Account has no admin role in AppHub"); emit AppHubUpdate(hub, prevHubAddr, msg.sender); } event AppHubUpdate(address hub, address oldHub, address maintainer); // The following functions are overrides required by Solidity, EIP-165. function supportsInterface(bytes4 interfaceId) public view virtual override(AccessControl) returns (bool) { return super.supportsInterface(interfaceId); } } // File @openzeppelin/contracts/utils/[email protected] // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol) pragma solidity ^0.8.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` */ library Counters { struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { unchecked { counter._value += 1; } } function decrement(Counter storage counter) internal { uint256 value = counter._value; require(value > 0, "Counter: decrement overflow"); unchecked { counter._value = value - 1; } } function reset(Counter storage counter) internal { counter._value = 0; } } // File contracts/eip-6956/IERC6956.sol pragma solidity ^0.8.18; /** * @title IERC6956 Asset-Bound Non-Fungible Tokens * @notice Asset-bound Non-Fungible Tokens anchor a token 1:1 to a (physical or digital) asset and token transfers are authorized through attestation of control over the asset * @dev See https://eips.ethereum.org/EIPS/eip-6956 * Note: The ERC-165 identifier for this interface is 0xa9cf7635 */ interface IERC6956 { /** @dev Authorization, typically mapped to authorizationMaps, where each bit indicates whether a particular ERC6956Role is authorized * Typically used in constructor (hardcoded or params) to set burnAuthorization and approveAuthorization * Also used in optional updateBurnAuthorization, updateApproveAuthorization, I */ enum Authorization { NONE, // = 0, // None of the above OWNER, // = (1<<OWNER), // The owner of the token, i.e. the digital representation ISSUER, // = (1<<ISSUER), // The issuer of the tokens, i.e. this smart contract ASSET, // = (1<<ASSET), // The asset, i.e. via attestation OWNER_AND_ISSUER, // = (1<<OWNER) | (1<<ISSUER), OWNER_AND_ASSET, // = (1<<OWNER) | (1<<ASSET), ASSET_AND_ISSUER, // = (1<<ASSET) | (1<<ISSUER), ALL // = (1<<OWNER) | (1<<ISSUER) | (1<<ASSET) // Owner + Issuer + Asset } /** * @notice This emits when approved address for an anchored tokenId is changed or reaffirmed via attestation * @dev This emits when approveAnchor() is called and corresponds to ERC-721 behavior * @param owner The owner of the anchored tokenId * @param approved The approved address, address(0) indicates there is no approved address * @param anchor The anchor, for which approval has been chagned * @param tokenId ID (>0) of the anchored token */ event AnchorApproval(address indexed owner, address approved, bytes32 indexed anchor, uint256 tokenId); /** * @notice This emits when the ownership of any anchored NFT changes by any mechanism * @dev This emits together with tokenId-based ERC-721.Transfer and provides an anchor-perspective on transfers * @param from The previous owner, address(0) indicate there was none. * @param to The new owner, address(0) indicates the token is burned * @param anchor The anchor which is bound to tokenId * @param tokenId ID (>0) of the anchored token */ event AnchorTransfer(address indexed from, address indexed to, bytes32 indexed anchor, uint256 tokenId); /** * @notice This emits when an attestation has been used indicating no second attestation with the same attestationHash will be accepted * @param to The to address specified in the attestation * @param anchor The anchor specificed in the attestation * @param attestationHash The hash of the attestation, see ERC-6956 for details * @param totalUsedAttestationsForAnchor The total number of attestations already used for the particular anchor */ event AttestationUse(address indexed to, bytes32 indexed anchor, bytes32 indexed attestationHash, uint256 totalUsedAttestationsForAnchor); /** * @notice This emits when the trust-status of an oracle changes. * @dev Trusted oracles must explicitely be specified. * If the last event for a particular oracle-address indicates it's trusted, attestations from this oracle are valid. * @param oracle Address of the oracle signing attestations * @param trusted indicating whether this address is trusted (true). Use (false) to no longer trust from an oracle. */ event OracleUpdate(address indexed oracle, bool indexed trusted); /** * @notice Returns the 1:1 mapped anchor for a tokenId * @param tokenId ID (>0) of the anchored token * @return anchor The anchor bound to tokenId, 0x0 if tokenId does not represent an anchor */ function anchorByToken(uint256 tokenId) external view returns (bytes32 anchor); /** * @notice Returns the ID of the 1:1 mapped token of an anchor. * @param anchor The anchor (>0x0) * @return tokenId ID of the anchored token, 0 if no anchored token exists */ function tokenByAnchor(bytes32 anchor) external view returns (uint256 tokenId); /** * @notice The number of attestations already used to modify the state of an anchor or its bound tokens * @param anchor The anchor(>0) * @return attestationUses The number of attestation uses for a particular anchor, 0 if anchor is invalid. */ function attestationsUsedByAnchor(bytes32 anchor) view external returns (uint256 attestationUses); /** * @notice Decodes and returns to-address, anchor and the attestation hash, if the attestation is valid * @dev MUST throw when * - Attestation has already been used (an AttestationUse-Event with matching attestationHash was emitted) * - Attestation is not signed by trusted oracle (the last OracleUpdate-Event for the signer-address does not indicate trust) * - Attestation is not valid yet or expired * - [if IERC6956AttestationLimited is implemented] attestationUsagesLeft(attestation.anchor) <= 0 * - [if IERC6956ValidAnchors is implemented] validAnchors(data) does not return true. * @param attestation The attestation subject to the format specified in ERC-6956 * @param data Optional additional data, may contain proof as the first abi-encoded argument when IERC6956ValidAnchors is implemented * @return to Address where the ownership of an anchored token or approval shall be changed to * @return anchor The anchor (>0) * @return attestationHash The attestation hash computed on-chain as `keccak256(attestation)` */ function decodeAttestationIfValid(bytes memory attestation, bytes memory data) external view returns (address to, bytes32 anchor, bytes32 attestationHash); /** * @notice Indicates whether any of ASSET, OWNER, ISSUER is authorized to burn */ function burnAuthorization() external view returns(Authorization burnAuth); /** * @notice Indicates whether any of ASSET, OWNER, ISSUER is authorized to approve */ function approveAuthorization() external view returns(Authorization approveAuth); /** * @notice Corresponds to transferAnchor(bytes,bytes) without additional data * @param attestation Attestation, refer ERC-6956 for details */ function transferAnchor(bytes memory attestation) external; /** * @notice Changes the ownership of an NFT mapped to attestation.anchor to attestation.to address. * @dev Permissionless, i.e. anybody invoke and sign a transaction. The transfer is authorized through the oracle-signed attestation. * - Uses decodeAttestationIfValid() * - When using a centralized "gas-payer" recommended to implement IERC6956AttestationLimited. * - Matches the behavior of ERC-721.safeTransferFrom(ownerOf[tokenByAnchor(attestation.anchor)], attestation.to, tokenByAnchor(attestation.anchor), ..) and mint an NFT if `tokenByAnchor(anchor)==0`. * - Throws when attestation.to == ownerOf(tokenByAnchor(attestation.anchor)) * - Emits AnchorTransfer * * @param attestation Attestation, refer EIP-6956 for details * @param data Additional data, may be used for additional transfer-conditions, may be sent partly or in full in a call to safeTransferFrom * */ function transferAnchor(bytes memory attestation, bytes memory data) external; /** * @notice Corresponds to approveAnchor(bytes,bytes) without additional data * @param attestation Attestation, refer ERC-6956 for details */ function approveAnchor(bytes memory attestation) external; /** * @notice Approves attestation.to the token bound to attestation.anchor. . * @dev Permissionless, i.e. anybody invoke and sign a transaction. The transfer is authorized through the oracle-signed attestation. * - Uses decodeAttestationIfValid() * - When using a centralized "gas-payer" recommended to implement IERC6956AttestationLimited. * - Matches the behavior of ERC-721.approve(attestation.to, tokenByAnchor(attestation.anchor)). * - Throws when ASSET is not authorized to approve. * * @param attestation Attestation, refer EIP-6956 for details */ function approveAnchor(bytes memory attestation, bytes memory data) external; /** * @notice Corresponds to burnAnchor(bytes,bytes) without additional data * @param attestation Attestation, refer ERC-6956 for details */ function burnAnchor(bytes memory attestation) external; /** * @notice Burns the token mapped to attestation.anchor. Uses ERC-721._burn. * @dev Permissionless, i.e. anybody invoke and sign a transaction. The transfer is authorized through the oracle-signed attestation. * - Uses decodeAttestationIfValid() * - When using a centralized "gas-payer" recommended to implement IERC6956AttestationLimited. * - Throws when ASSET is not authorized to burn * * @param attestation Attestation, refer EIP-6956 for details */ function burnAnchor(bytes memory attestation, bytes memory data) external; } // File contracts/eip-6956/ERC6956.sol pragma solidity ^0.8.18; /** Used for several authorization mechansims, e.g. who can burn, who can set approval, ... * @dev Specifying the role in the ecosystem. Used in conjunction with IERC6956.Authorization */ enum Role { OWNER, // =0, The owner of the digital token ISSUER, // =1, The issuer (contract) of the tokens, typically represented through a MAINTAINER_ROLE, the contract owner etc. ASSET, // =2, The asset identified by the anchor INVALID // =3, Reserved, do not use. } /** * @title ASSET-BOUND NFT minimal reference implementation * @author Thomas Bergmueller (@tbergmueller) * * @dev Error messages * ``` * ERROR | Message * ------|------------------------------------------------------------------- * E1 | Only maintainer allowed * E2 | No permission to burn * E3 | Token does not exist, call transferAnchor first to mint * E4 | batchSize must be 1 * E5 | Token not transferable * E6 | Token already owned * E7 | Not authorized based on ERC6956Authorization * E8 | Attestation not signed by trusted oracle * E9 | Attestation already used * E10 | Attestation not valid yet * E11 | Attestation expired * E12 | Attestation expired (contract limit) * E13 | Invalid signature length * E14-20| Reserved for future use * ``` */ contract ERC6956 is ERC721, ERC721Enumerable, ERC721Burnable, IERC6956 { using Counters for Counters.Counter; mapping(bytes32 => bool) internal _anchorIsReleased; // currently released anchors. Per default, all anchors are dropped, i.e. 1:1 bound mapping(address => bool) public maintainers; /// @notice Resolves tokenID to anchor. Inverse of tokenByAnchor mapping(uint256 => bytes32) public anchorByToken; /// @notice Resolves Anchor to tokenID. Inverse of anchorByToken mapping(bytes32 => uint256) public tokenByAnchor; mapping(address => bool) private _trustedOracles; /// @dev stores the anchors for each attestation mapping(bytes32 => bytes32) private _anchorByUsedAttestation; /// @dev stores handed-back tokens (via burn) mapping (bytes32 => uint256) private _burnedTokensByAnchor; /** * @dev Counter to keep track of issued tokens */ Counters.Counter private _tokenIdCounter; /// @dev Default validity timespan of attestation. In validateAttestation the attestationTime is checked for MIN(defaultAttestationvalidity, attestation.expiry) uint256 public maxAttestationExpireTime = 5*60; // 5min valid per default Authorization public burnAuthorization; Authorization public approveAuthorization; /// @dev Records the number of transfers done for each attestation mapping(bytes32 => uint256) public attestationsUsedByAnchor; modifier onlyMaintainer() { require(isMaintainer(msg.sender), "ERC6956-E1"); _; } /** * @notice Behaves like ERC721 burn() for wallet-cleaning purposes. Note only the tokenId (as a wrapper) is burned, not the ASSET represented by the ANCHOR. * @dev * - tokenId is remembered for the anchor, to ensure a later transferAnchor(), which would mint, assigns the same tokenId. This ensures strict 1:1 relation * - For burning, the anchor needs to be released. This forced release FOR BURNING ONLY is allowed for owner() or approvedOwner(). * * @param tokenId The token that shall be burned */ function burn(uint256 tokenId) public override { // remember the tokenId of burned tokens, s.t. one can issue the token with the same number again bytes32 anchor = anchorByToken[tokenId]; require(_roleBasedAuthorization(anchor, createAuthorizationMap(burnAuthorization)), "ERC6956-E2"); _burn(tokenId); } function burnAnchor(bytes memory attestation, bytes memory data) public virtual authorized(Role.ASSET, createAuthorizationMap(burnAuthorization)) { address to; bytes32 anchor; bytes32 attestationHash; (to, anchor, attestationHash) = decodeAttestationIfValid(attestation, data); _commitAttestation(to, anchor, attestationHash); uint256 tokenId = tokenByAnchor[anchor]; // remember the tokenId of burned tokens, s.t. one can issue the token with the same number again _burn(tokenId); } function burnAnchor(bytes memory attestation) public virtual { return burnAnchor(attestation, ""); } function approveAnchor(bytes memory attestation, bytes memory data) public virtual authorized(Role.ASSET, createAuthorizationMap(approveAuthorization)) { address to; bytes32 anchor; bytes32 attestationHash; (to, anchor, attestationHash) = decodeAttestationIfValid(attestation, data); _commitAttestation(to, anchor, attestationHash); require(tokenByAnchor[anchor]>0, "ERC6956-E3"); _approve(to, tokenByAnchor[anchor]); } // approveAuth == ISSUER does not really make sense.. so no separate implementation, since ERC-721.approve already implies owner... function approve(address to, uint256 tokenId) public virtual override(ERC721,IERC721) authorized(Role.OWNER, createAuthorizationMap(approveAuthorization)) { super.approve(to, tokenId); } function approveAnchor(bytes memory attestation) public virtual { return approveAnchor(attestation, ""); } /** * @notice Adds or removes a trusted oracle, used when verifying signatures in `decodeAttestationIfValid()` * @dev Emits OracleUpdate * @param oracle address of oracle * @param doTrust true to add, false to remove */ function updateOracle(address oracle, bool doTrust) public onlyMaintainer() { _trustedOracles[oracle] = doTrust; emit OracleUpdate(oracle, doTrust); } /** * @dev A very simple function wich MUST return false, when `a` is not a maintainer * When derived contracts extend ERC6956 contract, this function may be overridden * e.g. by using AccessControl, onlyOwner or other common mechanisms * * Having this simple mechanism in the reference implementation ensures that the reference * implementation is fully ERC-6956 compatible */ function isMaintainer(address a) public virtual view returns (bool) { return maintainers[a]; } function createAuthorizationMap(Authorization _auth) public pure returns (uint256) { uint256 authMap = 0; if(_auth == Authorization.OWNER || _auth == Authorization.OWNER_AND_ASSET || _auth == Authorization.OWNER_AND_ISSUER || _auth == Authorization.ALL) { authMap |= uint256(1<<uint256(Role.OWNER)); } if(_auth == Authorization.ISSUER || _auth == Authorization.ASSET_AND_ISSUER || _auth == Authorization.OWNER_AND_ISSUER || _auth == Authorization.ALL) { authMap |= uint256(1<<uint256(Role.ISSUER)); } if(_auth == Authorization.ASSET || _auth == Authorization.ASSET_AND_ISSUER || _auth == Authorization.OWNER_AND_ASSET || _auth == Authorization.ALL) { authMap |= uint256(1<<uint256(Role.ASSET)); } return authMap; } function _roleBasedAuthorization(bytes32 anchor, uint256 authorizationMap) internal view returns (bool) { uint256 tokenId = tokenByAnchor[anchor]; Role myRole = Role.INVALID; Role alternateRole = Role.INVALID; if(_isApprovedOrOwner(_msgSender(), tokenId)) { myRole = Role.OWNER; } if(isMaintainer(msg.sender)) { alternateRole = Role.ISSUER; } return hasAuthorization(myRole, authorizationMap) || hasAuthorization(alternateRole, authorizationMap); } ///@dev Hook executed before decodeAttestationIfValid returns. Override in derived contracts function _beforeAttestationUse(bytes32 anchor, address to, bytes memory data) internal view virtual {} function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize) internal virtual override(ERC721, ERC721Enumerable) { require(batchSize == 1, "ERC6956-E4"); bytes32 anchor = anchorByToken[tokenId]; emit AnchorTransfer(from, to, anchor, tokenId); if(to == address(0)) { // we are burning, ensure the mapping is deleted BEFORE the transfer // to avoid reentrant-attacks _burnedTokensByAnchor[anchor] = tokenId; // Remember tokenId for a potential re-mint delete tokenByAnchor[anchor]; delete anchorByToken[tokenId]; } else { require(_anchorIsReleased[anchor], "ERC6956-E5"); } delete _anchorIsReleased[anchor]; // make sure anchor is non-released after the transfer again } /// @dev hook called after an anchor is minted function _afterAnchorMint(address to, bytes32 anchor, uint256 tokenId) internal virtual {} /** * @notice Add (_add=true) or remove (_add=false) a maintainer * @dev Note this is a trivial implementation, which can leave the contract without a maintainer. * Since the function is access-controlled via onlyMaintainer, this results in the contract * becoming unmaintainable. * This may be desired behavior, for example if the contract shall become immutable until * all eternity, therefore making a project truly trustless. */ function updateMaintainer(address _maintainer, bool _add) public onlyMaintainer() { maintainers[_maintainer] = _add; } /// @dev Verifies a anchor is valid and mints a token to the target address. /// Internal function to be called whenever minting is needed. /// Parameters: /// @param to Beneficiary account address /// @param anchor The anchor (from Merkle tree) function _safeMint(address to, bytes32 anchor) internal virtual { assert(tokenByAnchor[anchor] <= 0); // saftey for contract-internal errors uint256 tokenId = _burnedTokensByAnchor[anchor]; if(tokenId < 1) { _tokenIdCounter.increment(); tokenId = _tokenIdCounter.current(); } assert(anchorByToken[tokenId] <= 0); // saftey for contract-internal errors anchorByToken[tokenId] = anchor; tokenByAnchor[anchor] = tokenId; super._safeMint(to, tokenId); _afterAnchorMint(to, anchor, tokenId); } function _commitAttestation(address to, bytes32 anchor, bytes32 attestationHash) internal { _anchorByUsedAttestation[attestationHash] = anchor; uint256 totalAttestationsByAnchor = attestationsUsedByAnchor[anchor] +1; attestationsUsedByAnchor[anchor] = totalAttestationsByAnchor; emit AttestationUse(to, anchor, attestationHash, totalAttestationsByAnchor ); } function transferAnchor(bytes memory attestation, bytes memory data) public virtual { bytes32 anchor; address to; bytes32 attestationHash; (to, anchor, attestationHash) = decodeAttestationIfValid(attestation, data); _commitAttestation(to, anchor, attestationHash); // commit already here, will be reverted in error case anyway uint256 fromToken = tokenByAnchor[anchor]; // tokenID, null if not exists address from = address(0); // owneraddress or 0x00, if not exists _anchorIsReleased[anchor] = true; // Attestation always temporarily releases the anchor if(fromToken > 0) { from = ownerOf(fromToken); require(from != to, "ERC6956-E6"); _safeTransfer(from, to, fromToken, ""); } else { _safeMint(to, anchor); } } function transferAnchor(bytes memory attestation) public virtual { return transferAnchor(attestation, ""); } function hasAuthorization(Role _role, uint256 _auth ) public pure returns (bool) { uint256 result = uint256(_auth & (1 << uint256(_role))); return result > 0; } modifier authorized(Role _role, uint256 _authMap) { require(hasAuthorization(_role, _authMap), "ERC6956-E7"); _; } // The following functions are overrides required by Solidity, EIP-165. function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC721Enumerable) returns (bool) { return interfaceId == type(IERC6956).interfaceId || super.supportsInterface(interfaceId); } /** * @notice Returns whether a certain address is registered as trusted oracle, i.e. attestations signed by this address are accepted in `decodeAttestationIfValid` * @dev This function may be overwritten when extending ERC-6956, e.g. when other oracle-registration mechanics are used * @param oracleAddress Address of the oracle in question * @return isTrusted True, if oracle is trusted */ function isTrustedOracle(address oracleAddress) public virtual view returns (bool isTrusted) { return _trustedOracles[oracleAddress]; } function decodeAttestationIfValid(bytes memory attestation, bytes memory data) public view returns (address to, bytes32 anchor, bytes32 attestationHash) { uint256 attestationTime; uint256 validStartTime; uint256 validEndTime; bytes memory signature; bytes32[] memory proof; attestationHash = keccak256(attestation); (to, anchor, attestationTime, validStartTime, validEndTime, signature) = abi.decode(attestation, (address, bytes32, uint256, uint256, uint256, bytes)); bytes32 messageHash = keccak256(abi.encodePacked(to, anchor, attestationTime, validStartTime, validEndTime, proof)); address signer = _extractSigner(messageHash, signature); // Check if from trusted oracle require(isTrustedOracle(signer), "ERC6956-E8"); require(_anchorByUsedAttestation[attestationHash] <= 0, "ERC6956-E9"); // Check expiry uint256 timestamp = block.timestamp; require(timestamp > validStartTime, "ERC6956-E10"); require(attestationTime + maxAttestationExpireTime > block.timestamp, "ERC6956-E11"); require(validEndTime > block.timestamp, "ERC6956-E112"); // Calling hook! _beforeAttestationUse(anchor, to, data); return(to, anchor, attestationHash); } /// @notice Compatible with ERC721.tokenURI(). Returns {baseURI}{anchor} /// @dev Returns when called for tokenId=5, baseURI=https://myurl.com/collection/ and anchorByToken[5] = 0x12345 /// Example: https://myurl.com/collection/0x12345 /// Works for non-burned tokens / active-Anchors only. /// Anchor-based tokenURIs are needed as an anchor's corresponding tokenId is only known after mint. /// @param tokenId TokenID /// @return tokenURI Returns the Uniform Resource Identifier (URI) for `tokenId` token. function tokenURI(uint256 tokenId) public view override returns (string memory) { bytes32 anchor = anchorByToken[tokenId]; string memory anchorString = Strings.toHexString(uint256(anchor)); return bytes(_baseURI()).length > 0 ? string(abi.encodePacked(_baseURI(), anchorString)) : ""; } function _baseURI() internal view virtual override(ERC721) returns (string memory) { return _baseUri; } /** * @dev Base URI, MUST end with a slash. Will be used as `{baseURI}{tokenId}` in tokenURI() function */ string internal _baseUri = ""; // needs to end with '/' /// @notice Set a new BaseURI. Can be used with dynamic NFTs that have server APIs, IPFS-buckets /// or any other suitable system. Refer tokenURI(tokenId) for anchor-based or tokenId-based format. /// @param tokenBaseURI The token base-URI. Must end with slash '/'. function updateBaseURI(string calldata tokenBaseURI) public onlyMaintainer() { _baseUri = tokenBaseURI; } event BurnAuthorizationChange(Authorization burnAuth, address indexed maintainer); function updateBurnAuthorization(Authorization burnAuth) public onlyMaintainer() { burnAuthorization = burnAuth; emit BurnAuthorizationChange(burnAuth, msg.sender); // TODO event } event ApproveAuthorizationChange(Authorization approveAuth, address indexed maintainer); function updateApproveAuthorization(Authorization approveAuth) public onlyMaintainer() { approveAuthorization = approveAuth; emit ApproveAuthorizationChange(approveAuth, msg.sender); // TODO event } constructor(string memory _name, string memory _symbol) ERC721(_name, _symbol) { maintainers[msg.sender] = true; // deployer is automatically maintainer // Indicates general float-ability, i.e. whether anchors can be digitally dropped and released // OWNER and ASSET shall normally be in sync anyway, so this is reasonable default // authorization for approve and burn, as it mimicks ERC-721 behavior burnAuthorization = Authorization.OWNER_AND_ASSET; approveAuthorization = Authorization.OWNER_AND_ASSET; } /* ########################## SIGNATURE MAGIC, ########################## adapted from https://solidity-by-example.org/signature/ */ /** * Returns the signer of a message. * * OFF-CHAIN: * const [alice] = ethers.getSigners(); // = 0x3c44... * const messageHash = ethers.utils.solidityKeccak256(["address", "bytes32"], [a, b]); const sig = await alice.signMessage(ethers.utils.arrayify(messageHash)); ONCHAIN In this contract, call from ``` function (address a, bytes32 b, bytes memory sig) { messageHash = keccak256(abi.encodePacked(to, b)); signer = extractSigner(messageHash, sig); // signer will be 0x3c44... } ``` * * @param messageHash A keccak25(abi.encodePacked(...)) hash * @param sig Signature (length 65 bytes) * * @return The signer */ function _extractSigner(bytes32 messageHash, bytes memory sig) internal pure returns (address) { require(sig.length == 65, "ERC6956-E13"); /* Signature is produced by signing a keccak256 hash with the following format: "\x19Ethereum Signed Message\n" + len(msg) + msg */ bytes32 ethSignedMessageHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", messageHash)); bytes32 r; bytes32 s; uint8 v; // Extract the r, s, and v parameters from the signature assembly { r := mload(add(sig, 32)) s := mload(add(sig, 64)) v := byte(0, mload(add(sig, 96))) } // Ensure the v parameter is either 27 or 28 // TODO is this needed? if (v < 27) { v += 27; } // Recover the public key from the signature and message hash // and convert it to an address address signer = ecrecover(ethSignedMessageHash, v, r, s); return signer; } } // File @openzeppelin/contracts/utils/cryptography/[email protected] // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol) pragma solidity ^0.8.0; /** * @dev These functions deal with verification of Merkle Tree proofs. * * The tree and the proofs can be generated using our * https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. * You will find a quickstart guide in the readme. * * WARNING: You should avoid using leaf values that are 64 bytes long prior to * hashing, or use a hash function other than keccak256 for hashing leaves. * This is because the concatenation of a sorted pair of internal nodes in * the merkle tree could be reinterpreted as a leaf value. * OpenZeppelin's JavaScript library generates merkle trees that are safe * against this attack out of the box. */ library MerkleProof { /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify( bytes32[] memory proof, bytes32 root, bytes32 leaf ) internal pure returns (bool) { return processProof(proof, leaf) == root; } /** * @dev Calldata version of {verify} * * _Available since v4.7._ */ function verifyCalldata( bytes32[] calldata proof, bytes32 root, bytes32 leaf ) internal pure returns (bool) { return processProofCalldata(proof, leaf) == root; } /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. When processing the proof, the pairs * of leafs & pre-images are assumed to be sorted. * * _Available since v4.4._ */ function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Calldata version of {processProof} * * _Available since v4.7._ */ function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function multiProofVerify( bytes32[] memory proof, bool[] memory proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProof(proof, proofFlags, leaves) == root; } /** * @dev Calldata version of {multiProofVerify} * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function multiProofVerifyCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProofCalldata(proof, proofFlags, leaves) == root; } /** * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false * respectively. * * CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer). * * _Available since v4.7._ */ function processMultiProof( bytes32[] memory proof, bool[] memory proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { return hashes[totalHashes - 1]; } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Calldata version of {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function processMultiProofCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { return hashes[totalHashes - 1]; } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { return a < b ? _efficientHash(a, b) : _efficientHash(b, a); } function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, a) mstore(0x20, b) value := keccak256(0x00, 0x40) } } } // File contracts/eip-6956/IERC6956AttestationLimited.sol pragma solidity ^0.8.18; /** * @title Attestation-limited Asset-Bound NFT * @dev See https://eips.ethereum.org/EIPS/eip-6956 * Note: The ERC-165 identifier for this interface is 0x75a2e933 */ interface IERC6956AttestationLimited is IERC6956 { enum AttestationLimitPolicy { IMMUTABLE, INCREASE_ONLY, DECREASE_ONLY, FLEXIBLE } /// @notice Returns the attestation limit for a particular anchor /// @dev MUST return the global attestation limit per default /// and override the global attestation limit in case an anchor-based limit is set function attestationLimit(bytes32 anchor) external view returns (uint256 limit); /// @notice Returns number of attestations left for a particular anchor /// @dev Is computed by comparing the attestationsUsedByAnchor(anchor) and the current attestation limit /// (current limited emitted via GlobalAttestationLimitUpdate or AttestationLimt events) function attestationUsagesLeft(bytes32 anchor) external view returns (uint256 nrTransfersLeft); /// @notice Indicates the policy, in which direction attestation limits can be updated (globally or per anchor) function attestationLimitPolicy() external view returns (AttestationLimitPolicy policy); /// @notice This emits when the global attestation limt is updated event GlobalAttestationLimitUpdate(uint256 indexed transferLimit, address updatedBy); /// @notice This emits when an anchor-specific attestation limit is updated event AttestationLimitUpdate(bytes32 indexed anchor, uint256 indexed tokenId, uint256 indexed transferLimit, address updatedBy); /// @dev This emits in the transaction, where attestationUsagesLeft becomes 0 event AttestationLimitReached(bytes32 indexed anchor, uint256 indexed tokenId, uint256 indexed transferLimit); } // File contracts/eip-6956/IERC6956Floatable.sol pragma solidity ^0.8.18; /** * @title Floatable Asset-Bound NFT * @notice A floatable Asset-Bound NFT can (temporarily) be transferred without attestation * @dev See https://eips.ethereum.org/EIPS/eip-6956 * Note: The ERC-165 identifier for this interface is 0xf82773f7 */ interface IERC6956Floatable is IERC6956 { enum FloatState { Default, // 0, inherits from floatAll Floating, // 1 Anchored // 2 } /// @notice Indicates that an anchor-specific floating state changed event FloatingStateChange(bytes32 indexed anchor, uint256 indexed tokenId, FloatState isFloating, address operator); /// @notice Emits when FloatingAuthorization is changed. event FloatingAuthorizationChange(Authorization startAuthorization, Authorization stopAuthorization, address maintainer); /// @notice Emits, when the default floating state is changed event FloatingAllStateChange(bool areFloating, address operator); /// @notice Indicates whether an anchored token is floating, namely can be transferred without attestation function floating(bytes32 anchor) external view returns (bool); /// @notice Indicates whether any of OWNER, ISSUER, (ASSET) is allowed to start floating function floatStartAuthorization() external view returns (Authorization canStartFloating); /// @notice Indicates whether any of OWNER, ISSUER, (ASSET) is allowed to stop floating function floatStopAuthorization() external view returns (Authorization canStartFloating); /** * @notice Allows to override or reset to floatAll-behavior per anchor * @dev Must throw when newState == Floating and floatStartAuthorization does not authorize msg.sender * @dev Must throw when newState == Anchored and floatStopAuthorization does not authorize msg.sender * @param anchor The anchor, whose anchored token shall override default behavior * @param newState Override-State. If set to Default, the anchor will behave like floatAll */ function float(bytes32 anchor, FloatState newState) external; } // File contracts/eip-6956/IERC6956ValidAnchors.sol pragma solidity ^0.8.18; /** * @title Anchor-validating Asset-Bound NFT * @dev See https://eips.ethereum.org/EIPS/eip-6956 * Note: The ERC-165 identifier for this interface is 0x051c9bd8 */ interface IERC6956ValidAnchors is IERC6956 { /** * @notice Emits when the valid anchors for the contract are updated. * @param validAnchorHash Hash representing all valid anchors. Typically Root of MerkleTree * @param maintainer msg.sender updating the hash */ event ValidAnchorsUpdate(bytes32 indexed validAnchorHash, address indexed maintainer); /** * @notice Indicates whether an anchor is valid in the present contract * @dev Typically implemented via MerkleTrees, where proof is used to verify anchor is part of the MerkleTree * MUST return false when no ValidAnchorsUpdate-event has been emitted yet * @param anchor The anchor in question * @param proof Proof that the anchor is valid, typically MerkleProof * @return isValid True, when anchor and proof can be verified against validAnchorHash (emitted via ValidAnchorsUpdate-event) */ function anchorValid(bytes32 anchor, bytes32[] memory proof) external view returns (bool isValid); } // File contracts/eip-6956/ERC6956Full.sol pragma solidity ^0.8.18; /** * @title ASSET-BOUND NFT implementation with all interfaces * @author Thomas Bergmueller (@tbergmueller) * @notice Extends ERC6956.sol with additional interfaces and functionality * * @dev Error-codes * ERROR | Message * ------|------------------------------------------------------------------- * E1-20 | See ERC6956.sol * E21 | No permission to start floating * E22 | No permission to stop floating * E23 | allowFloating can only be called when changing floating state * E24 | No attested transfers left * E25 | data must contain merkle-proof * E26 | Anchor not valid * E27 | Updating attestedTransferLimit violates policy */ contract ERC6956Full is ERC6956, IERC6956AttestationLimited, IERC6956Floatable, IERC6956ValidAnchors { Authorization public floatStartAuthorization; Authorization public floatStopAuthorization; /// ############################################################################################################################### /// ############################################################################################## IERC6956AttestedTransferLimited /// ############################################################################################################################### mapping(bytes32 => uint256) public attestedTransferLimitByAnchor; mapping(bytes32 => FloatState) public floatingStateByAnchor; uint256 public globalAttestedTransferLimitByAnchor; AttestationLimitPolicy public attestationLimitPolicy; bool public allFloating; /// @dev The merkle-tree root node, where proof is validated against. Update via updateValidAnchors(). Use salt-leafs in merkle-trees! bytes32 private _validAnchorsMerkleRoot; function _requireValidLimitUpdate(uint256 oldValue, uint256 newValue) internal view { if(newValue > oldValue) { require(attestationLimitPolicy == AttestationLimitPolicy.FLEXIBLE || attestationLimitPolicy == AttestationLimitPolicy.INCREASE_ONLY, "ERC6956-E27"); } else { require(attestationLimitPolicy == AttestationLimitPolicy.FLEXIBLE || attestationLimitPolicy == AttestationLimitPolicy.DECREASE_ONLY, "ERC6956-E27"); } } function updateGlobalAttestationLimit(uint256 _nrTransfers) public onlyMaintainer() { _requireValidLimitUpdate(globalAttestedTransferLimitByAnchor, _nrTransfers); globalAttestedTransferLimitByAnchor = _nrTransfers; emit GlobalAttestationLimitUpdate(_nrTransfers, msg.sender); } function updateAttestationLimit(bytes32 anchor, uint256 _nrTransfers) public onlyMaintainer() { uint256 currentLimit = attestationLimit(anchor); _requireValidLimitUpdate(currentLimit, _nrTransfers); attestedTransferLimitByAnchor[anchor] = _nrTransfers; emit AttestationLimitUpdate(anchor, tokenByAnchor[anchor], _nrTransfers, msg.sender); } function attestationLimit(bytes32 anchor) public view returns (uint256 limit) { if(attestedTransferLimitByAnchor[anchor] > 0) { // Per anchor overwrites always, even if smaller than globalAttestedTransferLimit return attestedTransferLimitByAnchor[anchor]; } return globalAttestedTransferLimitByAnchor; } function attestationUsagesLeft(bytes32 anchor) public view returns (uint256 nrTransfersLeft) { // FIXME panics when attestationsUsedByAnchor > attestedTransferLimit // since this should never happen, maybe ok? return attestationLimit(anchor) - attestationsUsedByAnchor[anchor]; } /// ############################################################################################################################### /// ############################################################################################## FLOATABILITY /// ############################################################################################################################### function updateFloatingAuthorization(Authorization startAuthorization, Authorization stopAuthorization) public onlyMaintainer() { floatStartAuthorization = startAuthorization; floatStopAuthorization = stopAuthorization; emit FloatingAuthorizationChange(startAuthorization, stopAuthorization, msg.sender); } function floatAll(bool doFloatAll) public onlyMaintainer() { require(doFloatAll != allFloating, "ERC6956-E23"); allFloating = doFloatAll; emit FloatingAllStateChange(doFloatAll, msg.sender); } function _floating(bool defaultFloatState, FloatState anchorFloatState) internal pure returns (bool floats) { if(anchorFloatState == FloatState.Default) { return defaultFloatState; } return anchorFloatState == FloatState.Floating; } function float(bytes32 anchor, FloatState newFloatState) public { bool currentFloatState = floating(anchor); bool willFloat = _floating(allFloating, newFloatState); require(willFloat != currentFloatState, "ERC6956-E23"); if(willFloat) { require(_roleBasedAuthorization(anchor, createAuthorizationMap(floatStartAuthorization)), "ERC6956-E21"); } else { require(_roleBasedAuthorization(anchor, createAuthorizationMap(floatStopAuthorization)), "ERC6956-E22"); } floatingStateByAnchor[anchor] = newFloatState; emit FloatingStateChange(anchor, tokenByAnchor[anchor], newFloatState, msg.sender); } function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize) internal virtual override(ERC6956) { bytes32 anchor = anchorByToken[tokenId]; if(!_anchorIsReleased[anchor]) { // Only write when not already released - this saves gas, as memory-write is quite expensive compared to IF if(floating(anchor)) { _anchorIsReleased[anchor] = true; // FIXME OPTIMIZATION, we do not need } } super._beforeTokenTransfer(from, to, tokenId, batchSize); } function _beforeAttestationUse(bytes32 anchor, address to, bytes memory data) internal view virtual override(ERC6956) { // empty, can be overwritten by derived conctracts. require(attestationUsagesLeft(anchor) > 0, "ERC6956-E24"); // IERC6956ValidAnchors check anchor is indeed valid in contract require(data.length > 0, "ERC6956-E25"); bytes32[] memory proof; (proof) = abi.decode(data, (bytes32[])); // Decode it with potentially more data following. If there is more data, this may be passed on to safeTransfer require(anchorValid(anchor, proof), "ERC6956-E26"); super._beforeAttestationUse(anchor, to, data); } /// @notice Update the Merkle root containing the valid anchors. Consider salt-leaves! /// @dev Proof (transferAnchor) needs to be provided from this tree. /// @dev The merkle-tree needs to contain at least one "salt leaf" in order to not publish the complete merkle-tree when all anchors should have been dropped at least once. /// @param merkleRootNode The root, containing all anchors we want validated. function updateValidAnchors(bytes32 merkleRootNode) public onlyMaintainer() { _validAnchorsMerkleRoot = merkleRootNode; emit ValidAnchorsUpdate(merkleRootNode, msg.sender); } function anchorValid(bytes32 anchor, bytes32[] memory proof) public virtual view returns (bool) { return MerkleProof.verify( proof, _validAnchorsMerkleRoot, keccak256(bytes.concat(keccak256(abi.encode(anchor))))); } function floating(bytes32 anchor) public view returns (bool){ return _floating(allFloating, floatingStateByAnchor[anchor]); } constructor( string memory _name, string memory _symbol, AttestationLimitPolicy _limitUpdatePolicy) ERC6956(_name, _symbol) { attestationLimitPolicy = _limitUpdatePolicy; // Note per default no-one change floatability. canStartFloating and canStopFloating needs to be configured first! } function supportsInterface(bytes4 interfaceId) public view virtual override(ERC6956) returns (bool) { return interfaceId == type(IERC6956AttestationLimited).interfaceId || interfaceId == type(IERC6956Floatable).interfaceId || interfaceId == type(IERC6956ValidAnchors).interfaceId || super.supportsInterface(interfaceId); } } // File contracts/factory/BaseProvider.sol pragma solidity ^0.8.18; /** * @title InitArgsProvider, typically implemented by factories * @author [email protected] * @dev Provides initArgs for a deployed contract's address, that can be passed to that deployed contract's `initialize()` function. * The deployed contract typically implements `ProvideableContract`. The constructor of `ProvideableContract` checks for this interface * and calls usually calls `getInitArgs(address(this))` */ interface IInitArgsProvider { /** * @notice Provides initArgs (typically from a factory) for a particular deployed smart-contract address. * @dev is called from `ProvidableContract`-constructor at deploy-time. Main reason for this implementation * is that Contracts are deployed via create2, so any constructor-parameter is address defining. This allows * at deploy time to set additional parameters, which are not address-defining. * @param deployedContract Address of the deployed contract requesting initArgs * @return initArgs abi-encoded init args */ function getInitArgs(address deployedContract) external view returns (bytes memory initArgs); } /** * @title ProvidableContract (to be extended by actual contracts) * @author [email protected] * @notice Abstract ProvidableContract defining the `initialize()` function, which is called at deploy-time, if the deployer implements IInitArgsProvider * @dev Any contract deployed through SlimFactory must extend `ProvidableContract`. */ abstract contract ProvidableContract { /** * @notice Indicates the deployer of this contract. */ address public deployedBy; /** * @notice Returns the Version in format X.Y.Z * @dev Needs to match `BaseProvider.getVersion()` */ function getVersion() public virtual pure returns (string memory); /** * @notice Initializer called at deploytime or manually afterwards. * @dev MUST ensure it can only be executed once, typically by setting a notInitialized bool and saying require(notInitialized) * @param initArgs abi-encoded init args provided by `IInitArgsProvider` */ function initialize(bytes memory initArgs) public virtual; /** * @dev Stores the deployer-address and - if the deployer supports the IInitArgsProvider interface - requests initArgs and calls `initialize()` */ constructor() { // saftey feature, lets people easily verifiy it has been deployed through a trusted factory deployedBy = msg.sender; // Callback to the factory if(ERC165Checker.supportsInterface(deployedBy, type(IInitArgsProvider).interfaceId)) { IInitArgsProvider factory = IInitArgsProvider(msg.sender); initialize(factory.getInitArgs(address(this))); } } } /** * @title BaseProvider (to be extended by actual providers) * @author [email protected] * @notice Abstract BaseProvider contract to deliver a `ProvidableContract`, must be extended by actual SlimFactory-Providers * @dev A provider is a contract, which provides the bytecode of a particular `ProvidableContract`, a function to encode deployArgs (constructorArgs) and a function to encode initArgs */ abstract contract BaseProvider { /** * Returns bytecode with constructor args. Needs to be implemented by actual provider contract.abi * Typical implementation: * ``` * bytes memory bytecode = type(DemoContract).creationCode; // DemoContract is ProvidableContract * return abi.encodePacked(bytecode, args); * ``` */ function getBytecode(bytes memory args) public virtual pure returns (bytes memory); /** * Returns the version as string in format X.Y.Z * Needs to match `BaseProvider.getVersion()` */ function getVersion() public virtual pure returns (string memory); function getVersionHash() public pure returns (bytes32) { return keccak256(abi.encode(getVersion())); } function getDefaultInitArgs() public virtual view returns (bytes memory); function getDefaultArgs(address appHub, string memory name, string memory symbol) public virtual view returns (bytes memory); // ############################### NOT sure whether to keep the below (currently not used) // TODO or remove function getBytecodeHash(bytes memory bytecode) public pure returns (bytes32) { return keccak256(abi.encode(bytecode, getVersionHash())); } /** * @dev Verifies via hashing that the bytecode is indeed suitable to be deployed with this contract * @param byteCode The bytecode, typically the creationCode + args * @param byteCodeHash The bytecode hash, computed typically by calling getBytecodeHash() at some point */ function verifyByteCode(bytes memory byteCode, bytes32 byteCodeHash) public virtual pure returns (bool) { return byteCodeHash == getBytecodeHash(byteCode); } } // File contracts/factory/SlimFactory.sol pragma solidity ^0.8.18; /** * @title A slim Register+Deploy factory for arbitrary, `ProvidableContract`-extending contracts using create2 deploy mechanism * @author [email protected] * @notice Two-step factory with create2 requesting bytecode from deployed `BaseProvider`-extending, versioned and potentially incompatible contract templates. * @dev In order to deploy a contract follow these steps * 1. Write the `MyContract is ProvidableContract`, lets say with version 1.2.3 * 2. Write a `MyContractProvider is BaseProvider`, which serves the bytecode of `MyContract` and offers getDeployArgs / getInitArgs functions * 3. Deploy `MyContractProvider` with any arbitrary wallet and to any arbitrary address. Note its deployed `providerAddr` * 4. Call `SlimFactory.updateProvider(providerAddr)`. The version will be requested from `providerAddr` onchain. * 5. Register * 5.1. [OPTIONAL] Obtain from MyContractProvider optionally deployArgs = getDeployArgs() and initArgs = getInitArgs() * 5.2. Call SlimFactory.register("1.2.3", deployArgs, initArgs). If deployArgs and/or initArgs are not needed, pass empty `bytes memory`. * 5.3. Record the registeredAddress, which is returned from register() as well as emitted via ContractRegistered event. * 6. Deploy a previously registered contract via SlimFactory.deploy(registeredAddress) */ contract SlimFactory is ERC165, IInitArgsProvider { event ContractDeployed(address indexed addr, string version, address deployer); event ContractRegistered(address indexed addr, string version, address registrar); event ContractUnregistered(address indexed addr, address maintainer); event ProviderUpdate(address indexed addr, string indexed version, address maintainer); event RegistrarUpdate(address to, bool added, address maintainer); event MaintainerUpdate(address to, bool added, address maintainer); event DeployerUpdate(address to, bool added, address maintainer); event DeploymentSaltUpdate(bytes32 newSalt, bytes32 oldSalt, address maintainer); mapping (address => bytes) public deployArgsByAddress; mapping (address => address) public providerForAddress; // provider by deployment! mapping (address => bytes32) public bytecodeHash; mapping (bytes32 => address) public addressByBytecodeHash; mapping (address => address) public registrarByContract; mapping (address => bytes) public initArgsByAddress; mapping (string => address) public providerByVersion; mapping (bytes32 => string) public versionByVersionHash; address public appHubAddress; /** * Keeps a list of all deployed contracts (in deployment order) */ address[] public deployedContracts; /** * @notice Backlog of contracts that have been registered but not deployed yet */ mapping (address => bool) public pendingDeployments; mapping (address => bool) private _authorizedDeployer; mapping (address => bool) private _authorizedMaintainer; mapping (address => bool) private _authorizedRegistrar; bytes32 private _staticSalt = keccak256("slimFactory"); // https://solidity-by-example.org/app/create2/ // 2. Compute the address of the contract to be deployed // NOTE: _salt is a random number used to create an address function getAddress( bytes memory bytecode, bytes32 _salt ) public view returns (address) { uint actualSalt = uint(_salt); bytes32 hash = keccak256( abi.encodePacked(bytes1(0xff), address(this), actualSalt, keccak256(bytecode)) ); // NOTE: cast last 20 bytes of hash to address return address(uint160(uint(hash))); } /** * @param bytecode Bytecode + packed constructorArgs of contract implementing IDeployedContract * @param salt The deployment salt. * @dev Isolated function to actually deploy contracts (can be used by extending contracts) * inspired by https://solidity-by-example.org/app/create2/ * Salt is taken as parameter to also allow deploying contracts with an "old" salt in case of * emergency salt-upgrade. */ function _deployBinary(bytes memory bytecode, bytes32 salt) internal whenOperational() returns (address) { address addr; uint actualSalt = uint(salt); /* NOTE: How to call create2 create2(v, p, n, s) create new contract with code at memory p to p + n and send v wei and return the new address where new address = first 20 bytes of keccak256(0xff + address(this) + s + keccak256(mem[p…(p+n))) s = big-endian 256-bit value */ assembly { addr := create2( callvalue(), // wei sent with current call // Actual code starts after skipping the first 32 bytes add(bytecode, 0x20), mload(bytecode), // Load the size of code contained in the first 32 bytes actualSalt // Salt from function arguments ) if iszero(extcodesize(addr)) { revert(0, 0) } } return addr; } /** * @notice Updates the deployment salt - do only use in absolut emergencies! * @dev This shall not be used at all and is just for emergencies and major fuckups. As soon * as the salt is updated, it can happen that the same contract / same version / same constructorArgs * can be re-deployed to a different address. */ function updateDeploymentSalt(bytes32 newSalt) public onlyMaintainer() whenOperational() { emit DeploymentSaltUpdate(_staticSalt, newSalt, msg.sender); _staticSalt = newSalt; } /** * @dev Hook called after registration of a new contract. Typically overwritten in extending implementations * @param addr Address of the just registered contract * @param contractVersion Version of the just registered contract as indicated by provider in format X.Y.Z */ function _afterRegistration(address addr, string memory contractVersion) internal virtual {} /** * @dev Hook called after deployment of of a registered contract. Typically overwritten in extending implementations * @param addr Address of the just registered contract * @param contractVersion Version of the just registered contract as indicated by provider in format X.Y.Z */ function _afterDeployment(address addr, string memory contractVersion) internal virtual {} /** * @notice Unregisters undeployed contracts (undo register(), as long as not deployed) * @param toUnregister The address of the contract to unregister * @dev Can be called by maintainer or the registrar who registered the particular contract at `toUnregister`-address */ function unregister(address toUnregister) public maintainerOrRegistrar() { require(pendingDeployments[toUnregister], "Only registered, not-deployed contracts can be unregistered"); if(!isAuthorizedMaintainer(msg.sender)) { require(registrarByContract[toUnregister] == msg.sender, "Can only unregister own registered contracts"); } _beforeUnregister(toUnregister); delete addressByBytecodeHash[bytecodeHash[toUnregister]]; delete bytecodeHash[toUnregister]; delete deployArgsByAddress[toUnregister]; delete initArgsByAddress[toUnregister]; delete pendingDeployments[toUnregister]; delete registrarByContract[toUnregister]; delete providerForAddress[toUnregister]; emit ContractUnregistered(toUnregister, msg.sender); } /** * @dev Hook called before unregistering a contract - permission to unregister has been verified before calling this function */ function _beforeUnregister(address addrToUnregister) internal virtual {} /** * @notice Registers a new Contract deployment of contract with version X.Y.Z. Can only be executed by authorized registrars. * @dev The returned address is then typically passed into `deploy()` to execute the deployment * @param contractVersion The version in format X.Y.Z which should be deployed * @param deployArgs DeployArgs, typically obtained from the BaseProvider-extending contract getDeployArgs(...arbitraryParams ...) * @param initArgs InitArgs requestable through getInitArgs(), typically obtained from BaseProvider-extending contract getInitArgs(...) or getDefaultInitArgs(...) * @return registeredAddress The predicted address, where the contract will be deployed to via `deploy(registeredAddress)` */ function register(string memory contractVersion, bytes memory deployArgs, bytes memory initArgs) public onlyRegistrar() whenOperational() returns (address registeredAddress) { address _provider = providerByVersion[contractVersion]; require(_provider != address(0), "No provider found"); BaseProvider p = BaseProvider(_provider); registeredAddress = getAddress(p.getBytecode(deployArgs), _staticSalt); require(providerForAddress[registeredAddress] == address(0), "Contract already registered"); registrarByContract[registeredAddress] = msg.sender; providerForAddress[registeredAddress] = _provider; _beforeRegister(registeredAddress, contractVersion, deployArgs, initArgs); deployArgsByAddress[registeredAddress] = deployArgs; bytes memory byteCodeForDeployment = p.getBytecode(deployArgs); bytes32 bcHash = p.getBytecodeHash(byteCodeForDeployment); require(addressByBytecodeHash[bcHash] == address(0), "Identical bytecode already registered"); bytecodeHash[registeredAddress] = bcHash; addressByBytecodeHash[bcHash] = registeredAddress; initArgsByAddress[registeredAddress] = initArgs; pendingDeployments[registeredAddress] = true; emit ContractRegistered(registeredAddress, contractVersion, msg.sender); _afterRegistration(registeredAddress,contractVersion); return registeredAddress; } /** * @notice Hook called before registering a contract, typically overridden by extending contracts */ function _beforeRegister(address /*_deployment*/, string memory /*_version*/, bytes memory /*_deployArgs*/, bytes memory /*_initArgs*/) internal virtual {} /** * @notice Actually deploys the previously registered contract. Can only be executed by authorized deployers. * @dev Note that if you get an "Error: Transaction reverted without a reason string", * the most likely reason is corrupt init data. Verify init-data is correct! * Also a common error is that the factory is lacking permissions to run initialize() * on the just deployed contract. * Verifies bytecode-integrity to account for potential corroptions between registration and deployment. * This also accounts for cases, where the _staticSalt has changed between registration and deployment. * Further does regression-testing by verifying deployed address matches registered address * @param registeredAddress The address as returned from `register()` */ function deploy(address registeredAddress) public virtual onlyDeployer() returns (address) { BaseProvider p = BaseProvider(providerForAddress[registeredAddress]); bytes memory argsForDeployment = deployArgsByAddress[registeredAddress]; bytes memory byteCodeForDeployment = p.getBytecode(argsForDeployment); require(p.verifyByteCode(byteCodeForDeployment, bytecodeHash[registeredAddress]), "Bytecode verification failed, version mismatch?"); address deployedAddress = _deployBinary(byteCodeForDeployment, _staticSalt); require(deployedAddress == registeredAddress, "Predicted and deployed address mismatch"); ProvidableContract pc = ProvidableContract(deployedAddress); delete pendingDeployments[registeredAddress]; emit ContractDeployed(deployedAddress, pc.getVersion(), msg.sender); _afterDeployment(deployedAddress, pc.getVersion()); return deployedAddress; } /** * @notice Adds or updates a provider contract. Can only be used by authorized maintainers. * @dev Note updating should be avoided, rather increase the the Revision Z in X.Y.Z versioning. * @dev The version is determined by calling BaseProvider(_providerAddress).getVersion() * @param providerAddress Address of the deployed ProviderContract (which extends BaseProvider) */ function updateProvider(address providerAddress) public onlyMaintainer() { BaseProvider bp = BaseProvider(providerAddress); string memory _version = bp.getVersion(); require(providerByVersion[_version] != providerAddress, "No change required"); emit ProviderUpdate(providerAddress, _version, msg.sender ); providerByVersion[_version] = providerAddress; } /** * @notice Removes the provider of `version`, i.e. stop supporting this version */ function removeVersion(string memory version) public onlyMaintainer() { address provider = providerByVersion[version]; require(provider != address(0), "Version unknown"); emit ProviderUpdate(address(0), version, msg.sender); delete providerByVersion[version]; } /** * @notice Indicates whether a certain version is supported / can be registered and deployed * @param version in Format x.y.z */ function versionSupported(string memory version) public view returns (bool) { return providerByVersion[version] != address(0); } /** * @notice Returns the init args stored for a contract deployed to `deployedAddress` * @dev Typically called (exactly once) from the deployedContract's constructor via BaseProvider-Constructor. */ function getInitArgs(address deployedAddress) public view returns (bytes memory) { return initArgsByAddress[deployedAddress]; } // ####################################################### SIMPLE ACCESS CONTROL // Overwrite isAuthorized* in extending contracts, e.g. if you want to use // Role-based AccessControl etc. /** * @notice Indicates that `àccount` is authorized to deploy. * @dev Typically overridden in extending contracts when role-based access control shall be used */ function isAuthorizedDeployer(address account) public virtual view returns (bool) { return _authorizedDeployer[account]; } /** * @notice Indicates that `account` is authorized to register and unregister (own) contracts. * @dev Typically overridden in extending contracts when role-based access control shall be used */ function isAuthorizedRegistrar(address account) public virtual view returns (bool) { return _authorizedRegistrar[account]; } /** * @notice Indicates that `account` is authorized to maintain this factory. * @dev Typically overridden in extending contracts when role-based access control shall be used */ function isAuthorizedMaintainer(address account) public virtual view returns (bool) { return _authorizedMaintainer[account]; } modifier onlyRegistrar() { require(isAuthorizedRegistrar(msg.sender), "Authorized Registrar only"); _; } modifier onlyDeployer() { require(isAuthorizedDeployer(msg.sender), "Authorized Deployer only"); _; } modifier onlyMaintainer() { require(isAuthorizedMaintainer(msg.sender), "Authorized Maintainer only"); _; } modifier maintainerOrRegistrar() { require(isAuthorizedMaintainer(msg.sender) || isAuthorizedRegistrar(msg.sender), "msg.sender must be maintainer or registrar"); _; } /** * This function is typically overwritten when e.g. implementing pausable interface */ function isOperational() public virtual view returns (bool) { return true; } /** * @notice Allows to `add` or remove an `account` as an authorized registrar. */ function updateAuthorizedRegistrar(address account, bool add) public onlyMaintainer() { require(_authorizedRegistrar[account] != add, "No change required"); emit RegistrarUpdate(account, add, msg.sender); _authorizedRegistrar[account] = add; } /** * @notice Allows to `add` or remove an `account` as an authorized deployer. */ function updateAuthorizedDeployer(address account, bool add) public onlyMaintainer() { require(_authorizedDeployer[account] != add, "No change required"); emit DeployerUpdate(account, add, msg.sender); _authorizedDeployer[account] = add; } /** * @notice Allows to `add` or remove an `account` as an authorized maintainer. */ function updateAuthorizedMaintainer(address account, bool add) public onlyMaintainer() { require(_authorizedMaintainer[account] != add, "No change required"); emit MaintainerUpdate(account, add, msg.sender); _authorizedMaintainer[account] = add; } modifier whenOperational() { require(isOperational(), "Not operational"); _; } // ####################################################### ERC165 function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165) returns (bool) { return interfaceId == type(IInitArgsProvider).interfaceId || super.supportsInterface(interfaceId); } constructor(address _appHub) { _authorizedMaintainer[msg.sender] = true; emit MaintainerUpdate(msg.sender, true, msg.sender); appHubAddress = _appHub; } } // File contracts/IERC6454.sol /// @title EIP-6454 Minimalistic Non-Transferable interface for NFTs /// @dev See https://eips.ethereum.org/EIPS/eip-6454 /// @dev Note: the ERC-165 identifier for this interface is 0x91a6262f. pragma solidity ^0.8.18; interface IERC6454 /* is IERC165 */ { /** * @notice Used to check whether the given token is transferable or not. * @dev If this function returns `false`, the transfer of the token MUST revert execution. * @dev If the tokenId does not exist, this method MUST revert execution, unless the token is being checked for * minting. * @dev The `from` parameter MAY be used to also validate the approval of the token for transfer, but anyone * interacting with this function SHOULD NOT rely on it as it is not mandated by the proposal. * @param tokenId ID of the token being checked * @param from Address from which the token is being transferred * @param to Address to which the token is being transferred * @return Boolean value indicating whether the given token is transferable */ function isTransferable(uint256 tokenId, address from, address to) external view returns (bool); } // File contracts/MetaAnchor.sol pragma solidity ^0.8.18; /** * @title Meta Anchor (TM) Digital Soul (TM) contract * @author metaanchor.io * @notice This contract anchors DigitalSoul-NFTs to Physical Objects. They're called * DigitalSoul-NFTs because as they anchor 1:1 and inseperably to a specific physical object * over its entire lifecycle. Whoever posesses/controls the physical object has the * authorization to control the corresponding DigitalSoul-NFT, e.g. can transfer or mint. * Note that neither from- nor to-account need to sign transfers, authorization is solely * provided through access to the physical object! * * ~~ OWNER OF THIS CONTRACT ~~ * The owner is indicated through `owner()`. The owner issues the collection and physical objects, * manages the contract and it's appearance on marketplaces/platforms and * is the issuer of any meta data, assets or perks associated with the DigitalSoul-NFTs. * * ~~ SYSTEM DESCRIPTION ~~ * A Physical Object is equipped with a uniquely identifiable MetaAnchor security tag ("anchor"). * A user optically authenticates the MetaAnchor security tag with a smartphone and specifies the * to`-account, which shall receive the DigitalSoul-NFT. * Upon the authenticated presence of the Physical Object through the MetaAnchor technology, * `transferAnchor` is invoked. The DigitalSoul-NFT gets minted or transfered to the * `to`-account, irregardless whether an eventual previous owner approves or not. * Using the well-known `tokenURI()`, the DigitalSoul (metadata) of the Physical Object can be resolved. * Metadata is stored off-chain (IPFS, centralized server, ...) by the owner of this contract, hence the * producer/issuer of the Physical Objects. * Metadata is linked to the anchor (not the tokenID!), hence anchored 1:1 to the physical object. * * ~~ SMART CONTRACT TLDR ~~ * a) DigitalSoul-NFTs are technically ERC-6956 Asset-Bound NFTs, fully compatible with ERC-721. * b) When an account owns or has owned the DigitalSoul-NFT this proves this account has benefitted from * having access to the Physical Object corresponding to the specific anchor. * c) `ownerOf[tokenByAnchor(anchor)]` indicates the current owner of the DigitalSoul-NFT, which * corresponds to the particular physical object identified through `anchor`. * d) `isFloating(anchor)` respectively `isFloating(anchorByToken(token))` indicates whether a DigitalSoul-Token * can also be transferred without having access to the physical object. * This is useful for e.g. pre-sale activity or temporary lending of DigitalSoul-Tokens to other accounts. * e) When `isFloating(anchor)==true`, a DigitalSoul-Token acts like an "ordinary" ERC-721 NFT with the caveat, * that it can be transferred from anywhere as soon as the physical object is used to authorize transferAnchor. * f) DigitalSoul-NFTs have a limited amount of `transferAnchor()` calls. Use `attestationUsagesLeft(anchor)` to see how * often a DigitalSoul-NFT can still be transferred. * * ~~ SECURITY CONSIDERATIONS ~~ * If you do not control / restrict other people's access to the physical object, a DigitalSoul-NFT may * be transferred from your wallet without your consent anytime. Protect the physical object from * unauthorized access or theft like you would protect any other "ordinary" physical thing. * * On the bright side, if your DigitalSoul-NFT should get stolen, you can recover it anytime * through using the physical object and `transferAnchor()`. * * ~~ Legal disclaimer ~~ * metaanchor.io licenses this contract to the `owner()` without warrenty of any kind, express or implied, * including but not limited to the warranties of merchantability, fitness for particular purpose and noninfringement. * In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether * in an action of contract, tort or otherwise, arising from, out of or in connection with this software * or the use or other dealings in the software. * * @dev This contract extends [ERC-6956, also authored by us](https://eips.ethereum.org/EIPS/eip-6956) and is therefore * fully compatible with ERC-721 [especially when a token `floating`]. * TokenIds are assigned to anchors in the order of minting. Once a tokenId <> anchor relation is established, * it is immutable over the complete lifecycle. */ contract MetaAnchor is ERC6956Full, Pausable, Ownable, AppContract, ProvidableContract, IERC6454{ /// @notice ORACLE_ROLE is an accepted signer for attestations. /// @return Role hash, as should be passed to hasRole(), grantRole() bytes32 public constant ORACLE_ROLE = keccak256("ORACLE_ROLE"); /// @notice MINTER_ROLE can call dropAnchor and safeMint(), the latter is not recommended to use directly /// @return Role hash, as should be passed to hasRole(), grantRole() bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); /// @notice MINTER_ROLE can call dropAnchor and safeMint(), the latter is not recommended to use directly /// @return Role hash, as should be passed to hasRole(), grantRole() bytes32 public constant MAINTAINER_ROLE = keccak256("MAINTAINER_ROLE"); bytes32 public constant DEPLOYER_ROLE = keccak256("DEPLOYER_ROLE"); string internal _contractUri = ""; bool private _isInitialized; /// @notice Contract version string function getVersion() public virtual pure override returns (string memory) { return "0.3.1"; } /// @notice Takes identifiying _name and _symbol parameters. updateBaseURI() and maxDropsPerAnchor() shall directly after deployment. /// @dev Typically used via MetaAnchorFactory, which ensures to set default parameters. /// @param _hub The address of the AppHub for role management /// @param _name The Name of the Contract, usually also the Collection-Name /// @param _symbol The symbol for tokens of this contract. In MetaAnchor-language often referred to as CSN (contract short name) constructor(address _hub, string memory _name, string memory _symbol, IERC6956AttestationLimited.AttestationLimitPolicy _limitUpdatePolicy) ERC6956Full(_name, _symbol, _limitUpdatePolicy) AppContract(_hub) { // Better safe than sorry - remove the Deployer (factory) from ERC6956. // This is possible, because this constructor is run after all dependent constructors, so also // after ERC6956Full-constructor as well as the ProvidableContract-constructor (calling initialize) delete maintainers[msg.sender]; } /** * @notice Decodes init-args, typically generated by the ProviderContract * @param initArgs abi-encoded init-args * @return _burnAuthorization Indicates which authorization is needed to burn tokens * @return _approveAuthorizaion Indicates which authorization is needed to approve other accounts for a token * @return _canStartFloatingAuthorization Indicates which authorization is needed to start floating of an anchor * @return _canStopFloatingAuthorization Indicates which authorization is needed to stop floating of an anchor * @return _attestationLimit The initial attestation limit. This is the only way to define the attestationLimit if AttestationLimitPolicy is IMMUTABLE. */ function decodeInitArgs(bytes memory initArgs) public pure returns ( IERC6956.Authorization _burnAuthorization, IERC6956.Authorization _approveAuthorizaion, // IERC6956Floatable IERC6956.Authorization _canStartFloatingAuthorization, IERC6956.Authorization _canStopFloatingAuthorization, // IERC6956AttestationLimited uint256 _attestationLimit ) { (_burnAuthorization, _approveAuthorizaion, _canStartFloatingAuthorization, _canStopFloatingAuthorization, _attestationLimit ) = abi.decode( initArgs, ( IERC6956.Authorization, IERC6956.Authorization, IERC6956.Authorization, IERC6956.Authorization, uint256 ) ); // implicitely return values } /** * @notice Initializes the contract with well-defined init args (refer `decodeInitArgs` for definition) * @dev This is the only way how attestationLimits can be defined when AttestationLimitPolicy == IMMUTABLE. * @param initArgs abi-encoded, typically requested from MetaAnchorFactory and generated by MetaAnchorProvider */ function initialize(bytes memory initArgs) public virtual override onlyMaintainer() { require(!_isInitialized, "initialize() can only be called once"); _isInitialized = true; ( IERC6956.Authorization _burnAuthorization, IERC6956.Authorization _approveAuthorizaion, // IERC6956Floatable IERC6956.Authorization _canStartFloatingAuthorization, IERC6956.Authorization _canStopFloatingAuthorization, // IERC6956AttestationLimited uint256 _attestationLimit ) = decodeInitArgs(initArgs); updateBurnAuthorization(_burnAuthorization); updateApproveAuthorization(_approveAuthorizaion); updateFloatingAuthorization(_canStartFloatingAuthorization, _canStopFloatingAuthorization); updateGlobalAttestationLimit(_attestationLimit); } // ####################################### ERC6956-Overrides for permissions function isMaintainer(address a) public virtual view override(ERC6956) returns (bool) { // explicitly override the permission system of ERC6956 with AppHub return hasRole(MAINTAINER_ROLE, a) || super.isMaintainer(a); } /** * @notice Declares `oracleAddress` trusted, if it has the `ORACLE_ROLE` * @dev Overrides ERC6956 oracle logic, does NOT emit OracleUpdate events, when ORACLE_ROLE is granted via grantRole() * @param oracleAddress Oracle address in question * @return isTrusted true, if oracleAddress has ORACLE_ROLE */ function isTrustedOracle(address oracleAddress) public view override(ERC6956) returns (bool isTrusted) { return hasRole(ORACLE_ROLE, oracleAddress); } /** * @notice When calling ContractURI, typically json-metadata is returned. Refer e.g. the OpenSea format suggestion * @return ContractURI pointing to the json */ function contractURI() public view returns (string memory) { return _contractUri; } /** * @notice Pauses the contract. This means among other things that drops/releases are no longer possible. */ function pause() public onlyRole(PAUSER_ROLE) { _pause(); } /** * Unpauses the contract / reverts pause(). */ function unpause() public onlyRole(PAUSER_ROLE) { _unpause(); } // ####################################### IERC6454 /** * @notice Refer IERC6454. * @param tokenId TokenId in question * @param from current owner address or approved address * @param to target address, where tokenId shall be transfered to. * @dev Indicates general */ function isTransferable(uint256 tokenId, address from, address to) external view returns (bool transferable) { if(from == address(0)) { // Minting can only be done through transferAnchor() return false; } bytes32 anchor = anchorByToken[tokenId]; require(anchor != 0x0, "Token does not exist"); // A non-existent tokenId will resolve to the invalid anchor 0x0. ERC-6454 requires this throw if (from == address(0) && to == address(0)) { // Indicate the token can be transferred in general, as tokens can be oracle-transferred anytime - as long as limit is not reached // but even if the limit is reached, a floating token could be transfered by "traditional" ways. return attestationUsagesLeft(anchor) > 0 || floating(anchor); } return floating(anchor) && _isApprovedOrOwner(from, tokenId); } // ####################################### ER165 function supportsInterface(bytes4 interfaceId) public view virtual override(ERC6956Full, AppContract) returns (bool) { return super.supportsInterface(interfaceId) || interfaceId == type(IERC6454).interfaceId; } /// @notice Set a new contractURI. Refer `contractURI` for details. /// @param contractUri The token base-URI. Must end with slash '/'. function updateContractURI(string calldata contractUri) public onlyRole(MAINTAINER_ROLE) whenNotPaused() { _contractUri = contractUri; } /// @notice Transfers ownership over the contract. The owner has no updating power in this contract, but is returned when calling owner(). /// This allows the owner to act/sign accordinlgy external software applications / marketplaces etc. /// The owner can be changed by MAINTAINER_ROLE or the current owner. /// @dev Overrides Ownable's function. For MetaAnchor, the MAINTAINER_ROLE can also change ownership. /// Do NOT use onlyOwner modifier in this contract, as this would give power to the owner, which is not desired in our use-case. /// @param newOwner The new owner function transferOwnership(address newOwner) override public virtual ownerOrMaintainer() whenNotPaused() { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); // Calls the Ownable implementation } modifier ownerOrMaintainer() { require(hasRole(MAINTAINER_ROLE, msg.sender) || msg.sender == owner(), "Caller must be maintainer or owner"); _; } // ################################## PAUSABLE function wrappers function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize) internal virtual override(ERC6956Full) whenNotPaused() { super._beforeTokenTransfer(from, to, tokenId, batchSize); } function anchorValid(bytes32 anchor, bytes32[] memory proof) public virtual view override(ERC6956Full) whenNotPaused() returns (bool isValid) { return super.anchorValid(anchor, proof); } function _beforeAttestationUse(bytes32 anchor, address to, bytes memory data) internal view virtual override(ERC6956Full) whenNotPaused() { super._beforeAttestationUse(anchor, to, data); } function _approve(address to, uint256 tokenId) internal virtual override(ERC721) whenNotPaused(){ super._approve(to, tokenId); } function _setApprovalForAll(address owner, address operator, bool approved) internal virtual override(ERC721) whenNotPaused() { super._setApprovalForAll(owner, operator, approved); } } // File contracts/MetaAnchorFactory.sol pragma solidity ^0.8.18; /** * @title MetaAnchor Factory * @author [email protected] * @notice Registers and deploys MetaAnchor contracts and lets you verify via `hasDeployed()` * whether contract is an original MetaAnchor contract. Corresponding deployed contracts will have the same address on all EVM-blockchains. * @dev A Meta Anchor (TM) contract is identified solely by its symbol. This factory ensures max. one contract per symbol exists. * Contracts will deploy to a deterministic address on all EVM-chains, depending solely on (version, deployArgs). * Each MetaAnchor-contract needs to have the following mandatory constructor arguments (in that order): * (address appHub, string name, string symbol) * - The latter two are passed to ERC-721. * - The factory ensures at most one registered (and consequently deployed) contract per symbol exists * In order to ensure deterministic deployment cross-chain * - The provider registered for a version needs to return the same byteCode on all chains * - deployArgs when registering deployment of a certain version need to be identical * - This factory needs to be deployed to the same address on all chains * Also features a mechanism to grant finite numbers of registrations and deployments to arbitrary accounts * * Refer documentation of `SlimFactory` or details on the registration/deployment process */ contract MetaAnchorFactory is AppContract, SlimFactory, Pausable, IDeployedContract { /** * Emits when new registrations are granted to an `account` * @param account Account, which has been granted `nrAdded` additional registrations * @param nrAdded Indicates how many additional registrations have been added to the account * @param registrationsLeft Registrations left for the account * @param registrationLimit New registration limit for account after adding `nrAdded` */ event RegistrationsGranted(address indexed account, uint256 nrAdded, uint256 registrationsLeft, uint256 registrationLimit); /** * Emits when new deployments are granted to an `account` * @param account Account, which has been granted `nrAdded` additional deployments * @param nrAdded Indicates how many additional deployments have been added to the account * @param deploymentsLeft Deployments left for the account * @param deploymentLimit New deployment limit for account after adding `nrAdded` */ event DeploymentsGranted(address indexed account, uint256 nrAdded, uint256 deploymentsLeft, uint256 deploymentLimit); /** * @notice DEPLOYER_ROLE is permitted to deploy new contracts */ bytes32 public constant DEPLOYER_ROLE = keccak256("DEPLOYER_ROLE"); /** * @notice MAINTAINER_ROLE corresponds to the permissions of SlimFactory.isMaintainer(), * which can maintain the factory and unregister contracts */ bytes32 public constant MAINTAINER_ROLE = keccak256("MAINTAINER_ROLE"); /** * @notice Can add providers, remove registrations etc */ bytes32 public constant FACTORY_MAINTAINER_ROLE = keccak256("FACTORY_MAINTAINER_ROLE"); /** * @notice Can pause the contract */ bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); /** * @notice REGISTRAR_ROLE can register new contracts and unregister own earlier registrations */ bytes32 public constant REGISTRAR_ROLE = keccak256("REGISTRAR_ROLE"); /** * @notice Version of this contract */ string public constant version = "0.3.2"; /** * @notice Registration limits per account. Applies only to accounts not granted the REGISTRAR_ROLE */ mapping (address => uint256) public registrationLimit; /** * @notice Deployment limits per account. Applies only to accounts not granted the DEPLOYER_ROLE */ mapping (address => uint256) public deploymentLimit; /** * @notice Records the number of active registrations per contract */ mapping (address => uint256) public registrationsByAccount; /** * @notice Records the number of active deployments per contract */ mapping (address => uint256) public deploymentsByAccount; /** * @notice Records the deployer account of a specific deployment. */ mapping (address => address) public deployerOf; /** * @notice Resolves a symbol to the registered contract address 1:1 */ mapping (string => address) public contractBySymbol; /** * @notice Resolves a contract address to the symbol 1:1 */ mapping (address => string) public symbolByContract; /** * @notice IDeployedContract interface, indicates the deployer of this contract */ address public deployedBy; /** * @notice IDeployedContract interface, indicates whether a contract at `addr` was deployed through this factory * @param addr Address of contract in question, typically a MetaAnchor-contract */ function hasDeployed(address addr) public view returns (bool hasDeployedAddr) { return deployerOf[addr] != address(0); } // ################################ Use AppHub-Permissions to overwrite SlimFactory-Authorization mechanics /** * Indicates that accounts with `FACTORY_MAINTAINER_ROLE` are the only maintainers * @param addr Account in question */ function isAuthorizedMaintainer(address addr) public view override returns (bool) { return hasRole(FACTORY_MAINTAINER_ROLE, addr); } /** * @notice Indicates whether an account `addr` currently has permissions/capacity to register a contract * @param addr Account-address */ function isAuthorizedRegistrar(address addr) public view override returns (bool) { return hasRole(REGISTRAR_ROLE, addr) || (registrationsLeft(addr) > 0); } /** * @notice Indicates whether an account `addr` currently has permissions/capacity to deploy a contract * @param addr Account-address */ function isAuthorizedDeployer(address addr) public view override returns (bool) { return hasRole(DEPLOYER_ROLE, addr) || (deploymentsLeft(addr) > 0); } /** * @dev Hook from Slimfactory. Verifies before registration that the symbol is still available and if App-Hub address matches the one of this factory * @param deploymentAddress Address of the registered contract * @param _deployArgs ABI-encoded deployment arguments, where the first 3 parameters are (appHubAddress, contractName, contractSymbol) */ function _beforeRegister(address deploymentAddress, string memory /*_version*/, bytes memory _deployArgs, bytes memory /*_initArgs*/) internal virtual override(SlimFactory) { (address appHub, , string memory symbol ) = abi.decode(_deployArgs, (address, string, string)); require(contractBySymbol[symbol] == address(0), "Symbol already taken"); require(appHub == appHubAddress, "AppHubAddress mismatch"); registrationsByAccount[msg.sender] += 1; symbolByContract[deploymentAddress] = symbol; contractBySymbol[symbol] = deploymentAddress; } /** * @dev Hook from SlimFactory. Rollback of state-changes made in `_beforeRegister` * @param toUnregister Contract that will be unregistered */ function _beforeUnregister(address toUnregister) internal override(SlimFactory) { registrationsByAccount[registrarByContract[toUnregister]] -= 1; delete contractBySymbol[symbolByContract[toUnregister]]; delete symbolByContract[toUnregister]; super._beforeUnregister(toUnregister); } // ################################## UTILITY for finite-time deployments of foreign accounts /** * @notice Allows FACTORY_MAINTAINER_ROLEs to grant additional `nrRegistrations` to `account` */ function grantRegistrations(address account, uint256 nrRegistrations) public onlyRole(FACTORY_MAINTAINER_ROLE) { registrationLimit[account] += nrRegistrations; emit RegistrationsGranted(account, nrRegistrations, registrationsLeft(account), registrationLimit[account]); } /** * @notice Allows FACTORY_MAINTAINER_ROLEs to grant additional `nrDeployments` to `account` */ function grantDeployments(address account, uint256 nrDeployments) public onlyRole(FACTORY_MAINTAINER_ROLE) { deploymentLimit[account] += nrDeployments; emit DeploymentsGranted(account, nrDeployments, deploymentsLeft(account), deploymentLimit[account]); } /** * @notice Indicates how many deployments are left for `account`. * @dev Note if account has DEPLOYER_ROLE, it can even deploy registered contracts if this method returns 0 */ function deploymentsLeft(address account) public view returns(uint256 nrDeploymentsLeft) { uint256 limit = deploymentLimit[account]; uint256 used = deploymentsByAccount[account]; if(used > limit) { return 0; } return limit - used; } /** * @notice Indicates how many registrations are left for `account`. * @dev Note if account has REGISTRAR_ROLE, it can even register new contracts if this method returns 0 */ function registrationsLeft(address account) public view returns(uint256 nrRegistrationsLeft) { uint256 limit = registrationLimit[account]; uint256 used = registrationsByAccount[account]; if(used > limit) { return 0; } return limit - used; } /** * @dev Tracks deployment details for stats and deployment permissions * @param _deploymentAddr Address of the just-deployed contract */ function _afterDeployment(address _deploymentAddr, string memory /*version*/) internal override(SlimFactory) { deploymentsByAccount[msg.sender] += 1; deployerOf[_deploymentAddr] = msg.sender; } /** * @notice Registers a new MetaAnchor contract with `version` using default settings. Refer `SlimFactory.deploy()` for further details. * @param name Name of the contract (immutable) * @param symbol Symbol of the contract (immutable), identifying the MetaAnchor-contract unambigiously * @param contractVersion The contract version, which shall be deployed in format X.Y.Z */ function registerWithDefaults(string memory name, string memory symbol, string memory contractVersion) public { require(versionSupported(contractVersion), "Requested version not supported"); BaseProvider bp = BaseProvider(providerByVersion[contractVersion]); bytes memory constructorArgs = bp.getDefaultArgs(appHubAddress, name, symbol); bytes memory initArgs = bp.getDefaultInitArgs(); register(contractVersion, constructorArgs, initArgs); } // ################################### ERC-165 function supportsInterface(bytes4 interfaceId) public view virtual override(AppContract, SlimFactory) returns (bool) { return interfaceId == type(IDeployedContract).interfaceId || super.supportsInterface(interfaceId); } // ########################### PAUSABLE /** * @notice Pauses the contract. * @dev This means among other things that deployments and registrations are no longer possible (via `isOperational`). */ function pause() public onlyRole(PAUSER_ROLE) { _pause(); } /** * Unpauses the contract / reverts pause(). */ function unpause() public onlyRole(PAUSER_ROLE) { _unpause(); } /** * Only operational, when contract is not paused */ function isOperational() public virtual view override(SlimFactory) returns (bool) { return !paused(); } constructor(address _hub) AppContract(_hub) SlimFactory(_hub) { // Set default parameters for a higher chance that behavior across chains is equal! deployedBy = msg.sender; } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_hub","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"hub","type":"address"},{"indexed":false,"internalType":"address","name":"oldHub","type":"address"},{"indexed":false,"internalType":"address","name":"maintainer","type":"address"}],"name":"AppHubUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"string","name":"version","type":"string"},{"indexed":false,"internalType":"address","name":"deployer","type":"address"}],"name":"ContractDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"string","name":"version","type":"string"},{"indexed":false,"internalType":"address","name":"registrar","type":"address"}],"name":"ContractRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"address","name":"maintainer","type":"address"}],"name":"ContractUnregistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"bool","name":"added","type":"bool"},{"indexed":false,"internalType":"address","name":"maintainer","type":"address"}],"name":"DeployerUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"newSalt","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"oldSalt","type":"bytes32"},{"indexed":false,"internalType":"address","name":"maintainer","type":"address"}],"name":"DeploymentSaltUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"nrAdded","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"deploymentsLeft","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"deploymentLimit","type":"uint256"}],"name":"DeploymentsGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"bool","name":"added","type":"bool"},{"indexed":false,"internalType":"address","name":"maintainer","type":"address"}],"name":"MaintainerUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":true,"internalType":"string","name":"version","type":"string"},{"indexed":false,"internalType":"address","name":"maintainer","type":"address"}],"name":"ProviderUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"bool","name":"added","type":"bool"},{"indexed":false,"internalType":"address","name":"maintainer","type":"address"}],"name":"RegistrarUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"nrAdded","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"registrationsLeft","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"registrationLimit","type":"uint256"}],"name":"RegistrationsGranted","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"}],"name":"RoleRevoked","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":[],"name":"DEPLOYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FACTORY_MAINTAINER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINTAINER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REGISTRAR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"addressByBytecodeHash","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"appHubAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"bytecodeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"contractBySymbol","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"registeredAddress","type":"address"}],"name":"deploy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deployArgsByAddress","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deployedBy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"deployedContracts","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deployerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deploymentLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deploymentsByAccount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"deploymentsLeft","outputs":[{"internalType":"uint256","name":"nrDeploymentsLeft","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"bytecode","type":"bytes"},{"internalType":"bytes32","name":"_salt","type":"bytes32"}],"name":"getAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"deployedAddress","type":"address"}],"name":"getInitArgs","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"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":"address","name":"account","type":"address"},{"internalType":"uint256","name":"nrDeployments","type":"uint256"}],"name":"grantDeployments","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"nrRegistrations","type":"uint256"}],"name":"grantRegistrations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"hasDeployed","outputs":[{"internalType":"bool","name":"hasDeployedAddr","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":"","type":"address"}],"name":"initArgsByAddress","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isAuthorizedDeployer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isAuthorizedMaintainer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isAuthorizedRegistrar","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isOperational","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pendingDeployments","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"providerByVersion","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"providerForAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"contractVersion","type":"string"},{"internalType":"bytes","name":"deployArgs","type":"bytes"},{"internalType":"bytes","name":"initArgs","type":"bytes"}],"name":"register","outputs":[{"internalType":"address","name":"registeredAddress","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"contractVersion","type":"string"}],"name":"registerWithDefaults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"registrarByContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"registrationLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"registrationsByAccount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"registrationsLeft","outputs":[{"internalType":"uint256","name":"nrRegistrationsLeft","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"version","type":"string"}],"name":"removeVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","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":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"symbolByContract","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"toUnregister","type":"address"}],"name":"unregister","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"hub","type":"address"}],"name":"updateAppHub","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"add","type":"bool"}],"name":"updateAuthorizedDeployer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"add","type":"bool"}],"name":"updateAuthorizedMaintainer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"add","type":"bool"}],"name":"updateAuthorizedRegistrar","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"newSalt","type":"bytes32"}],"name":"updateDeploymentSalt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"providerAddress","type":"address"}],"name":"updateProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"versionByVersionHash","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"version","type":"string"}],"name":"versionSupported","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040527f7818bc9a57f80aba9f029bdb4f8cea68d4c1e1633cdab17a6843b82f5f9ab7376010553480156200003557600080fd5b506040516200359338038062003593833981016040819052620000589162000108565b600180546001600160a01b0319166001600160a01b038316178155336000818152600e6020908152604091829020805460ff19168517905581518381529081019390935282015281907f4c7955e1033c3625c926adda75a0b51e45d84d775de8d189e2530443c826b8139060600160405180910390a1600a80546001600160a01b039092166001600160a01b03199283161790556011805460ff191690556019805490911633179055506200013a565b6000602082840312156200011b57600080fd5b81516001600160a01b03811681146200013357600080fd5b9392505050565b613449806200014a6000396000f3fe608060405234801561001057600080fd5b506004361061029c5760003560e01c8061a976146102a157806301ffc9a7146102ca5780630b132815146102ed5780630ddafcb71461030d5780630f786eb41461032257806319c0e22a146103355780631cb7fa91146103485780631f21cc911461035b578063216470c81461036e578063248a9ca31461038157806329fe274f146103a25780632b936087146103d05780632ec2c246146103f95780632f2ff15d1461040c5780633089b0161461041f57806330fc362f1461043f578063357543f71461045257806336568abe14610465578063381780d314610478578063388d9a0b1461048b57806339676bce1461049e5780633dda4a6c146104be5780633f4ba83a146104d1578063416dc732146104d957806341d078f91461050257806344d01fd11461051557806348aac3921461052a5780634c96a3891461053d57806354fd4d50146105505780635c975abb146105745780638456cb591461057f5780638710b0b7146105875780638e4cc935146105aa57806391d14854146105ca5780639ad1ee10146105dd5780639d7cd25b146105f0578063a217fddf14610619578063a36c898514610621578063b24bc00214610634578063b8a56eb214610647578063bc3ef3c01461065a578063bcabbffb1461066d578063c782b2fb1461068d578063cd905dff146106a0578063d012a1d4146106a8578063d1419762146106dc578063d547741f146106ef578063d6c8401714610702578063e0926c8c14610736578063e63ab1e91461075f578063e81cf77d14610774578063e8baf9af14610787578063ea0cd9a0146107a7578063ecd00261146107ba578063ef70768a146107cf578063f0e35016146107e2578063f68e9553146107f5578063f87422541461080a575b600080fd5b6102b46102af366004612aa7565b610831565b6040516102c19190612b14565b60405180910390f35b6102dd6102d8366004612b27565b6108cb565b60405190151581526020016102c1565b6103006102fb366004612c14565b6108f6565b6040516102c19190612c9b565b61032061031b366004612cbd565b610d4b565b005b6102b4610330366004612aa7565b610e16565b6102dd610343366004612cf6565b610e2f565b6102b4610356366004612aa7565b610e6c565b601954610300906001600160a01b031681565b6102b461037c366004612d2a565b610f18565b61039461038f366004612d2a565b610f31565b6040519081526020016102c1565b6102dd6103b0366004612aa7565b6001600160a01b0390811660009081526016602052604090205416151590565b6103006103de366004612d2a565b6005602052600090815260409020546001600160a01b031681565b610320610407366004612aa7565b610f46565b61032061041a366004612d43565b6111cd565b61039461042d366004612aa7565b60126020526000908152604090205481565b61032061044d366004612c14565b6111ee565b6102dd610460366004612aa7565b611362565b610320610473366004612d43565b611394565b6102dd610486366004612aa7565b611412565b610320610499366004612cbd565b61143d565b6103946104ac366004612aa7565b60046020526000908152604090205481565b6102b46104cc366004612aa7565b611508565b610320611521565b6103006104e7366004612aa7565b6016602052600090815260409020546001600160a01b031681565b6102dd610510366004612aa7565b611544565b61039460008051602061337483398151915281565b610300610538366004612d68565b61155e565b61030061054b366004612aa7565b6115b5565b6102b460405180604001604052806005815260200164181719971960d91b81525081565b60115460ff166102dd565b6103206119d3565b6102dd610595366004612aa7565b600c6020526000908152604090205460ff1681565b6103946105b8366004612aa7565b60136020526000908152604090205481565b6102dd6105d8366004612d43565b6119f3565b6103006105eb366004612d2a565b611a90565b6103006105fe366004612aa7565b6006602052600090815260409020546001600160a01b031681565b610394600081565b61032061062f366004612aa7565b611aba565b610320610642366004612cbd565b611c6b565b610320610655366004612dac565b611d36565b610320610668366004612d2a565b611de6565b61039461067b366004612aa7565b60146020526000908152604090205481565b61039461069b366004612aa7565b611e75565b6102dd611ebd565b6103006106b6366004612cf6565b80516020818301810180516017825292820191909301209152546001600160a01b031681565b6103206106ea366004612cf6565b611ed1565b6103206106fd366004612d43565b611fd9565b610300610710366004612cf6565b80516020818301810180516008825292820191909301209152546001600160a01b031681565b610300610744366004612aa7565b6003602052600090815260409020546001600160a01b031681565b6103946000805160206133d483398151915281565b600a54610300906001600160a01b031681565b610394610795366004612aa7565b60156020526000908152604090205481565b6103946107b5366004612aa7565b611ff5565b61039460008051602061339483398151915281565b6103206107dd366004612aa7565b61202b565b6103206107f0366004612dac565b612199565b6103946000805160206133f483398151915281565b6103947f339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab9581565b6002602052600090815260409020805461084a90612dd8565b80601f016020809104026020016040519081016040528092919081815260200182805461087690612dd8565b80156108c35780601f10610898576101008083540402835291602001916108c3565b820191906000526020600020905b8154815290600101906020018083116108a657829003601f168201915b505050505081565b60006001600160e01b03198216631b6ff5ef60e11b14806108f057506108f08261223c565b92915050565b600061090133611362565b61094e5760405162461bcd60e51b8152602060048201526019602482015278417574686f72697a656420526567697374726172206f6e6c7960381b60448201526064015b60405180910390fd5b610956611ebd565b6109725760405162461bcd60e51b815260040161094590612e12565b60006008856040516109849190612e3b565b908152604051908190036020019020546001600160a01b03169050806109e05760405162461bcd60e51b8152602060048201526011602482015270139bc81c1c9bdd9a59195c88199bdd5b99607a1b6044820152606401610945565b6040516311d9814560e11b81528190610a5f906001600160a01b038316906323b3028a90610a12908990600401612b14565b600060405180830381865afa158015610a2f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a579190810190612e87565b60105461155e565b6001600160a01b038082166000908152600360205260409020549194501615610ac85760405162461bcd60e51b815260206004820152601b60248201527a10dbdb9d1c9858dd08185b1c9958591e481c9959da5cdd195c9959602a1b6044820152606401610945565b6001600160a01b0383811660009081526006602090815260408083208054336001600160a01b03199182161790915560039092529091208054909116918416919091179055610b1983878787612261565b6001600160a01b0383166000908152600260205260409020610b3b8682612f1d565b506040516311d9814560e11b81526000906001600160a01b038316906323b3028a90610b6b908990600401612b14565b600060405180830381865afa158015610b88573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bb09190810190612e87565b90506000826001600160a01b031663323e1e3b836040518263ffffffff1660e01b8152600401610be09190612b14565b602060405180830381865afa158015610bfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c219190612fdc565b6000818152600560205260409020549091506001600160a01b031615610c975760405162461bcd60e51b815260206004820152602560248201527f4964656e746963616c2062797465636f646520616c72656164792072656769736044820152641d195c995960da1b6064820152608401610945565b6001600160a01b03851660008181526004602090815260408083208590558483526005825280832080546001600160a01b031916851790559282526007905220610ce18782612f1d565b506001600160a01b0385166000818152600c602052604090819020805460ff19166001179055517f22889bf4107add8fa7be4d783201d8c9234cbf7d10a519d47fa9070a0b92ad5b90610d37908b903390612ff5565b60405180910390a2505050505b9392505050565b610d5433611544565b610d705760405162461bcd60e51b81526004016109459061301f565b6001600160a01b0382166000908152600d602052604090205481151560ff909116151503610db05760405162461bcd60e51b815260040161094590613053565b7fa79756a62eeadcf4edcdd62ec59d188985cb9e5a26b48d9bedd37244438d55ab828233604051610de39392919061307f565b60405180910390a16001600160a01b03919091166000908152600d60205260409020805460ff1916911515919091179055565b6007602052600090815260409020805461084a90612dd8565b6000806001600160a01b0316600883604051610e4b9190612e3b565b908152604051908190036020019020546001600160a01b0316141592915050565b6001600160a01b0381166000908152600760205260409020805460609190610e9390612dd8565b80601f0160208091040260200160405190810160405280929190818152602001828054610ebf90612dd8565b8015610f0c5780601f10610ee157610100808354040283529160200191610f0c565b820191906000526020600020905b815481529060010190602001808311610eef57829003601f168201915b50505050509050919050565b6009602052600090815260409020805461084a90612dd8565b60009081526020819052604090206001015490565b610f4f33611544565b80610f5e5750610f5e33611362565b610fbd5760405162461bcd60e51b815260206004820152602a60248201527f6d73672e73656e646572206d757374206265206d61696e7461696e6572206f72604482015269103932b3b4b9ba3930b960b11b6064820152608401610945565b6001600160a01b0381166000908152600c602052604090205460ff166110495760405162461bcd60e51b815260206004820152603b60248201527f4f6e6c7920726567697374657265642c206e6f742d6465706c6f79656420636f60448201527a1b9d1c9858dd1cc818d85b881899481d5b9c9959da5cdd195c9959602a1b6064820152608401610945565b61105233611544565b6110d4576001600160a01b038181166000908152600660205260409020541633146110d45760405162461bcd60e51b815260206004820152602c60248201527f43616e206f6e6c7920756e7265676973746572206f776e20726567697374657260448201526b656420636f6e74726163747360a01b6064820152608401610945565b6110dd816123db565b6001600160a01b0381166000818152600460209081526040808320805484526005835281842080546001600160a01b0319169055938352928290556002905290812061112891612a44565b6001600160a01b038116600090815260076020526040812061114991612a44565b6001600160a01b0381166000818152600c60209081526040808320805460ff191690556006825280832080546001600160a01b031990811690915560039092529182902080549091169055517f6c0b8518b86a3f2aab1a16148ee99e9cce485dfb40b2c510326a696b577a6f43906111c2903390612c9b565b60405180910390a250565b6111d682610f31565b6111df81612480565b6111e9838361248a565b505050565b6111f781610e2f565b6112435760405162461bcd60e51b815260206004820152601f60248201527f5265717565737465642076657273696f6e206e6f7420737570706f72746564006044820152606401610945565b60006008826040516112559190612e3b565b90815260405190819003602001812054600a546305cd5a2160e51b83526001600160a01b039182169350600092849263b9ab44209261129d92911690899089906004016130a2565b600060405180830381865afa1580156112ba573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112e29190810190612e87565b90506000826001600160a01b031663de191a9f6040518163ffffffff1660e01b8152600401600060405180830381865afa158015611324573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261134c9190810190612e87565b90506113598483836108f6565b50505050505050565b600061137c6000805160206133f4833981519152836119f3565b806108f05750600061138d83611ff5565b1192915050565b6001600160a01b03811633146114045760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610945565b61140e828261250e565b5050565b600061142c600080516020613394833981519152836119f3565b806108f05750600061138d83611e75565b61144633611544565b6114625760405162461bcd60e51b81526004016109459061301f565b6001600160a01b0382166000908152600f602052604090205481151560ff9091161515036114a25760405162461bcd60e51b815260040161094590613053565b7f4dcb632405a82ed0b4860fb7768a7994956842dac6dd03ca0c0ca9b623ecce8b8282336040516114d59392919061307f565b60405180910390a16001600160a01b03919091166000908152600f60205260409020805460ff1916911515919091179055565b6018602052600090815260409020805461084a90612dd8565b6000805160206133d483398151915261153981612480565b611541612573565b50565b60006108f0600080516020613374833981519152836119f3565b8151602092830120604080516001600160f81b0319818601523060601b6001600160601b03191660218201526035810193909352605580840192909252805180840390920182526075909201909152805191012090565b60006115c033611412565b6116075760405162461bcd60e51b8152602060048201526018602482015277417574686f72697a6564204465706c6f796572206f6e6c7960401b6044820152606401610945565b6001600160a01b0380831660009081526003602090815260408083205460029092528220805491909316929061163c90612dd8565b80601f016020809104026020016040519081016040528092919081815260200182805461166890612dd8565b80156116b55780601f1061168a576101008083540402835291602001916116b5565b820191906000526020600020905b81548152906001019060200180831161169857829003601f168201915b505050505090506000826001600160a01b03166323b3028a836040518263ffffffff1660e01b81526004016116ea9190612b14565b600060405180830381865afa158015611707573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261172f9190810190612e87565b6001600160a01b03868116600090815260046020819052604091829020549151634fa48f7760e11b815293945091861692639f491eee926117749286929091016130e2565b602060405180830381865afa158015611791573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b59190613104565b6118195760405162461bcd60e51b815260206004820152602f60248201527f42797465636f646520766572696669636174696f6e206661696c65642c20766560448201526e7273696f6e206d69736d617463683f60881b6064820152608401610945565b6000611827826010546125bf565b9050856001600160a01b0316816001600160a01b03161461189a5760405162461bcd60e51b815260206004820152602760248201527f50726564696374656420616e64206465706c6f7965642061646472657373206d6044820152660d2e6dac2e8c6d60cb1b6064820152608401610945565b6001600160a01b038087166000908152600c6020526040808220805460ff1916905580516303639b8b60e21b8152905184938416927f0b9cb2adc2bb771fa4d112f6792bf5b3f1900f97283c8b3d99ffc518ac678e64928492630d8e6e2c926004808401939192918290030181865afa15801561191b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119439190810190613141565b33604051611952929190612ff5565b60405180910390a26119c982826001600160a01b0316630d8e6e2c6040518163ffffffff1660e01b8152600401600060405180830381865afa15801561199c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119c49190810190613141565b612609565b5095945050505050565b6000805160206133d48339815191526119eb81612480565b611541612658565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1680610d445750600154604051632474521560e21b81526001600160a01b03909116906391d1485490611a4f9086908690600401613175565b602060405180830381865afa158015611a6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d449190613104565b600b8181548110611aa057600080fd5b6000918252602090912001546001600160a01b0316905081565b6000611ac581612480565b600180546001600160a01b038481166001600160a01b031983161790925516611af583631b6ff5ef60e11b612695565b611b515760405162461bcd60e51b815260206004820152602760248201527f417070487562206d75737420696d706c656d656e7420494465706c6f796564436044820152661bdb9d1c9858dd60ca1b6064820152608401610945565b600154604051632474521560e21b81526001600160a01b03909116906391d1485490611b84906000903390600401613175565b602060405180830381865afa158015611ba1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bc59190613104565b611c1d5760405162461bcd60e51b815260206004820152602360248201527f4163636f756e7420686173206e6f2061646d696e20726f6c6520696e20417070604482015262243ab160e91b6064820152608401610945565b604080516001600160a01b03858116825283166020820152338183015290517fddc2af4c556b986b670e1d76c36d780afac8f87b3b40d118b0661a8d1e9274429181900360600190a1505050565b611c7433611544565b611c905760405162461bcd60e51b81526004016109459061301f565b6001600160a01b0382166000908152600e602052604090205481151560ff909116151503611cd05760405162461bcd60e51b815260040161094590613053565b7f4c7955e1033c3625c926adda75a0b51e45d84d775de8d189e2530443c826b813828233604051611d039392919061307f565b60405180910390a16001600160a01b03919091166000908152600e60205260409020805460ff1916911515919091179055565b600080516020613374833981519152611d4e81612480565b6001600160a01b03831660009081526012602052604081208054849290611d769084906131a2565b90915550506001600160a01b0383167f2ee86f542eb033d23dcac069078af9cbee0b275677e96fe3201238e25f9599a983611db086611ff5565b6001600160a01b03871660009081526012602052604090819020549051611dd9939291906131b5565b60405180910390a2505050565b611def33611544565b611e0b5760405162461bcd60e51b81526004016109459061301f565b611e13611ebd565b611e2f5760405162461bcd60e51b815260040161094590612e12565b60105460408051918252602082018390523382820152517fe36534ece9f01369394e4f79bb091d49758b24bb6e6e7b75898659314de34f7b9181900360600190a1601055565b6001600160a01b038116600090815260136020908152604080832054601590925282205481811115611eab575060009392505050565b611eb581836131cb565b949350505050565b6000611ecb60115460ff1690565b15905090565b611eda33611544565b611ef65760405162461bcd60e51b81526004016109459061301f565b6000600882604051611f089190612e3b565b908152604051908190036020019020546001600160a01b0316905080611f625760405162461bcd60e51b815260206004820152600f60248201526e2b32b939b4b7b7103ab735b737bbb760891b6044820152606401610945565b81604051611f709190612e3b565b604051809103902060006001600160a01b03166000805160206133b483398151915233604051611fa09190612c9b565b60405180910390a3600882604051611fb89190612e3b565b90815260405190819003602001902080546001600160a01b03191690555050565b611fe282610f31565b611feb81612480565b6111e9838361250e565b6001600160a01b038116600090815260126020908152604080832054601490925282205481811115611eab575060009392505050565b61203433611544565b6120505760405162461bcd60e51b81526004016109459061301f565b60008190506000816001600160a01b0316630d8e6e2c6040518163ffffffff1660e01b8152600401600060405180830381865afa158015612095573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120bd9190810190613141565b9050826001600160a01b03166008826040516120d99190612e3b565b908152604051908190036020019020546001600160a01b03160361210f5760405162461bcd60e51b815260040161094590613053565b8060405161211d9190612e3b565b6040518091039020836001600160a01b03166000805160206133b48339815191523360405161214c9190612c9b565b60405180910390a3826008826040516121659190612e3b565b90815260405190819003602001902080546001600160a01b03929092166001600160a01b0319909216919091179055505050565b6000805160206133748339815191526121b181612480565b6001600160a01b038316600090815260136020526040812080548492906121d99084906131a2565b90915550506001600160a01b0383167f99b7cb3383f0fd6fbc3b0995d35746310b052d8b955655d2e6da6185928fd7c58361221386611e75565b6001600160a01b03871660009081526013602052604090819020549051611dd9939291906131b5565b60006001600160e01b03198216631cb7fa9160e01b14806108f057506108f0826126b1565b6000808380602001905181019061227891906131de565b925050915060006001600160a01b03166017826040516122989190612e3b565b908152604051908190036020019020546001600160a01b0316146122f55760405162461bcd60e51b815260206004820152601460248201527329bcb6b137b61030b63932b0b23c903a30b5b2b760611b6044820152606401610945565b600a546001600160a01b0383811691161461234b5760405162461bcd60e51b8152602060048201526016602482015275082e0e090eac482c8c8e4cae6e640dad2e6dac2e8c6d60531b6044820152606401610945565b33600090815260146020526040812080546001929061236b9084906131a2565b90915550506001600160a01b03861660009081526018602052604090206123928282612f1d565b50856017826040516123a49190612e3b565b90815260405190819003602001902080546001600160a01b03929092166001600160a01b0319909216919091179055505050505050565b6001600160a01b038082166000908152600660209081526040808320549093168252601490529081208054600192906124159084906131cb565b90915550506001600160a01b0381166000908152601860205260409081902090516017916124429161324a565b908152604080516020928190038301902080546001600160a01b03191690556001600160a01b03831660009081526018909252812061154191612a44565b61154181336126bc565b61249482826119f3565b61140e576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556124ca3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b61251882826119f3565b1561140e576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b61257b612715565b6011805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516125b59190612c9b565b60405180910390a1565b60006125c9611ebd565b6125e55760405162461bcd60e51b815260040161094590612e12565b8251600090839081906020870134f59150813b61260157600080fd5b509392505050565b3360009081526015602052604081208054600192906126299084906131a2565b9091555050506001600160a01b0316600090815260166020526040902080546001600160a01b03191633179055565b612660612760565b6011805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586125a83390565b60006126a0836127a6565b8015610d445750610d4483836127d9565b60006108f082612862565b6126c682826119f3565b61140e576126d381612897565b6126de8360206128a9565b6040516020016126ef9291906132c0565b60408051601f198184030181529082905262461bcd60e51b825261094591600401612b14565b60115460ff1661275e5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610945565b565b60115460ff161561275e5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610945565b60006127b9826301ffc9a760e01b6127d9565b80156108f057506127d2826001600160e01b03196127d9565b1592915050565b604080516001600160e01b03198316602480830191909152825180830390910181526044909101909152602080820180516001600160e01b03166301ffc9a760e01b178152825160009392849283928392918391908a617530fa92503d9150600051905082801561284b575060208210155b80156128575750600081115b979650505050505050565b60006001600160e01b03198216637965db0b60e01b14806108f057506301ffc9a760e01b6001600160e01b03198316146108f0565b60606108f06001600160a01b03831660145b606060006128b883600261332f565b6128c39060026131a2565b6001600160401b038111156128da576128da612b51565b6040519080825280601f01601f191660200182016040528015612904576020820181803683370190505b509050600360fc1b8160008151811061291f5761291f613346565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061294e5761294e613346565b60200101906001600160f81b031916908160001a905350600061297284600261332f565b61297d9060016131a2565b90505b60018111156129f5576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106129b1576129b1613346565b1a60f81b8282815181106129c7576129c7613346565b60200101906001600160f81b031916908160001a90535060049490941c936129ee8161335c565b9050612980565b508315610d445760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610945565b508054612a5090612dd8565b6000825580601f10612a60575050565b601f01602090049060005260206000209081019061154191905b80821115612a8e5760008155600101612a7a565b5090565b6001600160a01b038116811461154157600080fd5b600060208284031215612ab957600080fd5b8135610d4481612a92565b60005b83811015612adf578181015183820152602001612ac7565b50506000910152565b60008151808452612b00816020860160208601612ac4565b601f01601f19169290920160200192915050565b602081526000610d446020830184612ae8565b600060208284031215612b3957600080fd5b81356001600160e01b031981168114610d4457600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715612b8f57612b8f612b51565b604052919050565b60006001600160401b03821115612bb057612bb0612b51565b50601f01601f191660200190565b600082601f830112612bcf57600080fd5b8135612be2612bdd82612b97565b612b67565b818152846020838601011115612bf757600080fd5b816020850160208301376000918101602001919091529392505050565b600080600060608486031215612c2957600080fd5b83356001600160401b0380821115612c4057600080fd5b612c4c87838801612bbe565b94506020860135915080821115612c6257600080fd5b612c6e87838801612bbe565b93506040860135915080821115612c8457600080fd5b50612c9186828701612bbe565b9150509250925092565b6001600160a01b0391909116815260200190565b801515811461154157600080fd5b60008060408385031215612cd057600080fd5b8235612cdb81612a92565b91506020830135612ceb81612caf565b809150509250929050565b600060208284031215612d0857600080fd5b81356001600160401b03811115612d1e57600080fd5b611eb584828501612bbe565b600060208284031215612d3c57600080fd5b5035919050565b60008060408385031215612d5657600080fd5b823591506020830135612ceb81612a92565b60008060408385031215612d7b57600080fd5b82356001600160401b03811115612d9157600080fd5b612d9d85828601612bbe565b95602094909401359450505050565b60008060408385031215612dbf57600080fd5b8235612dca81612a92565b946020939093013593505050565b600181811c90821680612dec57607f821691505b602082108103612e0c57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600f908201526e139bdd081bdc195c985d1a5bdb985b608a1b604082015260600190565b60008251612e4d818460208701612ac4565b9190910192915050565b6000612e65612bdd84612b97565b9050828152838383011115612e7957600080fd5b610d44836020830184612ac4565b600060208284031215612e9957600080fd5b81516001600160401b03811115612eaf57600080fd5b8201601f81018413612ec057600080fd5b611eb584825160208401612e57565b601f8211156111e957600081815260208120601f850160051c81016020861015612ef65750805b601f850160051c820191505b81811015612f1557828155600101612f02565b505050505050565b81516001600160401b03811115612f3657612f36612b51565b612f4a81612f448454612dd8565b84612ecf565b602080601f831160018114612f7f5760008415612f675750858301515b600019600386901b1c1916600185901b178555612f15565b600085815260208120601f198616915b82811015612fae57888601518255948401946001909101908401612f8f565b5085821015612fcc5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215612fee57600080fd5b5051919050565b6040815260006130086040830185612ae8565b905060018060a01b03831660208301529392505050565b6020808252601a9082015279417574686f72697a6564204d61696e7461696e6572206f6e6c7960301b604082015260600190565b602080825260129082015271139bc818da185b99d9481c995c5d5a5c995960721b604082015260600190565b6001600160a01b0393841681529115156020830152909116604082015260600190565b6001600160a01b03841681526060602082018190526000906130c690830185612ae8565b82810360408401526130d88185612ae8565b9695505050505050565b6040815260006130f56040830185612ae8565b90508260208301529392505050565b60006020828403121561311657600080fd5b8151610d4481612caf565b600082601f83011261313257600080fd5b610d4483835160208501612e57565b60006020828403121561315357600080fd5b81516001600160401b0381111561316957600080fd5b611eb584828501613121565b9182526001600160a01b0316602082015260400190565b634e487b7160e01b600052601160045260246000fd5b808201808211156108f0576108f061318c565b9283526020830191909152604082015260600190565b818103818111156108f0576108f061318c565b6000806000606084860312156131f357600080fd5b83516131fe81612a92565b60208501519093506001600160401b038082111561321b57600080fd5b61322787838801613121565b9350604086015191508082111561323d57600080fd5b50612c9186828701613121565b600080835461325881612dd8565b600182811680156132705760018114613285576132b4565b60ff19841687528215158302870194506132b4565b8760005260208060002060005b858110156132ab5781548a820152908401908201613292565b50505082870194505b50929695505050505050565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b8152600083516132f2816017850160208801612ac4565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351613323816028840160208801612ac4565b01602801949350505050565b80820281158282048414176108f0576108f061318c565b634e487b7160e01b600052603260045260246000fd5b60008161336b5761336b61318c565b50600019019056fea4c23fbdf7b47e131467038825c29083fa0078286002513daa4fb6f766a56ca7fc425f2263d0df187444b70e47283d622c70181c5baebb1306a01edba1ce184cd681debd67bb43cf0724f56740458b31cf33fcb137367bf4dbd7e431088fe9b965d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862aedcc084d3dcd65a1f7f23c65c46722faca6953d28e43150a467cf43e5c309238a2646970667358221220547400ff5095ccebc670c9e42e6caf8e64bcc952bd62e9cf1d4e150afb05ac8b64736f6c63430008120033000000000000000000000000bfb532a5700dd799ab59672e9eb26364a14298c8
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061029c5760003560e01c8061a976146102a157806301ffc9a7146102ca5780630b132815146102ed5780630ddafcb71461030d5780630f786eb41461032257806319c0e22a146103355780631cb7fa91146103485780631f21cc911461035b578063216470c81461036e578063248a9ca31461038157806329fe274f146103a25780632b936087146103d05780632ec2c246146103f95780632f2ff15d1461040c5780633089b0161461041f57806330fc362f1461043f578063357543f71461045257806336568abe14610465578063381780d314610478578063388d9a0b1461048b57806339676bce1461049e5780633dda4a6c146104be5780633f4ba83a146104d1578063416dc732146104d957806341d078f91461050257806344d01fd11461051557806348aac3921461052a5780634c96a3891461053d57806354fd4d50146105505780635c975abb146105745780638456cb591461057f5780638710b0b7146105875780638e4cc935146105aa57806391d14854146105ca5780639ad1ee10146105dd5780639d7cd25b146105f0578063a217fddf14610619578063a36c898514610621578063b24bc00214610634578063b8a56eb214610647578063bc3ef3c01461065a578063bcabbffb1461066d578063c782b2fb1461068d578063cd905dff146106a0578063d012a1d4146106a8578063d1419762146106dc578063d547741f146106ef578063d6c8401714610702578063e0926c8c14610736578063e63ab1e91461075f578063e81cf77d14610774578063e8baf9af14610787578063ea0cd9a0146107a7578063ecd00261146107ba578063ef70768a146107cf578063f0e35016146107e2578063f68e9553146107f5578063f87422541461080a575b600080fd5b6102b46102af366004612aa7565b610831565b6040516102c19190612b14565b60405180910390f35b6102dd6102d8366004612b27565b6108cb565b60405190151581526020016102c1565b6103006102fb366004612c14565b6108f6565b6040516102c19190612c9b565b61032061031b366004612cbd565b610d4b565b005b6102b4610330366004612aa7565b610e16565b6102dd610343366004612cf6565b610e2f565b6102b4610356366004612aa7565b610e6c565b601954610300906001600160a01b031681565b6102b461037c366004612d2a565b610f18565b61039461038f366004612d2a565b610f31565b6040519081526020016102c1565b6102dd6103b0366004612aa7565b6001600160a01b0390811660009081526016602052604090205416151590565b6103006103de366004612d2a565b6005602052600090815260409020546001600160a01b031681565b610320610407366004612aa7565b610f46565b61032061041a366004612d43565b6111cd565b61039461042d366004612aa7565b60126020526000908152604090205481565b61032061044d366004612c14565b6111ee565b6102dd610460366004612aa7565b611362565b610320610473366004612d43565b611394565b6102dd610486366004612aa7565b611412565b610320610499366004612cbd565b61143d565b6103946104ac366004612aa7565b60046020526000908152604090205481565b6102b46104cc366004612aa7565b611508565b610320611521565b6103006104e7366004612aa7565b6016602052600090815260409020546001600160a01b031681565b6102dd610510366004612aa7565b611544565b61039460008051602061337483398151915281565b610300610538366004612d68565b61155e565b61030061054b366004612aa7565b6115b5565b6102b460405180604001604052806005815260200164181719971960d91b81525081565b60115460ff166102dd565b6103206119d3565b6102dd610595366004612aa7565b600c6020526000908152604090205460ff1681565b6103946105b8366004612aa7565b60136020526000908152604090205481565b6102dd6105d8366004612d43565b6119f3565b6103006105eb366004612d2a565b611a90565b6103006105fe366004612aa7565b6006602052600090815260409020546001600160a01b031681565b610394600081565b61032061062f366004612aa7565b611aba565b610320610642366004612cbd565b611c6b565b610320610655366004612dac565b611d36565b610320610668366004612d2a565b611de6565b61039461067b366004612aa7565b60146020526000908152604090205481565b61039461069b366004612aa7565b611e75565b6102dd611ebd565b6103006106b6366004612cf6565b80516020818301810180516017825292820191909301209152546001600160a01b031681565b6103206106ea366004612cf6565b611ed1565b6103206106fd366004612d43565b611fd9565b610300610710366004612cf6565b80516020818301810180516008825292820191909301209152546001600160a01b031681565b610300610744366004612aa7565b6003602052600090815260409020546001600160a01b031681565b6103946000805160206133d483398151915281565b600a54610300906001600160a01b031681565b610394610795366004612aa7565b60156020526000908152604090205481565b6103946107b5366004612aa7565b611ff5565b61039460008051602061339483398151915281565b6103206107dd366004612aa7565b61202b565b6103206107f0366004612dac565b612199565b6103946000805160206133f483398151915281565b6103947f339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab9581565b6002602052600090815260409020805461084a90612dd8565b80601f016020809104026020016040519081016040528092919081815260200182805461087690612dd8565b80156108c35780601f10610898576101008083540402835291602001916108c3565b820191906000526020600020905b8154815290600101906020018083116108a657829003601f168201915b505050505081565b60006001600160e01b03198216631b6ff5ef60e11b14806108f057506108f08261223c565b92915050565b600061090133611362565b61094e5760405162461bcd60e51b8152602060048201526019602482015278417574686f72697a656420526567697374726172206f6e6c7960381b60448201526064015b60405180910390fd5b610956611ebd565b6109725760405162461bcd60e51b815260040161094590612e12565b60006008856040516109849190612e3b565b908152604051908190036020019020546001600160a01b03169050806109e05760405162461bcd60e51b8152602060048201526011602482015270139bc81c1c9bdd9a59195c88199bdd5b99607a1b6044820152606401610945565b6040516311d9814560e11b81528190610a5f906001600160a01b038316906323b3028a90610a12908990600401612b14565b600060405180830381865afa158015610a2f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a579190810190612e87565b60105461155e565b6001600160a01b038082166000908152600360205260409020549194501615610ac85760405162461bcd60e51b815260206004820152601b60248201527a10dbdb9d1c9858dd08185b1c9958591e481c9959da5cdd195c9959602a1b6044820152606401610945565b6001600160a01b0383811660009081526006602090815260408083208054336001600160a01b03199182161790915560039092529091208054909116918416919091179055610b1983878787612261565b6001600160a01b0383166000908152600260205260409020610b3b8682612f1d565b506040516311d9814560e11b81526000906001600160a01b038316906323b3028a90610b6b908990600401612b14565b600060405180830381865afa158015610b88573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bb09190810190612e87565b90506000826001600160a01b031663323e1e3b836040518263ffffffff1660e01b8152600401610be09190612b14565b602060405180830381865afa158015610bfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c219190612fdc565b6000818152600560205260409020549091506001600160a01b031615610c975760405162461bcd60e51b815260206004820152602560248201527f4964656e746963616c2062797465636f646520616c72656164792072656769736044820152641d195c995960da1b6064820152608401610945565b6001600160a01b03851660008181526004602090815260408083208590558483526005825280832080546001600160a01b031916851790559282526007905220610ce18782612f1d565b506001600160a01b0385166000818152600c602052604090819020805460ff19166001179055517f22889bf4107add8fa7be4d783201d8c9234cbf7d10a519d47fa9070a0b92ad5b90610d37908b903390612ff5565b60405180910390a2505050505b9392505050565b610d5433611544565b610d705760405162461bcd60e51b81526004016109459061301f565b6001600160a01b0382166000908152600d602052604090205481151560ff909116151503610db05760405162461bcd60e51b815260040161094590613053565b7fa79756a62eeadcf4edcdd62ec59d188985cb9e5a26b48d9bedd37244438d55ab828233604051610de39392919061307f565b60405180910390a16001600160a01b03919091166000908152600d60205260409020805460ff1916911515919091179055565b6007602052600090815260409020805461084a90612dd8565b6000806001600160a01b0316600883604051610e4b9190612e3b565b908152604051908190036020019020546001600160a01b0316141592915050565b6001600160a01b0381166000908152600760205260409020805460609190610e9390612dd8565b80601f0160208091040260200160405190810160405280929190818152602001828054610ebf90612dd8565b8015610f0c5780601f10610ee157610100808354040283529160200191610f0c565b820191906000526020600020905b815481529060010190602001808311610eef57829003601f168201915b50505050509050919050565b6009602052600090815260409020805461084a90612dd8565b60009081526020819052604090206001015490565b610f4f33611544565b80610f5e5750610f5e33611362565b610fbd5760405162461bcd60e51b815260206004820152602a60248201527f6d73672e73656e646572206d757374206265206d61696e7461696e6572206f72604482015269103932b3b4b9ba3930b960b11b6064820152608401610945565b6001600160a01b0381166000908152600c602052604090205460ff166110495760405162461bcd60e51b815260206004820152603b60248201527f4f6e6c7920726567697374657265642c206e6f742d6465706c6f79656420636f60448201527a1b9d1c9858dd1cc818d85b881899481d5b9c9959da5cdd195c9959602a1b6064820152608401610945565b61105233611544565b6110d4576001600160a01b038181166000908152600660205260409020541633146110d45760405162461bcd60e51b815260206004820152602c60248201527f43616e206f6e6c7920756e7265676973746572206f776e20726567697374657260448201526b656420636f6e74726163747360a01b6064820152608401610945565b6110dd816123db565b6001600160a01b0381166000818152600460209081526040808320805484526005835281842080546001600160a01b0319169055938352928290556002905290812061112891612a44565b6001600160a01b038116600090815260076020526040812061114991612a44565b6001600160a01b0381166000818152600c60209081526040808320805460ff191690556006825280832080546001600160a01b031990811690915560039092529182902080549091169055517f6c0b8518b86a3f2aab1a16148ee99e9cce485dfb40b2c510326a696b577a6f43906111c2903390612c9b565b60405180910390a250565b6111d682610f31565b6111df81612480565b6111e9838361248a565b505050565b6111f781610e2f565b6112435760405162461bcd60e51b815260206004820152601f60248201527f5265717565737465642076657273696f6e206e6f7420737570706f72746564006044820152606401610945565b60006008826040516112559190612e3b565b90815260405190819003602001812054600a546305cd5a2160e51b83526001600160a01b039182169350600092849263b9ab44209261129d92911690899089906004016130a2565b600060405180830381865afa1580156112ba573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112e29190810190612e87565b90506000826001600160a01b031663de191a9f6040518163ffffffff1660e01b8152600401600060405180830381865afa158015611324573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261134c9190810190612e87565b90506113598483836108f6565b50505050505050565b600061137c6000805160206133f4833981519152836119f3565b806108f05750600061138d83611ff5565b1192915050565b6001600160a01b03811633146114045760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610945565b61140e828261250e565b5050565b600061142c600080516020613394833981519152836119f3565b806108f05750600061138d83611e75565b61144633611544565b6114625760405162461bcd60e51b81526004016109459061301f565b6001600160a01b0382166000908152600f602052604090205481151560ff9091161515036114a25760405162461bcd60e51b815260040161094590613053565b7f4dcb632405a82ed0b4860fb7768a7994956842dac6dd03ca0c0ca9b623ecce8b8282336040516114d59392919061307f565b60405180910390a16001600160a01b03919091166000908152600f60205260409020805460ff1916911515919091179055565b6018602052600090815260409020805461084a90612dd8565b6000805160206133d483398151915261153981612480565b611541612573565b50565b60006108f0600080516020613374833981519152836119f3565b8151602092830120604080516001600160f81b0319818601523060601b6001600160601b03191660218201526035810193909352605580840192909252805180840390920182526075909201909152805191012090565b60006115c033611412565b6116075760405162461bcd60e51b8152602060048201526018602482015277417574686f72697a6564204465706c6f796572206f6e6c7960401b6044820152606401610945565b6001600160a01b0380831660009081526003602090815260408083205460029092528220805491909316929061163c90612dd8565b80601f016020809104026020016040519081016040528092919081815260200182805461166890612dd8565b80156116b55780601f1061168a576101008083540402835291602001916116b5565b820191906000526020600020905b81548152906001019060200180831161169857829003601f168201915b505050505090506000826001600160a01b03166323b3028a836040518263ffffffff1660e01b81526004016116ea9190612b14565b600060405180830381865afa158015611707573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261172f9190810190612e87565b6001600160a01b03868116600090815260046020819052604091829020549151634fa48f7760e11b815293945091861692639f491eee926117749286929091016130e2565b602060405180830381865afa158015611791573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b59190613104565b6118195760405162461bcd60e51b815260206004820152602f60248201527f42797465636f646520766572696669636174696f6e206661696c65642c20766560448201526e7273696f6e206d69736d617463683f60881b6064820152608401610945565b6000611827826010546125bf565b9050856001600160a01b0316816001600160a01b03161461189a5760405162461bcd60e51b815260206004820152602760248201527f50726564696374656420616e64206465706c6f7965642061646472657373206d6044820152660d2e6dac2e8c6d60cb1b6064820152608401610945565b6001600160a01b038087166000908152600c6020526040808220805460ff1916905580516303639b8b60e21b8152905184938416927f0b9cb2adc2bb771fa4d112f6792bf5b3f1900f97283c8b3d99ffc518ac678e64928492630d8e6e2c926004808401939192918290030181865afa15801561191b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119439190810190613141565b33604051611952929190612ff5565b60405180910390a26119c982826001600160a01b0316630d8e6e2c6040518163ffffffff1660e01b8152600401600060405180830381865afa15801561199c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119c49190810190613141565b612609565b5095945050505050565b6000805160206133d48339815191526119eb81612480565b611541612658565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1680610d445750600154604051632474521560e21b81526001600160a01b03909116906391d1485490611a4f9086908690600401613175565b602060405180830381865afa158015611a6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d449190613104565b600b8181548110611aa057600080fd5b6000918252602090912001546001600160a01b0316905081565b6000611ac581612480565b600180546001600160a01b038481166001600160a01b031983161790925516611af583631b6ff5ef60e11b612695565b611b515760405162461bcd60e51b815260206004820152602760248201527f417070487562206d75737420696d706c656d656e7420494465706c6f796564436044820152661bdb9d1c9858dd60ca1b6064820152608401610945565b600154604051632474521560e21b81526001600160a01b03909116906391d1485490611b84906000903390600401613175565b602060405180830381865afa158015611ba1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bc59190613104565b611c1d5760405162461bcd60e51b815260206004820152602360248201527f4163636f756e7420686173206e6f2061646d696e20726f6c6520696e20417070604482015262243ab160e91b6064820152608401610945565b604080516001600160a01b03858116825283166020820152338183015290517fddc2af4c556b986b670e1d76c36d780afac8f87b3b40d118b0661a8d1e9274429181900360600190a1505050565b611c7433611544565b611c905760405162461bcd60e51b81526004016109459061301f565b6001600160a01b0382166000908152600e602052604090205481151560ff909116151503611cd05760405162461bcd60e51b815260040161094590613053565b7f4c7955e1033c3625c926adda75a0b51e45d84d775de8d189e2530443c826b813828233604051611d039392919061307f565b60405180910390a16001600160a01b03919091166000908152600e60205260409020805460ff1916911515919091179055565b600080516020613374833981519152611d4e81612480565b6001600160a01b03831660009081526012602052604081208054849290611d769084906131a2565b90915550506001600160a01b0383167f2ee86f542eb033d23dcac069078af9cbee0b275677e96fe3201238e25f9599a983611db086611ff5565b6001600160a01b03871660009081526012602052604090819020549051611dd9939291906131b5565b60405180910390a2505050565b611def33611544565b611e0b5760405162461bcd60e51b81526004016109459061301f565b611e13611ebd565b611e2f5760405162461bcd60e51b815260040161094590612e12565b60105460408051918252602082018390523382820152517fe36534ece9f01369394e4f79bb091d49758b24bb6e6e7b75898659314de34f7b9181900360600190a1601055565b6001600160a01b038116600090815260136020908152604080832054601590925282205481811115611eab575060009392505050565b611eb581836131cb565b949350505050565b6000611ecb60115460ff1690565b15905090565b611eda33611544565b611ef65760405162461bcd60e51b81526004016109459061301f565b6000600882604051611f089190612e3b565b908152604051908190036020019020546001600160a01b0316905080611f625760405162461bcd60e51b815260206004820152600f60248201526e2b32b939b4b7b7103ab735b737bbb760891b6044820152606401610945565b81604051611f709190612e3b565b604051809103902060006001600160a01b03166000805160206133b483398151915233604051611fa09190612c9b565b60405180910390a3600882604051611fb89190612e3b565b90815260405190819003602001902080546001600160a01b03191690555050565b611fe282610f31565b611feb81612480565b6111e9838361250e565b6001600160a01b038116600090815260126020908152604080832054601490925282205481811115611eab575060009392505050565b61203433611544565b6120505760405162461bcd60e51b81526004016109459061301f565b60008190506000816001600160a01b0316630d8e6e2c6040518163ffffffff1660e01b8152600401600060405180830381865afa158015612095573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120bd9190810190613141565b9050826001600160a01b03166008826040516120d99190612e3b565b908152604051908190036020019020546001600160a01b03160361210f5760405162461bcd60e51b815260040161094590613053565b8060405161211d9190612e3b565b6040518091039020836001600160a01b03166000805160206133b48339815191523360405161214c9190612c9b565b60405180910390a3826008826040516121659190612e3b565b90815260405190819003602001902080546001600160a01b03929092166001600160a01b0319909216919091179055505050565b6000805160206133748339815191526121b181612480565b6001600160a01b038316600090815260136020526040812080548492906121d99084906131a2565b90915550506001600160a01b0383167f99b7cb3383f0fd6fbc3b0995d35746310b052d8b955655d2e6da6185928fd7c58361221386611e75565b6001600160a01b03871660009081526013602052604090819020549051611dd9939291906131b5565b60006001600160e01b03198216631cb7fa9160e01b14806108f057506108f0826126b1565b6000808380602001905181019061227891906131de565b925050915060006001600160a01b03166017826040516122989190612e3b565b908152604051908190036020019020546001600160a01b0316146122f55760405162461bcd60e51b815260206004820152601460248201527329bcb6b137b61030b63932b0b23c903a30b5b2b760611b6044820152606401610945565b600a546001600160a01b0383811691161461234b5760405162461bcd60e51b8152602060048201526016602482015275082e0e090eac482c8c8e4cae6e640dad2e6dac2e8c6d60531b6044820152606401610945565b33600090815260146020526040812080546001929061236b9084906131a2565b90915550506001600160a01b03861660009081526018602052604090206123928282612f1d565b50856017826040516123a49190612e3b565b90815260405190819003602001902080546001600160a01b03929092166001600160a01b0319909216919091179055505050505050565b6001600160a01b038082166000908152600660209081526040808320549093168252601490529081208054600192906124159084906131cb565b90915550506001600160a01b0381166000908152601860205260409081902090516017916124429161324a565b908152604080516020928190038301902080546001600160a01b03191690556001600160a01b03831660009081526018909252812061154191612a44565b61154181336126bc565b61249482826119f3565b61140e576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556124ca3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b61251882826119f3565b1561140e576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b61257b612715565b6011805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516125b59190612c9b565b60405180910390a1565b60006125c9611ebd565b6125e55760405162461bcd60e51b815260040161094590612e12565b8251600090839081906020870134f59150813b61260157600080fd5b509392505050565b3360009081526015602052604081208054600192906126299084906131a2565b9091555050506001600160a01b0316600090815260166020526040902080546001600160a01b03191633179055565b612660612760565b6011805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586125a83390565b60006126a0836127a6565b8015610d445750610d4483836127d9565b60006108f082612862565b6126c682826119f3565b61140e576126d381612897565b6126de8360206128a9565b6040516020016126ef9291906132c0565b60408051601f198184030181529082905262461bcd60e51b825261094591600401612b14565b60115460ff1661275e5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610945565b565b60115460ff161561275e5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610945565b60006127b9826301ffc9a760e01b6127d9565b80156108f057506127d2826001600160e01b03196127d9565b1592915050565b604080516001600160e01b03198316602480830191909152825180830390910181526044909101909152602080820180516001600160e01b03166301ffc9a760e01b178152825160009392849283928392918391908a617530fa92503d9150600051905082801561284b575060208210155b80156128575750600081115b979650505050505050565b60006001600160e01b03198216637965db0b60e01b14806108f057506301ffc9a760e01b6001600160e01b03198316146108f0565b60606108f06001600160a01b03831660145b606060006128b883600261332f565b6128c39060026131a2565b6001600160401b038111156128da576128da612b51565b6040519080825280601f01601f191660200182016040528015612904576020820181803683370190505b509050600360fc1b8160008151811061291f5761291f613346565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061294e5761294e613346565b60200101906001600160f81b031916908160001a905350600061297284600261332f565b61297d9060016131a2565b90505b60018111156129f5576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106129b1576129b1613346565b1a60f81b8282815181106129c7576129c7613346565b60200101906001600160f81b031916908160001a90535060049490941c936129ee8161335c565b9050612980565b508315610d445760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610945565b508054612a5090612dd8565b6000825580601f10612a60575050565b601f01602090049060005260206000209081019061154191905b80821115612a8e5760008155600101612a7a565b5090565b6001600160a01b038116811461154157600080fd5b600060208284031215612ab957600080fd5b8135610d4481612a92565b60005b83811015612adf578181015183820152602001612ac7565b50506000910152565b60008151808452612b00816020860160208601612ac4565b601f01601f19169290920160200192915050565b602081526000610d446020830184612ae8565b600060208284031215612b3957600080fd5b81356001600160e01b031981168114610d4457600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715612b8f57612b8f612b51565b604052919050565b60006001600160401b03821115612bb057612bb0612b51565b50601f01601f191660200190565b600082601f830112612bcf57600080fd5b8135612be2612bdd82612b97565b612b67565b818152846020838601011115612bf757600080fd5b816020850160208301376000918101602001919091529392505050565b600080600060608486031215612c2957600080fd5b83356001600160401b0380821115612c4057600080fd5b612c4c87838801612bbe565b94506020860135915080821115612c6257600080fd5b612c6e87838801612bbe565b93506040860135915080821115612c8457600080fd5b50612c9186828701612bbe565b9150509250925092565b6001600160a01b0391909116815260200190565b801515811461154157600080fd5b60008060408385031215612cd057600080fd5b8235612cdb81612a92565b91506020830135612ceb81612caf565b809150509250929050565b600060208284031215612d0857600080fd5b81356001600160401b03811115612d1e57600080fd5b611eb584828501612bbe565b600060208284031215612d3c57600080fd5b5035919050565b60008060408385031215612d5657600080fd5b823591506020830135612ceb81612a92565b60008060408385031215612d7b57600080fd5b82356001600160401b03811115612d9157600080fd5b612d9d85828601612bbe565b95602094909401359450505050565b60008060408385031215612dbf57600080fd5b8235612dca81612a92565b946020939093013593505050565b600181811c90821680612dec57607f821691505b602082108103612e0c57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600f908201526e139bdd081bdc195c985d1a5bdb985b608a1b604082015260600190565b60008251612e4d818460208701612ac4565b9190910192915050565b6000612e65612bdd84612b97565b9050828152838383011115612e7957600080fd5b610d44836020830184612ac4565b600060208284031215612e9957600080fd5b81516001600160401b03811115612eaf57600080fd5b8201601f81018413612ec057600080fd5b611eb584825160208401612e57565b601f8211156111e957600081815260208120601f850160051c81016020861015612ef65750805b601f850160051c820191505b81811015612f1557828155600101612f02565b505050505050565b81516001600160401b03811115612f3657612f36612b51565b612f4a81612f448454612dd8565b84612ecf565b602080601f831160018114612f7f5760008415612f675750858301515b600019600386901b1c1916600185901b178555612f15565b600085815260208120601f198616915b82811015612fae57888601518255948401946001909101908401612f8f565b5085821015612fcc5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215612fee57600080fd5b5051919050565b6040815260006130086040830185612ae8565b905060018060a01b03831660208301529392505050565b6020808252601a9082015279417574686f72697a6564204d61696e7461696e6572206f6e6c7960301b604082015260600190565b602080825260129082015271139bc818da185b99d9481c995c5d5a5c995960721b604082015260600190565b6001600160a01b0393841681529115156020830152909116604082015260600190565b6001600160a01b03841681526060602082018190526000906130c690830185612ae8565b82810360408401526130d88185612ae8565b9695505050505050565b6040815260006130f56040830185612ae8565b90508260208301529392505050565b60006020828403121561311657600080fd5b8151610d4481612caf565b600082601f83011261313257600080fd5b610d4483835160208501612e57565b60006020828403121561315357600080fd5b81516001600160401b0381111561316957600080fd5b611eb584828501613121565b9182526001600160a01b0316602082015260400190565b634e487b7160e01b600052601160045260246000fd5b808201808211156108f0576108f061318c565b9283526020830191909152604082015260600190565b818103818111156108f0576108f061318c565b6000806000606084860312156131f357600080fd5b83516131fe81612a92565b60208501519093506001600160401b038082111561321b57600080fd5b61322787838801613121565b9350604086015191508082111561323d57600080fd5b50612c9186828701613121565b600080835461325881612dd8565b600182811680156132705760018114613285576132b4565b60ff19841687528215158302870194506132b4565b8760005260208060002060005b858110156132ab5781548a820152908401908201613292565b50505082870194505b50929695505050505050565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b8152600083516132f2816017850160208801612ac4565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351613323816028840160208801612ac4565b01602801949350505050565b80820281158282048414176108f0576108f061318c565b634e487b7160e01b600052603260045260246000fd5b60008161336b5761336b61318c565b50600019019056fea4c23fbdf7b47e131467038825c29083fa0078286002513daa4fb6f766a56ca7fc425f2263d0df187444b70e47283d622c70181c5baebb1306a01edba1ce184cd681debd67bb43cf0724f56740458b31cf33fcb137367bf4dbd7e431088fe9b965d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862aedcc084d3dcd65a1f7f23c65c46722faca6953d28e43150a467cf43e5c309238a2646970667358221220547400ff5095ccebc670c9e42e6caf8e64bcc952bd62e9cf1d4e150afb05ac8b64736f6c63430008120033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000bfb532a5700dd799ab59672e9eb26364a14298c8
-----Decoded View---------------
Arg [0] : _hub (address): 0xbfB532A5700dD799ab59672e9EB26364a14298c8
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000bfb532a5700dd799ab59672e9eb26364a14298c8
Deployed Bytecode Sourcemap
193742:10808:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;159656:53;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;203440:246;;;;;;:::i;:::-;;:::i;:::-;;;1610:14:1;;1603:22;1585:41;;1573:2;1558:18;203440:246:0;1445:187:1;166400:1494:0;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;174536:271::-;;;;;;:::i;:::-;;:::i;:::-;;159985:51;;;;;;:::i;:::-;;:::i;171463:142::-;;;;;;:::i;:::-;;:::i;171836:141::-;;;;;;:::i;:::-;;:::i;197150:25::-;;;;;-1:-1:-1;;;;;197150:25:0;;;160102:55;;;;;;:::i;:::-;;:::i;26084:131::-;;;;;;:::i;:::-;;:::i;:::-;;;5056:25:1;;;5044:2;5029:18;26084:131:0;4910:177:1;197405:134:0;;;;;;:::i;:::-;-1:-1:-1;;;;;197501:16:0;;;197461:20;197501:16;;;:10;:16;;;;;;;:30;;;197405:134;159859:57;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;159859:57:0;;;164545:851;;;;;;:::i;:::-;;:::i;26525:147::-;;;;;;:::i;:::-;;:::i;196072:53::-;;;;;;:::i;:::-;;;;;;;;;;;;;;202880:500;;;;;;:::i;:::-;;:::i;198125:169::-;;;;;;:::i;:::-;;:::i;27669:218::-;;;;;;:::i;:::-;;:::i;198464:165::-;;;;;;:::i;:::-;;:::i;174153:275::-;;;;;;:::i;:::-;;:::i;159804:48::-;;;;;;:::i;:::-;;;;;;;;;;;;;;196987:51;;;;;;:::i;:::-;;:::i;204067:77::-;;;:::i;196705:46::-;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;196705:46:0;;;197807:146;;;;;;:::i;:::-;;:::i;195428:86::-;;-1:-1:-1;;;;;;;;;;;195428:86:0;;160921:406;;;;;;:::i;:::-;;:::i;169049:1014::-;;;;;;:::i;:::-;;:::i;195900:40::-;;;;;;;;;;;;;;;-1:-1:-1;;;195900:40:0;;;;;34315:86;34386:7;;;;34315:86;;203919:73;;;:::i;160431:51::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;196252;;;;;;:::i;:::-;;;;;;;;;;;;;;96085:190;;;;;;:::i;:::-;;:::i;160288:34::-;;;;;;:::i;:::-;;:::i;159923:55::-;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;159923:55:0;;;23662:49;;23707:4;23662:49;;96378:507;;;;;;:::i;:::-;;:::i;174917:279::-;;;;;;:::i;:::-;;:::i;200350:301::-;;;;;;:::i;:::-;;:::i;163219:199::-;;;;;;:::i;:::-;;:::i;196400:58::-;;;;;;:::i;:::-;;;;;;;;;;;;;;201266:294;;;;;;:::i;:::-;;:::i;204224:118::-;;;:::i;196849:51::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;196849:51:0;;;170998:302;;;;;;:::i;:::-;;:::i;26965:149::-;;;;;;:::i;:::-;;:::i;160043:52::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;160043:52:0;;;159716:54;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;159716:54:0;;;195578:62;;-1:-1:-1;;;;;;;;;;;195578:62:0;;160164:28;;;;;-1:-1:-1;;;;;160164:28:0;;;196553:56;;;;;;:::i;:::-;;;;;;;;;;;;;;201768:304;;;;;;:::i;:::-;;:::i;195023:66::-;;-1:-1:-1;;;;;;;;;;;195023:66:0;;170483:404;;;;;;:::i;:::-;;:::i;200779:277::-;;;;;;:::i;:::-;;:::i;195764:68::-;;-1:-1:-1;;;;;;;;;;;195764:68:0;;195273:70;;195315:28;195273:70;;159656:53;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;203440:246::-;203551:4;-1:-1:-1;;;;;;203575:50:0;;-1:-1:-1;;;203575:50:0;;:103;;;203642:36;203666:11;203642:23;:36::i;:::-;203568:110;203440:246;-1:-1:-1;;203440:246:0:o;166400:1494::-;166547:25;173286:33;173308:10;173286:21;:33::i;:::-;173278:71;;;;-1:-1:-1;;;173278:71:0;;7828:2:1;173278:71:0;;;7810:21:1;7867:2;7847:18;;;7840:30;-1:-1:-1;;;7886:18:1;;;7879:55;7951:18;;173278:71:0;;;;;;;;;175253:15:::1;:13;:15::i;:::-;175245:43;;;;-1:-1:-1::0;;;175245:43:0::1;;;;;;;:::i;:::-;166589:17:::2;166609;166627:15;166609:34;;;;;;:::i;:::-;::::0;;;::::2;::::0;;;;;::::2;::::0;;;;-1:-1:-1;;;;;166609:34:0::2;::::0;-1:-1:-1;166609:34:0;166656:53:::2;;;::::0;-1:-1:-1;;;166656:53:0;;8820:2:1;166656:53:0::2;::::0;::::2;8802:21:1::0;8859:2;8839:18;;;8832:30;-1:-1:-1;;;8878:18:1;;;8871:47;8935:18;;166656:53:0::2;8618:341:1::0;166656:53:0::2;166802:25;::::0;-1:-1:-1;;;166802:25:0;;166750:9;;166791:50:::2;::::0;-1:-1:-1;;;;;166802:13:0;::::2;::::0;::::2;::::0;:25:::2;::::0;166816:10;;166802:25:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;::::0;;::::2;-1:-1:-1::0;;166802:25:0::2;::::0;::::2;;::::0;::::2;::::0;;;::::2;::::0;::::2;:::i;:::-;166829:11;;166791:10;:50::i;:::-;-1:-1:-1::0;;;;;166862:37:0;;::::2;166911:1;166862:37:::0;;;:18:::2;:37;::::0;;;;;166771:70;;-1:-1:-1;166862:37:0::2;:51:::0;166854:91:::2;;;::::0;-1:-1:-1;;;166854:91:0;;9954:2:1;166854:91:0::2;::::0;::::2;9936:21:1::0;9993:2;9973:18;;;9966:30;-1:-1:-1;;;10012:18:1;;;10005:57;10079:18;;166854:91:0::2;9752:351:1::0;166854:91:0::2;-1:-1:-1::0;;;;;166956:38:0;;::::2;;::::0;;;:19:::2;:38;::::0;;;;;;;:51;;166997:10:::2;-1:-1:-1::0;;;;;;166956:51:0;;::::2;;::::0;;;167020:18:::2;:37:::0;;;;;;:49;;;;::::2;::::0;;::::2;::::0;;;::::2;::::0;;167082:73:::2;166956:38:::0;167117:15;167134:10;167146:8;167082:15:::2;:73::i;:::-;-1:-1:-1::0;;;;;167168:38:0;::::2;;::::0;;;:19:::2;:38;::::0;;;;:51:::2;167209:10:::0;167168:38;:51:::2;:::i;:::-;-1:-1:-1::0;167267:25:0::2;::::0;-1:-1:-1;;;167267:25:0;;167230:34:::2;::::0;-1:-1:-1;;;;;167267:13:0;::::2;::::0;::::2;::::0;:25:::2;::::0;167281:10;;167267:25:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;::::0;;::::2;-1:-1:-1::0;;167267:25:0::2;::::0;::::2;;::::0;::::2;::::0;;;::::2;::::0;::::2;:::i;:::-;167230:62;;167304:14;167321:1;-1:-1:-1::0;;;;;167321:17:0::2;;167339:21;167321:40;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;167423:1;167382:29:::0;;;:21:::2;:29;::::0;;;;;167304:57;;-1:-1:-1;;;;;;167382:29:0::2;:43:::0;167374:93:::2;;;::::0;-1:-1:-1;;;167374:93:0;;12697:2:1;167374:93:0::2;::::0;::::2;12679:21:1::0;12736:2;12716:18;;;12709:30;12775:34;12755:18;;;12748:62;-1:-1:-1;;;12826:18:1;;;12819:35;12871:19;;167374:93:0::2;12495:401:1::0;167374:93:0::2;-1:-1:-1::0;;;;;167480:31:0;::::2;;::::0;;;:12:::2;:31;::::0;;;;;;;:40;;;167531:29;;;:21:::2;:29:::0;;;;;:49;;-1:-1:-1;;;;;;167531:49:0::2;::::0;::::2;::::0;;167593:36;;;:17:::2;:36:::0;;;:47:::2;167632:8:::0;167593:36;:47:::2;:::i;:::-;-1:-1:-1::0;;;;;;167653:37:0;::::2;;::::0;;;:18:::2;:37;::::0;;;;;;:44;;-1:-1:-1;;167653:44:0::2;167693:4;167653:44;::::0;;167721:66;::::2;::::0;::::2;::::0;167759:15;;167776:10:::2;::::0;167721:66:::2;:::i;:::-;;;;;;;;167862:24;;;;175299:1;166400:1494:::0;;;;;:::o;174536:271::-;173555:34;173578:10;173555:22;:34::i;:::-;173547:73;;;;-1:-1:-1;;;173547:73:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;174640:28:0;::::1;;::::0;;;:19:::1;:28;::::0;;;;;:35;::::1;;:28;::::0;;::::1;:35;;::::0;174632:66:::1;;;;-1:-1:-1::0;;;174632:66:0::1;;;;;;;:::i;:::-;174714:40;174729:7;174738:3;174743:10;174714:40;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1::0;;;;;174765:28:0;;;::::1;;::::0;;;:19:::1;:28;::::0;;;;:34;;-1:-1:-1;;174765:34:0::1;::::0;::::1;;::::0;;;::::1;::::0;;174536:271::o;159985:51::-;;;;;;;;;;;;;;;;:::i;171463:142::-;171533:4;171595:1;-1:-1:-1;;;;;171557:40:0;:17;171575:7;171557:26;;;;;;:::i;:::-;;;;;;;;;;;;;;;-1:-1:-1;;;;;171557:26:0;:40;;;171463:142;-1:-1:-1;;171463:142:0:o;171836:141::-;-1:-1:-1;;;;;171935:34:0;;;;;;:17;:34;;;;;171928:41;;171903:12;;171935:34;171928:41;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;171836:141;;;:::o;160102:55::-;;;;;;;;;;;;;;;;:::i;26084:131::-;26158:7;26185:12;;;;;;;;;;:22;;;;26084:131::o;164545:851::-;173700:34;173723:10;173700:22;:34::i;:::-;:71;;;;173738:33;173760:10;173738:21;:33::i;:::-;173692:126;;;;-1:-1:-1;;;173692:126:0;;14516:2:1;173692:126:0;;;14498:21:1;14555:2;14535:18;;;14528:30;14594:34;14574:18;;;14567:62;-1:-1:-1;;;14645:18:1;;;14638:40;14695:19;;173692:126:0;14314:406:1;173692:126:0;-1:-1:-1;;;;;164639:32:0;::::1;;::::0;;;:18:::1;:32;::::0;;;;;::::1;;164631:104;;;::::0;-1:-1:-1;;;164631:104:0;;14927:2:1;164631:104:0::1;::::0;::::1;14909:21:1::0;14966:2;14946:18;;;14939:30;15005:34;14985:18;;;14978:62;-1:-1:-1;;;15056:18:1;;;15049:57;15123:19;;164631:104:0::1;14725:423:1::0;164631:104:0::1;164750:34;164773:10;164750:22;:34::i;:::-;164746:171;;-1:-1:-1::0;;;;;164809:33:0;;::::1;;::::0;;;:19:::1;:33;::::0;;;;;::::1;164846:10;164809:47;164801:104;;;::::0;-1:-1:-1;;;164801:104:0;;15355:2:1;164801:104:0::1;::::0;::::1;15337:21:1::0;15394:2;15374:18;;;15367:30;15433:34;15413:18;;;15406:62;-1:-1:-1;;;15484:18:1;;;15477:42;15536:19;;164801:104:0::1;15153:408:1::0;164801:104:0::1;164929:31;164947:12;164929:17;:31::i;:::-;-1:-1:-1::0;;;;;165002:26:0;::::1;164980:49;165002:26:::0;;;:12:::1;:26;::::0;;;;;;;;;164980:49;;:21:::1;:49:::0;;;;;164973:56;;-1:-1:-1;;;;;;164973:56:0::1;::::0;;165047:26;;;165040:33;;;;165091:19:::1;:33:::0;;;;;165084:40:::1;::::0;::::1;:::i;:::-;-1:-1:-1::0;;;;;165142:31:0;::::1;;::::0;;;:17:::1;:31;::::0;;;;165135:38:::1;::::0;::::1;:::i;:::-;-1:-1:-1::0;;;;;165191:32:0;::::1;;::::0;;;:18:::1;:32;::::0;;;;;;;165184:39;;-1:-1:-1;;165184:39:0::1;::::0;;165241:19:::1;:33:::0;;;;;165234:40;;-1:-1:-1;;;;;;165234:40:0;;::::1;::::0;;;165292:18:::1;:32:::0;;;;;;;165285:39;;;;::::1;::::0;;165342:46;::::1;::::0;::::1;::::0;165377:10:::1;::::0;165342:46:::1;:::i;:::-;;;;;;;;164545:851:::0;:::o;26525:147::-;26608:18;26621:4;26608:12;:18::i;:::-;24153:16;24164:4;24153:10;:16::i;:::-;26639:25:::1;26650:4;26656:7;26639:10;:25::i;:::-;26525:147:::0;;;:::o;202880:500::-;203009:33;203026:15;203009:16;:33::i;:::-;203001:77;;;;-1:-1:-1;;;203001:77:0;;15768:2:1;203001:77:0;;;15750:21:1;15807:2;15787:18;;;15780:30;15846:33;15826:18;;;15819:61;15897:18;;203001:77:0;15566:355:1;203001:77:0;203089:15;203120:17;203138:15;203120:34;;;;;;:::i;:::-;;;;;;;;;;;;;;;203215:13;;-1:-1:-1;;;203197:46:0;;-1:-1:-1;;;;;203120:34:0;;;;-1:-1:-1;203120:34:0;;;;203197:17;;:46;;203215:13;;;203230:4;;203236:6;;203197:46;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;203197:46:0;;;;;;;;;;;;:::i;:::-;203166:77;;203254:21;203278:2;-1:-1:-1;;;;;203278:21:0;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;203278:23:0;;;;;;;;;;;;:::i;:::-;203254:47;;203312:52;203321:15;203338;203355:8;203312;:52::i;:::-;;202990:390;;;202880:500;;;:::o;198125:169::-;198200:4;198224:29;-1:-1:-1;;;;;;;;;;;198248:4:0;198224:7;:29::i;:::-;:62;;;;198284:1;198258:23;198276:4;198258:17;:23::i;:::-;:27;198217:69;198125:169;-1:-1:-1;;198125:169:0:o;27669:218::-;-1:-1:-1;;;;;27765:23:0;;4371:10;27765:23;27757:83;;;;-1:-1:-1;;;27757:83:0;;16611:2:1;27757:83:0;;;16593:21:1;16650:2;16630:18;;;16623:30;16689:34;16669:18;;;16662:62;-1:-1:-1;;;16740:18:1;;;16733:45;16795:19;;27757:83:0;16409:411:1;27757:83:0;27853:26;27865:4;27871:7;27853:11;:26::i;:::-;27669:218;;:::o;198464:165::-;198538:4;198562:28;-1:-1:-1;;;;;;;;;;;198585:4:0;198562:7;:28::i;:::-;:59;;;;198619:1;198595:21;198611:4;198595:15;:21::i;174153:275::-;173555:34;173578:10;173555:22;:34::i;:::-;173547:73;;;;-1:-1:-1;;;173547:73:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;174258:29:0;::::1;;::::0;;;:20:::1;:29;::::0;;;;;:36;::::1;;:29;::::0;;::::1;:36;;::::0;174250:67:::1;;;;-1:-1:-1::0;;;174250:67:0::1;;;;;;;:::i;:::-;174333:41;174349:7;174358:3;174363:10;174333:41;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1::0;;;;;174385:29:0;;;::::1;;::::0;;;:20:::1;:29;::::0;;;;:35;;-1:-1:-1;;174385:35:0::1;::::0;::::1;;::::0;;;::::1;::::0;;174153:275::o;196987:51::-;;;;;;;;;;;;;;;;:::i;204067:77::-;-1:-1:-1;;;;;;;;;;;24153:16:0;24164:4;24153:10;:16::i;:::-;204126:10:::1;:8;:10::i;:::-;204067:77:::0;:::o;197807:146::-;197883:4;197907:38;-1:-1:-1;;;;;;;;;;;197940:4:0;197907:7;:38::i;160921:406::-;161184:19;;;;;;;161126:78;;;-1:-1:-1;;;;;;161126:78:0;;;17036:39:1;161165:4:0;17137:2:1;17108:15;-1:-1:-1;;;;;;17104:45:1;17091:11;;;17084:66;17166:12;;;17159:28;;;;17203:12;;;;17196:28;;;;161126:78:0;;;;;;;;;;17240:12:1;;;;161126:78:0;;;161102:113;;;;;;160921:406::o;169049:1014::-;169150:7;173421:32;173442:10;173421:20;:32::i;:::-;173413:69;;;;-1:-1:-1;;;173413:69:0;;17465:2:1;173413:69:0;;;17447:21:1;17504:2;17484:18;;;17477:30;-1:-1:-1;;;17523:18:1;;;17516:54;17587:18;;173413:69:0;17263:348:1;173413:69:0;-1:-1:-1;;;;;169205:37:0;;::::1;169175:14;169205:37:::0;;;:18:::1;:37;::::0;;;;;;;;169297:19:::1;:38:::0;;;;;169264:71;;169205:37;;;::::1;::::0;169297:38;169264:71:::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;169346:34;169383:1;-1:-1:-1::0;;;;;169383:13:0::1;;169397:17;169383:32;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;::::0;;::::1;-1:-1:-1::0;;169383:32:0::1;::::0;::::1;;::::0;::::1;::::0;;;::::1;::::0;::::1;:::i;:::-;-1:-1:-1::0;;;;;169477:31:0;;::::1;;::::0;;;:12:::1;:31;::::0;;;;;;;;;169437:72;;-1:-1:-1;;;169437:72:0;;169346:69;;-1:-1:-1;169437:16:0;;::::1;::::0;::::1;::::0;:72:::1;::::0;169346:69;;169477:31;;169437:72:::1;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;169429:132;;;::::0;-1:-1:-1;;;169429:132:0;;18361:2:1;169429:132:0::1;::::0;::::1;18343:21:1::0;18400:2;18380:18;;;18373:30;18439:34;18419:18;;;18412:62;-1:-1:-1;;;18490:18:1;;;18483:45;18545:19;;169429:132:0::1;18159:411:1::0;169429:132:0::1;169574:23;169600:49;169614:21;169637:11;;169600:13;:49::i;:::-;169574:75;;169689:17;-1:-1:-1::0;;;;;169670:36:0::1;:15;-1:-1:-1::0;;;;;169670:36:0::1;;169662:88;;;::::0;-1:-1:-1;;;169662:88:0;;18777:2:1;169662:88:0::1;::::0;::::1;18759:21:1::0;18816:2;18796:18;;;18789:30;18855:34;18835:18;;;18828:62;-1:-1:-1;;;18906:18:1;;;18899:37;18953:19;;169662:88:0::1;18575:403:1::0;169662:88:0::1;-1:-1:-1::0;;;;;169840:37:0;;::::1;169763:21;169840:37:::0;;;:18:::1;:37;::::0;;;;;169833:44;;-1:-1:-1;;169833:44:0::1;::::0;;169929:15;;-1:-1:-1;;;169929:15:0;;;;169806;;169895:62;::::1;::::0;::::1;::::0;;;169929:13:::1;::::0;:15:::1;::::0;;::::1;::::0;169763:21;;169929:15;;;;;;169895:62;169929:15:::1;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;::::0;;::::1;-1:-1:-1::0;;169929:15:0::1;::::0;::::1;;::::0;::::1;::::0;;;::::1;::::0;::::1;:::i;:::-;169946:10;169895:62;;;;;;;:::i;:::-;;;;;;;;169968:50;169985:15;170002:2;-1:-1:-1::0;;;;;170002:13:0::1;;:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;::::0;;::::1;-1:-1:-1::0;;170002:15:0::1;::::0;::::1;;::::0;::::1;::::0;;;::::1;::::0;::::1;:::i;:::-;169968:16;:50::i;:::-;-1:-1:-1::0;170036:15:0;169049:1014;-1:-1:-1;;;;;169049:1014:0:o;203919:73::-;-1:-1:-1;;;;;;;;;;;24153:16:0;24164:4;24153:10;:16::i;:::-;203976:8:::1;:6;:8::i;96085:190::-:0;96186:4;24667:12;;;;;;;;;;;-1:-1:-1;;;;;24667:29:0;;;;;;;;;;;;96209:59;;;-1:-1:-1;96241:4:0;;:27;;-1:-1:-1;;;96241:27:0;;-1:-1:-1;;;;;96241:4:0;;;;:12;;:27;;96254:4;;96260:7;;96241:27;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;160288:34::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;160288:34:0;;-1:-1:-1;160288:34:0;:::o;96378:507::-;23707:4;24153:16;23707:4;24153:10;:16::i;:::-;96486:4:::1;::::0;;-1:-1:-1;;;;;96498:18:0;;::::1;-1:-1:-1::0;;;;;;96498:18:0;::::1;;::::0;;;96486:4:::1;96609:73;96512:3:::0;-1:-1:-1;;;96609:31:0::1;:73::i;:::-;96601:125;;;::::0;-1:-1:-1;;;96601:125:0;;20047:2:1;96601:125:0::1;::::0;::::1;20029:21:1::0;20086:2;20066:18;;;20059:30;20125:34;20105:18;;;20098:62;-1:-1:-1;;;20176:18:1;;;20169:37;20223:19;;96601:125:0::1;19845:403:1::0;96601:125:0::1;96741:4;::::0;:44:::1;::::0;-1:-1:-1;;;96741:44:0;;-1:-1:-1;;;;;96741:4:0;;::::1;::::0;:12:::1;::::0;:44:::1;::::0;:4:::1;::::0;96774:10:::1;::::0;96741:44:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;96733:92;;;::::0;-1:-1:-1;;;96733:92:0;;20455:2:1;96733:92:0::1;::::0;::::1;20437:21:1::0;20494:2;20474:18;;;20467:30;20533:34;20513:18;;;20506:62;-1:-1:-1;;;20584:18:1;;;20577:33;20627:19;;96733:92:0::1;20253:399:1::0;96733:92:0::1;96837:42;::::0;;-1:-1:-1;;;;;20915:15:1;;;20897:34;;20967:15;;20962:2;20947:18;;20940:43;96868:10:0::1;20999:18:1::0;;;20992:43;96837:42:0;;::::1;::::0;;;;20847:2:1;96837:42:0;;::::1;96449:436;96378:507:::0;;:::o;174917:279::-;173555:34;173578:10;173555:22;:34::i;:::-;173547:73;;;;-1:-1:-1;;;173547:73:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;175023:30:0;::::1;;::::0;;;:21:::1;:30;::::0;;;;;:37;::::1;;:30;::::0;;::::1;:37;;::::0;175015:68:::1;;;;-1:-1:-1::0;;;175015:68:0::1;;;;;;;:::i;:::-;175099:42;175116:7;175125:3;175130:10;175099:42;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1::0;;;;;175152:30:0;;;::::1;;::::0;;;:21:::1;:30;::::0;;;;:36;;-1:-1:-1;;175152:36:0::1;::::0;::::1;;::::0;;;::::1;::::0;;174917:279::o;200350:301::-;-1:-1:-1;;;;;;;;;;;24153:16:0;24164:4;24153:10;:16::i;:::-;-1:-1:-1;;;;;200472:26:0;::::1;;::::0;;;:17:::1;:26;::::0;;;;:45;;200502:15;;200472:26;:45:::1;::::0;200502:15;;200472:45:::1;:::i;:::-;::::0;;;-1:-1:-1;;;;;;;200541:102:0;::::1;;200571:15:::0;200588:26:::1;200562:7:::0;200588:17:::1;:26::i;:::-;-1:-1:-1::0;;;;;200616:26:0;::::1;;::::0;;;:17:::1;:26;::::0;;;;;;;200541:102;;::::1;::::0;;;200616:26;200541:102:::1;:::i;:::-;;;;;;;;200350:301:::0;;;:::o;163219:199::-;173555:34;173578:10;173555:22;:34::i;:::-;173547:73;;;;-1:-1:-1;;;173547:73:0;;;;;;;:::i;:::-;175253:15:::1;:13;:15::i;:::-;175245:43;;;;-1:-1:-1::0;;;175245:43:0::1;;;;;;;:::i;:::-;163345:11:::2;::::0;163324:54:::2;::::0;;21834:25:1;;;21890:2;21875:18;;21868:34;;;163367:10:0::2;21918:18:1::0;;;21911:60;163324:54:0;::::2;::::0;;;;21822:2:1;163324:54:0;;::::2;163389:11;:21:::0;163219:199::o;201266:294::-;-1:-1:-1;;;;;201382:24:0;;201328:25;201382:24;;;:15;:24;;;;;;;;;201432:20;:29;;;;;;201475:12;;;201472:52;;;-1:-1:-1;201511:1:0;;201266:294;-1:-1:-1;;;201266:294:0:o;201472:52::-;201542:12;201550:4;201542:5;:12;:::i;:::-;201534:20;201266:294;-1:-1:-1;;;;201266:294:0:o;204224:118::-;204300:4;204325:8;34386:7;;;;;34315:86;204325:8;204324:9;204317:16;;204224:118;:::o;170998:302::-;173555:34;173578:10;173555:22;:34::i;:::-;173547:73;;;;-1:-1:-1;;;173547:73:0;;;;;;;:::i;:::-;171079:16:::1;171098:17;171116:7;171098:26;;;;;;:::i;:::-;::::0;;;::::1;::::0;;;;;::::1;::::0;;;;-1:-1:-1;;;;;171098:26:0::1;::::0;-1:-1:-1;171098:26:0;171135:50:::1;;;::::0;-1:-1:-1;;;171135:50:0;;22317:2:1;171135:50:0::1;::::0;::::1;22299:21:1::0;22356:2;22336:18;;;22329:30;-1:-1:-1;;;22375:18:1;;;22368:45;22430:18;;171135:50:0::1;22115:339:1::0;171135:50:0::1;171228:7;171201:47;;;;;;:::i;:::-;;;;;;;;171224:1;-1:-1:-1::0;;;;;171201:47:0::1;-1:-1:-1::0;;;;;;;;;;;171237:10:0::1;171201:47;;;;;;:::i;:::-;;;;;;;;171266:17;171284:7;171266:26;;;;;;:::i;:::-;::::0;;;::::1;::::0;;;;;::::1;::::0;;;171259:33;;-1:-1:-1;;;;;;171259:33:0::1;::::0;;-1:-1:-1;;170998:302:0:o;26965:149::-;27049:18;27062:4;27049:12;:18::i;:::-;24153:16;24164:4;24153:10;:16::i;:::-;27080:26:::1;27092:4;27098:7;27080:11;:26::i;201768:304::-:0;-1:-1:-1;;;;;201888:26:0;;201832:27;201888:26;;;:17;:26;;;;;;;;;201940:22;:31;;;;;;201985:12;;;201982:52;;;-1:-1:-1;202021:1:0;;201768:304;-1:-1:-1;;;201768:304:0:o;170483:404::-;173555:34;173578:10;173555:22;:34::i;:::-;173547:73;;;;-1:-1:-1;;;173547:73:0;;;;;;;:::i;:::-;170567:15:::1;170598;170567:47;;170625:22;170650:2;-1:-1:-1::0;;;;;170650:13:0::1;;:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;::::0;;::::1;-1:-1:-1::0;;170650:15:0::1;::::0;::::1;;::::0;::::1;::::0;;;::::1;::::0;::::1;:::i;:::-;170625:40;;170715:15;-1:-1:-1::0;;;;;170684:46:0::1;:17;170702:8;170684:27;;;;;;:::i;:::-;::::0;;;::::1;::::0;;;;;::::1;::::0;;;;-1:-1:-1;;;;;170684:27:0::1;:46:::0;170676:77:::1;;;;-1:-1:-1::0;;;170676:77:0::1;;;;;;;:::i;:::-;170801:8;170769:54;;;;;;:::i;:::-;;;;;;;;170784:15;-1:-1:-1::0;;;;;170769:54:0::1;-1:-1:-1::0;;;;;;;;;;;170811:10:0::1;170769:54;;;;;;:::i;:::-;;;;;;;;170864:15;170834:17;170852:8;170834:27;;;;;;:::i;:::-;::::0;;;::::1;::::0;;;;;::::1;::::0;;;:45;;-1:-1:-1;;;;;170834:45:0;;;::::1;-1:-1:-1::0;;;;;;170834:45:0;;::::1;::::0;;;::::1;::::0;;-1:-1:-1;;;170483:404:0:o;200779:277::-;-1:-1:-1;;;;;;;;;;;24153:16:0;24164:4;24153:10;:16::i;:::-;-1:-1:-1;;;;;200897:24:0;::::1;;::::0;;;:15:::1;:24;::::0;;;;:41;;200925:13;;200897:24;:41:::1;::::0;200925:13;;200897:41:::1;:::i;:::-;::::0;;;-1:-1:-1;;;;;;;200954:94:0;::::1;;200982:13:::0;200997:24:::1;200973:7:::0;200997:15:::1;:24::i;:::-;-1:-1:-1::0;;;;;201023:24:0;::::1;;::::0;;;:15:::1;:24;::::0;;;;;;;200954:94;;::::1;::::0;;;201023:24;200954:94:::1;:::i;175387:228::-:0;175480:4;-1:-1:-1;;;;;;175504:50:0;;-1:-1:-1;;;175504:50:0;;:103;;;175571:36;175595:11;175571:23;:36::i;199018:607::-;199203:14;199221:20;199257:11;199246:50;;;;;;;;;;;;:::i;:::-;199202:94;;;;;199351:1;-1:-1:-1;;;;;199315:38:0;:16;199332:6;199315:24;;;;;;:::i;:::-;;;;;;;;;;;;;;;-1:-1:-1;;;;;199315:24:0;:38;199307:71;;;;-1:-1:-1;;;199307:71:0;;23364:2:1;199307:71:0;;;23346:21:1;23403:2;23383:18;;;23376:30;-1:-1:-1;;;23422:18:1;;;23415:50;23482:18;;199307:71:0;23162:344:1;199307:71:0;199407:13;;-1:-1:-1;;;;;199397:23:0;;;199407:13;;199397:23;199389:58;;;;-1:-1:-1;;;199389:58:0;;23713:2:1;199389:58:0;;;23695:21:1;23752:2;23732:18;;;23725:30;-1:-1:-1;;;23771:18:1;;;23764:52;23833:18;;199389:58:0;23511:346:1;199389:58:0;199491:10;199468:34;;;;:22;:34;;;;;:39;;199506:1;;199468:34;:39;;199506:1;;199468:39;:::i;:::-;;;;-1:-1:-1;;;;;;;199518:35:0;;;;;;:16;:35;;;;;:44;199556:6;199518:35;:44;:::i;:::-;;199600:17;199573:16;199590:6;199573:24;;;;;;:::i;:::-;;;;;;;;;;;;;;:44;;-1:-1:-1;;;;;199573:44:0;;;;-1:-1:-1;;;;;;199573:44:0;;;;;;;;;-1:-1:-1;;;;;;199018:607:0:o;199802:323::-;-1:-1:-1;;;;;199916:33:0;;;199893:57;199916:33;;;:19;:33;;;;;;;;;;;;199893:57;;:22;:57;;;;;:62;;199954:1;;199893:57;:62;;199954:1;;199893:62;:::i;:::-;;;;-1:-1:-1;;;;;;;199990:30:0;;;;;;:16;:30;;;;;;;199973:48;;:16;;:48;;;:::i;:::-;;;;;;;;;;;;;;;;199966:55;;-1:-1:-1;;;;;;199966:55:0;;;-1:-1:-1;;;;;200039:30:0;;-1:-1:-1;200039:30:0;;;:16;:30;;;;;200032:37;;;:::i;25008:105::-;25075:30;25086:4;4371:10;25075;:30::i;29266:238::-;29350:22;29358:4;29364:7;29350;:22::i;:::-;29345:152;;29389:6;:12;;;;;;;;;;;-1:-1:-1;;;;;29389:29:0;;;;;;;;;:36;;-1:-1:-1;;29389:36:0;29421:4;29389:36;;;29472:12;4371:10;;4291:98;29472:12;-1:-1:-1;;;;;29445:40:0;29463:7;-1:-1:-1;;;;;29445:40:0;29457:4;29445:40;;;;;;;;;;29266:238;;:::o;29684:239::-;29768:22;29776:4;29782:7;29768;:22::i;:::-;29764:152;;;29839:5;29807:12;;;;;;;;;;;-1:-1:-1;;;;;29807:29:0;;;;;;;;;;:37;;-1:-1:-1;;29807:37:0;;;29864:40;4371:10;;29807:12;;29864:40;;29839:5;29864:40;29684:239;;:::o;35170:120::-;34179:16;:14;:16::i;:::-;35229:7:::1;:15:::0;;-1:-1:-1;;35229:15:0::1;::::0;;35260:22:::1;4371:10:::0;35269:12:::1;35260:22;;;;;;:::i;:::-;;;;;;;;35170:120::o:0;161803:1050::-;161899:7;175253:15;:13;:15::i;:::-;175245:43;;;;-1:-1:-1;;;175245:43:0;;;;;;;:::i;:::-;162574:15;;161919:12:::1;::::0;161965:4;;;;162550::::1;162536:19:::0;::::1;162403:11;162377:345;162369:353;;162760:4;162748:17;162738:75;;162796:1;162793::::0;162786:12:::1;162738:75;-1:-1:-1::0;162841:4:0;161803:1050;-1:-1:-1;;;161803:1050:0:o;202243:216::-;202384:10;202363:32;;;;:20;:32;;;;;:37;;202399:1;;202363:32;:37;;202399:1;;202363:37;:::i;:::-;;;;-1:-1:-1;;;;;;;;202411:27:0;;;;;:10;:27;;;;;:40;;-1:-1:-1;;;;;;202411:40:0;202441:10;202411:40;;;202243:216::o;34911:118::-;33920:19;:17;:19::i;:::-;34971:7:::1;:14:::0;;-1:-1:-1;;34971:14:0::1;34981:4;34971:14;::::0;;35001:20:::1;35008:12;4371:10:::0;;4291:98;79586:285;79673:4;79782:23;79797:7;79782:14;:23::i;:::-;:81;;;;;79809:54;79842:7;79851:11;79809:32;:54::i;97042:190::-;97167:4;97190:36;97214:11;97190:23;:36::i;25403:492::-;25492:22;25500:4;25506:7;25492;:22::i;:::-;25487:401;;25680:28;25700:7;25680:19;:28::i;:::-;25781:38;25809:4;25816:2;25781:19;:38::i;:::-;25585:257;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;25585:257:0;;;;;;;;;;-1:-1:-1;;;25531:345:0;;;;;;;:::i;34659:108::-;34386:7;;;;34718:41;;;;-1:-1:-1;;;34718:41:0;;27083:2:1;34718:41:0;;;27065:21:1;27122:2;27102:18;;;27095:30;-1:-1:-1;;;27141:18:1;;;27134:50;27201:18;;34718:41:0;26881:344:1;34718:41:0;34659:108::o;34474:::-;34386:7;;;;34544:9;34536:38;;;;-1:-1:-1;;;34536:38:0;;27432:2:1;34536:38:0;;;27414:21:1;27471:2;27451:18;;;27444:30;-1:-1:-1;;;27490:18:1;;;27483:46;27546:18;;34536:38:0;27230:340:1;78927:433:0;78991:4;79202:68;79235:7;-1:-1:-1;;;79202:32:0;:68::i;:::-;:150;;;;-1:-1:-1;79288:64:0;79321:7;-1:-1:-1;;;;;;79288:32:0;:64::i;:::-;79287:65;79182:170;78927:433;-1:-1:-1;;78927:433:0:o;82739:662::-;82912:71;;;-1:-1:-1;;;;;;27737:33:1;;82912:71:0;;;;27719:52:1;;;;82912:71:0;;;;;;;;;;27692:18:1;;;;82912:71:0;;;;;;;;;-1:-1:-1;;;;;82912:71:0;-1:-1:-1;;;82912:71:0;;;83198:20;;82841:4;;82912:71;82841:4;;;;;;82912:71;82841:4;;83198:20;83163:7;83156:5;83145:86;83134:97;;83259:16;83245:30;;83310:4;83304:11;83289:26;;83345:7;:29;;;;;83370:4;83356:10;:18;;83345:29;:48;;;;;83392:1;83378:11;:15;83345:48;83338:55;82739:662;-1:-1:-1;;;;;;;82739:662:0:o;24261:204::-;24346:4;-1:-1:-1;;;;;;24370:47:0;;-1:-1:-1;;;24370:47:0;;:87;;-1:-1:-1;;;;;;;;;;6410:40:0;;;24421:36;6301:157;21520:151;21578:13;21611:52;-1:-1:-1;;;;;21623:22:0;;19675:2;20916:447;20991:13;21017:19;21049:10;21053:6;21049:1;:10;:::i;:::-;:14;;21062:1;21049:14;:::i;:::-;-1:-1:-1;;;;;21039:25:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;21039:25:0;;21017:47;;-1:-1:-1;;;21075:6:0;21082:1;21075:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;21075:15:0;;;;;;;;;-1:-1:-1;;;21101:6:0;21108:1;21101:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;21101:15:0;;;;;;;;-1:-1:-1;21132:9:0;21144:10;21148:6;21144:1;:10;:::i;:::-;:14;;21157:1;21144:14;:::i;:::-;21132:26;;21127:131;21164:1;21160;:5;21127:131;;;-1:-1:-1;;;21208:5:0;21216:3;21208:11;21199:21;;;;;;;:::i;:::-;;;;21187:6;21194:1;21187:9;;;;;;;;:::i;:::-;;;;:33;-1:-1:-1;;;;;21187:33:0;;;;;;;;-1:-1:-1;21245:1:0;21235:11;;;;;21167:3;;;:::i;:::-;;;21127:131;;;-1:-1:-1;21276:10:0;;21268:55;;;;-1:-1:-1;;;21268:55:0;;28430:2:1;21268:55:0;;;28412:21:1;;;28449:18;;;28442:30;28508:34;28488:18;;;28481:62;28560:18;;21268:55:0;28228:356:1;-1:-1:-1;;;;;;;:::i;:::-;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;14:131:1:-;-1:-1:-1;;;;;89:31:1;;79:42;;69:70;;135:1;132;125:12;150:247;209:6;262:2;250:9;241:7;237:23;233:32;230:52;;;278:1;275;268:12;230:52;317:9;304:23;336:31;361:5;336:31;:::i;402:250::-;487:1;497:113;511:6;508:1;505:13;497:113;;;587:11;;;581:18;568:11;;;561:39;533:2;526:10;497:113;;;-1:-1:-1;;644:1:1;626:16;;619:27;402:250::o;657:270::-;698:3;736:5;730:12;763:6;758:3;751:19;779:76;848:6;841:4;836:3;832:14;825:4;818:5;814:16;779:76;:::i;:::-;909:2;888:15;-1:-1:-1;;884:29:1;875:39;;;;916:4;871:50;;657:270;-1:-1:-1;;657:270:1:o;932:217::-;1079:2;1068:9;1061:21;1042:4;1099:44;1139:2;1128:9;1124:18;1116:6;1099:44;:::i;1154:286::-;1212:6;1265:2;1253:9;1244:7;1240:23;1236:32;1233:52;;;1281:1;1278;1271:12;1233:52;1307:23;;-1:-1:-1;;;;;;1359:32:1;;1349:43;;1339:71;;1406:1;1403;1396:12;1637:127;1698:10;1693:3;1689:20;1686:1;1679:31;1729:4;1726:1;1719:15;1753:4;1750:1;1743:15;1769:275;1840:2;1834:9;1905:2;1886:13;;-1:-1:-1;;1882:27:1;1870:40;;-1:-1:-1;;;;;1925:34:1;;1961:22;;;1922:62;1919:88;;;1987:18;;:::i;:::-;2023:2;2016:22;1769:275;;-1:-1:-1;1769:275:1:o;2049:187::-;2098:4;-1:-1:-1;;;;;2120:30:1;;2117:56;;;2153:18;;:::i;:::-;-1:-1:-1;2219:2:1;2198:15;-1:-1:-1;;2194:29:1;2225:4;2190:40;;2049:187::o;2241:464::-;2284:5;2337:3;2330:4;2322:6;2318:17;2314:27;2304:55;;2355:1;2352;2345:12;2304:55;2391:6;2378:20;2422:49;2438:32;2467:2;2438:32;:::i;:::-;2422:49;:::i;:::-;2496:2;2487:7;2480:19;2542:3;2535:4;2530:2;2522:6;2518:15;2514:26;2511:35;2508:55;;;2559:1;2556;2549:12;2508:55;2624:2;2617:4;2609:6;2605:17;2598:4;2589:7;2585:18;2572:55;2672:1;2647:16;;;2665:4;2643:27;2636:38;;;;2651:7;2241:464;-1:-1:-1;;;2241:464:1:o;2710:741::-;2815:6;2823;2831;2884:2;2872:9;2863:7;2859:23;2855:32;2852:52;;;2900:1;2897;2890:12;2852:52;2927:23;;-1:-1:-1;;;;;2999:14:1;;;2996:34;;;3026:1;3023;3016:12;2996:34;3049:50;3091:7;3082:6;3071:9;3067:22;3049:50;:::i;:::-;3039:60;;3152:2;3141:9;3137:18;3124:32;3108:48;;3181:2;3171:8;3168:16;3165:36;;;3197:1;3194;3187:12;3165:36;3220:52;3264:7;3253:8;3242:9;3238:24;3220:52;:::i;:::-;3210:62;;3325:2;3314:9;3310:18;3297:32;3281:48;;3354:2;3344:8;3341:16;3338:36;;;3370:1;3367;3360:12;3338:36;;3393:52;3437:7;3426:8;3415:9;3411:24;3393:52;:::i;:::-;3383:62;;;2710:741;;;;;:::o;3456:203::-;-1:-1:-1;;;;;3620:32:1;;;;3602:51;;3590:2;3575:18;;3456:203::o;3664:118::-;3750:5;3743:13;3736:21;3729:5;3726:32;3716:60;;3772:1;3769;3762:12;3787:382;3852:6;3860;3913:2;3901:9;3892:7;3888:23;3884:32;3881:52;;;3929:1;3926;3919:12;3881:52;3968:9;3955:23;3987:31;4012:5;3987:31;:::i;:::-;4037:5;-1:-1:-1;4094:2:1;4079:18;;4066:32;4107:30;4066:32;4107:30;:::i;:::-;4156:7;4146:17;;;3787:382;;;;;:::o;4174:322::-;4243:6;4296:2;4284:9;4275:7;4271:23;4267:32;4264:52;;;4312:1;4309;4302:12;4264:52;4339:23;;-1:-1:-1;;;;;4374:30:1;;4371:50;;;4417:1;4414;4407:12;4371:50;4440;4482:7;4473:6;4462:9;4458:22;4440:50;:::i;4501:180::-;4560:6;4613:2;4601:9;4592:7;4588:23;4584:32;4581:52;;;4629:1;4626;4619:12;4581:52;-1:-1:-1;4652:23:1;;4501:180;-1:-1:-1;4501:180:1:o;5092:315::-;5160:6;5168;5221:2;5209:9;5200:7;5196:23;5192:32;5189:52;;;5237:1;5234;5227:12;5189:52;5273:9;5260:23;5250:33;;5333:2;5322:9;5318:18;5305:32;5346:31;5371:5;5346:31;:::i;6342:389::-;6419:6;6427;6480:2;6468:9;6459:7;6455:23;6451:32;6448:52;;;6496:1;6493;6486:12;6448:52;6523:23;;-1:-1:-1;;;;;6558:30:1;;6555:50;;;6601:1;6598;6591:12;6555:50;6624;6666:7;6657:6;6646:9;6642:22;6624:50;:::i;:::-;6614:60;6721:2;6706:18;;;;6693:32;;-1:-1:-1;;;;6342:389:1:o;6921:315::-;6989:6;6997;7050:2;7038:9;7029:7;7025:23;7021:32;7018:52;;;7066:1;7063;7056:12;7018:52;7105:9;7092:23;7124:31;7149:5;7124:31;:::i;:::-;7174:5;7226:2;7211:18;;;;7198:32;;-1:-1:-1;;;6921:315:1:o;7241:380::-;7320:1;7316:12;;;;7363;;;7384:61;;7438:4;7430:6;7426:17;7416:27;;7384:61;7491:2;7483:6;7480:14;7460:18;7457:38;7454:161;;7537:10;7532:3;7528:20;7525:1;7518:31;7572:4;7569:1;7562:15;7600:4;7597:1;7590:15;7454:161;;7241:380;;;:::o;7980:339::-;8182:2;8164:21;;;8221:2;8201:18;;;8194:30;-1:-1:-1;;;8255:2:1;8240:18;;8233:45;8310:2;8295:18;;7980:339::o;8324:289::-;8455:3;8493:6;8487:13;8509:66;8568:6;8563:3;8556:4;8548:6;8544:17;8509:66;:::i;:::-;8591:16;;;;;8324:289;-1:-1:-1;;8324:289:1:o;8964:321::-;9039:5;9068:53;9084:36;9113:6;9084:36;:::i;9068:53::-;9059:62;;9144:6;9137:5;9130:21;9184:3;9175:6;9170:3;9166:16;9163:25;9160:45;;;9201:1;9198;9191:12;9160:45;9214:65;9272:6;9265:4;9258:5;9254:16;9249:3;9214:65;:::i;9290:457::-;9369:6;9422:2;9410:9;9401:7;9397:23;9393:32;9390:52;;;9438:1;9435;9428:12;9390:52;9465:16;;-1:-1:-1;;;;;9493:30:1;;9490:50;;;9536:1;9533;9526:12;9490:50;9559:22;;9612:4;9604:13;;9600:27;-1:-1:-1;9590:55:1;;9641:1;9638;9631:12;9590:55;9664:77;9733:7;9728:2;9722:9;9717:2;9713;9709:11;9664:77;:::i;10233:544::-;10334:2;10329:3;10326:11;10323:448;;;10370:1;10395:5;10391:2;10384:17;10440:4;10436:2;10426:19;10510:2;10498:10;10494:19;10491:1;10487:27;10481:4;10477:38;10546:4;10534:10;10531:20;10528:47;;;-1:-1:-1;10569:4:1;10528:47;10624:2;10619:3;10615:12;10612:1;10608:20;10602:4;10598:31;10588:41;;10679:82;10697:2;10690:5;10687:13;10679:82;;;10742:17;;;10723:1;10712:13;10679:82;;;10683:3;;;10233:544;;;:::o;10953:1348::-;11071:10;;-1:-1:-1;;;;;11093:30:1;;11090:56;;;11126:18;;:::i;:::-;11155:96;11244:6;11204:38;11236:4;11230:11;11204:38;:::i;:::-;11198:4;11155:96;:::i;:::-;11306:4;;11370:2;11359:14;;11387:1;11382:662;;;;12088:1;12105:6;12102:89;;;-1:-1:-1;12157:19:1;;;12151:26;12102:89;-1:-1:-1;;10910:1:1;10906:11;;;10902:24;10898:29;10888:40;10934:1;10930:11;;;10885:57;12204:81;;11352:943;;11382:662;10180:1;10173:14;;;10217:4;10204:18;;-1:-1:-1;;11418:20:1;;;11535:236;11549:7;11546:1;11543:14;11535:236;;;11638:19;;;11632:26;11617:42;;11730:27;;;;11698:1;11686:14;;;;11565:19;;11535:236;;;11539:3;11799:6;11790:7;11787:19;11784:201;;;11860:19;;;11854:26;-1:-1:-1;;11943:1:1;11939:14;;;11955:3;11935:24;11931:37;11927:42;11912:58;11897:74;;11784:201;-1:-1:-1;;;;;12031:1:1;12015:14;;;12011:22;11998:36;;-1:-1:-1;10953:1348:1:o;12306:184::-;12376:6;12429:2;12417:9;12408:7;12404:23;12400:32;12397:52;;;12445:1;12442;12435:12;12397:52;-1:-1:-1;12468:16:1;;12306:184;-1:-1:-1;12306:184:1:o;12901:316::-;13078:2;13067:9;13060:21;13041:4;13098:44;13138:2;13127:9;13123:18;13115:6;13098:44;:::i;:::-;13090:52;;13207:1;13203;13198:3;13194:11;13190:19;13182:6;13178:32;13173:2;13162:9;13158:18;13151:60;12901:316;;;;;:::o;13222:350::-;13424:2;13406:21;;;13463:2;13443:18;;;13436:30;-1:-1:-1;;;13497:2:1;13482:18;;13475:56;13563:2;13548:18;;13222:350::o;13577:342::-;13779:2;13761:21;;;13818:2;13798:18;;;13791:30;-1:-1:-1;;;13852:2:1;13837:18;;13830:48;13910:2;13895:18;;13577:342::o;13924:385::-;-1:-1:-1;;;;;14176:15:1;;;14158:34;;14235:14;;14228:22;14223:2;14208:18;;14201:50;14287:15;;;14282:2;14267:18;;14260:43;14108:2;14093:18;;13924:385::o;15926:478::-;-1:-1:-1;;;;;16151:32:1;;16133:51;;16220:2;16215;16200:18;;16193:30;;;-1:-1:-1;;16246:44:1;;16271:18;;16263:6;16246:44;:::i;:::-;16338:9;16330:6;16326:22;16321:2;16310:9;16306:18;16299:50;16366:32;16391:6;16383;16366:32;:::i;:::-;16358:40;15926:478;-1:-1:-1;;;;;;15926:478:1:o;17616:288::-;17791:2;17780:9;17773:21;17754:4;17811:44;17851:2;17840:9;17836:18;17828:6;17811:44;:::i;:::-;17803:52;;17891:6;17886:2;17875:9;17871:18;17864:34;17616:288;;;;;:::o;17909:245::-;17976:6;18029:2;18017:9;18008:7;18004:23;18000:32;17997:52;;;18045:1;18042;18035:12;17997:52;18077:9;18071:16;18096:28;18118:5;18096:28;:::i;18983:236::-;19037:5;19090:3;19083:4;19075:6;19071:17;19067:27;19057:55;;19108:1;19105;19098:12;19057:55;19130:83;19209:3;19200:6;19194:13;19187:4;19179:6;19175:17;19130:83;:::i;19224:337::-;19304:6;19357:2;19345:9;19336:7;19332:23;19328:32;19325:52;;;19373:1;19370;19363:12;19325:52;19400:16;;-1:-1:-1;;;;;19428:30:1;;19425:50;;;19471:1;19468;19461:12;19425:50;19494:61;19547:7;19538:6;19527:9;19523:22;19494:61;:::i;19566:274::-;19740:25;;;-1:-1:-1;;;;;19801:32:1;19796:2;19781:18;;19774:60;19728:2;19713:18;;19566:274::o;21046:127::-;21107:10;21102:3;21098:20;21095:1;21088:31;21138:4;21135:1;21128:15;21162:4;21159:1;21152:15;21178:125;21243:9;;;21264:10;;;21261:36;;;21277:18;;:::i;21308:319::-;21510:25;;;21566:2;21551:18;;21544:34;;;;21609:2;21594:18;;21587:34;21498:2;21483:18;;21308:319::o;21982:128::-;22049:9;;;22070:11;;;22067:37;;;22084:18;;:::i;22459:698::-;22575:6;22583;22591;22644:2;22632:9;22623:7;22619:23;22615:32;22612:52;;;22660:1;22657;22650:12;22612:52;22692:9;22686:16;22711:31;22736:5;22711:31;:::i;:::-;22810:2;22795:18;;22789:25;22761:5;;-1:-1:-1;;;;;;22863:14:1;;;22860:34;;;22890:1;22887;22880:12;22860:34;22913:61;22966:7;22957:6;22946:9;22942:22;22913:61;:::i;:::-;22903:71;;23020:2;23009:9;23005:18;22999:25;22983:41;;23049:2;23039:8;23036:16;23033:36;;;23065:1;23062;23055:12;23033:36;;23088:63;23143:7;23132:8;23121:9;23117:24;23088:63;:::i;25217:842::-;25345:3;25374:1;25407:6;25401:13;25437:36;25463:9;25437:36;:::i;:::-;25492:1;25509:18;;;25536:133;;;;25683:1;25678:356;;;;25502:532;;25536:133;-1:-1:-1;;25569:24:1;;25557:37;;25642:14;;25635:22;25623:35;;25614:45;;;-1:-1:-1;25536:133:1;;25678:356;25709:6;25706:1;25699:17;25739:4;25784:2;25781:1;25771:16;25809:1;25823:165;25837:6;25834:1;25831:13;25823:165;;;25915:14;;25902:11;;;25895:35;25958:16;;;;25852:10;;25823:165;;;25827:3;;;26017:6;26012:3;26008:16;26001:23;;25502:532;-1:-1:-1;26050:3:1;;25217:842;-1:-1:-1;;;;;;25217:842:1:o;26064:812::-;-1:-1:-1;;;26470:3:1;26463:38;26445:3;26530:6;26524:13;26546:75;26614:6;26609:2;26604:3;26600:12;26593:4;26585:6;26581:17;26546:75;:::i;:::-;-1:-1:-1;;;26680:2:1;26640:16;;;26672:11;;;26665:40;26730:13;;26752:76;26730:13;26814:2;26806:11;;26799:4;26787:17;;26752:76;:::i;:::-;26848:17;26867:2;26844:26;;26064:812;-1:-1:-1;;;;26064:812:1:o;27782:168::-;27855:9;;;27886;;27903:15;;;27897:22;;27883:37;27873:71;;27924:18;;:::i;27955:127::-;28016:10;28011:3;28007:20;28004:1;27997:31;28047:4;28044:1;28037:15;28071:4;28068:1;28061:15;28087:136;28126:3;28154:5;28144:39;;28163:18;;:::i;:::-;-1:-1:-1;;;28199:18:1;;28087:136::o
Swarm Source
ipfs://547400ff5095ccebc670c9e42e6caf8e64bcc952bd62e9cf1d4e150afb05ac8b
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
[ 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.