ERC-20
Gaming
Overview
Max Total Supply
291,708 BEC
Holders
213 (0.00%)
Market
Onchain Market Cap
$0.00
Circulating Supply Market Cap
-
Other Info
Token Contract (WITH 18 Decimals)
Balance
999 BECValue
$0.00Loading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Source Code Verified (Exact Match)
Contract Name:
BECCore
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// contracts/BECCore.sol // SPDX-License-Identifier: MIT /** /3333333 /33333333 /333333 | 33__ 33 | 33_____/ /33__ 33 | 33 \ 33 | 33 | 33 \__/ | 3333333 | 33333 | 33 | 33__ 33 | 33__/ | 33 | 33 \ 33 | 33 | 33 33 | 3333333/ | 33333333 | 333333/ |_______/ |________/ \______/ # https://blackeyedcreatures.com */ pragma solidity ^0.8.25; import {ERC404B} from "./erc404/ERC404B.sol"; import {BECURIStorage} from "./BECURIStorage.sol"; /** * @title Black Eyed Creatures Core Contract * @dev This is the base contract for Black Eyed Creatures (BEC). * @author https://42i.co */ contract BECCore is BECURIStorage { /// @dev Role constants for managing access to specific methods. bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); /// @dev Mapping between creature ID and the seed that generates its DNA. /// 0: Type (8, 3bit), Strategy (32, 5bit), Generation (4, 2bit), Seed (212bit) mapping(uint256 creatureId => bytes32 seed) internal creatureSeed; /// @dev Constructor initializes the ERC404 token with name "Black Eyed Creatures" and symbol "BEC". constructor() ERC404B("Black Eyed Creatures", "BEC", 333) { _setRoleAdmin(MINTER_ROLE, GENETICIST); } /** * @notice Mints new creatures with given DNA seeds for a specified address. * @dev Only addresses with MINTER_ROLE can call this function. * @param _creatureOwner Address of the new owner of the minted creatures. * @param _seed A seed value used to generate creature DNAs. * @param _quantity Quantity of minted creatures. * @return creatureIds Array of IDs for the newly minted creatures. */ function mintWithSeed( address _creatureOwner, bytes32 _seed, uint256 _quantity ) public payable onlyRole(MINTER_ROLE) returns (uint256[] memory) { if (_quantity == 0) revert BECZeroQuantityMinting(); uint256 baseCreatureId = nextTokenId(); if (baseCreatureId + _quantity > 133333) revert BECCapLimitReached(); uint256[] memory mintedCreatureIds = new uint256[](_quantity); _mint(_creatureOwner, _quantity); creatureSeed[baseCreatureId] = _seed; for (uint256 i = 0; i < _quantity; i++) { mintedCreatureIds[i] = baseCreatureId + i; } return mintedCreatureIds; } /** * @notice Retrieves the next available token ID for minting new creatures. * @dev This function returns the token ID that will be assigned to the next minted creature. * @return uint256 Next available token ID. */ function nextTokenId() public view virtual returns (uint256) { return _nextTokenId; } /** * @notice Retrieves the seed of a creature by ID. * @param _creatureId ID of the creature. * @return bytes32 Seed of the creatures. */ function getSeed(uint256 _creatureId) public view returns (bytes32) { bytes32 seed = 0; for (uint256 i = 0; seed == 0; i++) { seed = creatureSeed[_creatureId - i]; } return seed; } /** * @notice Retrieves the seeds of a set creatures by ID. * @param _creatureIds ID of the creatures. * @return bytes32[] Seeds of the creatures. */ function getSeeds(uint256[] calldata _creatureIds) public view returns (bytes32[] memory) { bytes32[] memory seeds = new bytes32[](_creatureIds.length); for (uint256 j = 0; j < _creatureIds.length; j++) { seeds[j] = getSeed(_creatureIds[j]); } return seeds; } /** * @notice Retrieves the total number of tokens currently in circulation. * @dev This function returns the total count of tokens that have been minted and are currently in existence. * @return uint256 Total number of tokens in circulation. */ function totalTokens() public view returns (uint256) { return _totalTokens(); } /** * @notice Burns a creature by ID. * @dev Only owner or approved senders can call this function. * @param _creatureId ID of the creature to be burned. */ function burn(uint256 _creatureId) public { if (!_isApprovedOrOwner(msg.sender, _creatureId)) revert ERC721InsufficientApproval(msg.sender, _creatureId); _burn(_creatureId); } /** * @notice Retrieves the number of creatures that have been burned. * @return uint256 Number of burned creatures. */ function burned() public view returns (uint256) { return _burned(); } /** * @dev Forces the exemption status for ERC-721 transfers for the caller. * This function can only be called by the owner, and is created for setting as exempt DEXs & LPs. * An address that is not a contract, cannot be forced. * * Emits: * - {Transfer} event for each target_ ERC721 token from/to the stash. * * @param _target The address to be setted as exempt. * @param _state The new exemption state to set (true for exempt, false for non-exempt). */ function forceERC721TransferExempt(address _target, bool _state) external onlyOwner { if (_target.code.length == 0) revert BECInvalidAddress(_target); _setERC721TransferExempt(_target, _state); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol) pragma solidity ^0.8.20; import {IAccessControl} from "./IAccessControl.sol"; import {Context} from "../utils/Context.sol"; import {ERC165} from "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address account => bool) hasRole; bytes32 adminRole; } mapping(bytes32 role => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with an {AccessControlUnauthorizedAccount} error including the required role. */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual returns (bool) { return _roles[role].hasRole[account]; } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()` * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier. */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account` * is missing `role`. */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert AccessControlUnauthorizedAccount(account, role); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address callerConfirmation) public virtual { if (callerConfirmation != _msgSender()) { revert AccessControlBadConfirmation(); } _revokeRole(role, callerConfirmation); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual returns (bool) { if (!hasRole(role, account)) { _roles[role].hasRole[account] = true; emit RoleGranted(role, account, _msgSender()); return true; } else { return false; } } /** * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual returns (bool) { if (hasRole(role, account)) { _roles[role].hasRole[account] = false; emit RoleRevoked(role, account, _msgSender()); return true; } else { return false; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol) pragma solidity ^0.8.20; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev The `account` is missing a role. */ error AccessControlUnauthorizedAccount(address account, bytes32 neededRole); /** * @dev The caller of a function is not the expected one. * * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}. */ error AccessControlBadConfirmation(); /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, 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 `callerConfirmation`. */ function renounceRole(bytes32 role, address callerConfirmation) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @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. * * The initial owner is set to the address provided by the deployer. 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; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @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 { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling 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 { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _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); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) pragma solidity ^0.8.20; /** * @dev Standard ERC20 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens. */ interface IERC20Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC20InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC20InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. * @param spender Address that may be allowed to operate on tokens without being their owner. * @param allowance Amount of tokens a `spender` is allowed to operate with. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC20InvalidApprover(address approver); /** * @dev Indicates a failure with the `spender` to be approved. Used in approvals. * @param spender Address that may be allowed to operate on tokens without being their owner. */ error ERC20InvalidSpender(address spender); } /** * @dev Standard ERC721 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens. */ interface IERC721Errors { /** * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20. * Used in balance queries. * @param owner Address of the current owner of a token. */ error ERC721InvalidOwner(address owner); /** * @dev Indicates a `tokenId` whose `owner` is the zero address. * @param tokenId Identifier number of a token. */ error ERC721NonexistentToken(uint256 tokenId); /** * @dev Indicates an error related to the ownership over a particular token. Used in transfers. * @param sender Address whose tokens are being transferred. * @param tokenId Identifier number of a token. * @param owner Address of the current owner of a token. */ error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC721InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC721InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param tokenId Identifier number of a token. */ error ERC721InsufficientApproval(address operator, uint256 tokenId); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC721InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC721InvalidOperator(address operator); } /** * @dev Standard ERC1155 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens. */ interface IERC1155Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. * @param tokenId Identifier number of a token. */ error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC1155InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC1155InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param owner Address of the current owner of a token. */ error ERC1155MissingApprovalForAll(address operator, address owner); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC1155InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC1155InvalidOperator(address operator); /** * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. * Used in batch transfers. * @param idsLength Length of the array of token identifiers * @param valuesLength Length of the array of token amounts */ error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.20; import {IERC721} from "../IERC721.sol"; /** * @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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @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 address zero. * * 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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.20; /** * @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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.20; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS } /** * @dev The signature derives the `address(0)`. */ error ECDSAInvalidSignature(); /** * @dev The signature has an invalid length. */ error ECDSAInvalidSignatureLength(uint256 length); /** * @dev The signature has an S value that is in the upper half order. */ error ECDSAInvalidSignatureS(bytes32 s); /** * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not * return address(0) without also returning an error description. Errors are documented using an enum (error type) * and a bytes32 providing additional information about the error. * * If no error is returned, then the address can be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length)); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) { unchecked { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); // We do not check for an overflow here since the shift operation results in 0 or 1. uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError, bytes32) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS, s); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature, bytes32(0)); } return (signer, RecoverError.NoError, bytes32(0)); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s); _throwError(error, errorArg); return recovered; } /** * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided. */ function _throwError(RecoverError error, bytes32 errorArg) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert ECDSAInvalidSignature(); } else if (error == RecoverError.InvalidSignatureLength) { revert ECDSAInvalidSignatureLength(uint256(errorArg)); } else if (error == RecoverError.InvalidSignatureS) { revert ECDSAInvalidSignatureS(errorArg); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement 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); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @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 towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (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 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 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. uint256 twos = denominator & (0 - denominator); 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 (unsignedRoundsUp(rounding) && 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 * towards zero. * * 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 + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * 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 + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * 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 + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * 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 256, 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 + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @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), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @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) { uint256 localValue = value; 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] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } 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); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// contracts/BECAccessControl.sol // SPDX-License-Identifier: MIT /** /3333333 /33333333 /333333 | 33__ 33 | 33_____/ /33__ 33 | 33 \ 33 | 33 | 33 \__/ | 3333333 | 33333 | 33 | 33__ 33 | 33__/ | 33 | 33 \ 33 | 33 | 33 33 | 3333333/ | 33333333 | 333333/ |_______/ |________/ \______/ # https://blackeyedcreatures.com */ pragma solidity ^0.8.25; import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; /** * @title Black Eyed Creatures Access Control * @author https://42i.co */ abstract contract BECAccessControl is AccessControl { /// @dev Role identifier for the GENETICIST role. bytes32 public constant GENETICIST = keccak256("GENETICIST"); /// @dev Constructor grants the GENETICIST role to the address deploying the contract. constructor() { _setRoleAdmin(GENETICIST, GENETICIST); _grantRole(GENETICIST, msg.sender); } }
// contracts/BECEnabler.sol // SPDX-License-Identifier: MIT /** /3333333 /33333333 /333333 | 33__ 33 | 33_____/ /33__ 33 | 33 \ 33 | 33 | 33 \__/ | 3333333 | 33333 | 33 | 33__ 33 | 33__/ | 33 | 33 \ 33 | 33 | 33 33 | 3333333/ | 33333333 | 333333/ |_______/ |________/ \______/ # https://blackeyedcreatures.com */ pragma solidity ^0.8.25; import {BECWithdrawable} from "./BECWithdrawable.sol"; /** * @title Black Eyed Creatures Enabler * @author https://42i.co */ contract BECEnabler is BECWithdrawable { event BECEnabled(address contractAddress); /// @dev Internal state variable to track whether the BEC ecosystem is enabled. bool internal enabled = false; /** * @notice Checks whether the contract enabled. * @return bool True if the contract is enabled, false otherwise. */ function isEnabled() external view returns (bool) { return enabled; } /** * @notice Enables the BEC ecosystem functionalities. * @dev Sets the internal `enabled` state variable to true, activating the functionalities of the BEC ecosystem that depend on this state. * This action can typically control the operational state of various contract features, such as minting or token transfers. */ function enable() external onlyOwner { enabled = true; emit BECEnabled(address(this)); } }
// contracts/BECGenesisEngine.sol // SPDX-License-Identifier: MIT /** /3333333 /33333333 /333333 | 33__ 33 | 33_____/ /33__ 33 | 33 \ 33 | 33 | 33 \__/ | 3333333 | 33333 | 33 | 33__ 33 | 33__/ | 33 | 33 \ 33 | 33 | 33 33 | 3333333/ | 33333333 | 333333/ |_______/ |________/ \______/ # http://blackeyedcreatures.com */ pragma solidity ^0.8.25; import {BECCore} from "./BECCore.sol"; import {BECLab} from "./BECLab.sol"; import {BECWithdrawable} from "./BECWithdrawable.sol"; import {BECAccessControl} from "./BECAccessControl.sol"; import {IBECDnaStrategy} from "./strategies/IBECDnaStrategy.sol"; import {IBECMetaExtension} from "./meta-extensions/IBECMetaExtension.sol"; import {IERC721Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; /** * @title Black Eyed Creatures Genesis Engine Contract * @notice Orchestrates the unveiling of creature DNA within the Black Eyed Creatures universe. * @dev Manages the revelation of creature DNA based on different logics. * @author https://42i.co */ contract BECGenesisEngine is BECWithdrawable, BECAccessControl, IERC721Errors { /// @dev A constant identifier for the role that is permitted to update the genesis storage. bytes32 public constant GENESIS_STORAGE_UPDATER = keccak256("GENESIS_STORAGE_UPDATER"); /// @dev Core contract address. address private immutable coreContractAddress; /// @dev Nested mapping structure to store the probability information of each variation for each phenotype and family, represented bitwise. /// The outermost mapping categorizes by [distribution]. /// The intermediate mapping categorizes by [phenotype]. /// The innermost mapping categorizes by [family]. /// The uint256 value associated with each [distribution][phenotype][family] contains: /// - familyTickets (32b): Represents the quantity of tickets allocated to this specific family, influencing the probability of selection. /// - variationsCount (8b): Indicates the total number of variations available within the family. /// - variationExponent (3b): Specifies the bit length used to represent the rarity of each family and variation. This value acts as an exponent for calculating their respective ticket quantities. mapping(uint256 distribution => mapping(uint256 phenotype => mapping(uint256 family => uint256 tickets))) public tickets; /// @dev A mapping storing uint256s, each containing 32-bit segments representing the total tickets for each phenotype in a specific distribution. mapping(uint256 distribution => uint256 tickets) public phenotypeTickets; /// @dev A mapping to store specific data associated with each creature, indexed by the creature's ID. mapping(uint256 creatureId => uint256 value) public genesisStorage; /// @dev A mapping that associates each dna strategy with a strategy contract address, indexed by the strategy ID. mapping(uint256 strategyId => address contractAddress) public dnaStrategies; /// @dev An array of metadata extensions. IBECMetaExtension[] public extensions; /** * @notice Initializes the Genesis Engine. * @dev Sets the coreContractAddress to the provided BEC core contract address. * @param _becCore The address of the BEC core contract. */ constructor(address _becCore) { coreContractAddress = _becCore; _setRoleAdmin(GENESIS_STORAGE_UPDATER, GENETICIST); } /** * @notice Sets the genesis storage value for a specific creature. * @dev The function requires that the storage value for the creature has not been set previously. It can only be called by an address with the GENESIS_STORAGE_UPDATER role. * @param _creatureId The ID of the creature for which the storage value is to be set. * @param _value The value to be stored. */ function setGenesisStorage(uint256 _creatureId, uint256 _value) public onlyRole(GENESIS_STORAGE_UPDATER) { if (genesisStorage[_creatureId] != 0) revert BECGenesisStoreAlreadySet(_creatureId); genesisStorage[_creatureId] = _value; } /** * @notice Retrieves the DNA of a specific creature. * @dev The function fetches the seed associated with the creature from the core contract, * determines the strategy using the seed, and then retrieves the DNA using the strategy. * It requires that the creature with the given ID exists. * @param _creatureId The ID of the creature whose DNA is to be retrieved. * @return uint256 The DNA of the specified creature. */ function getDna(uint256 _creatureId) public view returns (uint256) { BECCore coreContract = BECCore(payable(coreContractAddress)); if (!coreContract.exists(_creatureId)) revert ERC721NonexistentToken(_creatureId); bytes32 seed = coreContract.getSeed(_creatureId); IBECDnaStrategy strategy = IBECDnaStrategy(dnaStrategies[uint256(uint8(seed[0]) >> 3) & 0x1F]); return strategy.getDna(_creatureId); } /** * @notice Retrieves the token URI of a specific creature. * @dev The function fetches the seed associated with the creature from the core contract, determines the strategy using the seed, and then retrieves the token URI using the strategy. * @param _creatureId The ID of the creature whose token URI is to be retrieved. * @return string The token URI of the specified creature. */ function tokenURI(uint256 _creatureId) public view returns (string memory) { BECCore coreContract = BECCore(payable(coreContractAddress)); bytes32 seed = coreContract.getSeed(_creatureId); IBECDnaStrategy strategy = IBECDnaStrategy(dnaStrategies[uint256(uint8(seed[0]) >> 3) & 0x1F]); return strategy.tokenURI(_creatureId); } /** * @notice Retrieves the genesis storage value for a specific creature. * @dev Returns the stored value associated with the given creature ID from the genesisStorage mapping. * @param _creatureId The ID of the creature whose genesis storage value is to be retrieved. * @return uint256 The genesis storage value of the specified creature. */ function getGenesisStorage(uint256 _creatureId) public view returns (uint256) { return genesisStorage[_creatureId]; } /** * @notice Retrieves the amount of tickets of a family for a specific phenotype within a given distribution ID. * @dev Accesses the tickets mapping with the provided _distribution, _phenotype, and _family to return the associated family ticket information. * @param _distribution The distribution identifier. * @param _phenotype The phenotype identifier. * @param _family The family identifier within the phenotype. * @return uint256 The family ticket information of the specified phenotype and family. */ function getFamilyTickets(uint256 _distribution, uint256 _phenotype, uint256 _family) public view returns (uint256) { return tickets[_distribution][_phenotype][_family] & 0xFFFFFFFF; } /** * @notice Retrieves the amount of tickets of a variation for a specific phenotype and family within a given distribution ID. * @dev Calculates the variation ticket information based on the stored ticket information and the provided _variation. * @param _distribution The distribution identifier. * @param _phenotype The phenotype identifier. * @param _family The family identifier within the phenotype. * @param _variation The variation identifier within the family. * @return uint256 The variation ticket information of the specified phenotype, family, and variation. */ function getVariationTickets(uint256 _distribution, uint256 _phenotype, uint256 _family, uint256 _variation) public view returns (uint256) { return 1 << ((tickets[_distribution][_phenotype][_family] >> (40 + (_variation * 3))) & 0x7); } /** * @notice Retrieves the count of variations for a specific phenotype and family within a given distribution ID. * @dev Calculates the variations count based on the stored ticket information. * @param _distribution The distribution identifier. * @param _phenotype The phenotype identifier. * @param _family The family identifier within the phenotype. * @return uint256 The count of variations for the specified phenotype and family. */ function getVariationsCount(uint256 _distribution, uint256 _phenotype, uint256 _family) public view returns (uint256) { return (tickets[_distribution][_phenotype][_family] >> 32) & 0xFF; } /** * @notice Retrieves the total number of tickets for each phenotype within a given distribution. * @dev Accesses the ticketsPerPhenotype mapping with the provided _distribution ID to return the associated ticket count. * @param _distribution The ID of the distribution. * @return uint256 The total number of tickets for each phenotype in the specified distribution. */ function getPhenotypeTickets(uint256 _distribution) public view returns (uint256) { return phenotypeTickets[_distribution]; } /** * @notice Adds ticket information for a specific distribution. * @dev Requires that the distribution has not been previously set. Iterates through the _tickets parameter to populate the tickets mapping for the given distribution. Can only be called by an address with the GENETICIST role. * @param _distribution The ID of the distribution to which the tickets are to be added. * @param _phenotypeTickets The total number of tickets for each phenotype within the distribution. * @param _tickets A two-dimensional array representing the ticket information to be added for each phenotype and family. */ function addTickets(uint256 _distribution, uint256 _phenotypeTickets, uint256[][] memory _tickets) public onlyRole(GENETICIST) { if (phenotypeTickets[_distribution] != 0) revert BECDistributionAlreadySet(_distribution); phenotypeTickets[_distribution] = _phenotypeTickets; for (uint256 i = 0; i < _tickets.length; i++) { for (uint256 j = 0; j < _tickets[i].length; j++) { tickets[_distribution][i][j] = _tickets[i][j]; } } } /** * @notice Registers a DNA strategy for a distribution. * @dev Can only be called by an address with the GENETICIST role. * @param _dnaStrategy The address of the DNA strategy contract to be registered. */ function registerStrategy(address _dnaStrategy) public onlyRole(GENETICIST) { IBECDnaStrategy dnaStrategy = IBECDnaStrategy(_dnaStrategy); uint256 distributionId = dnaStrategy.getDistributionId(); if (tickets[distributionId][0][0] == 0) revert BECWrongDistributionId(distributionId); uint256 strategyId = dnaStrategy.getStrategyId(); dnaStrategies[strategyId] = _dnaStrategy; } /** * @notice Adds a new metadata extension to the Genesis Engine. * @dev Appends a new extension contract address to the `extensions` array. * This function can only be invoked by an address with the GENETICIST role. * Each extension should implement the IBECMetaExtension interface. * @param _extensionAddress The address of the metadata extension contract to add. */ function addExtension(address _extensionAddress) public onlyRole(GENETICIST) { IBECMetaExtension extension = IBECMetaExtension(_extensionAddress); extensions.push(extension); } /** * @notice Clears all registered metadata extensions from the Genesis Engine. * @dev Deletes the `extensions` array, effectively removing all metadata extension contracts. * This action cannot be undone. This function can only be invoked by an address with the GENETICIST role. */ function clearExtensions() public onlyRole(GENETICIST) { delete extensions; } /** * @notice Retrieves the addresses of all registered metadata extensions. * @dev Returns an array of addresses for each metadata extension contract currently registered in the `extensions` array. * @return An array of IBECMetaExtension contract addresses currently registered. */ function getExtensions() external view returns (IBECMetaExtension[] memory) { return extensions; } }
// contracts/BECLab.sol // SPDX-License-Identifier: MIT /** /3333333 /33333333 /333333 | 33__ 33 | 33_____/ /33__ 33 | 33 \ 33 | 33 | 33 \__/ | 3333333 | 33333 | 33 | 33__ 33 | 33__/ | 33 | 33 \ 33 | 33 | 33 33 | 3333333/ | 33333333 | 333333/ |_______/ |________/ \______/ # https://blackeyedcreatures.com */ pragma solidity ^0.8.25; import {BECCore} from "./BECCore.sol"; import {BECEnabler} from "./BECEnabler.sol"; import {BECAccessControl} from "./BECAccessControl.sol"; import {BECGenesisEngine} from "./BECGenesisEngine.sol"; import {EIP712} from "./eip712/EIP712.sol"; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import {IERC721Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; /** * @title Black Eyed Creatures Lab Contract * @author https://42i.co */ contract BECLab is BECEnabler, BECAccessControl, EIP712, IERC721Errors { using ECDSA for bytes32; event FamilyNameSet(uint256 indexed phenotype, uint256 indexed family, uint256[] ambassadors, string name); event VariationNameSet(uint256 indexed phenotype, uint256 indexed family, uint256 indexed variation, uint256[] ambassadors, string name); event CreatureNameSet(uint256 indexed creatureId, string name); /// @dev Core contract address. address private immutable coreContractAddress; /// @dev Genesis engine contract address. address private immutable genesisEngineAddress; /// @dev Blcksphr contract address. address private immutable blcksphrsAddress; /// @dev Mapping of the lab registry /// Structure: /// [bucket] each bucket stores 8 creature registries, of 4 bytes each /// - isVariationAmbassador (1bit) /// - isFamilyAmbassador (1bit) /// - ambassadorPhenotype (3bit) /// - ambassadorFamily (5bit) /// - ambassadorVariation (6bit) /// - omegas (16bit) mapping(uint256 bucket => uint256 registries) internal labRegistry; /// @dev Mapping that keeps track of each family name. mapping(uint256 phenotype => mapping(uint256 family => string name)) public familyNames; /// @dev Mapping that keeps track of each variation name. mapping(uint256 phenotype => mapping(uint256 family => mapping(uint256 variation => string name))) public variationNames; /// @dev Names of the creatures. mapping(uint256 creatureId => string name) public names; /// @dev Hash of names, and if they are used or not (default not). mapping(bytes32 nameHash => bool isUsed) internal nameUsed; /// @dev Mapping storing the amount of families and variations set by the address. mapping(address caller => uint256 count) public familyVariationAndNamesSet; /// @dev A constant identifier for the role that is permitted to update the lab register. bytes32 public constant LAB_REGISTER_UPDATER = keccak256("LAB_REGISTER_UPDATER"); /// @dev The typehash for the data type specified in the family structured data. /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#rationale-for-typehash bytes32 public constant VERIFY_FAMILY_TYPEHASH = keccak256("VerifyFamilyName(uint256 phenotype,uint256 family,uint256[] ambassadors,string name,address wallet)"); /// @dev The typehash for the data type specified in the variation structured data. /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#rationale-for-typehash bytes32 public constant VERIFY_VARIATION_TYPEHASH = keccak256("VerifyVariationName(uint256 phenotype,uint256 family,uint256 variation,uint256[] ambassadors,string name,address wallet)"); /** * @dev Constructor for the Lab contract. * @param _becCore The core contract address. * @param _becGenesisEngine The genesis engine contract address. * @param _blcksphrsAddress The blcksphr contract address. */ constructor(address _becCore, address _becGenesisEngine, address _blcksphrsAddress) { coreContractAddress = _becCore; genesisEngineAddress = _becGenesisEngine; blcksphrsAddress = _blcksphrsAddress; _setRoleAdmin(LAB_REGISTER_UPDATER, GENETICIST); } /** * @notice Checks if a variation name proposal meets the necessary criteria for a given phenotype, family, and variation. * @dev This function examines the validity of a name proposal for a variation by assessing the criteria regarding * the phenotype, family, variation, and the three proposed ambassador creatures. * A successful execution of this function indicates the name proposal meets all established conditions. * @param _phenotype The phenotype within which the family resides. * @param _family The family within which the variation exists. * @param _variation The specific variation for which the name validity is being verified. * @param _ambassadorIds The 3 ambassador ids. * @param _name The proposed name for the variation. * * Requirements: * - Phenotype number must be less than 6. * - Name length should be up to 8 characters. * - Name must be alphanumeric. * - The proposed ambassador creatures must be distinct. * - The creatures cannot already be variation ambassadors. * - Each proposed ambassador must be associated with the specified phenotype, family, and variation. */ function verifyVariationName( uint256 _phenotype, uint256 _family, uint256 _variation, uint256[] memory _ambassadorIds, string memory _name ) public view { // Verify basics if (_phenotype > 5) revert BECInvalidPhenotype(_phenotype); if (bytes(_name).length > 8 || bytes(_name).length == 0) revert BECInvalidName(_name); if (!isAZ(bytes(_name))) revert BECInvalidName(_name); if (nameUsed[keccak256(abi.encodePacked(_name))]) revert BECDuplicatedName(_name); if (_ambassadorIds.length != 3) revert BECInvalidAmbassadorsLength(_ambassadorIds.length); if (bytes(variationNames[_phenotype][_family][_variation]).length != 0) revert BECVariationNameAlreadySet(_phenotype, _family, _variation); // Verify creatures if ( _ambassadorIds[0] == _ambassadorIds[1] || _ambassadorIds[0] == _ambassadorIds[2] || _ambassadorIds[1] == _ambassadorIds[2] ) revert BECInvalidAmbassadors(_ambassadorIds[0], _ambassadorIds[1], _ambassadorIds[2]); // Verifying ambassadors and family & variation for each creature for (uint256 i = 0; i < 3; i++) { uint256 registry = (labRegistry[_ambassadorIds[i] / 8] >> ((_ambassadorIds[i] % 8) * 32)) & 0xFFFFFFFF; if (registry & 0x1 != 0) revert BECAlreadyVariationAmbassador(_ambassadorIds[i]); verifyFamilyAndVariation(_phenotype, _family, _variation, _ambassadorIds[i]); } } /** * @notice Verifies if a creature's family and variation match the provided family and variation within a specified phenotype. * @dev Extracts the creature's DNA related to the provided phenotype. It then verifies if the extracted DNA matches the provided family and variation. * A successful execution indicates that the creature has the expected family and variation within the specified phenotype. * @param _phenotype The phenotype within which the family and variation reside. * @param _family The expected family of the creature within the given phenotype. * @param _variation The expected variation of the creature within the provided family. * @param _creatureId The ID of the creature (creature) to be verified. * * Requirements: * - The creature's family and variation, as determined from its DNA for the given phenotype, must match `_family` and `_variation` respectively. */ function verifyFamilyAndVariation( uint256 _phenotype, uint256 _family, uint256 _variation, uint256 _creatureId ) internal view { unchecked { uint256 phenotypeTraits = BECGenesisEngine(payable(genesisEngineAddress)).getDna(_creatureId) >> ((_phenotype * 16)); uint256 dnaVariation = (phenotypeTraits >> 8) & 0xFF; uint256 dnaFamily = (phenotypeTraits) & 0xFF; if (dnaFamily != _family) revert BECInvalidFamily(_creatureId); if (dnaVariation != _variation) revert BECInvalidVariation(_creatureId); } } /** * @notice Allows a user to propose a name for a variation by specifying the phenotype, family, variation, ambassador creatures, * and the name itself. * @dev This function allows users to suggest a name for a specific variation by proposing three creatures as ambassadors. * Before calling this function, users should call verifyVariationNameProposal() with the same parameters * to ensure that the proposal is valid. * The proposal will be checked by a validator backend after submission. * The proposal is validated through a signature. If the proposal meets all criteria, the name is set for the variation. * @param _phenotype The phenotype within which the family resides. * @param _family The family within which the variation exists. * @param _variation The specific variation for which a name is being proposed. * @param _ambassadorIds An array of ambassador creature IDs proposed for the naming. * @param _name The proposed name for the variation. * * Requirements: * - Phenotype number must be less than 6. * - Name length should be up to 8 characters. * - Name must be alphanumeric. * - The proposal price must be met. * - The caller must own all three proposed ambassador creatures. * - The proposed ambassador creatures must be distinct. * - The creatures cannot already be variation ambassadors. * - There shouldn't be a pre-existing name or proposal for the specified variation. */ function setVariationName( uint256 _phenotype, uint256 _family, uint256 _variation, uint256[] memory _ambassadorIds, string memory _name, bytes calldata _signature ) public { if (!enabled) revert BECNotEnabled(); // Verify basics if (!validateVariationSignature(_phenotype, _family, _variation, _ambassadorIds, _name, _signature)) revert EIP712InvalidSignature(_signature); if (bytes(_name).length > 8 || bytes(_name).length == 0) revert BECInvalidName(_name); if (nameUsed[keccak256(abi.encodePacked(_name))]) revert BECDuplicatedName(_name); if (bytes(variationNames[_phenotype][_family][_variation]).length != 0) revert BECVariationNameAlreadySet(_phenotype, _family, _variation); BECCore coreContract = BECCore(payable(coreContractAddress)); for (uint256 i = 0; i < 3; i++) { // Verify ownership if (msg.sender != coreContract.ownerOf(_ambassadorIds[i])) revert BECInvalidOwner(msg.sender, _ambassadorIds[i]); // Verifying creature was not used for being ambassador uint256 registry = (labRegistry[_ambassadorIds[i] / 8] >> ((_ambassadorIds[i] % 8) * 32)) & 0xFFFFFFFF; if (registry & 0x1 != 0) revert BECAlreadyVariationAmbassador(_ambassadorIds[i]); // Setting creature as ambassador in the registry setVariationAmbassadorToRegistry(_ambassadorIds[i], _phenotype, _family, _variation); } // Set variation name variationNames[_phenotype][_family][_variation] = _name; nameUsed[keccak256(abi.encodePacked(_name))] = true; familyVariationAndNamesSet[msg.sender] += 1; emit VariationNameSet(_phenotype, _family, _variation, _ambassadorIds, _name); } /** * @notice Validates the signature for a variation name proposal. * @dev Checks if the provided signature is valid for the given variation name proposal details. * @param _phenotype The phenotype ID involved in the proposal. * @param _family The family ID involved in the proposal. * @param _variation The variation ID for which the name is proposed. * @param _ambassadorIds The IDs of the ambassador creatures proposed. * @param _name The proposed name for the variation. * @param _signature The signature to validate. * @return bool Returns true if the signature is valid, false otherwise. */ function validateVariationSignature( uint256 _phenotype, uint256 _family, uint256 _variation, uint256[] memory _ambassadorIds, string memory _name, bytes calldata _signature ) internal view returns (bool) { if (allowlistSigningKey == address(0)) revert EIP712BECSigningKeyNotSet(); bytes32 digest = keccak256( abi.encodePacked( "\x19\x01", EIP712_DOMAIN_SEPARATOR, keccak256( abi.encode( VERIFY_VARIATION_TYPEHASH, _phenotype, _family, _variation, keccak256(abi.encodePacked(_ambassadorIds)), keccak256(bytes(_name)), msg.sender ) ) ) ); address recoveredAddress = digest.recover(_signature); return recoveredAddress == allowlistSigningKey; } /** * @notice Updates the registry entry to set the creature as a variation ambassador. * @dev This function performs bitwise operations on the provided registry entry to indicate * that the creature is now an ambassador for a specified variation. It updates and returns * the modified registry entry by setting the appropriate bits based on the phenotype, family, * and variation passed as arguments. * @param _creatureId The creature Id. * @param _variationAmbassadorPhenotype The phenotype associated with the variation ambassador. * @param _variationAmbassadorFamily The family associated with the variation ambassador. * @param _variationAmbassadorVariation The specific variation the creature is an ambassador for. */ function setVariationAmbassadorToRegistry( uint256 _creatureId, uint256 _variationAmbassadorPhenotype, uint256 _variationAmbassadorFamily, uint256 _variationAmbassadorVariation ) private { unchecked { labRegistry[_creatureId / 8] |= (1 | (_variationAmbassadorPhenotype << 2) | (_variationAmbassadorFamily << 5) | (_variationAmbassadorVariation << 10)) << ((_creatureId % 8) * 32); } } /** * @notice Retrieves the name of a specified variation. If the variation hasn't been approved by ambassadors, * it returns a default name based on the family and variation numbers. * @dev Checks the approval status of the variation using the variationAmbassadorsProposal mapping. If approved, * it fetches the name from the variationNames mapping. Otherwise, it constructs a default name. * @param _phenotype The phenotype of the variation. * @param _family The family of the variation. * @param _variation The specific variation number. * @return variationName The name of the variation or a default name if not approved. */ function getVariationName( uint256 _phenotype, uint256 _family, uint256 _variation ) public view returns (string memory) { if (bytes(variationNames[_phenotype][_family][_variation]).length != 0) { return capitalized(variationNames[_phenotype][_family][_variation]); } return string(abi.encodePacked("#(", Strings.toString(_family), ", ", Strings.toString(_variation), ")")); } /** * @notice Checks if a family name proposal meets the necessary criteria for a given phenotype and family. * @dev This function examines the validity of a name proposal for a family by assessing the criteria regarding * the phenotype, family, and the three proposed ambassador creatures. * A successful execution of this function indicates the name proposal meets all established conditions. * The checks include validations for phenotype number, name length, name format, * ambassador uniqueness, and ambassador association with the specific phenotype and family. * It also ensures all variations within the family have been named before a family name is proposed. * @param _phenotype The phenotype within which the family resides. * @param _family The family for which the name validity is being verified. * @param _ambassadorIds An array of ambassador creature IDs proposed for the naming. * @param _name The proposed name for the family. * * Requirements: * - Phenotype number must be less than 6. * - Name length should be up to 8 characters. * - Name must be alphanumeric. * - The proposed ambassador creatures must be distinct. * - Each proposed ambassador must be associated with the specified phenotype and family. * - All variations within the family must have been named. * * @return Returns `true` if the name proposal is valid; reverts otherwise. */ function verifyFamilyName( uint256 _phenotype, uint256 _family, uint256[] memory _ambassadorIds, string memory _name ) public view returns (bool) { unchecked { // Verify basics if (_phenotype > 5) revert BECInvalidPhenotype(_phenotype); if (bytes(_name).length > 8 || bytes(_name).length == 0) revert BECInvalidName(_name); if (!isAZ(bytes(_name))) revert BECInvalidName(_name); if (nameUsed[keccak256(abi.encodePacked(_name))]) revert BECDuplicatedName(_name); if (_ambassadorIds.length != 3) revert BECInvalidAmbassadorsLength(_ambassadorIds.length); if (bytes(familyNames[_phenotype][_family]).length != 0) revert BECFamilyNameAlreadySet(_phenotype, _family); BECGenesisEngine genesisEngineContract = BECGenesisEngine(payable(genesisEngineAddress)); // Verify all variations of the family set up uint256 variationsCount = genesisEngineContract.getVariationsCount(0, _phenotype, _family); for (uint256 v = 0; v < variationsCount; v++) { if (bytes(variationNames[_phenotype][_family][v]).length == 0) revert BECNotAllVariationsSet(_phenotype, _family, v); } // Verify creatures are different if ( _ambassadorIds[0] == _ambassadorIds[1] || _ambassadorIds[0] == _ambassadorIds[2] || _ambassadorIds[1] == _ambassadorIds[2] ) revert BECInvalidAmbassadors(_ambassadorIds[0], _ambassadorIds[1], _ambassadorIds[2]); // Verifying ambassadors and family & variation for each creature for (uint256 i = 0; i < 3; i++) { uint256 registry = (labRegistry[_ambassadorIds[i] / 8] >> ((_ambassadorIds[i] % 8) * 32)) & 0xFFFFFFFF; verifyFamilyAmbassador(_ambassadorIds[i], registry); verifyFamily(_phenotype, _family, _ambassadorIds[i]); } return true; } } /** * @notice Validates if a creature can be designated as a family ambassador. * @dev Evaluates the provided creature's registry to determine if the creature can be designated as a family ambassador. * A successful execution indicates that the creature meets the criteria to become a family ambassador, * i.e., it is not already a family ambassador and it is a variation ambassador. * @param _creatureId The creatureId to be verified. * @param _registry The registry entry of the creature (creature) to be verified. * * Requirements: * - The creature should not already be a family ambassador. * - The creature must be a variation ambassador. */ function verifyFamilyAmbassador(uint256 _creatureId, uint256 _registry) internal pure { unchecked { if ((_registry & 2) != 0) revert BECAlreadyFamilyAmbassador(_creatureId); // Checks that the second bit (isFamilyAmbassador) is 0 if ((_registry & 1) == 0) revert BECNotVariationAmbassador(_creatureId); // Checks that the first bit (isVariationAmbassador) is 1 } } /** * @notice Verifies if the family of a creature corresponds to the specified family within a given phenotype. * @dev Extracts the creature's DNA related to the given phenotype and checks if its family matches the provided `_family`. * A successful execution indicates the creature belongs to the expected family within the specified phenotype. * @param _phenotype The phenotype within which the family resides. * @param _family The expected family of the creature within the given phenotype. * @param _creatureId The ID of the creature (creature) to be verified. * * Requirements: * - The creature's family, as determined from its DNA for the given phenotype, must match `_family`. */ function verifyFamily(uint256 _phenotype, uint256 _family, uint256 _creatureId) internal view { unchecked { uint256 phenotypeTraits = BECGenesisEngine(payable(genesisEngineAddress)).getDna(_creatureId) >> ((_phenotype * 16)); uint256 dnaFamily = (phenotypeTraits) & 0xFF; if (dnaFamily != _family) revert BECInvalidFamily(_creatureId); } } /** * @notice Proposes a name for a family within a specific phenotype. * @dev This function allows users to suggest a name for a specific family by proposing three creatures as ambassadors. * The proposal will be checked by a validator backend after submission. If valid, the name will be approved. * The function includes basic validation for phenotype number, name length, name format, proposal price, * creature ownership, ambassador uniqueness, and previous proposals for the same family. * @param _phenotype The phenotype within which the family resides. * @param _family The family for which a name is being proposed. * @param _ambassadorIds An array of ambassador creature IDs proposed for the naming. * @param _name The proposed name for the family. * * Requirements: * - Phenotype number must be less than 6. * - Name length should be up to 8 characters. * - Name must be alphanumeric. * - The proposal price must be met. * - The caller must own all three proposed ambassador creatures. * - The proposed ambassador creatures must be distinct. * - All family variations should have their names set. * - The creatures cannot already be family ambassadors. * - There shouldn't be a pre-existing name or proposal for the specified family. */ function setFamilyName( uint256 _phenotype, uint256 _family, uint256[] memory _ambassadorIds, string memory _name, bytes calldata _signature ) public { if (!enabled) revert BECNotEnabled(); // Verify not already set if (!validateFamilySignature(_phenotype, _family, _ambassadorIds, _name, _signature)) revert EIP712InvalidSignature(_signature); if (bytes(_name).length > 8 || bytes(_name).length == 0) revert BECInvalidName(_name); if (nameUsed[keccak256(abi.encodePacked(_name))]) revert BECDuplicatedName(_name); if (bytes(familyNames[_phenotype][_family]).length != 0) revert BECFamilyNameAlreadySet(_phenotype, _family); BECCore coreContract = BECCore(payable(coreContractAddress)); for (uint256 i = 0; i < 3; i++) { if (msg.sender != coreContract.ownerOf(_ambassadorIds[i])) revert BECInvalidOwner(msg.sender, _ambassadorIds[i]); uint256 registry = (labRegistry[_ambassadorIds[i] / 8] >> ((_ambassadorIds[i] % 8) * 32)) & 0xFFFFFFFF; verifyFamilyAmbassador(_ambassadorIds[i], registry); setFamilyAmbassadorToRegistry(_ambassadorIds[i], _phenotype, _family); } familyNames[_phenotype][_family] = _name; nameUsed[keccak256(abi.encodePacked(_name))] = true; familyVariationAndNamesSet[msg.sender] += 1 << 64; emit FamilyNameSet(_phenotype, _family, _ambassadorIds, _name); } /** * @notice Validates the signature for a family name proposal. * @dev Checks if the provided signature is valid for the given family name proposal details. * @param _phenotype The phenotype ID involved in the proposal. * @param _family The family ID for which the name is proposed. * @param _ambassadorIds The IDs of the ambassador creatures proposed. * @param _name The proposed name for the family. * @param _signature The signature to validate. * @return bool Returns true if the signature is valid, false otherwise. */ function validateFamilySignature( uint256 _phenotype, uint256 _family, uint256[] memory _ambassadorIds, string memory _name, bytes calldata _signature ) internal view returns (bool) { if (allowlistSigningKey == address(0)) revert EIP712BECSigningKeyNotSet(); bytes32 digest = keccak256( abi.encodePacked( "\x19\x01", EIP712_DOMAIN_SEPARATOR, keccak256( abi.encode( VERIFY_FAMILY_TYPEHASH, _phenotype, _family, keccak256(abi.encodePacked(_ambassadorIds)), keccak256(bytes(_name)), msg.sender ) ) ) ); address recoveredAddress = digest.recover(_signature); return recoveredAddress == allowlistSigningKey; } /** * @notice Retrieves the name of a family within a specific phenotype. * @dev This function returns the name of a family based on the given phenotype and family parameters. * If the ambassador proposal for the family name has been approved, it returns the assigned family name. * Otherwise, it returns a default placeholder name constructed with the family number. * @param _phenotype The phenotype within which the family resides. * @param _family The specific family for which the name is being queried. * @return A string representing either the assigned name of the family (if the name proposal was approved) * or a default placeholder name indicating the family number. */ function getFamilyName(uint256 _phenotype, uint256 _family) public view returns (string memory) { if (bytes(familyNames[_phenotype][_family]).length != 0) { return capitalized(familyNames[_phenotype][_family]); } return string(abi.encodePacked("#(", Strings.toString(_family), ")")); } /** * @notice Updates the registry entry to set the creature as a family ambassador. * @dev This function performs bitwise operations on the provided registry entry to indicate * that the creature is now an ambassador for a specified family. It updates and returns * the modified registry entry by setting the appropriate bits based on the laphenotypeyer and family * passed as arguments. * @param _creatureId The creature Id. * @param _phenotype The phenotype associated with the family ambassador. * @param _family The specific family the creature is an ambassador for. */ function setFamilyAmbassadorToRegistry(uint256 _creatureId, uint256 _phenotype, uint256 _family) private { unchecked { labRegistry[_creatureId / 8] |= (2 | (_phenotype << 2) | (_family << 5)) << ((_creatureId % 8) * 32); } } /** * @notice Determines whether the provided string consists only of A-Z characters. * @dev The function checks each character of the input string to ensure it's a letter (A-Z). * Non-alphabetic characters will result in a return value of false. * ^[A-Z]{0,6}$ * @param _string The input string, given as a byte array, to be verified. * @return bool Returns true if all characters in the string are A-Z, otherwise returns false. */ function isAZ(bytes memory _string) internal pure returns (bool) { unchecked { if (_string.length < 3 || _string.length > 7) { return false; } for (uint256 i = 0; i < _string.length; i++) { bytes1 char = _string[i]; if (char < 0x41 || char > 0x5A) { // not A-Z return false; } } return true; } } /** * @notice Removes the capitalization of all characters besides the first one. * @dev This function iterates over all the elements of the string array and transforms it to lowercase. * @param _caps the string all in caps. * @return A string capitalized. (First leter in uppercase, the rest in lowercase). */ function capitalized(string memory _caps) internal pure returns (string memory) { bytes memory b = bytes(_caps); for (uint i = 1; i < b.length; i++) { if (uint8(b[i]) >= 65 && uint8(b[i]) <= 90) { b[i] = bytes1(uint8(b[i]) + 32); } } return string(b); } /** * @notice Sets the allowlist signing key for validating signatures. * @dev Updates the allowlist signing key used for signature validation in name proposals. * @param newSigningKey The new signing key to be used for validation. */ function setAllowlistSigningAddress(address newSigningKey) public onlyRole(GENETICIST) { _setAllowlistSigningAddress(newSigningKey); } /** * @notice Retrieves the lab registry record for a specific creature. * @dev Fetches the registry record for a creature based on its ID. * The record contains information about the creature's ambassador status and other traits. * @param _creatureId The ID of the creature. * @return uint256 The registry record of the specified creature. */ function getLabRegistryRecord(uint256 _creatureId) external view returns (uint256) { return (labRegistry[_creatureId / 8] >> ((_creatureId % 8) * 32)) & 0xFFFFFFFF; } /** * @notice Retrieves the number of Omegas for a specific creature. * @dev Fetches the Omega count for a creature from the lab registry based on its ID. * @param _creatureId The ID of the creature. * @return uint256 The number of Omegas associated with the creature. */ function getOmegas(uint256 _creatureId) external view returns (uint256) { return (labRegistry[_creatureId / 8] >> ((((_creatureId % 8) * 32)) + 16)) & 0xFFFF; } /** * @notice Increments the Omega count for a specific creature. * @dev Adds a specified quantity to the Omega count of a creature in the lab registry. * @param _creatureId The ID of the creature. * @param _quantity The quantity to add to the creature's Omega count. */ function incrementOmegas(uint256 _creatureId, uint256 _quantity) external onlyRole(LAB_REGISTER_UPDATER) { labRegistry[_creatureId / 8] += _quantity << (16 + ((_creatureId % 8) * 32)); } /** * @notice Grants the LAB_REGISTER_UPDATER role to a specified address. * @dev Assigns the role responsible for updating lab registry entries to a given address. * @param _address The address to be granted the LAB_REGISTER_UPDATER role. */ function grantLabRegisterUpdaterRole(address _address) external onlyRole(GENETICIST) { grantRole(LAB_REGISTER_UPDATER, _address); } /** * @notice Sets a name for a specific creature. * @dev Assigns a name to a creature based on its ID. The caller must be the owner of the creature. * @param _creatureId The ID of the creature. * @param _name The name to assign to the creature. */ function setCreatureName(uint256 _creatureId, string memory _name) public { BECCore coreContract = BECCore(payable(coreContractAddress)); if (msg.sender != coreContract.ownerOf(_creatureId)) revert BECInvalidOwner(msg.sender, _creatureId); if (bytes(_name).length > 8 || bytes(_name).length == 0) revert BECInvalidName(_name); if (nameUsed[keccak256(abi.encodePacked(_name))]) revert BECDuplicatedName(_name); if (!isAZ(bytes(_name))) revert BECInvalidName(_name); names[_creatureId] = _name; nameUsed[keccak256(abi.encodePacked(_name))] = true; familyVariationAndNamesSet[msg.sender] += 1 << 128; emit CreatureNameSet(_creatureId, _name); } /** * @notice Retrieves the name of a specific creature. * @dev Returns the name of a creature based on its ID. If the creature does not have a custom name, a default name is generated. * @param _creatureId The ID of the creature. * @return string The name of the creature or a default name if no custom name is set. */ function getCreatureName(uint256 _creatureId) external view virtual returns (string memory) { if (bytes(names[_creatureId]).length > 0) { return capitalized(names[_creatureId]); } return string(abi.encodePacked("BEC #", Strings.toString(_creatureId))); } }
// contracts/BECURIStorage.sol // SPDX-License-Identifier: MIT /** /3333333 /33333333 /333333 | 33__ 33 | 33_____/ /33__ 33 | 33 \ 33 | 33 | 33 \__/ | 3333333 | 33333 | 33 | 33__ 33 | 33__/ | 33 | 33 \ 33 | 33 | 33 33 | 3333333/ | 33333333 | 333333/ |_______/ |________/ \______/ # http://blackeyedcreatures.com */ pragma solidity ^0.8.25; import {ERC404B} from "./erc404/ERC404B.sol"; import {BECAccessControl} from "./BECAccessControl.sol"; import {BECGenesisEngine} from "./BECGenesisEngine.sol"; import {BECWithdrawable} from "./BECWithdrawable.sol"; import {EIP712} from "./eip712/EIP712.sol"; import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; /** * @title Black Eyed Creatures URI Storage * @dev Contract for managing URIs and IPFS-related functionality for Black Eyed Creatures (BEC) tokens. * @author https://42i.co */ abstract contract BECURIStorage is ERC404B, BECAccessControl, BECWithdrawable, EIP712 { /// @dev Using Elliptic Curve Digital Signature Algorithm (ECDSA). using ECDSA for bytes32; /// @dev Base URI for retrieve creature images. string _tokenBaseURI; /// @dev Base URL for the site. string internal _siteBaseUrl; /// @dev Genesis engine contract address. address genesisEngineContractAddress; /// @dev Mapping containing the IPFS uri of each token. mapping(uint256 tokenId => string ipfsUri) public ipfsUris; // The typehash for the data type specified in the structured data. // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#rationale-for-typehash bytes32 public constant IPFS_URI_TYPEHASH = keccak256("SetIPFSUri(uint256 creatureId,string uri)"); /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 _interfaceId) public view virtual override(ERC404B, AccessControl) returns (bool) { return super.supportsInterface(_interfaceId); } /** * @notice Sets the Base Token URI. * @param _uri the URI to set. */ function setBaseURI(string memory _uri) public onlyOwner { _tokenBaseURI = _uri; } /** * @notice Sets the Site Base Token URI. * @dev Allows the owner to set the base URL for the site. * @param _uri The new site base URI to set. */ function setSiteBaseURI(string memory _uri) public onlyOwner { _siteBaseUrl = _uri; } /** * @notice Sets the IPFS-specific Token URI. * @dev Allows setting a specific IPFS URI for a creature token. * @param _creatureId The ID of the creature token. * @param _uri The IPFS URI to set for the token. * @param _signature The signature to validate the operation. */ function setIPFSTokenURI(uint256 _creatureId, string calldata _uri, bytes calldata _signature) public { if (!validateIPFSUriSignature(_creatureId, _uri, _signature)) revert EIP712InvalidSignature(_signature); ipfsUris[_creatureId] = _uri; } /** * @notice Gets the Site Base Token URI. * @dev Returns the current site base URI. * @return uri The current site base URI. */ function getSiteBaseURI() public view returns (string memory uri) { return _siteBaseUrl; } /** * @notice Gets the image URI for a creature token. * @dev Generates and returns the image URI for a given creature token ID. * @param _creatureId The ID of the creature token. * @return uri The image URI for the creature token. */ function getImageURI(uint256 _creatureId) public view returns (string memory uri) { if (bytes(ipfsUris[_creatureId]).length > 0) { return ipfsUris[_creatureId]; } else { return string( abi.encodePacked( _tokenBaseURI, Strings.toHexString(uint256(uint160(address(this))), 20), "/", Strings.toString(_creatureId), ".png" ) ); } } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 _creatureId) public view virtual override returns (string memory) { BECGenesisEngine genesisEngineContract = BECGenesisEngine(payable(genesisEngineContractAddress)); return genesisEngineContract.tokenURI(_creatureId); } /** * @notice Sets the address of the Genesis Engine contract. * @dev Allows the contract to interact with the Genesis Engine, enabling dynamic token URI generation based on creature DNA. * @param _genesisEngineContractAddress The address of the Genesis Engine contract. */ function setGenesisEngineContractAddress(address _genesisEngineContractAddress) public onlyRole(GENETICIST) { genesisEngineContractAddress = _genesisEngineContractAddress; } /** * @notice Sets a new signing key for the allowlist. * @dev Updates the signing key used to validate signatures for certain privileged operations. * @param _signingKey The new public address to be used as the signing key. */ function setAllowlistSigningAddress(address _signingKey) public onlyOwner { _setAllowlistSigningAddress(_signingKey); } /** * @notice Validates the signature for setting IPFS image creature uri. * @dev Uses EIP-712 signing standard to verify the signature against the expected message format and content, * including the creatureId, and the IPFS URI of the creature. * @param _creatureId The creature. * @param _uri The IPFS uri for the creature. * @param _signature The signature to validate. * @return bool True if the signature is valid, false otherwise. */ function validateIPFSUriSignature( uint256 _creatureId, string calldata _uri, bytes calldata _signature ) internal view returns (bool) { if (allowlistSigningKey == address(0)) revert EIP712BECSigningKeyNotSet(); bytes32 digest = keccak256( abi.encodePacked( "\x19\x01", EIP712_DOMAIN_SEPARATOR, keccak256(abi.encode(IPFS_URI_TYPEHASH, _creatureId, keccak256(bytes(_uri)), msg.sender)) ) ); address recoveredAddress = digest.recover(_signature); return recoveredAddress == allowlistSigningKey; } }
// contracts/BECWithdrawable.sol // SPDX-License-Identifier: MIT /** /3333333 /33333333 /333333 | 33__ 33 | 33_____/ /33__ 33 | 33 \ 33 | 33 | 33 \__/ | 3333333 | 33333 | 33 | 33__ 33 | 33__/ | 33 | 33 \ 33 | 33 | 33 33 | 3333333/ | 33333333 | 333333/ |_______/ |________/ \______/ # http://blackeyedcreatures.com */ pragma solidity ^0.8.25; import {IBECErrors} from "./IBECErrors.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; /** * @title Black Eyed Creatures Widthdrawable Contract * @dev This contract adds the availablitily to extract ether and erc-20 token balance from the contract that * implements it. * @author https://42i.co */ abstract contract BECWithdrawable is Ownable, IBECErrors { /// @dev Event emitted when the contract receives ether from an address. event Received(address from, uint256 amount); /// @dev Constructor for Withdrawable. constructor () Ownable(msg.sender) {} /** * @dev Withdraws specified amount of royalties from contract to address. * @param _amount amount of royalties to withdraw. * @param _address address to withdraw the balance to. */ function withdraw(uint256 _amount, address payable _address) public payable onlyOwner { if (_address == address(0)) revert BECInvalidAddress(_address); if (_amount > address(this).balance) revert BECInsufficientFunds(_amount, address(this).balance); _address.transfer(_amount); } /** * @dev Withdraws token specified ERC20 amount to the given address. * @param _tokenAddress Address of the token to withdraw. * @param _amount Amount of tokens to withdraw. * @param _address Address to withdraw the tokens to. */ function withdrawERC20Token( address _tokenAddress, uint256 _amount, address payable _address ) public payable onlyOwner { IERC20 tokenContract = IERC20(_tokenAddress); if (_address == address(0)) revert BECInvalidAddress(_address); if (_amount > tokenContract.balanceOf(address(this))) revert BECInsufficientFunds(_amount, tokenContract.balanceOf(address(this))); tokenContract.transfer(_address, _amount); } /** * @dev Withdraws token specified ERC721 tokenId to the given address. * @param _tokenAddress Address of the token to withdraw. * @param _tokenId The id of the token to withdraw. * @param _address Address to withdraw the tokens to. */ function withdrawERC721Token( address _tokenAddress, uint256 _tokenId, address _address ) public payable onlyOwner { IERC721 tokenContract = IERC721(_tokenAddress); if (_address == address(0)) revert BECInvalidAddress(_address); if (address(this) != tokenContract.ownerOf(_tokenId)) revert BECInvalidOwner(address(this), _tokenId); tokenContract.safeTransferFrom(address(this), _address, _tokenId); } /** * @dev Function to receive Ether. msg.data must be empty. */ receive() external payable { emit Received(msg.sender, msg.value); } /** * @dev Fallback function is called when msg.data is not empty. */ fallback() external payable {} }
// contracts/eip712/EIP712.sol // SPDX-License-Identifier: MIT /** /3333333 /33333333 /333333 | 33__ 33 | 33_____/ /33__ 33 | 33 \ 33 | 33 | 33 \__/ | 3333333 | 33333 | 33 | 33__ 33 | 33__/ | 33 | 33 \ 33 | 33 | 33 33 | 3333333/ | 33333333 | 333333/ |_______/ |________/ \______/ # http://blackeyedcreatures.com */ pragma solidity ^0.8.25; import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; /** * @title EIP712 Base Contract for Typed Structured Data Hashing and Signing * @dev Implements EIP-712 standard providing a secure method for generating off-chain signatures * that can be verified on-chain. Utilizes OpenZeppelin's ECDSA library for cryptographic operations, * ensuring robust and secure handling of digital signatures. * @author https://42i.co */ contract EIP712 { /** * @dev Indicates that the signature was invalid. * @param signature The used signature. */ error EIP712InvalidSignature(bytes signature); /** * @dev Indicates that the signing key was not set. */ error EIP712BECSigningKeyNotSet(); /// @dev Using Elliptic Curve Digital Signature Algorithm (ECDSA) using ECDSA for bytes32; /// @dev The key used to sign allowlist signatures. address allowlistSigningKey = address(0); /// @dev EIP-712 Domain Separator, providing protection against replay attacks across different contracts and networks. /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#definition-of-domainseparator bytes32 public immutable EIP712_DOMAIN_SEPARATOR; /** * @dev Initializes the contract by setting up the DOMAIN_SEPARATOR to include the contract's details * and the current chain ID, ensuring signatures are valid for specific interactions on the intended network. */ constructor() { // This should match whats in the client side allowlist signing code EIP712_DOMAIN_SEPARATOR = keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes("BEC")), keccak256(bytes("3")), block.chainid, address(this) ) ); } /** * @notice Sets a new signing key for the allowlist, updating the key used for signature validation. * @dev Internal function to update the allowlist signing key, ensuring only authorized signatures are considered valid. * @param _signingKey The new signing key address to be used for validating signatures. */ function _setAllowlistSigningAddress(address _signingKey) internal { allowlistSigningKey = _signingKey; } }
// contracts/erc404/ERC404B.sol // SPDX-License-Identifier: MIT /** /3333333 /33333333 /333333 | 33__ 33 | 33_____/ /33__ 33 | 33 \ 33 | 33 | 33 \__/ | 3333333 | 33333 | 33 | 33__ 33 | 33__/ | 33 | 33 \ 33 | 33 | 33 33 | 3333333/ | 33333333 | 333333/ |_______/ |________/ \______/ # https://blackeyedcreatures.com */ pragma solidity ^0.8.25; import {IERC404B} from "./IERC404B.sol"; import {IERC404BErrors} from "./IERC404BErrors.sol"; import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import {IERC20Errors, IERC721Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import {DoubleEndedQueue} from "./lib/DoubleEndedQueue.sol"; import {BitMaps} from "solidity-bits/contracts/BitMaps.sol"; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; /** * @title Stash Contract * @dev This empty contract serves as the designated address for ERC721 tokens that have been minted but not yet burned and currently have no owner. */ contract Stash {} /** * @title ERC404B Contract * @dev Implements the IERC404 interface to provide a hybrid token mechanism supporting both ERC-20 and ERC-721 functionalities. * This contract diverts tokens without current ownership to a "stash" address instead of sending them to the zero address (0x00) as is common with burns. * It also enables the actual burning of tokens, sending them irreversibly to the zero address. * Features include batch minting for ERC-721 tokens to optimize minting operations, gas savings optimizations, and support for EIP-2612 permit-based transactions. * @author https://42i.co */ contract ERC404B is IERC404B, IERC20Errors, IERC721Errors, IERC404BErrors { using Strings for uint256; using BitMaps for BitMaps.BitMap; using DoubleEndedQueue for DoubleEndedQueue.Uint256Deque; // DoubleEndedQueue.Uint32Deque would be great /// @dev Token Name. string private _name; /// @dev Token Symbol. string private _symbol; /// @dev Token decimal digits. uint8 private immutable _DECIMALS; /// @dev The number of ERC20 tokens required for one ERC721 token. uint256 private immutable _UNIT; /// @dev The number of tokens held by each address. mapping(address holder => uint256 balance) private _balances; /// @dev Identifier for the next token to mint. uint256 internal _nextTokenId = _startTokenId(); /// @dev ERC721 token approvals. mapping(uint256 tokenId => address approvedAddress) private _tokenApprovals; /// @dev ERC721 operator approvals. mapping(address holder => mapping(address operator => bool approval)) private _operatorApprovals; /// @dev ERC20 token allowances. mapping(address holder => mapping(address operator => uint256 allowance)) private _allowances; /// @dev Exempt addresses from ERC-721 transfers (e.g., pairs, routers) for gas savings. mapping(address holder => bool exempt) private _erc721TransferExempt; /// @dev Bitmask to extract lower 160 bits from a uint256. uint256 private constant _BITMASK_LOWER160BITS = (1 << 160) - 1; /// @dev Bitmask to extract upper 96 bits from a uint256. uint256 private constant _BITMASK_UPPER96BITS = ((1 << 96) - 1) << 160; /// @dev Array of owned ERC-721 token IDs, each position stores a batch of tokens with the initial ID (_BITMASK_LOWER160BITS) and quantity (_BITMASK_UPPER96BITS). mapping(address holder => uint256[] batchArray) private _owned; /// @dev Mapping storing in each position the owner address (_BITMASK_LOWER160BITS) and index of this batch in _owned (_BITMASK_UPPER96BITS). mapping(uint256 tokenId => uint256 addressAndPosition) private _ownedData; /// @dev Bitmap storing the head of the batches, indicating where the _ownedData is located. BitMaps.BitMap private _batchHead; /// @dev Bitmap representing burned tokens. BitMaps.BitMap private _burnedTokens; /// @dev Amount of burned tokens. uint256 private _burnedCount = 0; /// @dev Queue of ERC-721 tokens in the stash. DoubleEndedQueue.Uint256Deque private _stashQueue; /// @dev Transfer(address,address,uint256) hash signature. bytes32 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; /// @dev Approval(address,address,uint256) hash signature. bytes32 private constant _APPROVAL_EVENT_SIGNATURE = 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925; /// @dev ApprovalForAll(address,address,bool) hash signature. bytes32 private constant _APPROVALFORALL_EVENT_SIGNATURE = 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31; /// @dev Stash address for this token. address private immutable _STASH_ADDRESS; /// @dev EIP-2612 nonces. mapping(address => uint256) public nonces; /// @dev Initial chain id for EIP-2612 support. uint256 internal immutable _INITIAL_CHAIN_ID; /// @dev Initial domain separator for EIP-2612 support. bytes32 internal immutable _INITIAL_DOMAIN_SEPARATOR; /** * @dev Initializes the contract with token details and necessary parameters. * * @param name_ The name of the token. * @param symbol_ The symbol of the token. * @param unit_ The equivalence between 1 ERC721 token and ERC20 needed for that token. */ constructor(string memory name_, string memory symbol_, uint256 unit_) { _name = name_; _symbol = symbol_; _DECIMALS = 18; _UNIT = unit_ * 10 ** _DECIMALS; _STASH_ADDRESS = address(new Stash()); // EIP-2612 initialization _INITIAL_CHAIN_ID = block.chainid; _INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator(); } /** * @dev Returns the starting token ID. * * @return The starting token ID, which is set to 1 by default. * To change the starting token ID, please override this function. */ function _startTokenId() internal pure returns (uint256) { return 1; } /** * @dev Returns the total number of tokens minted in the contract. * * @return The total number of tokens minted. */ function _totalMinted() internal view virtual returns (uint256) { return _nextTokenId - _startTokenId(); } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId_) public view virtual returns (bool) { return interfaceId_ == type(IERC404B).interfaceId || interfaceId_ == type(IERC165).interfaceId || interfaceId_ == type(IERC20).interfaceId || interfaceId_ == type(IERC721).interfaceId || interfaceId_ == type(IERC721Receiver).interfaceId || interfaceId_ == type(IERC721Metadata).interfaceId; } /// IERC20 + ERC721 Metadata Methods /// /** * @dev See {IERC404-name}. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC404-symbol}. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC404-decimals}. */ function decimals() public view virtual override returns (uint8) { return _DECIMALS; } /** * @dev See {IERC404-unit}. */ function unit() public view virtual returns (uint256) { return _UNIT; } /** * @dev See {IERC404-tokenURI}. */ function tokenURI(uint256 tokenId_) public view virtual override returns (string memory) { if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId_.toString())) : ""; } /** * @dev Base URI for computing the {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. * * It is empty by default and can be overridden in child contracts. * @return The base URI string. */ function _baseURI() internal view virtual returns (string memory) { return ""; } /** * @dev Checks whether the specified `tokenId` exists in the contract. * Tokens start existing when they are minted using the {_mint} function. Burned tokens are not considered to exist. * * @param tokenId_ The ID of the token to check. * @return A boolean indicating whether the token exists. */ function _exists(uint256 tokenId_) internal view virtual returns (bool) { if (_burnedTokens.get(tokenId_)) { return false; } return tokenId_ < _nextTokenId && _startTokenId() <= tokenId_; } /** * @dev See {IERC404-exists}. */ function exists(uint256 tokenId_) external view virtual returns (bool) { return _exists(tokenId_); } /// ERC721 Methods /// /** * @dev See {IERC404-ownerOf}. */ function ownerOf(uint256 tokenId_) public view virtual override returns (address owner) { if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_); uint256 data = _ownedData[_batchHead.scanForward(tokenId_)]; assembly { owner := and(data, _BITMASK_LOWER160BITS) } if (owner == address(0)) { owner = _STASH_ADDRESS; } } /** * @dev See {IERC404-safeTransferFrom}. */ function safeTransferFrom(address from_, address to_, uint256 tokenId_) public virtual override { safeTransferFrom(from_, to_, tokenId_, ""); } /** * @dev See {IERC404-safeTransferFrom}. */ function safeTransferFrom(address from_, address to_, uint256 tokenId_, bytes memory data_) public virtual override { if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_); if (!_isApprovedOrOwner(msg.sender, tokenId_)) revert ERC721InsufficientApproval(msg.sender, tokenId_); _safeTransferERC721(from_, to_, tokenId_, data_); } /** * @dev Safely transfers `tokenId_` token from `from_` to `to_`, ensuring the recipient contract * implements the ERC721Receiver interface to prevent tokens from being forever locked. * * `data_` is additional data without a specified format, included in the call to `to_`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to implement alternative * token transfer mechanisms, such as signature-based ones. * * Requirements: * - `to_` cannot be the zero nor stash address. * - `tokenId_` must exist and be owned by `from_`. * - If `to_` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}. * * Emits a {Transfer} event. * * @param from_ The address sending the token. * @param to_ The address receiving the token. * @param tokenId_ The ID of the token being transferred. * @param data_ Additional data sent during the token transfer. */ function _safeTransferERC721(address from_, address to_, uint256 tokenId_, bytes memory data_) internal virtual { if (!_checkOnERC721Received(from_, to_, tokenId_, 1, data_)) revert ERC721ReceiverNotImplemented(to_, tokenId_, 1, data_); if (to_ == address(0) || to_ == _STASH_ADDRESS || to_ == from_) revert ERC721InvalidReceiver(to_); _transferERC721(from_, to_, tokenId_); } /** * @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 startTokenId_ The first ID of the tokens to be transferred. * @param quantity_ Amount of tokens to be transferred. * @param data_ Optional data to send along with the call. * @return r Boolean indicating whether the call returned the expected magic value. */ function _checkOnERC721Received(address from_, address to_, uint256 startTokenId_, uint256 quantity_, bytes memory data_) private returns (bool r) { if (to_.code.length > 0) { r = true; for (uint256 tokenId = startTokenId_; tokenId < startTokenId_ + quantity_; tokenId++) { try IERC721Receiver(to_).onERC721Received(msg.sender, from_, tokenId, data_) returns (bytes4 retval) { r = r && retval == IERC721Receiver.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert ERC721ReceiverNotImplemented(to_, startTokenId_, quantity_, data_); } else { assembly { revert(add(32, reason), mload(reason)) } } } } return r; } else { return true; } } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * - `tokenId` must exist. * * @param spender_ The address being checked for approval. * @param tokenId_ The ID of the token being checked. * @return A boolean indicating whether `spender` is allowed to manage `tokenId`. */ function _isApprovedOrOwner(address spender_, uint256 tokenId_) internal view virtual returns (bool) { address owner = ownerOf(tokenId_); return (spender_ == owner || getApproved(tokenId_) == spender_ || isApprovedForAll(owner, spender_)); } /** * @dev Adds a batch of tokens to the `_owned` mapping for the given owner. * * @param batchInitialId_ The initial ID of the batch of tokens. * @param owner_ The address of the owner. * @param quantity_ The quantity of tokens in the batch. */ function _pushOwned(uint256 batchInitialId_, address owner_, uint256 quantity_) internal virtual { uint256 data; assembly { data := add(and(batchInitialId_, _BITMASK_LOWER160BITS), and(shl(160, quantity_), _BITMASK_UPPER96BITS)) } _owned[owner_].push(data); } /** * @dev Sets the data for a specific batch of tokens in the `_owned` mapping for the given owner and index. * * @param batchInitialId_ The initial ID of the batch of tokens. * @param owner_ The address of the owner. * @param index_ The index of the batch in the `_owned` array. * @param quantity_ The quantity of tokens in the batch. */ function _setOwned(uint256 batchInitialId_, address owner_, uint256 index_, uint256 quantity_) internal virtual { uint256 data; assembly { data := add(and(batchInitialId_, _BITMASK_LOWER160BITS), and(shl(160, quantity_), _BITMASK_UPPER96BITS)) } _owned[owner_][index_] = data; } /** * @dev Retrieves the initial ID and quantity of tokens in a batch owned by a specific address. * * @param owner_ The address of the token owner. * @param index_ The index of the batch in the owner's collection. * @return batchInitialId The initial ID of the tokens in the batch. * @return batchQuantity The quantity of tokens in the batch. */ function _getOwnedBatchInitialIdAndQuantity(address owner_, uint256 index_) internal view virtual returns (uint256 batchInitialId, uint256 batchQuantity) { uint256 data = _owned[owner_][index_]; assembly { batchInitialId := and(data, _BITMASK_LOWER160BITS) batchQuantity := shr(160, data) } } /** * @dev Sets the data for a batch of owned tokens at a specific index in the _ownedData mapping. * This function is used to update the data associated with a batch of tokens owned by an address. * It ensures that the index does not exceed the upper limit defined by _BITMASK_UPPER96BITS >> 160. * * @param batchInitialId_ The initial ID of the tokens in the batch. * @param ownerOf_ The address of the owner of the tokens in the batch. * @param index_ The index of the batch within the _owned[ownerOf_] mapping. */ function _setOwnedData(uint256 batchInitialId_, address ownerOf_, uint256 index_) internal virtual { if (index_ > _BITMASK_UPPER96BITS >> 160) { revert ERC404OwnedIndexOverflow(index_); } uint256 data; assembly { data := add(and(ownerOf_, _BITMASK_LOWER160BITS), and(shl(160, index_), _BITMASK_UPPER96BITS)) } _ownedData[batchInitialId_] = data; } /** * @dev Retrieves the owner, index within the owner's batch, and token ID at the head of the batch for the given token ID. * * Requirements: * - The token ID must exist. * * @param tokenId_ The ID of the token for which to retrieve information. * @return owner The address of the token's owner. * @return index The index of the token within the owner's batch. * @return tokenIdBatchHead The token ID at the head of the batch. */ function _getOwnerOwnedIndexAndBatchHeadId(uint256 tokenId_) internal view returns (address owner, uint256 index, uint256 tokenIdBatchHead) { tokenIdBatchHead = _batchHead.scanForward(tokenId_); uint256 data = _ownedData[tokenIdBatchHead]; assembly { index := shr(160, data) owner := and(data, _BITMASK_LOWER160BITS) } } /** * @dev Transfers an ERC721 token from one address to another. * * Requirements: * - `from_` must be the owner of the token. * - Token ID must exist and be owned by `from_`. * - If `to_` is a smart contract, it must implement {IERC721Receiver-onERC721Received}. * - If `to_` is exempt from ERC721 transfer, the token is moved to the stash. * * Emits an {IERC721-Transfer} event. * Emits an {IERC20-Transfer} event. * * @param from_ The address transferring the token. * @param to_ The address receiving the token. * @param tokenId_ The ID of the token being transferred. */ function _transferERC721(address from_, address to_, uint256 tokenId_) internal virtual { (address owner, uint256 index, uint256 tokenIdBatchHead) = _getOwnerOwnedIndexAndBatchHeadId(tokenId_); // _beforeTokenTransfers(from_, to_, tokenId_, 1); delete _tokenApprovals[tokenId_]; // On transfer, any previous approval is reset. uint256 batchQuantity; uint256 data = _owned[owner][index]; assembly { batchQuantity := shr(160, data) } _removeTokenFrom(from_, index, tokenId_, tokenIdBatchHead, batchQuantity); if (_erc721TransferExempt[to_]) { // Is exempt: move to stash _batchHead.set(tokenId_); _stashQueue.pushFront(tokenId_); address mutableStashAddress = _STASH_ADDRESS; assembly { // Emit ERC721.Transfer(from_, _STASH_ADDRESS, tokenId_) log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(mutableStashAddress, _BITMASK_LOWER160BITS), tokenId_) } } else { // Add ownership to "to_" assembly { data := add(and(tokenId_, _BITMASK_LOWER160BITS), and(shl(160, 1), _BITMASK_UPPER96BITS)) } _owned[to_].push(data); uint256 index_ = _owned[to_].length - 1; assembly { data := add(and(to_, _BITMASK_LOWER160BITS), and(shl(160, index_), _BITMASK_UPPER96BITS)) } _ownedData[tokenId_] = data; assembly { // emit IERC721.Transfer(from_, to_, tokenId_); log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(to_, _BITMASK_LOWER160BITS), 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_] -= _UNIT; _balances[to_] += _UNIT; } data = _UNIT; assembly { // emit IERC20.Transfer(from_, to_, _UNIT); mstore(0x00, data) log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(to_, _BITMASK_LOWER160BITS)) } // _afterTokenTransfers(from_, to_, tokenId_, 1); } /** * @dev Removes a token from an address, adjusting the internal data structures accordingly. * * Requirements: * - `from_` must be the owner of the token. * * @param from_ The address from which the token is being removed. * @param index_ The index of the token within the owner's batch. * @param tokenId_ The ID of the token being removed. * @param batchInitialId_ The initial ID of the batch. * @param batchQuantity_ The quantity of tokens in the batch. */ function _removeTokenFrom(address from_, uint256 index_, uint256 tokenId_, uint256 batchInitialId_, uint256 batchQuantity_) internal { unchecked { // If Is Batch Head == No tokens before in the batch. if (batchInitialId_ == tokenId_) { if (batchQuantity_ == 1) { _removeSingleToken(from_, index_); } else { _removeBatchHeadToken(from_, index_, tokenId_, batchQuantity_); } } else { // Is not batch head == There is tokens before for the _removeNonHeadToken(from_, index_, tokenId_, batchInitialId_, batchQuantity_); } } } /** * @dev Removes a single token from the owner's collection. * * This internal function is used during ERC721 token transfers to remove a single token from the owner's collection. * It shifts the token data in the owner's collection to fill the gap left by the removed token, ensuring continuous indexing. * If the removed token is not the last token in the collection, it updates the metadata and batch information accordingly. * * @param from_ The address of the owner from which the token is being removed. * @param index_ The index of the token in the owner's collection to be removed. */ function _removeSingleToken(address from_, uint256 index_) internal { unchecked { uint256[] storage ownedFrom = _owned[from_]; uint256 fromStackLastIndex = ownedFrom.length - 1; if (fromStackLastIndex != index_) { uint256 data = ownedFrom[fromStackLastIndex]; ownedFrom[index_] = data; uint256 lastBatchInitialId; assembly { lastBatchInitialId := and(data, _BITMASK_LOWER160BITS) data := add(and(from_, _BITMASK_LOWER160BITS), and(shl(160, index_), _BITMASK_UPPER96BITS)) } _ownedData[lastBatchInitialId] = data; } ownedFrom.pop(); } } /** * @dev Removes the batch head token from the owner's collection. * * This internal function is used during ERC721 token transfers to remove the batch head token from the owner's collection. * It sets the subsequent token ID as the new batch head, updates the batch information, and shifts the remaining tokens accordingly. * * @param from_ The address of the owner from which the batch head token is being removed. * @param index_ The index of the batch head token in the owner's collection to be removed. * @param tokenId_ The ID of the batch head token being removed. * @param batchQuantity_ The quantity of tokens in the batch (including the batch head). */ function _removeBatchHeadToken(address from_, uint256 index_, uint256 tokenId_, uint256 batchQuantity_) internal { unchecked { uint256 subsequentTokenId = tokenId_ + 1; _batchHead.set(subsequentTokenId); uint256 data; assembly { data := add(and(from_, _BITMASK_LOWER160BITS), and(shl(160, index_), _BITMASK_UPPER96BITS)) } _ownedData[subsequentTokenId] = data; assembly { data := add( and(subsequentTokenId, _BITMASK_LOWER160BITS), and(shl(160, sub(batchQuantity_, 1)), _BITMASK_UPPER96BITS) ) } _owned[from_][index_] = data; } } /** * @dev Removes a non-head token from the owner's collection within a batch. * * This internal function is used during ERC721 token transfers to remove a token that is not the batch head from the owner's collection within a batch. * It updates the batch information, shifts the remaining tokens accordingly, and creates a new batch if necessary. * * @param from_ The address of the owner from which the token is being removed. * @param index_ The index of the token in the owner's collection to be removed. * @param tokenId_ The ID of the token being removed. * @param batchInitialId_ The ID of the first token in the batch. * @param batchQuantity_ The quantity of tokens in the batch. */ function _removeNonHeadToken(address from_, uint256 index_, uint256 tokenId_, uint256 batchInitialId_, uint256 batchQuantity_) internal { unchecked { _batchHead.set(tokenId_); uint256 batchSizeAndIndex = tokenId_ - batchInitialId_; uint256 data; assembly { data := add(and(batchInitialId_, _BITMASK_LOWER160BITS), and(shl(160, batchSizeAndIndex), _BITMASK_UPPER96BITS)) } _owned[from_][index_] = data; if (batchSizeAndIndex < batchQuantity_ - 1) { // It means that the batch continues uint256 subsequentTokenId = tokenId_ + 1; _batchHead.set(subsequentTokenId); batchSizeAndIndex = (batchQuantity_ - 1) - (tokenId_ - batchInitialId_); assembly { data := add(and(subsequentTokenId, _BITMASK_LOWER160BITS), and(shl(160, batchSizeAndIndex), _BITMASK_UPPER96BITS)) } _owned[from_].push(data); batchSizeAndIndex = _owned[from_].length - 1; assembly { data := add(and(from_, _BITMASK_LOWER160BITS), and(shl(160, batchSizeAndIndex), _BITMASK_UPPER96BITS)) } _ownedData[subsequentTokenId] = data; } } } /** * @dev See {IERC404-getApproved}. */ function getApproved(uint256 tokenId_) public view virtual override returns (address) { if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_); return _tokenApprovals[tokenId_]; } /** * @dev See {IERC404-setApprovalForAll}. */ function setApprovalForAll(address operator_, bool approved_) public virtual override { address owner = msg.sender; if(operator_ == owner) revert ERC721InvalidOperator(operator_); _operatorApprovals[owner][operator_] = approved_; assembly { // emit IERC721.ApprovalForAll(owner, operator, approved); mstore(0x00, approved_) log3(0x00, 0x20, _APPROVALFORALL_EVENT_SIGNATURE, and(owner, _BITMASK_LOWER160BITS), and(operator_, _BITMASK_LOWER160BITS)) } } /** * @dev See {IERC404-isApprovedForAll}. */ function isApprovedForAll(address owner_, address operator_) public view virtual override returns (bool) { return _operatorApprovals[owner_][operator_]; } /** * @dev Safely mints a specified quantity of ERC721 tokens and assigns them to the specified address. * * This internal function is equivalent to calling `_safeMint(to, quantity, "")`, providing an empty data parameter. * It ensures that the minted tokens are safely transferred to the recipient by calling the ERC721 safe transfer function. * * @param to_ The address to which the minted tokens will be assigned. * @param quantity_ The number of tokens to mint. */ function _safeMint(address to_, uint256 quantity_) internal virtual { _safeMint(to_, quantity_, ""); } /** * @dev Safely mints a specified quantity of ERC721 tokens and assigns them to the specified address. * * This internal function is equivalent to calling `_mint(to_, quantity_)` followed by a check to ensure that the recipient contract implements ERC721Receiver. * It requires the recipient contract to implement the ERC721Receiver interface's `onERC721Received` function to receive the tokens safely. * * @param to_ The address to which the minted tokens will be assigned. * @param quantity_ The number of tokens to mint. * @param data_ Additional data sent along with the token transfer, if any. */ function _safeMint(address to_, uint256 quantity_, bytes memory data_) internal virtual { if (!_checkOnERC721Received(address(0), to_, _nextTokenId, quantity_, data_)) { revert ERC721ReceiverNotImplemented(to_, _nextTokenId, quantity_, data_); } _mint(to_, quantity_); } /** * @dev Mints a specified quantity of ERC721 tokens and assigns them to the specified address. * * This internal function performs the minting of ERC721 tokens and updates the balances accordingly. * It also emits one ERC20 Transfer event and a ERC721 Transfer event for each minted token. * If the recipient address is exempt from ERC721 transfer fees, the method sets the batch head accordingly; * otherwise, it adds the minted tokens to the recipient's ownership. * * Requirements: * - `quantity_` must be greater than 0. * - `to_` address must not be the zero nor stash address. * * Emits an IERC20 {Transfer} event. * Emits an IERC721 {Transfer} event for each minted token. * * @param to_ The address to which the minted tokens will be assigned. * @param quantity_ The number of tokens to mint. */ function _mint(address to_, uint256 quantity_) internal virtual { if (quantity_ == 0) revert ERC721InvalidMintQuantity(); if (to_ == address(0) || to_ == _STASH_ADDRESS) revert ERC20InvalidReceiver(to_); // _beforeTokenTransfers(address(0), to_, _nextTokenId, quantity_); uint256 value; uint256 toMasked; uint256 end; uint256 batchTokenId = _nextTokenId; unchecked { value = quantity_ * _UNIT; _balances[to_] += value; // May overflow in big quantities if total balance not controlled. end = batchTokenId + quantity_; } assembly { // emit IERC20.Transfer(0x00, to_, _UNIT); toMasked := and(to_, _BITMASK_LOWER160BITS) mstore(0x00, value) log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, 0x00, toMasked) } if (_erc721TransferExempt[to_]) { _batchHead.setBatch(batchTokenId, quantity_); } else { _batchHead.set(batchTokenId); _pushOwned(batchTokenId, to_, quantity_); _setOwnedData(batchTokenId, to_, _owned[to_].length - 1); // Use assembly to loop and emit the `Transfer` event for gas savings. // The duplicated `log4` removes an extra check and reduces stack juggling. assembly { // emit IERC721.Transfer(0x00, to_, batchTokenId); log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, 0x00, toMasked, batchTokenId) // The `iszero(eq(,))` check ensures that large values of `quantity` // that overflows uint256 will make the loop run out of gas. // The compiler will optimize the `iszero` away for performance. for { let tokenId := add(batchTokenId, 1) } iszero(eq(tokenId, end)) { tokenId := add(tokenId, 1) } { // emit IERC721.Transfer(0x00, to_, tokenId); log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, 0x00, toMasked, tokenId) } } } // _afterTokenTransfers(address(0), to_, _nextTokenId, quantity_); unchecked { _nextTokenId += quantity_; } } /// ERC20 Methods /// /** * @dev See {IERC404-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalTokens() * _UNIT; } /** * @dev Calculates the total number of tokens that have been minted and not burned. * * This internal function returns the difference between the total minted tokens and the burned tokens, representing the total number of existing tokens in circulation. * * @return The total number of existing tokens in circulation. */ function _totalTokens() internal view virtual returns (uint256) { return _totalMinted() - _burned(); } /** * @dev Retrieves the total number of tokens that have been burned. * * This internal function returns the count of tokens that have been burned within the contract. * * @return The total number of tokens that have been burned. */ function _burned() internal view virtual returns (uint256) { return _burnedCount; } /** * @dev See {IERC404-transfer}. */ function transfer(address to_, uint256 valueOrId_) public virtual override returns (bool) { address owner = msg.sender; transferFrom(owner, to_, valueOrId_); return true; } /** * @dev See {IERC404-allowance}. */ function allowance(address owner_, address spender_) public view virtual override returns (uint256) { return _allowances[owner_][spender_]; } /// ERC404 Combined (Methods with similar interfaces and behavior in ERC20 & ERC721) /// /** * @dev See {IERC404-balanceOf}. */ function balanceOf(address account_) public view virtual override returns (uint256) { return _balances[account_]; } /** * @dev See {IERC404-transferFrom}. */ function transferFrom(address from_, address to_, uint256 valueOrId_) public virtual returns (bool) { if (_exists(valueOrId_)) { safeTransferFrom(from_, to_, valueOrId_, ""); } else { return _transferFromERC20(from_, to_, valueOrId_); } return true; } /** * @dev Transfers ERC20 tokens from one address to another, handling ERC721 exemptions internally. * * This function is used to transfer ERC20 tokens directly between addresses, handling exemptions for ERC721 transfers * internally. It checks for valid recipients, allowances, and handles ERC721 exemptions if the recipient address is * exempt from ERC721 transfers. * * Requirements: * - `to_` cannot be the zero address or the stash address. * * @param from_ The address sending the ERC20 tokens. * @param to_ The address receiving the ERC20 tokens. * @param value_ The amount of ERC20 tokens to transfer. * @return A boolean indicating whether the transfer was successful. */ function _transferFromERC20(address from_, address to_, uint256 value_) public virtual returns (bool) { if (to_ == address(0) || to_ == _STASH_ADDRESS || to_ == from_) revert ERC20InvalidReceiver(to_); if (from_ != msg.sender) { uint256 allowed = _allowances[from_][msg.sender]; // Check that the operator has sufficient allowance. if (allowed != type(uint256).max) { if(value_ > allowed) revert ERC20InsufficientAllowance(from_, allowed, value_); _allowances[from_][msg.sender] = allowed - value_; } } // Transferring ERC-20s directly requires the _transferERC20WithERC721 function. return _transferERC20WithERC721(from_, to_, value_); } /** * @dev This function handles the transfer of ERC-20 tokens and optionally adjusts the ERC-721 token balances based on the transfer exemptions. * * Requirements: * - The sender (`from_`) must have a balance of at least `value_`. * * Emits: * - {IERC20.Transfer} event for ERC-20 and possibly a {IERC721.Transfer} for each ERC-721 Token. * * @param from_ Address sending the tokens. * @param to_ Address receiving the tokens. * @param value_ Amount of ERC-20 tokens to transfer. * @return bool True if the transfer is successful. */ function _transferERC20WithERC721(address from_, address to_, uint256 value_) internal virtual returns (bool) { uint256 erc20BalanceOfSenderBefore = _balances[from_]; uint256 erc20BalanceOfReceiverBefore = _balances[to_]; if (erc20BalanceOfSenderBefore < value_) revert ERC20InsufficientBalance(from_, erc20BalanceOfSenderBefore, value_); unchecked { _balances[from_] -= value_; _balances[to_] += value_; } assembly { // emit IERC20.Transfer(from_, to_, value_); mstore(0x00, value_) log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(to_, _BITMASK_LOWER160BITS)) } // Skip ERC-721 transfer to exempt addresses to save gas bool isFromERC721TransferExempt = _erc721TransferExempt[from_]; bool isToERC721TransferExempt = _erc721TransferExempt[to_]; if (isFromERC721TransferExempt && isToERC721TransferExempt) { // Case 1) Both sender and recipient are ERC-721 transfer exempt. No ERC-721s need to be transferred. } else if (isFromERC721TransferExempt) { // Case 2) The sender is ERC-721 transfer exempt, but the recipient is not. unchecked { uint256 tokensToRetrieveFromStash = (_balances[to_] / _UNIT) - (erc20BalanceOfReceiverBefore / _UNIT); _retrieveFromStash(to_, tokensToRetrieveFromStash); } } else if (isToERC721TransferExempt) { // Case 3) The sender is not ERC-721 transfer exempt, but the recipient is. unchecked { uint256 tokensToStash = (erc20BalanceOfSenderBefore / _UNIT) - (_balances[from_] / _UNIT); _stash(from_, tokensToStash); } } else { // Case 4) Neither the sender nor the recipient are ERC-721 transfer exempt. _batchTransferERC721WithBalanceAdjustment(from_, to_, erc20BalanceOfSenderBefore, erc20BalanceOfReceiverBefore, value_); } return true; } /** * @dev Internal function to batch transfer ERC721 tokens with balance adjustment. * * Emits a {IERC721.Transfer} event for each token transferred, including the initial token ID and all subsequent IDs in the batch. * * @param from_ The address from which to transfer tokens. * @param to_ The address to which to transfer tokens. * @param fromPreviousBalance_ The previous balance of tokens for the sender. * @param toPreviousBalance_ The previous balance of tokens for the recipient. * @param transferedValue_ The value of tokens to be transferred. */ function _batchTransferERC721WithBalanceAdjustment(address from_, address to_, uint256 fromPreviousBalance_, uint256 toPreviousBalance_, uint256 transferedValue_) internal { uint256 tokenId; uint256 end; uint256 nftsToTransfer = transferedValue_ / _UNIT; for (uint256 i = 0; i < nftsToTransfer; ) { // Transfers the whole batch uint256 lastOwnedIndex = _owned[from_].length - 1; (uint256 batchInitialId_, uint256 batchQuantity_) = _getOwnedBatchInitialIdAndQuantity(from_, lastOwnedIndex); if (batchQuantity_ + i <= nftsToTransfer) { // Transfer whole batch _owned[to_].push(_owned[from_][lastOwnedIndex]); _owned[from_].pop(); uint256 lastToIndex = _owned[to_].length - 1; _setOwnedData(batchInitialId_, to_, lastToIndex); unchecked { tokenId = batchInitialId_; end = batchInitialId_ + batchQuantity_; i += batchQuantity_; } } else { // Transfers part of the batch unchecked { uint256 tokensToTransfer = nftsToTransfer - i; uint256 tokensInPreviousBatch = batchQuantity_ - tokensToTransfer; _setOwned(batchInitialId_, from_, lastOwnedIndex, tokensInPreviousBatch); uint256 newBatchInitialId = batchInitialId_ + tokensInPreviousBatch; _batchHead.set(newBatchInitialId); _pushOwned(newBatchInitialId, to_, tokensToTransfer); _setOwnedData(newBatchInitialId, to_, _owned[to_].length - 1); tokenId = newBatchInitialId; end = newBatchInitialId + tokensToTransfer; i = nftsToTransfer; } } unchecked { for (uint256 j = tokenId; j < end; ++j) { delete _tokenApprovals[j]; // On transfer, any previous approval is reset. assembly { // emit IERC721.Transfer(from_, to_, emitInitialId); log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(to_, _BITMASK_LOWER160BITS), j) } } } } // If the transfer changes either the sender or the recipient's holdings from a fractional to a non-fractional // amount (or vice versa), adjust ERC-721s. unchecked { // First check if the send causes the sender to lose a whole token that was represented by an ERC-721 // due to a fractional part being transferred. if (fromPreviousBalance_ / _UNIT - _balances[from_] / _UNIT > nftsToTransfer) { _stash(from_, 1); } // Then, check if the transfer causes the receiver to gain a whole new token which requires gaining // an additional ERC-721. if (_balances[to_] / _UNIT - toPreviousBalance_ / _UNIT > nftsToTransfer) { _retrieveFromStash(to_); } } } /** * @dev Internal virtual function to stash ERC721 tokens. * * Emits a {IERC721.Transfer} event for each token stashed. * * @param from_ The address from which to stash tokens. * @param quantity_ The quantity of tokens to be stashed. */ function _stash(address from_, uint256 quantity_) internal virtual { unchecked { uint256 batchInitialId_; uint256 batchQuantity_; uint256 data; // Stash loop variables uint256 begin; uint256 end; for (uint256 stashed = 0; stashed < quantity_; ) { data = _owned[from_][_owned[from_].length - 1]; assembly { batchInitialId_ := and(data, _BITMASK_LOWER160BITS) batchQuantity_ := shr(160, data) } if (stashed + batchQuantity_ <= quantity_) { // Transfer the whole batch delete _ownedData[batchInitialId_]; _batchHead.setBatch(batchInitialId_, batchQuantity_); // Set batchead in a massive way to all tokens. _owned[from_].pop(); // Remove batch from owned ids stashed += batchQuantity_; // Increment the stashed items begin = batchInitialId_; end = begin + batchQuantity_; } else { // Only transfer the amount needed, maintain the batch uint256 tokensToStash = quantity_ - stashed; uint256 nonStashedBatchSize = batchQuantity_ - tokensToStash; begin = batchInitialId_ + nonStashedBatchSize; end = begin + tokensToStash; _batchHead.setBatch(begin, tokensToStash); // Set batchead in a massive way to all tokens to be stashed _setOwned(batchInitialId_, from_, _owned[from_].length - 1, nonStashedBatchSize); // Update the batch size stashed = quantity_; // Update the stashed items } address mutableStashAddress = _STASH_ADDRESS; for (uint256 i=begin; i<end; ++i) { _stashQueue.pushFront(i); delete _tokenApprovals[i]; // On stash of a token, any previous approval is reset. assembly { // emit IERC721.Transfer(from_, _STASH_ADDRESS, tokenId); log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(from_, _BITMASK_LOWER160BITS), and(mutableStashAddress, _BITMASK_LOWER160BITS), i) } } } } } /** * @dev Internal virtual function to retrieve ERC721 tokens from the stash. * * Emits a {IERC721.Transfer} event for each token retrieved. * * @param to_ The address to which retrieved tokens will be transferred. */ function _retrieveFromStash(address to_) internal virtual { uint256 id = _stashQueue.popBack(); _pushOwned(id, to_, 1); unchecked { _setOwnedData(id, to_, _owned[to_].length - 1); } address mutableStashAddress = _STASH_ADDRESS; assembly { // emit IERC721.Transfer(_STASH_ADDRESS, to_, tokenId); log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(mutableStashAddress, _BITMASK_LOWER160BITS), and(to_, _BITMASK_LOWER160BITS), id) } } /** * @dev Internal function to retrieve multiple ERC721 tokens from the stash and transfer them to a recipient. * * Emits a {IERC721.Transfer} event for each token retrieved, including the token ID transferred to the recipient. * * @param to_ The address to which retrieved tokens will be transferred. * @param amount_ The number of tokens to retrieve from the stash. */ function _retrieveFromStash(address to_, uint256 amount_) internal { for (uint256 i = 0; i < amount_; ) { _retrieveFromStash(to_); unchecked { ++i; } } } /** * @dev See {IERC404-approve}. */ function approve(address spender_, uint256 valueOrId_) public virtual returns (bool) { if (_exists(valueOrId_)) { _erc721Approve(spender_, valueOrId_); } else { return _erc20Approve(spender_, valueOrId_); } return true; } /** * @dev Approves a specific address to transfer the specified ERC-721 token. * * Requirements: * - The caller must be the owner of the ERC-721 token or have been approved by the owner. * * Emits: * - {IERC721.Approval} event for ERC-721 Tokens. * * @param spender_ Address to be approved for the specified ERC-721 token. * @param id_ ID of the ERC-721 token to be approved. */ function _erc721Approve(address spender_, uint256 id_) public virtual { address erc721Owner = ownerOf(id_); if (msg.sender != erc721Owner && !isApprovedForAll(erc721Owner, msg.sender)) { revert ERC721InvalidApprover(msg.sender); } _tokenApprovals[id_] = spender_; assembly { // emit IERC721.Approval(erc721Owner, spender_, id_); log4(0x00, 0x00, _APPROVAL_EVENT_SIGNATURE, and(erc721Owner, _BITMASK_LOWER160BITS), and(spender_, _BITMASK_LOWER160BITS), id_) } } /** * @dev Approves a specific address to spend a specified amount of ERC-20 tokens on behalf of the caller. * * Requirements: * - The spender address must not be the zero address. * * Emits: * - {IERC20.Approval} event for ERC-20 Tokens. * * @param spender_ Address to be approved for spending the specified ERC-20 tokens. * @param value_ Amount of ERC-20 tokens to be approved for spending. * @return bool True if the approval is successful. */ function _erc20Approve(address spender_, uint256 value_) public virtual returns (bool) { address owner = msg.sender; if (spender_ == address(0) || spender_ == _STASH_ADDRESS) { revert ERC20InvalidSpender(spender_); } _allowances[owner][spender_] = value_; assembly { // emit IERC20.Approval(msg.sender, spender_, value_); let ownerMasked := and(owner, _BITMASK_LOWER160BITS) let approvedMasked := and(spender_, _BITMASK_LOWER160BITS) mstore(0x00, value_) log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, ownerMasked, approvedMasked) } return true; } /** * @dev See {IERC20Permit-permit}. */ function permit(address owner_, address spender_, uint256 value_, uint256 deadline_, uint8 v_, bytes32 r_, bytes32 s_) public virtual { if (deadline_ < block.timestamp) { revert EIP2612PermitDeadlineExpired(owner_, spender_, value_, deadline_, v_, r_, s_); } // permit cannot be used for ERC-721 token approvals, so ensure // the value does not fall within the valid range of ERC-721 token ids. if (_exists(value_)) { revert ERC404InvalidTransferValue(value_); } if (spender_ == address(0) || spender_ == _STASH_ADDRESS) { revert ERC20InvalidSpender(spender_); } unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"), owner_, spender_, value_, nonces[owner_]++, deadline_ ) ) ) ), v_, r_, s_ ); if (recoveredAddress == address(0) || recoveredAddress != owner_) { revert EIP2612InvalidSigner(recoveredAddress, owner_, spender_, value_, deadline_, v_, r_, s_); } _allowances[recoveredAddress][spender_] = value_; } assembly { // emit IERC20.Approval(owner_, spender_, value_); let ownerMasked := and(owner_, _BITMASK_LOWER160BITS) let approvedMasked := and(spender_, _BITMASK_LOWER160BITS) mstore(0x00, value_) log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, ownerMasked, approvedMasked) } } /** * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. */ function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == _INITIAL_CHAIN_ID ? _INITIAL_DOMAIN_SEPARATOR : _computeDomainSeparator(); } /** * @notice Internal function to compute the domain separator for EIP-2612 permits. * @dev This function computes the domain separator based on the contract's name, version, chain ID, and address. * * @return bytes32 The computed domain separator value. */ function _computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(_name)), keccak256("1"), block.chainid, address(this) ) ); } /** * @dev See {IERC404-isERC721TransferExempt}. */ function isERC721TransferExempt(address target_) external view override returns (bool isExempt) { isExempt = _erc721TransferExempt[target_]; } /** * @dev See {IERC404-setERC721TransferExempt}. */ function setERC721TransferExempt(bool state_) external override { _setERC721TransferExempt(msg.sender, state_); } /** * @dev Internal function to set the exemption status for ERC-721 transfers. * * Requirements: * - `target_` address cannot be the zero address or the stash address. * * @param target_ The address for which to set the exemption status. * @param state_ The new exemption state to set (true for exempt, false for non-exempt). */ function _setERC721TransferExempt(address target_, bool state_) internal virtual { if (target_ == address(0) || target_ == _STASH_ADDRESS) { revert ERC404InvalidERC721Exemption(target_); } // Adjust the ERC721 balances of the target to respect exemption rules. if (state_) { _stashAll(target_); } else { _retrieveAllFromStash(target_); } _erc721TransferExempt[target_] = state_; } /** * @dev Internal function to stash all ERC-721 tokens owned by the target address. * * Emits: * - {IERC721.Transfer} event for ERC-721 tokens being transferred to the stash. * * @param target_ The address whose tokens are to be stashed. */ function _stashAll(address target_) private { uint256[] memory ownedTarget = _owned[target_]; for (uint256 i = 0; i < ownedTarget.length; ) { (uint256 batchInitialId_, uint256 batchQuantity_) = _getOwnedBatchInitialIdAndQuantity(target_, i); delete _ownedData[batchInitialId_]; // Resets _ownedData _batchHead.setBatch(batchInitialId_, batchQuantity_); // Set batchead in a massive way to all tokens. // add all tokens to the stash unchecked { uint256 end = batchInitialId_ + batchQuantity_; address mutableStashAddress = _STASH_ADDRESS; for (uint256 b = batchInitialId_; b < end; ++b) { delete _tokenApprovals[b]; // On stash of a token, any previous approval is reset. _stashQueue.pushFront(b); assembly { // emit IERC721.Transfer(target_, _STASH_ADDRESS, batchInitialId_); log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, and(target_, _BITMASK_LOWER160BITS), and(mutableStashAddress, _BITMASK_LOWER160BITS), b) } } ++i; } } delete _owned[target_]; } /** * @dev Internal function to retrieve all ERC-721 tokens from the stash for the target address. * * Emits: * - {IERC721.Transfer} event for ERC-721 tokens being transferred from the stash. * * @param target_ The address to retrieve ERC-721 tokens for. */ function _retrieveAllFromStash(address target_) private { uint256 expectedERC721Balance = _balances[target_] / _UNIT; uint256 actualERC721Balance = 0; uint256[] memory ownedTarget = _owned[target_]; for (uint256 i = 0; i < ownedTarget.length; ) { uint256 data = ownedTarget[i]; assembly { actualERC721Balance := add(actualERC721Balance, shr(160, data)) i := add(i, 1) // Avoiding an unchecked block after this one } } unchecked { expectedERC721Balance -= actualERC721Balance; for (uint256 i = 0; i < expectedERC721Balance; ++i) { // Transfer ERC721 balance in from pool _retrieveFromStash(target_); } } } /** * @dev See {IERC404-owned}. */ function owned(address owner_) public view virtual returns (uint256[] memory ownedCreatureIds) { if (owner_ == _STASH_ADDRESS) return tokensInStash(); uint256 size = 0; uint256 data; uint256[] memory ownedOwner = _owned[owner_]; for (uint256 i = 0; i < ownedOwner.length; ) { data = ownedOwner[i]; assembly { size := add(size, shr(160, data)) i := add(i, 1) } } ownedCreatureIds = new uint256[](size); unchecked { uint256 ix = 0; uint256 batchInitialId_; uint256 batchQuantity_; for (uint256 i = 0; i < ownedOwner.length; ++i) { data = ownedOwner[i]; assembly { batchInitialId_ := and(data, _BITMASK_LOWER160BITS) batchQuantity_ := shr(160, data) } for (uint256 j = 0; j < batchQuantity_; ++j) { ownedCreatureIds[ix] = batchInitialId_ + j; ++ix; } } } } /** * @dev Internal function to burn (destroy) an ERC-721 token. * * Emits: * - {IERC721.Transfer} event from `from` to `address(0)` (burning the token). * - {IERC20.Transfer} event from `from` to `address(0)` with `_UNIT` value (The ERC-20 side of the token). * * @param tokenId_ ID of the ERC-721 token to be burned. */ function _burn(uint256 tokenId_) internal virtual { if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_); (address from, uint256 index, uint256 tokenIdBatchHead) = _getOwnerOwnedIndexAndBatchHeadId(tokenId_); // _beforeTokenTransfers(from, to, tokenId, 1); delete _tokenApprovals[tokenId_]; // On transfer, any previous approval is reset. uint256 batchQuantity_; uint256 data = _owned[from][index]; assembly { batchQuantity_ := shr(160, data) } _removeTokenFrom(from, index, tokenId_, tokenIdBatchHead, batchQuantity_); delete _ownedData[tokenId_]; _batchHead.set(tokenId_); _burnedTokens.set(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[from] -= _UNIT; ++_burnedCount; } data = _UNIT; assembly { let fromMasked := and(from, _BITMASK_LOWER160BITS) // emit IERC20.Transfer(from_, to_, _UNIT); mstore(0x00, data) log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, fromMasked, 0x00) // emit IERC721.Transfer(from, address(0), tokenId_); log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, fromMasked, 0x00, tokenId_) } // _afterTokenTransfers(from, address(0), tokenId, 1); } /** * @dev See {IERC404-stashAddress}. */ function stashAddress() public view returns (address) { return _STASH_ADDRESS; } /** * @dev See {IERC404-stashLength}. */ function stashLength() public view returns (uint256) { return _stashQueue.length(); } /** * @dev See {IERC404-tokensInStash}. */ function tokensInStash() public view returns (uint256[] memory) { return _stashQueue.retriveQueueItems(); } /** * @dev See {IERC404-exchangeWithStash}. */ function exchangeWithStash(uint256 tokenId_, uint128 index_) public { uint256 stashTokenId = _stashQueue.at(index_); if (!_exists(tokenId_)) revert ERC721NonexistentToken(tokenId_); if (!_isApprovedOrOwner(msg.sender, tokenId_)) revert ERC721InsufficientApproval(msg.sender, tokenId_); (address owner, uint256 index, uint256 tokenIdBatchHead) = _getOwnerOwnedIndexAndBatchHeadId(tokenId_); // _beforeTokenTransfers(msg.sender, _STASH_ADDRESS, tokenId_, 1); // _beforeTokenTransfers(_STASH_ADDRESS, msg.sender, stashTokenId, 1); delete _tokenApprovals[tokenId_]; // On transfer, any previous approval is reset. uint256 batchQuantity_; uint256 data = _owned[owner][index]; assembly { batchQuantity_ := shr(160, data) } _removeTokenFrom(owner, index, tokenId_, tokenIdBatchHead, batchQuantity_); delete _ownedData[tokenId_]; _batchHead.set(tokenId_); _stashQueue.setIndexValue(index_, tokenId_); // Sets the token to exchange into the stash // Now, sets the Stash token to the tokenId owner assembly { data := add(and(stashTokenId, _BITMASK_LOWER160BITS), and(shl(160, 1), _BITMASK_UPPER96BITS)) } _owned[owner].push(data); unchecked { uint256 ownedIndex = _owned[owner].length - 1; assembly { data := add(and(owner, _BITMASK_LOWER160BITS), and(shl(160, ownedIndex), _BITMASK_UPPER96BITS)) } } _ownedData[stashTokenId] = data; address stashMasked = _STASH_ADDRESS; assembly { stashMasked := and(stashMasked, _BITMASK_LOWER160BITS) let ownerMasked := and(owner, _BITMASK_LOWER160BITS) // emit IERC721.Transfer(_STASH_ADDRESS, owner, stashTokenId); log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, stashMasked, ownerMasked, stashTokenId) // emit IERC721.Transfer(owner, _STASH_ADDRESS, tokenId_); log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, ownerMasked, stashMasked, tokenId_) } // _afterTokenTransfers(msg.sender, _STASH_ADDRESS, tokenId_, 1); // _afterTokenTransfers(_STASH_ADDRESS, msg.sender, stashTokenId, 1); } }
// contracts/erc404/IERC404B.sol // SPDX-License-Identifier: MIT /** /3333333 /33333333 /333333 | 33__ 33 | 33_____/ /33__ 33 | 33 \ 33 | 33 | 33 \__/ | 3333333 | 33333 | 33 | 33__ 33 | 33__/ | 33 | 33 \ 33 | 33 | 33 33 | 3333333/ | 33333333 | 333333/ |_______/ |________/ \______/ # https://blackeyedcreatures.com */ pragma solidity ^0.8.25; import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol"; import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; /** * @title IERC404B Interface * @dev Interface for a hybrid token contract combining ERC20 and ERC721 functionalities with a unique "stash" feature. * The stash is a holding area for tokens that are currently unowned but not burned, allowing for controlled management and re-distribution. * Supports ERC165 for interface detection and ERC20Permit for token allowance via signatures. */ interface IERC404B is IERC165, IERC20Permit { /// IERC20 + ERC721 Metadata Methods /// /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() external view returns (uint8); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); /// ERC721 Methods /// /** * @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 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); /// ERC20 Methods /// /** * @dev Returns the amount of ERC20 tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Moves `amountOrId` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits {Transfer} events. */ function transfer(address to, uint256 amountOrId) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /// ERC404 Combined (Methods with similar interfaces and behavior in ERC20 & ERC721) /// /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256 balance); /** * @dev Moves `amountOrId` tokens from `from` to `to` using the * allowance mechanism. `amountOrId` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * WARNING: In case of Id, 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. * - `amountOrId` amount should be less or equal than balance OR tokenId 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 {Transfer} events. */ function transferFrom(address from, address to, uint256 amountOrId) external returns (bool); /** * @dev Sets `amountOrId` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amountOrId) external returns (bool); /// ERC404 Specific /// /** * @notice Retrieves the equivalence between 1 ERC721 token and ERC20 needed for that token. * @dev This function returns the unit value used in conversions between ERC721 and ERC20 tokens. * @return The unit value representing the equivalence between 1 ERC721 token and ERC20. */ function unit() external view returns (uint256); /** * @notice Checks if the specified token exists. * * A token is considered to exist if it has been minted using {_mint} and is not in the set of burned tokens. * * @param tokenId_ The ID of the token to check. * @return True if the token exists, false otherwise. */ function exists(uint256 tokenId_) external view returns (bool); /** * @dev Checks if the specified address is exempt from ERC-721 transfers. * This function retrieves the exemption status for ERC-721 transfers for the given address. * * @param target_ The address to check for ERC-721 transfer exemption. * @return isExempt True if the address is exempt from ERC-721 transfers, false otherwise. */ function isERC721TransferExempt(address target_) external view returns (bool isExempt); /** * @dev Sets the exemption status for ERC-721 transfers for the caller. * * Emits: * - {Transfer} event for each target_ ERC721 token from/to the stash. * * @param state_ The new exemption state to set (true for exempt, false for non-exempt). */ function setERC721TransferExempt(bool state_) external; /** * @dev Retrieves the IDs of ERC-721 tokens owned by a specific address. * * @param owner_ The address for which ERC-721 token IDs are being retrieved. * @return ownedCreatureIds An array of uint256 representing the ERC-721 token IDs owned by the specified address. */ function owned(address owner_) external view returns (uint256[] memory); /** * @dev External function to get the current stash address. * * @return address Current stash address. */ function stashAddress() external view returns (address); /** * @dev External function to get the current length of the stash queue. * * @return uint256 Current length of the stash queue. */ function stashLength() external view returns (uint256); /** * @dev External function to retrieve all tokens currently in the stash queue. * * @return uint256[] An array containing all tokens currently in the stash queue. */ function tokensInStash() external view returns (uint256[] memory); /** * @dev Public function to exchange an ERC-721 token with a token in the stash. * * Requirements: * - The caller must be the owner or have approval to transfer the tokenId_. * - The stashTokenId_ must belong to the stash. * * Emits: * - {Transfer} event for the token exchanged from the stash to the caller. * - {Transfer} event for the token exchanged from the caller to the stash. * * @param tokenId_ The ID of the ERC-721 token to exchange. * @param index_ The index of the token at the stash to exchange with. */ function exchangeWithStash(uint256 tokenId_, uint128 index_) external; }
// contracts/erc404/IERC404BErrors.sol // SPDX-License-Identifier: MIT /** /3333333 /33333333 /333333 | 33__ 33 | 33_____/ /33__ 33 | 33 \ 33 | 33 | 33 \__/ | 3333333 | 33333 | 33 | 33__ 33 | 33__/ | 33 | 33 \ 33 | 33 | 33 33 | 3333333/ | 33333333 | 333333/ |_______/ |________/ \______/ # https://blackeyedcreatures.com */ pragma solidity ^0.8.25; /** * @dev ERC404B3Errors interface defines custom error messages for the ERC404B3 contract. */ interface IERC404BErrors { /** * @dev Indicates that the specified token is not found in the stash. * @param stashTokenId The ID of the token in the stash. */ error ERC404TokenNotInStash(uint256 stashTokenId); /** * @dev Indicates that the index value provided is not valid in the stash queue. * @param indexInQueue The index value in the queue. * @param stashTokenId The ID of the token in the stash. */ error ERC404NotValidIndexValueInStash(uint128 indexInQueue, uint256 stashTokenId); /** * @dev Indicates that the transfer value is invalid. * @param value The invalid transfer value. */ error ERC404InvalidTransferValue(uint256 value); /** * @dev Indicates that the target address is not eligible for ERC721 exemption. * @param target The address that is not eligible for exemption. */ error ERC404InvalidERC721Exemption(address target); /** * @dev Indicates an overflow in the owned index. * @param index The index value causing the overflow. */ error ERC404OwnedIndexOverflow(uint256 index); /** * @dev Indicates an invalid mint quantity for ERC721. */ error ERC721InvalidMintQuantity(); /** * @dev Indicates that the recipient address has not implemented ERC721Receiver. * @param to The recipient address. * @param tokenId The ID of the token being transferred. * @param quantity The quantity of tokens being transferred. * @param data Additional data for the transfer. */ error ERC721ReceiverNotImplemented(address to, uint256 tokenId, uint256 quantity, bytes data); /** * @dev Indicates that the permit deadline has expired for EIP-2612 permit. * @param owner The owner of the tokens. * @param spender The spender of the tokens. * @param value The token value. * @param deadline The expired deadline. * @param v Signature parameter v. * @param r Signature parameter r. * @param s Signature parameter s. */ error EIP2612PermitDeadlineExpired(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s); /** * @dev Indicates that the signer of the permit is invalid for EIP-2612 permit. * @param recoveredAddress The recovered signer address. * @param owner The owner of the tokens. * @param spender The spender of the tokens. * @param value The token value. * @param deadline The permit deadline. * @param v Signature parameter v. * @param r Signature parameter r. * @param s Signature parameter s. */ error EIP2612InvalidSigner(address recoveredAddress, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/DoubleEndedQueue.sol) // Modified by Pandora Labs to support native uint256 operations // Modified by 42i.co to retriveQueueItems && setIndexValue pragma solidity ^0.8.25; /** * @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of * the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and * FIFO queues. Storage use is optimized, and all operations are O(1) constant time. This includes {clear}, given that * the existing queue contents are left in storage. * * The struct is called `Uint256Deque`. This data structure can only be used in storage, and not in memory. * * ```solidity * DoubleEndedQueue.Uint256Deque queue; * ``` */ library DoubleEndedQueue { /** * @dev An operation (e.g. {front}) couldn't be completed due to the queue being empty. */ error QueueEmpty(); /** * @dev A push operation couldn't be completed due to the queue being full. */ error QueueFull(); /** * @dev An operation (e.g. {at}) couldn't be completed due to an index being out of bounds. */ error QueueOutOfBounds(); /** * @dev Indices are 128 bits so begin and end are packed in a single storage slot for efficient access. * * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and * lead to unexpected behavior. * * The first item is at data[begin] and the last item is at data[end - 1]. This range can wrap around. */ struct Uint256Deque { uint128 _begin; uint128 _end; mapping(uint128 index => uint256) _data; } /** * @dev Retrieves all items from the queue as an array of uint256 values. * This function does not modify the state of the queue. */ function retriveQueueItems(Uint256Deque storage deque) internal view returns (uint256[] memory dequeTokens) { unchecked { uint128 beginIndex = deque._begin; uint128 queueLenght = deque._end - beginIndex; dequeTokens = new uint256[](queueLenght); for (uint128 i = 0; i < queueLenght; ++i) { dequeTokens[i] = deque._data[beginIndex+i]; } } } /** * @dev Sets the value at a specific index in the queue. The index is relative to the current `begin` of the queue. * This function allows for direct manipulation of queue items at a given index, and should be used with caution as * improper usage can lead to logical errors in the queue state. * * Reverts with `QueueOutOfBounds` if the index is out of bounds. */ function setIndexValue(Uint256Deque storage deque, uint128 index, uint256 value) internal { if (index >= length(deque)) revert QueueOutOfBounds(); deque._data[index+deque._begin] = value; } /** * @dev Inserts an item at the end of the queue. * * Reverts with {QueueFull} if the queue is full. */ function pushBack(Uint256Deque storage deque, uint256 value) internal { unchecked { uint128 backIndex = deque._end; if (backIndex + 1 == deque._begin) revert QueueFull(); deque._data[backIndex] = value; deque._end = backIndex + 1; } } /** * @dev Removes the item at the end of the queue and returns it. * * Reverts with {QueueEmpty} if the queue is empty. */ function popBack( Uint256Deque storage deque ) internal returns (uint256 value) { unchecked { uint128 backIndex = deque._end; if (backIndex == deque._begin) revert QueueEmpty(); --backIndex; value = deque._data[backIndex]; delete deque._data[backIndex]; deque._end = backIndex; } } /** * @dev Inserts an item at the beginning of the queue. * * Reverts with {QueueFull} if the queue is full. */ function pushFront(Uint256Deque storage deque, uint256 value) internal { unchecked { uint128 frontIndex = deque._begin - 1; if (frontIndex == deque._end) revert QueueFull(); deque._data[frontIndex] = value; deque._begin = frontIndex; } } /** * @dev Removes the item at the beginning of the queue and returns it. * * Reverts with `QueueEmpty` if the queue is empty. */ function popFront( Uint256Deque storage deque ) internal returns (uint256 value) { unchecked { uint128 frontIndex = deque._begin; if (frontIndex == deque._end) revert QueueEmpty(); value = deque._data[frontIndex]; delete deque._data[frontIndex]; deque._begin = frontIndex + 1; } } /** * @dev Returns the item at the beginning of the queue. * * Reverts with `QueueEmpty` if the queue is empty. */ function front( Uint256Deque storage deque ) internal view returns (uint256 value) { if (empty(deque)) revert QueueEmpty(); return deque._data[deque._begin]; } /** * @dev Returns the item at the end of the queue. * * Reverts with `QueueEmpty` if the queue is empty. */ function back( Uint256Deque storage deque ) internal view returns (uint256 value) { if (empty(deque)) revert QueueEmpty(); unchecked { return deque._data[deque._end - 1]; } } /** * @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at * `length(deque) - 1`. * * Reverts with `QueueOutOfBounds` if the index is out of bounds. */ function at( Uint256Deque storage deque, uint256 index ) internal view returns (uint256 value) { if (index >= length(deque)) revert QueueOutOfBounds(); // By construction, length is a uint128, so the check above ensures that index can be safely downcast to uint128 unchecked { return deque._data[deque._begin + uint128(index)]; } } /** * @dev Resets the queue back to being empty. * * NOTE: The current items are left behind in storage. This does not affect the functioning of the queue, but misses * out on potential gas refunds. */ function clear(Uint256Deque storage deque) internal { deque._begin = 0; deque._end = 0; } /** * @dev Returns the number of items in the queue. */ function length(Uint256Deque storage deque) internal view returns (uint256) { unchecked { return uint256(deque._end - deque._begin); } } /** * @dev Returns true if the queue is empty. */ function empty(Uint256Deque storage deque) internal view returns (bool) { return deque._end == deque._begin; } }
// contracts/IBECErrors.sol // SPDX-License-Identifier: MIT /** /3333333 /33333333 /333333 | 33__ 33 | 33_____/ /33__ 33 | 33 \ 33 | 33 | 33 \__/ | 3333333 | 33333 | 33 | 33__ 33 | 33__/ | 33 | 33 \ 33 | 33 | 33 33 | 3333333/ | 33333333 | 333333/ |_______/ |________/ \______/ # https://blackeyedcreatures.com */ pragma solidity ^0.8.25; /** * @title IBECErrors * @dev Interface for Black Eyed Creatures (BEC) custom errors. * @author https://42i.co */ interface IBECErrors { /** * @dev Indicates that a minting operation attempted to mint zero creatures. */ error BECZeroQuantityMinting(); /** * @dev Indicates that a minting operation has exceeded the cap limit for creatures. */ error BECCapLimitReached(); /** * @dev Indicates that invalid ambassadors were provided. * @param alpha ID of the first ambassador. * @param beta ID of the second ambassador. * @param gamma ID of the third ambassador. */ error BECInvalidAmbassadors(uint256 alpha, uint256 beta, uint256 gamma); /** * @dev Indicates that an incorrect number of ambassadors was provided. * @param length The number of ambassadors provided. */ error BECInvalidAmbassadorsLength(uint256 length); /** * @dev Indicates that a creature is already set as a variation ambassador. * @param creatureId The ID of the creature. */ error BECAlreadyVariationAmbassador(uint256 creatureId); /** * @dev Indicates that a creature is already set as a family ambassador. * @param creatureId The ID of the creature. */ error BECAlreadyFamilyAmbassador(uint256 creatureId); /** * @dev Indicates that a creature is not a variation ambassador when required. * @param creatureId The ID of the creature. */ error BECNotVariationAmbassador(uint256 creatureId); /** * @dev Indicates that an invalid phenotype was provided. * @param phenotype The invalid phenotype identifier. */ error BECInvalidPhenotype(uint256 phenotype); /** * @dev Indicates that an invalid family was provided for a creature. * @param creatureId The ID of the creature. */ error BECInvalidFamily(uint256 creatureId); /** * @dev Indicates that an invalid variation was provided for a creature. * @param creatureId The ID of the creature. */ error BECInvalidVariation(uint256 creatureId); /** * @dev Indicates that an invalid name was provided, either empty or too long. * @param name The invalid name submitted. */ error BECInvalidName(string name); /** * @dev Indicates that a duplicated name was provided. * @param name The duplicate name submitted. */ error BECDuplicatedName(string name); /** * @dev Indicates that a variation name has already been set for a given phenotype, family, and variation. * @param phenotype The phenotype identifier. * @param family The family identifier. * @param variation The variation identifier. */ error BECVariationNameAlreadySet(uint256 phenotype, uint256 family, uint256 variation); /** * @dev Indicates that a family name has already been set for a given phenotype and family. * @param phenotype The phenotype identifier. * @param family The family identifier. */ error BECFamilyNameAlreadySet(uint256 phenotype, uint256 family); /** * @dev Indicates that not all variations have been set for a given phenotype and family. * @param phenotype The phenotype identifier. * @param family The family identifier. * @param variation The variation identifier that is missing. */ error BECNotAllVariationsSet(uint256 phenotype, uint256 family, uint256 variation); /** * @dev Indicates that not all required variations were present. */ error BECNotAllVariationsPresent(); /** * @dev Indicates that a hunt has already finished. */ error BECHuntFinished(); /** * @dev Indicates that the ritual price was not fully paid. * @param price The expected price. * @param paid The amount that was actually paid. */ error BECRitualPriceNotPaid(uint256 price, uint256 paid); /** * @dev Indicates that the maximum number of hunts allowed was exceeded. * @param allowed The allowed number of hunts. * @param required The required number of hunts attempted. */ error BECMaxHuntsAllowed(uint256 allowed, uint256 required); /** * @dev Indicates that the maximum number of reproductions allowed was exceeded. * @param allowed The allowed number of reproductions. * @param required The required number of reproductions attempted. */ error BECMaxReproductionsAllowed(uint256 allowed, uint256 required); /** * @dev Indicates that the maximum number of reproductions for a specific creature was exceeded. * @param creatureId The ID of the creature. * @param allowed The allowed number of reproductions for this creature. * @param required The required number of reproductions attempted. */ error BECMaxCreatureReproductionsAllowed(uint256 creatureId, uint256 allowed, uint256 required); /** * @dev Indicates that the creature is not of type 0, which is required for the operation. * @param creatureId The ID of the creature. */ error BECNotType0Creature(uint256 creatureId); /** * @dev Indicates that the creature is fruitless, meaning it cannot reproduce. * @param creatureId The ID of the creature. */ error BECFruitlessCreature(uint256 creatureId); /** * @dev Indicates that a parent creature was attempted to be used as payment, which is not allowed. * @param creatureId The ID of the creature. */ error BECParentCreatureAsPayment(uint256 creatureId); /** * @dev Indicates that an invalid owner was provided for a token. * @param operator The address of the operator trying to act on the token. * @param tokenId The token ID being acted upon. */ error BECInvalidOwner(address operator, uint256 tokenId); /** * @dev Indicates that there are insufficient funds for the requested operation. * @param requested The amount of funds requested. * @param available The amount of funds available. */ error BECInsufficientFunds(uint256 requested, uint256 available); /** * @dev Indicates that an invalid owner was provided for a Black Sphere. * @param owner The incorrect owner address. * @param blacksphere The Black Sphere ID involved. */ error BlackSphereInvalidOwner(address owner, uint256 blacksphere); /** * @dev Indicates that the function or feature called is not currently enabled. */ error BECNotEnabled(); /** * @dev Indicates that the genesis store for a creature has already been set. * @param creatureId The ID of the creature. */ error BECGenesisStoreAlreadySet(uint256 creatureId); /** * @dev Indicates that the distribution for a creature has already been set. * @param distribution The distribution ID. */ error BECDistributionAlreadySet(uint256 distribution); /** * @dev Indicates that the wrong distribution ID was provided. * @param distributionId The incorrect distribution ID provided. */ error BECWrongDistributionId(uint256 distributionId); /** * @dev Indicates that the domain for a creature has already been set. * @param domain The domain ID. */ error BECDomainAlreadySet(uint256 domain); /** * @dev Indicates that an empty array was provided for golden data. */ error BECEmptyGoldenDataArray(); /** * @dev Indicates that a non-empty golden deltas array was provided when expected to be empty. */ error BECNotEmptyGoldenDeltasArray(); /** * @dev Indicates that more creatures were provided than there are phenotypes available. */ error BECMoreCreaturesThanPhenotypes(); /** * @dev Indicates that an awakening operation has already been performed. */ error BECAlreadyAwaken(); /** * @dev Indicates that IDs were not provided in order. */ error BECIdsNotInOrder(); /** * @dev Indicates that an invalid address was provided. * @param target The target address. */ error BECInvalidAddress(address target); /** * @dev Indicates that an invalid protocol bit was used. */ error BECInvalidProtocolBit(); /** * @dev Indicates that an index was out of bounds. */ error BECIndexOutOfBounds(); }
// contracts/meta-extensions/IBECMetaExtension.sol // SPDX-License-Identifier: MIT /** /3333333 /33333333 /333333 | 33__ 33 | 33_____/ /33__ 33 | 33 \ 33 | 33 | 33 \__/ | 3333333 | 33333 | 33 | 33__ 33 | 33__/ | 33 | 33 \ 33 | 33 | 33 33 | 3333333/ | 33333333 | 333333/ |_______/ |________/ \______/ # https://blackeyedcreatures.com */ pragma solidity ^0.8.25; /** * @title Black Eyed Creatures Meta Extension Interface * @dev Defines the interface for meta extensions within the Black Eyed Creatures ecosystem. * Meta extensions are modular contracts that provide additional token metadata for creatures, enhancing their attributes, * appearance, or interactions within the ecosystem. * @notice Implementations of this interface should ensure that extensions are applied in a manner that is consistent with * the ecosystem's rules and enhances the user experience. * @author https://42i.co */ interface IBECMetaExtension { /** * @notice Applies the meta extension to a creature and returns the additional metadata. * @dev When implemented, this function should handle the logic for appending the creature's metadata based on the extension's purpose. * @param _creatureId The unique identifier of the creature to which the extension is applied. * @return string A string representing the modified or additional metadata for the creature. */ function applyExtension(uint256 _creatureId) external view returns (string memory); }
// contracts/strategies/IBECDnaStrategy.sol // SPDX-License-Identifier: MIT /** /3333333 /33333333 /333333 | 33__ 33 | 33_____/ /33__ 33 | 33 \ 33 | 33 | 33 \__/ | 3333333 | 33333 | 33 | 33__ 33 | 33__/ | 33 | 33 \ 33 | 33 | 33 33 | 3333333/ | 33333333 | 333333/ |_______/ |________/ \______/ # https://blackeyedcreatures.com */ pragma solidity ^0.8.25; /** * @title Black Eyed Creatures DNA Strategy * @notice The strategies are the contracts that mints and generates the metada for the BECs. * This interface helps with the information the genesis engine needs for each creature type. * @dev The genesis engine (through different strategies) creates DNA based in different logis, * but always creating DNA that are compliant with the following order (8b each): * 00: body_family * 01: body_variation * 02: head_family * 03: head_variation * 04: ears_family * 05: ears_variation * 06: face_family * 07: face_variation * 08: hair_family * 09: hair_variation * 10: eyes_family * 11: eyes_variation * 12: bg_color_family * 13: bg_color_variation * 14: skin_color_family * 15: skin_color_variation * 16: secondary_color_family * 17: secondary_color_variation * 18-30: unused * 31: type: normal|golden|ghost|others * * @author https://42i.co */ interface IBECDnaStrategy { /** * @notice Retrieves the DNA of a creature based on its id. * @param _creatureId The id of the creature. * @return uint256 The DNA of the specified creature. */ function getDna(uint256 _creatureId) external view returns (uint256); /** * @notice Gets the metadata tokenURI for this creature. * @param _creatureId The id of the creature. * @return string memory The token uri. */ function tokenURI(uint256 _creatureId) external view returns (string memory); /** * @notice Identifies the strategy ID. * @return uint256 The ID of the strategy. */ function getStrategyId() external view returns (uint256); /** * @notice Identifies the distribution ID associated with this strategy. * @return uint256 The distribution ID. */ function getDistributionId() external view returns (uint256); }
// SPDX-License-Identifier: MIT /** _____ ___ ___ __ ____ _ __ / ___/____ / (_)___/ (_) /___ __ / __ )(_) /______ \__ \/ __ \/ / / __ / / __/ / / / / __ / / __/ ___/ ___/ / /_/ / / / /_/ / / /_/ /_/ / / /_/ / / /_(__ ) /____/\____/_/_/\__,_/_/\__/\__, / /_____/_/\__/____/ /____/ - npm: https://www.npmjs.com/package/solidity-bits - github: https://github.com/estarriolvetch/solidity-bits */ pragma solidity ^0.8.0; import "./BitScan.sol"; import "./Popcount.sol"; /** * @dev This Library is a modified version of Openzeppelin's BitMaps library with extra features. * * 1. Functions of finding the index of the closest set bit from a given index are added. * The indexing of each bucket is modifed to count from the MSB to the LSB instead of from the LSB to the MSB. * The modification of indexing makes finding the closest previous set bit more efficient in gas usage. * 2. Setting and unsetting the bitmap consecutively. * 3. Accounting number of set bits within a given range. * */ /** * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential. * Largelly inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor]. */ library BitMaps { using BitScan for uint256; uint256 private constant MASK_INDEX_ZERO = (1 << 255); uint256 private constant MASK_FULL = type(uint256).max; struct BitMap { mapping(uint256 => uint256) _data; } /** * @dev Returns whether the bit at `index` is set. */ function get(BitMap storage bitmap, uint256 index) internal view returns (bool) { uint256 bucket = index >> 8; uint256 mask = MASK_INDEX_ZERO >> (index & 0xff); return bitmap._data[bucket] & mask != 0; } /** * @dev Sets the bit at `index` to the boolean `value`. */ function setTo( BitMap storage bitmap, uint256 index, bool value ) internal { if (value) { set(bitmap, index); } else { unset(bitmap, index); } } /** * @dev Sets the bit at `index`. */ function set(BitMap storage bitmap, uint256 index) internal { uint256 bucket = index >> 8; uint256 mask = MASK_INDEX_ZERO >> (index & 0xff); bitmap._data[bucket] |= mask; } /** * @dev Unsets the bit at `index`. */ function unset(BitMap storage bitmap, uint256 index) internal { uint256 bucket = index >> 8; uint256 mask = MASK_INDEX_ZERO >> (index & 0xff); bitmap._data[bucket] &= ~mask; } /** * @dev Consecutively sets `amount` of bits starting from the bit at `startIndex`. */ function setBatch(BitMap storage bitmap, uint256 startIndex, uint256 amount) internal { uint256 bucket = startIndex >> 8; uint256 bucketStartIndex = (startIndex & 0xff); unchecked { if(bucketStartIndex + amount < 256) { bitmap._data[bucket] |= MASK_FULL << (256 - amount) >> bucketStartIndex; } else { bitmap._data[bucket] |= MASK_FULL >> bucketStartIndex; amount -= (256 - bucketStartIndex); bucket++; while(amount > 256) { bitmap._data[bucket] = MASK_FULL; amount -= 256; bucket++; } bitmap._data[bucket] |= MASK_FULL << (256 - amount); } } } /** * @dev Consecutively unsets `amount` of bits starting from the bit at `startIndex`. */ function unsetBatch(BitMap storage bitmap, uint256 startIndex, uint256 amount) internal { uint256 bucket = startIndex >> 8; uint256 bucketStartIndex = (startIndex & 0xff); unchecked { if(bucketStartIndex + amount < 256) { bitmap._data[bucket] &= ~(MASK_FULL << (256 - amount) >> bucketStartIndex); } else { bitmap._data[bucket] &= ~(MASK_FULL >> bucketStartIndex); amount -= (256 - bucketStartIndex); bucket++; while(amount > 256) { bitmap._data[bucket] = 0; amount -= 256; bucket++; } bitmap._data[bucket] &= ~(MASK_FULL << (256 - amount)); } } } /** * @dev Returns number of set bits within a range. */ function popcountA(BitMap storage bitmap, uint256 startIndex, uint256 amount) internal view returns(uint256 count) { uint256 bucket = startIndex >> 8; uint256 bucketStartIndex = (startIndex & 0xff); unchecked { if(bucketStartIndex + amount < 256) { count += Popcount.popcount256A( bitmap._data[bucket] & (MASK_FULL << (256 - amount) >> bucketStartIndex) ); } else { count += Popcount.popcount256A( bitmap._data[bucket] & (MASK_FULL >> bucketStartIndex) ); amount -= (256 - bucketStartIndex); bucket++; while(amount > 256) { count += Popcount.popcount256A(bitmap._data[bucket]); amount -= 256; bucket++; } count += Popcount.popcount256A( bitmap._data[bucket] & (MASK_FULL << (256 - amount)) ); } } } /** * @dev Returns number of set bits within a range. */ function popcountB(BitMap storage bitmap, uint256 startIndex, uint256 amount) internal view returns(uint256 count) { uint256 bucket = startIndex >> 8; uint256 bucketStartIndex = (startIndex & 0xff); unchecked { if(bucketStartIndex + amount < 256) { count += Popcount.popcount256B( bitmap._data[bucket] & (MASK_FULL << (256 - amount) >> bucketStartIndex) ); } else { count += Popcount.popcount256B( bitmap._data[bucket] & (MASK_FULL >> bucketStartIndex) ); amount -= (256 - bucketStartIndex); bucket++; while(amount > 256) { count += Popcount.popcount256B(bitmap._data[bucket]); amount -= 256; bucket++; } count += Popcount.popcount256B( bitmap._data[bucket] & (MASK_FULL << (256 - amount)) ); } } } /** * @dev Find the closest index of the set bit before `index`. */ function scanForward(BitMap storage bitmap, uint256 index) internal view returns (uint256 setBitIndex) { uint256 bucket = index >> 8; // index within the bucket uint256 bucketIndex = (index & 0xff); // load a bitboard from the bitmap. uint256 bb = bitmap._data[bucket]; // offset the bitboard to scan from `bucketIndex`. bb = bb >> (0xff ^ bucketIndex); // bb >> (255 - bucketIndex) if(bb > 0) { unchecked { setBitIndex = (bucket << 8) | (bucketIndex - bb.bitScanForward256()); } } else { while(true) { require(bucket > 0, "BitMaps: The set bit before the index doesn't exist."); unchecked { bucket--; } // No offset. Always scan from the least significiant bit now. bb = bitmap._data[bucket]; if(bb > 0) { unchecked { setBitIndex = (bucket << 8) | (255 - bb.bitScanForward256()); break; } } } } } function getBucket(BitMap storage bitmap, uint256 bucket) internal view returns (uint256) { return bitmap._data[bucket]; } }
// SPDX-License-Identifier: MIT /** _____ ___ ___ __ ____ _ __ / ___/____ / (_)___/ (_) /___ __ / __ )(_) /______ \__ \/ __ \/ / / __ / / __/ / / / / __ / / __/ ___/ ___/ / /_/ / / / /_/ / / /_/ /_/ / / /_/ / / /_(__ ) /____/\____/_/_/\__,_/_/\__/\__, / /_____/_/\__/____/ /____/ - npm: https://www.npmjs.com/package/solidity-bits - github: https://github.com/estarriolvetch/solidity-bits */ pragma solidity ^0.8.0; library BitScan { uint256 constant private DEBRUIJN_256 = 0x818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff; bytes constant private LOOKUP_TABLE_256 = hex"0001020903110a19042112290b311a3905412245134d2a550c5d32651b6d3a7506264262237d468514804e8d2b95569d0d495ea533a966b11c886eb93bc176c9071727374353637324837e9b47af86c7155181ad4fd18ed32c9096db57d59ee30e2e4a6a5f92a6be3498aae067ddb2eb1d5989b56fd7baf33ca0c2ee77e5caf7ff0810182028303840444c545c646c7425617c847f8c949c48a4a8b087b8c0c816365272829aaec650acd0d28fdad4e22d6991bd97dfdcea58b4d6f29fede4f6fe0f1f2f3f4b5b6b607b8b93a3a7b7bf357199c5abcfd9e168bcdee9b3f1ecf5fd1e3e5a7a8aa2b670c4ced8bbe8f0f4fc3d79a1c3cde7effb78cce6facbf9f8"; /** @dev Isolate the least significant set bit. */ function isolateLS1B256(uint256 bb) pure internal returns (uint256) { require(bb > 0); unchecked { return bb & (0 - bb); } } /** @dev Isolate the most significant set bit. */ function isolateMS1B256(uint256 bb) pure internal returns (uint256) { require(bb > 0); unchecked { bb |= bb >> 128; bb |= bb >> 64; bb |= bb >> 32; bb |= bb >> 16; bb |= bb >> 8; bb |= bb >> 4; bb |= bb >> 2; bb |= bb >> 1; return (bb >> 1) + 1; } } /** @dev Find the index of the lest significant set bit. (trailing zero count) */ function bitScanForward256(uint256 bb) pure internal returns (uint8) { unchecked { return uint8(LOOKUP_TABLE_256[(isolateLS1B256(bb) * DEBRUIJN_256) >> 248]); } } /** @dev Find the index of the most significant set bit. */ function bitScanReverse256(uint256 bb) pure internal returns (uint8) { unchecked { return 255 - uint8(LOOKUP_TABLE_256[((isolateMS1B256(bb) * DEBRUIJN_256) >> 248)]); } } function log2(uint256 bb) pure internal returns (uint8) { unchecked { return uint8(LOOKUP_TABLE_256[(isolateMS1B256(bb) * DEBRUIJN_256) >> 248]); } } }
// SPDX-License-Identifier: MIT /** _____ ___ ___ __ ____ _ __ / ___/____ / (_)___/ (_) /___ __ / __ )(_) /______ \__ \/ __ \/ / / __ / / __/ / / / / __ / / __/ ___/ ___/ / /_/ / / / /_/ / / /_/ /_/ / / /_/ / / /_(__ ) /____/\____/_/_/\__,_/_/\__/\__, / /_____/_/\__/____/ /____/ - npm: https://www.npmjs.com/package/solidity-bits - github: https://github.com/estarriolvetch/solidity-bits */ pragma solidity ^0.8.0; library Popcount { uint256 private constant m1 = 0x5555555555555555555555555555555555555555555555555555555555555555; uint256 private constant m2 = 0x3333333333333333333333333333333333333333333333333333333333333333; uint256 private constant m4 = 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f; uint256 private constant h01 = 0x0101010101010101010101010101010101010101010101010101010101010101; function popcount256A(uint256 x) internal pure returns (uint256 count) { unchecked{ for (count=0; x!=0; count++) x &= x - 1; } } function popcount256B(uint256 x) internal pure returns (uint256) { if (x == type(uint256).max) { return 256; } unchecked { x -= (x >> 1) & m1; //put count of each 2 bits into those 2 bits x = (x & m2) + ((x >> 2) & m2); //put count of each 4 bits into those 4 bits x = (x + (x >> 4)) & m4; //put count of each 8 bits into those 8 bits x = (x * h01) >> 248; //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ... } return x; } }
{ "viaIR": true, "optimizer": { "enabled": true, "runs": 200, "details": { "yulDetails": { "optimizerSteps": "u" } } }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"BECAlreadyAwaken","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECAlreadyFamilyAmbassador","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECAlreadyVariationAmbassador","type":"error"},{"inputs":[],"name":"BECCapLimitReached","type":"error"},{"inputs":[{"internalType":"uint256","name":"distribution","type":"uint256"}],"name":"BECDistributionAlreadySet","type":"error"},{"inputs":[{"internalType":"uint256","name":"domain","type":"uint256"}],"name":"BECDomainAlreadySet","type":"error"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"BECDuplicatedName","type":"error"},{"inputs":[],"name":"BECEmptyGoldenDataArray","type":"error"},{"inputs":[{"internalType":"uint256","name":"phenotype","type":"uint256"},{"internalType":"uint256","name":"family","type":"uint256"}],"name":"BECFamilyNameAlreadySet","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECFruitlessCreature","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECGenesisStoreAlreadySet","type":"error"},{"inputs":[],"name":"BECHuntFinished","type":"error"},{"inputs":[],"name":"BECIdsNotInOrder","type":"error"},{"inputs":[],"name":"BECIndexOutOfBounds","type":"error"},{"inputs":[{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"}],"name":"BECInsufficientFunds","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"BECInvalidAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"alpha","type":"uint256"},{"internalType":"uint256","name":"beta","type":"uint256"},{"internalType":"uint256","name":"gamma","type":"uint256"}],"name":"BECInvalidAmbassadors","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"BECInvalidAmbassadorsLength","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECInvalidFamily","type":"error"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"BECInvalidName","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"BECInvalidOwner","type":"error"},{"inputs":[{"internalType":"uint256","name":"phenotype","type":"uint256"}],"name":"BECInvalidPhenotype","type":"error"},{"inputs":[],"name":"BECInvalidProtocolBit","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECInvalidVariation","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"},{"internalType":"uint256","name":"allowed","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"BECMaxCreatureReproductionsAllowed","type":"error"},{"inputs":[{"internalType":"uint256","name":"allowed","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"BECMaxHuntsAllowed","type":"error"},{"inputs":[{"internalType":"uint256","name":"allowed","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"BECMaxReproductionsAllowed","type":"error"},{"inputs":[],"name":"BECMoreCreaturesThanPhenotypes","type":"error"},{"inputs":[],"name":"BECNotAllVariationsPresent","type":"error"},{"inputs":[{"internalType":"uint256","name":"phenotype","type":"uint256"},{"internalType":"uint256","name":"family","type":"uint256"},{"internalType":"uint256","name":"variation","type":"uint256"}],"name":"BECNotAllVariationsSet","type":"error"},{"inputs":[],"name":"BECNotEmptyGoldenDeltasArray","type":"error"},{"inputs":[],"name":"BECNotEnabled","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECNotType0Creature","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECNotVariationAmbassador","type":"error"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"BECParentCreatureAsPayment","type":"error"},{"inputs":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"paid","type":"uint256"}],"name":"BECRitualPriceNotPaid","type":"error"},{"inputs":[{"internalType":"uint256","name":"phenotype","type":"uint256"},{"internalType":"uint256","name":"family","type":"uint256"},{"internalType":"uint256","name":"variation","type":"uint256"}],"name":"BECVariationNameAlreadySet","type":"error"},{"inputs":[{"internalType":"uint256","name":"distributionId","type":"uint256"}],"name":"BECWrongDistributionId","type":"error"},{"inputs":[],"name":"BECZeroQuantityMinting","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"blacksphere","type":"uint256"}],"name":"BlackSphereInvalidOwner","type":"error"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[{"internalType":"address","name":"recoveredAddress","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"EIP2612InvalidSigner","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"EIP2612PermitDeadlineExpired","type":"error"},{"inputs":[],"name":"EIP712BECSigningKeyNotSet","type":"error"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"EIP712InvalidSignature","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"ERC404InvalidERC721Exemption","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"ERC404InvalidTransferValue","type":"error"},{"inputs":[{"internalType":"uint128","name":"indexInQueue","type":"uint128"},{"internalType":"uint256","name":"stashTokenId","type":"uint256"}],"name":"ERC404NotValidIndexValueInStash","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"ERC404OwnedIndexOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"stashTokenId","type":"uint256"}],"name":"ERC404TokenNotInStash","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721IncorrectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721InsufficientApproval","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC721InvalidApprover","type":"error"},{"inputs":[],"name":"ERC721InvalidMintQuantity","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC721InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC721InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC721InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonexistentToken","type":"error"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"ERC721ReceiverNotImplemented","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"QueueEmpty","type":"error"},{"inputs":[],"name":"QueueFull","type":"error"},{"inputs":[],"name":"QueueOutOfBounds","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"length","type":"uint256"}],"name":"StringsInsufficientHexLength","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Received","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"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GENETICIST","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"IPFS_URI_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"_erc20Approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"_erc721Approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"_transferFromERC20","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"spender_","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"valueOrId_","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account_","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_creatureId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"burned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint128","name":"index_","type":"uint128"}],"name":"exchangeWithStash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"bool","name":"_state","type":"bool"}],"name":"forceERC721TransferExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_creatureId","type":"uint256"}],"name":"getImageURI","outputs":[{"internalType":"string","name":"uri","type":"string"}],"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":"uint256","name":"_creatureId","type":"uint256"}],"name":"getSeed","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_creatureIds","type":"uint256[]"}],"name":"getSeeds","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSiteBaseURI","outputs":[{"internalType":"string","name":"uri","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ipfsUris","outputs":[{"internalType":"string","name":"ipfsUri","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"operator_","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target_","type":"address"}],"name":"isERC721TransferExempt","outputs":[{"internalType":"bool","name":"isExempt","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_creatureOwner","type":"address"},{"internalType":"bytes32","name":"_seed","type":"bytes32"},{"internalType":"uint256","name":"_quantity","type":"uint256"}],"name":"mintWithSeed","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"owned","outputs":[{"internalType":"uint256[]","name":"ownedCreatureIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"},{"internalType":"uint256","name":"deadline_","type":"uint256"},{"internalType":"uint8","name":"v_","type":"uint8"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"s_","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signingKey","type":"address"}],"name":"setAllowlistSigningAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator_","type":"address"},{"internalType":"bool","name":"approved_","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_uri","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state_","type":"bool"}],"name":"setERC721TransferExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_genesisEngineContractAddress","type":"address"}],"name":"setGenesisEngineContractAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_creatureId","type":"uint256"},{"internalType":"string","name":"_uri","type":"string"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"setIPFSTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_uri","type":"string"}],"name":"setSiteBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stashAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stashLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_creatureId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokensInStash","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"valueOrId_","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"valueOrId_","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address payable","name":"_address","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address payable","name":"_address","type":"address"}],"name":"withdrawERC20Token","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"address","name":"_address","type":"address"}],"name":"withdrawERC721Token","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
610140604052346100f5576100126101eb565b604051615bc0610ac78239608051816107e1015260a051818181610f490152818161174e0152818161341c01528181613b2601528181614222015281816142890152818161450e01528181614fa80152615634015260c0518181816112f0015281816120120152818161219b0152818161230e0152818161275b01528181612d3e015281816131a40152818161335d015281816135610152818161447f015281816146a50152818161528a015281816155fa0152615743015260e0518161181f015261010051816118460152610120518181816112480152613c1d0152615bc090f35b600080fd5b634e487b7160e01b600052604160045260246000fd5b90601f01601f191681019081106001600160401b0382111761013157604052565b6100fa565b9061014a61014360405190565b9283610110565b565b6001600160401b03811161013157602090601f01601f19160190565b9061017a6101758361014c565b610136565b918252565b6101896014610168565b7f426c61636b204579656420437265617475726573000000000000000000000000602082015290565b6101ba61017f565b90565b6101c76003610168565b6242454360e81b602082015290565b6101ba6101bd565b6101ba6101ba6101ba9290565b61020f6101f66101b2565b6101fe6101d6565b61020961014d6101de565b91610247565b61014a6000805160206167028339815191527f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a66107ab565b9061014a9291610336565b61025f6101ba6101ba9290565b6001600160a01b031690565b6101ba90610252565b906001600160a01b03905b9181191691161790565b6101ba9061025f906001600160a01b031682565b6101ba90610289565b6101ba9061029d565b906102bf6101ba6102c6926102a6565b8254610274565b9055565b6102d46001610168565b603360f81b602082015290565b6101ba6102ca565b9052565b6102e99061025f565b9095949261014a9461032861032f9261032160809661031a60a088019c6000890152565b6020870152565b6040850152565b6060830152565b01906102ed565b9061034192916103db565b61035561034e600061026b565b60126102af565b61035d6101d6565b61036f610368825190565b9160200190565b206103c961037b6102e1565b610386610368825190565b2091610391306102a6565b926103bd61039e60405190565b948593602085019346916000805160206166e2833981519152866102f6565b90810382520382610110565b6103d4610368825190565b2061012052565b61014a9283929091336103f9565b60208101929161014a91906102ed565b92909161040592610457565b61040f600061026b565b6104188161025f565b6104218361025f565b14610430575061014a90610822565b6104539061043d60405190565b631e4fbdf760e01b8152918291600483016103e9565b0390fd5b906104629291610488565b61048560008051602061670283398151915261047e81806107ab565b33906108a3565b50565b61014a92839290916106d5565b906000199061027f565b906104af6101ba6102c6926101de565b8254610495565b634e487b7160e01b600052602260045260246000fd5b90600160028304921680156104ec575b60208310146104e757565b6104b6565b91607f16916104dc565b9160001960089290920291821b911b61027f565b919061051b6101ba6102c6936101de565b9083546104f6565b61014a9160009161050a565b81811061053a575050565b806105486000600193610523565b0161052f565b9190601f811161055d57505050565b61056f61014a93600052602060002090565b906020601f840181900483019310610591575b6020601f90910104019061052f565b9091508190610582565b906105a4815190565b906001600160401b038211610131576105c7826105c185546104cc565b8561054e565b602090601f8311600114610602576102c69291600091836105f7575b5050600019600883021c1916906002021790565b0151905038806105e3565b601f1983169161061785600052602060002090565b9260005b8181106106555750916002939185600196941061063c575b50505002019055565b01516000196008601f8516021c19169055388080610633565b9193602060018192878701518155019501920161061b565b9061014a9161059b565b6106846101ba6101ba9290565b60ff1690565b634e487b7160e01b600052601160045260246000fd5b60ff16604d81116106b157600a0a90565b61068a565b818102929181159184041417156106b157565b6040513d6000823e3d90fd5b610734929161070661070d926106f36106ec610929565b600361049f565b6106ff6000600c61049f565b600061066d565b600161066d565b6107176012610677565b60805261072e61072960805160ff1690565b6106a0565b906106b6565b60a052604051605b81016001600160401b038111828210176101315761075f8291605b616687843990565b03906000f0801561078857610773906102a6565b60c0524660e0526107826109eb565b61010052565b6106c9565b905b600052602052604060002090565b906104af6101ba6102c69290565b906107de6107da6107d66107be85610a7a565b946101ba8560016107d084601061078d565b0161079d565b9390565b9190565b917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff61080960405190565b600090a4565b6101ba9061025f565b6101ba905461080f565b6108486108426108326011610818565b61083d8460116102af565b6102a6565b916102a6565b907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e061087360405190565b600090a3565b9061078f906102a6565b9060ff9061027f565b9061089c6101ba6102c692151590565b8254610883565b6108b46108b08383610aac565b1590565b15610922576108da60016108d58460006108cf86601061078d565b01610879565b61088c565b6108ee6108426108e8339390565b936102a6565b917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d61091960405190565b600090a4600190565b5050600090565b6101ba60016101de565b80546000939291610950610946836104cc565b8085529360200190565b91600181169081156109a2575060011461096957505050565b61097c9192939450600052602060002090565b916000925b81841061098e5750500190565b805484840152602090930192600101610981565b92949550505060ff1916825215156020020190565b906101ba91610933565b9061014a6109db926109d260405190565b938480926109b7565b0383610110565b6101ba906109c1565b6103bd610a5a6109fb60006109e2565b610a06610368825190565b20610a10306102a6565b90610a1a60405190565b93849260208401927fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc646916000805160206166e2833981519152866102f6565b610a65610368825190565b2090565b6101ba9081565b6101ba9054610a69565b6001610a936101ba92610a8b600090565b50601061078d565b01610a70565b6101ba90610684565b6101ba9054610a99565b6101ba9160006108cf610ac193610a8b600090565b610aa256fe60806040526004361015610020575b361561001657005b61001e613215565b005b60003560e01c8062f714ce1461041f57806301ffc9a71461041a578063058985de1461041557806306fdde0314610410578063081812fc1461040b578063095ea7b31461040657806314d0ae661461040157806318160ddd146103fc57806323b872dd146103f7578063248a9ca3146103f25780632f2ff15d146103ed578063313ce567146103e857806334b02e8e146103e35780633644e515146103de578063364f5d23146103d957806336568abe146103d4578063412e5f49146103cf57806342842e0e146103ca57806342966c68146103c55780634443f0a4146103c057806344a5bfa8146103bb5780634f558e79146103b65780634f8a2737146103b157806355f804b3146103ac5780635b21186d146103a75780635e56b06a146103a25780636315ab461461039d5780636352211e1461039857806364aae4161461039357806370a082311461038e578063715018a61461038957806373f425611461038457806375794a3c1461037f5780637e1c0c091461037a5780637e3c9599146103755780637ecebe00146103705780638adae3261461036b5780638da5cb5b14610366578063907af6c0146103615780639198e19a1461035c57806391d148541461035757806395d89b411461035257806396a8ef9e1461034d578063a217fddf14610348578063a22cb46514610343578063a9059cbb1461033e578063aa97eca214610339578063ade474e614610334578063b1ab93171461032f578063b88d4fde1461032a578063be00df4a14610325578063c87b56dd14610320578063d505accf1461031b578063d539139314610316578063d547741f14610311578063dab400f31461030c578063dd62ed3e14610307578063e0d4ea3714610302578063e985e9c5146102fd578063ecb41c75146102f8578063ed915ea1146102f3578063f2fde38b146102ee578063fcf8be1f146102e95763fd89b0f50361000e5761135c565b611340565b611328565b611314565b6112db565b6112bf565b6112a4565b611288565b611233565b61121a565b6111e1565b6111c2565b611132565b61111a565b6110fe565b611094565b611079565b61105e565b611042565b611029565b61100e565b610fe8565b610fa4565b610f88565b610f6d565b610f34565b610f19565b610ee0565b610ec5565b610e51565b610e13565b610df8565b610ddd565b610dc5565b610daa565b610d7a565b610d5f565b610d46565b610d2b565b610d12565b610cbb565b610ca3565b610bdd565b610bc1565b610b16565b610a57565b610a3e565b610a23565b610a0a565b6109d1565b6109b6565b61099b565b6107cc565b6107b3565b610798565b61077c565b610728565b610705565b610659565b610601565b6105c6565b610537565b6104e1565b61048f565b805b0361042d57565b600080fd5b9050359061043f82610424565b565b6001600160a01b031690565b90565b6001600160a01b038116610426565b9050359061043f82610450565b919060408382031261042d5761044d9060206104888286610432565b940161045f565b6104a361049d36600461046c565b9061147f565b604051005b0390f35b6001600160e01b03198116610426565b9050359061043f826104ac565b9060208282031261042d5761044d916104bc565b9052565b3461042d576104a86104fc6104f73660046104c9565b611489565b60405191829182901515815260200190565b801515610426565b9050359061043f8261050e565b9060208282031261042d5761044d91610516565b3461042d576104a361054a366004610523565b611492565b600091031261042d57565b60005b83811061056d5750506000910152565b818101518382015260200161055d565b61059e6105a76020936105b193610592815190565b80835293849260200190565b9586910161055a565b601f01601f191690565b0190565b602080825261044d9291019061057d565b3461042d576105d636600461054f565b6104a86105e16114a5565b604051918291826105b5565b9060208282031261042d5761044d91610432565b3461042d576104a861061c6106173660046105ed565b6114c2565b604051918291826001600160a01b03909116815260200190565b919060408382031261042d5761044d906020610652828661045f565b9401610432565b3461042d576104a86104fc61066f366004610636565b90611510565b909160608284031261042d5761044d61068e848461045f565b9360406106528260208701610432565b906106be6106b76106ad845190565b8084529260200190565b9260200190565b9060005b8181106106cf5750505090565b9091926106ec6106e56001928651815260200190565b9460200190565b9291016106c2565b602080825261044d9291019061069e565b6104a861071c610716366004610675565b91611721565b604051918291826106f4565b3461042d5761073836600461054f565b6104a8610743611741565b6040519182918290815260200190565b909160608284031261042d5761044d61076c848461045f565b936040610652826020870161045f565b3461042d576104a86104fc610792366004610753565b91611792565b3461042d576104a86107436107ae3660046105ed565b6117d6565b3461042d576104a36107c636600461046c565b90611813565b3461042d576107dc36600461054f565b6040517f000000000000000000000000000000000000000000000000000000000000000060ff168152602090f35b61044d61044d61044d9290565b906108219061080a565b600052602052604060002090565b634e487b7160e01b600052600060045260246000fd5b634e487b7160e01b600052602260045260246000fd5b906001600283049216801561087b575b602083101461087657565b610845565b91607f169161086b565b805460009392916108a26108988361085b565b8085529360200190565b91600181169081156108f457506001146108bb57505050565b6108ce9192939450600052602060002090565b916000925b8184106108e05750500190565b8054848401526020909301926001016108d3565b92949550505060ff1916825215156020020190565b9061044d91610885565b634e487b7160e01b600052604160045260246000fd5b90601f01601f191681019081106001600160401b0382111761094a57604052565b610913565b9061043f6109699261096060405190565b93848092610909565b0383610929565b906000106109815761044d9061094f565b61082f565b600061099661044d926016610817565b610970565b3461042d576104a86105e16109b13660046105ed565b610986565b3461042d576109c636600461054f565b6104a861074361181d565b3461042d576109e136600461054f565b6104a87fdb2819cfe36df1a8e2df5d8d9cfe49bf1b7c55ce41ab4723ae144d927ae5245b610743565b3461042d576104a3610a1d36600461046c565b90611870565b3461042d576104a86105e1610a393660046105ed565b611997565b3461042d576104a3610a51366004610753565b91611a38565b3461042d576104a3610a6a3660046105ed565b611a63565b909182601f8301121561042d578135916001600160401b03831161042d57602001926020830284011161042d57565b9060208282031261042d5781356001600160401b03811161042d57610ac39201610a6f565b9091565b90610ad66106b76106ad845190565b9060005b818110610ae75750505090565b909192610afd6106e56001928651815260200190565b929101610ada565b602080825261044d92910190610ac7565b3461042d576104a8610b32610b2c366004610a9e565b90611abb565b60405191829182610b05565b909182601f8301121561042d578135916001600160401b03831161042d57602001926001830284011161042d57565b60608183031261042d57610b818282610432565b9260208201356001600160401b03811161042d5783610ba1918401610b3e565b92909360408201356001600160401b03811161042d57610ac39201610b3e565b3461042d576104a3610bd4366004610b6d565b93929092611cbf565b3461042d576104a86104fc610bf33660046105ed565b611d10565b9061043f610c0560405190565b9283610929565b6001600160401b03811161094a57602090601f01601f19160190565b90826000939282370152565b90929192610c49610c4482610c0c565b610bf8565b938185528183011161042d5761043f916020850190610c28565b9080601f8301121561042d5781602061044d93359101610c34565b9060208282031261042d5781356001600160401b03811161042d5761044d9201610c63565b3461042d576104a3610cb6366004610c7e565b611e04565b3461042d576104a3610cce366004610c7e565b611e24565b6001600160801b038116610426565b9050359061043f82610cd3565b919060408382031261042d5761044d906020610d0b8286610432565b9401610ce2565b3461042d576104a3610d25366004610cef565b90611edd565b3461042d57610d3b36600461054f565b6104a861071c61207a565b3461042d576104a3610d59366004610636565b906120aa565b3461042d576104a861061c610d753660046105ed565b61213e565b3461042d576104a86104fc610d90366004610753565b916121f2565b9060208282031261042d5761044d9161045f565b3461042d576104a8610743610dc0366004610d96565b61233e565b3461042d57610dd536600461054f565b6104a3612372565b3461042d57610ded36600461054f565b6104a861074361237a565b3461042d57610e0836600461054f565b6104a8610743612382565b3461042d57610e2336600461054f565b6104a861074361238c565b919060408382031261042d5761044d906020610e4a828661045f565b9401610516565b3461042d576104a3610e64366004610e2e565b906123f2565b61044d90610441906001600160a01b031682565b61044d90610e6a565b61044d90610e7e565b9061082190610e87565b61044d916008021c81565b9061044d9154610e9a565b6000610ec061044d92600f610e90565b610ea5565b3461042d576104a8610743610edb366004610d96565b610eb0565b3461042d57610ef036600461054f565b6104a87f114ba586f27424819fdf1eac564faf22081abcab4f662a9e508c112ed1a7cbcf610743565b3461042d57610f2936600461054f565b6104a861061c6123fc565b3461042d57610f4436600461054f565b6104a87f0000000000000000000000000000000000000000000000000000000000000000610743565b3461042d57610f7d36600461054f565b6104a8610743612406565b3461042d576104a86104fc610f9e36600461046c565b90612425565b3461042d57610fb436600461054f565b6104a86105e1612445565b909160608284031261042d5761044d610fd8848461045f565b9360406104888260208701610432565b6104a3610ff6366004610fbf565b916125d8565b61044d600061080a565b61044d610ffc565b3461042d5761101e36600461054f565b6104a8610743611006565b3461042d576104a361103c366004610e2e565b90612603565b3461042d576104a86104fc611058366004610636565b90612699565b3461042d576104a86104fc611074366004610d96565b6126aa565b3461042d5761108936600461054f565b6104a86105e16126c1565b3461042d576104a861071c6110aa366004610d96565b612750565b9060808282031261042d576110c4818361045f565b926110d2826020850161045f565b926110e08360408301610432565b9260608201356001600160401b03811161042d5761044d9201610c63565b3461042d576104a36111113660046110af565b92919091612896565b3461042d576104a361112d366004610d96565b6128f4565b3461042d576104a86105e16111483660046105ed565b612966565b60ff8116610426565b9050359061043f8261114d565b60e08183031261042d57611177828261045f565b92611185836020840161045f565b926111938160408501610432565b926111a18260608301610432565b9261044d6111b28460808501611156565b9360c06106528260a08701610432565b3461042d576104a36111d5366004611163565b95949094939193612b35565b3461042d576111f136600461054f565b6104a87f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6610743565b3461042d576104a361122d36600461046c565b90612dd6565b3461042d5761124336600461054f565b6104a87f0000000000000000000000000000000000000000000000000000000000000000610743565b919060408382031261042d5761044d906020610488828661045f565b3461042d576104a861074361129e36600461126c565b90612de0565b3461042d576104a86107436112ba3660046105ed565b612e0a565b3461042d576104a86104fc6112d536600461126c565b90612e68565b3461042d576112eb36600461054f565b6104a87f000000000000000000000000000000000000000000000000000000000000000061061c565b6104a3611322366004610fbf565b91613098565b3461042d576104a361133b366004610d96565b61310d565b3461042d576104a86104fc611356366004610636565b90613116565b3461042d576104a361136f366004610d96565b61320c565b9061043f91611381613250565b6113d8565b61044161044d61044d9290565b61044d90611386565b6104dd90610e87565b60208101929161043f919061139c565b90815260408101929161043f9160200152565b0152565b6040513d6000823e3d90fd5b6000916113e761044184611393565b6113f082610e87565b1461145c576113fe30610e87565b8031831161143257508280926114148293610e87565b828215611429575bf11561142457565b6113cc565b506108fc61141c565b9050319061145861144260405190565b631944d18360e21b8152928392600484016113b5565b0390fd5b6114589061146960405190565b639c86094560e01b8152918291600483016113a5565b9061043f91611374565b61044d906132a5565b61043f90336132ce565b61044d9061094f565b61044d600061149c565b61044d90610441565b61044d90546114af565b6114d26114ce8261338d565b1590565b6114e9576114e461044d916004610817565b6114b8565b611458906114f660405190565b637e27328960e01b81529182916004830190815260200190565b9061151a8161338d565b1561152d57611528916120aa565b600190565b61044d91613116565b61044d9392919061156b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a66133d0565b6133d0565b611650565b634e487b7160e01b600052601160045260246000fd5b9190611591565b9290565b820180921161159c57565b611570565b6001600160401b03811161094a5760208091020190565b906115c5610c44836115a1565b918252565b369037565b9061043f6115e56115df846115b8565b936115a1565b601f1901602084016115ca565b90600019905b9181191691161790565b9061161061044d6116179290565b82546115f2565b9055565b634e487b7160e01b600052603260045260246000fd5b9061163a825190565b81101561164b576020809102010190565b61161b565b50919261165d600061080a565b841461170f5761166b612382565b916116768584611586565b611689611685620208d561080a565b9190565b116116fd576116b5906116a58661169f816115cf565b966133db565b6116b0846017610817565b611602565b6116bf600061080a565b845b8110156116f6576116ef816116e96116dc6116c19487611586565b6116e68389611631565b52565b60010190565b90506116bf565b5092505090565b60405163318df65960e01b8152600490fd5b604051631758383360e11b8152600490fd5b61044d9291906060611536565b8181029291811591840414171561159c57565b61044d61174c6135a3565b7f00000000000000000000000000000000000000000000000000000000000000009061172e565b906115c5610c4483610c0c565b61044d6000611773565b61044d611780565b919061179d8261338d565b156117b6579061152892916117b061178a565b92612896565b61044d926121f2565b90610821565b61044d9081565b61044d90546117c5565b60016117ef61044d926117e7600090565b5060106117bf565b016117cc565b9061043f91611806611566826117d6565b90611810916135b6565b50565b9061043f916117f5565b7f00000000000000000000000000000000000000000000000000000000000000004603611868577f000000000000000000000000000000000000000000000000000000000000000090565b61044d61370d565b9061187a33610441565b6001600160a01b03821603611892576118109161379d565b60405163334bd91960e11b8152600490fd5b61044d905461085b565b61044d9081906001600160a01b031681565b805460009392916118d76118d38361085b565b9390565b916001811690811561192857506001146118f057505050565b6119039192939450600052602060002090565b6000905b8382106119145750500190565b600181602092548486015201910190611907565b60ff191683525050811515909102019150565b6105b16119539260209261194d815190565b94859290565b9384910161055a565b61197a611987936119746119749361044d97956118c0565b9061193b565b602f60f81b815260010190565b632e706e6760e01b815260040190565b6119ad6119a861044d836016610817565b6118a4565b6119ba611685600061080a565b11156119d3576119ce61044d916016610817565b61149c565b611a2c61044d61044d92611a12611a0c6119fc6119f76119f230610e87565b610e7e565b6118ae565b611a06601461080a565b9061385a565b916139be565b90611a1c60405190565b938492602084019260138461195c565b90810382520382610929565b909161043f926117b061178a565b6001600160a01b03909116815260408101929161043f9160200152565b611a706114ce8233613a51565b611a7d5761043f90613ab2565b61145890611a8a60405190565b63177e802f60e01b81529182913360048401611a46565b919081101561164b576020020190565b3561044d81610424565b91908092611ac8846115cf565b92611ad3600061080a565b855b811015611b0d57611b06816116e9611afc6112ba611af7611ad5968a8a611aa1565b611ab1565b6116e6838a611631565b9050611ad3565b509350505090565b91906105a781611b2c816105b19560209181520190565b8095610c28565b602080825261044d93910191611b15565b9160001960089290920291821b911b6115f8565b9190611b6961044d6116179361080a565b908354611b44565b61043f91600091611b58565b818110611b88575050565b80611b966000600193611b71565b01611b7d565b9190601f8111611bab57505050565b611bbd61043f93600052602060002090565b906020601f840181900483019310611bdf575b6020601f909101040190611b7d565b9091508190611bd0565b91906001600160401b03821161094a57611c0d82611c07855461085b565b85611b9c565b600090601f8311600114611c4857611617929160009183611c3d575b5050600019600883021c1916906002021790565b013590503880611c29565b90601f19831691611c5e85600052602060002090565b92825b818110611c9c57509160029391856001969410611c82575b50505002019055565b0135600019601f84166008021c19165b9055388080611c79565b92936020600181928786013581550195019301611c61565b9061043f9291611be9565b9493909192611cd46114ce838387878b613be2565b611cee575050611ce961043f93946016610817565b611cb4565b611458611cfa60405190565b631d9394a560e21b815292839260048401611b33565b61044d9061338d565b61043f90611d25613250565b611df9565b90611d33815190565b906001600160401b03821161094a57611d5082611c07855461085b565b602090601f8311600114611d8a57611617929160009183611d7f575050600019600883021c1916906002021790565b015190503880611c29565b601f19831691611d9f85600052602060002090565b9260005b818110611dd757509160029391856001969410611dc35750505002019055565b01516000196008601f8516021c1916611c92565b91936020600181928787015181550195019201611da3565b9061043f91611d2a565b61043f906014611def565b61043f90611d19565b61043f90611e19613250565b61043f906013611def565b61043f90611e0d565b61044d61044d61044d926001600160801b031690565b916001600160a01b0360089290920291821b911b6115f8565b9190611e6d61044d61161793610e87565b908354611e43565b61043f91600091611e5c565b805482101561164b57611e9b600191600052602060002090565b91020190600090565b90815491600160401b83101561094a5782611ec791600161043f95018155611e81565b90611b58565b9061161061044d6116179261080a565b90600d611ef2611eec83611e2d565b82613d41565b90611eff6114ce8561338d565b61206d57611f106114ce8533613a51565b61206057611fdd611fce611fca61200893611f76611fa089611f3181613d9e565b94829c929691611f4c6000611f47876004610817565b611e75565b60089685611f6c611f6684611f618d8d610e90565b611e81565b90610ea5565b60a01c928a613dcc565b611f8b6000611f86856009610817565b611b71565b611f9b83600a613e2d565b613e2d565b613e9e565b611fc56001600160a01b038816600160a01b01611fc061044d8585610e90565b611ea4565b610e90565b5490565b611fd8600161080a565b900390565b6001600160a01b03841660a09190911b6001600160a01b03191601612003836009610817565b611ecd565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169216908183600080516020615b6b833981519152600080a4600080516020615b6b833981519152600080a4565b61145884611a8a60405190565b611458846114f660405190565b61044d600d613f05565b906001600160a01b03906115f8565b906120a361044d61161792610e87565b8254612084565b6120b38261213e565b906001600160a01b0382163314158061212b575b612113576120df816120da856004610817565b612093565b6001600160a01b0390811691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a4565b60405163a9fbf51f60e01b8152336004820152602490fd5b506121396114ce3384612e68565b6120c7565b61214a6114ce8261338d565b6114e95761216c61216561217192612160600a90565b614043565b6009610817565b6117cc565b6001600160a01b0316906121886104416000611393565b6001600160a01b0383161461219957565b7f00000000000000000000000000000000000000000000000000000000000000009150565b6001600160a01b03909116815260608101939261043f9290916040916113c8906020830152565b9190820391821161159c57565b9291906122026104416000611393565b6001600160a01b038216148015612303575b80156122e8575b6122b757336001600160a01b0385160361223a575b61044d9293614150565b61225261216c61224b866006610e90565b3390610e90565b936000198503612264575b9350612230565b8483116122925761228a61227c8461044d96976121e5565b61200361224b846006610e90565b84935061225d565b8490611458846122a160405190565b637dc7a0d960e11b8152938493600485016121be565b611458906122c460405190565b63ec442f0560e01b8152918291600483016001600160a01b03909116815260200190565b506001600160a01b0384166001600160a01b0382161461221b565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166001600160a01b03821614612214565b61216c61044d9161234d600090565b506002610e90565b61235d613250565b61043f61043f61236d6000611393565b6142fe565b61043f612355565b61044d61434a565b61044d60036117cc565b61044d6135a3565b9061043f916123a1613250565b9190823b6123b2611685600061080a565b146123c15761043f91926132ce565b611458836123ce60405190565b639c86094560e01b8152918291600483016001600160a01b03909116815260200190565b9061043f91612394565b61044d60116114b8565b61044d600d614354565b61044d905b60ff1690565b61044d9054612410565b61044d91600061243a612440936117e7600090565b01610e90565b61241b565b61044d600161149c565b9061043f929161245d613250565b6124a7565b9050519061043f82610450565b9060208282031261042d5761044d91612462565b6001600160a01b0391821681529116602082015260608101929161043f9160400152565b6124b090610e87565b906124be6104416000611393565b6001600160a01b038416146123c1576124df6124d930610e87565b92610e87565b6040516331a9108f60e11b815260048101839052602081602481855afa80156114245761251b916000916125a9575b506001600160a01b031690565b6001600160a01b0384160361258557803b1561042d5761255c936000809461254260405190565b96879586948593632142170760e11b855260048501612483565b03925af180156114245761256d5750565b61043f90600061257d8183610929565b81019061054f565b509061145861259360405190565b633f82dd3d60e11b815292839260048401611a46565b6125cb915060203d6020116125d1575b6125c38183610929565b81019061246f565b3861250e565b503d6125b9565b9061043f929161244f565b9060ff906115f8565b906125fc61044d61161792151590565b82546125e3565b90336001600160a01b038316146126685761262c8161262784611fc5336005610e90565b6125ec565b60009081526001600160a01b03919091169033907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3190602090a3565b6114588261267560405190565b630b61174360e31b8152918291600483016001600160a01b03909116815260200190565b6126a4919033611792565b50600190565b61244061044d916126b9600090565b506007610e90565b61044d601461149c565b906126e66126da6106ad845490565b92600052602060002090565b9060005b8181106126f75750505090565b90919261271b61271460019261270c876117cc565b815260200190565b9460010190565b9291016126ea565b9061044d916126cb565b9061043f6109699261273e60405190565b93848092612723565b61044d9061272d565b906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166001600160a01b0383161461288c5760006127958161080a565b926127ab6127a66000926008610e90565b612747565b91845b6127b961044d855190565b8610156127e0576001906127d46127d08887611631565b5190565b60a01c019501946127ae565b6127ee9193949295506115cf565b9182946127fa8261080a565b905080915b61280a61044d875190565b8310156128845761281e6127d08488611631565b60a081901c966001600160a01b03909116949061283a8361080a565b935b8885101561286757612714612861916116e9612857888b0190565b6116e6838d611631565b9361283c565b9893509390945061287a91965060010190565b91949590956127ff565b505050915050565b905061044d61207a565b939291906128a66114ce8361338d565b6128d2576128b76114ce8333613a51565b6128c55761043f93946143d2565b61145882611a8a60405190565b611458826114f660405190565b61043f906128eb613250565b61043f906144d6565b61043f906128df565b9092919261290d610c4482610c0c565b938185528183011161042d5761043f91602085019061055a565b9080601f8301121561042d57815161044d926020016128fd565b9060208282031261042d5781516001600160401b03811161042d5761044d9201612927565b60006129ae91612974606090565b5061298d61298861298861298860156114b8565b610e87565b6040519384928391829163c87b56dd60e01b83526004830190815260200190565b03915afa908115611424576000916129c4575090565b61044d91503d806000833e6129d98183610929565b810190612941565b949290979695939160e086019860008701612a03916001600160a01b03169052565b6001600160a01b031660208601526040850152606084015260ff16608083015260a082015260c00152565b9194612a7d6113c892989795612a7660a096612a6661043f9a612a5660c08a019e60008b0152565b6001600160a01b03166020890152565b6001600160a01b03166040870152565b6060850152565b6080830152565b6020809392612aa16115c56105b19461190160f01b815260020190565b01918252565b6113c861043f94612ad0606094989795612ac6608086019a6000870152565b60ff166020850152565b6040830152565b9593919897969492909861010087019960008801612afc916001600160a01b03169052565b6001600160a01b031660208701526001600160a01b031660408601526060850152608084015260ff1660a083015260c082015260e00152565b95909394929192612b434290565b8310612d9557612b528461338d565b612d6e57600095612b6287611393565b936001600160a01b0385166001600160a01b038816148015612d33575b612d025760208883611a2c612c1e8d8b612bf48e612b9b61181d565b93611a2c8b612bab83600f610e90565b612bc3612bb7826117cc565b91600183015b90611ecd565b6040519687958e8701957f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c987612a2e565b612c06612bff825190565b9160200190565b2090612c1160405190565b9384928884019283612a84565b612c29612bff825190565b20612c418888612c3860405190565b94859485612aa7565b838052039060015afa15611424578751946001600160a01b03166001600160a01b038616148015612ce6575b612cc057505050509181612cad60209361200384611fc57f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925986006610e90565b84526001600160a01b03908116941692a3565b61145894958997612cd060405190565b63d01a799560e01b815298899860048a01612ad7565b506001600160a01b0389166001600160a01b0386161415612c6d565b61145887612d0f60405190565b634a1406b160e11b8152918291600483016001600160a01b03909116815260200190565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166001600160a01b03881614612b7f565b61145884612d7b60405190565b635dbad48560e01b81529182916004830190815260200190565b85611458938895612da560405190565b63dc99de6360e01b8152978897600489016129e1565b9061043f91612dcc611566826117d6565b906118109161379d565b9061043f91612dbb565b61044d91611fc561216c92612df3600090565b506006610e90565b600019811461159c5760010190565b90600090612e18600061080a565b612e22600061080a565b905b612e2d8461080a565b8103612e605750612e2d612e58612e5261216c6017612e4c868a6121e5565b90610817565b92612dfb565b919050612e24565b925050915090565b61044d91611fc561244092612e7b600090565b506005610e90565b9061043f9291612e91613250565b612ef3565b9050519061043f82610424565b9060208282031261042d5761044d91612e96565b9050519061043f8261050e565b9060208282031261042d5761044d91612eb7565b91602061043f9294936113c86040820196600083019061139c565b612eff90929192610e87565b612f0c6104416000611393565b612f1583610e87565b1461308b57612f2390610e87565b906370a08231612f3230610e87565b90612f3c60405190565b612f468260e01b90565b81526001600160a01b0383166004820152602081602481885afa801561142457612f7591600091613072575090565b8511612fe857505091602091612faf936000612f9060405190565b809681958294612fa463a9059cbb60e01b90565b845260048401612ed8565b03925af1801561142457612fc05750565b6118109060203d602011612fe1575b612fd98183610929565b810190612ec4565b503d612fcf565b6020613021928561300a8894612ffd60405190565b9687948593849360e01b90565b83526001600160a01b031660048301526024820190565b03915afa91821561142457600092613041575b5061145861144260405190565b61306491925060203d60201161306b575b61305c8183610929565b810190612ea3565b9082613034565b503d613052565b61044d915060203d60201161306b5761305c8183610929565b6114588261146960405190565b9061043f9291612e83565b61043f906130af613250565b6130b96000611393565b6001600160a01b0381166001600160a01b038316146130dc575061043f906142fe565b611458906130e960405190565b631e4fbdf760e01b8152918291600483016001600160a01b03909116815260200190565b61043f906130a3565b906131246104416000611393565b6001600160a01b038316148015613199575b61318c5761314d8161200384611fc5336006610e90565b60009081526001600160a01b03919091169033907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590602090a3600190565b61145882612d0f60405190565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166001600160a01b03831614613136565b61043f906132017fdb2819cfe36df1a8e2df5d8d9cfe49bf1b7c55ce41ab4723ae144d927ae5245b6133d0565b61043f906015612093565b61043f906131d4565b7f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f8852587461323f60405190565b8061324b343383611a46565b0390a1565b6132586123fc565b339061326c825b916001600160a01b031690565b036132745750565b6114589061328160405190565b63118cdaa760e01b8152918291600483016001600160a01b03909116815260200190565b637965db0b60e01b6001600160e01b03198216149081156132c4575090565b61044d91506144e1565b91906132dd6104416000611393565b6001600160a01b038416148015613352575b6133215761262761043f9293826000146133135761330c81614640565b6007610e90565b61331c816144fb565b61330c565b6114588361332e60405190565b63024b6d7560e31b8152918291600483016001600160a01b03909116815260200190565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166001600160a01b038416146132ef565b61339881600b614752565b6133ca576133a961044d60036117cc565b811090816133b5575090565b90506133c561168561158d614794565b111590565b50600090565b61043f90339061479e565b6000906133e78261080a565b8314613591576133f961044183611393565b6001600160a01b038216148015613556575b6122b75761341960036117cc565b917f0000000000000000000000000000000000000000000000000000000000000000840261345861344b846002610e90565b612bbd836105b1836117cc565b8152838301906001600160a01b038316908181600080516020615b6b833981519152602082a361348c612440856007610e90565b156134bf5750505050816134ae61043f936134b8936134a9600a90565b6148af565b6105b160036117cc565b6003611ecd565b90919293806134d2600192611f96600a90565b6134dd8787836147d6565b61350a6134ee611fca886008610e90565b9661350384986134fd8661080a565b906121e5565b908361481f565b808484600080516020615b6b8339815191528180a4015b8381036135395750505050506134b861043f916134ae565b8085918484600080516020615b6b8339815191528180a401613521565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166001600160a01b0382161461340b565b604051636e45634760e11b8152600490fd5b61044d6135ae6149b4565b6134fd61434a565b6135c36114ce8383612425565b1561362c576135de600161262784600061243a8660106117bf565b6135f86135f26135ec339390565b93610e87565b91610e87565b917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d61362360405190565b600090a4600190565b5050600090565b805460009392916136466108988361085b565b91600181169081156108f4575060011461365f57505050565b6136729192939450600052602060002090565b916000925b8184106136845750500190565b805484840152602090930192600101613677565b9061044d91613633565b9061043f610969926136b360405190565b93848092613698565b61044d906136a2565b9095949261043f946136f76136fe926136f06080966136e960a088019c6000890152565b6020870152565b6040850152565b6060830152565b01906001600160a01b03169052565b611a2c61378e61371d60006136bc565b613728612bff825190565b2061373230610e87565b9061373c60405190565b93849260208401927fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc646917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f866136c5565b613799612bff825190565b2090565b6137a78282612425565b1561362c576137c16000612627848261243a8660106117bf565b6137cf6135f26135ec339390565b917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b61362360405190565b9061043f6115e561380a84611773565b93610c0c565b90613819825190565b81101561164b570160200190565b801561159c576000190190565b61241561044d61044d9290565b61044d9061385561168561044d9460ff1690565b901c90565b908161388a61388561387584613870600261080a565b61172e565b61387f600261080a565b90611586565b6137fa565b92600060306138a161389b8361080a565b87613810565b536001600f60fb1b821a6138bd6138b78361080a565b88613810565b53806138d96138d087613870600261080a565b61387f8361080a565b915b61391a575b50506116856138ee9161080a565b036138f857505090565b61145861390460405190565b63e22e27eb60e01b8152928392600484016113b5565b90926139258261080a565b841115613993576f181899199a1a9b1b9c1cb0b131b232b360811b61394a600f61080a565b821690601082101561164b57839261396a6139879261398d941a60f81b90565b861a613976888c613810565b536139816004613834565b90613841565b94613827565b916138db565b926138e0565b634e487b7160e01b600052601260045260246000fd5b81156139b9570490565b613999565b6139c7816149c9565b906139d86001926105b1600161080a565b91806139e3846137fa565b936020018401905b6139f6575b50505090565b8115613a4c57613a309060001901926f181899199a1a9b1b9c1cb0b131b232b360811b600a82061a8453613a2a600a61080a565b906139af565b9081613a3f611685600061080a565b14613a4c579091816139eb565b6139f0565b613a5a8261213e565b6001600160a01b0381166001600160a01b03831614928315613a8d575b508215613a8357505090565b61044d9250612e68565b613a989193506114c2565b613aaa6001600160a01b03831661325f565b149138613a77565b613abe6114ce8261338d565b6114e9576000613aff613ad083613d9e565b613ae285611f47886004979697610817565b85613af5611f6684611f61886008610e90565b60a01c9285613dcc565b613b0e82611f86856009610817565b613b1983600a613e2d565b613b2483600b613e2d565b7f000000000000000000000000000000000000000000000000000000000000000090613b65613b54826002610e90565b612bbd84613b61836117cc565b0390565b613b7c613b756116e9600c6117cc565b600c611ecd565b9082526001600160a01b03168181600080516020615b6b833981519152602083a3600080516020615b6b8339815191528280a4565b61044d913691610c34565b6136fe61043f94612ad0606094989795613bdb608086019a6000870152565b6020850152565b9390613bee60126114b8565b613bfe61325f6104416000611393565b14613ce757613cbb613ccd93611a2c92613c97613cd398613c6e613c687f000000000000000000000000000000000000000000000000000000000000000095613c647f114ba586f27424819fdf1eac564faf22081abcab4f662a9e508c112ed1a7cbcf90565b9591565b90613bb1565b613c79612bff825190565b2090611a2c613c8760405190565b9485936020850193339285613bbc565b613ca2612bff825190565b2090613cad60405190565b938492602084019283612a84565b613cc6612bff825190565b2092613bb1565b90614b6b565b613ce361325f61044160126114b8565b1490565b6040516395e0712b60e01b8152600490fd5b61044d905b6001600160801b031690565b61044d9054613cf9565b613cfe61044d61044d9290565b613cfe61044d61044d926001600160801b031690565b9061082190613d21565b90613d4e61044d83614354565b811015613d8c5781613d8661216c92613d79613d736000600161044d98019501613d0a565b91613d14565b016001600160801b031690565b90613d37565b60405163580821e760e01b8152600490fd5b613da990600a614043565b613db761216c826009610817565b6001600160a01b0381169260a09190911c9190565b93919092613dd78290565b8103613e045750613de8600161080a565b8203613df957505061043f91614d2b565b909161043f93614c78565b919261043f94614b81565b61044d600160ff1b61080a565b61044d9061385561168561044d9490565b613e6e61043f926000613e67613e4c613e466008613834565b84613841565b92613e55613e0f565b90613e6060ff61080a565b1690613e1c565b9301610817565b90613e78826117cc565b1790611ecd565b6001600160801b03908116911601906001600160801b03821161159c57565b9190613eac61044d84614354565b613eb582611e2d565b1015613d8c5782613d8661200392613ed66000600161043f98019401613d0a565b90613e7f565b61044d9060801c613cfe565b61044d9054613edc565b600161044d91016001600160801b031690565b613f1d613f2a82613f1581613d0a565b928391613ee8565b036001600160801b031690565b91613f3c613f3784611e2d565b6115cf565b938490613f496000613d14565b6001600160801b0386165b6001600160801b0382161015613fa857613fa1613f5491613f9c613f8a61216c60018901613d86858c016001600160801b031690565b6116e6613f9684611e2d565b8c611631565b613ef2565b9050613f49565b50935093505050565b15613fb857565b60405162461bcd60e51b815260206004820152603460248201527f4269744d6170733a205468652073657420626974206265666f7265207468652060448201527334b73232bc103237b2b9b713ba1032bc34b9ba1760611b6064820152608490fd5b61044d9061402e61168561044d9460ff1690565b901b90565b61044d61044d61044d9260ff1690565b6000916140506008613834565b9061405b8282613841565b92839161408e61407c61216c60ff9361407460ff61080a565b169785610817565b8661408760ff61080a565b1890613e1c565b9081966000926140a06116858561080a565b11156140cd57505050506140c46140be6140c99493611fd89361401a565b94614f3e565b614033565b1790565b92979650929094505b6140f4906140ed6140e68761080a565b8211613fb1565b6000190190565b908161410561216c82888b01610817565b9061410f8761080a565b821161411d575050906140d6565b61413d919798506140c9965061414993506141439250946140c49561401a565b95614f3e565b91613834565b0360ff1690565b9160029261416161216c8286610e90565b61416e61216c8587610e90565b928082106142da576141906141838488610e90565b612bbd83613b61836117cc565b61419d61344b8688610e90565b60008181526001600160a01b038681169190851690600080516020615b6b83398151915290602090a36141d4612440846007610e90565b6141e2612440876007610e90565b9080806142d3575b156141fd575b5050505050505050600190565b15614261575050505061424e90611fd861421d61216c8561425497610e90565b6142487f000000000000000000000000000000000000000000000000000000000000000080926139af565b926139af565b90615361565b38808080808080806141f0565b949092949391936000146142c5575050506142c092611fd86142ba926142b561216c866142af7f000000000000000000000000000000000000000000000000000000000000000080956139af565b95610e90565b6139af565b906151e4565b614254565b909291936142c09550614f97565b50816141ea565b61145883916142e860405190565b63391434e360e21b8152938493600485016121be565b6143196135f261430e60116114b8565b612988846011612093565b907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e061434460405190565b600090a3565b61044d600c6117cc565b614387600061044d92614365600090565b500161437961437382613ee8565b91613d0a565b90036001600160801b031690565b611e2d565b6104dd9061080a565b6001600160a01b03909116815261044d93608082019390926143c591906143bb90613bdb565b604083019061438c565b606081840391015261057d565b9093926143ee6114ce826143e6600161080a565b86898761541b565b6144af57506144006104416000611393565b6001600160a01b038516148015614474575b8015614459575b614428579261043f9293615585565b6114588461443560405190565b633250574960e11b8152918291600483016001600160a01b03909116815260200190565b506001600160a01b0381166001600160a01b03851614614419565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166001600160a01b03851614614412565b84611458849260016144c060405190565b633f756b1760e01b815294859460048601614395565b61043f906012612093565b613ce36301ffc9a760e01b5b916001600160e01b03191690565b61453361450c61216c836002610e90565b7f0000000000000000000000000000000000000000000000000000000000000000906139af565b9061453e600061080a565b9061454d6127a6826008610e90565b93825b61455b61044d875190565b84101561457e576001906145726127d08689611631565b60a01c01930192614550565b9194509203905090614590600061080a565b825b8110156145b0576145a9614592916116e9866156fa565b9050614590565b50915050565b8181106145c1575050565b806145cf6000600193611b71565b016145b6565b9190918282106145e457505050565b61043f92916145f99091600052602060002090565b91820191016145b6565b90600160401b811161094a578161461b61043f935490565b908281556145d5565b600061043f91614603565b906000036109815761043f90614624565b9061464f6127a6836008610e90565b9060009061465c8261080a565b905b61466961044d855190565b82101561473b57906146a29161467f8287615778565b61469186611f86846009989598610817565b61469d8186600a6148af565b840190565b947f0000000000000000000000000000000000000000000000000000000000000000935b8681101561471d57806146e187611f47614718946004610817565b6146f181600d6157cd565b6157cd565b806001600160a01b03878116908b16600080516020615b6b8339815191528a80a460010190565b6146c6565b509450915061044d6147326146699260010190565b9291505061465e565b9361043f935061474d91506008610e90565b61462f565b9061477f61216c61478f92614765600090565b506000614778613e4c613e466008613834565b9501610817565b9161478a600061080a565b921690565b141590565b61044d600161080a565b906147ac6114ce8284612425565b6147b4575050565b6114586147c060405190565b63e2517d3f60e01b815292839260048401611a46565b61044d611fc09161043f946147e9600090565b506001600160a01b0390911660a09190911b6001600160a01b03191601926008610e90565b61044d6001600160a01b031961080a565b9092919261483b61044d61483161480e565b61398160a0613834565b8411614877576120039061043f9394614852600090565b506001600160a01b0390911660a09190911b6001600160a01b03191601916009610817565b6114588461488460405190565b631605cc3f60e11b81529182916004830190815260200190565b61044d9061402e61168561044d9490565b916148c36148bd6008613834565b83613841565b80926148cf60ff61080a565b1691610100918184016148e46116858561080a565b101561491e5750613e67613e6e9361491961043f979694614913600095613b6161490d60001990565b9361080a565b9061489e565b613e1c565b959491935061495e9061495790611fd86000199561494e6000614941838a613e1c565b970196613e6e8c89610817565b613b618861080a565b9560010190565b945b6149698461080a565b8111156149945761495761498e91614985856120038a87610817565b611fd88661080a565b94614960565b613e6e926149136149ae92613b6161043f9899959761080a565b92610817565b61044d6149c160036117cc565b6134fd614794565b6149d3600061080a565b907a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000006149f98161080a565b821015614b49575b506d04ee2d6d415b85acef8100000000614a1a8161080a565b821015614b27575b50662386f26fc10000614a348161080a565b821015614b05575b506305f5e100614a4b8161080a565b821015614ae3575b50612710614a608161080a565b821015614ac1575b50614a73606461080a565b811015614a9f575b614a88611685600a61080a565b1015614a915790565b61044d906105b1600161080a565b614ab0614abb91613a2a606461080a565b916105b1600261080a565b90614a7b565b614adc91613a2a614ad19261080a565b916105b1600461080a565b9038614a68565b614afe91613a2a614af39261080a565b916105b1600861080a565b9038614a53565b614b2091613a2a614b159261080a565b916105b1601061080a565b9038614a3c565b614b4291613a2a614b379261080a565b916105b1602061080a565b9038614a22565b614b6491613a2a614b599261080a565b916105b1604061080a565b9038614a01565b61044d91614b789161582b565b909291926158cb565b909392600a93614b918486613e2d565b614bc5828503926008976001600160a01b0390911660a085901b6001600160a01b0319160190611ec790611f61878b610e90565b614bd4600191611fd88361080a565b95868310614be6575b50505050505050565b614c42611fca85611fd893611fc5614c1a614c4898614c6c9d613b61614c126120039e6105b18d61080a565b9e8f90613e2d565b6001600160a01b038c1660a09190911b6001600160a01b03191601611fc061044d8585610e90565b9161080a565b6001600160a01b0390911660a09190911b6001600160a01b03191601916009610817565b38808080808080614bdd565b9190611f6161043f94614c92611ec7946105b1600161080a565b90614c9e82600a613e2d565b614cc66001600160a01b03871660a086901b6001600160a01b03191601612003846009610817565b6001600160a01b0390911660001990910160a01b6001600160a01b03191601936008610e90565b634e487b7160e01b600052603160045260246000fd5b80548015614d26576000190190614d23614d1d8383611e81565b90611b71565b55565b614ced565b9061043f91614d3e61044d826008610e90565b91614d4a611fce845490565b818103614d5a575b505050614d03565b614da492614d6e611f666120039387611e81565b614d7c81611ec78689611e81565b6001600160a01b0391821660a09490941b6001600160a01b0319169390930192166009610817565b388080614d52565b614db7610100611773565b7e01020903110a19042112290b311a3905412245134d2a550c5d32651b6d3a7560208201527f06264262237d468514804e8d2b95569d0d495ea533a966b11c886eb93bc176c960408201527f071727374353637324837e9b47af86c7155181ad4fd18ed32c9096db57d59ee360608201527f0e2e4a6a5f92a6be3498aae067ddb2eb1d5989b56fd7baf33ca0c2ee77e5caf760808201527fff0810182028303840444c545c646c7425617c847f8c949c48a4a8b087b8c0c860a08201527f16365272829aaec650acd0d28fdad4e22d6991bd97dfdcea58b4d6f29fede4f660c08201527ffe0f1f2f3f4b5b6b607b8b93a3a7b7bf357199c5abcfd9e168bcdee9b3f1ecf560e08201527ffd1e3e5a7a8aa2b670c4ced8bbe8f0f4fc3d79a1c3cde7effb78cce6facbf9f861010082015290565b61044d614dac565b61044d614eea565b61044d7e818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff61080a565b61241561044d61044d9260ff1690565b61044d9060f81c614f22565b614f92614f8461044d92614f50600090565b50614f7e614f74614f68614f62614ef2565b9361599b565b614f70614efa565b0290565b61398160f8613834565b90613810565b516001600160f81b03191690565b614f32565b909194614fa2600090565b50614fce7f000000000000000000000000000000000000000000000000000000000000000080966139af565b93600095614fdc600061080a565b86811015615173579786979860089795969790614ffc611fca8984610e90565b918961500d6001946134fd8661080a565b918a6150198482615778565b94909b61502c61168561158d8989611586565b1161510b57615083611fca8585611fc561507e61044d615093986150788f9d9b99615072611f6661509b9f61044d6150679161508c9f610e90565b92611f61868b610e90565b90611ea4565b84610e90565b614d03565b6134fd8661080a565b8d8c61481f565b898101930190565b9789918d915b905b6150b7575b50505050509796959493614fdc565b8b8482101561510557859383600080516020615b6b83398151915284936150e66150fc97611f47876004610817565b6001600160a01b0390811693169180a460010190565b8c908a926150a3565b506150a8565b9250509261511b908d9a939a0390565b98899003908161512c918c856159c1565b019061513982600a613e2d565b896151458982856147d6565b61514e91610e90565b546151588361080a565b61516491038a8361481f565b958601818a9789918d916150a1565b506151bf94965080611685946151a5615193611fd89461158d979c6139af565b611fd8846142b561216c866002610e90565b88106151d0575b50614248816142b561216c8b6002610e90565b116151c75750565b61043f906156fa565b6151de906142ba600161080a565b386151ac565b91906000926151f3600061080a565b925b8284101561535a5760086152098382610e90565b90615233611f6661521d611fca8785610e90565b9361522d600195611fd88761080a565b90611e81565b60018060a01b0381169060a01c87868a61524d84809c0190565b8a106153145761507e61044d61528295949387986152766105b195611f866152889b6009610817565b611fc5878b600a6148af565b96820190565b7f000000000000000000000000000000000000000000000000000000000000000091835b6152ba575b505050506151f5565b8181101561530f57615309816152d386936146ec600d90565b6152e28b611f47836004610817565b806001600160a01b03868116908a16600080516020615b6b8339815191528e80a460010190565b906152ac565b6152b1565b50508703905096879003858282019381858b81019b61533491600a6148af565b61533d91610e90565b546153478661080a565b900390615353936159c1565b8495615288565b9350505050565b9161536c600061080a565b825b8110156145b05761538561536e916116e9866156fa565b905061536c565b9050519061043f826104ac565b9060208282031261042d5761044d9161538c565b6001600160a01b0391821681529116602082015261044d9260808201929091906143c590612ad0565b3d156153f0576153e53d611773565b903d6000602084013e565b606090565b6001600160a01b03909116815261044d93608082019390926143c59190612ad090613bdb565b93919291600092823b6154306116858661080a565b111561557a576001936001968587905b615450575b505050505050505090565b61545d61044d858a611586565b8110156155755761547061298887610e87565b602061547b60405190565b918290630a85bd0160e11b825281878161549b8c898b33600486016153ad565b03925af160009181615545575b506155155750866154c1578691906001015b9091615440565b50508594506154ce6153d6565b906154e36116856154dd845190565b9261080a565b0361550d575090611458916154f760405190565b633f756b1760e01b8152948594600486016153f5565b805190602001fd5b896154ba918994939b9161552c575b509960010190565b905061553e630a85bd0160e11b6144ed565b1438615524565b61556791925060203d811161556e575b61555f8183610929565b810190615399565b90386154a8565b503d615555565b615445565b505050505050600190565b91816155c461559383613d9e565b6155a66000611f47886004979697610817565b856155ba611f6684611f6160089889610e90565b60a01c9289613dcc565b6155d2612440836007610e90565b1561569a5750506155e581611f96600a90565b6155f081600d6157cd565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116908416600080516020615b6b833981519152600080a45b7f0000000000000000000000000000000000000000000000000000000000000000615661614183846002610e90565b61566f61344b836002610e90565b60009081526001600160a01b039182169290911690600080516020615b6b83398151915290602090a3565b6156d491611fdd916156ca91611fca91611fc56001600160a01b038816600160a01b01611fc061044d8585610e90565b6134fd600161080a565b6001600160a01b03828116908416600080516020615b6b833981519152600080a4615632565b615704600d615a41565b9061573561572e615715600161080a565b6157208185876147d6565b613b61611fca856008610e90565b828461481f565b6001600160a01b03908116907f000000000000000000000000000000000000000000000000000000000000000016600080516020615b6b833981519152600080a4565b61579391611f61611f669261578b600090565b506008610e90565b6001600160a01b0381169160a09190911c90565b906001600160801b03906115f8565b906157c661044d61161792613d21565b82546157a7565b806157e46157da82613d0a565b6143796001613d14565b916157f1613cfe83613ee8565b6001600160801b038416146158195761043f936120038460016158149401613d37565b6157b6565b604051638acb5f2760e01b8152600490fd5b90600091615837825190565b615844611685604161080a565b0361586e5761586792506020820151906060604084015193015160001a90615aac565b9192909190565b50905061588b6158866158816000611393565b925190565b61080a565b909160029190565b634e487b7160e01b600052602160045260246000fd5b600411156158b357565b615893565b9061043f826158a9565b61044d9061080a565b6158d560006158b8565b6158de826158b8565b036158e7575050565b6158f160016158b8565b6158fa826158b8565b036159115760405163f645eedf60e01b8152600490fd5b61591b60026158b8565b615924826158b8565b0361595257611458615935836158c2565b60405163fce698f760e01b81529182916004830190815260200190565b61596561595f60036158b8565b916158b8565b1461596d5750565b6114589061597a60405190565b6335e2f38360e21b81529182916004830190815260200190565b1561042d57565b6159af6159a8600061080a565b8211615994565b6159bd81613b61600061080a565b1690565b91611f61611ec7929361043f956159d6600090565b506001600160a01b0390911660a09190911b6001600160a01b03191601936008610e90565b600161044d91036001600160801b031690565b906fffffffffffffffffffffffffffffffff199060801b6115f8565b90615a3a61044d61161792613d21565b8254615a0e565b9081615a4c81613ee8565b90615a59613cfe85613d0a565b6001600160801b03831614615a9a576001615a7661043f936159fb565b910193615a956000611f8684615a8f61216c828b613d37565b98613d37565b615a2a565b6040516375e52f4f60e01b8152600490fd5b9091615ab7846158c2565b615ae36116857f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a061080a565b11615b565790615afc60209460009493612c3860405190565b838052039060015afa1561142457600051600091615b1983611393565b6001600160a01b0381166001600160a01b03841614615b425750615b3c8361080a565b91929190565b915091615b4e9061080a565b909160019190565b505050615b636000611393565b916003919056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212202701fb4ac6bfe60b7631cc1bea381b78d9c385162634a0e7a45801e33efeef5464736f6c63430008190033608060405234601657604051603f601c8239603f90f35b600080fdfe6080604052600080fdfea26469706673582212207e52eb64f3b00738a15edb69d7ae1fbdb79ee4d572f95c49d49da01ad9561f1664736f6c634300081900338b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400fdb2819cfe36df1a8e2df5d8d9cfe49bf1b7c55ce41ab4723ae144d927ae5245b
Deployed Bytecode
0x60806040526004361015610020575b361561001657005b61001e613215565b005b60003560e01c8062f714ce1461041f57806301ffc9a71461041a578063058985de1461041557806306fdde0314610410578063081812fc1461040b578063095ea7b31461040657806314d0ae661461040157806318160ddd146103fc57806323b872dd146103f7578063248a9ca3146103f25780632f2ff15d146103ed578063313ce567146103e857806334b02e8e146103e35780633644e515146103de578063364f5d23146103d957806336568abe146103d4578063412e5f49146103cf57806342842e0e146103ca57806342966c68146103c55780634443f0a4146103c057806344a5bfa8146103bb5780634f558e79146103b65780634f8a2737146103b157806355f804b3146103ac5780635b21186d146103a75780635e56b06a146103a25780636315ab461461039d5780636352211e1461039857806364aae4161461039357806370a082311461038e578063715018a61461038957806373f425611461038457806375794a3c1461037f5780637e1c0c091461037a5780637e3c9599146103755780637ecebe00146103705780638adae3261461036b5780638da5cb5b14610366578063907af6c0146103615780639198e19a1461035c57806391d148541461035757806395d89b411461035257806396a8ef9e1461034d578063a217fddf14610348578063a22cb46514610343578063a9059cbb1461033e578063aa97eca214610339578063ade474e614610334578063b1ab93171461032f578063b88d4fde1461032a578063be00df4a14610325578063c87b56dd14610320578063d505accf1461031b578063d539139314610316578063d547741f14610311578063dab400f31461030c578063dd62ed3e14610307578063e0d4ea3714610302578063e985e9c5146102fd578063ecb41c75146102f8578063ed915ea1146102f3578063f2fde38b146102ee578063fcf8be1f146102e95763fd89b0f50361000e5761135c565b611340565b611328565b611314565b6112db565b6112bf565b6112a4565b611288565b611233565b61121a565b6111e1565b6111c2565b611132565b61111a565b6110fe565b611094565b611079565b61105e565b611042565b611029565b61100e565b610fe8565b610fa4565b610f88565b610f6d565b610f34565b610f19565b610ee0565b610ec5565b610e51565b610e13565b610df8565b610ddd565b610dc5565b610daa565b610d7a565b610d5f565b610d46565b610d2b565b610d12565b610cbb565b610ca3565b610bdd565b610bc1565b610b16565b610a57565b610a3e565b610a23565b610a0a565b6109d1565b6109b6565b61099b565b6107cc565b6107b3565b610798565b61077c565b610728565b610705565b610659565b610601565b6105c6565b610537565b6104e1565b61048f565b805b0361042d57565b600080fd5b9050359061043f82610424565b565b6001600160a01b031690565b90565b6001600160a01b038116610426565b9050359061043f82610450565b919060408382031261042d5761044d9060206104888286610432565b940161045f565b6104a361049d36600461046c565b9061147f565b604051005b0390f35b6001600160e01b03198116610426565b9050359061043f826104ac565b9060208282031261042d5761044d916104bc565b9052565b3461042d576104a86104fc6104f73660046104c9565b611489565b60405191829182901515815260200190565b801515610426565b9050359061043f8261050e565b9060208282031261042d5761044d91610516565b3461042d576104a361054a366004610523565b611492565b600091031261042d57565b60005b83811061056d5750506000910152565b818101518382015260200161055d565b61059e6105a76020936105b193610592815190565b80835293849260200190565b9586910161055a565b601f01601f191690565b0190565b602080825261044d9291019061057d565b3461042d576105d636600461054f565b6104a86105e16114a5565b604051918291826105b5565b9060208282031261042d5761044d91610432565b3461042d576104a861061c6106173660046105ed565b6114c2565b604051918291826001600160a01b03909116815260200190565b919060408382031261042d5761044d906020610652828661045f565b9401610432565b3461042d576104a86104fc61066f366004610636565b90611510565b909160608284031261042d5761044d61068e848461045f565b9360406106528260208701610432565b906106be6106b76106ad845190565b8084529260200190565b9260200190565b9060005b8181106106cf5750505090565b9091926106ec6106e56001928651815260200190565b9460200190565b9291016106c2565b602080825261044d9291019061069e565b6104a861071c610716366004610675565b91611721565b604051918291826106f4565b3461042d5761073836600461054f565b6104a8610743611741565b6040519182918290815260200190565b909160608284031261042d5761044d61076c848461045f565b936040610652826020870161045f565b3461042d576104a86104fc610792366004610753565b91611792565b3461042d576104a86107436107ae3660046105ed565b6117d6565b3461042d576104a36107c636600461046c565b90611813565b3461042d576107dc36600461054f565b6040517f000000000000000000000000000000000000000000000000000000000000001260ff168152602090f35b61044d61044d61044d9290565b906108219061080a565b600052602052604060002090565b634e487b7160e01b600052600060045260246000fd5b634e487b7160e01b600052602260045260246000fd5b906001600283049216801561087b575b602083101461087657565b610845565b91607f169161086b565b805460009392916108a26108988361085b565b8085529360200190565b91600181169081156108f457506001146108bb57505050565b6108ce9192939450600052602060002090565b916000925b8184106108e05750500190565b8054848401526020909301926001016108d3565b92949550505060ff1916825215156020020190565b9061044d91610885565b634e487b7160e01b600052604160045260246000fd5b90601f01601f191681019081106001600160401b0382111761094a57604052565b610913565b9061043f6109699261096060405190565b93848092610909565b0383610929565b906000106109815761044d9061094f565b61082f565b600061099661044d926016610817565b610970565b3461042d576104a86105e16109b13660046105ed565b610986565b3461042d576109c636600461054f565b6104a861074361181d565b3461042d576109e136600461054f565b6104a87fdb2819cfe36df1a8e2df5d8d9cfe49bf1b7c55ce41ab4723ae144d927ae5245b610743565b3461042d576104a3610a1d36600461046c565b90611870565b3461042d576104a86105e1610a393660046105ed565b611997565b3461042d576104a3610a51366004610753565b91611a38565b3461042d576104a3610a6a3660046105ed565b611a63565b909182601f8301121561042d578135916001600160401b03831161042d57602001926020830284011161042d57565b9060208282031261042d5781356001600160401b03811161042d57610ac39201610a6f565b9091565b90610ad66106b76106ad845190565b9060005b818110610ae75750505090565b909192610afd6106e56001928651815260200190565b929101610ada565b602080825261044d92910190610ac7565b3461042d576104a8610b32610b2c366004610a9e565b90611abb565b60405191829182610b05565b909182601f8301121561042d578135916001600160401b03831161042d57602001926001830284011161042d57565b60608183031261042d57610b818282610432565b9260208201356001600160401b03811161042d5783610ba1918401610b3e565b92909360408201356001600160401b03811161042d57610ac39201610b3e565b3461042d576104a3610bd4366004610b6d565b93929092611cbf565b3461042d576104a86104fc610bf33660046105ed565b611d10565b9061043f610c0560405190565b9283610929565b6001600160401b03811161094a57602090601f01601f19160190565b90826000939282370152565b90929192610c49610c4482610c0c565b610bf8565b938185528183011161042d5761043f916020850190610c28565b9080601f8301121561042d5781602061044d93359101610c34565b9060208282031261042d5781356001600160401b03811161042d5761044d9201610c63565b3461042d576104a3610cb6366004610c7e565b611e04565b3461042d576104a3610cce366004610c7e565b611e24565b6001600160801b038116610426565b9050359061043f82610cd3565b919060408382031261042d5761044d906020610d0b8286610432565b9401610ce2565b3461042d576104a3610d25366004610cef565b90611edd565b3461042d57610d3b36600461054f565b6104a861071c61207a565b3461042d576104a3610d59366004610636565b906120aa565b3461042d576104a861061c610d753660046105ed565b61213e565b3461042d576104a86104fc610d90366004610753565b916121f2565b9060208282031261042d5761044d9161045f565b3461042d576104a8610743610dc0366004610d96565b61233e565b3461042d57610dd536600461054f565b6104a3612372565b3461042d57610ded36600461054f565b6104a861074361237a565b3461042d57610e0836600461054f565b6104a8610743612382565b3461042d57610e2336600461054f565b6104a861074361238c565b919060408382031261042d5761044d906020610e4a828661045f565b9401610516565b3461042d576104a3610e64366004610e2e565b906123f2565b61044d90610441906001600160a01b031682565b61044d90610e6a565b61044d90610e7e565b9061082190610e87565b61044d916008021c81565b9061044d9154610e9a565b6000610ec061044d92600f610e90565b610ea5565b3461042d576104a8610743610edb366004610d96565b610eb0565b3461042d57610ef036600461054f565b6104a87f114ba586f27424819fdf1eac564faf22081abcab4f662a9e508c112ed1a7cbcf610743565b3461042d57610f2936600461054f565b6104a861061c6123fc565b3461042d57610f4436600461054f565b6104a87f0000000000000000000000000000000000000000000000120d4da7b0bd140000610743565b3461042d57610f7d36600461054f565b6104a8610743612406565b3461042d576104a86104fc610f9e36600461046c565b90612425565b3461042d57610fb436600461054f565b6104a86105e1612445565b909160608284031261042d5761044d610fd8848461045f565b9360406104888260208701610432565b6104a3610ff6366004610fbf565b916125d8565b61044d600061080a565b61044d610ffc565b3461042d5761101e36600461054f565b6104a8610743611006565b3461042d576104a361103c366004610e2e565b90612603565b3461042d576104a86104fc611058366004610636565b90612699565b3461042d576104a86104fc611074366004610d96565b6126aa565b3461042d5761108936600461054f565b6104a86105e16126c1565b3461042d576104a861071c6110aa366004610d96565b612750565b9060808282031261042d576110c4818361045f565b926110d2826020850161045f565b926110e08360408301610432565b9260608201356001600160401b03811161042d5761044d9201610c63565b3461042d576104a36111113660046110af565b92919091612896565b3461042d576104a361112d366004610d96565b6128f4565b3461042d576104a86105e16111483660046105ed565b612966565b60ff8116610426565b9050359061043f8261114d565b60e08183031261042d57611177828261045f565b92611185836020840161045f565b926111938160408501610432565b926111a18260608301610432565b9261044d6111b28460808501611156565b9360c06106528260a08701610432565b3461042d576104a36111d5366004611163565b95949094939193612b35565b3461042d576111f136600461054f565b6104a87f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6610743565b3461042d576104a361122d36600461046c565b90612dd6565b3461042d5761124336600461054f565b6104a87f0e7a552dfd1dbc578a80e6130b42ccb1e661a00a922ebfd0a0def6c5f5501fe4610743565b919060408382031261042d5761044d906020610488828661045f565b3461042d576104a861074361129e36600461126c565b90612de0565b3461042d576104a86107436112ba3660046105ed565b612e0a565b3461042d576104a86104fc6112d536600461126c565b90612e68565b3461042d576112eb36600461054f565b6104a87f000000000000000000000000e25df5e33f915ab698e12e62fa2d8e3cacbb859d61061c565b6104a3611322366004610fbf565b91613098565b3461042d576104a361133b366004610d96565b61310d565b3461042d576104a86104fc611356366004610636565b90613116565b3461042d576104a361136f366004610d96565b61320c565b9061043f91611381613250565b6113d8565b61044161044d61044d9290565b61044d90611386565b6104dd90610e87565b60208101929161043f919061139c565b90815260408101929161043f9160200152565b0152565b6040513d6000823e3d90fd5b6000916113e761044184611393565b6113f082610e87565b1461145c576113fe30610e87565b8031831161143257508280926114148293610e87565b828215611429575bf11561142457565b6113cc565b506108fc61141c565b9050319061145861144260405190565b631944d18360e21b8152928392600484016113b5565b0390fd5b6114589061146960405190565b639c86094560e01b8152918291600483016113a5565b9061043f91611374565b61044d906132a5565b61043f90336132ce565b61044d9061094f565b61044d600061149c565b61044d90610441565b61044d90546114af565b6114d26114ce8261338d565b1590565b6114e9576114e461044d916004610817565b6114b8565b611458906114f660405190565b637e27328960e01b81529182916004830190815260200190565b9061151a8161338d565b1561152d57611528916120aa565b600190565b61044d91613116565b61044d9392919061156b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a66133d0565b6133d0565b611650565b634e487b7160e01b600052601160045260246000fd5b9190611591565b9290565b820180921161159c57565b611570565b6001600160401b03811161094a5760208091020190565b906115c5610c44836115a1565b918252565b369037565b9061043f6115e56115df846115b8565b936115a1565b601f1901602084016115ca565b90600019905b9181191691161790565b9061161061044d6116179290565b82546115f2565b9055565b634e487b7160e01b600052603260045260246000fd5b9061163a825190565b81101561164b576020809102010190565b61161b565b50919261165d600061080a565b841461170f5761166b612382565b916116768584611586565b611689611685620208d561080a565b9190565b116116fd576116b5906116a58661169f816115cf565b966133db565b6116b0846017610817565b611602565b6116bf600061080a565b845b8110156116f6576116ef816116e96116dc6116c19487611586565b6116e68389611631565b52565b60010190565b90506116bf565b5092505090565b60405163318df65960e01b8152600490fd5b604051631758383360e11b8152600490fd5b61044d9291906060611536565b8181029291811591840414171561159c57565b61044d61174c6135a3565b7f0000000000000000000000000000000000000000000000120d4da7b0bd1400009061172e565b906115c5610c4483610c0c565b61044d6000611773565b61044d611780565b919061179d8261338d565b156117b6579061152892916117b061178a565b92612896565b61044d926121f2565b90610821565b61044d9081565b61044d90546117c5565b60016117ef61044d926117e7600090565b5060106117bf565b016117cc565b9061043f91611806611566826117d6565b90611810916135b6565b50565b9061043f916117f5565b7f00000000000000000000000000000000000000000000000000000000000000014603611868577ffee4e2a8816bc8a50511385138f948759f30bbeb14079b813bb7ff9de11b2f1990565b61044d61370d565b9061187a33610441565b6001600160a01b03821603611892576118109161379d565b60405163334bd91960e11b8152600490fd5b61044d905461085b565b61044d9081906001600160a01b031681565b805460009392916118d76118d38361085b565b9390565b916001811690811561192857506001146118f057505050565b6119039192939450600052602060002090565b6000905b8382106119145750500190565b600181602092548486015201910190611907565b60ff191683525050811515909102019150565b6105b16119539260209261194d815190565b94859290565b9384910161055a565b61197a611987936119746119749361044d97956118c0565b9061193b565b602f60f81b815260010190565b632e706e6760e01b815260040190565b6119ad6119a861044d836016610817565b6118a4565b6119ba611685600061080a565b11156119d3576119ce61044d916016610817565b61149c565b611a2c61044d61044d92611a12611a0c6119fc6119f76119f230610e87565b610e7e565b6118ae565b611a06601461080a565b9061385a565b916139be565b90611a1c60405190565b938492602084019260138461195c565b90810382520382610929565b909161043f926117b061178a565b6001600160a01b03909116815260408101929161043f9160200152565b611a706114ce8233613a51565b611a7d5761043f90613ab2565b61145890611a8a60405190565b63177e802f60e01b81529182913360048401611a46565b919081101561164b576020020190565b3561044d81610424565b91908092611ac8846115cf565b92611ad3600061080a565b855b811015611b0d57611b06816116e9611afc6112ba611af7611ad5968a8a611aa1565b611ab1565b6116e6838a611631565b9050611ad3565b509350505090565b91906105a781611b2c816105b19560209181520190565b8095610c28565b602080825261044d93910191611b15565b9160001960089290920291821b911b6115f8565b9190611b6961044d6116179361080a565b908354611b44565b61043f91600091611b58565b818110611b88575050565b80611b966000600193611b71565b01611b7d565b9190601f8111611bab57505050565b611bbd61043f93600052602060002090565b906020601f840181900483019310611bdf575b6020601f909101040190611b7d565b9091508190611bd0565b91906001600160401b03821161094a57611c0d82611c07855461085b565b85611b9c565b600090601f8311600114611c4857611617929160009183611c3d575b5050600019600883021c1916906002021790565b013590503880611c29565b90601f19831691611c5e85600052602060002090565b92825b818110611c9c57509160029391856001969410611c82575b50505002019055565b0135600019601f84166008021c19165b9055388080611c79565b92936020600181928786013581550195019301611c61565b9061043f9291611be9565b9493909192611cd46114ce838387878b613be2565b611cee575050611ce961043f93946016610817565b611cb4565b611458611cfa60405190565b631d9394a560e21b815292839260048401611b33565b61044d9061338d565b61043f90611d25613250565b611df9565b90611d33815190565b906001600160401b03821161094a57611d5082611c07855461085b565b602090601f8311600114611d8a57611617929160009183611d7f575050600019600883021c1916906002021790565b015190503880611c29565b601f19831691611d9f85600052602060002090565b9260005b818110611dd757509160029391856001969410611dc35750505002019055565b01516000196008601f8516021c1916611c92565b91936020600181928787015181550195019201611da3565b9061043f91611d2a565b61043f906014611def565b61043f90611d19565b61043f90611e19613250565b61043f906013611def565b61043f90611e0d565b61044d61044d61044d926001600160801b031690565b916001600160a01b0360089290920291821b911b6115f8565b9190611e6d61044d61161793610e87565b908354611e43565b61043f91600091611e5c565b805482101561164b57611e9b600191600052602060002090565b91020190600090565b90815491600160401b83101561094a5782611ec791600161043f95018155611e81565b90611b58565b9061161061044d6116179261080a565b90600d611ef2611eec83611e2d565b82613d41565b90611eff6114ce8561338d565b61206d57611f106114ce8533613a51565b61206057611fdd611fce611fca61200893611f76611fa089611f3181613d9e565b94829c929691611f4c6000611f47876004610817565b611e75565b60089685611f6c611f6684611f618d8d610e90565b611e81565b90610ea5565b60a01c928a613dcc565b611f8b6000611f86856009610817565b611b71565b611f9b83600a613e2d565b613e2d565b613e9e565b611fc56001600160a01b038816600160a01b01611fc061044d8585610e90565b611ea4565b610e90565b5490565b611fd8600161080a565b900390565b6001600160a01b03841660a09190911b6001600160a01b03191601612003836009610817565b611ecd565b6001600160a01b037f000000000000000000000000e25df5e33f915ab698e12e62fa2d8e3cacbb859d81169216908183600080516020615b6b833981519152600080a4600080516020615b6b833981519152600080a4565b61145884611a8a60405190565b611458846114f660405190565b61044d600d613f05565b906001600160a01b03906115f8565b906120a361044d61161792610e87565b8254612084565b6120b38261213e565b906001600160a01b0382163314158061212b575b612113576120df816120da856004610817565b612093565b6001600160a01b0390811691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a4565b60405163a9fbf51f60e01b8152336004820152602490fd5b506121396114ce3384612e68565b6120c7565b61214a6114ce8261338d565b6114e95761216c61216561217192612160600a90565b614043565b6009610817565b6117cc565b6001600160a01b0316906121886104416000611393565b6001600160a01b0383161461219957565b7f000000000000000000000000e25df5e33f915ab698e12e62fa2d8e3cacbb859d9150565b6001600160a01b03909116815260608101939261043f9290916040916113c8906020830152565b9190820391821161159c57565b9291906122026104416000611393565b6001600160a01b038216148015612303575b80156122e8575b6122b757336001600160a01b0385160361223a575b61044d9293614150565b61225261216c61224b866006610e90565b3390610e90565b936000198503612264575b9350612230565b8483116122925761228a61227c8461044d96976121e5565b61200361224b846006610e90565b84935061225d565b8490611458846122a160405190565b637dc7a0d960e11b8152938493600485016121be565b611458906122c460405190565b63ec442f0560e01b8152918291600483016001600160a01b03909116815260200190565b506001600160a01b0384166001600160a01b0382161461221b565b506001600160a01b037f000000000000000000000000e25df5e33f915ab698e12e62fa2d8e3cacbb859d166001600160a01b03821614612214565b61216c61044d9161234d600090565b506002610e90565b61235d613250565b61043f61043f61236d6000611393565b6142fe565b61043f612355565b61044d61434a565b61044d60036117cc565b61044d6135a3565b9061043f916123a1613250565b9190823b6123b2611685600061080a565b146123c15761043f91926132ce565b611458836123ce60405190565b639c86094560e01b8152918291600483016001600160a01b03909116815260200190565b9061043f91612394565b61044d60116114b8565b61044d600d614354565b61044d905b60ff1690565b61044d9054612410565b61044d91600061243a612440936117e7600090565b01610e90565b61241b565b61044d600161149c565b9061043f929161245d613250565b6124a7565b9050519061043f82610450565b9060208282031261042d5761044d91612462565b6001600160a01b0391821681529116602082015260608101929161043f9160400152565b6124b090610e87565b906124be6104416000611393565b6001600160a01b038416146123c1576124df6124d930610e87565b92610e87565b6040516331a9108f60e11b815260048101839052602081602481855afa80156114245761251b916000916125a9575b506001600160a01b031690565b6001600160a01b0384160361258557803b1561042d5761255c936000809461254260405190565b96879586948593632142170760e11b855260048501612483565b03925af180156114245761256d5750565b61043f90600061257d8183610929565b81019061054f565b509061145861259360405190565b633f82dd3d60e11b815292839260048401611a46565b6125cb915060203d6020116125d1575b6125c38183610929565b81019061246f565b3861250e565b503d6125b9565b9061043f929161244f565b9060ff906115f8565b906125fc61044d61161792151590565b82546125e3565b90336001600160a01b038316146126685761262c8161262784611fc5336005610e90565b6125ec565b60009081526001600160a01b03919091169033907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3190602090a3565b6114588261267560405190565b630b61174360e31b8152918291600483016001600160a01b03909116815260200190565b6126a4919033611792565b50600190565b61244061044d916126b9600090565b506007610e90565b61044d601461149c565b906126e66126da6106ad845490565b92600052602060002090565b9060005b8181106126f75750505090565b90919261271b61271460019261270c876117cc565b815260200190565b9460010190565b9291016126ea565b9061044d916126cb565b9061043f6109699261273e60405190565b93848092612723565b61044d9061272d565b906001600160a01b037f000000000000000000000000e25df5e33f915ab698e12e62fa2d8e3cacbb859d166001600160a01b0383161461288c5760006127958161080a565b926127ab6127a66000926008610e90565b612747565b91845b6127b961044d855190565b8610156127e0576001906127d46127d08887611631565b5190565b60a01c019501946127ae565b6127ee9193949295506115cf565b9182946127fa8261080a565b905080915b61280a61044d875190565b8310156128845761281e6127d08488611631565b60a081901c966001600160a01b03909116949061283a8361080a565b935b8885101561286757612714612861916116e9612857888b0190565b6116e6838d611631565b9361283c565b9893509390945061287a91965060010190565b91949590956127ff565b505050915050565b905061044d61207a565b939291906128a66114ce8361338d565b6128d2576128b76114ce8333613a51565b6128c55761043f93946143d2565b61145882611a8a60405190565b611458826114f660405190565b61043f906128eb613250565b61043f906144d6565b61043f906128df565b9092919261290d610c4482610c0c565b938185528183011161042d5761043f91602085019061055a565b9080601f8301121561042d57815161044d926020016128fd565b9060208282031261042d5781516001600160401b03811161042d5761044d9201612927565b60006129ae91612974606090565b5061298d61298861298861298860156114b8565b610e87565b6040519384928391829163c87b56dd60e01b83526004830190815260200190565b03915afa908115611424576000916129c4575090565b61044d91503d806000833e6129d98183610929565b810190612941565b949290979695939160e086019860008701612a03916001600160a01b03169052565b6001600160a01b031660208601526040850152606084015260ff16608083015260a082015260c00152565b9194612a7d6113c892989795612a7660a096612a6661043f9a612a5660c08a019e60008b0152565b6001600160a01b03166020890152565b6001600160a01b03166040870152565b6060850152565b6080830152565b6020809392612aa16115c56105b19461190160f01b815260020190565b01918252565b6113c861043f94612ad0606094989795612ac6608086019a6000870152565b60ff166020850152565b6040830152565b9593919897969492909861010087019960008801612afc916001600160a01b03169052565b6001600160a01b031660208701526001600160a01b031660408601526060850152608084015260ff1660a083015260c082015260e00152565b95909394929192612b434290565b8310612d9557612b528461338d565b612d6e57600095612b6287611393565b936001600160a01b0385166001600160a01b038816148015612d33575b612d025760208883611a2c612c1e8d8b612bf48e612b9b61181d565b93611a2c8b612bab83600f610e90565b612bc3612bb7826117cc565b91600183015b90611ecd565b6040519687958e8701957f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c987612a2e565b612c06612bff825190565b9160200190565b2090612c1160405190565b9384928884019283612a84565b612c29612bff825190565b20612c418888612c3860405190565b94859485612aa7565b838052039060015afa15611424578751946001600160a01b03166001600160a01b038616148015612ce6575b612cc057505050509181612cad60209361200384611fc57f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925986006610e90565b84526001600160a01b03908116941692a3565b61145894958997612cd060405190565b63d01a799560e01b815298899860048a01612ad7565b506001600160a01b0389166001600160a01b0386161415612c6d565b61145887612d0f60405190565b634a1406b160e11b8152918291600483016001600160a01b03909116815260200190565b506001600160a01b037f000000000000000000000000e25df5e33f915ab698e12e62fa2d8e3cacbb859d166001600160a01b03881614612b7f565b61145884612d7b60405190565b635dbad48560e01b81529182916004830190815260200190565b85611458938895612da560405190565b63dc99de6360e01b8152978897600489016129e1565b9061043f91612dcc611566826117d6565b906118109161379d565b9061043f91612dbb565b61044d91611fc561216c92612df3600090565b506006610e90565b600019811461159c5760010190565b90600090612e18600061080a565b612e22600061080a565b905b612e2d8461080a565b8103612e605750612e2d612e58612e5261216c6017612e4c868a6121e5565b90610817565b92612dfb565b919050612e24565b925050915090565b61044d91611fc561244092612e7b600090565b506005610e90565b9061043f9291612e91613250565b612ef3565b9050519061043f82610424565b9060208282031261042d5761044d91612e96565b9050519061043f8261050e565b9060208282031261042d5761044d91612eb7565b91602061043f9294936113c86040820196600083019061139c565b612eff90929192610e87565b612f0c6104416000611393565b612f1583610e87565b1461308b57612f2390610e87565b906370a08231612f3230610e87565b90612f3c60405190565b612f468260e01b90565b81526001600160a01b0383166004820152602081602481885afa801561142457612f7591600091613072575090565b8511612fe857505091602091612faf936000612f9060405190565b809681958294612fa463a9059cbb60e01b90565b845260048401612ed8565b03925af1801561142457612fc05750565b6118109060203d602011612fe1575b612fd98183610929565b810190612ec4565b503d612fcf565b6020613021928561300a8894612ffd60405190565b9687948593849360e01b90565b83526001600160a01b031660048301526024820190565b03915afa91821561142457600092613041575b5061145861144260405190565b61306491925060203d60201161306b575b61305c8183610929565b810190612ea3565b9082613034565b503d613052565b61044d915060203d60201161306b5761305c8183610929565b6114588261146960405190565b9061043f9291612e83565b61043f906130af613250565b6130b96000611393565b6001600160a01b0381166001600160a01b038316146130dc575061043f906142fe565b611458906130e960405190565b631e4fbdf760e01b8152918291600483016001600160a01b03909116815260200190565b61043f906130a3565b906131246104416000611393565b6001600160a01b038316148015613199575b61318c5761314d8161200384611fc5336006610e90565b60009081526001600160a01b03919091169033907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590602090a3600190565b61145882612d0f60405190565b506001600160a01b037f000000000000000000000000e25df5e33f915ab698e12e62fa2d8e3cacbb859d166001600160a01b03831614613136565b61043f906132017fdb2819cfe36df1a8e2df5d8d9cfe49bf1b7c55ce41ab4723ae144d927ae5245b6133d0565b61043f906015612093565b61043f906131d4565b7f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f8852587461323f60405190565b8061324b343383611a46565b0390a1565b6132586123fc565b339061326c825b916001600160a01b031690565b036132745750565b6114589061328160405190565b63118cdaa760e01b8152918291600483016001600160a01b03909116815260200190565b637965db0b60e01b6001600160e01b03198216149081156132c4575090565b61044d91506144e1565b91906132dd6104416000611393565b6001600160a01b038416148015613352575b6133215761262761043f9293826000146133135761330c81614640565b6007610e90565b61331c816144fb565b61330c565b6114588361332e60405190565b63024b6d7560e31b8152918291600483016001600160a01b03909116815260200190565b506001600160a01b037f000000000000000000000000e25df5e33f915ab698e12e62fa2d8e3cacbb859d166001600160a01b038416146132ef565b61339881600b614752565b6133ca576133a961044d60036117cc565b811090816133b5575090565b90506133c561168561158d614794565b111590565b50600090565b61043f90339061479e565b6000906133e78261080a565b8314613591576133f961044183611393565b6001600160a01b038216148015613556575b6122b75761341960036117cc565b917f0000000000000000000000000000000000000000000000120d4da7b0bd140000840261345861344b846002610e90565b612bbd836105b1836117cc565b8152838301906001600160a01b038316908181600080516020615b6b833981519152602082a361348c612440856007610e90565b156134bf5750505050816134ae61043f936134b8936134a9600a90565b6148af565b6105b160036117cc565b6003611ecd565b90919293806134d2600192611f96600a90565b6134dd8787836147d6565b61350a6134ee611fca886008610e90565b9661350384986134fd8661080a565b906121e5565b908361481f565b808484600080516020615b6b8339815191528180a4015b8381036135395750505050506134b861043f916134ae565b8085918484600080516020615b6b8339815191528180a401613521565b506001600160a01b037f000000000000000000000000e25df5e33f915ab698e12e62fa2d8e3cacbb859d166001600160a01b0382161461340b565b604051636e45634760e11b8152600490fd5b61044d6135ae6149b4565b6134fd61434a565b6135c36114ce8383612425565b1561362c576135de600161262784600061243a8660106117bf565b6135f86135f26135ec339390565b93610e87565b91610e87565b917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d61362360405190565b600090a4600190565b5050600090565b805460009392916136466108988361085b565b91600181169081156108f4575060011461365f57505050565b6136729192939450600052602060002090565b916000925b8184106136845750500190565b805484840152602090930192600101613677565b9061044d91613633565b9061043f610969926136b360405190565b93848092613698565b61044d906136a2565b9095949261043f946136f76136fe926136f06080966136e960a088019c6000890152565b6020870152565b6040850152565b6060830152565b01906001600160a01b03169052565b611a2c61378e61371d60006136bc565b613728612bff825190565b2061373230610e87565b9061373c60405190565b93849260208401927fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc646917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f866136c5565b613799612bff825190565b2090565b6137a78282612425565b1561362c576137c16000612627848261243a8660106117bf565b6137cf6135f26135ec339390565b917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b61362360405190565b9061043f6115e561380a84611773565b93610c0c565b90613819825190565b81101561164b570160200190565b801561159c576000190190565b61241561044d61044d9290565b61044d9061385561168561044d9460ff1690565b901c90565b908161388a61388561387584613870600261080a565b61172e565b61387f600261080a565b90611586565b6137fa565b92600060306138a161389b8361080a565b87613810565b536001600f60fb1b821a6138bd6138b78361080a565b88613810565b53806138d96138d087613870600261080a565b61387f8361080a565b915b61391a575b50506116856138ee9161080a565b036138f857505090565b61145861390460405190565b63e22e27eb60e01b8152928392600484016113b5565b90926139258261080a565b841115613993576f181899199a1a9b1b9c1cb0b131b232b360811b61394a600f61080a565b821690601082101561164b57839261396a6139879261398d941a60f81b90565b861a613976888c613810565b536139816004613834565b90613841565b94613827565b916138db565b926138e0565b634e487b7160e01b600052601260045260246000fd5b81156139b9570490565b613999565b6139c7816149c9565b906139d86001926105b1600161080a565b91806139e3846137fa565b936020018401905b6139f6575b50505090565b8115613a4c57613a309060001901926f181899199a1a9b1b9c1cb0b131b232b360811b600a82061a8453613a2a600a61080a565b906139af565b9081613a3f611685600061080a565b14613a4c579091816139eb565b6139f0565b613a5a8261213e565b6001600160a01b0381166001600160a01b03831614928315613a8d575b508215613a8357505090565b61044d9250612e68565b613a989193506114c2565b613aaa6001600160a01b03831661325f565b149138613a77565b613abe6114ce8261338d565b6114e9576000613aff613ad083613d9e565b613ae285611f47886004979697610817565b85613af5611f6684611f61886008610e90565b60a01c9285613dcc565b613b0e82611f86856009610817565b613b1983600a613e2d565b613b2483600b613e2d565b7f0000000000000000000000000000000000000000000000120d4da7b0bd14000090613b65613b54826002610e90565b612bbd84613b61836117cc565b0390565b613b7c613b756116e9600c6117cc565b600c611ecd565b9082526001600160a01b03168181600080516020615b6b833981519152602083a3600080516020615b6b8339815191528280a4565b61044d913691610c34565b6136fe61043f94612ad0606094989795613bdb608086019a6000870152565b6020850152565b9390613bee60126114b8565b613bfe61325f6104416000611393565b14613ce757613cbb613ccd93611a2c92613c97613cd398613c6e613c687f0e7a552dfd1dbc578a80e6130b42ccb1e661a00a922ebfd0a0def6c5f5501fe495613c647f114ba586f27424819fdf1eac564faf22081abcab4f662a9e508c112ed1a7cbcf90565b9591565b90613bb1565b613c79612bff825190565b2090611a2c613c8760405190565b9485936020850193339285613bbc565b613ca2612bff825190565b2090613cad60405190565b938492602084019283612a84565b613cc6612bff825190565b2092613bb1565b90614b6b565b613ce361325f61044160126114b8565b1490565b6040516395e0712b60e01b8152600490fd5b61044d905b6001600160801b031690565b61044d9054613cf9565b613cfe61044d61044d9290565b613cfe61044d61044d926001600160801b031690565b9061082190613d21565b90613d4e61044d83614354565b811015613d8c5781613d8661216c92613d79613d736000600161044d98019501613d0a565b91613d14565b016001600160801b031690565b90613d37565b60405163580821e760e01b8152600490fd5b613da990600a614043565b613db761216c826009610817565b6001600160a01b0381169260a09190911c9190565b93919092613dd78290565b8103613e045750613de8600161080a565b8203613df957505061043f91614d2b565b909161043f93614c78565b919261043f94614b81565b61044d600160ff1b61080a565b61044d9061385561168561044d9490565b613e6e61043f926000613e67613e4c613e466008613834565b84613841565b92613e55613e0f565b90613e6060ff61080a565b1690613e1c565b9301610817565b90613e78826117cc565b1790611ecd565b6001600160801b03908116911601906001600160801b03821161159c57565b9190613eac61044d84614354565b613eb582611e2d565b1015613d8c5782613d8661200392613ed66000600161043f98019401613d0a565b90613e7f565b61044d9060801c613cfe565b61044d9054613edc565b600161044d91016001600160801b031690565b613f1d613f2a82613f1581613d0a565b928391613ee8565b036001600160801b031690565b91613f3c613f3784611e2d565b6115cf565b938490613f496000613d14565b6001600160801b0386165b6001600160801b0382161015613fa857613fa1613f5491613f9c613f8a61216c60018901613d86858c016001600160801b031690565b6116e6613f9684611e2d565b8c611631565b613ef2565b9050613f49565b50935093505050565b15613fb857565b60405162461bcd60e51b815260206004820152603460248201527f4269744d6170733a205468652073657420626974206265666f7265207468652060448201527334b73232bc103237b2b9b713ba1032bc34b9ba1760611b6064820152608490fd5b61044d9061402e61168561044d9460ff1690565b901b90565b61044d61044d61044d9260ff1690565b6000916140506008613834565b9061405b8282613841565b92839161408e61407c61216c60ff9361407460ff61080a565b169785610817565b8661408760ff61080a565b1890613e1c565b9081966000926140a06116858561080a565b11156140cd57505050506140c46140be6140c99493611fd89361401a565b94614f3e565b614033565b1790565b92979650929094505b6140f4906140ed6140e68761080a565b8211613fb1565b6000190190565b908161410561216c82888b01610817565b9061410f8761080a565b821161411d575050906140d6565b61413d919798506140c9965061414993506141439250946140c49561401a565b95614f3e565b91613834565b0360ff1690565b9160029261416161216c8286610e90565b61416e61216c8587610e90565b928082106142da576141906141838488610e90565b612bbd83613b61836117cc565b61419d61344b8688610e90565b60008181526001600160a01b038681169190851690600080516020615b6b83398151915290602090a36141d4612440846007610e90565b6141e2612440876007610e90565b9080806142d3575b156141fd575b5050505050505050600190565b15614261575050505061424e90611fd861421d61216c8561425497610e90565b6142487f0000000000000000000000000000000000000000000000120d4da7b0bd14000080926139af565b926139af565b90615361565b38808080808080806141f0565b949092949391936000146142c5575050506142c092611fd86142ba926142b561216c866142af7f0000000000000000000000000000000000000000000000120d4da7b0bd14000080956139af565b95610e90565b6139af565b906151e4565b614254565b909291936142c09550614f97565b50816141ea565b61145883916142e860405190565b63391434e360e21b8152938493600485016121be565b6143196135f261430e60116114b8565b612988846011612093565b907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e061434460405190565b600090a3565b61044d600c6117cc565b614387600061044d92614365600090565b500161437961437382613ee8565b91613d0a565b90036001600160801b031690565b611e2d565b6104dd9061080a565b6001600160a01b03909116815261044d93608082019390926143c591906143bb90613bdb565b604083019061438c565b606081840391015261057d565b9093926143ee6114ce826143e6600161080a565b86898761541b565b6144af57506144006104416000611393565b6001600160a01b038516148015614474575b8015614459575b614428579261043f9293615585565b6114588461443560405190565b633250574960e11b8152918291600483016001600160a01b03909116815260200190565b506001600160a01b0381166001600160a01b03851614614419565b506001600160a01b037f000000000000000000000000e25df5e33f915ab698e12e62fa2d8e3cacbb859d166001600160a01b03851614614412565b84611458849260016144c060405190565b633f756b1760e01b815294859460048601614395565b61043f906012612093565b613ce36301ffc9a760e01b5b916001600160e01b03191690565b61453361450c61216c836002610e90565b7f0000000000000000000000000000000000000000000000120d4da7b0bd140000906139af565b9061453e600061080a565b9061454d6127a6826008610e90565b93825b61455b61044d875190565b84101561457e576001906145726127d08689611631565b60a01c01930192614550565b9194509203905090614590600061080a565b825b8110156145b0576145a9614592916116e9866156fa565b9050614590565b50915050565b8181106145c1575050565b806145cf6000600193611b71565b016145b6565b9190918282106145e457505050565b61043f92916145f99091600052602060002090565b91820191016145b6565b90600160401b811161094a578161461b61043f935490565b908281556145d5565b600061043f91614603565b906000036109815761043f90614624565b9061464f6127a6836008610e90565b9060009061465c8261080a565b905b61466961044d855190565b82101561473b57906146a29161467f8287615778565b61469186611f86846009989598610817565b61469d8186600a6148af565b840190565b947f000000000000000000000000e25df5e33f915ab698e12e62fa2d8e3cacbb859d935b8681101561471d57806146e187611f47614718946004610817565b6146f181600d6157cd565b6157cd565b806001600160a01b03878116908b16600080516020615b6b8339815191528a80a460010190565b6146c6565b509450915061044d6147326146699260010190565b9291505061465e565b9361043f935061474d91506008610e90565b61462f565b9061477f61216c61478f92614765600090565b506000614778613e4c613e466008613834565b9501610817565b9161478a600061080a565b921690565b141590565b61044d600161080a565b906147ac6114ce8284612425565b6147b4575050565b6114586147c060405190565b63e2517d3f60e01b815292839260048401611a46565b61044d611fc09161043f946147e9600090565b506001600160a01b0390911660a09190911b6001600160a01b03191601926008610e90565b61044d6001600160a01b031961080a565b9092919261483b61044d61483161480e565b61398160a0613834565b8411614877576120039061043f9394614852600090565b506001600160a01b0390911660a09190911b6001600160a01b03191601916009610817565b6114588461488460405190565b631605cc3f60e11b81529182916004830190815260200190565b61044d9061402e61168561044d9490565b916148c36148bd6008613834565b83613841565b80926148cf60ff61080a565b1691610100918184016148e46116858561080a565b101561491e5750613e67613e6e9361491961043f979694614913600095613b6161490d60001990565b9361080a565b9061489e565b613e1c565b959491935061495e9061495790611fd86000199561494e6000614941838a613e1c565b970196613e6e8c89610817565b613b618861080a565b9560010190565b945b6149698461080a565b8111156149945761495761498e91614985856120038a87610817565b611fd88661080a565b94614960565b613e6e926149136149ae92613b6161043f9899959761080a565b92610817565b61044d6149c160036117cc565b6134fd614794565b6149d3600061080a565b907a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000006149f98161080a565b821015614b49575b506d04ee2d6d415b85acef8100000000614a1a8161080a565b821015614b27575b50662386f26fc10000614a348161080a565b821015614b05575b506305f5e100614a4b8161080a565b821015614ae3575b50612710614a608161080a565b821015614ac1575b50614a73606461080a565b811015614a9f575b614a88611685600a61080a565b1015614a915790565b61044d906105b1600161080a565b614ab0614abb91613a2a606461080a565b916105b1600261080a565b90614a7b565b614adc91613a2a614ad19261080a565b916105b1600461080a565b9038614a68565b614afe91613a2a614af39261080a565b916105b1600861080a565b9038614a53565b614b2091613a2a614b159261080a565b916105b1601061080a565b9038614a3c565b614b4291613a2a614b379261080a565b916105b1602061080a565b9038614a22565b614b6491613a2a614b599261080a565b916105b1604061080a565b9038614a01565b61044d91614b789161582b565b909291926158cb565b909392600a93614b918486613e2d565b614bc5828503926008976001600160a01b0390911660a085901b6001600160a01b0319160190611ec790611f61878b610e90565b614bd4600191611fd88361080a565b95868310614be6575b50505050505050565b614c42611fca85611fd893611fc5614c1a614c4898614c6c9d613b61614c126120039e6105b18d61080a565b9e8f90613e2d565b6001600160a01b038c1660a09190911b6001600160a01b03191601611fc061044d8585610e90565b9161080a565b6001600160a01b0390911660a09190911b6001600160a01b03191601916009610817565b38808080808080614bdd565b9190611f6161043f94614c92611ec7946105b1600161080a565b90614c9e82600a613e2d565b614cc66001600160a01b03871660a086901b6001600160a01b03191601612003846009610817565b6001600160a01b0390911660001990910160a01b6001600160a01b03191601936008610e90565b634e487b7160e01b600052603160045260246000fd5b80548015614d26576000190190614d23614d1d8383611e81565b90611b71565b55565b614ced565b9061043f91614d3e61044d826008610e90565b91614d4a611fce845490565b818103614d5a575b505050614d03565b614da492614d6e611f666120039387611e81565b614d7c81611ec78689611e81565b6001600160a01b0391821660a09490941b6001600160a01b0319169390930192166009610817565b388080614d52565b614db7610100611773565b7e01020903110a19042112290b311a3905412245134d2a550c5d32651b6d3a7560208201527f06264262237d468514804e8d2b95569d0d495ea533a966b11c886eb93bc176c960408201527f071727374353637324837e9b47af86c7155181ad4fd18ed32c9096db57d59ee360608201527f0e2e4a6a5f92a6be3498aae067ddb2eb1d5989b56fd7baf33ca0c2ee77e5caf760808201527fff0810182028303840444c545c646c7425617c847f8c949c48a4a8b087b8c0c860a08201527f16365272829aaec650acd0d28fdad4e22d6991bd97dfdcea58b4d6f29fede4f660c08201527ffe0f1f2f3f4b5b6b607b8b93a3a7b7bf357199c5abcfd9e168bcdee9b3f1ecf560e08201527ffd1e3e5a7a8aa2b670c4ced8bbe8f0f4fc3d79a1c3cde7effb78cce6facbf9f861010082015290565b61044d614dac565b61044d614eea565b61044d7e818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff61080a565b61241561044d61044d9260ff1690565b61044d9060f81c614f22565b614f92614f8461044d92614f50600090565b50614f7e614f74614f68614f62614ef2565b9361599b565b614f70614efa565b0290565b61398160f8613834565b90613810565b516001600160f81b03191690565b614f32565b909194614fa2600090565b50614fce7f0000000000000000000000000000000000000000000000120d4da7b0bd14000080966139af565b93600095614fdc600061080a565b86811015615173579786979860089795969790614ffc611fca8984610e90565b918961500d6001946134fd8661080a565b918a6150198482615778565b94909b61502c61168561158d8989611586565b1161510b57615083611fca8585611fc561507e61044d615093986150788f9d9b99615072611f6661509b9f61044d6150679161508c9f610e90565b92611f61868b610e90565b90611ea4565b84610e90565b614d03565b6134fd8661080a565b8d8c61481f565b898101930190565b9789918d915b905b6150b7575b50505050509796959493614fdc565b8b8482101561510557859383600080516020615b6b83398151915284936150e66150fc97611f47876004610817565b6001600160a01b0390811693169180a460010190565b8c908a926150a3565b506150a8565b9250509261511b908d9a939a0390565b98899003908161512c918c856159c1565b019061513982600a613e2d565b896151458982856147d6565b61514e91610e90565b546151588361080a565b61516491038a8361481f565b958601818a9789918d916150a1565b506151bf94965080611685946151a5615193611fd89461158d979c6139af565b611fd8846142b561216c866002610e90565b88106151d0575b50614248816142b561216c8b6002610e90565b116151c75750565b61043f906156fa565b6151de906142ba600161080a565b386151ac565b91906000926151f3600061080a565b925b8284101561535a5760086152098382610e90565b90615233611f6661521d611fca8785610e90565b9361522d600195611fd88761080a565b90611e81565b60018060a01b0381169060a01c87868a61524d84809c0190565b8a106153145761507e61044d61528295949387986152766105b195611f866152889b6009610817565b611fc5878b600a6148af565b96820190565b7f000000000000000000000000e25df5e33f915ab698e12e62fa2d8e3cacbb859d91835b6152ba575b505050506151f5565b8181101561530f57615309816152d386936146ec600d90565b6152e28b611f47836004610817565b806001600160a01b03868116908a16600080516020615b6b8339815191528e80a460010190565b906152ac565b6152b1565b50508703905096879003858282019381858b81019b61533491600a6148af565b61533d91610e90565b546153478661080a565b900390615353936159c1565b8495615288565b9350505050565b9161536c600061080a565b825b8110156145b05761538561536e916116e9866156fa565b905061536c565b9050519061043f826104ac565b9060208282031261042d5761044d9161538c565b6001600160a01b0391821681529116602082015261044d9260808201929091906143c590612ad0565b3d156153f0576153e53d611773565b903d6000602084013e565b606090565b6001600160a01b03909116815261044d93608082019390926143c59190612ad090613bdb565b93919291600092823b6154306116858661080a565b111561557a576001936001968587905b615450575b505050505050505090565b61545d61044d858a611586565b8110156155755761547061298887610e87565b602061547b60405190565b918290630a85bd0160e11b825281878161549b8c898b33600486016153ad565b03925af160009181615545575b506155155750866154c1578691906001015b9091615440565b50508594506154ce6153d6565b906154e36116856154dd845190565b9261080a565b0361550d575090611458916154f760405190565b633f756b1760e01b8152948594600486016153f5565b805190602001fd5b896154ba918994939b9161552c575b509960010190565b905061553e630a85bd0160e11b6144ed565b1438615524565b61556791925060203d811161556e575b61555f8183610929565b810190615399565b90386154a8565b503d615555565b615445565b505050505050600190565b91816155c461559383613d9e565b6155a66000611f47886004979697610817565b856155ba611f6684611f6160089889610e90565b60a01c9289613dcc565b6155d2612440836007610e90565b1561569a5750506155e581611f96600a90565b6155f081600d6157cd565b6001600160a01b037f000000000000000000000000e25df5e33f915ab698e12e62fa2d8e3cacbb859d8116908416600080516020615b6b833981519152600080a45b7f0000000000000000000000000000000000000000000000120d4da7b0bd140000615661614183846002610e90565b61566f61344b836002610e90565b60009081526001600160a01b039182169290911690600080516020615b6b83398151915290602090a3565b6156d491611fdd916156ca91611fca91611fc56001600160a01b038816600160a01b01611fc061044d8585610e90565b6134fd600161080a565b6001600160a01b03828116908416600080516020615b6b833981519152600080a4615632565b615704600d615a41565b9061573561572e615715600161080a565b6157208185876147d6565b613b61611fca856008610e90565b828461481f565b6001600160a01b03908116907f000000000000000000000000e25df5e33f915ab698e12e62fa2d8e3cacbb859d16600080516020615b6b833981519152600080a4565b61579391611f61611f669261578b600090565b506008610e90565b6001600160a01b0381169160a09190911c90565b906001600160801b03906115f8565b906157c661044d61161792613d21565b82546157a7565b806157e46157da82613d0a565b6143796001613d14565b916157f1613cfe83613ee8565b6001600160801b038416146158195761043f936120038460016158149401613d37565b6157b6565b604051638acb5f2760e01b8152600490fd5b90600091615837825190565b615844611685604161080a565b0361586e5761586792506020820151906060604084015193015160001a90615aac565b9192909190565b50905061588b6158866158816000611393565b925190565b61080a565b909160029190565b634e487b7160e01b600052602160045260246000fd5b600411156158b357565b615893565b9061043f826158a9565b61044d9061080a565b6158d560006158b8565b6158de826158b8565b036158e7575050565b6158f160016158b8565b6158fa826158b8565b036159115760405163f645eedf60e01b8152600490fd5b61591b60026158b8565b615924826158b8565b0361595257611458615935836158c2565b60405163fce698f760e01b81529182916004830190815260200190565b61596561595f60036158b8565b916158b8565b1461596d5750565b6114589061597a60405190565b6335e2f38360e21b81529182916004830190815260200190565b1561042d57565b6159af6159a8600061080a565b8211615994565b6159bd81613b61600061080a565b1690565b91611f61611ec7929361043f956159d6600090565b506001600160a01b0390911660a09190911b6001600160a01b03191601936008610e90565b600161044d91036001600160801b031690565b906fffffffffffffffffffffffffffffffff199060801b6115f8565b90615a3a61044d61161792613d21565b8254615a0e565b9081615a4c81613ee8565b90615a59613cfe85613d0a565b6001600160801b03831614615a9a576001615a7661043f936159fb565b910193615a956000611f8684615a8f61216c828b613d37565b98613d37565b615a2a565b6040516375e52f4f60e01b8152600490fd5b9091615ab7846158c2565b615ae36116857f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a061080a565b11615b565790615afc60209460009493612c3860405190565b838052039060015afa1561142457600051600091615b1983611393565b6001600160a01b0381166001600160a01b03841614615b425750615b3c8361080a565b91929190565b915091615b4e9061080a565b909160019190565b505050615b636000611393565b916003919056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212202701fb4ac6bfe60b7631cc1bea381b78d9c385162634a0e7a45801e33efeef5464736f6c63430008190033
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.