Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
11173229 | 419 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
FxGenArt721
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 2 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {ECDSA} from "openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import {EIP712} from "openzeppelin/contracts/utils/cryptography/EIP712.sol"; import {ERC721} from "openzeppelin/contracts/token/ERC721/ERC721.sol"; import {Initializable} from "openzeppelin-upgradeable/contracts/proxy/utils/Initializable.sol"; import {LibString} from "solady/src/utils/LibString.sol"; import {Ownable} from "solady/src/auth/Ownable.sol"; import {Pausable} from "openzeppelin/contracts/security/Pausable.sol"; import {RoyaltyManager} from "src/tokens/extensions/RoyaltyManager.sol"; import {SSTORE2} from "sstore2/contracts/SSTORE2.sol"; import {IAccessControl} from "openzeppelin/contracts/access/IAccessControl.sol"; import {IERC4906} from "openzeppelin/contracts/interfaces/IERC4906.sol"; import {IFxContractRegistry} from "src/interfaces/IFxContractRegistry.sol"; import {IFxGenArt721, GenArtInfo, InitInfo, IssuerInfo, MetadataInfo, MintInfo, ProjectInfo, ReserveInfo} from "src/interfaces/IFxGenArt721.sol"; import {IMinter} from "src/interfaces/IMinter.sol"; import {IRandomizer} from "src/interfaces/IRandomizer.sol"; import {IRenderer} from "src/interfaces/IRenderer.sol"; import "src/utils/Constants.sol"; /** * @title FxGenArt721 * @author fx(hash) * @notice See the documentation in {IFxGenArt721} */ contract FxGenArt721 is IFxGenArt721, IERC4906, ERC721, EIP712, Initializable, Ownable, Pausable, RoyaltyManager { /*////////////////////////////////////////////////////////////////////////// STORAGE //////////////////////////////////////////////////////////////////////////*/ /** * @inheritdoc IFxGenArt721 */ address public immutable contractRegistry; /** * @inheritdoc IFxGenArt721 */ address public immutable roleRegistry; /** * @dev Packed value of name and symbol where combined length is 30 bytes or less */ bytes32 internal nameAndSymbol_; /** * @dev Project name */ string internal name_; /** * @dev Project symbol */ string internal symbol_; /** * @inheritdoc IFxGenArt721 */ uint96 public totalSupply; /** * @inheritdoc IFxGenArt721 */ address public randomizer; /** * @inheritdoc IFxGenArt721 */ address public renderer; /** * @inheritdoc IFxGenArt721 */ uint96 public nonce; /** * @inheritdoc IFxGenArt721 */ IssuerInfo public issuerInfo; /** * @inheritdoc IFxGenArt721 */ MetadataInfo public metadataInfo; /** * @inheritdoc IFxGenArt721 */ mapping(uint256 => GenArtInfo) public genArtInfo; /*////////////////////////////////////////////////////////////////////////// MODIFIERS //////////////////////////////////////////////////////////////////////////*/ /** * @dev Modifier for restricting calls to only registered minters */ modifier onlyMinter() { if (!isMinter(msg.sender)) revert UnregisteredMinter(); _; } /** * @dev Modifier for restricting calls to only authorized accounts with given role */ modifier onlyRole(bytes32 _role) { if (!IAccessControl(roleRegistry).hasRole(_role, msg.sender)) revert UnauthorizedAccount(); _; } /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ /** * @dev Initializes FxContractRegistry and FxRoleRegistry */ constructor( address _contractRegistry, address _roleRegistry ) ERC721("FxGenArt721", "FXHASH") EIP712("FxGenArt721", "1") { contractRegistry = _contractRegistry; roleRegistry = _roleRegistry; } /*////////////////////////////////////////////////////////////////////////// INITIALIZER //////////////////////////////////////////////////////////////////////////*/ /** * @inheritdoc IFxGenArt721 */ function initialize( address _owner, InitInfo calldata _initInfo, ProjectInfo memory _projectInfo, MetadataInfo calldata _metadataInfo, MintInfo[] calldata _mintInfo, address[] calldata _royaltyReceivers, uint32[] calldata _allocations, uint96 _basisPoints ) external initializer { (, , , uint32 lockTime, , , ) = IFxContractRegistry(contractRegistry).configInfo(); _projectInfo.earliestStartTime = (_isVerified(_owner)) ? uint32(block.timestamp) : uint32(block.timestamp) + lockTime; if (_projectInfo.earliestStartTime < LAUNCH_TIMESTAMP) _pause(); issuerInfo.projectInfo = _projectInfo; metadataInfo = _metadataInfo; randomizer = _initInfo.randomizer; renderer = _initInfo.renderer; _initializeOwner(_owner); _registerMinters(_mintInfo); _setPrimaryReceiver(_initInfo.primaryReceivers, _initInfo.allocations); _setBaseRoyalties(_royaltyReceivers, _allocations, _basisPoints); _setNameAndSymbol(_initInfo.name, _initInfo.symbol); _setTags(_initInfo.tagIds); if (_initInfo.onchainData.length > 0) _setOnchainPointer(_initInfo.onchainData); emit ProjectInitialized(issuerInfo.primaryReceiver, _projectInfo, _metadataInfo, _mintInfo); } /*////////////////////////////////////////////////////////////////////////// EXTERNAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @inheritdoc IFxGenArt721 */ function burn(uint256 _tokenId) external whenNotPaused { if (!issuerInfo.projectInfo.burnEnabled) revert BurnInactive(); if (!_isApprovedOrOwner(msg.sender, _tokenId)) revert NotAuthorized(); _burn(_tokenId); --totalSupply; } /** * @inheritdoc IFxGenArt721 */ function fulfillSeedRequest(uint256 _tokenId, bytes32 _seed) external { if (msg.sender != randomizer) revert NotAuthorized(); genArtInfo[_tokenId].seed = _seed; emit SeedFulfilled(randomizer, _tokenId, _seed); } /** * @inheritdoc IFxGenArt721 */ function mint(address _to, uint256 _amount, uint256 /* _payment */) external onlyMinter whenNotPaused { if (!issuerInfo.projectInfo.mintEnabled) revert MintInactive(); uint96 currentId = totalSupply; for (uint256 i; i < _amount; ++i) { _mintRandom(_to, ++currentId); } totalSupply = currentId; } /** * @inheritdoc IFxGenArt721 */ function mintParams(address _to, bytes calldata _fxParams) external onlyMinter whenNotPaused { if (!issuerInfo.projectInfo.mintEnabled) revert MintInactive(); _mintParams(_to, ++totalSupply, _fxParams); } /*////////////////////////////////////////////////////////////////////////// OWNER FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @inheritdoc IFxGenArt721 */ function ownerMint(address _to) external onlyOwner whenNotPaused { _mintRandom(_to, ++totalSupply); } /** * @inheritdoc IFxGenArt721 */ function ownerMintParams(address _to, bytes calldata _fxParams) external onlyOwner whenNotPaused { _mintParams(_to, ++totalSupply, _fxParams); } /** * @inheritdoc IFxGenArt721 */ function reduceSupply(uint120 _supply) external onlyOwner { uint120 prevSupply = issuerInfo.projectInfo.maxSupply; if (_supply >= prevSupply || _supply < totalSupply) revert InvalidAmount(); issuerInfo.projectInfo.maxSupply = _supply; if (_supply == 0) emit ProjectDeleted(); emit SupplyReduced(prevSupply, _supply); } /** * @inheritdoc IFxGenArt721 */ function registerMinters(MintInfo[] memory _mintInfo) external onlyOwner { if (issuerInfo.projectInfo.mintEnabled) revert MintActive(); uint256 length = issuerInfo.activeMinters.length; for (uint256 i; i < length; ++i) { address minter = issuerInfo.activeMinters[i]; issuerInfo.minters[minter] = FALSE; } delete issuerInfo.activeMinters; _registerMinters(_mintInfo); } /** * @inheritdoc IFxGenArt721 */ function setBaseRoyalties( address[] calldata _receivers, uint32[] calldata _allocations, uint96 _basisPoints ) external onlyOwner { _setBaseRoyalties(_receivers, _allocations, _basisPoints); } /** * @inheritdoc IFxGenArt721 */ function setBurnEnabled(bool _flag) external onlyOwner { if (remainingSupply() != 0) revert SupplyRemaining(); issuerInfo.projectInfo.burnEnabled = _flag; emit BurnEnabled(_flag); } /** * @inheritdoc IFxGenArt721 */ function setMintEnabled(bool _flag) external onlyOwner { issuerInfo.projectInfo.mintEnabled = _flag; emit MintEnabled(_flag); } /** * @inheritdoc IFxGenArt721 */ function setOnchainPointer(bytes calldata _onchainData, bytes calldata _signature) external onlyOwner { bytes32 digest = generateOnchainPointerHash(_onchainData); _verifySignature(digest, _signature); _setOnchainPointer(_onchainData); } /** * @inheritdoc IFxGenArt721 */ function setPrimaryReceivers(address[] calldata _receivers, uint32[] calldata _allocations) external onlyOwner { _setPrimaryReceiver(_receivers, _allocations); } /** * @inheritdoc IFxGenArt721 */ function setRenderer(address _renderer, bytes calldata _signature) external onlyOwner { bytes32 digest = generateRendererHash(_renderer); _verifySignature(digest, _signature); renderer = _renderer; emit RendererUpdated(_renderer); emit BatchMetadataUpdate(1, totalSupply); } /*////////////////////////////////////////////////////////////////////////// ADMIN FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @inheritdoc IFxGenArt721 */ function setRandomizer(address _randomizer) external onlyRole(ADMIN_ROLE) { randomizer = _randomizer; emit RandomizerUpdated(_randomizer); } /*////////////////////////////////////////////////////////////////////////// METADATA FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @inheritdoc IFxGenArt721 */ function setBaseURI(bytes calldata _uri) external onlyRole(METADATA_ROLE) { metadataInfo.baseURI = _uri; emit BaseURIUpdated(_uri); emit BatchMetadataUpdate(1, totalSupply); } /*////////////////////////////////////////////////////////////////////////// MODERATOR FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @inheritdoc IFxGenArt721 */ function pause() external onlyRole(MODERATOR_ROLE) { _pause(); } /** * @inheritdoc IFxGenArt721 */ function setTags(uint256[] calldata _tagIds) external onlyRole(MODERATOR_ROLE) { _setTags(_tagIds); } /** * @inheritdoc IFxGenArt721 */ function unpause() external onlyRole(MODERATOR_ROLE) { _unpause(); } /*////////////////////////////////////////////////////////////////////////// READ FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @inheritdoc IFxGenArt721 */ function activeMinters() external view returns (address[] memory) { return issuerInfo.activeMinters; } /** * @inheritdoc IFxGenArt721 */ function contractURI() external view returns (string memory) { return IRenderer(renderer).contractURI(); } /** * @inheritdoc IFxGenArt721 */ function primaryReceiver() external view returns (address) { return issuerInfo.primaryReceiver; } /** * @inheritdoc IFxGenArt721 */ function generateOnchainPointerHash(bytes calldata _data) public view returns (bytes32) { bytes32 structHash = keccak256(abi.encode(SET_ONCHAIN_POINTER_TYPEHASH, _data, nonce)); return _hashTypedDataV4(structHash); } /** * @inheritdoc IFxGenArt721 */ function generateRendererHash(address _renderer) public view returns (bytes32) { bytes32 structHash = keccak256(abi.encode(SET_RENDERER_TYPEHASH, _renderer, nonce)); return _hashTypedDataV4(structHash); } /** * @inheritdoc IFxGenArt721 */ function isMinter(address _minter) public view returns (bool) { return issuerInfo.minters[_minter] == TRUE; } /** * @inheritdoc IFxGenArt721 */ function remainingSupply() public view returns (uint256) { return issuerInfo.projectInfo.maxSupply - totalSupply; } /** * @inheritdoc ERC721 */ function name() public view override returns (string memory) { (string memory packedName, ) = LibString.unpackTwo(nameAndSymbol_); return (nameAndSymbol_ == bytes32(0)) ? name_ : packedName; } /** * @inheritdoc ERC721 */ function symbol() public view override returns (string memory) { (, string memory packedSymbol) = LibString.unpackTwo(nameAndSymbol_); return (nameAndSymbol_ == bytes32(0)) ? symbol_ : packedSymbol; } /** * @inheritdoc ERC721 */ function tokenURI(uint256 _tokenId) public view override returns (string memory) { _requireMinted(_tokenId); bytes memory data = abi.encode( metadataInfo.baseURI, metadataInfo.onchainPointer, genArtInfo[_tokenId].minter, genArtInfo[_tokenId].seed, genArtInfo[_tokenId].fxParams ); return IRenderer(renderer).tokenURI(_tokenId, data); } /*////////////////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @dev Mints single token to given account using fxParams as input */ function _mintParams(address _to, uint256 _tokenId, bytes calldata _fxParams) internal { if (remainingSupply() == 0) revert InsufficientSupply(); if (issuerInfo.projectInfo.inputSize < _fxParams.length) revert InvalidInputSize(); _mint(_to, _tokenId); genArtInfo[_tokenId].minter = _to; genArtInfo[_tokenId].fxParams = _fxParams; IRandomizer(randomizer).requestRandomness(_tokenId); } /** * @dev Mints single token to given account using randomly generated seed as input */ function _mintRandom(address _to, uint256 _tokenId) internal { if (remainingSupply() == 0) revert InsufficientSupply(); _mint(_to, _tokenId); genArtInfo[_tokenId].minter = _to; IRandomizer(randomizer).requestRandomness(_tokenId); } /** * @dev Registers arbitrary number of minter contracts and sets their reserves */ function _registerMinters(MintInfo[] memory _mintInfo) internal { address minter; uint64 startTime; uint128 totalAllocation; ReserveInfo memory reserveInfo; uint32 earliestStartTime = issuerInfo.projectInfo.earliestStartTime; uint120 maxSupply = issuerInfo.projectInfo.maxSupply; for (uint256 i; i < _mintInfo.length; ++i) { minter = _mintInfo[i].minter; reserveInfo = _mintInfo[i].reserveInfo; startTime = reserveInfo.startTime; if (!IAccessControl(roleRegistry).hasRole(MINTER_ROLE, minter)) revert UnauthorizedMinter(); if (startTime == 0) { reserveInfo.startTime = (block.timestamp > earliestStartTime) ? uint64(block.timestamp) : earliestStartTime; } else if (startTime < earliestStartTime) { revert InvalidStartTime(); } if (reserveInfo.endTime < startTime) revert InvalidEndTime(); if (maxSupply != OPEN_EDITION_SUPPLY) totalAllocation += reserveInfo.allocation; issuerInfo.minters[minter] = TRUE; issuerInfo.activeMinters.push(minter); IMinter(minter).setMintDetails(reserveInfo, _mintInfo[i].params); } if (maxSupply != OPEN_EDITION_SUPPLY) { if (totalAllocation > remainingSupply()) revert AllocationExceeded(); } } /** * @dev Sets receivers and allocations for base royalties of token sales */ function _setBaseRoyalties( address[] calldata _receivers, uint32[] calldata _allocations, uint96 _basisPoints ) internal override { (address feeReceiver, , uint32 secondaryFeeAllocation, , , , ) = IFxContractRegistry(contractRegistry) .configInfo(); _checkFeeReceiver(_receivers, _allocations, feeReceiver, secondaryFeeAllocation); super._setBaseRoyalties(_receivers, _allocations, _basisPoints); } /** * @dev Sets primary receiver address for token sales */ function _setPrimaryReceiver(address[] calldata _receivers, uint32[] calldata _allocations) internal { (address feeReceiver, uint32 primaryFeeAllocation, , , , , ) = IFxContractRegistry(contractRegistry) .configInfo(); _checkFeeReceiver(_receivers, _allocations, feeReceiver, primaryFeeAllocation); address receiver = _getOrCreateSplit(_receivers, _allocations); issuerInfo.primaryReceiver = receiver; emit PrimaryReceiverUpdated(receiver, _receivers, _allocations); } /** * @dev Packs name and symbol into single slot if combined length is 30 bytes or less */ function _setNameAndSymbol(string calldata _name, string calldata _symbol) internal { bytes32 packed = LibString.packTwo(_name, _symbol); if (packed == bytes32(0)) { name_ = _name; symbol_ = _symbol; } else { nameAndSymbol_ = packed; } } /** * @dev Sets the onchain pointer for reconstructing metadata onchain */ function _setOnchainPointer(bytes calldata _onchainData) internal { address onchainPointer = SSTORE2.write(_onchainData); metadataInfo.onchainPointer = onchainPointer; emit OnchainPointerUpdated(onchainPointer); } /** * @dev Emits event for setting the project tag descriptions */ function _setTags(uint256[] calldata _tagIds) internal { emit ProjectTags(_tagIds); } /** * @dev Verifies that a signature was generated for the computed digest */ function _verifySignature(bytes32 _digest, bytes calldata _signature) internal { address signer = ECDSA.recover(_digest, _signature); if (!IAccessControl(roleRegistry).hasRole(SIGNER_ROLE, signer)) revert UnauthorizedAccount(); nonce++; } /** * @dev Checks if creator is verified by the system */ function _isVerified(address _creator) internal view returns (bool) { return (IAccessControl(roleRegistry).hasRole(CREATOR_ROLE, _creator)); } /** * @dev Checks if fee receiver and allocation amount are included in their respective arrays */ function _checkFeeReceiver( address[] calldata _receivers, uint32[] calldata _allocations, address _feeReceiver, uint32 _feeAllocation ) internal pure { bool feeReceiverExists; for (uint256 i; i < _allocations.length; i++) { if (_receivers[i] == _feeReceiver && _allocations[i] == _feeAllocation) feeReceiverExists = true; } if (!feeReceiverExists) revert InvalidFeeReceiver(); } /** * @inheritdoc ERC721 */ function _exists(uint256 _tokenId) internal view override(ERC721, RoyaltyManager) returns (bool) { return super._exists(_tokenId); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @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, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode 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 {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] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { 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); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode 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 {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); 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] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); 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. * * _Available since v4.2._ */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { // 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); } // 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); } return (signer, RecoverError.NoError); } /** * @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) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.8; import "./ECDSA.sol"; import "../ShortStrings.sol"; import "../../interfaces/IERC5267.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. * * _Available since v3.4._ * * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment */ abstract contract EIP712 is IERC5267 { using ShortStrings for *; bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _cachedDomainSeparator; uint256 private immutable _cachedChainId; address private immutable _cachedThis; bytes32 private immutable _hashedName; bytes32 private immutable _hashedVersion; ShortString private immutable _name; ShortString private immutable _version; string private _nameFallback; string private _versionFallback; /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { _name = name.toShortStringWithFallback(_nameFallback); _version = version.toShortStringWithFallback(_versionFallback); _hashedName = keccak256(bytes(name)); _hashedVersion = keccak256(bytes(version)); _cachedChainId = block.chainid; _cachedDomainSeparator = _buildDomainSeparator(); _cachedThis = address(this); } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { if (address(this) == _cachedThis && block.chainid == _cachedChainId) { return _cachedDomainSeparator; } else { return _buildDomainSeparator(); } } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev See {EIP-5267}. * * _Available since v4.9._ */ function eip712Domain() public view virtual override returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { return ( hex"0f", // 01111 _name.toStringWithFallback(_nameFallback), _version.toStringWithFallback(_versionFallback), block.chainid, address(this), bytes32(0), new uint256[](0) ); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/ERC721.sol) pragma solidity ^0.8.0; import "./IERC721.sol"; import "./IERC721Receiver.sol"; import "./extensions/IERC721Metadata.sol"; import "../../utils/Address.sol"; import "../../utils/Context.sol"; import "../../utils/Strings.sol"; import "../../utils/introspection/ERC165.sol"; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including * the Metadata extension, but not including the Enumerable extension, which is available separately as * {ERC721Enumerable}. */ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { using Address for address; using Strings for uint256; // Token name string private _name; // Token symbol string private _symbol; // Mapping from token ID to owner address mapping(uint256 => address) private _owners; // Mapping owner address to token count mapping(address => uint256) private _balances; // Mapping from token ID to approved address mapping(uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; /** * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), "ERC721: address zero is not a valid owner"); return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { address owner = _ownerOf(tokenId); require(owner != address(0), "ERC721: invalid token ID"); return owner; } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireMinted(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ""; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721.ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require( _msgSender() == owner || isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not token owner or approved for all" ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { _requireMinted(tokenId); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom(address from, address to, uint256 tokenId) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); _safeTransfer(from, to, tokenId, data); } /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * `data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual { _transfer(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist */ function _ownerOf(uint256 tokenId) internal view virtual returns (address) { return _owners[tokenId]; } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted (`_mint`), * and stop existing when they are burned (`_burn`). */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _ownerOf(tokenId) != address(0); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { address owner = ERC721.ownerOf(tokenId); return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: * * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual { _mint(to, tokenId); require( _checkOnERC721Received(address(0), to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer" ); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(address(0), to, tokenId, 1); // Check that tokenId was not minted by `_beforeTokenTransfer` hook require(!_exists(tokenId), "ERC721: token already minted"); unchecked { // Will not overflow unless all 2**256 token ids are minted to the same owner. // Given that tokens are minted one by one, it is impossible in practice that // this ever happens. Might change if we allow batch minting. // The ERC fails to describe this case. _balances[to] += 1; } _owners[tokenId] = to; emit Transfer(address(0), to, tokenId); _afterTokenTransfer(address(0), to, tokenId, 1); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * This is an internal function that does not check if the sender is authorized to operate on the token. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal virtual { address owner = ERC721.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId, 1); // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook owner = ERC721.ownerOf(tokenId); // Clear approvals delete _tokenApprovals[tokenId]; unchecked { // Cannot overflow, as that would require more tokens to be burned/transferred // out than the owner initially received through minting and transferring in. _balances[owner] -= 1; } delete _owners[tokenId]; emit Transfer(owner, address(0), tokenId); _afterTokenTransfer(owner, address(0), tokenId, 1); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer(address from, address to, uint256 tokenId) internal virtual { require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId, 1); // Check that tokenId was not transferred by `_beforeTokenTransfer` hook require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); // Clear approvals from the previous owner delete _tokenApprovals[tokenId]; unchecked { // `_balances[from]` cannot overflow for the same reason as described in `_burn`: // `from`'s balance is the number of token held, which is at least one before the current // transfer. // `_balances[to]` could overflow in the conditions described in `_mint`. That would require // all 2**256 token ids to be minted, which in practice is impossible. _balances[from] -= 1; _balances[to] += 1; } _owners[tokenId] = to; emit Transfer(from, to, tokenId); _afterTokenTransfer(from, to, tokenId, 1); } /** * @dev Approve `to` to operate on `tokenId` * * Emits an {Approval} event. */ function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721.ownerOf(tokenId), to, tokenId); } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Emits an {ApprovalForAll} event. */ function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { require(owner != operator, "ERC721: approve to caller"); _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Reverts if the `tokenId` has not been minted yet. */ function _requireMinted(uint256 tokenId) internal view virtual { require(_exists(tokenId), "ERC721: invalid token ID"); } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory data ) private returns (bool) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { return retval == IERC721Receiver.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("ERC721: transfer to non ERC721Receiver implementer"); } else { /// @solidity memory-safe-assembly assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } /** * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`. * - When `from` is zero, the tokens will be minted for `to`. * - When `to` is zero, ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * - `batchSize` is non-zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {} /** * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`. * - When `from` is zero, the tokens were minted for `to`. * - When `to` is zero, ``from``'s tokens were burned. * - `from` and `to` are never both zero. * - `batchSize` is non-zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {} /** * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override. * * WARNING: Anyone calling this MUST ensure that the balances remain consistent with the ownership. The invariant * being that for any address `a` the value returned by `balanceOf(a)` must be equal to the number of tokens such * that `ownerOf(tokenId)` is `a`. */ // solhint-disable-next-line func-name-mixedcase function __unsafe_increaseBalance(address account, uint256 amount) internal { _balances[account] += amount; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for converting numbers into strings and other string operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `length` of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = type(uint256).max; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the base 10 decimal representation of `value`. function toString(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. str := add(mload(0x40), 0x80) // Update the free memory pointer to allocate. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end of the memory to calculate the length later. let end := str let w := not(0) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 1)`. // Write the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(str, add(48, mod(temp, 10))) // Keep dividing `temp` until zero. temp := div(temp, 10) if iszero(temp) { break } } let length := sub(end, str) // Move the pointer 32 bytes leftwards to make room for the length. str := sub(str, 0x20) // Store the length. mstore(str, length) } } /// @dev Returns the base 10 decimal representation of `value`. function toString(int256 value) internal pure returns (string memory str) { if (value >= 0) { return toString(uint256(value)); } unchecked { str = toString(uint256(-value)); } /// @solidity memory-safe-assembly assembly { // We still have some spare memory space on the left, // as we have allocated 3 words (96 bytes) for up to 78 digits. let length := mload(str) // Load the string length. mstore(str, 0x2d) // Store the '-' character. str := sub(str, 1) // Move back the string pointer by a byte. mstore(str, add(length, 1)) // Update the string length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HEXADECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2 + 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) { str = toHexStringNoPrefix(value, length); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexStringNoPrefix(uint256 value, uint256 length) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. // We add 0x20 to the total and round down to a multiple of 0x20. // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f))) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let start := sub(str, add(length, length)) let w := not(1) // Tsk. let temp := value // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for {} 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(xor(str, start)) { break } } if temp { // Store the function selector of `HexLengthInsufficient()`. mstore(0x00, 0x2194895a) // Revert with (offset, size). revert(0x1c, 0x04) } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2 + 2` bytes. function toHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x". /// The output excludes leading "0" from the `toHexString` output. /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. function toMinimalHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := add(mload(str), 2) // Compute the length. mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero. str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output excludes leading "0" from the `toHexStringNoPrefix` output. /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := mload(str) // Get the length. str := add(str, o) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2` bytes. function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x40 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. str := add(mload(0x40), 0x80) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let w := not(1) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(temp) { break } } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksummed(address value) internal pure returns (string memory str) { str = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(str, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 {} { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { str := mload(0x40) // Allocate the memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(str, 0x80)) // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) str := add(str, 2) mstore(str, 40) let o := add(str, 0x20) mstore(add(o, 40), 0) value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 {} { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory str) { str = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { let length := mload(raw) str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(str, add(length, length)) // Store the length of the output. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let o := add(str, 0x20) let end := add(raw, length) for {} iszero(eq(raw, end)) {} { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RUNE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of UTF characters in the string. function runeCount(string memory s) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { mstore(0x00, div(not(0), 255)) mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) let o := add(s, 0x20) let end := add(o, mload(s)) for { result := 1 } 1 { result := add(result, 1) } { o := add(o, byte(0, mload(shr(250, mload(o))))) if iszero(lt(o, end)) { break } } } } } /// @dev Returns if this string is a 7-bit ASCII string. /// (i.e. all characters codes are in [0..127]) function is7BitASCII(string memory s) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let mask := shl(7, div(not(0), 255)) result := 1 let n := mload(s) if n { let o := add(s, 0x20) let end := add(o, n) let last := mload(end) mstore(end, 0) for {} 1 {} { if and(mask, mload(o)) { result := 0 break } o := add(o, 0x20) if iszero(lt(o, end)) { break } } mstore(end, last) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, all indices of the following operations // are byte (ASCII) offsets, not UTF character offsets. /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`. function replace(string memory subject, string memory search, string memory replacement) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) let replacementLength := mload(replacement) subject := add(subject, 0x20) search := add(search, 0x20) replacement := add(replacement, 0x20) result := add(mload(0x40), 0x20) let subjectEnd := add(subject, subjectLength) if iszero(gt(searchLength, subjectLength)) { let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Copy the `replacement` one word at a time. for { let o := 0 } 1 {} { mstore(add(result, o), mload(add(replacement, o))) o := add(o, 0x20) if iszero(lt(o, replacementLength)) { break } } result := add(result, replacementLength) subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } } let resultRemainder := result result := add(mload(0x40), 0x20) let k := add(sub(resultRemainder, result), sub(subjectEnd, subject)) // Copy the rest of the string one word at a time. for {} lt(subject, subjectEnd) {} { mstore(resultRemainder, mload(subject)) resultRemainder := add(resultRemainder, 0x20) subject := add(subject, 0x20) } result := sub(result, 0x20) let last := add(add(result, 0x20), k) // Zeroize the slot after the string. mstore(last, 0) mstore(0x40, add(last, 0x20)) // Allocate the memory. mstore(result, k) // Store the length. } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for { let subjectLength := mload(subject) } 1 {} { if iszero(mload(search)) { if iszero(gt(from, subjectLength)) { result := from break } result := subjectLength break } let searchLength := mload(search) let subjectStart := add(subject, 0x20) result := not(0) // Initialize to `NOT_FOUND`. subject := add(subjectStart, from) let end := add(sub(add(subjectStart, subjectLength), searchLength), 1) let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(add(search, 0x20)) if iszero(and(lt(subject, end), lt(from, subjectLength))) { break } if iszero(lt(searchLength, 0x20)) { for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if iszero(shr(m, xor(mload(subject), s))) { if eq(keccak256(subject, searchLength), h) { result := sub(subject, subjectStart) break } } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } for {} 1 {} { if iszero(shr(m, xor(mload(subject), s))) { result := sub(subject, subjectStart) break } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = indexOf(subject, search, 0); } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { result := not(0) // Initialize to `NOT_FOUND`. let searchLength := mload(search) if gt(searchLength, mload(subject)) { break } let w := result let fromMax := sub(mload(subject), searchLength) if iszero(gt(fromMax, from)) { from := fromMax } let end := add(add(subject, 0x20), w) subject := add(add(subject, 0x20), from) if iszero(gt(subject, end)) { break } // As this function is not too often used, // we shall simply use keccak256 for smaller bytecode size. for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if eq(keccak256(subject, searchLength), h) { result := sub(subject, add(end, 1)) break } subject := add(subject, w) // `sub(subject, 1)`. if iszero(gt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = lastIndexOf(subject, search, uint256(int256(-1))); } /// @dev Returns whether `subject` starts with `search`. function startsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( iszero(gt(searchLength, mload(subject))), eq( keccak256(add(subject, 0x20), searchLength), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns whether `subject` ends with `search`. function endsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) let subjectLength := mload(subject) // Whether `search` is not longer than `subject`. let withinRange := iszero(gt(searchLength, subjectLength)) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( withinRange, eq( keccak256( // `subject + 0x20 + max(subjectLength - searchLength, 0)`. add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))), searchLength ), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns `subject` repeated `times`. function repeat(string memory subject, uint256 times) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(or(iszero(times), iszero(subjectLength))) { subject := add(subject, 0x20) result := mload(0x40) let output := add(result, 0x20) for {} 1 {} { // Copy the `subject` one word at a time. for { let o := 0 } 1 {} { mstore(add(output, o), mload(add(subject, o))) o := add(o, 0x20) if iszero(lt(o, subjectLength)) { break } } output := add(output, subjectLength) times := sub(times, 1) if iszero(times) { break } } mstore(output, 0) // Zeroize the slot after the string. let resultLength := sub(output, add(result, 0x20)) mstore(result, resultLength) // Store the length. // Allocate the memory. mstore(0x40, add(result, add(resultLength, 0x20))) } } } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(gt(subjectLength, end)) { end := subjectLength } if iszero(gt(subjectLength, start)) { start := subjectLength } if lt(start, end) { result := mload(0x40) let resultLength := sub(end, start) mstore(result, resultLength) subject := add(subject, start) let w := not(0x1f) // Copy the `subject` one word at a time, backwards. for { let o := and(add(resultLength, 0x1f), w) } 1 {} { mstore(add(result, o), mload(add(subject, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(result, 0x20), resultLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(result, and(add(resultLength, 0x3f), w))) } } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. /// `start` is a byte offset. function slice(string memory subject, uint256 start) internal pure returns (string memory result) { result = slice(subject, start, uint256(int256(-1))); } /// @dev Returns all the indices of `search` in `subject`. /// The indices are byte offsets. function indicesOf(string memory subject, string memory search) internal pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) if iszero(gt(searchLength, subjectLength)) { subject := add(subject, 0x20) search := add(search, 0x20) result := add(mload(0x40), 0x20) let subjectStart := subject let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Append to `result`. mstore(result, sub(subject, subjectStart)) result := add(result, 0x20) // Advance `subject` by `searchLength`. subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } let resultEnd := result // Assign `result` to the free memory pointer. result := mload(0x40) // Store the length of `result`. mstore(result, shr(5, sub(resultEnd, add(result, 0x20)))) // Allocate memory for result. // We allocate one more word, so this array can be recycled for {split}. mstore(0x40, add(resultEnd, 0x20)) } } } /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string. function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) { uint256[] memory indices = indicesOf(subject, delimiter); /// @solidity memory-safe-assembly assembly { let w := not(0x1f) let indexPtr := add(indices, 0x20) let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) mstore(add(indicesEnd, w), mload(subject)) mstore(indices, add(mload(indices), 1)) let prevIndex := 0 for {} 1 {} { let index := mload(indexPtr) mstore(indexPtr, 0x60) if iszero(eq(index, prevIndex)) { let element := mload(0x40) let elementLength := sub(index, prevIndex) mstore(element, elementLength) // Copy the `subject` one word at a time, backwards. for { let o := and(add(elementLength, 0x1f), w) } 1 {} { mstore(add(element, o), mload(add(add(subject, prevIndex), o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(element, 0x20), elementLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(element, and(add(elementLength, 0x3f), w))) // Store the `element` into the array. mstore(indexPtr, element) } prevIndex := add(index, mload(delimiter)) indexPtr := add(indexPtr, 0x20) if iszero(lt(indexPtr, indicesEnd)) { break } } result := indices if iszero(mload(delimiter)) { result := add(indices, 0x20) mstore(result, sub(mload(indices), 2)) } } } /// @dev Returns a concatenated string of `a` and `b`. /// Cheaper than `string.concat()` and does not de-align the free memory pointer. function concat(string memory a, string memory b) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let w := not(0x1f) result := mload(0x40) let aLength := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(aLength, 0x20), w) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let bLength := mload(b) let output := add(result, aLength) // Copy `b` one word at a time, backwards. for { let o := and(add(bLength, 0x20), w) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let totalLength := add(aLength, bLength) let last := add(add(result, 0x20), totalLength) // Zeroize the slot after the string. mstore(last, 0) // Stores the length. mstore(result, totalLength) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 0x1f), w)) } } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. /// WARNING! This function is only compatible with 7-bit ASCII strings. function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let length := mload(subject) if length { result := add(mload(0x40), 0x20) subject := add(subject, 1) let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) let w := not(0) for { let o := length } 1 {} { o := add(o, w) let b := and(0xff, mload(add(subject, o))) mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20))) if iszero(o) { break } } result := mload(0x40) mstore(result, length) // Store the length. let last := add(add(result, 0x20), length) mstore(last, 0) // Zeroize the slot after the string. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } } /// @dev Returns a lowercased copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function upper(string memory subject) internal pure returns (string memory result) { result = toCase(subject, true); } /// @dev Escapes the string to be used within HTML tags. function escapeHTML(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { for { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // Store the bytes of the packed offsets and strides into the scratch space. // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. mstore(0x1f, 0x900094) mstore(0x08, 0xc0000000a6ab) // Store ""&'<>" into the scratch space. mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) } iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // Not in `["\"","'","&","<",">"]`. if iszero(and(shl(c, 1), 0x500000c400000000)) { mstore8(result, c) result := add(result, 1) continue } let t := shr(248, mload(c)) mstore(result, mload(and(t, 0x1f))) result := add(result, shr(5, t)) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { for { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // Store "\\u0000" in scratch space. // Store "0123456789abcdef" in scratch space. // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. // into the scratch space. mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) // Bitmask for detecting `["\"","\\"]`. let e := or(shl(0x22, 1), shl(0x5c, 1)) } iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) if iszero(lt(c, 0x20)) { if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`. mstore8(result, c) result := add(result, 1) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), c) result := add(result, 2) continue } if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`. mstore8(0x1d, mload(shr(4, c))) // Hex value. mstore8(0x1e, mload(and(c, 15))) // Hex value. mstore(result, mload(0x19)) // "\\u00XX". result := add(result, 6) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), mload(add(c, 8))) result := add(result, 2) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Packs a single string with its length into a single word. /// Returns `bytes32(0)` if the length is zero or greater than 31. function packOne(string memory a) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { // We don't need to zero right pad the string, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes. mload(add(a, 0x1f)), // `length != 0 && length < 32`. Abuses underflow. // Assumes that the length is valid and within the block gas limit. lt(sub(mload(a), 1), 0x1f) ) } } /// @dev Unpacks a string packed using {packOne}. /// Returns the empty string if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packOne}, the output behaviour is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. result := mload(0x40) // Allocate 2 words (1 for the length, 1 for the bytes). mstore(0x40, add(result, 0x40)) // Zeroize the length slot. mstore(result, 0) // Store the length and bytes. mstore(add(result, 0x1f), packed) // Right pad with zeroes. mstore(add(add(result, 0x20), mload(result)), 0) } } /// @dev Packs two strings with their lengths into a single word. /// Returns `bytes32(0)` if combined length is zero or greater than 30. function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let aLength := mload(a) // We don't need to zero right pad the strings, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes of `a` and `b`. or( shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))), mload(sub(add(b, 0x1e), aLength)) ), // `totalLength != 0 && totalLength < 31`. Abuses underflow. // Assumes that the lengths are valid and within the block gas limit. lt(sub(add(aLength, mload(b)), 1), 0x1e) ) } } /// @dev Unpacks strings packed using {packTwo}. /// Returns the empty strings if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packTwo}, the output behaviour is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. resultA := mload(0x40) resultB := add(resultA, 0x40) // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. mstore(0x40, add(resultB, 0x40)) // Zeroize the length slots. mstore(resultA, 0) mstore(resultB, 0) // Store the lengths and bytes. mstore(add(resultA, 0x1f), packed) mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) // Right pad with zeroes. mstore(add(add(resultA, 0x20), mload(resultA)), 0) mstore(add(add(resultB, 0x20), mload(resultB)), 0) } } /// @dev Directly returns `a` without copying. function directReturn(string memory a) internal pure { assembly { // Assumes that the string does not start from the scratch space. let retStart := sub(a, 0x20) let retSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the string is produced // by a method that doesn't zero right pad. mstore(add(retStart, retSize), 0) // Store the return offset. mstore(retStart, 0x20) // End the transaction, returning the string. return(retStart, retSize) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// /// @dev Note: /// This implementation does NOT auto-initialize the owner to `msg.sender`. /// You MUST call the `_initializeOwner` in the constructor / initializer. /// /// While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. /// It is intentionally chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(not(_OWNER_SLOT_NOT), newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { /// @solidity memory-safe-assembly assembly { let ownerSlot := not(_OWNER_SLOT_NOT) // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. /// Override to return a different value if needed. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ownershipHandoverValidFor() internal view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + _ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(not(_OWNER_SLOT_NOT)) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {IRoyaltyManager, RoyaltyInfo} from "src/interfaces/IRoyaltyManager.sol"; import {ISplitsMain} from "src/interfaces/ISplitsMain.sol"; import "src/utils/Constants.sol"; /** * @title RoyaltyManager * @author fx(hash) * @notice See the documentation in {IRoyaltyManager} */ abstract contract RoyaltyManager is IRoyaltyManager { /*////////////////////////////////////////////////////////////////////////// STORAGE //////////////////////////////////////////////////////////////////////////*/ /** * @notice Returns royalty information of index in array list */ RoyaltyInfo public baseRoyalties; /** * @notice Mapping of token ID to array of royalty information */ mapping(uint256 => RoyaltyInfo) public tokenRoyalties; /*////////////////////////////////////////////////////////////////////////// EXTERNAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @inheritdoc IRoyaltyManager */ function getRoyalties( uint256 _tokenId ) external view returns (address[] memory receivers, uint256[] memory basisPoints) { RoyaltyInfo storage tokenRoyalties_ = tokenRoyalties[_tokenId]; if (tokenRoyalties_.receiver != address(0) && tokenRoyalties_.basisPoints != 0) { receivers = new address[](2); basisPoints = new uint256[](2); receivers[1] = tokenRoyalties_.receiver; basisPoints[1] = tokenRoyalties_.basisPoints; } else { receivers = new address[](1); basisPoints = new uint256[](1); } receivers[0] = baseRoyalties.receiver; basisPoints[0] = baseRoyalties.basisPoints; } /** * @inheritdoc IRoyaltyManager */ function royaltyInfo( uint256 _tokenId, uint256 _salePrice ) external view returns (address receiver, uint256 amount) { RoyaltyInfo storage tokenRoyalties_ = tokenRoyalties[_tokenId]; if (tokenRoyalties_.receiver != address(0) && tokenRoyalties_.basisPoints != 0) { revert MoreThanOneRoyaltyReceiver(); } else if (baseRoyalties.receiver == address(0) && baseRoyalties.basisPoints == 0) { return (receiver, amount); } else { receiver = baseRoyalties.receiver; amount = (_salePrice * baseRoyalties.basisPoints) / FEE_DENOMINATOR; } } /*////////////////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ function _getOrCreateSplit( address[] calldata _receivers, uint32[] calldata _allocations ) internal returns (address receiver) { receiver = ISplitsMain(SPLITS_MAIN).predictImmutableSplitAddress(_receivers, _allocations, 0); if (receiver.code.length == 0) { ISplitsMain(SPLITS_MAIN).createSplit(_receivers, _allocations, 0, address(0)); } } /** * @notice Sets the base royalties for all tokens * @param _receivers Array of addresses receiving royalties * @param _allocations Array of allocation amounts for calculating royalty shares * @param _basisPoints Total allocation scalar for calculating royalty shares */ function _setBaseRoyalties( address[] calldata _receivers, uint32[] calldata _allocations, uint96 _basisPoints ) internal virtual { _checkRoyalties(_receivers, _allocations, _basisPoints); /// compute split if necessary address receiver; if (_receivers.length == 0 || _basisPoints == 0) { delete baseRoyalties; } else if (_receivers.length > 1) { receiver = _getOrCreateSplit(_receivers, _allocations); } else { receiver = _receivers[0]; } baseRoyalties = RoyaltyInfo(receiver, _basisPoints); emit TokenRoyaltiesUpdated(receiver, _receivers, _allocations, _basisPoints); } /** * @notice Sets the royalties for a specific token ID * @param _tokenId ID of the token * @param _receiver Address receiving royalty payments * @param _basisPoints Total allocation scalar for calculating royalty shares */ function _setTokenRoyalties(uint256 _tokenId, address _receiver, uint96 _basisPoints) internal { if (!_exists(_tokenId)) revert NonExistentToken(); if (_basisPoints > MAX_ROYALTY_BPS) revert OverMaxBasisPointsAllowed(); if (baseRoyalties.basisPoints + _basisPoints >= FEE_DENOMINATOR) revert InvalidRoyaltyConfig(); tokenRoyalties[_tokenId] = RoyaltyInfo(_receiver, _basisPoints); emit TokenIdRoyaltiesUpdated(_tokenId, _receiver, _basisPoints); } /** * @dev Checks if the token ID exists */ function _exists(uint256 _tokenId) internal view virtual returns (bool); /** * @dev Checks if: * 1. Total basis points of royalties exceeds 10,000 (100%) * 2. A single receiver exceeds 2,500 (25%) */ function _checkRoyalties( address[] memory _receivers, uint32[] memory _allocations, uint96 _basisPoints ) internal pure { uint256 allocationsLength = _allocations.length; if (_receivers.length != allocationsLength) revert LengthMismatch(); if (_basisPoints >= FEE_DENOMINATOR) revert InvalidRoyaltyConfig(); for (uint256 i; i < allocationsLength; ++i) { if ((_allocations[i] * _basisPoints) / ALLOCATION_DENOMINATOR > MAX_ROYALTY_BPS) revert OverMaxBasisPointsAllowed(); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./utils/Bytecode.sol"; /** @title A key-value storage with auto-generated keys for storing chunks of data with a lower write & read cost. @author Agustin Aguilar <[email protected]> Readme: https://github.com/0xsequence/sstore2#readme */ library SSTORE2 { error WriteError(); /** @notice Stores `_data` and returns `pointer` as key for later retrieval @dev The pointer is a contract address with `_data` as code @param _data to be written @return pointer Pointer to the written `_data` */ function write(bytes memory _data) internal returns (address pointer) { // Append 00 to _data so contract can't be called // Build init code bytes memory code = Bytecode.creationCodeFor( abi.encodePacked( hex'00', _data ) ); // Deploy contract using create assembly { pointer := create(0, add(code, 32), mload(code)) } // Address MUST be non-zero if (pointer == address(0)) revert WriteError(); } /** @notice Reads the contents of the `_pointer` code as data, skips the first byte @dev The function is intended for reading pointers generated by `write` @param _pointer to be read @return data read from `_pointer` contract */ function read(address _pointer) internal view returns (bytes memory) { return Bytecode.codeAt(_pointer, 1, type(uint256).max); } /** @notice Reads the contents of the `_pointer` code as data, skips the first byte @dev The function is intended for reading pointers generated by `write` @param _pointer to be read @param _start number of bytes to skip @return data read from `_pointer` contract */ function read(address _pointer, uint256 _start) internal view returns (bytes memory) { return Bytecode.codeAt(_pointer, _start + 1, type(uint256).max); } /** @notice Reads the contents of the `_pointer` code as data, skips the first byte @dev The function is intended for reading pointers generated by `write` @param _pointer to be read @param _start number of bytes to skip @param _end index before which to end extraction @return data read from `_pointer` contract */ function read(address _pointer, uint256 _start, uint256 _end) internal view returns (bytes memory) { return Bytecode.codeAt(_pointer, _start + 1, _end + 1); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4906.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; import "./IERC721.sol"; /// @title EIP-721 Metadata Update Extension interface IERC4906 is IERC165, IERC721 { /// @dev This event emits when the metadata of a token is changed. /// So that the third-party platforms such as NFT market could /// timely update the images and related attributes of the NFT. event MetadataUpdate(uint256 _tokenId); /// @dev This event emits when the metadata of a range of tokens is changed. /// So that the third-party platforms such as NFT market could /// timely update the images and related attributes of the NFTs. event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {ConfigInfo} from "src/lib/Structs.sol"; /** * @title IFxContractRegistry * @author fx(hash) * @notice Registry for managing fxhash smart contracts */ interface IFxContractRegistry { /*////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Event emitted when contract gets registered * @param _contractName Name of the contract * @param _hashedName Hashed name of the contract * @param _contractAddr Address of the contract */ event ContractRegistered(string indexed _contractName, bytes32 indexed _hashedName, address indexed _contractAddr); /** * @notice Event emitted when the config information is updated * @param _owner Address of the registry owner * @param _configInfo Updated config information */ event ConfigUpdated(address indexed _owner, ConfigInfo _configInfo); /*////////////////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Error thrown when array lengths do not match */ error LengthMismatch(); /** * @notice Error thrown when array length is zero */ error LengthZero(); /*////////////////////////////////////////////////////////////////////////// FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Returns the system config information */ function configInfo() external view returns (address, uint32, uint32, uint32, uint64, string memory, string memory); /** * @notice Mapping of hashed contract name to contract address */ function contracts(bytes32) external view returns (address); /** * @notice Registers deployed contract addresses based on hashed value of name * @param _names Array of contract names * @param _contracts Array of contract addresses */ function register(string[] calldata _names, address[] calldata _contracts) external; /** * @notice Sets the system config information * @param _configInfo Config information (lock time, referrer share, default metadata) */ function setConfig(ConfigInfo calldata _configInfo) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {GenArtInfo, InitInfo, IssuerInfo, MetadataInfo, MintInfo, ProjectInfo, ReserveInfo} from "src/lib/Structs.sol"; import {ISeedConsumer} from "src/interfaces/ISeedConsumer.sol"; import {IToken} from "src/interfaces/IToken.sol"; /** * @title IFxGenArt721 * @author fx(hash) * @notice ERC-721 token for generative art projects created on fxhash */ interface IFxGenArt721 is ISeedConsumer, IToken { /*////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Event emitted when the base URI is updated * @param _uri Decoded content identifier of metadata pointer */ event BaseURIUpdated(bytes _uri); /** * @notice Event emitted when public burn is enabled or disabled * @param _flag Status of burn */ event BurnEnabled(bool indexed _flag); /** * @notice Event emitted when public mint is enabled or disabled * @param _flag Status of mint */ event MintEnabled(bool indexed _flag); /** * @notice Event emitted when project is deleted only once supply is set to zero */ event ProjectDeleted(); /** * @notice Event emitted when new project is initialized * @param _primaryReceiver Address of splitter contract receiving primary sales * @param _projectInfo Project information * @param _metadataInfo Metadata information of token * @param _mintInfo Array of authorized minter contracts and their reserves */ event ProjectInitialized( address indexed _primaryReceiver, ProjectInfo _projectInfo, MetadataInfo _metadataInfo, MintInfo[] _mintInfo ); /** * @notice Event emitted when the primary receiver address is updated * @param _receiver The split address receiving funds on behalf of the users * @param _receivers Array of addresses receiving a portion of the funds in a split * @param _allocations Array of allocation shares for the split */ event PrimaryReceiverUpdated(address indexed _receiver, address[] _receivers, uint32[] _allocations); /** * @notice Event emitted when project tags are set * @param _tagIds Array of tag IDs describing the project */ event ProjectTags(uint256[] _tagIds); /** * @notice Event emitted when Randomizer contract is updated * @param _randomizer Address of new Randomizer contract */ event RandomizerUpdated(address indexed _randomizer); /** * @notice Event emitted when Renderer contract is updated * @param _renderer Address of new Renderer contract */ event RendererUpdated(address indexed _renderer); /** * @notice Event emitted when onchain data of project is updated * @param _pointer SSTORE2 pointer to the onchain data */ event OnchainPointerUpdated(address _pointer); /** * @notice Event emitted when maximum supply is reduced * @param _prevSupply Amount of previous supply * @param _newSupply Amount of new supply */ event SupplyReduced(uint120 indexed _prevSupply, uint120 indexed _newSupply); /*////////////////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Error thrown when total minter allocation exceeds maximum supply */ error AllocationExceeded(); /** * @notice Error thrown when burning is inactive */ error BurnInactive(); /** * @notice Error thrown when the fee receiver address is not included in the receiver allocations */ error FeeReceiverMissing(); /** * @notice Error thrown when remaining supply is zero */ error InsufficientSupply(); /** * @notice Error thrown when max supply amount is invalid */ error InvalidAmount(); /** * @notice Error thrown when input size does not match actual byte size of params data */ error InvalidInputSize(); /** * @notice Error thrown when reserve start time is invalid */ error InvalidStartTime(); /** * @notice Error thrown when reserve end time is invalid */ error InvalidEndTime(); /** * @notice Error thrown when the configured fee receiver is not valid */ error InvalidFeeReceiver(); /** * @notice Error thrown when minting is active */ error MintActive(); /** * @notice Error thrown when minting is inactive */ error MintInactive(); /** * @notice Error thrown when caller is not authorized to execute transaction */ error NotAuthorized(); /** * @notice Error thrown when signer is not the owner */ error NotOwner(); /** * @notice Error thrown when supply is remaining */ error SupplyRemaining(); /** * @notice Error thrown when caller does not have the specified role */ error UnauthorizedAccount(); /** * @notice Error thrown when caller does not have minter role */ error UnauthorizedMinter(); /** * @notice Error thrown when minter is not registered on token contract */ error UnregisteredMinter(); /*////////////////////////////////////////////////////////////////////////// FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /* * @notice Returns the list of minter contracts currently active on the token */ function activeMinters() external view returns (address[] memory); /** * @notice Burns token ID from the circulating supply * @param _tokenId ID of the token */ function burn(uint256 _tokenId) external; /** * @notice Returns address of the FxContractRegistry contract */ function contractRegistry() external view returns (address); /** * @notice Returns contract-level metadata for storefront marketplaces */ function contractURI() external view returns (string memory); /** * @inheritdoc ISeedConsumer */ function fulfillSeedRequest(uint256 _tokenId, bytes32 _seed) external; /** * @notice Mapping of token ID to GenArtInfo struct (minter, seed, fxParams) */ function genArtInfo(uint256 _tokenId) external view returns (address, bytes32, bytes memory); /** * @notice Generates typed data hash for setting project metadata onchain * @param _data Bytes-encoded onchain data * @return Typed data hash */ function generateOnchainPointerHash(bytes calldata _data) external view returns (bytes32); /** * @notice Generates typed data hash for setting the primary receiver address * @param _renderer Address of the new renderer contract * @return Typed data hash */ function generateRendererHash(address _renderer) external view returns (bytes32); /** * @notice Initializes new generative art project * @param _owner Address of token proxy owner * @param _initInfo Initialization information set on project creation * @param _projectInfo Project information * @param _metadataInfo Metadata information * @param _mintInfo Array of authorized minter contracts and their reserves * @param _royaltyReceivers Array of addresses receiving royalties * @param _allocations Array of allocation amounts for calculating royalty shares * @param _basisPoints Total allocation scalar for calculating royalty shares */ function initialize( address _owner, InitInfo calldata _initInfo, ProjectInfo calldata _projectInfo, MetadataInfo calldata _metadataInfo, MintInfo[] calldata _mintInfo, address[] calldata _royaltyReceivers, uint32[] calldata _allocations, uint96 _basisPoints ) external; /** * @notice Gets the authorization status for the given minter contract * @param _minter Address of the minter contract * @return Authorization status */ function isMinter(address _minter) external view returns (bool); /** * @notice Returns the issuer information of the project (primaryReceiver, ProjectInfo) */ function issuerInfo() external view returns (address, ProjectInfo memory); /** * @notice Returns the metadata information of the project (baseURI, onchainPointer) */ function metadataInfo() external view returns (bytes memory, address); /** * @inheritdoc IToken */ function mint(address _to, uint256 _amount, uint256 _payment) external; /** * @notice Mints single fxParams token * @dev Only callable by registered minter contracts * @param _to Address receiving minted token * @param _fxParams Random sequence of fixed-length bytes used as input */ function mintParams(address _to, bytes calldata _fxParams) external; /** * @notice Current nonce for admin signatures */ function nonce() external returns (uint96); /** * @notice Mints single token with randomly generated seed * @dev Only callable by contract owner * @param _to Address receiving token */ function ownerMint(address _to) external; /** * @notice Mints single fxParams token * @dev Only callable by contract owner * @param _to Address receiving minted token * @param _fxParams Random sequence of fixed-length bytes used as input */ function ownerMintParams(address _to, bytes calldata _fxParams) external; /** * @notice Pauses all function executions where modifier is applied */ function pause() external; /** * @inheritdoc IToken */ function primaryReceiver() external view returns (address); /** * @notice Returns the address of the randomizer contract */ function randomizer() external view returns (address); /** * @notice Reduces maximum supply of collection * @param _supply Maximum supply amount */ function reduceSupply(uint120 _supply) external; /** * @notice Registers minter contracts with resereve info * @param _mintInfo Mint information of token reserves */ function registerMinters(MintInfo[] memory _mintInfo) external; /** * @notice Returns the remaining supply of tokens left to mint */ function remainingSupply() external view returns (uint256); /** * @notice Returns the address of the Renderer contract */ function renderer() external view returns (address); /** * @notice Returns the address of the FxRoleRegistry contract */ function roleRegistry() external view returns (address); /** * @notice Sets the base royalties for all secondary token sales * @param _receivers Array of addresses receiving royalties * @param _allocations Array of allocations used to calculate royalty payments * @param _basisPoints basis points used to calculate royalty payments */ function setBaseRoyalties( address[] calldata _receivers, uint32[] calldata _allocations, uint96 _basisPoints ) external; /** * @notice Sets the new URI of the token metadata * @param _uri Decoded content identifier of metadata pointer */ function setBaseURI(bytes calldata _uri) external; /** * @notice Sets flag status of public burn to enabled or disabled * @param _flag Status of burn */ function setBurnEnabled(bool _flag) external; /** * @notice Sets flag status of public mint to enabled or disabled * @param _flag Status of mint */ function setMintEnabled(bool _flag) external; /** * @notice Sets the onchain pointer for reconstructing project metadata onchain * @param _onchainData Bytes-encoded metadata * @param _signature Signature of creator used to verify metadata update */ function setOnchainPointer(bytes calldata _onchainData, bytes calldata _signature) external; /** * @notice Sets the primary receiver address for primary sale proceeds * @param _receivers Array of addresses receiving shares from primary sales * @param _allocations Array of allocation amounts for calculating primary sales shares */ function setPrimaryReceivers(address[] calldata _receivers, uint32[] calldata _allocations) external; /** * @notice Sets the new randomizer contract * @param _randomizer Address of the randomizer contract */ function setRandomizer(address _randomizer) external; /** * @notice Sets the new renderer contract * @param _renderer Address of the renderer contract * @param _signature Signature of creator used to verify renderer update */ function setRenderer(address _renderer, bytes calldata _signature) external; /** * @notice Emits an event for setting tag descriptions for the project * @param _tagIds Array of tag IDs describing the project */ function setTags(uint256[] calldata _tagIds) external; /** * @notice Returns the current circulating supply of tokens */ function totalSupply() external view returns (uint96); /** * @notice Unpauses all function executions where modifier is applied */ function unpause() external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {ReserveInfo} from "src/lib/Structs.sol"; /** * @title IMinter * @author fx(hash) * @notice Interface for FxGenArt721 tokens to interact with minters */ interface IMinter { /*////////////////////////////////////////////////////////////////////////// FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Sets the mint details for token reserves * @param _reserveInfo Reserve information for the token * @param _mintDetails Details of the mint pertaining to the minter */ function setMintDetails(ReserveInfo calldata _reserveInfo, bytes calldata _mintDetails) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; /** * @title IRandomizer * @author fx(hash) * @notice Interface for FxGenArt721 tokens to interact with randomizers */ interface IRandomizer { /*////////////////////////////////////////////////////////////////////////// FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Requests random seed for a given token * @param _tokenId ID of the token */ function requestRandomness(uint256 _tokenId) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; /** * @title IRenderer * @author fx(hash) * @notice Interface for FxGenArt721 tokens to interact with renderers */ interface IRenderer { /*////////////////////////////////////////////////////////////////////////// FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Returns address of the FxContractRegistry contract */ function contractRegistry() external view returns (address); /** * @notice Gets the contact-level metadata for the project * @return URI of the contract metadata */ function contractURI() external view returns (string memory); /** * @notice Gets the metadata for a token * @param _tokenId ID of the token * @param _data Additional data used to construct metadata * @return URI of the token metadata */ function tokenURI(uint256 _tokenId, bytes calldata _data) external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; /*////////////////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////////////////*/ // Core string constant FX_CONTRACT_REGISTRY = "FX_CONTRACT_REGISTRY"; string constant FX_GEN_ART_721 = "FX_GEN_ART_721"; string constant FX_ISSUER_FACTORY = "FX_ISSUER_FACTORY"; string constant FX_MINT_TICKET_721 = "FX_MINT_TICKET_721"; string constant FX_ROLE_REGISTRY = "FX_ROLE_REGISTRY"; string constant FX_TICKET_FACTORY = "FX_TICKET_FACTORY"; // Periphery string constant DUTCH_AUCTION = "DUTCH_AUCTION"; string constant FIXED_PRICE = "FIXED_PRICE"; string constant ONCHFS_RENDERER = "ONCHFS_RENDERER"; string constant IPFS_RENDERER = "IPFS_RENDERER"; string constant PSEUDO_RANDOMIZER = "PSEUDO_RANDOMIZER"; string constant TICKET_REDEEMER = "TICKET_REDEEMER"; // EIP-712 bytes32 constant CLAIM_TYPEHASH = keccak256( "Claim(address token,uint256 reserveId,uint96 nonce,uint256 index,address user)" ); bytes32 constant SET_ONCHAIN_POINTER_TYPEHASH = keccak256("SetOnchainPointer(bytes onchainData,uint96 nonce)"); bytes32 constant SET_PRIMARY_RECEIVER_TYPEHASH = keccak256("SetPrimaryReceiver(address receiver,uint96 nonce)"); bytes32 constant SET_RENDERER_TYPEHASH = keccak256("SetRenderer(address renderer,uint96 nonce)"); // IPFS bytes constant IPFS_URL = hex"697066733a2f2f172c151325290607391d2c391b242225180a020b291b260929391d1b31222525202804120031280917120b280400"; string constant IPFS_PREFIX = "ipfs://"; // Metadata string constant API_VERSION = "0.2"; string constant ATTRIBUTES_ENDPOINT = "/attributes.json"; string constant METADATA_ENDPOINT = "/metadata.json"; string constant THUMBNAIL_ENDPOINT = "/thumbnail.json"; // ONCHFS string constant FX_HASH_QUERY = "/?fxhash="; string constant FX_PARAMS_QUERY = "#0x"; string constant ITERATION_QUERY = "&fxiteration="; string constant MINTER_QUERY = "&fxminter="; string constant ONCHFS_PREFIX = "onchfs://"; // Minters uint8 constant UNINITIALIZED = 0; uint8 constant FALSE = 1; uint8 constant TRUE = 2; // Project uint32 constant LOCK_TIME = 3600; // 1 hour uint64 constant TIME_UNLIMITED = type(uint64).max; uint120 constant OPEN_EDITION_SUPPLY = type(uint120).max; uint256 constant LAUNCH_TIMESTAMP = 1709226000; // 2/29/24 15:00 GMT // Roles bytes32 constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); bytes32 constant BANNED_USER_ROLE = keccak256("BANNED_USER_ROLE"); bytes32 constant CREATOR_ROLE = keccak256("CREATOR_ROLE"); bytes32 constant METADATA_ROLE = keccak256("METADATA_ROLE"); bytes32 constant MINTER_ROLE = keccak256("MINTER_ROLE"); bytes32 constant MODERATOR_ROLE = keccak256("MODERATOR_ROLE"); bytes32 constant SIGNER_ROLE = keccak256("SIGNER_ROLE"); // Royalties uint32 constant ALLOCATION_DENOMINATOR = 1_000_000; uint96 constant FEE_DENOMINATOR = 10_000; uint96 constant MAX_ROYALTY_BPS = 2500; // 25% // Splits address constant SPLITS_MAIN = 0x2ed6c4B5dA6378c7897AC67Ba9e43102Feb694EE; // Ticket uint256 constant AUCTION_DECAY_RATE = 200; // 2% uint256 constant DAILY_TAX_RATE = 27; // 0.274% uint256 constant MINIMUM_PRICE = 0.001 ether; uint256 constant ONE_DAY = 86_400; uint256 constant SCALING_FACTOR = 10_000; uint256 constant TEN_MINUTES = 600;
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(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) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/ShortStrings.sol) pragma solidity ^0.8.8; import "./StorageSlot.sol"; // | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | // | length | 0x BB | type ShortString is bytes32; /** * @dev This library provides functions to convert short memory strings * into a `ShortString` type that can be used as an immutable variable. * * Strings of arbitrary length can be optimized using this library if * they are short enough (up to 31 bytes) by packing them with their * length (1 byte) in a single EVM word (32 bytes). Additionally, a * fallback mechanism can be used for every other case. * * Usage example: * * ```solidity * contract Named { * using ShortStrings for *; * * ShortString private immutable _name; * string private _nameFallback; * * constructor(string memory contractName) { * _name = contractName.toShortStringWithFallback(_nameFallback); * } * * function name() external view returns (string memory) { * return _name.toStringWithFallback(_nameFallback); * } * } * ``` */ library ShortStrings { // Used as an identifier for strings longer than 31 bytes. bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; error StringTooLong(string str); error InvalidShortString(); /** * @dev Encode a string of at most 31 chars into a `ShortString`. * * This will trigger a `StringTooLong` error is the input string is too long. */ function toShortString(string memory str) internal pure returns (ShortString) { bytes memory bstr = bytes(str); if (bstr.length > 31) { revert StringTooLong(str); } return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length)); } /** * @dev Decode a `ShortString` back to a "normal" string. */ function toString(ShortString sstr) internal pure returns (string memory) { uint256 len = byteLength(sstr); // using `new string(len)` would work locally but is not memory safe. string memory str = new string(32); /// @solidity memory-safe-assembly assembly { mstore(str, len) mstore(add(str, 0x20), sstr) } return str; } /** * @dev Return the length of a `ShortString`. */ function byteLength(ShortString sstr) internal pure returns (uint256) { uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; if (result > 31) { revert InvalidShortString(); } return result; } /** * @dev Encode a string into a `ShortString`, or write it to storage if it is too long. */ function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) { if (bytes(value).length < 32) { return toShortString(value); } else { StorageSlot.getStringSlot(store).value = value; return ShortString.wrap(_FALLBACK_SENTINEL); } } /** * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}. */ function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) { if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) { return toString(value); } else { return store; } } /** * @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}. * * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of * actual characters as the UTF-8 encoding of a single character can span over multiple bytes. */ function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) { if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) { return byteLength(value); } else { return bytes(store).length; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol) pragma solidity ^0.8.0; interface IERC5267 { /** * @dev MAY be emitted to signal that the domain could have changed. */ event EIP712DomainChanged(); /** * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 * signature. */ function eip712Domain() external view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../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 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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../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 v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./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); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {RoyaltyInfo} from "src/lib/Structs.sol"; /** * @title IRoyaltyManager * @author fx(hash) * @notice Extension for managing secondary royalties of FxGenArt721 tokens */ interface IRoyaltyManager { /*////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Event emitted when the royalties for a token ID have been updated * @param _tokenId ID of the token * @param _receiver Addresses receiving the royalties * @param _basisPoints Points used to calculate royalty payments (100 = 1%) */ event TokenIdRoyaltiesUpdated(uint256 indexed _tokenId, address _receiver, uint96 _basisPoints); /** * @notice Event emitted when the royalties for a list of receivers have been updated * @param _receiver The address receiving royalties for the token either an account or a split address * @param _receivers Array of addresses receiving royalties * @param _allocations Array of allocations used to determine the proportional share of royalty payments * @param _basisPoints Points used to calculate royalty payments (100 = 1%) */ event TokenRoyaltiesUpdated( address indexed _receiver, address[] _receivers, uint32[] _allocations, uint96 _basisPoints ); /*////////////////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Error thrown when the royalties are not set */ error BaseRoyaltiesNotSet(); /** * @notice Error thrown when royalty configuration is greater than or equal to 100% */ error InvalidRoyaltyConfig(); /** * @notice Error thrown when array lengths do not match */ error LengthMismatch(); /** * @notice Error thrown when more than one royalty receiver is set */ error MoreThanOneRoyaltyReceiver(); /** * @notice Error thrown when the token ID does not exist */ error NonExistentToken(); /** * @notice Error thrown when royalty receiver is zero address */ error NoRoyaltyReceiver(); /** * @notice Error thrown when total basis points exceeds maximum value allowed */ error OverMaxBasisPointsAllowed(); /** * @notice Error thrown when the token royalties are not set */ error TokenRoyaltiesNotSet(); /*////////////////////////////////////////////////////////////////////////// FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Gets the royalties for a specific token ID * @param _tokenId ID of the token * @return Total receivers and basis points */ function getRoyalties(uint256 _tokenId) external view returns (address[] memory, uint256[] memory); /** * @notice Returns the royalty information for a specific token ID and sale price * @param _tokenId ID of the token * @param _salePrice Sale price of the token * @return receiver Address receiving royalties * @return royaltyAmount Amount to royalties being paid out */ function royaltyInfo(uint256 _tokenId, uint256 _salePrice) external view returns (address, uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; /** * @title ISplitsMain * @author 0xSplits * @notice Interface for SplitsFactory to interact with SplitsMain */ interface ISplitsMain { function createSplit( address[] calldata accounts, uint32[] calldata percentAllocations, uint32 distributorFee, address controller ) external returns (address); function distributeETH( address split, address[] calldata accounts, uint32[] calldata percentAllocations, uint32 distributorFee, address distributorAddress ) external; function getHash(address split) external view returns (bytes32); function predictImmutableSplitAddress( address[] calldata accounts, uint32[] calldata percentAllocations, uint32 distributorFee ) external view returns (address); function updateSplit( address split, address[] calldata accounts, uint32[] calldata percentAllocations, uint32 distributorFee ) external; function withdraw(address account, uint256 withdrawETH, address[] calldata tokens) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library Bytecode { error InvalidCodeAtRange(uint256 _size, uint256 _start, uint256 _end); /** @notice Generate a creation code that results on a contract with `_code` as bytecode @param _code The returning value of the resulting `creationCode` @return creationCode (constructor) for new contract */ function creationCodeFor(bytes memory _code) internal pure returns (bytes memory) { /* 0x00 0x63 0x63XXXXXX PUSH4 _code.length size 0x01 0x80 0x80 DUP1 size size 0x02 0x60 0x600e PUSH1 14 14 size size 0x03 0x60 0x6000 PUSH1 00 0 14 size size 0x04 0x39 0x39 CODECOPY size 0x05 0x60 0x6000 PUSH1 00 0 size 0x06 0xf3 0xf3 RETURN <CODE> */ return abi.encodePacked( hex"63", uint32(_code.length), hex"80_60_0E_60_00_39_60_00_F3", _code ); } /** @notice Returns the size of the code on a given address @param _addr Address that may or may not contain code @return size of the code on the given `_addr` */ function codeSize(address _addr) internal view returns (uint256 size) { assembly { size := extcodesize(_addr) } } /** @notice Returns the code of a given address @dev It will fail if `_end < _start` @param _addr Address that may or may not contain code @param _start number of bytes of code to skip on read @param _end index before which to end extraction @return oCode read from `_addr` deployed bytecode Forked from: https://gist.github.com/KardanovIR/fe98661df9338c842b4a30306d507fbd */ function codeAt(address _addr, uint256 _start, uint256 _end) internal view returns (bytes memory oCode) { uint256 csize = codeSize(_addr); if (csize == 0) return bytes(""); if (_start > csize) return bytes(""); if (_end < _start) revert InvalidCodeAtRange(csize, _start, _end); unchecked { uint256 reqSize = _end - _start; uint256 maxSize = csize - _start; uint256 size = maxSize < reqSize ? maxSize : reqSize; assembly { // allocate output byte array - this could also be done without assembly // by using o_code = new bytes(size) oCode := mload(0x40) // new "memory end" including padding mstore(0x40, add(oCode, and(add(add(size, 0x20), 0x1f), not(0x1f)))) // store length in memory mstore(oCode, size) // actually retrieve the code, this needs assembly extcodecopy(_addr, add(oCode, 0x20), _start, size) } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC721.sol) pragma solidity ^0.8.0; import "../token/ERC721/IERC721.sol";
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; /*////////////////////////////////////////////////////////////////////////// STRUCTS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Struct of dutch auction information * - `refunded` Flag indicating if refunds are enabled * - `stepLength` Duration (in seconds) of each auction step * - `prices` Array of prices for each step of the auction */ struct AuctionInfo { bool refunded; uint248 stepLength; uint256[] prices; } /** * @notice Struct of system config information * - `feeReceiver` Address receiving platform fees * - `primaryFeeAllocation` Amount of basis points allocated to calculate platform fees on primary sale proceeds * - `secondaryFeeAllocation` Amount of basis points allocated to calculate platform fees on royalty payments * - `lockTime` Locked time duration added to mint start time for unverified creators * - `referrerShare` Share amount distributed to accounts referring tokens * - `defaultMetadataURI` Default base URI of token metadata * - `externalURI` External URI for displaying tokens */ struct ConfigInfo { address feeReceiver; uint32 primaryFeeAllocation; uint32 secondaryFeeAllocation; uint32 lockTime; uint64 referrerShare; string defaultMetadataURI; string externalURI; } /** * @notice Struct of generative art information * - `minter` Address of initial token owner * - `seed` Hash of randomly generated seed * - `fxParams` Random sequence of fixed-length bytes used as token input */ struct GenArtInfo { address minter; bytes32 seed; bytes fxParams; } /** * @notice Struct of initialization information used on project creation * - `name` Name of project * - `symbol` Symbol of project * - `primaryReceiver` Address of splitter contract receiving primary sales * - `randomizer` Address of Randomizer contract * - `renderer` Address of Renderer contract * - `tagIds` Array of tag IDs describing the project * - 'onchainData' Onchain data to be stored using SSTORE2 and available to renderers */ struct InitInfo { string name; string symbol; address[] primaryReceivers; uint32[] allocations; address randomizer; address renderer; uint256[] tagIds; bytes onchainData; } /** * @notice Struct of issuer information * - `primaryReceiver` Address of splitter contract receiving primary sales * - `projectInfo` Project information * - `activeMinters` Array of authorized minter contracts used for enumeration * - `minters` Mapping of minter contract to authorization status */ struct IssuerInfo { address primaryReceiver; ProjectInfo projectInfo; address[] activeMinters; mapping(address => uint8) minters; } /** * @notice Struct of metadata information * - `baseURI` Decoded URI of content identifier * - `onchainPointer` Address of bytes-encoded data rendered onchain */ struct MetadataInfo { bytes baseURI; address onchainPointer; } /** * @notice Struct of mint information * - `minter` Address of the minter contract * - `reserveInfo` Reserve information * - `params` Optional bytes data decoded inside minter */ struct MintInfo { address minter; ReserveInfo reserveInfo; bytes params; } /** * @notice Struct of minter information * - `totalMints` Total number of mints executed by the minter * - `totalPaid` Total amount paid by the minter */ struct MinterInfo { uint128 totalMints; uint128 totalPaid; } /** * @notice Struct of project information * - `mintEnabled` Flag inidicating if minting is enabled * - `burnEnabled` Flag inidicating if burning is enabled * - `maxSupply` Maximum supply of tokens * - `inputSize` Maximum input size of fxParams bytes data * - `earliestStartTime` Earliest possible start time for registering minters */ struct ProjectInfo { bool mintEnabled; bool burnEnabled; uint120 maxSupply; uint88 inputSize; uint32 earliestStartTime; } /** * @notice Struct of refund information * - `lastPrice` Price of last sale before selling out * - `minterInfo` Mapping of minter address to struct of minter information */ struct RefundInfo { uint256 lastPrice; mapping(address minter => MinterInfo) minterInfo; } /** * @notice Struct of reserve information * - `startTime` Start timestamp of minter * - `endTime` End timestamp of minter * - `allocation` Allocation amount for minter */ struct ReserveInfo { uint64 startTime; uint64 endTime; uint128 allocation; } /** * @notice Struct of royalty information * - `receiver` Address receiving royalties * - `basisPoints` Points used to calculate the royalty payment (0.01%) */ struct RoyaltyInfo { address receiver; uint96 basisPoints; } /** * @notice Struct of tax information * - `startTime` Timestamp of when harberger taxation begins * - `foreclosureTime` Timestamp of token foreclosure * - `currentPrice` Current listing price of token * - `depositAmount` Total amount of taxes deposited */ struct TaxInfo { uint48 startTime; uint48 foreclosureTime; uint80 currentPrice; uint80 depositAmount; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; /** * @title ISeedConsumer * @author fx(hash) * @notice Interface for randomizers to interact with FxGenArt721 tokens */ interface ISeedConsumer { /*////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Event emitted when a seed request is fulfilled for a specific token * @param _randomizer Address of the randomizer contract * @param _tokenId ID of the token * @param _seed Hash of the random seed */ event SeedFulfilled(address indexed _randomizer, uint256 indexed _tokenId, bytes32 _seed); /*////////////////////////////////////////////////////////////////////////// FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Fullfills the random seed request on the FxGenArt721 token contract * @param _tokenId ID of the token * @param _seed Hash of the random seed */ function fulfillSeedRequest(uint256 _tokenId, bytes32 _seed) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; /** * @title IToken * @author fx(hash) * @notice Interface for minters to interact with tokens */ interface IToken { /*////////////////////////////////////////////////////////////////////////// FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /** * @notice Mints arbitrary number of tokens * @dev Only callable by registered minter contracts * @param _to Address receiving tokens * @param _amount Number of tokens being minted * @param _payment Total payment amount of the transaction */ function mint(address _to, uint256 _amount, uint256 _payment) external; /** * @notice Returns address of primary receiver for token sales */ function primaryReceiver() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // 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. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 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 + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @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 v4.9.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ * _Available since v4.9 for `string`, `bytes`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "remappings": [ "openzeppelin/=lib/openzeppelin-contracts/", "openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "forge-std/=lib/forge-std/src/", "scripty.sol/=lib/scripty.sol/", "solady/=lib/solady/", "solmate/=lib/solmate/", "sstore2/=lib/sstore2/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/" ], "optimizer": { "enabled": true, "runs": 2 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_contractRegistry","type":"address"},{"internalType":"address","name":"_roleRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AllocationExceeded","type":"error"},{"inputs":[],"name":"BaseRoyaltiesNotSet","type":"error"},{"inputs":[],"name":"BurnInactive","type":"error"},{"inputs":[],"name":"FeeReceiverMissing","type":"error"},{"inputs":[],"name":"InsufficientSupply","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidEndTime","type":"error"},{"inputs":[],"name":"InvalidFeeReceiver","type":"error"},{"inputs":[],"name":"InvalidInputSize","type":"error"},{"inputs":[],"name":"InvalidRoyaltyConfig","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[],"name":"InvalidStartTime","type":"error"},{"inputs":[],"name":"LengthMismatch","type":"error"},{"inputs":[],"name":"MintActive","type":"error"},{"inputs":[],"name":"MintInactive","type":"error"},{"inputs":[],"name":"MoreThanOneRoyaltyReceiver","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NoRoyaltyReceiver","type":"error"},{"inputs":[],"name":"NonExistentToken","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"OverMaxBasisPointsAllowed","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[],"name":"SupplyRemaining","type":"error"},{"inputs":[],"name":"TokenRoyaltiesNotSet","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnauthorizedAccount","type":"error"},{"inputs":[],"name":"UnauthorizedMinter","type":"error"},{"inputs":[],"name":"UnregisteredMinter","type":"error"},{"inputs":[],"name":"WriteError","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"_uri","type":"bytes"}],"name":"BaseURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"_flag","type":"bool"}],"name":"BurnEnabled","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"MetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"_flag","type":"bool"}],"name":"MintEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_pointer","type":"address"}],"name":"OnchainPointerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_receiver","type":"address"},{"indexed":false,"internalType":"address[]","name":"_receivers","type":"address[]"},{"indexed":false,"internalType":"uint32[]","name":"_allocations","type":"uint32[]"}],"name":"PrimaryReceiverUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"ProjectDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_primaryReceiver","type":"address"},{"components":[{"internalType":"bool","name":"mintEnabled","type":"bool"},{"internalType":"bool","name":"burnEnabled","type":"bool"},{"internalType":"uint120","name":"maxSupply","type":"uint120"},{"internalType":"uint88","name":"inputSize","type":"uint88"},{"internalType":"uint32","name":"earliestStartTime","type":"uint32"}],"indexed":false,"internalType":"struct ProjectInfo","name":"_projectInfo","type":"tuple"},{"components":[{"internalType":"bytes","name":"baseURI","type":"bytes"},{"internalType":"address","name":"onchainPointer","type":"address"}],"indexed":false,"internalType":"struct MetadataInfo","name":"_metadataInfo","type":"tuple"},{"components":[{"internalType":"address","name":"minter","type":"address"},{"components":[{"internalType":"uint64","name":"startTime","type":"uint64"},{"internalType":"uint64","name":"endTime","type":"uint64"},{"internalType":"uint128","name":"allocation","type":"uint128"}],"internalType":"struct ReserveInfo","name":"reserveInfo","type":"tuple"},{"internalType":"bytes","name":"params","type":"bytes"}],"indexed":false,"internalType":"struct MintInfo[]","name":"_mintInfo","type":"tuple[]"}],"name":"ProjectInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"_tagIds","type":"uint256[]"}],"name":"ProjectTags","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_randomizer","type":"address"}],"name":"RandomizerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_renderer","type":"address"}],"name":"RendererUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_randomizer","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_seed","type":"bytes32"}],"name":"SeedFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint120","name":"_prevSupply","type":"uint120"},{"indexed":true,"internalType":"uint120","name":"_newSupply","type":"uint120"}],"name":"SupplyReduced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"_receiver","type":"address"},{"indexed":false,"internalType":"uint96","name":"_basisPoints","type":"uint96"}],"name":"TokenIdRoyaltiesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_receiver","type":"address"},{"indexed":false,"internalType":"address[]","name":"_receivers","type":"address[]"},{"indexed":false,"internalType":"uint32[]","name":"_allocations","type":"uint32[]"},{"indexed":false,"internalType":"uint96","name":"_basisPoints","type":"uint96"}],"name":"TokenRoyaltiesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"activeMinters","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseRoyalties","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint96","name":"basisPoints","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"contractRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes32","name":"_seed","type":"bytes32"}],"name":"fulfillSeedRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"genArtInfo","outputs":[{"internalType":"address","name":"minter","type":"address"},{"internalType":"bytes32","name":"seed","type":"bytes32"},{"internalType":"bytes","name":"fxParams","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"generateOnchainPointerHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_renderer","type":"address"}],"name":"generateRendererHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","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":"_tokenId","type":"uint256"}],"name":"getRoyalties","outputs":[{"internalType":"address[]","name":"receivers","type":"address[]"},{"internalType":"uint256[]","name":"basisPoints","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"address[]","name":"primaryReceivers","type":"address[]"},{"internalType":"uint32[]","name":"allocations","type":"uint32[]"},{"internalType":"address","name":"randomizer","type":"address"},{"internalType":"address","name":"renderer","type":"address"},{"internalType":"uint256[]","name":"tagIds","type":"uint256[]"},{"internalType":"bytes","name":"onchainData","type":"bytes"}],"internalType":"struct InitInfo","name":"_initInfo","type":"tuple"},{"components":[{"internalType":"bool","name":"mintEnabled","type":"bool"},{"internalType":"bool","name":"burnEnabled","type":"bool"},{"internalType":"uint120","name":"maxSupply","type":"uint120"},{"internalType":"uint88","name":"inputSize","type":"uint88"},{"internalType":"uint32","name":"earliestStartTime","type":"uint32"}],"internalType":"struct ProjectInfo","name":"_projectInfo","type":"tuple"},{"components":[{"internalType":"bytes","name":"baseURI","type":"bytes"},{"internalType":"address","name":"onchainPointer","type":"address"}],"internalType":"struct MetadataInfo","name":"_metadataInfo","type":"tuple"},{"components":[{"internalType":"address","name":"minter","type":"address"},{"components":[{"internalType":"uint64","name":"startTime","type":"uint64"},{"internalType":"uint64","name":"endTime","type":"uint64"},{"internalType":"uint128","name":"allocation","type":"uint128"}],"internalType":"struct ReserveInfo","name":"reserveInfo","type":"tuple"},{"internalType":"bytes","name":"params","type":"bytes"}],"internalType":"struct MintInfo[]","name":"_mintInfo","type":"tuple[]"},{"internalType":"address[]","name":"_royaltyReceivers","type":"address[]"},{"internalType":"uint32[]","name":"_allocations","type":"uint32[]"},{"internalType":"uint96","name":"_basisPoints","type":"uint96"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","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":"_minter","type":"address"}],"name":"isMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"issuerInfo","outputs":[{"internalType":"address","name":"primaryReceiver","type":"address"},{"components":[{"internalType":"bool","name":"mintEnabled","type":"bool"},{"internalType":"bool","name":"burnEnabled","type":"bool"},{"internalType":"uint120","name":"maxSupply","type":"uint120"},{"internalType":"uint88","name":"inputSize","type":"uint88"},{"internalType":"uint32","name":"earliestStartTime","type":"uint32"}],"internalType":"struct ProjectInfo","name":"projectInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataInfo","outputs":[{"internalType":"bytes","name":"baseURI","type":"bytes"},{"internalType":"address","name":"onchainPointer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"bytes","name":"_fxParams","type":"bytes"}],"name":"mintParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"ownerMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"bytes","name":"_fxParams","type":"bytes"}],"name":"ownerMintParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"primaryReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"randomizer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint120","name":"_supply","type":"uint120"}],"name":"reduceSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"minter","type":"address"},{"components":[{"internalType":"uint64","name":"startTime","type":"uint64"},{"internalType":"uint64","name":"endTime","type":"uint64"},{"internalType":"uint128","name":"allocation","type":"uint128"}],"internalType":"struct ReserveInfo","name":"reserveInfo","type":"tuple"},{"internalType":"bytes","name":"params","type":"bytes"}],"internalType":"struct MintInfo[]","name":"_mintInfo","type":"tuple[]"}],"name":"registerMinters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"remainingSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renderer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"roleRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","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":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_receivers","type":"address[]"},{"internalType":"uint32[]","name":"_allocations","type":"uint32[]"},{"internalType":"uint96","name":"_basisPoints","type":"uint96"}],"name":"setBaseRoyalties","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_uri","type":"bytes"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_flag","type":"bool"}],"name":"setBurnEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_flag","type":"bool"}],"name":"setMintEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_onchainData","type":"bytes"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"setOnchainPointer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_receivers","type":"address[]"},{"internalType":"uint32[]","name":"_allocations","type":"uint32[]"}],"name":"setPrimaryReceivers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_randomizer","type":"address"}],"name":"setRandomizer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_renderer","type":"address"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"setRenderer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tagIds","type":"uint256[]"}],"name":"setTags","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenRoyalties","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint96","name":"basisPoints","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101a06040523480156200001257600080fd5b50604051620062463803806200624683398101604081905262000035916200023a565b604080518082018252600b8082526a467847656e41727437323160a81b60208084018290528451808601865260018152603160f81b8183015285518087018752938452838201929092528451808601909552600685526508cb09082a6960d31b9085015291926000620000a9838262000319565b506001620000b8828262000319565b50620000ca9150839050600662000198565b61012052620000db81600762000198565b61014052815160208084019190912060e052815190820120610100524660a0526200016960e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c0526008805462ff0000191690556001600160a01b039182166101605216610180526200045b565b6000602083511015620001b857620001b083620001d1565b9050620001cb565b81620001c5848262000319565b5060ff90505b92915050565b600080829050601f8151111562000208578260405163305a27a960e01b8152600401620001ff9190620003e5565b60405180910390fd5b8051620002158262000436565b179392505050565b80516001600160a01b03811681146200023557600080fd5b919050565b600080604083850312156200024e57600080fd5b62000259836200021d565b915062000269602084016200021d565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200029d57607f821691505b602082108103620002be57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000314576000816000526020600020601f850160051c81016020861015620002ef5750805b601f850160051c820191505b818110156200031057828155600101620002fb565b5050505b505050565b81516001600160401b0381111562000335576200033562000272565b6200034d8162000346845462000288565b84620002c4565b602080601f8311600181146200038557600084156200036c5750858301515b600019600386901b1c1916600185901b17855562000310565b600085815260208120601f198616915b82811015620003b65788860151825594840194600190910190840162000395565b5085821015620003d55787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020808352835180602085015260005b818110156200041557858101830151858201604001528201620003f7565b506000604082860101526040601f19601f8301168501019250505092915050565b80516020808301519190811015620002be5760001960209190910360031b1b16919050565b60805160a05160c05160e0516101005161012051610140516101605161018051615d2d62000519600039600081816103e801528181610dfb0152818161124a0152818161184101528181611bd301528181611d5501528181612987015281816130fb01526134a60152600081816108870152818161146d01528181612841015261320301526000611e2b01526000611e0001526000613ddd01526000613db501526000613d1001526000613d3a01526000613d640152615d2d6000f3fe6080604052600436106102bd5760003560e01c806301ffc9a7146102c257806303bbc8ab146102f757806306fdde0314610387578063081812fc146103a957806308c73259146103d6578063095ea7b31461040a5780630ba1baf21461042c5780630f686cfe1461044c578063124f76cb1461046c578063156e29f61461048c57806318160ddd146104ac5780631ca6bf46146104e45780631e3bcc8e1461050457806323b872dd1461052457806325692962146105445780632a55205a1461054c5780633f4ba83a1461058b57806342842e0e146105a057806342966c68146105c05780634e313ed1146105e057806354d1f13d1461060057806355e42958146106085780635c975abb146106285780635f44f1eb146106475780635f5ef7aa146106675780636352211e146106955780636848fb51146106b557806370a08231146106d5578063715018a6146106f5578063767bcab5146106fd5780637b2c835f1461071d5780638456cb591461073d57806384b0196e14610752578063899308a81461077a5780638ada6b0f146107985780638d11ce40146107b85780638da5cb5b146107d857806395d89b41146107f1578063a22cb46514610806578063a5a2d09714610826578063aa271e1a14610855578063abf410e514610875578063affed0e0146108a9578063b4800cdc146108d0578063b88d4fde146108f2578063bb3bafd614610912578063c87b56dd14610940578063c97f333b14610960578063cb53b24b14610980578063d04bae67146109ef578063d2789d3014610a0f578063da0239a614610a2f578063deefe1fa14610a44578063e8a3d48514610a64578063e985e9c514610a79578063f04e283e14610a99578063f10fb58414610aac578063f2fde38b14610ad3578063f46a04eb14610ae6578063fc91501114610b06578063fee81cf414610b38578063ffa9066814610b6b575b600080fd5b3480156102ce57600080fd5b506102e26102dd366004614343565b610b8e565b60405190151581526020015b60405180910390f35b34801561030357600080fd5b506010546040805160a08101825260115460ff80821615158352610100820416151560208301526201000081046001600160781b031692820192909252600160881b82046001600160581b03166060820152600160e01b90910463ffffffff166080820152610379916001600160a01b03169082565b6040516102ee9291906143a9565b34801561039357600080fd5b5061039c610be0565b6040516102ee9190614416565b3480156103b557600080fd5b506103c96103c4366004614429565b610c93565b6040516102ee9190614442565b3480156103e257600080fd5b506103c97f000000000000000000000000000000000000000000000000000000000000000081565b34801561041657600080fd5b5061042a61042536600461447b565b610cba565b005b34801561043857600080fd5b5061042a6104473660046144eb565b610dd4565b34801561045857600080fd5b5061042a610467366004614543565b610e9a565b34801561047857600080fd5b5061042a6104873660046147f8565b610eb6565b34801561049857600080fd5b5061042a6104a7366004614840565b610f5c565b3480156104b857600080fd5b50600e546104cc906001600160601b031681565b6040516001600160601b0390911681526020016102ee565b3480156104f057600080fd5b5061042a6104ff3660046148b6565b611010565b34801561051057600080fd5b5061042a61051f36600461490a565b611072565b34801561053057600080fd5b5061042a61053f366004614927565b6110d5565b61042a611106565b34801561055857600080fd5b5061056c610567366004614968565b611155565b604080516001600160a01b0390931683526020830191909152016102ee565b34801561059757600080fd5b5061042a611223565b3480156105ac57600080fd5b5061042a6105bb366004614927565b6112e7565b3480156105cc57600080fd5b5061042a6105db366004614429565b611302565b3480156105ec57600080fd5b5061042a6105fb366004614a8b565b6113a2565b61042a6117cc565b34801561061457600080fd5b5061042a610623366004614bad565b611808565b34801561063457600080fd5b506102e260085462010000900460ff1690565b34801561065357600080fd5b5061042a6106623660046148b6565b611956565b34801561067357600080fd5b5061068761068236600461490a565b6119f7565b6040519081526020016102ee565b3480156106a157600080fd5b506103c96106b0366004614429565b611a7b565b3480156106c157600080fd5b5061042a6106d03660046148b6565b611aaf565b3480156106e157600080fd5b506106876106f036600461490a565b611b00565b61042a611b86565b34801561070957600080fd5b5061042a61071836600461490a565b611b9a565b34801561072957600080fd5b5061042a610738366004614be2565b611cbb565b34801561074957600080fd5b5061042a611d2e565b34801561075e57600080fd5b50610767611df2565b6040516102ee9796959493929190614c3b565b34801561078657600080fd5b506010546001600160a01b03166103c9565b3480156107a457600080fd5b50600f546103c9906001600160a01b031681565b3480156107c457600080fd5b5061042a6107d3366004614cab565b611e7b565b3480156107e457600080fd5b50638b78c6d819546103c9565b3480156107fd57600080fd5b5061039c611ea6565b34801561081257600080fd5b5061042a610821366004614d16565b611ed5565b34801561083257600080fd5b50610846610841366004614429565b611ee0565b6040516102ee93929190614d4f565b34801561086157600080fd5b506102e261087036600461490a565b611f95565b34801561088157600080fd5b506103c97f000000000000000000000000000000000000000000000000000000000000000081565b3480156108b557600080fd5b50600f546104cc90600160a01b90046001600160601b031681565b3480156108dc57600080fd5b506108e5611fb6565b6040516102ee9190614db9565b3480156108fe57600080fd5b5061042a61090d366004614dcc565b61201b565b34801561091e57600080fd5b5061093261092d366004614429565b612053565b6040516102ee929190614e37565b34801561094c57600080fd5b5061039c61095b366004614429565b6121fe565b34801561096c57600080fd5b5061042a61097b366004614e5c565b6122d0565b34801561098c57600080fd5b506109c861099b366004614429565b600a602052600090815260409020546001600160a01b03811690600160a01b90046001600160601b031682565b604080516001600160a01b0390931683526001600160601b039091166020830152016102ee565b3480156109fb57600080fd5b50610687610a0a366004614bad565b6123cb565b348015610a1b57600080fd5b5061042a610a2a366004614968565b612443565b348015610a3b57600080fd5b506106876124d7565b348015610a5057600080fd5b5061042a610a5f366004614e77565b612512565b348015610a7057600080fd5b5061039c612526565b348015610a8557600080fd5b506102e2610a94366004614ed6565b61259d565b61042a610aa736600461490a565b6125cb565b348015610ab857600080fd5b50600e546103c990600160601b90046001600160a01b031681565b61042a610ae136600461490a565b612608565b348015610af257600080fd5b5061042a610b01366004614be2565b61262f565b348015610b1257600080fd5b506009546109c8906001600160a01b03811690600160a01b90046001600160601b031682565b348015610b4457600080fd5b50610687610b5336600461490a565b63389a75e1600c908152600091909152602090205490565b348015610b7757600080fd5b50610b80612674565b6040516102ee929190614f04565b60006001600160e01b031982166380ac58cd60e01b1480610bbf57506001600160e01b03198216635b5e139f60e01b145b80610bda57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60606000610bef600b54612715565b50600b5490915015610c015780610c8d565b600c8054610c0e90614f2e565b80601f0160208091040260200160405190810160405280929190818152602001828054610c3a90614f2e565b8015610c875780601f10610c5c57610100808354040283529160200191610c87565b820191906000526020600020905b815481529060010190602001808311610c6a57829003601f168201915b50505050505b91505090565b6000610c9e82612751565b506000908152600460205260409020546001600160a01b031690565b6000610cc582611a7b565b9050806001600160a01b0316836001600160a01b031603610d375760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b0382161480610d535750610d53813361259d565b610dc55760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610d2e565b610dcf8383612776565b505050565b604051632474521560e21b8152600080516020615c98833981519152906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906391d1485490610e329084903390600401614f62565b602060405180830381865afa158015610e4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e739190614f79565b610e90576040516354bff84560e11b815260040160405180910390fd5b610dcf83836127e4565b610ea2612821565b610eaf858585858561283c565b5050505050565b610ebe612821565b60115460ff1615610ee257604051634a324f2160e11b815260040160405180910390fd5b60125460005b81811015610f4257600060106002018281548110610f0857610f08614f96565b60009182526020808320909101546001600160a01b031682526013905260409020805460ff19166001908117909155919091019050610ee8565b50610f4f601260006142fb565b610f58826128f2565b5050565b610f6533611f95565b610f82576040516308bd068960e41b815260040160405180910390fd5b610f8a612c3b565b60115460ff16610fad57604051630d0ca57160e21b815260040160405180910390fd5b600e546001600160601b031660005b83811015610fea57610fe285610fd184614fc2565b9350836001600160601b0316612c8d565b600101610fbc565b50600e80546001600160601b0319166001600160601b0392909216919091179055505050565b611018612821565b611020612c3b565b600e8054610dcf91859160009061103f906001600160601b0316614fc2565b91906101000a8154816001600160601b0302191690836001600160601b0316021790556001600160601b03168484612d4c565b61107a612821565b611082612c3b565b600e80546110d29183916000906110a1906001600160601b0316614fc2565b91906101000a8154816001600160601b0302191690836001600160601b0316021790556001600160601b0316612c8d565b50565b6110df3382612e51565b6110fb5760405162461bcd60e51b8152600401610d2e90614ff0565b610dcf838383612eaf565b60006202a3006001600160401b03164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b6000828152600a6020526040812080548291906001600160a01b03161580159061118f57508054600160a01b90046001600160601b031615155b156111ad57604051636ee13f7960e11b815260040160405180910390fd5b6009546001600160a01b03161580156111d65750600954600160a01b90046001600160601b0316155b156111e1575061121c565b6009546001600160a01b03811693506127109061120e90600160a01b90046001600160601b03168661503d565b611218919061506a565b9150505b9250929050565b604051632474521560e21b8152600080516020615c98833981519152906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906391d14854906112819084903390600401614f62565b602060405180830381865afa15801561129e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c29190614f79565b6112df576040516354bff84560e11b815260040160405180910390fd5b6110d2613001565b610dcf8383836040518060200160405280600081525061201b565b61130a612c3b565b601154610100900460ff166113325760405163055bfda960e21b815260040160405180910390fd5b61133c3382612e51565b6113595760405163ea8e4eb560e01b815260040160405180910390fd5b6113628161304f565b600e805460009061137b906001600160601b031661507e565b91906101000a8154816001600160601b0302191690836001600160601b0316021790555050565b600854610100900460ff16158080156113c25750600854600160ff909116105b806113e357506113d1306130d2565b1580156113e3575060085460ff166001145b6114465760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610d2e565b6008805460ff191660011790558015611469576008805461ff0019166101001790555b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663670017f46040518163ffffffff1660e01b8152600401600060405180830381865afa1580156114c9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526114f191908101906150e6565b50505093505050506115028d6130e1565b6115155761151081426151ab565b611517565b425b63ffffffff1660808c018190526365e0b810111561153757611537613193565b8a601060010160008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a8154816001600160781b0302191690836001600160781b0316021790555060608201518160000160116101000a8154816001600160581b0302191690836001600160581b03160217905550608082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555090505089601481816116109190615338565b50611623905060a08d0160808e0161490a565b600e80546001600160a01b0392909216600160601b026001600160601b0390921691909117905561165a60c08d0160a08e0161490a565b600f80546001600160a01b0319166001600160a01b03929092169190911790556116838d6131d4565b611695611690898b61544c565b6128f2565b6116ba6116a560408e018e615459565b8e80606001906116b59190615459565b6131fe565b6116c7878787878761283c565b6116e96116d48d806151cf565b8e80602001906116e491906151cf565b613315565b6116fe6116f960c08e018e615459565b6127e4565b600061170d60e08e018e6151cf565b9050111561172a5761172a61172560e08e018e6151cf565b6133bb565b6010546040516001600160a01b03909116907f23590eb5e7d2b7c44bee8243c998b8d6a9e31fe210ff6456d1483aba94204e9a9061176f908e908e908e908e90615510565b60405180910390a25080156117be576008805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050505050505050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b604051632474521560e21b81527f6bd6b5318a46e5fff572d5e4258a20774aab40cc35ac7680654b9081fcc82f80906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906391d14854906118789084903390600401614f62565b602060405180830381865afa158015611895573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b99190614f79565b6118d6576040516354bff84560e11b815260040160405180910390fd5b60146118e3838583615272565b507fb3d9642254c3192516d57a0ead79e37af105dd10093d4d0f262031a755bb86128383604051611915929190615651565b60405180910390a1600e54604051600080516020615c7883398151915291611949916001916001600160601b031690615665565b60405180910390a1505050565b61195e612821565b6000611969846119f7565b905061197681848461344a565b600f80546001600160a01b0319166001600160a01b0386169081179091556040517f482cbbbcf912da3be80deb8503ae1e94c0b7d5d1d0ec0af3d9d6403e06e609ee90600090a2600e54604051600080516020615c78833981519152916119e9916001916001600160601b031690615665565b60405180910390a150505050565b600f54604080517fd8843ff55286e2fb28551f1fdd8f11788a72deed64ef1f43d5a0807f38274b5460208201526001600160a01b03841691810191909152600160a01b9091046001600160601b031660608201526000908190608001604051602081830303815290604052805190602001209050611a74816135a6565b9392505050565b600080611a87836135d3565b90506001600160a01b038116610bda5760405162461bcd60e51b8152600401610d2e9061567c565b611ab833611f95565b611ad5576040516308bd068960e41b815260040160405180910390fd5b611add612c3b565b60115460ff1661102057604051630d0ca57160e21b815260040160405180910390fd5b60006001600160a01b038216611b6a5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610d2e565b506001600160a01b031660009081526003602052604090205490565b611b8e612821565b611b9860006135ee565b565b604051632474521560e21b81527fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906391d1485490611c0a9084903390600401614f62565b602060405180830381865afa158015611c27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4b9190614f79565b611c68576040516354bff84560e11b815260040160405180910390fd5b600e80546001600160601b0316600160601b6001600160a01b038516908102919091179091556040517f6e62e73badc47d5a0cd306cabd5fd4caa6c4964747a6f280da30bca7f5f55d4790600090a25050565b611cc3612821565b611ccb6124d7565b15611ce9576040516333a5288560e01b815260040160405180910390fd5b6011805461ff001916610100831515908102919091179091556040517fa3ac2654f732d046febe839fc0a468e86425b99e90c3ffa1a508faf6ea7f71b690600090a250565b604051632474521560e21b8152600080516020615c98833981519152906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906391d1485490611d8c9084903390600401614f62565b602060405180830381865afa158015611da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dcd9190614f79565b611dea576040516354bff84560e11b815260040160405180910390fd5b6110d2613193565b600060608082808083611e267f0000000000000000000000000000000000000000000000000000000000000000600661361a565b611e517f0000000000000000000000000000000000000000000000000000000000000000600761361a565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b611e83612821565b6000611e8f85856123cb565b9050611e9c81848461344a565b610eaf85856133bb565b60606000611eb5600b54612715565b600b54909250159050611ec85780610c8d565b600d8054610c0e90614f2e565b610f583383836136c5565b6016602052600090815260409020805460018201546002830180546001600160a01b03909316939192611f1290614f2e565b80601f0160208091040260200160405190810160405280929190818152602001828054611f3e90614f2e565b8015611f8b5780601f10611f6057610100808354040283529160200191611f8b565b820191906000526020600020905b815481529060010190602001808311611f6e57829003601f168201915b5050505050905083565b6001600160a01b031660009081526013602052604090205460ff1660021490565b6060601060020180548060200260200160405190810160405280929190818152602001828054801561201157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611ff3575b5050505050905090565b6120253383612e51565b6120415760405162461bcd60e51b8152600401610d2e90614ff0565b61204d8484848461378f565b50505050565b6000818152600a60205260409020805460609182916001600160a01b03161580159061208f57508054600160a01b90046001600160601b031615155b1561214857604080516002808252606082018352909160208301908036833750506040805160028082526060820183529396509291506020830190803683375050825485519294506001600160a01b03169185915060019081106120f5576120f5614f96565b6001600160a01b03929092166020928302919091019091015280548251600160a01b9091046001600160601b0316908390600190811061213757612137614f96565b602002602001018181525050612189565b604080516001808252818301909252906020808301908036833750506040805160018082528183019092529295509050602080830190803683370190505091505b60095483516001600160a01b039091169084906000906121ab576121ab614f96565b6001600160a01b0392909216602092830291909101909101526009548251600160a01b9091046001600160601b03169083906000906121ec576121ec614f96565b60200260200101818152505050915091565b606061220982612751565b6015546000838152601660209081526040808320805460018201549251949561224a956014956001600160a01b03928316959390921693600201910161572b565b60408051601f1981840301815290829052600f54634bda247160e11b83529092506001600160a01b0316906397b448e29061228b908690859060040161577a565b600060405180830381865afa1580156122a8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611a749190810190615793565b6122d8612821565b6011546001600160781b03620100009091048116908216811115806123105750600e546001600160601b03166001600160781b038316105b1561232e5760405163162908e360e11b815260040160405180910390fd5b6011805462010000600160881b031916620100006001600160781b03851690810291909117909155600003612387576040517fba23d4377813233c514b11e4a43ff9d9f429206f025d4cc5d9b828d25293d69190600090a15b816001600160781b0316816001600160781b03167fa4bc58713200ce29ea90cd13b98272fd7ed533f83933e6319ae0dac4fcdb2a7860405160405180910390a35050565b6000807f75cc6f0e6b83422eac1bcdaa50c48bb1649f2b39705873f1b36a243680e1da9b8484600f60149054906101000a90046001600160601b031660405160200161241a94939291906157c7565b60405160208183030381529060405280519060200120905061243b816135a6565b949350505050565b600e54600160601b90046001600160a01b031633146124755760405163ea8e4eb560e01b815260040160405180910390fd5b600082815260166020908152604091829020600101839055600e5491518381528492600160601b90046001600160a01b0316917f428aa48406af6213e3f02ecdb4612033f2360931d30d79433527d42f60dbb441910160405180910390a35050565b600e54601154600091612504916001600160601b03909116906201000090046001600160781b03166157fa565b6001600160781b0316905090565b61251a612821565b61204d848484846131fe565b600f546040805163e8a3d48560e01b815290516060926001600160a01b03169163e8a3d4859160048083019260009291908290030181865afa158015612570573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125989190810190615793565b905090565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b6125d3612821565b63389a75e1600c52806000526020600c2080544211156125fb57636f5e88186000526004601cfd5b600090556110d2816135ee565b612610612821565b8060601b61262657637448fbae6000526004601cfd5b6110d2816135ee565b612637612821565b6011805460ff19168215159081179091556040517f30d46918504e7d4aa88713881c9c85ce8224770ba203947f54b221f303b6581e90600090a250565b60148054819061268390614f2e565b80601f01602080910402602001604051908101604052809291908181526020018280546126af90614f2e565b80156126fc5780601f106126d1576101008083540402835291602001916126fc565b820191906000526020600020905b8154815290600101906020018083116126df57829003601f168201915b505050600190930154919250506001600160a01b031682565b604080516080810182526000808252918101828152601f820193909352805181016020018051605f830152829052825181016060019190915291565b61275a816137c2565b6110d25760405162461bcd60e51b8152600401610d2e9061567c565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906127ab82611a7b565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b7f91d93ab23c0e928561b37be74dc3858c4f7f90f67399c0e151f266b47b79a0f3828260405161281592919061581a565b60405180910390a15050565b638b78c6d819543314611b98576382b429006000526004601cfd5b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663670017f46040518163ffffffff1660e01b8152600401600060405180830381865afa15801561289d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128c591908101906150e6565b5050505092505091506128dc8787878786866137cd565b6128e98787878787613882565b50505050505050565b6040805160608101825260008082526020820181905291810182905281908190601154600160e01b810463ffffffff16906201000090046001600160781b031660005b8751811015612bf95787818151811061295057612950614f96565b602002602001015160000151965087818151811061297057612970614f96565b6020026020010151602001519350836000015195507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166391d148547f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6896040518363ffffffff1660e01b81526004016129f3929190614f62565b602060405180830381865afa158015612a10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a349190614f79565b612a515760405163955c501b60e01b815260040160405180910390fd5b856001600160401b0316600003612a8d578263ffffffff164211612a7b578263ffffffff16612a7d565b425b6001600160401b03168452612abd565b8263ffffffff16866001600160401b03161015612abd57604051632ca4094f60e21b815260040160405180910390fd5b856001600160401b031684602001516001600160401b03161015612af4576040516338af65f760e01b815260040160405180910390fd5b6001600160781b0382811614612b16576040840151612b139086615853565b94505b6001600160a01b0387166000818152601360205260408120805460ff191660021790556012805460018101825591527fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec34440180546001600160a01b03191682179055885163b490abde9086908b9085908110612b9357612b93614f96565b6020026020010151604001516040518363ffffffff1660e01b8152600401612bbc929190615873565b600060405180830381600087803b158015612bd657600080fd5b505af1158015612bea573d6000803e3d6000fd5b50505050806001019050612935565b506001600160781b03818116146128e957612c126124d7565b846001600160801b031611156128e9576040516374a5d1f560e01b815260040160405180910390fd5b612c4d60085462010000900460ff1690565b15611b985760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610d2e565b612c956124d7565b600003612cb557604051630cea840760e21b815260040160405180910390fd5b612cbf82826139d9565b6000818152601660205260409081902080546001600160a01b0319166001600160a01b0385811691909117909155600e549151637363ae1f60e01b815260048101849052600160601b9092041690637363ae1f90602401600060405180830381600087803b158015612d3057600080fd5b505af1158015612d44573d6000803e3d6000fd5b505050505050565b612d546124d7565b600003612d7457604051630cea840760e21b815260040160405180910390fd5b601154600160881b90046001600160581b0316811115612da757604051637b1dafd160e01b815260040160405180910390fd5b612db184846139d9565b600083815260166020526040902080546001600160a01b0319166001600160a01b038616178155600201612de6828483615272565b50600e54604051637363ae1f60e01b815260048101859052600160601b9091046001600160a01b031690637363ae1f90602401600060405180830381600087803b158015612e3357600080fd5b505af1158015612e47573d6000803e3d6000fd5b5050505050505050565b600080612e5d83611a7b565b9050806001600160a01b0316846001600160a01b03161480612e845750612e84818561259d565b8061243b5750836001600160a01b0316612e9d84610c93565b6001600160a01b031614949350505050565b826001600160a01b0316612ec282611a7b565b6001600160a01b031614612ee85760405162461bcd60e51b8152600401610d2e906158ba565b6001600160a01b038216612f4a5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610d2e565b826001600160a01b0316612f5d82611a7b565b6001600160a01b031614612f835760405162461bcd60e51b8152600401610d2e906158ba565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b038781168086526003855283862080546000190190559087168086528386208054600101905586865260029094528285208054909216841790915590518493600080516020615cd883398151915291a4505050565b613009613ad4565b6008805462ff0000191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516130459190614442565b60405180910390a1565b600061305a82611a7b565b905061306582611a7b565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b038516808552600384528285208054600019019055878552600290935281842080549091169055519293508492600080516020615cd8833981519152908390a45050565b6001600160a01b03163b151590565b604051632474521560e21b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906391d1485490613152907f828634d95e775031b9ff576b159a8509d3053581a8c9c4d7d86899e0afcd882f908690600401614f62565b602060405180830381865afa15801561316f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bda9190614f79565b61319b612c3b565b6008805462ff00001916620100001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586130383390565b6001600160a01b0316638b78c6d819819055806000600080516020615cb88339815191528180a350565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663670017f46040518163ffffffff1660e01b8152600401600060405180830381865afa15801561325f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261328791908101906150e6565b50505050509150915061329e8686868686866137cd565b60006132ac87878787613b29565b601080546001600160a01b0319166001600160a01b038316908117909155604051919250907fe23144dec9bf1b1786319285dc69eeda2c69e3ba61733d644b0f9ae4b038160c90613304908a908a908a908a90615978565b60405180910390a250505050505050565b600061338a85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f89018190048102820181019092528781529250879150869081908401838280828437600092019190915250613c4e92505050565b9050806133b257600c61339e858783615272565b50600d6133ac838583615272565b50610eaf565b600b5550505050565b60006133fc83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613c7a92505050565b601580546001600160a01b0319166001600160a01b0383161790556040519091507fa56408ec42f6ae6eb5833e81c6d78552ec855069a998e6e5135757b6cbc52d0390611949908390614442565b600061348c8484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613cdf92505050565b604051632474521560e21b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906391d14854906134fd907fe2f4eaae4a9751e85a3e4a7b9587827a877f29914755229b07a7b2da98285f70908590600401614f62565b602060405180830381865afa15801561351a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061353e9190614f79565b61355b576040516354bff84560e11b815260040160405180910390fd5b600f8054600160a01b90046001600160601b031690601461357b83614fc2565b91906101000a8154816001600160601b0302191690836001600160601b031602179055505050505050565b6000610bda6135b3613d03565b8360405161190160f01b8152600281019290925260228201526042902090565b6000908152600260205260409020546001600160a01b031690565b638b78c6d81980546001600160a01b03909216918290600080516020615cb8833981519152600080a355565b606060ff83146136345761362d83613e2e565b9050610bda565b81805461364090614f2e565b80601f016020809104026020016040519081016040528092919081815260200182805461366c90614f2e565b80156136b95780601f1061368e576101008083540402835291602001916136b9565b820191906000526020600020905b81548152906001019060200180831161369c57829003601f168201915b50505050509050610bda565b816001600160a01b0316836001600160a01b0316036137225760405162461bcd60e51b815260206004820152601960248201527822a9219b99189d1030b8383937bb32903a379031b0b63632b960391b6044820152606401610d2e565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b61379a848484612eaf565b6137a684848484613e6d565b61204d5760405162461bcd60e51b8152600401610d2e906159aa565b6000610bda82613f72565b6000805b8481101561386357836001600160a01b03168888838181106137f5576137f5614f96565b905060200201602081019061380a919061490a565b6001600160a01b031614801561385157508263ffffffff1686868381811061383457613834614f96565b905060200201602081019061384991906159fc565b63ffffffff16145b1561385b57600191505b6001016137d1565b50806128e957604051633480121760e21b815260040160405180910390fd5b6138f185858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250869250613f8f915050565b600084158061390757506001600160601b038216155b1561391657600060095561395d565b60018511156139325761392b86868686613b29565b905061395d565b8585600081811061394557613945614f96565b905060200201602081019061395a919061490a565b90505b6040805180820182526001600160a01b0383168082526001600160601b0385166020909201829052600160a01b909102811760095590517fd66d466679c2c45ae9b8d9075963b125eea6b1b6b34c40869a9b8ba8f873dca6906139c99089908990899089908990615a19565b60405180910390a2505050505050565b6001600160a01b038216613a2f5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610d2e565b613a38816137c2565b15613a555760405162461bcd60e51b8152600401610d2e90615a5b565b613a5e816137c2565b15613a7b5760405162461bcd60e51b8152600401610d2e90615a5b565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b031916841790555183929190600080516020615cd8833981519152908290a45050565b613ae660085462010000900460ff1690565b611b985760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610d2e565b6040516352844dd360e01b8152600090732ed6c4b5da6378c7897ac67ba9e43102feb694ee906352844dd390613b6b9088908890889088908890600401615a91565b602060405180830381865afa158015613b88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bac9190615ad1565b9050806001600160a01b03163b60000361243b57604051633b00fbc160e11b8152732ed6c4b5da6378c7897ac67ba9e43102feb694ee90637601f78290613c029088908890889088906000908190600401615aee565b6020604051808303816000875af1158015613c21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c459190615ad1565b50949350505050565b60008251601e600184518301031081601e850103518286015183601f0360031b1b170291505092915050565b600080613ca583604051602001613c919190615b3f565b604051602081830303815290604052614066565b90508051602082016000f091506001600160a01b038216613cd95760405163046a55db60e11b815260040160405180910390fd5b50919050565b6000806000613cee8585614092565b91509150613cfb816140d4565b509392505050565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015613d5c57507f000000000000000000000000000000000000000000000000000000000000000046145b15613d8657507f000000000000000000000000000000000000000000000000000000000000000090565b612598604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60606000613e3b83614219565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b6000613e81846001600160a01b03166130d2565b15613f6a57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290613eb8903390899088908890600401615b65565b6020604051808303816000875af1925050508015613ef3575060408051601f3d908101601f19168201909252613ef091810190615ba2565b60015b613f50573d808015613f21576040519150601f19603f3d011682016040523d82523d6000602084013e613f26565b606091505b508051600003613f485760405162461bcd60e51b8152600401610d2e906159aa565b805181602001fd5b6001600160e01b031916630a85bd0160e11b14905061243b565b50600161243b565b600080613f7e836135d3565b6001600160a01b0316141592915050565b815183518114613fb5576040516001621398b960e31b0319815260040160405180910390fd5b6127106001600160601b03831610613fe0576040516307555b5f60e31b815260040160405180910390fd5b60005b81811015610eaf576109c46001600160601b0316620f424063ffffffff168486848151811061401457614014614f96565b602002602001015163ffffffff1661402c9190615bbf565b6140369190615bea565b6001600160601b0316111561405e576040516376a3022160e11b815260040160405180910390fd5b600101613fe3565b606081518260405160200161407c929190615c10565b6040516020818303038152906040529050919050565b60008082516041036140c85760208301516040840151606085015160001a6140bc87828585614241565b9450945050505061121c565b5060009050600261121c565b60008160048111156140e8576140e8615c61565b036140f05750565b600181600481111561410457614104615c61565b0361414c5760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b6044820152606401610d2e565b600281600481111561416057614160615c61565b036141ad5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d2e565b60038160048111156141c1576141c1615c61565b036110d25760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610d2e565b600060ff8216601f811115610bda57604051632cd44ac360e21b815260040160405180910390fd5b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b0383111561426e57506000905060036142f2565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156142c2573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166142eb576000600192509250506142f2565b9150600090505b94509492505050565b50805460008255906000526020600020908101906110d291905b808211156143295760008155600101614315565b5090565b6001600160e01b0319811681146110d257600080fd5b60006020828403121561435557600080fd5b8135611a748161432d565b8051151582526020808201511515908301526040808201516001600160781b0316908301526060808201516001600160581b03169083015260809081015163ffffffff16910152565b6001600160a01b038316815260c08101611a746020830184614360565b60005b838110156143e15781810151838201526020016143c9565b50506000910152565b600081518084526144028160208601602086016143c6565b601f01601f19169290920160200192915050565b602081526000611a7460208301846143ea565b60006020828403121561443b57600080fd5b5035919050565b6001600160a01b0391909116815260200190565b6001600160a01b03811681146110d257600080fd5b803561447681614456565b919050565b6000806040838503121561448e57600080fd5b823561449981614456565b946020939093013593505050565b60008083601f8401126144b957600080fd5b5081356001600160401b038111156144d057600080fd5b6020830191508360208260051b850101111561121c57600080fd5b600080602083850312156144fe57600080fd5b82356001600160401b0381111561451457600080fd5b614520858286016144a7565b90969095509350505050565b80356001600160601b038116811461447657600080fd5b60008060008060006060868803121561455b57600080fd5b85356001600160401b038082111561457257600080fd5b61457e89838a016144a7565b9097509550602088013591508082111561459757600080fd5b506145a4888289016144a7565b90945092506145b790506040870161452c565b90509295509295909350565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b03811182821017156145fb576145fb6145c3565b60405290565b604051601f8201601f191681016001600160401b0381118282101715614629576146296145c3565b604052919050565b6001600160401b03811681146110d257600080fd5b80356001600160801b038116811461447657600080fd5b60006001600160401b03821115614676576146766145c3565b50601f01601f191660200190565b600082601f83011261469557600080fd5b81356146a86146a38261465d565b614601565b8181528460208386010111156146bd57600080fd5b816020850160208301376000918101602001919091529392505050565b60006001600160401b03808411156146f4576146f46145c3565b8360051b6020614705818301614601565b8681529350908401908084018783111561471e57600080fd5b855b838110156147ec578035858111156147385760008081fd5b8701808a0360a081121561474c5760008081fd5b6147546145d9565b823561475f81614456565b81526060601f1983018113156147755760008081fd5b61477d6145d9565b92508684013561478c81614631565b835260408481013561479d81614631565b848901526147ac858301614646565b81850152838884015260808501359350898411156147cc57600091508182fd5b6147d88e858701614684565b908301525084525050908201908201614720565b50505050509392505050565b60006020828403121561480a57600080fd5b81356001600160401b0381111561482057600080fd5b8201601f8101841361483157600080fd5b61243b848235602084016146da565b60008060006060848603121561485557600080fd5b833561486081614456565b95602085013595506040909401359392505050565b60008083601f84011261488757600080fd5b5081356001600160401b0381111561489e57600080fd5b60208301915083602082850101111561121c57600080fd5b6000806000604084860312156148cb57600080fd5b83356148d681614456565b925060208401356001600160401b038111156148f157600080fd5b6148fd86828701614875565b9497909650939450505050565b60006020828403121561491c57600080fd5b8135611a7481614456565b60008060006060848603121561493c57600080fd5b833561494781614456565b9250602084013561495781614456565b929592945050506040919091013590565b6000806040838503121561497b57600080fd5b50508035926020909101359150565b60006101008284031215613cd957600080fd5b80151581146110d257600080fd5b80356001600160781b038116811461447657600080fd5b63ffffffff811681146110d257600080fd5b600060a082840312156149e657600080fd5b60405160a081016001600160401b0381118282101715614a0857614a086145c3565b6040529050808235614a198161499d565b81526020830135614a298161499d565b6020820152614a3a604084016149ab565b604082015260608301356001600160581b0381168114614a5957600080fd5b60608201526080830135614a6c816149c2565b6080919091015292915050565b600060408284031215613cd957600080fd5b60008060008060008060008060008060006101808c8e031215614aad57600080fd5b614ab68c61446b565b9a506001600160401b0360208d0135811015614ad157600080fd5b614ae18e60208f01358f0161498a565b9a50614af08e60408f016149d4565b99508060e08e01351115614b0357600080fd5b614b138e60e08f01358f01614a79565b9850806101008e01351115614b2757600080fd5b614b388e6101008f01358f016144a7565b90985096506101208d0135811015614b4f57600080fd5b614b608e6101208f01358f016144a7565b90965094506101408d0135811015614b7757600080fd5b50614b898d6101408e01358e016144a7565b9093509150614b9b6101608d0161452c565b90509295989b509295989b9093969950565b60008060208385031215614bc057600080fd5b82356001600160401b03811115614bd657600080fd5b61452085828601614875565b600060208284031215614bf457600080fd5b8135611a748161499d565b60008151808452602080850194506020840160005b83811015614c3057815187529582019590820190600101614c14565b509495945050505050565b60ff60f81b8816815260e060208201526000614c5a60e08301896143ea565b8281036040840152614c6c81896143ea565b606084018890526001600160a01b038716608085015260a0840186905283810360c08501529050614c9d8185614bff565b9a9950505050505050505050565b60008060008060408587031215614cc157600080fd5b84356001600160401b0380821115614cd857600080fd5b614ce488838901614875565b90965094506020870135915080821115614cfd57600080fd5b50614d0a87828801614875565b95989497509550505050565b60008060408385031215614d2957600080fd5b8235614d3481614456565b91506020830135614d448161499d565b809150509250929050565b60018060a01b0384168152826020820152606060408201526000614d7660608301846143ea565b95945050505050565b60008151808452602080850194506020840160005b83811015614c305781516001600160a01b031687529582019590820190600101614d94565b602081526000611a746020830184614d7f565b60008060008060808587031215614de257600080fd5b8435614ded81614456565b93506020850135614dfd81614456565b92506040850135915060608501356001600160401b03811115614e1f57600080fd5b614e2b87828801614684565b91505092959194509250565b604081526000614e4a6040830185614d7f565b8281036020840152614d768185614bff565b600060208284031215614e6e57600080fd5b611a74826149ab565b60008060008060408587031215614e8d57600080fd5b84356001600160401b0380821115614ea457600080fd5b614eb0888389016144a7565b90965094506020870135915080821115614ec957600080fd5b50614d0a878288016144a7565b60008060408385031215614ee957600080fd5b8235614ef481614456565b91506020830135614d4481614456565b604081526000614f1760408301856143ea565b905060018060a01b03831660208301529392505050565b600181811c90821680614f4257607f821691505b602082108103613cd957634e487b7160e01b600052602260045260246000fd5b9182526001600160a01b0316602082015260400190565b600060208284031215614f8b57600080fd5b8151611a748161499d565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001600160601b038281166002600160601b03198101614fe657614fe6614fac565b6001019392505050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b8082028115828204841417610bda57610bda614fac565b634e487b7160e01b600052601260045260246000fd5b60008261507957615079615054565b500490565b60006001600160601b0382168061509757615097614fac565b6000190192915050565b600082601f8301126150b257600080fd5b81516150c06146a38261465d565b8181528460208386010111156150d557600080fd5b61243b8260208301602087016143c6565b600080600080600080600060e0888a03121561510157600080fd5b875161510c81614456565b602089015190975061511d816149c2565b604089015190965061512e816149c2565b606089015190955061513f816149c2565b608089015190945061515081614631565b60a08901519093506001600160401b038082111561516d57600080fd5b6151798b838c016150a1565b935060c08a015191508082111561518f57600080fd5b5061519c8a828b016150a1565b91505092959891949750929550565b63ffffffff8181168382160190808211156151c8576151c8614fac565b5092915050565b6000808335601e198436030181126151e657600080fd5b8301803591506001600160401b0382111561520057600080fd5b60200191503681900382131561121c57600080fd5b601f821115610dcf576000816000526020600020601f850160051c8101602086101561523e5750805b601f850160051c820191505b81811015612d445782815560010161524a565b600019600383901b1c191660019190911b1790565b6001600160401b03831115615289576152896145c3565b61529d836152978354614f2e565b83615215565b6000601f8411600181146152cb57600085156152b95750838201355b6152c3868261525d565b845550610eaf565b600083815260209020601f19861690835b828110156152fc57868501358255602094850194600190920191016152dc565b50868210156153195760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60008135610bda81614456565b8135601e1983360301811261534c57600080fd5b820180356001600160401b0381111561536457600080fd5b6020813603818401131561537757600080fd5b61538b826153858654614f2e565b86615215565b6000601f8311600181146153bb57600084156153a957508482018301355b6153b3858261525d565b875550615418565b600086815260209020601f19851690835b828110156153ed5787850186013582559385019360019091019085016153cc565b508582101561540c5760001960f88760031b161c198585890101351681555b505060018460011b0186555b5050610eaf61542882870161532b565b6001860180546001600160a01b0319166001600160a01b0392909216919091179055565b6000611a743684846146da565b6000808335601e1984360301811261547057600080fd5b8301803591506001600160401b0382111561548a57600080fd5b6020019150600581901b360382131561121c57600080fd5b6000808335601e198436030181126154b957600080fd5b83016020810192503590506001600160401b038111156154d857600080fd5b80360382131561121c57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b61551a8186614360565b600060a060e060a084015261552f86876154a2565b60408060e0870152615546610120870183856154e7565b9250602091508189013561555981614456565b6001600160a01b0390811661010088015286840360c088015287845282840190600589901b850184018a6000805b8c81101561563d57888403601f190186528235368f9003609e190181126155ac578283fd5b8e0180356155b981614456565b86168552808901356155ca81614631565b6001600160401b03908116868b015281890135906155e782614631565b168589015260606001600160801b03615601838301614646565b16908601526080615614828201836154a2565b92508c828801526156288d880184836154e7565b988b0198965050509288019250600101615587565b50919e9d5050505050505050505050505050565b60208152600061243b6020830184866154e7565b9182526001600160601b0316602082015260400190565b602080825260189082015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604082015260600190565b600081546156bb81614f2e565b8085526020600183811680156156d857600181146156f257615720565b60ff1985168884015283151560051b880183019550615720565b866000528260002060005b858110156157185781548a82018601529083019084016156fd565b890184019650505b505050505092915050565b60a08152600061573e60a08301886156ae565b6001600160a01b0387811660208501528616604084015260608301859052828103608084015261576e81856156ae565b98975050505050505050565b82815260406020820152600061243b60408301846143ea565b6000602082840312156157a557600080fd5b81516001600160401b038111156157bb57600080fd5b61243b848285016150a1565b8481526060602082015260006157e16060830185876154e7565b905060018060601b038316604083015295945050505050565b6001600160781b038281168282160390808211156151c8576151c8614fac565b6020808252810182905260006001600160fb1b0383111561583a57600080fd5b8260051b80856040850137919091016040019392505050565b6001600160801b038181168382160190808211156151c8576151c8614fac565b82516001600160401b039081168252602080850151909116908201526040838101516001600160801b03169082015260806060820181905260009061243b908301846143ea565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b8183526000602080850194508260005b85811015614c3057813561592281614456565b6001600160a01b03168752958201959082019060010161590f565b8183526000602080850194508260005b85811015614c30578135615960816149c2565b63ffffffff168752958201959082019060010161594d565b60408152600061598c6040830186886158ff565b828103602084015261599f81858761593d565b979650505050505050565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b600060208284031215615a0e57600080fd5b8135611a74816149c2565b606081526000615a2d6060830187896158ff565b8281036020840152615a4081868861593d565b91505060018060601b03831660408301529695505050505050565b6020808252601c908201527b115490cdcc8c4e881d1bdad95b88185b1c9958591e481b5a5b9d195960221b604082015260600190565b606081526000615aa56060830187896158ff565b8281036020840152615ab881868861593d565b91505063ffffffff831660408301529695505050505050565b600060208284031215615ae357600080fd5b8151611a7481614456565b608081526000615b0260808301888a6158ff565b8281036020840152615b1581878961593d565b63ffffffff95909516604084015250506001600160a01b0391909116606090910152949350505050565b6000815260008251615b588160018501602087016143c6565b9190910160010192915050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090615b98908301846143ea565b9695505050505050565b600060208284031215615bb457600080fd5b8151611a748161432d565b6001600160601b03818116838216028082169190828114615be257615be2614fac565b505092915050565b60006001600160601b0383811680615c0457615c04615054565b92169190910492915050565b606360f81b815260e083901b6001600160e01b03191660018201526880600e6000396000f360b81b60058201528151600090615c5381600e8501602087016143c6565b91909101600e019392505050565b634e487b7160e01b600052602160045260246000fdfe6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c71f3d55856e4058ed06ee057d79ada615f65cdf5f9ee88181b914225088f834f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212204797a087bfb97d73b359de8e1e19072dcacc43799151f8088f79b9b88864ae6364736f6c63430008170033000000000000000000000000ca6e30b1c7cbe7cf605ce30b334f968c5e2ea0160000000000000000000000008d3c748e99066e15425ba1620cdd066d85d6d918
Deployed Bytecode
0x6080604052600436106102bd5760003560e01c806301ffc9a7146102c257806303bbc8ab146102f757806306fdde0314610387578063081812fc146103a957806308c73259146103d6578063095ea7b31461040a5780630ba1baf21461042c5780630f686cfe1461044c578063124f76cb1461046c578063156e29f61461048c57806318160ddd146104ac5780631ca6bf46146104e45780631e3bcc8e1461050457806323b872dd1461052457806325692962146105445780632a55205a1461054c5780633f4ba83a1461058b57806342842e0e146105a057806342966c68146105c05780634e313ed1146105e057806354d1f13d1461060057806355e42958146106085780635c975abb146106285780635f44f1eb146106475780635f5ef7aa146106675780636352211e146106955780636848fb51146106b557806370a08231146106d5578063715018a6146106f5578063767bcab5146106fd5780637b2c835f1461071d5780638456cb591461073d57806384b0196e14610752578063899308a81461077a5780638ada6b0f146107985780638d11ce40146107b85780638da5cb5b146107d857806395d89b41146107f1578063a22cb46514610806578063a5a2d09714610826578063aa271e1a14610855578063abf410e514610875578063affed0e0146108a9578063b4800cdc146108d0578063b88d4fde146108f2578063bb3bafd614610912578063c87b56dd14610940578063c97f333b14610960578063cb53b24b14610980578063d04bae67146109ef578063d2789d3014610a0f578063da0239a614610a2f578063deefe1fa14610a44578063e8a3d48514610a64578063e985e9c514610a79578063f04e283e14610a99578063f10fb58414610aac578063f2fde38b14610ad3578063f46a04eb14610ae6578063fc91501114610b06578063fee81cf414610b38578063ffa9066814610b6b575b600080fd5b3480156102ce57600080fd5b506102e26102dd366004614343565b610b8e565b60405190151581526020015b60405180910390f35b34801561030357600080fd5b506010546040805160a08101825260115460ff80821615158352610100820416151560208301526201000081046001600160781b031692820192909252600160881b82046001600160581b03166060820152600160e01b90910463ffffffff166080820152610379916001600160a01b03169082565b6040516102ee9291906143a9565b34801561039357600080fd5b5061039c610be0565b6040516102ee9190614416565b3480156103b557600080fd5b506103c96103c4366004614429565b610c93565b6040516102ee9190614442565b3480156103e257600080fd5b506103c97f0000000000000000000000008d3c748e99066e15425ba1620cdd066d85d6d91881565b34801561041657600080fd5b5061042a61042536600461447b565b610cba565b005b34801561043857600080fd5b5061042a6104473660046144eb565b610dd4565b34801561045857600080fd5b5061042a610467366004614543565b610e9a565b34801561047857600080fd5b5061042a6104873660046147f8565b610eb6565b34801561049857600080fd5b5061042a6104a7366004614840565b610f5c565b3480156104b857600080fd5b50600e546104cc906001600160601b031681565b6040516001600160601b0390911681526020016102ee565b3480156104f057600080fd5b5061042a6104ff3660046148b6565b611010565b34801561051057600080fd5b5061042a61051f36600461490a565b611072565b34801561053057600080fd5b5061042a61053f366004614927565b6110d5565b61042a611106565b34801561055857600080fd5b5061056c610567366004614968565b611155565b604080516001600160a01b0390931683526020830191909152016102ee565b34801561059757600080fd5b5061042a611223565b3480156105ac57600080fd5b5061042a6105bb366004614927565b6112e7565b3480156105cc57600080fd5b5061042a6105db366004614429565b611302565b3480156105ec57600080fd5b5061042a6105fb366004614a8b565b6113a2565b61042a6117cc565b34801561061457600080fd5b5061042a610623366004614bad565b611808565b34801561063457600080fd5b506102e260085462010000900460ff1690565b34801561065357600080fd5b5061042a6106623660046148b6565b611956565b34801561067357600080fd5b5061068761068236600461490a565b6119f7565b6040519081526020016102ee565b3480156106a157600080fd5b506103c96106b0366004614429565b611a7b565b3480156106c157600080fd5b5061042a6106d03660046148b6565b611aaf565b3480156106e157600080fd5b506106876106f036600461490a565b611b00565b61042a611b86565b34801561070957600080fd5b5061042a61071836600461490a565b611b9a565b34801561072957600080fd5b5061042a610738366004614be2565b611cbb565b34801561074957600080fd5b5061042a611d2e565b34801561075e57600080fd5b50610767611df2565b6040516102ee9796959493929190614c3b565b34801561078657600080fd5b506010546001600160a01b03166103c9565b3480156107a457600080fd5b50600f546103c9906001600160a01b031681565b3480156107c457600080fd5b5061042a6107d3366004614cab565b611e7b565b3480156107e457600080fd5b50638b78c6d819546103c9565b3480156107fd57600080fd5b5061039c611ea6565b34801561081257600080fd5b5061042a610821366004614d16565b611ed5565b34801561083257600080fd5b50610846610841366004614429565b611ee0565b6040516102ee93929190614d4f565b34801561086157600080fd5b506102e261087036600461490a565b611f95565b34801561088157600080fd5b506103c97f000000000000000000000000ca6e30b1c7cbe7cf605ce30b334f968c5e2ea01681565b3480156108b557600080fd5b50600f546104cc90600160a01b90046001600160601b031681565b3480156108dc57600080fd5b506108e5611fb6565b6040516102ee9190614db9565b3480156108fe57600080fd5b5061042a61090d366004614dcc565b61201b565b34801561091e57600080fd5b5061093261092d366004614429565b612053565b6040516102ee929190614e37565b34801561094c57600080fd5b5061039c61095b366004614429565b6121fe565b34801561096c57600080fd5b5061042a61097b366004614e5c565b6122d0565b34801561098c57600080fd5b506109c861099b366004614429565b600a602052600090815260409020546001600160a01b03811690600160a01b90046001600160601b031682565b604080516001600160a01b0390931683526001600160601b039091166020830152016102ee565b3480156109fb57600080fd5b50610687610a0a366004614bad565b6123cb565b348015610a1b57600080fd5b5061042a610a2a366004614968565b612443565b348015610a3b57600080fd5b506106876124d7565b348015610a5057600080fd5b5061042a610a5f366004614e77565b612512565b348015610a7057600080fd5b5061039c612526565b348015610a8557600080fd5b506102e2610a94366004614ed6565b61259d565b61042a610aa736600461490a565b6125cb565b348015610ab857600080fd5b50600e546103c990600160601b90046001600160a01b031681565b61042a610ae136600461490a565b612608565b348015610af257600080fd5b5061042a610b01366004614be2565b61262f565b348015610b1257600080fd5b506009546109c8906001600160a01b03811690600160a01b90046001600160601b031682565b348015610b4457600080fd5b50610687610b5336600461490a565b63389a75e1600c908152600091909152602090205490565b348015610b7757600080fd5b50610b80612674565b6040516102ee929190614f04565b60006001600160e01b031982166380ac58cd60e01b1480610bbf57506001600160e01b03198216635b5e139f60e01b145b80610bda57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60606000610bef600b54612715565b50600b5490915015610c015780610c8d565b600c8054610c0e90614f2e565b80601f0160208091040260200160405190810160405280929190818152602001828054610c3a90614f2e565b8015610c875780601f10610c5c57610100808354040283529160200191610c87565b820191906000526020600020905b815481529060010190602001808311610c6a57829003601f168201915b50505050505b91505090565b6000610c9e82612751565b506000908152600460205260409020546001600160a01b031690565b6000610cc582611a7b565b9050806001600160a01b0316836001600160a01b031603610d375760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b0382161480610d535750610d53813361259d565b610dc55760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610d2e565b610dcf8383612776565b505050565b604051632474521560e21b8152600080516020615c98833981519152906001600160a01b037f0000000000000000000000008d3c748e99066e15425ba1620cdd066d85d6d91816906391d1485490610e329084903390600401614f62565b602060405180830381865afa158015610e4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e739190614f79565b610e90576040516354bff84560e11b815260040160405180910390fd5b610dcf83836127e4565b610ea2612821565b610eaf858585858561283c565b5050505050565b610ebe612821565b60115460ff1615610ee257604051634a324f2160e11b815260040160405180910390fd5b60125460005b81811015610f4257600060106002018281548110610f0857610f08614f96565b60009182526020808320909101546001600160a01b031682526013905260409020805460ff19166001908117909155919091019050610ee8565b50610f4f601260006142fb565b610f58826128f2565b5050565b610f6533611f95565b610f82576040516308bd068960e41b815260040160405180910390fd5b610f8a612c3b565b60115460ff16610fad57604051630d0ca57160e21b815260040160405180910390fd5b600e546001600160601b031660005b83811015610fea57610fe285610fd184614fc2565b9350836001600160601b0316612c8d565b600101610fbc565b50600e80546001600160601b0319166001600160601b0392909216919091179055505050565b611018612821565b611020612c3b565b600e8054610dcf91859160009061103f906001600160601b0316614fc2565b91906101000a8154816001600160601b0302191690836001600160601b0316021790556001600160601b03168484612d4c565b61107a612821565b611082612c3b565b600e80546110d29183916000906110a1906001600160601b0316614fc2565b91906101000a8154816001600160601b0302191690836001600160601b0316021790556001600160601b0316612c8d565b50565b6110df3382612e51565b6110fb5760405162461bcd60e51b8152600401610d2e90614ff0565b610dcf838383612eaf565b60006202a3006001600160401b03164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b6000828152600a6020526040812080548291906001600160a01b03161580159061118f57508054600160a01b90046001600160601b031615155b156111ad57604051636ee13f7960e11b815260040160405180910390fd5b6009546001600160a01b03161580156111d65750600954600160a01b90046001600160601b0316155b156111e1575061121c565b6009546001600160a01b03811693506127109061120e90600160a01b90046001600160601b03168661503d565b611218919061506a565b9150505b9250929050565b604051632474521560e21b8152600080516020615c98833981519152906001600160a01b037f0000000000000000000000008d3c748e99066e15425ba1620cdd066d85d6d91816906391d14854906112819084903390600401614f62565b602060405180830381865afa15801561129e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c29190614f79565b6112df576040516354bff84560e11b815260040160405180910390fd5b6110d2613001565b610dcf8383836040518060200160405280600081525061201b565b61130a612c3b565b601154610100900460ff166113325760405163055bfda960e21b815260040160405180910390fd5b61133c3382612e51565b6113595760405163ea8e4eb560e01b815260040160405180910390fd5b6113628161304f565b600e805460009061137b906001600160601b031661507e565b91906101000a8154816001600160601b0302191690836001600160601b0316021790555050565b600854610100900460ff16158080156113c25750600854600160ff909116105b806113e357506113d1306130d2565b1580156113e3575060085460ff166001145b6114465760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610d2e565b6008805460ff191660011790558015611469576008805461ff0019166101001790555b60007f000000000000000000000000ca6e30b1c7cbe7cf605ce30b334f968c5e2ea0166001600160a01b031663670017f46040518163ffffffff1660e01b8152600401600060405180830381865afa1580156114c9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526114f191908101906150e6565b50505093505050506115028d6130e1565b6115155761151081426151ab565b611517565b425b63ffffffff1660808c018190526365e0b810111561153757611537613193565b8a601060010160008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a8154816001600160781b0302191690836001600160781b0316021790555060608201518160000160116101000a8154816001600160581b0302191690836001600160581b03160217905550608082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555090505089601481816116109190615338565b50611623905060a08d0160808e0161490a565b600e80546001600160a01b0392909216600160601b026001600160601b0390921691909117905561165a60c08d0160a08e0161490a565b600f80546001600160a01b0319166001600160a01b03929092169190911790556116838d6131d4565b611695611690898b61544c565b6128f2565b6116ba6116a560408e018e615459565b8e80606001906116b59190615459565b6131fe565b6116c7878787878761283c565b6116e96116d48d806151cf565b8e80602001906116e491906151cf565b613315565b6116fe6116f960c08e018e615459565b6127e4565b600061170d60e08e018e6151cf565b9050111561172a5761172a61172560e08e018e6151cf565b6133bb565b6010546040516001600160a01b03909116907f23590eb5e7d2b7c44bee8243c998b8d6a9e31fe210ff6456d1483aba94204e9a9061176f908e908e908e908e90615510565b60405180910390a25080156117be576008805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050505050505050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b604051632474521560e21b81527f6bd6b5318a46e5fff572d5e4258a20774aab40cc35ac7680654b9081fcc82f80906001600160a01b037f0000000000000000000000008d3c748e99066e15425ba1620cdd066d85d6d91816906391d14854906118789084903390600401614f62565b602060405180830381865afa158015611895573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b99190614f79565b6118d6576040516354bff84560e11b815260040160405180910390fd5b60146118e3838583615272565b507fb3d9642254c3192516d57a0ead79e37af105dd10093d4d0f262031a755bb86128383604051611915929190615651565b60405180910390a1600e54604051600080516020615c7883398151915291611949916001916001600160601b031690615665565b60405180910390a1505050565b61195e612821565b6000611969846119f7565b905061197681848461344a565b600f80546001600160a01b0319166001600160a01b0386169081179091556040517f482cbbbcf912da3be80deb8503ae1e94c0b7d5d1d0ec0af3d9d6403e06e609ee90600090a2600e54604051600080516020615c78833981519152916119e9916001916001600160601b031690615665565b60405180910390a150505050565b600f54604080517fd8843ff55286e2fb28551f1fdd8f11788a72deed64ef1f43d5a0807f38274b5460208201526001600160a01b03841691810191909152600160a01b9091046001600160601b031660608201526000908190608001604051602081830303815290604052805190602001209050611a74816135a6565b9392505050565b600080611a87836135d3565b90506001600160a01b038116610bda5760405162461bcd60e51b8152600401610d2e9061567c565b611ab833611f95565b611ad5576040516308bd068960e41b815260040160405180910390fd5b611add612c3b565b60115460ff1661102057604051630d0ca57160e21b815260040160405180910390fd5b60006001600160a01b038216611b6a5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610d2e565b506001600160a01b031660009081526003602052604090205490565b611b8e612821565b611b9860006135ee565b565b604051632474521560e21b81527fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775906001600160a01b037f0000000000000000000000008d3c748e99066e15425ba1620cdd066d85d6d91816906391d1485490611c0a9084903390600401614f62565b602060405180830381865afa158015611c27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4b9190614f79565b611c68576040516354bff84560e11b815260040160405180910390fd5b600e80546001600160601b0316600160601b6001600160a01b038516908102919091179091556040517f6e62e73badc47d5a0cd306cabd5fd4caa6c4964747a6f280da30bca7f5f55d4790600090a25050565b611cc3612821565b611ccb6124d7565b15611ce9576040516333a5288560e01b815260040160405180910390fd5b6011805461ff001916610100831515908102919091179091556040517fa3ac2654f732d046febe839fc0a468e86425b99e90c3ffa1a508faf6ea7f71b690600090a250565b604051632474521560e21b8152600080516020615c98833981519152906001600160a01b037f0000000000000000000000008d3c748e99066e15425ba1620cdd066d85d6d91816906391d1485490611d8c9084903390600401614f62565b602060405180830381865afa158015611da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dcd9190614f79565b611dea576040516354bff84560e11b815260040160405180910390fd5b6110d2613193565b600060608082808083611e267f467847656e41727437323100000000000000000000000000000000000000000b600661361a565b611e517f3100000000000000000000000000000000000000000000000000000000000001600761361a565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b611e83612821565b6000611e8f85856123cb565b9050611e9c81848461344a565b610eaf85856133bb565b60606000611eb5600b54612715565b600b54909250159050611ec85780610c8d565b600d8054610c0e90614f2e565b610f583383836136c5565b6016602052600090815260409020805460018201546002830180546001600160a01b03909316939192611f1290614f2e565b80601f0160208091040260200160405190810160405280929190818152602001828054611f3e90614f2e565b8015611f8b5780601f10611f6057610100808354040283529160200191611f8b565b820191906000526020600020905b815481529060010190602001808311611f6e57829003601f168201915b5050505050905083565b6001600160a01b031660009081526013602052604090205460ff1660021490565b6060601060020180548060200260200160405190810160405280929190818152602001828054801561201157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611ff3575b5050505050905090565b6120253383612e51565b6120415760405162461bcd60e51b8152600401610d2e90614ff0565b61204d8484848461378f565b50505050565b6000818152600a60205260409020805460609182916001600160a01b03161580159061208f57508054600160a01b90046001600160601b031615155b1561214857604080516002808252606082018352909160208301908036833750506040805160028082526060820183529396509291506020830190803683375050825485519294506001600160a01b03169185915060019081106120f5576120f5614f96565b6001600160a01b03929092166020928302919091019091015280548251600160a01b9091046001600160601b0316908390600190811061213757612137614f96565b602002602001018181525050612189565b604080516001808252818301909252906020808301908036833750506040805160018082528183019092529295509050602080830190803683370190505091505b60095483516001600160a01b039091169084906000906121ab576121ab614f96565b6001600160a01b0392909216602092830291909101909101526009548251600160a01b9091046001600160601b03169083906000906121ec576121ec614f96565b60200260200101818152505050915091565b606061220982612751565b6015546000838152601660209081526040808320805460018201549251949561224a956014956001600160a01b03928316959390921693600201910161572b565b60408051601f1981840301815290829052600f54634bda247160e11b83529092506001600160a01b0316906397b448e29061228b908690859060040161577a565b600060405180830381865afa1580156122a8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611a749190810190615793565b6122d8612821565b6011546001600160781b03620100009091048116908216811115806123105750600e546001600160601b03166001600160781b038316105b1561232e5760405163162908e360e11b815260040160405180910390fd5b6011805462010000600160881b031916620100006001600160781b03851690810291909117909155600003612387576040517fba23d4377813233c514b11e4a43ff9d9f429206f025d4cc5d9b828d25293d69190600090a15b816001600160781b0316816001600160781b03167fa4bc58713200ce29ea90cd13b98272fd7ed533f83933e6319ae0dac4fcdb2a7860405160405180910390a35050565b6000807f75cc6f0e6b83422eac1bcdaa50c48bb1649f2b39705873f1b36a243680e1da9b8484600f60149054906101000a90046001600160601b031660405160200161241a94939291906157c7565b60405160208183030381529060405280519060200120905061243b816135a6565b949350505050565b600e54600160601b90046001600160a01b031633146124755760405163ea8e4eb560e01b815260040160405180910390fd5b600082815260166020908152604091829020600101839055600e5491518381528492600160601b90046001600160a01b0316917f428aa48406af6213e3f02ecdb4612033f2360931d30d79433527d42f60dbb441910160405180910390a35050565b600e54601154600091612504916001600160601b03909116906201000090046001600160781b03166157fa565b6001600160781b0316905090565b61251a612821565b61204d848484846131fe565b600f546040805163e8a3d48560e01b815290516060926001600160a01b03169163e8a3d4859160048083019260009291908290030181865afa158015612570573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125989190810190615793565b905090565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b6125d3612821565b63389a75e1600c52806000526020600c2080544211156125fb57636f5e88186000526004601cfd5b600090556110d2816135ee565b612610612821565b8060601b61262657637448fbae6000526004601cfd5b6110d2816135ee565b612637612821565b6011805460ff19168215159081179091556040517f30d46918504e7d4aa88713881c9c85ce8224770ba203947f54b221f303b6581e90600090a250565b60148054819061268390614f2e565b80601f01602080910402602001604051908101604052809291908181526020018280546126af90614f2e565b80156126fc5780601f106126d1576101008083540402835291602001916126fc565b820191906000526020600020905b8154815290600101906020018083116126df57829003601f168201915b505050600190930154919250506001600160a01b031682565b604080516080810182526000808252918101828152601f820193909352805181016020018051605f830152829052825181016060019190915291565b61275a816137c2565b6110d25760405162461bcd60e51b8152600401610d2e9061567c565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906127ab82611a7b565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b7f91d93ab23c0e928561b37be74dc3858c4f7f90f67399c0e151f266b47b79a0f3828260405161281592919061581a565b60405180910390a15050565b638b78c6d819543314611b98576382b429006000526004601cfd5b6000807f000000000000000000000000ca6e30b1c7cbe7cf605ce30b334f968c5e2ea0166001600160a01b031663670017f46040518163ffffffff1660e01b8152600401600060405180830381865afa15801561289d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128c591908101906150e6565b5050505092505091506128dc8787878786866137cd565b6128e98787878787613882565b50505050505050565b6040805160608101825260008082526020820181905291810182905281908190601154600160e01b810463ffffffff16906201000090046001600160781b031660005b8751811015612bf95787818151811061295057612950614f96565b602002602001015160000151965087818151811061297057612970614f96565b6020026020010151602001519350836000015195507f0000000000000000000000008d3c748e99066e15425ba1620cdd066d85d6d9186001600160a01b03166391d148547f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6896040518363ffffffff1660e01b81526004016129f3929190614f62565b602060405180830381865afa158015612a10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a349190614f79565b612a515760405163955c501b60e01b815260040160405180910390fd5b856001600160401b0316600003612a8d578263ffffffff164211612a7b578263ffffffff16612a7d565b425b6001600160401b03168452612abd565b8263ffffffff16866001600160401b03161015612abd57604051632ca4094f60e21b815260040160405180910390fd5b856001600160401b031684602001516001600160401b03161015612af4576040516338af65f760e01b815260040160405180910390fd5b6001600160781b0382811614612b16576040840151612b139086615853565b94505b6001600160a01b0387166000818152601360205260408120805460ff191660021790556012805460018101825591527fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec34440180546001600160a01b03191682179055885163b490abde9086908b9085908110612b9357612b93614f96565b6020026020010151604001516040518363ffffffff1660e01b8152600401612bbc929190615873565b600060405180830381600087803b158015612bd657600080fd5b505af1158015612bea573d6000803e3d6000fd5b50505050806001019050612935565b506001600160781b03818116146128e957612c126124d7565b846001600160801b031611156128e9576040516374a5d1f560e01b815260040160405180910390fd5b612c4d60085462010000900460ff1690565b15611b985760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610d2e565b612c956124d7565b600003612cb557604051630cea840760e21b815260040160405180910390fd5b612cbf82826139d9565b6000818152601660205260409081902080546001600160a01b0319166001600160a01b0385811691909117909155600e549151637363ae1f60e01b815260048101849052600160601b9092041690637363ae1f90602401600060405180830381600087803b158015612d3057600080fd5b505af1158015612d44573d6000803e3d6000fd5b505050505050565b612d546124d7565b600003612d7457604051630cea840760e21b815260040160405180910390fd5b601154600160881b90046001600160581b0316811115612da757604051637b1dafd160e01b815260040160405180910390fd5b612db184846139d9565b600083815260166020526040902080546001600160a01b0319166001600160a01b038616178155600201612de6828483615272565b50600e54604051637363ae1f60e01b815260048101859052600160601b9091046001600160a01b031690637363ae1f90602401600060405180830381600087803b158015612e3357600080fd5b505af1158015612e47573d6000803e3d6000fd5b5050505050505050565b600080612e5d83611a7b565b9050806001600160a01b0316846001600160a01b03161480612e845750612e84818561259d565b8061243b5750836001600160a01b0316612e9d84610c93565b6001600160a01b031614949350505050565b826001600160a01b0316612ec282611a7b565b6001600160a01b031614612ee85760405162461bcd60e51b8152600401610d2e906158ba565b6001600160a01b038216612f4a5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610d2e565b826001600160a01b0316612f5d82611a7b565b6001600160a01b031614612f835760405162461bcd60e51b8152600401610d2e906158ba565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b038781168086526003855283862080546000190190559087168086528386208054600101905586865260029094528285208054909216841790915590518493600080516020615cd883398151915291a4505050565b613009613ad4565b6008805462ff0000191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516130459190614442565b60405180910390a1565b600061305a82611a7b565b905061306582611a7b565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b038516808552600384528285208054600019019055878552600290935281842080549091169055519293508492600080516020615cd8833981519152908390a45050565b6001600160a01b03163b151590565b604051632474521560e21b81526000906001600160a01b037f0000000000000000000000008d3c748e99066e15425ba1620cdd066d85d6d91816906391d1485490613152907f828634d95e775031b9ff576b159a8509d3053581a8c9c4d7d86899e0afcd882f908690600401614f62565b602060405180830381865afa15801561316f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bda9190614f79565b61319b612c3b565b6008805462ff00001916620100001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586130383390565b6001600160a01b0316638b78c6d819819055806000600080516020615cb88339815191528180a350565b6000807f000000000000000000000000ca6e30b1c7cbe7cf605ce30b334f968c5e2ea0166001600160a01b031663670017f46040518163ffffffff1660e01b8152600401600060405180830381865afa15801561325f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261328791908101906150e6565b50505050509150915061329e8686868686866137cd565b60006132ac87878787613b29565b601080546001600160a01b0319166001600160a01b038316908117909155604051919250907fe23144dec9bf1b1786319285dc69eeda2c69e3ba61733d644b0f9ae4b038160c90613304908a908a908a908a90615978565b60405180910390a250505050505050565b600061338a85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f89018190048102820181019092528781529250879150869081908401838280828437600092019190915250613c4e92505050565b9050806133b257600c61339e858783615272565b50600d6133ac838583615272565b50610eaf565b600b5550505050565b60006133fc83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613c7a92505050565b601580546001600160a01b0319166001600160a01b0383161790556040519091507fa56408ec42f6ae6eb5833e81c6d78552ec855069a998e6e5135757b6cbc52d0390611949908390614442565b600061348c8484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613cdf92505050565b604051632474521560e21b81529091506001600160a01b037f0000000000000000000000008d3c748e99066e15425ba1620cdd066d85d6d91816906391d14854906134fd907fe2f4eaae4a9751e85a3e4a7b9587827a877f29914755229b07a7b2da98285f70908590600401614f62565b602060405180830381865afa15801561351a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061353e9190614f79565b61355b576040516354bff84560e11b815260040160405180910390fd5b600f8054600160a01b90046001600160601b031690601461357b83614fc2565b91906101000a8154816001600160601b0302191690836001600160601b031602179055505050505050565b6000610bda6135b3613d03565b8360405161190160f01b8152600281019290925260228201526042902090565b6000908152600260205260409020546001600160a01b031690565b638b78c6d81980546001600160a01b03909216918290600080516020615cb8833981519152600080a355565b606060ff83146136345761362d83613e2e565b9050610bda565b81805461364090614f2e565b80601f016020809104026020016040519081016040528092919081815260200182805461366c90614f2e565b80156136b95780601f1061368e576101008083540402835291602001916136b9565b820191906000526020600020905b81548152906001019060200180831161369c57829003601f168201915b50505050509050610bda565b816001600160a01b0316836001600160a01b0316036137225760405162461bcd60e51b815260206004820152601960248201527822a9219b99189d1030b8383937bb32903a379031b0b63632b960391b6044820152606401610d2e565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b61379a848484612eaf565b6137a684848484613e6d565b61204d5760405162461bcd60e51b8152600401610d2e906159aa565b6000610bda82613f72565b6000805b8481101561386357836001600160a01b03168888838181106137f5576137f5614f96565b905060200201602081019061380a919061490a565b6001600160a01b031614801561385157508263ffffffff1686868381811061383457613834614f96565b905060200201602081019061384991906159fc565b63ffffffff16145b1561385b57600191505b6001016137d1565b50806128e957604051633480121760e21b815260040160405180910390fd5b6138f185858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250869250613f8f915050565b600084158061390757506001600160601b038216155b1561391657600060095561395d565b60018511156139325761392b86868686613b29565b905061395d565b8585600081811061394557613945614f96565b905060200201602081019061395a919061490a565b90505b6040805180820182526001600160a01b0383168082526001600160601b0385166020909201829052600160a01b909102811760095590517fd66d466679c2c45ae9b8d9075963b125eea6b1b6b34c40869a9b8ba8f873dca6906139c99089908990899089908990615a19565b60405180910390a2505050505050565b6001600160a01b038216613a2f5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610d2e565b613a38816137c2565b15613a555760405162461bcd60e51b8152600401610d2e90615a5b565b613a5e816137c2565b15613a7b5760405162461bcd60e51b8152600401610d2e90615a5b565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b031916841790555183929190600080516020615cd8833981519152908290a45050565b613ae660085462010000900460ff1690565b611b985760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610d2e565b6040516352844dd360e01b8152600090732ed6c4b5da6378c7897ac67ba9e43102feb694ee906352844dd390613b6b9088908890889088908890600401615a91565b602060405180830381865afa158015613b88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bac9190615ad1565b9050806001600160a01b03163b60000361243b57604051633b00fbc160e11b8152732ed6c4b5da6378c7897ac67ba9e43102feb694ee90637601f78290613c029088908890889088906000908190600401615aee565b6020604051808303816000875af1158015613c21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c459190615ad1565b50949350505050565b60008251601e600184518301031081601e850103518286015183601f0360031b1b170291505092915050565b600080613ca583604051602001613c919190615b3f565b604051602081830303815290604052614066565b90508051602082016000f091506001600160a01b038216613cd95760405163046a55db60e11b815260040160405180910390fd5b50919050565b6000806000613cee8585614092565b91509150613cfb816140d4565b509392505050565b6000306001600160a01b037f0000000000000000000000002b55ba516c78b1c1b3dad0d633bf0e9e5181d79e16148015613d5c57507f000000000000000000000000000000000000000000000000000000000000210546145b15613d8657507f354273e4b0c0a6fb8bc5374a3ddab88c8df1ff1e16ff104712c96c5cff858ded90565b612598604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f39df4d366b573dfec71c02353e225a0e9b60ef0e76124c01c27647751d828bad918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60606000613e3b83614219565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b6000613e81846001600160a01b03166130d2565b15613f6a57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290613eb8903390899088908890600401615b65565b6020604051808303816000875af1925050508015613ef3575060408051601f3d908101601f19168201909252613ef091810190615ba2565b60015b613f50573d808015613f21576040519150601f19603f3d011682016040523d82523d6000602084013e613f26565b606091505b508051600003613f485760405162461bcd60e51b8152600401610d2e906159aa565b805181602001fd5b6001600160e01b031916630a85bd0160e11b14905061243b565b50600161243b565b600080613f7e836135d3565b6001600160a01b0316141592915050565b815183518114613fb5576040516001621398b960e31b0319815260040160405180910390fd5b6127106001600160601b03831610613fe0576040516307555b5f60e31b815260040160405180910390fd5b60005b81811015610eaf576109c46001600160601b0316620f424063ffffffff168486848151811061401457614014614f96565b602002602001015163ffffffff1661402c9190615bbf565b6140369190615bea565b6001600160601b0316111561405e576040516376a3022160e11b815260040160405180910390fd5b600101613fe3565b606081518260405160200161407c929190615c10565b6040516020818303038152906040529050919050565b60008082516041036140c85760208301516040840151606085015160001a6140bc87828585614241565b9450945050505061121c565b5060009050600261121c565b60008160048111156140e8576140e8615c61565b036140f05750565b600181600481111561410457614104615c61565b0361414c5760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b6044820152606401610d2e565b600281600481111561416057614160615c61565b036141ad5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610d2e565b60038160048111156141c1576141c1615c61565b036110d25760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610d2e565b600060ff8216601f811115610bda57604051632cd44ac360e21b815260040160405180910390fd5b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b0383111561426e57506000905060036142f2565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156142c2573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166142eb576000600192509250506142f2565b9150600090505b94509492505050565b50805460008255906000526020600020908101906110d291905b808211156143295760008155600101614315565b5090565b6001600160e01b0319811681146110d257600080fd5b60006020828403121561435557600080fd5b8135611a748161432d565b8051151582526020808201511515908301526040808201516001600160781b0316908301526060808201516001600160581b03169083015260809081015163ffffffff16910152565b6001600160a01b038316815260c08101611a746020830184614360565b60005b838110156143e15781810151838201526020016143c9565b50506000910152565b600081518084526144028160208601602086016143c6565b601f01601f19169290920160200192915050565b602081526000611a7460208301846143ea565b60006020828403121561443b57600080fd5b5035919050565b6001600160a01b0391909116815260200190565b6001600160a01b03811681146110d257600080fd5b803561447681614456565b919050565b6000806040838503121561448e57600080fd5b823561449981614456565b946020939093013593505050565b60008083601f8401126144b957600080fd5b5081356001600160401b038111156144d057600080fd5b6020830191508360208260051b850101111561121c57600080fd5b600080602083850312156144fe57600080fd5b82356001600160401b0381111561451457600080fd5b614520858286016144a7565b90969095509350505050565b80356001600160601b038116811461447657600080fd5b60008060008060006060868803121561455b57600080fd5b85356001600160401b038082111561457257600080fd5b61457e89838a016144a7565b9097509550602088013591508082111561459757600080fd5b506145a4888289016144a7565b90945092506145b790506040870161452c565b90509295509295909350565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b03811182821017156145fb576145fb6145c3565b60405290565b604051601f8201601f191681016001600160401b0381118282101715614629576146296145c3565b604052919050565b6001600160401b03811681146110d257600080fd5b80356001600160801b038116811461447657600080fd5b60006001600160401b03821115614676576146766145c3565b50601f01601f191660200190565b600082601f83011261469557600080fd5b81356146a86146a38261465d565b614601565b8181528460208386010111156146bd57600080fd5b816020850160208301376000918101602001919091529392505050565b60006001600160401b03808411156146f4576146f46145c3565b8360051b6020614705818301614601565b8681529350908401908084018783111561471e57600080fd5b855b838110156147ec578035858111156147385760008081fd5b8701808a0360a081121561474c5760008081fd5b6147546145d9565b823561475f81614456565b81526060601f1983018113156147755760008081fd5b61477d6145d9565b92508684013561478c81614631565b835260408481013561479d81614631565b848901526147ac858301614646565b81850152838884015260808501359350898411156147cc57600091508182fd5b6147d88e858701614684565b908301525084525050908201908201614720565b50505050509392505050565b60006020828403121561480a57600080fd5b81356001600160401b0381111561482057600080fd5b8201601f8101841361483157600080fd5b61243b848235602084016146da565b60008060006060848603121561485557600080fd5b833561486081614456565b95602085013595506040909401359392505050565b60008083601f84011261488757600080fd5b5081356001600160401b0381111561489e57600080fd5b60208301915083602082850101111561121c57600080fd5b6000806000604084860312156148cb57600080fd5b83356148d681614456565b925060208401356001600160401b038111156148f157600080fd5b6148fd86828701614875565b9497909650939450505050565b60006020828403121561491c57600080fd5b8135611a7481614456565b60008060006060848603121561493c57600080fd5b833561494781614456565b9250602084013561495781614456565b929592945050506040919091013590565b6000806040838503121561497b57600080fd5b50508035926020909101359150565b60006101008284031215613cd957600080fd5b80151581146110d257600080fd5b80356001600160781b038116811461447657600080fd5b63ffffffff811681146110d257600080fd5b600060a082840312156149e657600080fd5b60405160a081016001600160401b0381118282101715614a0857614a086145c3565b6040529050808235614a198161499d565b81526020830135614a298161499d565b6020820152614a3a604084016149ab565b604082015260608301356001600160581b0381168114614a5957600080fd5b60608201526080830135614a6c816149c2565b6080919091015292915050565b600060408284031215613cd957600080fd5b60008060008060008060008060008060006101808c8e031215614aad57600080fd5b614ab68c61446b565b9a506001600160401b0360208d0135811015614ad157600080fd5b614ae18e60208f01358f0161498a565b9a50614af08e60408f016149d4565b99508060e08e01351115614b0357600080fd5b614b138e60e08f01358f01614a79565b9850806101008e01351115614b2757600080fd5b614b388e6101008f01358f016144a7565b90985096506101208d0135811015614b4f57600080fd5b614b608e6101208f01358f016144a7565b90965094506101408d0135811015614b7757600080fd5b50614b898d6101408e01358e016144a7565b9093509150614b9b6101608d0161452c565b90509295989b509295989b9093969950565b60008060208385031215614bc057600080fd5b82356001600160401b03811115614bd657600080fd5b61452085828601614875565b600060208284031215614bf457600080fd5b8135611a748161499d565b60008151808452602080850194506020840160005b83811015614c3057815187529582019590820190600101614c14565b509495945050505050565b60ff60f81b8816815260e060208201526000614c5a60e08301896143ea565b8281036040840152614c6c81896143ea565b606084018890526001600160a01b038716608085015260a0840186905283810360c08501529050614c9d8185614bff565b9a9950505050505050505050565b60008060008060408587031215614cc157600080fd5b84356001600160401b0380821115614cd857600080fd5b614ce488838901614875565b90965094506020870135915080821115614cfd57600080fd5b50614d0a87828801614875565b95989497509550505050565b60008060408385031215614d2957600080fd5b8235614d3481614456565b91506020830135614d448161499d565b809150509250929050565b60018060a01b0384168152826020820152606060408201526000614d7660608301846143ea565b95945050505050565b60008151808452602080850194506020840160005b83811015614c305781516001600160a01b031687529582019590820190600101614d94565b602081526000611a746020830184614d7f565b60008060008060808587031215614de257600080fd5b8435614ded81614456565b93506020850135614dfd81614456565b92506040850135915060608501356001600160401b03811115614e1f57600080fd5b614e2b87828801614684565b91505092959194509250565b604081526000614e4a6040830185614d7f565b8281036020840152614d768185614bff565b600060208284031215614e6e57600080fd5b611a74826149ab565b60008060008060408587031215614e8d57600080fd5b84356001600160401b0380821115614ea457600080fd5b614eb0888389016144a7565b90965094506020870135915080821115614ec957600080fd5b50614d0a878288016144a7565b60008060408385031215614ee957600080fd5b8235614ef481614456565b91506020830135614d4481614456565b604081526000614f1760408301856143ea565b905060018060a01b03831660208301529392505050565b600181811c90821680614f4257607f821691505b602082108103613cd957634e487b7160e01b600052602260045260246000fd5b9182526001600160a01b0316602082015260400190565b600060208284031215614f8b57600080fd5b8151611a748161499d565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001600160601b038281166002600160601b03198101614fe657614fe6614fac565b6001019392505050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b8082028115828204841417610bda57610bda614fac565b634e487b7160e01b600052601260045260246000fd5b60008261507957615079615054565b500490565b60006001600160601b0382168061509757615097614fac565b6000190192915050565b600082601f8301126150b257600080fd5b81516150c06146a38261465d565b8181528460208386010111156150d557600080fd5b61243b8260208301602087016143c6565b600080600080600080600060e0888a03121561510157600080fd5b875161510c81614456565b602089015190975061511d816149c2565b604089015190965061512e816149c2565b606089015190955061513f816149c2565b608089015190945061515081614631565b60a08901519093506001600160401b038082111561516d57600080fd5b6151798b838c016150a1565b935060c08a015191508082111561518f57600080fd5b5061519c8a828b016150a1565b91505092959891949750929550565b63ffffffff8181168382160190808211156151c8576151c8614fac565b5092915050565b6000808335601e198436030181126151e657600080fd5b8301803591506001600160401b0382111561520057600080fd5b60200191503681900382131561121c57600080fd5b601f821115610dcf576000816000526020600020601f850160051c8101602086101561523e5750805b601f850160051c820191505b81811015612d445782815560010161524a565b600019600383901b1c191660019190911b1790565b6001600160401b03831115615289576152896145c3565b61529d836152978354614f2e565b83615215565b6000601f8411600181146152cb57600085156152b95750838201355b6152c3868261525d565b845550610eaf565b600083815260209020601f19861690835b828110156152fc57868501358255602094850194600190920191016152dc565b50868210156153195760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60008135610bda81614456565b8135601e1983360301811261534c57600080fd5b820180356001600160401b0381111561536457600080fd5b6020813603818401131561537757600080fd5b61538b826153858654614f2e565b86615215565b6000601f8311600181146153bb57600084156153a957508482018301355b6153b3858261525d565b875550615418565b600086815260209020601f19851690835b828110156153ed5787850186013582559385019360019091019085016153cc565b508582101561540c5760001960f88760031b161c198585890101351681555b505060018460011b0186555b5050610eaf61542882870161532b565b6001860180546001600160a01b0319166001600160a01b0392909216919091179055565b6000611a743684846146da565b6000808335601e1984360301811261547057600080fd5b8301803591506001600160401b0382111561548a57600080fd5b6020019150600581901b360382131561121c57600080fd5b6000808335601e198436030181126154b957600080fd5b83016020810192503590506001600160401b038111156154d857600080fd5b80360382131561121c57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b61551a8186614360565b600060a060e060a084015261552f86876154a2565b60408060e0870152615546610120870183856154e7565b9250602091508189013561555981614456565b6001600160a01b0390811661010088015286840360c088015287845282840190600589901b850184018a6000805b8c81101561563d57888403601f190186528235368f9003609e190181126155ac578283fd5b8e0180356155b981614456565b86168552808901356155ca81614631565b6001600160401b03908116868b015281890135906155e782614631565b168589015260606001600160801b03615601838301614646565b16908601526080615614828201836154a2565b92508c828801526156288d880184836154e7565b988b0198965050509288019250600101615587565b50919e9d5050505050505050505050505050565b60208152600061243b6020830184866154e7565b9182526001600160601b0316602082015260400190565b602080825260189082015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604082015260600190565b600081546156bb81614f2e565b8085526020600183811680156156d857600181146156f257615720565b60ff1985168884015283151560051b880183019550615720565b866000528260002060005b858110156157185781548a82018601529083019084016156fd565b890184019650505b505050505092915050565b60a08152600061573e60a08301886156ae565b6001600160a01b0387811660208501528616604084015260608301859052828103608084015261576e81856156ae565b98975050505050505050565b82815260406020820152600061243b60408301846143ea565b6000602082840312156157a557600080fd5b81516001600160401b038111156157bb57600080fd5b61243b848285016150a1565b8481526060602082015260006157e16060830185876154e7565b905060018060601b038316604083015295945050505050565b6001600160781b038281168282160390808211156151c8576151c8614fac565b6020808252810182905260006001600160fb1b0383111561583a57600080fd5b8260051b80856040850137919091016040019392505050565b6001600160801b038181168382160190808211156151c8576151c8614fac565b82516001600160401b039081168252602080850151909116908201526040838101516001600160801b03169082015260806060820181905260009061243b908301846143ea565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b8183526000602080850194508260005b85811015614c3057813561592281614456565b6001600160a01b03168752958201959082019060010161590f565b8183526000602080850194508260005b85811015614c30578135615960816149c2565b63ffffffff168752958201959082019060010161594d565b60408152600061598c6040830186886158ff565b828103602084015261599f81858761593d565b979650505050505050565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b600060208284031215615a0e57600080fd5b8135611a74816149c2565b606081526000615a2d6060830187896158ff565b8281036020840152615a4081868861593d565b91505060018060601b03831660408301529695505050505050565b6020808252601c908201527b115490cdcc8c4e881d1bdad95b88185b1c9958591e481b5a5b9d195960221b604082015260600190565b606081526000615aa56060830187896158ff565b8281036020840152615ab881868861593d565b91505063ffffffff831660408301529695505050505050565b600060208284031215615ae357600080fd5b8151611a7481614456565b608081526000615b0260808301888a6158ff565b8281036020840152615b1581878961593d565b63ffffffff95909516604084015250506001600160a01b0391909116606090910152949350505050565b6000815260008251615b588160018501602087016143c6565b9190910160010192915050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090615b98908301846143ea565b9695505050505050565b600060208284031215615bb457600080fd5b8151611a748161432d565b6001600160601b03818116838216028082169190828114615be257615be2614fac565b505092915050565b60006001600160601b0383811680615c0457615c04615054565b92169190910492915050565b606360f81b815260e083901b6001600160e01b03191660018201526880600e6000396000f360b81b60058201528151600090615c5381600e8501602087016143c6565b91909101600e019392505050565b634e487b7160e01b600052602160045260246000fdfe6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c71f3d55856e4058ed06ee057d79ada615f65cdf5f9ee88181b914225088f834f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212204797a087bfb97d73b359de8e1e19072dcacc43799151f8088f79b9b88864ae6364736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ca6e30b1c7cbe7cf605ce30b334f968c5e2ea0160000000000000000000000008d3c748e99066e15425ba1620cdd066d85d6d918
-----Decoded View---------------
Arg [0] : _contractRegistry (address): 0xCa6e30B1C7cBE7cF605cE30B334f968C5E2EA016
Arg [1] : _roleRegistry (address): 0x8d3C748e99066e15425BA1620cdD066d85D6d918
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000ca6e30b1c7cbe7cf605ce30b334f968c5e2ea016
Arg [1] : 0000000000000000000000008d3c748e99066e15425ba1620cdd066d85d6d918
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.