More Info
Private Name Tags
ContractCreator
Loading...
Loading
Contract Name:
BlastrNFT
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 300 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.21; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Base64.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import "../interfaces/IERC4906.sol"; import "../interfaces/IBlastrStorage.sol"; import "../interfaces/IBlastrNFT.sol"; import "../interfaces/IBlast.sol"; import "../interfaces/IBlastPoints.sol"; import "./BlastrLibrary.sol"; /// @author BLASTR team /// @title Refundable NFTs implementation contract BlastrNFT is ERC721Enumerable, IERC4906, Ownable, ReentrancyGuard { using ECDSA for bytes32; using Counters for Counters.Counter; using Strings for uint256; struct Lock { uint128 value; uint64 lockPeriod; uint64 lockedAt; } Counters.Counter private _tokenId; Counters.Counter private _keyHoldersMints; string private _tokenName; string private _tokenSymbol; uint256 public tvl; uint256 public maxSupply; uint256 public publicMintStartTime; address public factoryAddress; address public referrer; address public whitelistSigner; string public baseURI; string public preRevealImageURI; bool public initialized; IBlastrStorage public blastrStorage; uint256[] public refundedTokens; BlastrLibrary.MintConfig public publicMintConfig; BlastrLibrary.MintConfig public privateMintConfig; mapping(uint256 => Lock) public locks; // tokenId -> Lock mapping(uint256 => uint256) public upgradedAt; // tokenId -> upgradedAt mapping(address => uint256) private _publicMintsPerWallet; // address -> nb tokens minted mapping(address => uint256) private _privateMintsPerWallet; // address -> nb tokens minted mapping(uint256 => uint256) private _keyHoldersMintsPerToken; // tokenId -> nb tokens minted event Refund(uint256 tokenId, address indexed by, uint256 value); event Upgrade(uint256 tokenId, address indexed by, uint256 value); event GasFeesClaim(address owner, uint256 minClaimRateBips); event PublicMintStateUpdate(address owner, bool active); event PrivateMintStateUpdate(address owner, bool active); event WhitelistSignerUpdate(address owner, address whitelistSigner); event BaseUriUpdate(address owner, string baseURI); event PreRevealImageUriUpdate(address owner, string preRevealImageURI); event PublicMintConfigUpdate( address owner, uint128 mintPrice, uint64 lockPeriod, uint24 maxMintsPerTransaction, uint24 maxMintsPerWallet, bool active ); event PrivateMintConfigUpdate( address owner, uint128 mintPrice, uint64 lockPeriod, uint24 maxMintsPerTransaction, uint24 maxMintsPerWallet, bool active ); event Mint( uint256[] tokenIds, address indexed minter, address indexed recipient, uint128 value, uint24 quantity, uint64 lockPeriod, string mintType ); event YieldClaim( address owner, address protocolFeeCollector, address referrer, uint256 ownerYield, uint256 protocolYield, uint256 referrerYield ); error AlreadyInitialized(); error IncorrectMaxSupply(); error TransferFailed(); constructor() ERC721("", "") {} /* External functions */ function publicMint(uint24 _quantity) external payable nonReentrant { require(publicMintConfig.active, "Public mint is not active"); // First 5 min (300s) of the public mint are reserved for BLASTR key holders if (block.timestamp - publicMintStartTime < 300) { uint256 keysBalance = IBlastrNFT(blastrStorage.NFTContractAddress()).balanceOf(msg.sender); require (keysBalance > 0 && _quantity <= keysBalance, "The first 5 min of public mint are reserved for BLASTR key holders (max mint quantity: 1 per key owned)"); require (_keyHoldersMints.current() + _quantity <= maxSupply / 20, "Must not mint more than 5% of total supply"); uint256[] memory keysOwned = IBlastrNFT(blastrStorage.NFTContractAddress()).tokensOwnedBy(msg.sender); uint256 keysUsed = 0; for (uint256 i = 0; i < keysBalance; i++) { uint256 ownedTokenId = keysOwned[i]; if (_keyHoldersMintsPerToken[ownedTokenId] == 0) { _keyHoldersMintsPerToken[ownedTokenId] = 1; _keyHoldersMints.increment(); keysUsed++; if (keysUsed == _quantity) { break; } } } require(keysUsed == _quantity, "You don't own enough keys to mint asked quantity"); } require(_isNull(publicMintConfig.maxMintsPerTransaction) || _quantity <= publicMintConfig.maxMintsPerTransaction, "Exceeds max mints per transaction"); require(_isNull(publicMintConfig.maxMintsPerWallet) || _publicMintsPerWallet[msg.sender] + _quantity <= publicMintConfig.maxMintsPerWallet, "Exceeds max mints per wallet"); _publicMintsPerWallet[msg.sender] += _quantity; _mint(msg.sender, publicMintConfig.mintPrice, publicMintConfig.lockPeriod, _quantity, uint128(msg.value), 'public'); } function privateMint(uint24 _quantity, bytes memory _signature) external payable nonReentrant { require(privateMintConfig.active, "Private mint is not active"); require(_isNull(privateMintConfig.maxMintsPerTransaction) || _quantity <= privateMintConfig.maxMintsPerTransaction, "Exceeds max mints per transaction"); require(_isNull(privateMintConfig.maxMintsPerWallet) || _privateMintsPerWallet[msg.sender] + _quantity <= privateMintConfig.maxMintsPerWallet, "Exceeds max mints per wallet"); address recoveredAddress = keccak256(abi.encodePacked(msg.sender)).toEthSignedMessageHash().recover(_signature); require(recoveredAddress == whitelistSigner, "Your wallet is not whitelisted."); _privateMintsPerWallet[msg.sender] += _quantity; _mint(msg.sender, privateMintConfig.mintPrice, privateMintConfig.lockPeriod, _quantity, uint128(msg.value), 'private'); } // Refunds and burns the tokenId, tokenId can be re-minted later function refund(uint256 tokenId_) external nonReentrant { require(_exists(tokenId_), "Token ID does not exist"); require(ownerOf(tokenId_) == msg.sender, "Not the NFT owner"); Lock memory lock = locks[tokenId_]; require(lock.value > 0, "Nothing to refund"); address blastrKeysAddress = blastrStorage.NFTContractAddress(); if ( IBlastrNFT(blastrKeysAddress).balanceOf(msg.sender) == 0 || blastrKeysAddress == address(this) ) { require(block.timestamp >= lock.lockedAt + lock.lockPeriod, "Lock period not expired"); } emit Refund(tokenId_, msg.sender, lock.value); emit MetadataUpdate(tokenId_); _burn(tokenId_); // Transfer deposited ether to the msg.sender (bool success, ) = payable(msg.sender).call{value: lock.value}(""); if (!success) revert TransferFailed(); // Delete the Lock from the mapping delete locks[tokenId_]; // Add the token ID to the refundedTokens array refundedTokens.push(tokenId_); // Update TVL tvl -= lock.value; } // Caution: this method will release the funds that have been locked during the mint for a specific NFT to the owner function upgrade(uint256 tokenId_) external nonReentrant { require(_exists(tokenId_), "Token ID does not exist"); require(upgradedAt[tokenId_] == 0, "Already upgraded"); require(ownerOf(tokenId_) == msg.sender, "Not the NFT owner"); Lock memory lock = locks[tokenId_]; emit Upgrade(tokenId_, msg.sender, lock.value); emit MetadataUpdate(tokenId_); // Transfer locked ether to the owner (bool success, ) = payable(owner()).call{value: lock.value}(""); if (!success) revert TransferFailed(); // Delete the Lock from the mapping delete locks[tokenId_]; // Update TVL tvl -= lock.value; // Register the upgrade upgradedAt[tokenId_] = block.timestamp; } function claimYield() external nonReentrant { uint256 _claimableYield = claimableYield(); require(_claimableYield > 0, 'No yield to claim.'); uint256 protocolYield = 0; uint256 referrerYield = 0; uint256 contractYield = _claimableYield; address blastrKeysAddress = blastrStorage.NFTContractAddress(); address protocolFeeCollector = blastrStorage.feeCollector(); uint256 protocolFee = blastrStorage.protocolFee(); uint256 referrerFee = blastrStorage.referrerFee(); IBlastrNFT blastrKeysContract = IBlastrNFT(blastrKeysAddress); if (protocolFee > 0) { // If the owner owns a Blastr Key NFT if (blastrKeysContract.balanceOf(owner()) > 0) { // If the owner holds at least one upgraded token, no fees are applied uint256[] memory keysOwned = blastrKeysContract.tokensOwnedBy(owner()); bool ownerHoldsUpgradedToken; for (uint256 i = 0; i < keysOwned.length; i++) { uint256 ownedTokenId = keysOwned[i]; if (blastrKeysContract.upgradedAt(ownedTokenId) != 0) { ownerHoldsUpgradedToken = true; break; } } if (!ownerHoldsUpgradedToken) { // If no upgraded tokens held by the owner, only apply the discount (fees reduced by a factor of 5) // Else no fees are applied protocolYield = _claimableYield * protocolFee / 10000 / 5; contractYield -= protocolYield; } } else { protocolYield = _claimableYield * protocolFee / 10000; contractYield -= protocolYield; } } // Transfer contractYield to the owner (bool successContractYield, ) = payable(owner()).call{value: contractYield}(""); if (!successContractYield) revert TransferFailed(); if (protocolYield > 0) { // Transfer referrerYield to the referrer address if (referrer != address(0)) { if (referrerFee > 0) { referrerYield = protocolYield * referrerFee / 10000; (bool successReferrerYield, ) = payable(referrer).call{value: referrerYield}(""); if (!successReferrerYield) revert TransferFailed(); protocolYield -= referrerYield; } } // Transfer protocolYeld to the feeCollector (bool successProtocolYield, ) = payable(protocolFeeCollector).call{value: protocolYield}(""); if (!successProtocolYield) revert TransferFailed(); } emit YieldClaim( owner(), protocolFeeCollector, referrer, contractYield, protocolYield, referrerYield ); } function flipPublicMintState() external onlyOwner { publicMintConfig.active = !publicMintConfig.active; if (publicMintConfig.active) { publicMintStartTime = block.timestamp; } emit PublicMintStateUpdate(owner(), publicMintConfig.active); } function flipPrivateMintState() external onlyOwner { privateMintConfig.active = !privateMintConfig.active; emit PrivateMintStateUpdate(owner(), privateMintConfig.active); } function setPublicMintConfig(BlastrLibrary.MintConfig memory _publicMintConfig) external onlyOwner { bool wasActiveBefore = publicMintConfig.active; publicMintConfig = _publicMintConfig; if (!wasActiveBefore && publicMintConfig.active) { publicMintStartTime = block.timestamp; } emit PublicMintConfigUpdate( owner(), _publicMintConfig.mintPrice, _publicMintConfig.lockPeriod, _publicMintConfig.maxMintsPerTransaction, _publicMintConfig.maxMintsPerWallet, _publicMintConfig.active ); } function setPrivateMintConfig(BlastrLibrary.MintConfig memory _privateMintConfig) external onlyOwner { privateMintConfig = _privateMintConfig; emit PrivateMintConfigUpdate( owner(), _privateMintConfig.mintPrice, _privateMintConfig.lockPeriod, _privateMintConfig.maxMintsPerTransaction, _privateMintConfig.maxMintsPerWallet, _privateMintConfig.active ); } function setPreRevealImageURI(string calldata _preRevealImageURI) external onlyOwner { preRevealImageURI = _preRevealImageURI; emit PreRevealImageUriUpdate(msg.sender, _preRevealImageURI); if (bytes(baseURI).length == 0) { emit BatchMetadataUpdate(0, maxSupply); } } function setBaseURI(string calldata baseURI_) external onlyOwner { baseURI = baseURI_; emit BaseUriUpdate(msg.sender, baseURI_); emit BatchMetadataUpdate(0, maxSupply); } function setWhitelistSigner(address _whitelistSigner) external onlyOwner { whitelistSigner = _whitelistSigner; emit WhitelistSignerUpdate(msg.sender, _whitelistSigner); } function claimGasFees(uint256 _minClaimRateBips) external nonReentrant onlyOwner { IBlast blastYieldContract = IBlast(0x4300000000000000000000000000000000000002); blastYieldContract.claimGasAtMinClaimRate(address(this), owner(), _minClaimRateBips); emit GasFeesClaim(owner(), _minClaimRateBips); } function ownerMint(address _recipient, uint128 _mintPrice, uint64 _lockPeriod, uint24 _quantity) external payable onlyOwner { _mint(_recipient, _mintPrice, _lockPeriod, _quantity, uint128(msg.value), 'owner'); } /* Public functions */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721Enumerable) returns (bool) { return interfaceId == bytes4(0x49064906) || super.supportsInterface(interfaceId); } // Initializes the minimal proxy contract function initialize( address _ownerAddress, address _storageAddress, address _factoryAddress, string memory name_, string memory symbol_, uint256 _maxSupply, string memory baseURI_, // Do not use if _preRevealImageURI is used string memory _preRevealImageURI, // Do not use if baseURI_ is used address _referrer, address _whitelistSigner, BlastrLibrary.MintConfig memory _publicMintConfig, BlastrLibrary.MintConfig memory _privateMintConfig ) public { // Revert if clone contract already initialized if (initialized) revert AlreadyInitialized(); if (_maxSupply < 1) revert IncorrectMaxSupply(); initialized = true; // Transfer ownership to the creator _transferOwnership(_ownerAddress); // Set the initial values blastrStorage = IBlastrStorage(_storageAddress); factoryAddress = _factoryAddress; _tokenName = name_; _tokenSymbol = symbol_; maxSupply = _maxSupply; baseURI = baseURI_; preRevealImageURI = _preRevealImageURI; referrer = _referrer; whitelistSigner = _whitelistSigner; publicMintConfig = _publicMintConfig; privateMintConfig = _privateMintConfig; _configureBlast(); } function name() public view virtual override returns (string memory) { return _tokenName; } function symbol() public view virtual override returns (string memory) { return _tokenSymbol; } function tokenURI(uint256 tokenId_) public view override returns (string memory) { require(_exists(tokenId_), "ERC721: URI query for nonexistent token"); if (bytes(_baseURI()).length > 0) { return string(abi.encodePacked(_baseURI(), tokenId_.toString())); } else { // Generate custom tokenURI if there is no baseURI specified string memory upgradedString = upgradedAt[tokenId_] != 0 ? "Yes" : "No"; string memory externalUrl = string(abi.encodePacked("https://blastr.xyz/", Strings.toHexString(uint160(address(this)), 20), "/", Strings.toString(tokenId_))); return string( abi.encodePacked( "data:application/json;base64,", Base64.encode( bytes( string( abi.encodePacked( '{', '"id": "', Strings.toString(tokenId_), '",', '"name": "', name(), ' #', Strings.toString(tokenId_), '",', '"image": "', preRevealImageURI, '",', '"external_url": "', externalUrl, '",', '"attributes": [', '{', '"trait_type": "Value locked (wei)",', '"value": ', Strings.toString(locks[tokenId_].value), '},', '{', '"display_type": "date",', '"trait_type": "Value locked until",', '"value": ', Strings.toString(locks[tokenId_].lockedAt + locks[tokenId_].lockPeriod), '},', '{', '"trait_type": "Upgraded",', '"value": "', upgradedString, '"', '}', ']', '}' ) ) ) ) ) ); } } function claimableYield() public view returns (uint256) { return address(this).balance - tvl; } function tokensOwnedBy(address _ownerAddress) public view returns (uint256[] memory) { uint256 tokenCount = balanceOf(_ownerAddress); uint256[] memory result = new uint256[](tokenCount); // Always initialized, might be empty for (uint256 index = 0; index < tokenCount; index++) { result[index] = tokenOfOwnerByIndex(_ownerAddress, index); } return result; } /* Internal functions */ function _baseURI() internal view override returns (string memory) { return baseURI; } // Adds a condition where an upgraded token can not be transferred for 7 days after upgrade // Prevents users from upgrading and accepting bids immediately on marketplaces function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual override(ERC721Enumerable) { super._beforeTokenTransfer(from, to, firstTokenId, batchSize); require(upgradedAt[firstTokenId] == 0 || block.timestamp - upgradedAt[firstTokenId] > 86400 * 7, "After upgrade() tokens can not be transferred for 7 days"); } /* Private functions */ // Blast yield, gas, and points config function _configureBlast () private { IBlast blastYieldContract = IBlast(0x4300000000000000000000000000000000000002); blastYieldContract.configureAutomaticYield(); blastYieldContract.configureClaimableGas(); IBlastPoints(0x2536FE9ab3F511540F2f9e2eC2A805005C3Dd800).configurePointsOperator(blastrStorage.blastPointsOperator()); } function _mint(address _recipient, uint128 _mintPrice, uint64 _lockPeriod, uint24 _quantity, uint128 _msgValue, string memory mintType) private { require(_quantity > 0, "Quantity cannot be zero"); require(totalSupply() + _quantity <= maxSupply, "Max supply exceeded"); require(_msgValue == _mintPrice * _quantity, "Incorrect mint price"); uint256[] memory mintedTokens = new uint256[](_quantity); for (uint256 i = 0; i < _quantity; i++) { uint256 tokenId = _findAvailableTokenId(); mintedTokens[i] = tokenId; locks[tokenId] = Lock({ value: _mintPrice, lockPeriod: _lockPeriod, lockedAt: uint64(block.timestamp) }); _mint(_recipient, tokenId); } emit Mint(mintedTokens, msg.sender, _recipient, _msgValue, _quantity, _lockPeriod, mintType); tvl += _msgValue; } function _findAvailableTokenId() private returns (uint256) { if (refundedTokens.length > 0) { uint256 tokenId = refundedTokens[refundedTokens.length - 1]; emit MetadataUpdate(tokenId); refundedTokens.pop(); return tokenId; } else { uint256 newTokenId = _tokenId.current(); _tokenId.increment(); return newTokenId; } } // Checks if the variable is 0 function _isNull(uint256 variable) private pure returns (bool) { return variable == 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
// 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.8.0) (token/ERC721/extensions/ERC721Enumerable.sol) pragma solidity ^0.8.0; import "../ERC721.sol"; import "./IERC721Enumerable.sol"; /** * @dev This implements an optional extension of {ERC721} defined in the EIP that adds * enumerability of all the token ids in the contract as well as all token ids owned by each * account. */ abstract contract ERC721Enumerable is ERC721, IERC721Enumerable { // Mapping from owner to list of owned token IDs mapping(address => mapping(uint256 => uint256)) private _ownedTokens; // Mapping from token ID to index of the owner tokens list mapping(uint256 => uint256) private _ownedTokensIndex; // Array with all token ids, used for enumeration uint256[] private _allTokens; // Mapping from token id to position in the allTokens array mapping(uint256 => uint256) private _allTokensIndex; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. */ function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds"); return _ownedTokens[owner][index]; } /** * @dev See {IERC721Enumerable-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _allTokens.length; } /** * @dev See {IERC721Enumerable-tokenByIndex}. */ function tokenByIndex(uint256 index) public view virtual override returns (uint256) { require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds"); return _allTokens[index]; } /** * @dev See {ERC721-_beforeTokenTransfer}. */ function _beforeTokenTransfer( address from, address to, uint256 firstTokenId, uint256 batchSize ) internal virtual override { super._beforeTokenTransfer(from, to, firstTokenId, batchSize); if (batchSize > 1) { // Will only trigger during construction. Batch transferring (minting) is not available afterwards. revert("ERC721Enumerable: consecutive transfers not supported"); } uint256 tokenId = firstTokenId; if (from == address(0)) { _addTokenToAllTokensEnumeration(tokenId); } else if (from != to) { _removeTokenFromOwnerEnumeration(from, tokenId); } if (to == address(0)) { _removeTokenFromAllTokensEnumeration(tokenId); } else if (to != from) { _addTokenToOwnerEnumeration(to, tokenId); } } /** * @dev Private function to add a token to this extension's ownership-tracking data structures. * @param to address representing the new owner of the given token ID * @param tokenId uint256 ID of the token to be added to the tokens list of the given address */ function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { uint256 length = ERC721.balanceOf(to); _ownedTokens[to][length] = tokenId; _ownedTokensIndex[tokenId] = length; } /** * @dev Private function to add a token to this extension's token tracking data structures. * @param tokenId uint256 ID of the token to be added to the tokens list */ function _addTokenToAllTokensEnumeration(uint256 tokenId) private { _allTokensIndex[tokenId] = _allTokens.length; _allTokens.push(tokenId); } /** * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for * gas optimizations e.g. when performing a transfer operation (avoiding double writes). * This has O(1) time complexity, but alters the order of the _ownedTokens array. * @param from address representing the previous owner of the given token ID * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address */ function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = ERC721.balanceOf(from) - 1; uint256 tokenIndex = _ownedTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary if (tokenIndex != lastTokenIndex) { uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index } // This also deletes the contents at the last position of the array delete _ownedTokensIndex[tokenId]; delete _ownedTokens[from][lastTokenIndex]; } /** * @dev Private function to remove a token from this extension's token tracking data structures. * This has O(1) time complexity, but alters the order of the _allTokens array. * @param tokenId uint256 ID of the token to be removed from the tokens list */ function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = _allTokens.length - 1; uint256 tokenIndex = _allTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding // an 'if' statement (like in _removeTokenFromOwnerEnumeration) uint256 lastTokenId = _allTokens[lastTokenIndex]; _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index // This also deletes the contents at the last position of the array delete _allTokensIndex[tokenId]; _allTokens.pop(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Enumerable is IERC721 { /** * @dev Returns the total amount of tokens stored by the contract. */ function totalSupply() external view returns (uint256); /** * @dev Returns a token ID owned by `owner` at a given `index` of its token list. * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. */ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); /** * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. * Use along with {totalSupply} to enumerate all tokens. */ function tokenByIndex(uint256 index) external view returns (uint256); }
// 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) (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 (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 (last updated v4.7.0) (utils/Base64.sol) pragma solidity ^0.8.0; /** * @dev Provides a set of functions to operate with Base64 strings. * * _Available since v4.5._ */ library Base64 { /** * @dev Base64 Encoding/Decoding Table */ string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /** * @dev Converts a `bytes` to its Bytes64 `string` representation. */ function encode(bytes memory data) internal pure returns (string memory) { /** * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol */ if (data.length == 0) return ""; // Loads the table into memory string memory table = _TABLE; // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter // and split into 4 numbers of 6 bits. // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up // - `data.length + 2` -> Round up // - `/ 3` -> Number of 3-bytes chunks // - `4 *` -> 4 characters for each chunk string memory result = new string(4 * ((data.length + 2) / 3)); /// @solidity memory-safe-assembly assembly { // Prepare the lookup table (skip the first "length" byte) let tablePtr := add(table, 1) // Prepare result pointer, jump over length let resultPtr := add(result, 32) // Run over the input, 3 bytes at a time for { let dataPtr := data let endPtr := add(data, mload(data)) } lt(dataPtr, endPtr) { } { // Advance 3 bytes dataPtr := add(dataPtr, 3) let input := mload(dataPtr) // To write each character, shift the 3 bytes (18 bits) chunk // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) // and apply logical AND with 0x3F which is the number of // the previous character in the ASCII table prior to the Base64 Table // The result is then added to the table to get the character to write, // and finally write it in the result pointer but with a left shift // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) resultPtr := add(resultPtr, 1) // Advance mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) resultPtr := add(resultPtr, 1) // Advance mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) resultPtr := add(resultPtr, 1) // Advance mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) resultPtr := add(resultPtr, 1) // Advance } // When data `bytes` is not exactly 3 bytes long // it is padded with `=` characters at the end switch mod(mload(data), 3) case 1 { mstore8(sub(resultPtr, 1), 0x3d) mstore8(sub(resultPtr, 2), 0x3d) } case 2 { mstore8(sub(resultPtr, 1), 0x3d) } } return result; } }
// 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/Counters.sol) pragma solidity ^0.8.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` */ library Counters { struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { unchecked { counter._value += 1; } } function decrement(Counter storage counter) internal { uint256 value = counter._value; require(value > 0, "Counter: decrement overflow"); unchecked { counter._value = value - 1; } } function reset(Counter storage counter) internal { counter._value = 0; } }
// 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 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 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); }
// 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/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: UNLICENSED pragma solidity ^0.8.21; library BlastrLibrary { struct MintConfig { uint128 mintPrice; uint64 lockPeriod; uint24 maxMintsPerTransaction; uint24 maxMintsPerWallet; bool active; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.21; enum YieldMode { AUTOMATIC, VOID, CLAIMABLE } enum GasMode { VOID, CLAIMABLE } interface IBlast{ // configure function configureContract(address contractAddress, YieldMode _yield, GasMode gasMode, address governor) external; function configure(YieldMode _yield, GasMode gasMode, address governor) external; // base configuration options function configureClaimableYield() external; function configureClaimableYieldOnBehalf(address contractAddress) external; function configureAutomaticYield() external; function configureAutomaticYieldOnBehalf(address contractAddress) external; function configureVoidYield() external; function configureVoidYieldOnBehalf(address contractAddress) external; function configureClaimableGas() external; function configureClaimableGasOnBehalf(address contractAddress) external; function configureVoidGas() external; function configureVoidGasOnBehalf(address contractAddress) external; function configureGovernor(address _governor) external; function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external; // claim yield function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256); function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256); // claim gas function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256); function claimGasAtMinClaimRate(address contractAddress, address recipientOfGas, uint256 minClaimRateBips) external returns (uint256); function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256); function claimGas(address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume) external returns (uint256); // read functions function readClaimableYield(address contractAddress) external view returns (uint256); function readYieldConfiguration(address contractAddress) external view returns (uint8); function readGasParams(address contractAddress) external view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode); }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.21; interface IBlastPoints { function configurePointsOperator(address operator) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.21; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "../contracts/BlastrLibrary.sol"; interface IBlastrNFT is IERC721 { // Events event Refund(uint256 tokenId, address indexed by, uint256 value); event Upgrade(uint256 tokenId, address indexed by, uint256 value); event GasFeesClaim(address owner, uint256 minClaimRateBips); event PublicMintStateUpdate(address owner, bool active); event PrivateMintStateUpdate(address owner, bool active); event PublicMintConfigUpdate(address owner, uint256 mintPrice, uint256 lockPeriod, uint256 maxMintsPerTransaction, uint256 maxMintsPerWallet, bool active); event PrivateMintConfigUpdate(address owner, uint256 mintPrice, uint256 lockPeriod, uint256 maxMintsPerTransaction, uint256 maxMintsPerWallet, bool active); event Mint(uint256 tokenId, address minter, address indexed recipient, uint256 mintPrice, uint256 lockPeriod); event YieldClaim(address owner, address protocolFeeCollector, address referrer, uint256 ownerYield, uint256 protocolYield, uint256 referrerYield); // Functions function initialize(address _ownerAddress, address _storageAddress, address _factoryAddress, string memory name_, string memory symbol_, uint256 _maxSupply, string memory baseURI_, string memory _preRevealImageURI, address _referrer, address _whitelistSigner, BlastrLibrary.MintConfig memory _publicMintConfig, BlastrLibrary.MintConfig memory _privateMintConfig) external; function publicMint(uint24 _quantity) external payable; function privateMint(uint24 _quantity, bytes memory _signature) external payable; function refund(uint256 tokenId_) external; function upgrade(uint256 tokenId_) external; function claimYield() external; function flipPublicMintState() external; function flipPrivateMintState() external; function setPublicMintConfig(BlastrLibrary.MintConfig memory _publicMintConfig) external; function setPrivateMintConfig(BlastrLibrary.MintConfig memory _privateMintConfig) external; function setPreRevealImageURI(string calldata _preRevealImageURI) external; function setBaseURI(string calldata baseURI_) external; function setWhitelistSigner(address _whitelistSigner) external; function claimGasFees(uint256 _minClaimRateBips) external; function ownerMint(address _recipient, uint128 _mintPrice, uint64 _lockPeriod, uint24 _quantity) external payable; function totalSupply() external view returns (uint256); function tokensOwnedBy(address _ownerAddress) external view returns (uint256[] memory); // State variable getters function tvl() external view returns (uint256); function maxSupply() external view returns (uint256); function publicMintStartTime() external view returns (uint256); function factoryAddress() external view returns (address); function referrer() external view returns (address); function whitelistSigner() external view returns (address); function baseURI() external view returns (string memory); function preRevealImageURI() external view returns (string memory); function initialized() external view returns (bool); function publicMintConfig() external view returns (BlastrLibrary.MintConfig memory); function privateMintConfig() external view returns (BlastrLibrary.MintConfig memory); function locks(uint256 tokenId) external view returns (uint256 value, uint256 lockPeriod, uint256 lockedAt); function upgradedAt(uint256 tokenId) external view returns (uint256); }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.21; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; interface IBlastrStorage { // Events event FeeCollectorUpdated(address feeCollector); event ProtocolFeeUpdated(uint256 protocolFee); event BoostPriceUpdated(uint256 boostPrice); event NFTContractAddressUpdated(address NFTContractAddress); event MaxBoostsPerAddressPerCollectionUpdated(uint256 maxBoostsPerAddressPerCollection); event FactoryAdded(address factoryAddress); event CollectionAdded(address collectionAddress); // Function signatures function addCollection(address _collectionAddress) external; function addFactory(address _factoryAddress) external; function updateFeeCollector(address _feeCollector) external; function updateProtocolFee(uint256 _protocolFee) external; function updateBoostPrice(uint256 _boostPrice) external; function updateNFTContractAddress(address _NFTContractAddress) external; function updateMaxBoostsPerAddressPerCollection(uint256 _maxBoostsPerAddressPerCollection) external; // Public and external variable getters function feeCollector() external view returns (address); function blastPointsOperator() external view returns (address); function protocolFee() external view returns (uint256); function referrerFee() external view returns (uint256); function boostPrice() external view returns (uint256); function NFTContractAddress() external view returns (address); function maxBoostsPerAddressPerCollection() external view returns (uint256); function isCollection(address) external view returns (bool); function isFactory(address) external view returns (bool); }
// SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.21; import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /// @title EIP-721 Metadata Update Extension interface IERC4906 is IERC165 { /// @dev This event emits when the metadata of a token is changed. /// Third-party platforms such as NFT marketplaces can listen to /// the event and auto-update the tokens in their apps. 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); }
{ "optimizer": { "enabled": true, "runs": 300 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "viaIR": true, "evmVersion": "paris", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"IncorrectMaxSupply","type":"error"},{"inputs":[],"name":"TransferFailed","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":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseUriUpdate","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":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"minClaimRateBips","type":"uint256"}],"name":"GasFeesClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"MetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint128","name":"value","type":"uint128"},{"indexed":false,"internalType":"uint24","name":"quantity","type":"uint24"},{"indexed":false,"internalType":"uint64","name":"lockPeriod","type":"uint64"},{"indexed":false,"internalType":"string","name":"mintType","type":"string"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"string","name":"preRevealImageURI","type":"string"}],"name":"PreRevealImageUriUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint128","name":"mintPrice","type":"uint128"},{"indexed":false,"internalType":"uint64","name":"lockPeriod","type":"uint64"},{"indexed":false,"internalType":"uint24","name":"maxMintsPerTransaction","type":"uint24"},{"indexed":false,"internalType":"uint24","name":"maxMintsPerWallet","type":"uint24"},{"indexed":false,"internalType":"bool","name":"active","type":"bool"}],"name":"PrivateMintConfigUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"bool","name":"active","type":"bool"}],"name":"PrivateMintStateUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint128","name":"mintPrice","type":"uint128"},{"indexed":false,"internalType":"uint64","name":"lockPeriod","type":"uint64"},{"indexed":false,"internalType":"uint24","name":"maxMintsPerTransaction","type":"uint24"},{"indexed":false,"internalType":"uint24","name":"maxMintsPerWallet","type":"uint24"},{"indexed":false,"internalType":"bool","name":"active","type":"bool"}],"name":"PublicMintConfigUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"bool","name":"active","type":"bool"}],"name":"PublicMintStateUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Refund","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":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Upgrade","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"address","name":"whitelistSigner","type":"address"}],"name":"WhitelistSignerUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"address","name":"protocolFeeCollector","type":"address"},{"indexed":false,"internalType":"address","name":"referrer","type":"address"},{"indexed":false,"internalType":"uint256","name":"ownerYield","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolYield","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"referrerYield","type":"uint256"}],"name":"YieldClaim","type":"event"},{"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":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blastrStorage","outputs":[{"internalType":"contract IBlastrStorage","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minClaimRateBips","type":"uint256"}],"name":"claimGasFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimYield","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimableYield","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factoryAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flipPrivateMintState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"flipPublicMintState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_ownerAddress","type":"address"},{"internalType":"address","name":"_storageAddress","type":"address"},{"internalType":"address","name":"_factoryAddress","type":"address"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint256","name":"_maxSupply","type":"uint256"},{"internalType":"string","name":"baseURI_","type":"string"},{"internalType":"string","name":"_preRevealImageURI","type":"string"},{"internalType":"address","name":"_referrer","type":"address"},{"internalType":"address","name":"_whitelistSigner","type":"address"},{"components":[{"internalType":"uint128","name":"mintPrice","type":"uint128"},{"internalType":"uint64","name":"lockPeriod","type":"uint64"},{"internalType":"uint24","name":"maxMintsPerTransaction","type":"uint24"},{"internalType":"uint24","name":"maxMintsPerWallet","type":"uint24"},{"internalType":"bool","name":"active","type":"bool"}],"internalType":"struct BlastrLibrary.MintConfig","name":"_publicMintConfig","type":"tuple"},{"components":[{"internalType":"uint128","name":"mintPrice","type":"uint128"},{"internalType":"uint64","name":"lockPeriod","type":"uint64"},{"internalType":"uint24","name":"maxMintsPerTransaction","type":"uint24"},{"internalType":"uint24","name":"maxMintsPerWallet","type":"uint24"},{"internalType":"bool","name":"active","type":"bool"}],"internalType":"struct BlastrLibrary.MintConfig","name":"_privateMintConfig","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"locks","outputs":[{"internalType":"uint128","name":"value","type":"uint128"},{"internalType":"uint64","name":"lockPeriod","type":"uint64"},{"internalType":"uint64","name":"lockedAt","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint128","name":"_mintPrice","type":"uint128"},{"internalType":"uint64","name":"_lockPeriod","type":"uint64"},{"internalType":"uint24","name":"_quantity","type":"uint24"}],"name":"ownerMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"preRevealImageURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint24","name":"_quantity","type":"uint24"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"privateMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"privateMintConfig","outputs":[{"internalType":"uint128","name":"mintPrice","type":"uint128"},{"internalType":"uint64","name":"lockPeriod","type":"uint64"},{"internalType":"uint24","name":"maxMintsPerTransaction","type":"uint24"},{"internalType":"uint24","name":"maxMintsPerWallet","type":"uint24"},{"internalType":"bool","name":"active","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint24","name":"_quantity","type":"uint24"}],"name":"publicMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"publicMintConfig","outputs":[{"internalType":"uint128","name":"mintPrice","type":"uint128"},{"internalType":"uint64","name":"lockPeriod","type":"uint64"},{"internalType":"uint24","name":"maxMintsPerTransaction","type":"uint24"},{"internalType":"uint24","name":"maxMintsPerWallet","type":"uint24"},{"internalType":"bool","name":"active","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"publicMintStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referrer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"refundedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"baseURI_","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_preRevealImageURI","type":"string"}],"name":"setPreRevealImageURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"mintPrice","type":"uint128"},{"internalType":"uint64","name":"lockPeriod","type":"uint64"},{"internalType":"uint24","name":"maxMintsPerTransaction","type":"uint24"},{"internalType":"uint24","name":"maxMintsPerWallet","type":"uint24"},{"internalType":"bool","name":"active","type":"bool"}],"internalType":"struct BlastrLibrary.MintConfig","name":"_privateMintConfig","type":"tuple"}],"name":"setPrivateMintConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"mintPrice","type":"uint128"},{"internalType":"uint64","name":"lockPeriod","type":"uint64"},{"internalType":"uint24","name":"maxMintsPerTransaction","type":"uint24"},{"internalType":"uint24","name":"maxMintsPerWallet","type":"uint24"},{"internalType":"bool","name":"active","type":"bool"}],"internalType":"struct BlastrLibrary.MintConfig","name":"_publicMintConfig","type":"tuple"}],"name":"setPublicMintConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_whitelistSigner","type":"address"}],"name":"setWhitelistSigner","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":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_ownerAddress","type":"address"}],"name":"tokensOwnedBy","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","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":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tvl","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"upgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"upgradedAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whitelistSigner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6080604052346200032757620000146200032c565b6200001e6200032c565b81519091906001600160401b0380821162000311576000928354906001938483811c931691821562000306575b60209283851014620002f2578190601f948581116200029f575b5083908583116001146200023b5788926200022f575b5050600019600383901b1c191690851b1785555b85519283116200021b5783548481811c9116801562000210575b82821014620001fc57828111620001b4575b50809183116001146200014e575083948293949262000142575b5050600019600383901b1c191690821b1781555b600a8054336001600160a01b031982168117909255604051936001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3600b556154709081620003518239f35b015190503880620000d5565b90601f198316958486528286209286905b8882106200019c575050838596971062000182575b505050811b018155620000e9565b015160001960f88460031b161c1916905538808062000174565b8087859682949686015181550195019301906200015f565b8486528186208380860160051c820192848710620001f2575b0160051c019085905b828110620001e6575050620000bb565b878155018590620001d6565b92508192620001cd565b634e487b7160e01b86526022600452602486fd5b90607f1690620000a9565b634e487b7160e01b85526041600452602485fd5b0151905038806200007b565b8880528489208894509190601f1984168a5b878282106200028857505084116200026e575b505050811b0185556200008f565b015160001960f88460031b161c1916905538808062000260565b8385015186558b979095019493840193016200024d565b9091508780528388208580850160051c820192868610620002e8575b918991869594930160051c01915b828110620002d957505062000065565b8a8155859450899101620002c9565b92508192620002bb565b634e487b7160e01b87526022600452602487fd5b92607f16926200004b565b634e487b7160e01b600052604160045260246000fd5b600080fd5b60405190602082016001600160401b0381118382101762000311576040526000825256fe6080604052600436101561001257600080fd5b6000803560e01c80626059fd1461312657806301ffc9a71461308357806306fdde0314613067578063081812fc14613048578063095ea7b314612ec6578063158ef93e14612ea357806318160ddd14612e8557806323b872dd14612e5b578063268e280314612d77578063269c759b14612d08578063278ecde11461278d5780632f745c5914612765578063406cf229146122ae57806342842e0e1461228657806345977d03146120c15780634d9b9426146120405780634f6ccce714611fbc57806353c838e014611eb357806355f804b314611d3f5780636352211e14611d0f57806368447c9314611ce85780636c0360eb14611ccc57806370a0823114611ca8578063715018a614611c4b5780637d58367614611ab65780637e1c175714611a8c5780638da5cb5b14611a655780639106a059146119f657806395d89b411461195c578063966dae0e1461193557806399c89e81146118a25780639dbec671146117d1578063a22cb465146116fd578063a263a9eb146116d5578063a68aa96714611649578063b88d4fde146115fa578063bf4ad33814611456578063c87b56dd14611422578063d3381438146113b1578063d3cf00a314611393578063d5abeb0114611375578063d93a11ed1461096b578063d98de53e1461049f578063e4b3758b14610475578063e5328e0614610457578063e985e9c514610402578063ea66aeb31461038f578063ef81b4d414610368578063ef97ead81461032f578063f2fde38b1461029e5763f4dadc611461024d57600080fd5b3461029b57602036600319011261029b5760406060916004358152601c6020522054604051906001600160801b03811682526001600160401b038160801c16602083015260c01c6040820152f35b80fd5b503461029b57602036600319011261029b576102b861349a565b6102c06137ff565b6001600160a01b038116156102db576102d890613857565b80f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b503461029b57602036600319011261029b576004359060195482101561029b57602061035a836137c8565b90546040519160031b1c8152f35b503461029b578060031936011261029b5760206001600160a01b0360155416604051908152f35b503461029b57602036600319011261029b576103a961349a565b6103b2816138a1565b906103bc82614ed4565b925b8281106103df57604051602080825281906103db90820187613747565b0390f35b806103ed6103fd9284613f6b565b6103f782876140d2565b526140c3565b6103be565b503461029b57604036600319011261029b5761041c61349a565b60406104266134b0565b926001600160a01b0380931681526005602052209116600052602052602060ff604060002054166040519015158152f35b503461029b578060031936011261029b576020601054604051908152f35b503461029b57602036600319011261029b5760406020916004358152601d83522054604051908152f35b50602080600319360112610967576104b5613328565b906104be614188565b60ff601a5460f01c16156109235761012c6104db60125442613ffa565b106105b3575b61057c91601a5461051e62ffffff8261050a82809560c01c1680159081156105a6575b506140e6565b60d81c168015908115610584575b5061413c565b338552601e8352610536604086209183168254614026565b9055601a54906001600160801b0391657075626c696360d01b6040519461055c86613399565b60068652850152823416926001600160401b038260801c16911633614efc565b6001600b5580f35b9050338752601e855261059e604088205484861690614026565b111538610518565b9050838716111538610504565b6001600160a01b03918260185460081c166040516305391b2760e31b918282528482600481845afa91821561078757869286918991610906575b506024604051809981936370a0823160e01b8352336004840152165afa9586156107875787966108d2575b50851515806108c3575b1561082257600d9081549361063d62ffffff87168096614026565b601460115404106107ca579086899260046040518094819382525afa9081156107bf578291610792575b5060246040518095819363ea66aeb360e01b8352336004840152165afa918215610787578792610763575b508691875b878110610710575b5050509091929350036106b257906104e1565b60405162461bcd60e51b815260048101839052603060248201527f596f7520646f6e2774206f776e20656e6f756768206b65797320746f206d696e60448201526f742061736b6564207175616e7469747960801b6064820152608490fd5b61071a81836140d2565b5189528680526040892080541561073b575b50610736906140c3565b610697565b936107509194600180915584540184556140c3565b9284841461075e573861072c565b61069f565b6107809192503d8089833e61077881836133cf565b81019061404a565b9038610692565b6040513d89823e3d90fd5b6107b29150873d89116107b8575b6107aa81836133cf565b810190614007565b38610667565b503d6107a0565b6040513d84823e3d90fd5b60405162461bcd60e51b815260048101889052602a60248201527f4d757374206e6f74206d696e74206d6f7265207468616e203525206f6620746f60448201526974616c20737570706c7960b01b6064820152608490fd5b60405162461bcd60e51b815260048101869052606760248201527f5468652066697273742035206d696e206f66207075626c6963206d696e74206160448201527f726520726573657276656420666f7220424c41535452206b657920686f6c646560648201527f727320286d6178206d696e74207175616e746974793a203120706572206b6579608482015266206f776e65642960c81b60a482015260c490fd5b508562ffffff85161115610622565b9095508481813d83116108ff575b6108ea81836133cf565b810103126108fa57519438610618565b600080fd5b503d6108e0565b61091d9150823d84116107b8576107aa81836133cf565b386105ed565b6064906040519062461bcd60e51b82526004820152601960248201527f5075626c6963206d696e74206973206e6f7420616374697665000000000000006044820152fd5b5080fd5b503461029b5761028036600319011261029b5761098661349a565b9061098f6134b0565b6044356001600160a01b03938482168203611371576064356001600160401b03811161136d576109c390369060040161340b565b6084356001600160401b038111611369576109e290369060040161340b565b60c4356001600160401b03811161136557610a0190369060040161340b565b60e4356001600160401b03811161136157610a2090369060040161340b565b916101043593898516850361135d5761012435958a871687036113595760a0366101431901126113595760405197610a578961337e565b610144356001600160801b038116810361134d578952610164356001600160401b038116810361134d5760208a015262ffffff61018435166101843503611355576101843560408a01526101a43562ffffff8116810361134d5760608a01526101c43515156101c43503611355576101c43560808a015260a0366101e31901126113555760405199610ae88b61337e565b6101e4356001600160801b0381168103611351578b526001600160401b036102043516610204350361134d576102043560208c015262ffffff6102243516610224350361134d576102243560408c015262ffffff6102443516610244350361134d576102443560608c0152610264351515610264350361134d576102643560808c015260185460ff811661133c57600160a4351061132a5760ff19166001176018558c92610b9590613857565b610100600160a81b036018549160081b1690610100600160a81b03191617601855166001600160601b0360a01b60135416176013558051906001600160401b03821161131657610be6600e546135c4565b601f81116112af575b50602090601f831160011461123a57610c2092918b918361100d575b50508160011b916000199060031b1c19161790565b600e555b8051906001600160401b03821161122657610c40600f546135c4565b601f81116111bf575b50602090601f831160011461114a57610c7992918a918361100d5750508160011b916000199060031b1c19161790565b600f555b60a4356011558051906001600160401b03821161113657610ca882610ca36016546135c4565b61449c565b602090601f83116001146110af57610cd7929189918361100d5750508160011b916000199060031b1c19161790565b6016555b8051906001600160401b03821161109b579087939291610d0582610d006017546135c4565b61450d565b602090601f83116001146110185792610d41836080989694889694610ec49b99958d9261100d5750508160011b916000199060031b1c19161790565b6017555b166001600160601b0360a01b6014541617601455166001600160601b0360a01b6015541617601555610d976001600160801b038251166001600160801b03166001600160801b0319601a541617601a55565b6020810151601a805467ffffffffffffffff60801b191660809290921b67ffffffffffffffff60801b169190911790556040810151601a805460608401519386015160ff60f01b90151560f01b1662ffffff60d81b60d89590951b851662ffffff60c01b60c09590951b851666ffffffffffffff60c01b1990931692909217919091171790559065ffffffffffff60c01b19610e536001600160801b038551166001600160801b03166001600160801b0319601b541617601b55565b6020840151601b805467ffffffffffffffff60801b191660809290921b67ffffffffffffffff60801b16919091179055604084015192601b5492606086015160d81b169360c01b1691161717601b5501511515601b549060ff60f01b90151560f01b169060ff60f01b191617601b55565b6002604360981b0191823b156109675760405163388a0bbd60e11b815292828460048183855af18015610fd357610ff9575b829350803b15610ff557828091600460405180948193634e606c4760e01b83525af1908115610fd3578391610fde575b5050600460208260185460081c166040519283809263102b8f8560e21b82525afa908115610fd3578391610fb4575b50732536fe9ab3f511540f2f9e2ec2a805005c3dd80091823b15610faf57602484928360405195869485936336b91f2b60e01b85521660048401525af180156107bf57610f9f5750f35b610fa89061336b565b61029b5780f35b505050fd5b610fcd915060203d6020116107b8576107aa81836133cf565b38610f55565b6040513d85823e3d90fd5b610fe79061336b565b610ff2578138610f26565b50fd5b5050fd5b9190926110059061336b565b908290610ef6565b015190503880610c0b565b90601789526000805160206153fb83398151915291895b601f198516811061108057508387959293610ec49a989460019360809b9997601f19811610611067575b505050811b01601755610d45565b015160001960f88460031b161c19169055388080611059565b8183015184558b97506001909301926020928301920161102f565b634e487b7160e01b87526041600452602487fd5b601689528892917fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b5124289915b601f198416851061111b576001945083601f19811610611102575b505050811b01601655610cdb565b015160001960f88460031b161c191690553880806110f4565b818101518355602094850194600190930192909101906110d9565b634e487b7160e01b88526041600452602488fd5b600f8a5289929160008051602061541b833981519152915b601f19841685106111a4576001945083601f1981161061118b575b505050811b01600f55610c7d565b015160001960f88460031b161c1916905538808061117d565b81810151835560209485019460019093019290910190611162565b600f8a52601f830160051c60008051602061541b8339815191520160208410611211575b601f820160051c60008051602061541b8339815191520181106112065750610c49565b8a81556001016111e3565b5060008051602061541b8339815191526111e3565b634e487b7160e01b89526041600452602489fd5b600e8b528a92916000805160206153db833981519152915b601f1984168510611294576001945083601f1981161061127b575b505050811b01600e55610c24565b015160001960f88460031b161c1916905538808061126d565b81810151835560209485019460019093019290910190611252565b600e8b52601f830160051c6000805160206153db8339815191520160208410611301575b601f820160051c6000805160206153db8339815191520181106112f65750610bef565b8b81556001016112d3565b506000805160206153db8339815191526112d3565b634e487b7160e01b8a52604160045260248afd5b6040516325ab076960e01b8152600490fd5b60405162dc149f60e41b8152600490fd5b8b80fd5b8c80fd5b8a80fd5b8980fd5b8880fd5b8780fd5b8680fd5b8580fd5b8480fd5b8380fd5b503461029b578060031936011261029b576020601154604051908152f35b503461029b578060031936011261029b576020601254604051908152f35b503461029b57602036600319011261029b577fe81fbf9dcd9efb641e9dd6a384b82aedac00c55a93402509bd9866fab1a92afa60406001600160a01b036113f661349a565b6113fe6137ff565b16806001600160601b0360a01b60155416176015558151903382526020820152a180f35b503461029b57602036600319011261029b576103db6114426004356145a3565b604051918291602083526020830190613475565b503461029b5760a036600319011261029b577fca805018b1f306f78c930fd9dd300fc655fa266c44ad5e355f8c2d19d5ea8f64611492366134fb565b61149a6137ff565b601a54906115dc6001600160801b03825116926114cd846001600160801b03166001600160801b0319601a541617601a55565b6020830151601a805467ffffffffffffffff60801b1916608083901b67ffffffffffffffff60801b161790556001600160401b0316936040840151601a8054606087015160809097015166ffffffffffffff60c01b1990911660c084901b62ffffff60c01b161760d888901b62ffffff60d81b161790151560f081901b60ff60f01b169190911790915562ffffff96909391929160ff9060f01c1615806115eb575b6115e2575b6001600160a01b03600a54169187604051988998169416928794909695926001600160401b03906001600160801b0360a096946001600160a01b0360c08a019b16895216602088015216604086015262ffffff80921660608601521660808401521515910152565b0390a180f35b42601255611574565b5060ff601a5460f01c1661156f565b503461029b57608036600319011261029b5761161461349a565b61161c6134b0565b606435916001600160401b0383116113715761163f6102d893369060040161340b565b9160443591613a2d565b503461029b578060031936011261029b576116626137ff565b601b805460ff60f01b19811660f091821c60ff90811615831b60ff60f01b169190911792839055600a54604080516001600160a01b039290921682529390921c16151560208201527fe151bf9d2a434324b5e13c5bdff9bd2e9ab2e30c657f586da54bbe88cf1d8b0691819081016115dc565b503461029b578060031936011261029b5760206116f54760105490613ffa565b604051908152f35b503461029b57604036600319011261029b5761171761349a565b602435908115158092036117cd576001600160a01b031690813314611788573383526005602052604083208284526020526040832060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b60405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606490fd5b8280fd5b503461029b578060031936011261029b57604051908082601754916117f5836135c4565b92838352602094600191868382169182600014611880575050600114611838575b5050611824925003836133cf565b6103db604051928284938452830190613475565b90859250601782526000805160206153fb8339815191525b85831061186857505061182493508201013880611816565b80548389018501528794508693909201918101611850565b925093505061182494915060ff191682840152151560051b8201013880611816565b503461029b578060031936011261029b576118bb6137ff565b7ff2721e078a20e7f6ba187f7a54783e6e4cea86087bafc68840732db61dec478860ff601a548160f01b828260f01c161560f01b16908260f01b19161780601a5560f01c168061192c575b600a54604080516001600160a01b039092168252911515602082015290819081016115dc565b42601255611906565b503461029b578060031936011261029b5760206001600160a01b0360135416604051908152f35b503461029b578060031936011261029b57604051908082600f5491611980836135c4565b928383526020946001918683821691826000146118805750506001146119ae575050611824925003836133cf565b90859250600f825260008051602061541b8339815191525b8583106119de57505061182493508201013880611816565b805483890185015287945086939092019181016119c6565b503461029b578060031936011261029b57601b54604080516001600160801b0383168152608083811c6001600160401b0316602083015260c084901c62ffffff9081169383019390935260d884901c909216606082015260f09290921c60ff161515908201528060a081010390f35b503461029b578060031936011261029b5760206001600160a01b03600a5416604051908152f35b503461029b578060031936011261029b5760206001600160a01b0360185460081c16604051908152f35b503461029b57611ac53661357b565b611ad09291926137ff565b6001600160401b038111611c3757611aed81610d006017546135c4565b8192601f8211600114611ba757611b3d828085967f0e97d384f3f2db9658556130716bebad5af0675b729419b713437de32653febc9691611b9c575b508160011b916000199060031b1c19161790565b6017555b611b51604051928392338461456c565b0390a1611b5f6016546135c4565b15611b675780f35b7f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c60406011548151908482526020820152a180f35b905083013538611b29565b60178352601f198216936000805160206153fb83398151915290845b868110611c1f5750837f0e97d384f3f2db9658556130716bebad5af0675b729419b713437de32653febc959610611c05575b5050600182811b01601755611b41565b820135600019600385901b60f8161c191690553880611bf5565b90916020600181928587013581550193019101611bc3565b634e487b7160e01b82526041600452602482fd5b503461029b578060031936011261029b57611c646137ff565b806001600160a01b03600a546001600160601b0360a01b8116600a55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461029b57602036600319011261029b5760206116f5611cc761349a565b6138a1565b503461029b578060031936011261029b576103db6114426136ab565b503461029b578060031936011261029b5760206001600160a01b0360145416604051908152f35b503461029b57602036600319011261029b576020611d2e600435613964565b6001600160a01b0360405191168152f35b503461029b57611d4e3661357b565b611d599291926137ff565b6001600160401b038111611c3757611d7681610ca36016546135c4565b8192601f8211600114611e1157611dc5828085967f78cd0c51de67bd306f7a477494a110772ec9e86ffcfb04448079856a62dbe3b59691611b9c57508160011b916000199060031b1c19161790565b6016555b611dd9604051928392338461456c565b0390a17f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c60406011548151908482526020820152a180f35b60168352601f198216937fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b512428990845b868110611e9b5750837f78cd0c51de67bd306f7a477494a110772ec9e86ffcfb04448079856a62dbe3b5959610611e81575b5050600182811b01601655611dc9565b820135600019600385901b60f8161c191690553880611e71565b90916020600181928587013581550193019101611e3f565b503461029b5760a036600319011261029b577f059691c8ca8b8a0a17d6d79c46d63bf67f157d28700329f2f842fc08c1cf4d6b611eef366134fb565b611ef76137ff565b6001600160801b0381511690611f23826001600160801b03166001600160801b0319601b541617601b55565b6020810151601b805467ffffffffffffffff60801b1916608083901b67ffffffffffffffff60801b161790556115dc906001600160401b03166040830151601b8054606086015160809096015166ffffffffffffff60c01b1990911660c084901b62ffffff60c01b161760d887901b62ffffff60d81b161790151560f081901b60ff60f01b169190911790915562ffffff959092611574565b503461029b57602036600319011261029b57600435600854811015611fe65761035a60209161377b565b60405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b6064820152608490fd5b50608036600319011261029b5761205561349a565b602435906001600160801b03908183168303611371576044356001600160401b038116810361136d576064359062ffffff82168203611369576102d89461209a6137ff565b604051946120a786613399565b600586526437bbb732b960d91b6020870152341693614efc565b503461029b5760208060031936011261096757600435906120e0614188565b6121086121038360005260026020526001600160a01b0360406000205416151590565b6143bf565b818352601d8152604083205461224f5761212182613964565b916121386001600160a01b0393843391161461440b565b808452601c82526040842084808080604051946121548661333a565b54976001600160801b0398898116908188526001600160401b038160801c168a89015260c01c60408801527f0c3fdcacbee530581c67c89a851ff8052aa367c589919df3056398ce311a237d604051806121c633948c839092916001600160801b036020916040840195845216910152565b0390a27ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce788604051898152a1600a541688865116905af1612205613e44565b501561223d57601d9361222991838752601c85528660408120555116601054613ffa565b6010558352524260408220556001600b5580f35b6040516312171d8360e31b8152600490fd5b6064906040519062461bcd60e51b82526004820152601060248201526f105b1c9958591e481d5c19dc9859195960821b6044820152fd5b503461029b576102d8612298366134c6565b90604051926122a6846133b4565b858452613a2d565b503461029b578060031936011261029b576122c7614188565b6122d44760105490613ffa565b801561272b5781829082916001600160a01b03918260185460081c16936040516305391b2760e31b815260209081816004818a5afa908115612720578991612703575b506040516331056e5760e21b8152968288600481845afa9788156126f8578a986126d9575b506040516358710f4560e11b81528381600481855afa9081156126a05784908c926126ab575b50604051636e88a7bd60e01b81529192829060049082905afa9283156126a05788918c9461266d575b50169881612494575b5050909192939495965087808080868a600a54165af16123b2613e44565b501561223d578361241c575b50907f1895c62887d1ed7e831b47190e1164cd03e07077102c7891b069574cb27570d3958594939260c096600a541695806014541692604051978852169086015260408501526060840152608083015260a0820152a16001600b5580f35b8786601497969594939754169182612453575b50808080935085888b165af1612443613e44565b501561223d5790919293386123be565b801561242f57818093965061271061246e8293889798614489565b0480975af161247b613e44565b501561223d578261248b91613ffa565b9038878161242f565b87600a5416996040516370a0823160e01b81528b60048201528581602481855afa908115612662578d91612635575b501561260b576040519a63ea66aeb360e01b8c5260048c01528b8b602481845afa9a8b15612600578c9b6125e3575b508b9a8c5b81518110156125d2578d61250b82846140d2565b516040519063e4b3758b60e01b825260048201528881602481885afa9182156125c65791612595575b5061254757612542906140c3565b6124f7565b5050509091929394959697985060015b1561256e575b50505b908695949392913880612394565b61258d9294955061258460059261271092614489565b04048094613ffa565b91388061255d565b90508781813d83116125bf575b6125ac81836133cf565b810103126125bb575138612534565b8e80fd5b503d6125a2565b604051903d90823e3d90fd5b505050909192939495969798612557565b6125f9919b508c3d8091833e61077881836133cf565b99386124f2565b6040513d8e823e3d90fd5b50959697985061271091945061262f9293506126279086614489565b048094613ffa565b91612560565b90508581813d831161265b575b61264c81836133cf565b810103126113515751386124c3565b503d612642565b6040513d8f823e3d90fd5b85809295508193503d8311612699575b61268781836133cf565b8101031261135557879051923861238b565b503d61267d565b6040513d8d823e3d90fd5b809250813d83116126d2575b6126c181836133cf565b810103126113555751836004612362565b503d6126b7565b6126f1919850833d85116107b8576107aa81836133cf565b963861233c565b6040513d8c823e3d90fd5b61271a9150823d84116107b8576107aa81836133cf565b38612317565b6040513d8b823e3d90fd5b60405162461bcd60e51b81526020600482015260126024820152712737903cb4b2b632103a379031b630b4b69760711b6044820152606490fd5b503461029b57604036600319011261029b5760206116f561278461349a565b60243590613f6b565b503461029b576020908160031936011261029b57600435916127ad614188565b6127d06121038460005260026020526001600160a01b0360406000205416151590565b6127d983613964565b906127f06001600160a01b0392833391161461440b565b838352601c81526040832090604051916128098361333a565b54906001600160801b0393848316928385526001600160401b039083860194828260801c168652604087019160c01c825215612ccf5782846018546004604051809481936305391b2760e31b835260081c165afa908115612720579084918a91612cb2575b501694604051956370a0823160e01b875233600488015260249686818981855afa9081156126a0578b91612c85575b5015908115612c7b575b50612c18575b505050848451167f21e12a7cad0da5928167e1084ea4d5fdf8d9af66657a2543a9ac76a0ca081477604051806128fb33948c839092916001600160801b036020916040840195845216910152565b0390a27ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce782604051898152a161293087613964565b8082169081612b8e57505060085487875260098352604087205561295387614466565b6008546000199190828101908111612b7b578888526009845261297a60408920549161377b565b90549060031b1c6129a78161298e8461377b565b90919082549060031b91821b91600019901b1916179055565b88526009845260408820558787528660408120556008548015612b685782016129e36129d28261377b565b8154906000199060031b1b19169055565b600855878752601d835260408720548015908115612b51575b5015612aec5787918791612a0f84613964565b908484526004865260408420916001600160601b0360a01b928381541690551691828452600386526040842090815401905583835260028552604083209081541690557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a48480808087875116335af1612a89613e44565b501561223d57601c908686525283604081205560195490600160401b821015612ada5750612acf939461298e826001612ac594016019556137c8565b5116601054613ffa565b6010556001600b5580f35b634e487b7160e01b8552604160045284fd5b60405162461bcd60e51b8152600481018490526038818601527f41667465722075706772616465282920746f6b656e732063616e206e6f74206260448201527765207472616e7366657272656420666f722037206461797360401b6064820152608490fd5b62093a809150612b619042613ffa565b11386129fc565b634e487b7160e01b885260316004528488fd5b634e487b7160e01b885260116004528488fd5b612b97906138a1565b600019810191908211612b7b57888852600784526040882054828103612bdc575b50888852876040812055875260068352604087209087528252856040812055612953565b8189526006855260408920838a5285526040892054828a526006865260408a20828b5286528060408b2055895260078552604089205538612bb8565b8280612c299351169151169061444b565b164210612c38573880806128ad565b5060176064926040519262461bcd60e51b845260048401528201527f4c6f636b20706572696f64206e6f7420657870697265640000000000000000006044820152fd5b90503014386128a7565b90508681813d8311612cab575b612c9c81836133cf565b8101031261135557513861289d565b503d612c92565b612cc99150863d88116107b8576107aa81836133cf565b3861286e565b60405162461bcd60e51b8152600481018590526011602482015270139bdd1a1a5b99c81d1bc81c99599d5b99607a1b6044820152606490fd5b503461029b578060031936011261029b57601a54604080516001600160801b0383168152608083811c6001600160401b0316602083015260c084901c62ffffff9081169383019390935260d884901c909216606082015260f09290921c60ff161515908201528060a081010390f35b503461029b576020806003193601126109675760043590612d96614188565b612d9e6137ff565b600a54604051630951888f60e01b81523060048201526001600160a01b039182166024820152604481018490528281606481886002604360981b015af18015612e5057612e23575b50907fa1c8454e70ae3014662889130afe679a3c6067101b0c4225f0cbfd93fa66348b92604092600a5416918351928352820152a16001600b5580f35b91809192813d8311612e49575b612e3a81836133cf565b81010312611371579038612de6565b503d612e30565b6040513d87823e3d90fd5b503461029b576102d8612e6d366134c6565b91612e80612e7b8433613ac8565b6139cb565b613b90565b503461029b578060031936011261029b576020600854604051908152f35b503461029b578060031936011261029b57602060ff601854166040519015158152f35b503461029b57604036600319011261029b57612ee061349a565b602435906001600160a01b038080612ef785613964565b16921691808314612ff957803314908115612fd8575b5015612f6d57828452600460205260408420805473ffffffffffffffffffffffffffffffffffffffff191683179055612f4583613964565b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b60405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608490fd5b9050845260056020526040842033855260205260ff60408520541638612f0d565b60405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608490fd5b503461029b57602036600319011261029b576020611d2e600435613989565b503461029b578060031936011261029b576103db6114426135fe565b503461029b57602036600319011261029b5760043563ffffffff60e01b811680910361096757602090632483248360e11b81149081156130c9575b506040519015158152f35b63780e9d6360e01b8114915081156130e3575b50826130be565b6380ac58cd60e01b811491508115613115575b8115613104575b50826130dc565b6301ffc9a760e01b149050826130fd565b635b5e139f60e01b811491506130f6565b50604036600319011261029b5761313b613328565b6001600160401b03906024358281116113715761315c90369060040161340b565b91613165614188565b601b549260ff8460f01c16156132e3576131fd613205916131b062ffffff8761319d82809a60c01c1680159081156132d657506140e6565b60d81c1680159081156132bb575061413c565b60405160208101903360601b8252601481526131cb81613399565b5190207f19457468657265756d205369676e6564204d6573736167653a0a3332000000008852601c52603c87206142f8565b9190916141de565b6001600160a01b0380601554169116036132765761057c92338552601f602052613236604086209184168254614026565b9055601b5460405192906001600160801b0361325185613399565b60078552667072697661746560c81b6020860152803416938260801c16911633614efc565b60405162461bcd60e51b815260206004820152601f60248201527f596f75722077616c6c6574206973206e6f742077686974656c69737465642e006044820152606490fd5b9050338952601f60205261059e60408a205489891690614026565b9050838a16111538610504565b60405162461bcd60e51b815260206004820152601a60248201527f50726976617465206d696e74206973206e6f74206163746976650000000000006044820152606490fd5b6004359062ffffff821682036108fa57565b606081019081106001600160401b0382111761335557604052565b634e487b7160e01b600052604160045260246000fd5b6001600160401b03811161335557604052565b60a081019081106001600160401b0382111761335557604052565b604081019081106001600160401b0382111761335557604052565b602081019081106001600160401b0382111761335557604052565b90601f801991011681019081106001600160401b0382111761335557604052565b6001600160401b03811161335557601f01601f191660200190565b81601f820112156108fa57803590613422826133f0565b9261343060405194856133cf565b828452602083830101116108fa57816000926020809301838601378301015290565b60005b8381106134655750506000910152565b8181015183820152602001613455565b9060209161348e81518092818552858086019101613452565b601f01601f1916010190565b600435906001600160a01b03821682036108fa57565b602435906001600160a01b03821682036108fa57565b60609060031901126108fa576001600160a01b039060043582811681036108fa579160243590811681036108fa579060443590565b60a09060031901126108fa57604051906135148261337e565b816004356001600160801b03811681036108fa5781526024356001600160401b03811681036108fa57602082015262ffffff60443581811681036108fa57604083015260643590811681036108fa5760608201526084359081151582036108fa5760800152565b9060206003198301126108fa576004356001600160401b03928382116108fa57806023830112156108fa5781600401359384116108fa57602484830101116108fa576024019190565b90600182811c921680156135f4575b60208310146135de57565b634e487b7160e01b600052602260045260246000fd5b91607f16916135d3565b60405190600082600e5491613612836135c4565b80835260209360019081811690811561368b575060011461363e575b505061363c925003836133cf565b565b90939150600e6000526000805160206153db833981519152936000915b81831061367357505061363c9350820101388061362e565b8554888401850152948501948794509183019161365b565b91505061363c94925060ff191682840152151560051b820101388061362e565b60405190600082601654916136bf836135c4565b80835260209360019081811690811561368b57506001146136e857505061363c925003836133cf565b9093915060166000527fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b5124289936000915b81831061372f57505061363c9350820101388061362e565b85548884018501529485019487945091830191613717565b90815180825260208080930193019160005b828110613767575050505090565b835185529381019392810192600101613759565b6008548110156137b25760086000527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30190600090565b634e487b7160e01b600052603260045260246000fd5b6019548110156137b25760196000527f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c96950190600090565b6001600160a01b03600a5416330361381357565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b600a54906001600160a01b0380911691826001600160601b0360a01b821617600a55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b6001600160a01b031680156138c157600052600360205260406000205490565b60405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608490fd5b1561391f57565b60405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152606490fd5b60005260026020526001600160a01b0360406000205416613986811515613918565b90565b6139b16139ac8260005260026020526001600160a01b0360406000205416151590565b613918565b60005260046020526001600160a01b036040600020541690565b156139d257565b60405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201526c1c881bdc88185c1c1c9bdd9959609a1b6064820152608490fd5b90613a51939291613a41612e7b8433613ac8565b613a4c838383613b90565b613e74565b15613a5857565b60405162461bcd60e51b815280613a7160048201613a75565b0390fd5b60809060208152603260208201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b60608201520190565b906001600160a01b038080613adc84613964565b16931691838314938415613b0f575b508315613af9575b50505090565b613b0591929350613989565b1614388080613af3565b909350600052600560205260406000208260005260205260ff604060002054169238613aeb565b15613b3d57565b60405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201526437bbb732b960d91b6064820152608490fd5b90613bb690613b9e84613964565b6001600160a01b038481169390929183168414613b36565b818116938415613df35783613d475750600854856000526009602052604060002055613be185614466565b828403613d14575b50600090848252601d602052604090818320548015908115613cfd575b5015613c985790613c44847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9493613c3d89613964565b1614613b36565b858252600460205284818320916001600160601b0360a01b928381541690558584526003602052808420600019815401905581845280842060018154019055878452600260205283209182541617905580a4565b815162461bcd60e51b815260206004820152603860248201527f41667465722075706772616465282920746f6b656e732063616e206e6f74206260448201527765207472616e7366657272656420666f722037206461797360401b6064820152608490fd5b62093a809150613d0d9042613ffa565b1138613c06565b613d1d906138a1565b60406000858152600660205281812083825260205286828220558681526007602052205538613be9565b848403613d55575b50613be1565b613d5e906138a1565b6000198101908111613ddd576000908682526020906007825260409182842054828103613da6575b508884528383812055868452600681528284209184525281205538613d4f565b8785526006825283852083865282528385205488865260068352848620828752835280858720558552600782528385205538613d86565b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b3d15613e6f573d90613e55826133f0565b91613e6360405193846133cf565b82523d6000602084013e565b606090565b9290803b15613f6257613ec5916020916001600160a01b039460405180958194829389630a85bd0160e11b9b8c86523360048701521660248501526044840152608060648401526084830190613475565b03916000968791165af190829082613f1a575b5050613f0c57613ee6613e44565b80519081613f075760405162461bcd60e51b815280613a7160048201613a75565b602001fd5b6001600160e01b0319161490565b909192506020813d8211613f5a575b81613f36602093836133cf565b810103126109675751906001600160e01b03198216820361029b5750903880613ed8565b3d9150613f29565b50505050600190565b613f74816138a1565b821015613fa1576001600160a01b0316600052600660205260406000209060005260205260406000205490565b60405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b6064820152608490fd5b91908203918211613ddd57565b908160209103126108fa57516001600160a01b03811681036108fa5790565b91908201809211613ddd57565b6001600160401b0381116133555760051b60200190565b60209081818403126108fa578051906001600160401b0382116108fa57019180601f840112156108fa57825161407f81614033565b9361408d60405195866133cf565b818552838086019260051b8201019283116108fa578301905b8282106140b4575050505090565b815181529083019083016140a6565b6000198114613ddd5760010190565b80518210156137b25760209160051b010190565b156140ed57565b60405162461bcd60e51b815260206004820152602160248201527f45786365656473206d6178206d696e747320706572207472616e73616374696f6044820152603760f91b6064820152608490fd5b1561414357565b60405162461bcd60e51b815260206004820152601c60248201527f45786365656473206d6178206d696e7473207065722077616c6c6574000000006044820152606490fd5b6002600b5414614199576002600b55565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b60058110156142e257806141ef5750565b6001810361423c5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b600281036142895760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b60031461429257565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b634e487b7160e01b600052602160045260246000fd5b90604181511460001461432657614322916020820151906060604084015193015160001a90614330565b9091565b5050600090600290565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083116143b35791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa156143a65781516001600160a01b038116156143a0579190565b50600190565b50604051903d90823e3d90fd5b50505050600090600390565b156143c657565b60405162461bcd60e51b815260206004820152601760248201527f546f6b656e20494420646f6573206e6f742065786973740000000000000000006044820152606490fd5b1561441257565b60405162461bcd60e51b81526020600482015260116024820152702737ba103a34329027232a1037bbb732b960791b6044820152606490fd5b9190916001600160401b0380809416911601918211613ddd57565b60085490600160401b8210156133555761298e82600161363c940160085561377b565b81810292918115918404141715613ddd57565b601f81116144a8575050565b600090601682527fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b5124289906020601f850160051c83019410614503575b601f0160051c01915b8281106144f857505050565b8181556001016144ec565b90925082906144e3565b601f8111614519575050565b600090601782526000805160206153fb833981519152906020601f850160051c83019410614562575b601f0160051c01915b82811061455757505050565b81815560010161454b565b9092508290614542565b91926060936001600160a01b03829316845260406020850152816040850152848401376000828201840152601f01601f1916010190565b6145c38160005260026020526001600160a01b0360406000205416151590565b15614bc4576145d06136ab565b51156146255761398660206145ec6145e66136ab565b93614d91565b9260405193816146058693518092868087019101613452565b820161461982518093868085019101613452565b010380845201826133cf565b9081600052601d6020526040600020541515600014614ba35760405161464a81613399565b600381526259657360e81b6020820152915b30926040519161466b8361333a565b602a8352602083019260403685378051156137b257603084538051956001968710156137b2576078602183015360295b878111614b5c5750614b18576034614718916146ea956146ba85614d91565b906040519788937268747470733a2f2f626c617374722e78797a2f60681b60208601525180926033860190613452565b8201602f60f81b60338201526147098251809360208785019101613452565b010360148101865201846133cf565b61472181614d91565b9261472a6135fe565b9061473483614d91565b83600052601c6020526147546001600160801b0360406000205416614d91565b93600052601c6020526147876040600020546147816001600160401b0391828160801c169060c01c61444b565b16614d91565b9260405196607b60f81b6020890152661134b2111d101160c91b60218901526147ba81518092602060288c019101613452565b870161088b60f21b602882015268113730b6b2911d101160b91b602a8201526147ed825180936020603385019101613452565b019761202360f01b60338a015261480e82518093602060358d019101613452565b61088b60f21b6035838b010152691134b6b0b3b2911d101160b11b6037838b01015260009860175491614840836135c4565b92818116908115614aee5750600114614a98575b505050509260c1928592614a4095614a45989961088b60f21b8152701132bc3a32b93730b62fbab936111d101160791b600282015261489d825180936020601385019101613452565b019161088b60f21b60138401526e2261747472696275746573223a205b60881b6015840152607b60f81b60248401527f2274726169745f74797065223a202256616c7565206c6f636b656420287765696025840152620a488b60ea1b6045840152680113b30b63ab2911d160bd1b92836048820152614926825180936020605185019101613452565b01611f4b60f21b92836051830152607b60f81b60538301527f22646973706c61795f74797065223a202264617465222c00000000000000000060548301527f2274726169745f74797065223a202256616c7565206c6f636b656420756e7469606b830152621b088b60ea1b608b830152608e8201526149af825180936020609785019101613452565b01906097820152607b60f81b60998201527f2274726169745f74797065223a20225570677261646564222c00000000000000609a82015269113b30b63ab2911d101160b11b60b3820152614a0d82518093602060bd85019101613452565b01601160f91b60bd820152607d60f81b8060be830152605d60f81b60bf83015260c08201520360a18101845201826133cf565b614c4b565b613986603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000006020830152614a888151809260208686019101613452565b810103601d8101845201826133cf565b909192995060176000526000805160206153fb833981519152906000915b848310614ad6575050509790970190960160410195828282614a45614854565b8054848d018401604101526020909201918101614ab6565b60ff1916604193909501838101959095525050811515909102909101019650828282614a45614854565b606460405162461bcd60e51b815260206004820152602060248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b90600f811660108110156137b25783518310156137b2576f181899199a1a9b1b9c1cb0b131b232b360811b901a8383016020015360041c908015613ddd576000190161469b565b604051614baf81613399565b60028152614e6f60f01b60208201529161465c565b60405162461bcd60e51b815260206004820152602760248201527f4552433732313a2055524920717565727920666f72206e6f6e6578697374656e6044820152663a103a37b5b2b760c91b6064820152608490fd5b90614c23826133f0565b614c3060405191826133cf565b8281528092614c41601f19916133f0565b0190602036910137565b805115614d7d57604051614c5e8161333a565b604081527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208201527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f60408201528151600292838201809211613ddd576003918290046001600160fe1b0381168103613ddd57614ce0908594951b614c19565b936020850193829183518401925b838110614d2c5750505050510680600114614d1957600214614d0e575090565b603d90600019015390565b50603d9081600019820153600119015390565b85600491979293949701918251600190603f9082828260121c16880101518453828282600c1c16880101518385015382828260061c1688010151888501531685010151878201530195929190614cee565b50604051614d8a816133b4565b6000815290565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000080821015614ec6575b506d04ee2d6d415b85acef810000000080831015614eb7575b50662386f26fc1000080831015614ea8575b506305f5e10080831015614e99575b5061271080831015614e8a575b506064821015614e7a575b600a80921015614e70575b600190816021614e28828701614c19565b95860101905b614e3a575b5050505090565b600019019083906f181899199a1a9b1b9c1cb0b131b232b360811b8282061a835304918215614e6b57919082614e2e565b614e33565b9160010191614e17565b9190606460029104910191614e0c565b60049193920491019138614e01565b60089193920491019138614df4565b60109193920491019138614de5565b60209193920491019138614dd3565b604093508104915038614dba565b90614ede82614033565b614eeb60405191826133cf565b8281528092614c41601f1991614033565b909262ffffff9096959296169283156152bd57600896614f1d858954614026565b60115410615282576001600160801b038092169185830296818816978803613ddd57811696870361523d57614f5186614ed4565b986000906001600160401b0394854216925b898110614fed57505050505096614fdd6001600160a01b037f3c17cb77a104e5fa9f5e5427339add873947fe1b19af0177401348d86d2edece94614fba94614fe89a9b60405196879660a0885260a0880190613747565b998b60208801526040870152166060850152838803608085015216953395613475565b0390a3601054614026565b601055565b808d615002614ffa61534e565b9283926140d2565b5260408051906150118261333a565b8482526020918281018b8b1681528282019089825285600052601c85528a84600020935116906001600160401b0360801b905160801b16916001600160401b0360c01b905160c01b1691171790556001600160a01b038b169182156151fc576150996150938560005260026020526001600160a01b0360406000205416151590565b15615302565b8654846000526009825282600020556150b184614466565b6150ba8c6138a1565b83600052600682528260002081600052825284836000205584600052600782528260002055601d8152816000205480159081156151e5575b50156151825790600284939261512561509361517d989760005260026020526001600160a01b0360406000205416151590565b836000526003815282600020600181540190558460005252600020816001600160601b0360a01b82541617905560007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a46140c3565b614f63565b608491519062461bcd60e51b82526004820152603860248201527f41667465722075706772616465282920746f6b656e732063616e206e6f74206260448201527765207472616e7366657272656420666f722037206461797360401b6064820152fd5b62093a8091506151f59042613ffa565b11386150f2565b606491519062461bcd60e51b825280600483015260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152fd5b60405162461bcd60e51b815260206004820152601460248201527f496e636f7272656374206d696e742070726963650000000000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601360248201527213585e081cdd5c1c1b1e48195e18d959591959606a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152601760248201527f5175616e746974792063616e6e6f74206265207a65726f0000000000000000006044820152606490fd5b1561530957565b60405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606490fd5b601954156153cd576019546000198101818111613ddd5761536e816137c8565b90549060031b1c917ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a1156153b7576153b16129d2826137c8565b60195590565b634e487b7160e01b600052603160045260246000fd5b600c5460018101600c559056febb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fdc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c158d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac802a26469706673582212202086ade0891c51c66c0ac38b22f2b85dfa2572dc4b401923bcb3342ecbc6189664736f6c63430008150033
Deployed Bytecode
0x6080604052600436101561001257600080fd5b6000803560e01c80626059fd1461312657806301ffc9a71461308357806306fdde0314613067578063081812fc14613048578063095ea7b314612ec6578063158ef93e14612ea357806318160ddd14612e8557806323b872dd14612e5b578063268e280314612d77578063269c759b14612d08578063278ecde11461278d5780632f745c5914612765578063406cf229146122ae57806342842e0e1461228657806345977d03146120c15780634d9b9426146120405780634f6ccce714611fbc57806353c838e014611eb357806355f804b314611d3f5780636352211e14611d0f57806368447c9314611ce85780636c0360eb14611ccc57806370a0823114611ca8578063715018a614611c4b5780637d58367614611ab65780637e1c175714611a8c5780638da5cb5b14611a655780639106a059146119f657806395d89b411461195c578063966dae0e1461193557806399c89e81146118a25780639dbec671146117d1578063a22cb465146116fd578063a263a9eb146116d5578063a68aa96714611649578063b88d4fde146115fa578063bf4ad33814611456578063c87b56dd14611422578063d3381438146113b1578063d3cf00a314611393578063d5abeb0114611375578063d93a11ed1461096b578063d98de53e1461049f578063e4b3758b14610475578063e5328e0614610457578063e985e9c514610402578063ea66aeb31461038f578063ef81b4d414610368578063ef97ead81461032f578063f2fde38b1461029e5763f4dadc611461024d57600080fd5b3461029b57602036600319011261029b5760406060916004358152601c6020522054604051906001600160801b03811682526001600160401b038160801c16602083015260c01c6040820152f35b80fd5b503461029b57602036600319011261029b576102b861349a565b6102c06137ff565b6001600160a01b038116156102db576102d890613857565b80f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b503461029b57602036600319011261029b576004359060195482101561029b57602061035a836137c8565b90546040519160031b1c8152f35b503461029b578060031936011261029b5760206001600160a01b0360155416604051908152f35b503461029b57602036600319011261029b576103a961349a565b6103b2816138a1565b906103bc82614ed4565b925b8281106103df57604051602080825281906103db90820187613747565b0390f35b806103ed6103fd9284613f6b565b6103f782876140d2565b526140c3565b6103be565b503461029b57604036600319011261029b5761041c61349a565b60406104266134b0565b926001600160a01b0380931681526005602052209116600052602052602060ff604060002054166040519015158152f35b503461029b578060031936011261029b576020601054604051908152f35b503461029b57602036600319011261029b5760406020916004358152601d83522054604051908152f35b50602080600319360112610967576104b5613328565b906104be614188565b60ff601a5460f01c16156109235761012c6104db60125442613ffa565b106105b3575b61057c91601a5461051e62ffffff8261050a82809560c01c1680159081156105a6575b506140e6565b60d81c168015908115610584575b5061413c565b338552601e8352610536604086209183168254614026565b9055601a54906001600160801b0391657075626c696360d01b6040519461055c86613399565b60068652850152823416926001600160401b038260801c16911633614efc565b6001600b5580f35b9050338752601e855261059e604088205484861690614026565b111538610518565b9050838716111538610504565b6001600160a01b03918260185460081c166040516305391b2760e31b918282528482600481845afa91821561078757869286918991610906575b506024604051809981936370a0823160e01b8352336004840152165afa9586156107875787966108d2575b50851515806108c3575b1561082257600d9081549361063d62ffffff87168096614026565b601460115404106107ca579086899260046040518094819382525afa9081156107bf578291610792575b5060246040518095819363ea66aeb360e01b8352336004840152165afa918215610787578792610763575b508691875b878110610710575b5050509091929350036106b257906104e1565b60405162461bcd60e51b815260048101839052603060248201527f596f7520646f6e2774206f776e20656e6f756768206b65797320746f206d696e60448201526f742061736b6564207175616e7469747960801b6064820152608490fd5b61071a81836140d2565b5189528680526040892080541561073b575b50610736906140c3565b610697565b936107509194600180915584540184556140c3565b9284841461075e573861072c565b61069f565b6107809192503d8089833e61077881836133cf565b81019061404a565b9038610692565b6040513d89823e3d90fd5b6107b29150873d89116107b8575b6107aa81836133cf565b810190614007565b38610667565b503d6107a0565b6040513d84823e3d90fd5b60405162461bcd60e51b815260048101889052602a60248201527f4d757374206e6f74206d696e74206d6f7265207468616e203525206f6620746f60448201526974616c20737570706c7960b01b6064820152608490fd5b60405162461bcd60e51b815260048101869052606760248201527f5468652066697273742035206d696e206f66207075626c6963206d696e74206160448201527f726520726573657276656420666f7220424c41535452206b657920686f6c646560648201527f727320286d6178206d696e74207175616e746974793a203120706572206b6579608482015266206f776e65642960c81b60a482015260c490fd5b508562ffffff85161115610622565b9095508481813d83116108ff575b6108ea81836133cf565b810103126108fa57519438610618565b600080fd5b503d6108e0565b61091d9150823d84116107b8576107aa81836133cf565b386105ed565b6064906040519062461bcd60e51b82526004820152601960248201527f5075626c6963206d696e74206973206e6f7420616374697665000000000000006044820152fd5b5080fd5b503461029b5761028036600319011261029b5761098661349a565b9061098f6134b0565b6044356001600160a01b03938482168203611371576064356001600160401b03811161136d576109c390369060040161340b565b6084356001600160401b038111611369576109e290369060040161340b565b60c4356001600160401b03811161136557610a0190369060040161340b565b60e4356001600160401b03811161136157610a2090369060040161340b565b916101043593898516850361135d5761012435958a871687036113595760a0366101431901126113595760405197610a578961337e565b610144356001600160801b038116810361134d578952610164356001600160401b038116810361134d5760208a015262ffffff61018435166101843503611355576101843560408a01526101a43562ffffff8116810361134d5760608a01526101c43515156101c43503611355576101c43560808a015260a0366101e31901126113555760405199610ae88b61337e565b6101e4356001600160801b0381168103611351578b526001600160401b036102043516610204350361134d576102043560208c015262ffffff6102243516610224350361134d576102243560408c015262ffffff6102443516610244350361134d576102443560608c0152610264351515610264350361134d576102643560808c015260185460ff811661133c57600160a4351061132a5760ff19166001176018558c92610b9590613857565b610100600160a81b036018549160081b1690610100600160a81b03191617601855166001600160601b0360a01b60135416176013558051906001600160401b03821161131657610be6600e546135c4565b601f81116112af575b50602090601f831160011461123a57610c2092918b918361100d575b50508160011b916000199060031b1c19161790565b600e555b8051906001600160401b03821161122657610c40600f546135c4565b601f81116111bf575b50602090601f831160011461114a57610c7992918a918361100d5750508160011b916000199060031b1c19161790565b600f555b60a4356011558051906001600160401b03821161113657610ca882610ca36016546135c4565b61449c565b602090601f83116001146110af57610cd7929189918361100d5750508160011b916000199060031b1c19161790565b6016555b8051906001600160401b03821161109b579087939291610d0582610d006017546135c4565b61450d565b602090601f83116001146110185792610d41836080989694889694610ec49b99958d9261100d5750508160011b916000199060031b1c19161790565b6017555b166001600160601b0360a01b6014541617601455166001600160601b0360a01b6015541617601555610d976001600160801b038251166001600160801b03166001600160801b0319601a541617601a55565b6020810151601a805467ffffffffffffffff60801b191660809290921b67ffffffffffffffff60801b169190911790556040810151601a805460608401519386015160ff60f01b90151560f01b1662ffffff60d81b60d89590951b851662ffffff60c01b60c09590951b851666ffffffffffffff60c01b1990931692909217919091171790559065ffffffffffff60c01b19610e536001600160801b038551166001600160801b03166001600160801b0319601b541617601b55565b6020840151601b805467ffffffffffffffff60801b191660809290921b67ffffffffffffffff60801b16919091179055604084015192601b5492606086015160d81b169360c01b1691161717601b5501511515601b549060ff60f01b90151560f01b169060ff60f01b191617601b55565b6002604360981b0191823b156109675760405163388a0bbd60e11b815292828460048183855af18015610fd357610ff9575b829350803b15610ff557828091600460405180948193634e606c4760e01b83525af1908115610fd3578391610fde575b5050600460208260185460081c166040519283809263102b8f8560e21b82525afa908115610fd3578391610fb4575b50732536fe9ab3f511540f2f9e2ec2a805005c3dd80091823b15610faf57602484928360405195869485936336b91f2b60e01b85521660048401525af180156107bf57610f9f5750f35b610fa89061336b565b61029b5780f35b505050fd5b610fcd915060203d6020116107b8576107aa81836133cf565b38610f55565b6040513d85823e3d90fd5b610fe79061336b565b610ff2578138610f26565b50fd5b5050fd5b9190926110059061336b565b908290610ef6565b015190503880610c0b565b90601789526000805160206153fb83398151915291895b601f198516811061108057508387959293610ec49a989460019360809b9997601f19811610611067575b505050811b01601755610d45565b015160001960f88460031b161c19169055388080611059565b8183015184558b97506001909301926020928301920161102f565b634e487b7160e01b87526041600452602487fd5b601689528892917fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b5124289915b601f198416851061111b576001945083601f19811610611102575b505050811b01601655610cdb565b015160001960f88460031b161c191690553880806110f4565b818101518355602094850194600190930192909101906110d9565b634e487b7160e01b88526041600452602488fd5b600f8a5289929160008051602061541b833981519152915b601f19841685106111a4576001945083601f1981161061118b575b505050811b01600f55610c7d565b015160001960f88460031b161c1916905538808061117d565b81810151835560209485019460019093019290910190611162565b600f8a52601f830160051c60008051602061541b8339815191520160208410611211575b601f820160051c60008051602061541b8339815191520181106112065750610c49565b8a81556001016111e3565b5060008051602061541b8339815191526111e3565b634e487b7160e01b89526041600452602489fd5b600e8b528a92916000805160206153db833981519152915b601f1984168510611294576001945083601f1981161061127b575b505050811b01600e55610c24565b015160001960f88460031b161c1916905538808061126d565b81810151835560209485019460019093019290910190611252565b600e8b52601f830160051c6000805160206153db8339815191520160208410611301575b601f820160051c6000805160206153db8339815191520181106112f65750610bef565b8b81556001016112d3565b506000805160206153db8339815191526112d3565b634e487b7160e01b8a52604160045260248afd5b6040516325ab076960e01b8152600490fd5b60405162dc149f60e41b8152600490fd5b8b80fd5b8c80fd5b8a80fd5b8980fd5b8880fd5b8780fd5b8680fd5b8580fd5b8480fd5b8380fd5b503461029b578060031936011261029b576020601154604051908152f35b503461029b578060031936011261029b576020601254604051908152f35b503461029b57602036600319011261029b577fe81fbf9dcd9efb641e9dd6a384b82aedac00c55a93402509bd9866fab1a92afa60406001600160a01b036113f661349a565b6113fe6137ff565b16806001600160601b0360a01b60155416176015558151903382526020820152a180f35b503461029b57602036600319011261029b576103db6114426004356145a3565b604051918291602083526020830190613475565b503461029b5760a036600319011261029b577fca805018b1f306f78c930fd9dd300fc655fa266c44ad5e355f8c2d19d5ea8f64611492366134fb565b61149a6137ff565b601a54906115dc6001600160801b03825116926114cd846001600160801b03166001600160801b0319601a541617601a55565b6020830151601a805467ffffffffffffffff60801b1916608083901b67ffffffffffffffff60801b161790556001600160401b0316936040840151601a8054606087015160809097015166ffffffffffffff60c01b1990911660c084901b62ffffff60c01b161760d888901b62ffffff60d81b161790151560f081901b60ff60f01b169190911790915562ffffff96909391929160ff9060f01c1615806115eb575b6115e2575b6001600160a01b03600a54169187604051988998169416928794909695926001600160401b03906001600160801b0360a096946001600160a01b0360c08a019b16895216602088015216604086015262ffffff80921660608601521660808401521515910152565b0390a180f35b42601255611574565b5060ff601a5460f01c1661156f565b503461029b57608036600319011261029b5761161461349a565b61161c6134b0565b606435916001600160401b0383116113715761163f6102d893369060040161340b565b9160443591613a2d565b503461029b578060031936011261029b576116626137ff565b601b805460ff60f01b19811660f091821c60ff90811615831b60ff60f01b169190911792839055600a54604080516001600160a01b039290921682529390921c16151560208201527fe151bf9d2a434324b5e13c5bdff9bd2e9ab2e30c657f586da54bbe88cf1d8b0691819081016115dc565b503461029b578060031936011261029b5760206116f54760105490613ffa565b604051908152f35b503461029b57604036600319011261029b5761171761349a565b602435908115158092036117cd576001600160a01b031690813314611788573383526005602052604083208284526020526040832060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b60405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606490fd5b8280fd5b503461029b578060031936011261029b57604051908082601754916117f5836135c4565b92838352602094600191868382169182600014611880575050600114611838575b5050611824925003836133cf565b6103db604051928284938452830190613475565b90859250601782526000805160206153fb8339815191525b85831061186857505061182493508201013880611816565b80548389018501528794508693909201918101611850565b925093505061182494915060ff191682840152151560051b8201013880611816565b503461029b578060031936011261029b576118bb6137ff565b7ff2721e078a20e7f6ba187f7a54783e6e4cea86087bafc68840732db61dec478860ff601a548160f01b828260f01c161560f01b16908260f01b19161780601a5560f01c168061192c575b600a54604080516001600160a01b039092168252911515602082015290819081016115dc565b42601255611906565b503461029b578060031936011261029b5760206001600160a01b0360135416604051908152f35b503461029b578060031936011261029b57604051908082600f5491611980836135c4565b928383526020946001918683821691826000146118805750506001146119ae575050611824925003836133cf565b90859250600f825260008051602061541b8339815191525b8583106119de57505061182493508201013880611816565b805483890185015287945086939092019181016119c6565b503461029b578060031936011261029b57601b54604080516001600160801b0383168152608083811c6001600160401b0316602083015260c084901c62ffffff9081169383019390935260d884901c909216606082015260f09290921c60ff161515908201528060a081010390f35b503461029b578060031936011261029b5760206001600160a01b03600a5416604051908152f35b503461029b578060031936011261029b5760206001600160a01b0360185460081c16604051908152f35b503461029b57611ac53661357b565b611ad09291926137ff565b6001600160401b038111611c3757611aed81610d006017546135c4565b8192601f8211600114611ba757611b3d828085967f0e97d384f3f2db9658556130716bebad5af0675b729419b713437de32653febc9691611b9c575b508160011b916000199060031b1c19161790565b6017555b611b51604051928392338461456c565b0390a1611b5f6016546135c4565b15611b675780f35b7f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c60406011548151908482526020820152a180f35b905083013538611b29565b60178352601f198216936000805160206153fb83398151915290845b868110611c1f5750837f0e97d384f3f2db9658556130716bebad5af0675b729419b713437de32653febc959610611c05575b5050600182811b01601755611b41565b820135600019600385901b60f8161c191690553880611bf5565b90916020600181928587013581550193019101611bc3565b634e487b7160e01b82526041600452602482fd5b503461029b578060031936011261029b57611c646137ff565b806001600160a01b03600a546001600160601b0360a01b8116600a55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461029b57602036600319011261029b5760206116f5611cc761349a565b6138a1565b503461029b578060031936011261029b576103db6114426136ab565b503461029b578060031936011261029b5760206001600160a01b0360145416604051908152f35b503461029b57602036600319011261029b576020611d2e600435613964565b6001600160a01b0360405191168152f35b503461029b57611d4e3661357b565b611d599291926137ff565b6001600160401b038111611c3757611d7681610ca36016546135c4565b8192601f8211600114611e1157611dc5828085967f78cd0c51de67bd306f7a477494a110772ec9e86ffcfb04448079856a62dbe3b59691611b9c57508160011b916000199060031b1c19161790565b6016555b611dd9604051928392338461456c565b0390a17f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c60406011548151908482526020820152a180f35b60168352601f198216937fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b512428990845b868110611e9b5750837f78cd0c51de67bd306f7a477494a110772ec9e86ffcfb04448079856a62dbe3b5959610611e81575b5050600182811b01601655611dc9565b820135600019600385901b60f8161c191690553880611e71565b90916020600181928587013581550193019101611e3f565b503461029b5760a036600319011261029b577f059691c8ca8b8a0a17d6d79c46d63bf67f157d28700329f2f842fc08c1cf4d6b611eef366134fb565b611ef76137ff565b6001600160801b0381511690611f23826001600160801b03166001600160801b0319601b541617601b55565b6020810151601b805467ffffffffffffffff60801b1916608083901b67ffffffffffffffff60801b161790556115dc906001600160401b03166040830151601b8054606086015160809096015166ffffffffffffff60c01b1990911660c084901b62ffffff60c01b161760d887901b62ffffff60d81b161790151560f081901b60ff60f01b169190911790915562ffffff959092611574565b503461029b57602036600319011261029b57600435600854811015611fe65761035a60209161377b565b60405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b6064820152608490fd5b50608036600319011261029b5761205561349a565b602435906001600160801b03908183168303611371576044356001600160401b038116810361136d576064359062ffffff82168203611369576102d89461209a6137ff565b604051946120a786613399565b600586526437bbb732b960d91b6020870152341693614efc565b503461029b5760208060031936011261096757600435906120e0614188565b6121086121038360005260026020526001600160a01b0360406000205416151590565b6143bf565b818352601d8152604083205461224f5761212182613964565b916121386001600160a01b0393843391161461440b565b808452601c82526040842084808080604051946121548661333a565b54976001600160801b0398898116908188526001600160401b038160801c168a89015260c01c60408801527f0c3fdcacbee530581c67c89a851ff8052aa367c589919df3056398ce311a237d604051806121c633948c839092916001600160801b036020916040840195845216910152565b0390a27ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce788604051898152a1600a541688865116905af1612205613e44565b501561223d57601d9361222991838752601c85528660408120555116601054613ffa565b6010558352524260408220556001600b5580f35b6040516312171d8360e31b8152600490fd5b6064906040519062461bcd60e51b82526004820152601060248201526f105b1c9958591e481d5c19dc9859195960821b6044820152fd5b503461029b576102d8612298366134c6565b90604051926122a6846133b4565b858452613a2d565b503461029b578060031936011261029b576122c7614188565b6122d44760105490613ffa565b801561272b5781829082916001600160a01b03918260185460081c16936040516305391b2760e31b815260209081816004818a5afa908115612720578991612703575b506040516331056e5760e21b8152968288600481845afa9788156126f8578a986126d9575b506040516358710f4560e11b81528381600481855afa9081156126a05784908c926126ab575b50604051636e88a7bd60e01b81529192829060049082905afa9283156126a05788918c9461266d575b50169881612494575b5050909192939495965087808080868a600a54165af16123b2613e44565b501561223d578361241c575b50907f1895c62887d1ed7e831b47190e1164cd03e07077102c7891b069574cb27570d3958594939260c096600a541695806014541692604051978852169086015260408501526060840152608083015260a0820152a16001600b5580f35b8786601497969594939754169182612453575b50808080935085888b165af1612443613e44565b501561223d5790919293386123be565b801561242f57818093965061271061246e8293889798614489565b0480975af161247b613e44565b501561223d578261248b91613ffa565b9038878161242f565b87600a5416996040516370a0823160e01b81528b60048201528581602481855afa908115612662578d91612635575b501561260b576040519a63ea66aeb360e01b8c5260048c01528b8b602481845afa9a8b15612600578c9b6125e3575b508b9a8c5b81518110156125d2578d61250b82846140d2565b516040519063e4b3758b60e01b825260048201528881602481885afa9182156125c65791612595575b5061254757612542906140c3565b6124f7565b5050509091929394959697985060015b1561256e575b50505b908695949392913880612394565b61258d9294955061258460059261271092614489565b04048094613ffa565b91388061255d565b90508781813d83116125bf575b6125ac81836133cf565b810103126125bb575138612534565b8e80fd5b503d6125a2565b604051903d90823e3d90fd5b505050909192939495969798612557565b6125f9919b508c3d8091833e61077881836133cf565b99386124f2565b6040513d8e823e3d90fd5b50959697985061271091945061262f9293506126279086614489565b048094613ffa565b91612560565b90508581813d831161265b575b61264c81836133cf565b810103126113515751386124c3565b503d612642565b6040513d8f823e3d90fd5b85809295508193503d8311612699575b61268781836133cf565b8101031261135557879051923861238b565b503d61267d565b6040513d8d823e3d90fd5b809250813d83116126d2575b6126c181836133cf565b810103126113555751836004612362565b503d6126b7565b6126f1919850833d85116107b8576107aa81836133cf565b963861233c565b6040513d8c823e3d90fd5b61271a9150823d84116107b8576107aa81836133cf565b38612317565b6040513d8b823e3d90fd5b60405162461bcd60e51b81526020600482015260126024820152712737903cb4b2b632103a379031b630b4b69760711b6044820152606490fd5b503461029b57604036600319011261029b5760206116f561278461349a565b60243590613f6b565b503461029b576020908160031936011261029b57600435916127ad614188565b6127d06121038460005260026020526001600160a01b0360406000205416151590565b6127d983613964565b906127f06001600160a01b0392833391161461440b565b838352601c81526040832090604051916128098361333a565b54906001600160801b0393848316928385526001600160401b039083860194828260801c168652604087019160c01c825215612ccf5782846018546004604051809481936305391b2760e31b835260081c165afa908115612720579084918a91612cb2575b501694604051956370a0823160e01b875233600488015260249686818981855afa9081156126a0578b91612c85575b5015908115612c7b575b50612c18575b505050848451167f21e12a7cad0da5928167e1084ea4d5fdf8d9af66657a2543a9ac76a0ca081477604051806128fb33948c839092916001600160801b036020916040840195845216910152565b0390a27ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce782604051898152a161293087613964565b8082169081612b8e57505060085487875260098352604087205561295387614466565b6008546000199190828101908111612b7b578888526009845261297a60408920549161377b565b90549060031b1c6129a78161298e8461377b565b90919082549060031b91821b91600019901b1916179055565b88526009845260408820558787528660408120556008548015612b685782016129e36129d28261377b565b8154906000199060031b1b19169055565b600855878752601d835260408720548015908115612b51575b5015612aec5787918791612a0f84613964565b908484526004865260408420916001600160601b0360a01b928381541690551691828452600386526040842090815401905583835260028552604083209081541690557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a48480808087875116335af1612a89613e44565b501561223d57601c908686525283604081205560195490600160401b821015612ada5750612acf939461298e826001612ac594016019556137c8565b5116601054613ffa565b6010556001600b5580f35b634e487b7160e01b8552604160045284fd5b60405162461bcd60e51b8152600481018490526038818601527f41667465722075706772616465282920746f6b656e732063616e206e6f74206260448201527765207472616e7366657272656420666f722037206461797360401b6064820152608490fd5b62093a809150612b619042613ffa565b11386129fc565b634e487b7160e01b885260316004528488fd5b634e487b7160e01b885260116004528488fd5b612b97906138a1565b600019810191908211612b7b57888852600784526040882054828103612bdc575b50888852876040812055875260068352604087209087528252856040812055612953565b8189526006855260408920838a5285526040892054828a526006865260408a20828b5286528060408b2055895260078552604089205538612bb8565b8280612c299351169151169061444b565b164210612c38573880806128ad565b5060176064926040519262461bcd60e51b845260048401528201527f4c6f636b20706572696f64206e6f7420657870697265640000000000000000006044820152fd5b90503014386128a7565b90508681813d8311612cab575b612c9c81836133cf565b8101031261135557513861289d565b503d612c92565b612cc99150863d88116107b8576107aa81836133cf565b3861286e565b60405162461bcd60e51b8152600481018590526011602482015270139bdd1a1a5b99c81d1bc81c99599d5b99607a1b6044820152606490fd5b503461029b578060031936011261029b57601a54604080516001600160801b0383168152608083811c6001600160401b0316602083015260c084901c62ffffff9081169383019390935260d884901c909216606082015260f09290921c60ff161515908201528060a081010390f35b503461029b576020806003193601126109675760043590612d96614188565b612d9e6137ff565b600a54604051630951888f60e01b81523060048201526001600160a01b039182166024820152604481018490528281606481886002604360981b015af18015612e5057612e23575b50907fa1c8454e70ae3014662889130afe679a3c6067101b0c4225f0cbfd93fa66348b92604092600a5416918351928352820152a16001600b5580f35b91809192813d8311612e49575b612e3a81836133cf565b81010312611371579038612de6565b503d612e30565b6040513d87823e3d90fd5b503461029b576102d8612e6d366134c6565b91612e80612e7b8433613ac8565b6139cb565b613b90565b503461029b578060031936011261029b576020600854604051908152f35b503461029b578060031936011261029b57602060ff601854166040519015158152f35b503461029b57604036600319011261029b57612ee061349a565b602435906001600160a01b038080612ef785613964565b16921691808314612ff957803314908115612fd8575b5015612f6d57828452600460205260408420805473ffffffffffffffffffffffffffffffffffffffff191683179055612f4583613964565b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b60405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608490fd5b9050845260056020526040842033855260205260ff60408520541638612f0d565b60405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608490fd5b503461029b57602036600319011261029b576020611d2e600435613989565b503461029b578060031936011261029b576103db6114426135fe565b503461029b57602036600319011261029b5760043563ffffffff60e01b811680910361096757602090632483248360e11b81149081156130c9575b506040519015158152f35b63780e9d6360e01b8114915081156130e3575b50826130be565b6380ac58cd60e01b811491508115613115575b8115613104575b50826130dc565b6301ffc9a760e01b149050826130fd565b635b5e139f60e01b811491506130f6565b50604036600319011261029b5761313b613328565b6001600160401b03906024358281116113715761315c90369060040161340b565b91613165614188565b601b549260ff8460f01c16156132e3576131fd613205916131b062ffffff8761319d82809a60c01c1680159081156132d657506140e6565b60d81c1680159081156132bb575061413c565b60405160208101903360601b8252601481526131cb81613399565b5190207f19457468657265756d205369676e6564204d6573736167653a0a3332000000008852601c52603c87206142f8565b9190916141de565b6001600160a01b0380601554169116036132765761057c92338552601f602052613236604086209184168254614026565b9055601b5460405192906001600160801b0361325185613399565b60078552667072697661746560c81b6020860152803416938260801c16911633614efc565b60405162461bcd60e51b815260206004820152601f60248201527f596f75722077616c6c6574206973206e6f742077686974656c69737465642e006044820152606490fd5b9050338952601f60205261059e60408a205489891690614026565b9050838a16111538610504565b60405162461bcd60e51b815260206004820152601a60248201527f50726976617465206d696e74206973206e6f74206163746976650000000000006044820152606490fd5b6004359062ffffff821682036108fa57565b606081019081106001600160401b0382111761335557604052565b634e487b7160e01b600052604160045260246000fd5b6001600160401b03811161335557604052565b60a081019081106001600160401b0382111761335557604052565b604081019081106001600160401b0382111761335557604052565b602081019081106001600160401b0382111761335557604052565b90601f801991011681019081106001600160401b0382111761335557604052565b6001600160401b03811161335557601f01601f191660200190565b81601f820112156108fa57803590613422826133f0565b9261343060405194856133cf565b828452602083830101116108fa57816000926020809301838601378301015290565b60005b8381106134655750506000910152565b8181015183820152602001613455565b9060209161348e81518092818552858086019101613452565b601f01601f1916010190565b600435906001600160a01b03821682036108fa57565b602435906001600160a01b03821682036108fa57565b60609060031901126108fa576001600160a01b039060043582811681036108fa579160243590811681036108fa579060443590565b60a09060031901126108fa57604051906135148261337e565b816004356001600160801b03811681036108fa5781526024356001600160401b03811681036108fa57602082015262ffffff60443581811681036108fa57604083015260643590811681036108fa5760608201526084359081151582036108fa5760800152565b9060206003198301126108fa576004356001600160401b03928382116108fa57806023830112156108fa5781600401359384116108fa57602484830101116108fa576024019190565b90600182811c921680156135f4575b60208310146135de57565b634e487b7160e01b600052602260045260246000fd5b91607f16916135d3565b60405190600082600e5491613612836135c4565b80835260209360019081811690811561368b575060011461363e575b505061363c925003836133cf565b565b90939150600e6000526000805160206153db833981519152936000915b81831061367357505061363c9350820101388061362e565b8554888401850152948501948794509183019161365b565b91505061363c94925060ff191682840152151560051b820101388061362e565b60405190600082601654916136bf836135c4565b80835260209360019081811690811561368b57506001146136e857505061363c925003836133cf565b9093915060166000527fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b5124289936000915b81831061372f57505061363c9350820101388061362e565b85548884018501529485019487945091830191613717565b90815180825260208080930193019160005b828110613767575050505090565b835185529381019392810192600101613759565b6008548110156137b25760086000527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30190600090565b634e487b7160e01b600052603260045260246000fd5b6019548110156137b25760196000527f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c96950190600090565b6001600160a01b03600a5416330361381357565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b600a54906001600160a01b0380911691826001600160601b0360a01b821617600a55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b6001600160a01b031680156138c157600052600360205260406000205490565b60405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608490fd5b1561391f57565b60405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152606490fd5b60005260026020526001600160a01b0360406000205416613986811515613918565b90565b6139b16139ac8260005260026020526001600160a01b0360406000205416151590565b613918565b60005260046020526001600160a01b036040600020541690565b156139d257565b60405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201526c1c881bdc88185c1c1c9bdd9959609a1b6064820152608490fd5b90613a51939291613a41612e7b8433613ac8565b613a4c838383613b90565b613e74565b15613a5857565b60405162461bcd60e51b815280613a7160048201613a75565b0390fd5b60809060208152603260208201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b60608201520190565b906001600160a01b038080613adc84613964565b16931691838314938415613b0f575b508315613af9575b50505090565b613b0591929350613989565b1614388080613af3565b909350600052600560205260406000208260005260205260ff604060002054169238613aeb565b15613b3d57565b60405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201526437bbb732b960d91b6064820152608490fd5b90613bb690613b9e84613964565b6001600160a01b038481169390929183168414613b36565b818116938415613df35783613d475750600854856000526009602052604060002055613be185614466565b828403613d14575b50600090848252601d602052604090818320548015908115613cfd575b5015613c985790613c44847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9493613c3d89613964565b1614613b36565b858252600460205284818320916001600160601b0360a01b928381541690558584526003602052808420600019815401905581845280842060018154019055878452600260205283209182541617905580a4565b815162461bcd60e51b815260206004820152603860248201527f41667465722075706772616465282920746f6b656e732063616e206e6f74206260448201527765207472616e7366657272656420666f722037206461797360401b6064820152608490fd5b62093a809150613d0d9042613ffa565b1138613c06565b613d1d906138a1565b60406000858152600660205281812083825260205286828220558681526007602052205538613be9565b848403613d55575b50613be1565b613d5e906138a1565b6000198101908111613ddd576000908682526020906007825260409182842054828103613da6575b508884528383812055868452600681528284209184525281205538613d4f565b8785526006825283852083865282528385205488865260068352848620828752835280858720558552600782528385205538613d86565b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b3d15613e6f573d90613e55826133f0565b91613e6360405193846133cf565b82523d6000602084013e565b606090565b9290803b15613f6257613ec5916020916001600160a01b039460405180958194829389630a85bd0160e11b9b8c86523360048701521660248501526044840152608060648401526084830190613475565b03916000968791165af190829082613f1a575b5050613f0c57613ee6613e44565b80519081613f075760405162461bcd60e51b815280613a7160048201613a75565b602001fd5b6001600160e01b0319161490565b909192506020813d8211613f5a575b81613f36602093836133cf565b810103126109675751906001600160e01b03198216820361029b5750903880613ed8565b3d9150613f29565b50505050600190565b613f74816138a1565b821015613fa1576001600160a01b0316600052600660205260406000209060005260205260406000205490565b60405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b6064820152608490fd5b91908203918211613ddd57565b908160209103126108fa57516001600160a01b03811681036108fa5790565b91908201809211613ddd57565b6001600160401b0381116133555760051b60200190565b60209081818403126108fa578051906001600160401b0382116108fa57019180601f840112156108fa57825161407f81614033565b9361408d60405195866133cf565b818552838086019260051b8201019283116108fa578301905b8282106140b4575050505090565b815181529083019083016140a6565b6000198114613ddd5760010190565b80518210156137b25760209160051b010190565b156140ed57565b60405162461bcd60e51b815260206004820152602160248201527f45786365656473206d6178206d696e747320706572207472616e73616374696f6044820152603760f91b6064820152608490fd5b1561414357565b60405162461bcd60e51b815260206004820152601c60248201527f45786365656473206d6178206d696e7473207065722077616c6c6574000000006044820152606490fd5b6002600b5414614199576002600b55565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b60058110156142e257806141ef5750565b6001810361423c5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b600281036142895760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b60031461429257565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b634e487b7160e01b600052602160045260246000fd5b90604181511460001461432657614322916020820151906060604084015193015160001a90614330565b9091565b5050600090600290565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083116143b35791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa156143a65781516001600160a01b038116156143a0579190565b50600190565b50604051903d90823e3d90fd5b50505050600090600390565b156143c657565b60405162461bcd60e51b815260206004820152601760248201527f546f6b656e20494420646f6573206e6f742065786973740000000000000000006044820152606490fd5b1561441257565b60405162461bcd60e51b81526020600482015260116024820152702737ba103a34329027232a1037bbb732b960791b6044820152606490fd5b9190916001600160401b0380809416911601918211613ddd57565b60085490600160401b8210156133555761298e82600161363c940160085561377b565b81810292918115918404141715613ddd57565b601f81116144a8575050565b600090601682527fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b5124289906020601f850160051c83019410614503575b601f0160051c01915b8281106144f857505050565b8181556001016144ec565b90925082906144e3565b601f8111614519575050565b600090601782526000805160206153fb833981519152906020601f850160051c83019410614562575b601f0160051c01915b82811061455757505050565b81815560010161454b565b9092508290614542565b91926060936001600160a01b03829316845260406020850152816040850152848401376000828201840152601f01601f1916010190565b6145c38160005260026020526001600160a01b0360406000205416151590565b15614bc4576145d06136ab565b51156146255761398660206145ec6145e66136ab565b93614d91565b9260405193816146058693518092868087019101613452565b820161461982518093868085019101613452565b010380845201826133cf565b9081600052601d6020526040600020541515600014614ba35760405161464a81613399565b600381526259657360e81b6020820152915b30926040519161466b8361333a565b602a8352602083019260403685378051156137b257603084538051956001968710156137b2576078602183015360295b878111614b5c5750614b18576034614718916146ea956146ba85614d91565b906040519788937268747470733a2f2f626c617374722e78797a2f60681b60208601525180926033860190613452565b8201602f60f81b60338201526147098251809360208785019101613452565b010360148101865201846133cf565b61472181614d91565b9261472a6135fe565b9061473483614d91565b83600052601c6020526147546001600160801b0360406000205416614d91565b93600052601c6020526147876040600020546147816001600160401b0391828160801c169060c01c61444b565b16614d91565b9260405196607b60f81b6020890152661134b2111d101160c91b60218901526147ba81518092602060288c019101613452565b870161088b60f21b602882015268113730b6b2911d101160b91b602a8201526147ed825180936020603385019101613452565b019761202360f01b60338a015261480e82518093602060358d019101613452565b61088b60f21b6035838b010152691134b6b0b3b2911d101160b11b6037838b01015260009860175491614840836135c4565b92818116908115614aee5750600114614a98575b505050509260c1928592614a4095614a45989961088b60f21b8152701132bc3a32b93730b62fbab936111d101160791b600282015261489d825180936020601385019101613452565b019161088b60f21b60138401526e2261747472696275746573223a205b60881b6015840152607b60f81b60248401527f2274726169745f74797065223a202256616c7565206c6f636b656420287765696025840152620a488b60ea1b6045840152680113b30b63ab2911d160bd1b92836048820152614926825180936020605185019101613452565b01611f4b60f21b92836051830152607b60f81b60538301527f22646973706c61795f74797065223a202264617465222c00000000000000000060548301527f2274726169745f74797065223a202256616c7565206c6f636b656420756e7469606b830152621b088b60ea1b608b830152608e8201526149af825180936020609785019101613452565b01906097820152607b60f81b60998201527f2274726169745f74797065223a20225570677261646564222c00000000000000609a82015269113b30b63ab2911d101160b11b60b3820152614a0d82518093602060bd85019101613452565b01601160f91b60bd820152607d60f81b8060be830152605d60f81b60bf83015260c08201520360a18101845201826133cf565b614c4b565b613986603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000006020830152614a888151809260208686019101613452565b810103601d8101845201826133cf565b909192995060176000526000805160206153fb833981519152906000915b848310614ad6575050509790970190960160410195828282614a45614854565b8054848d018401604101526020909201918101614ab6565b60ff1916604193909501838101959095525050811515909102909101019650828282614a45614854565b606460405162461bcd60e51b815260206004820152602060248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b90600f811660108110156137b25783518310156137b2576f181899199a1a9b1b9c1cb0b131b232b360811b901a8383016020015360041c908015613ddd576000190161469b565b604051614baf81613399565b60028152614e6f60f01b60208201529161465c565b60405162461bcd60e51b815260206004820152602760248201527f4552433732313a2055524920717565727920666f72206e6f6e6578697374656e6044820152663a103a37b5b2b760c91b6064820152608490fd5b90614c23826133f0565b614c3060405191826133cf565b8281528092614c41601f19916133f0565b0190602036910137565b805115614d7d57604051614c5e8161333a565b604081527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208201527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f60408201528151600292838201809211613ddd576003918290046001600160fe1b0381168103613ddd57614ce0908594951b614c19565b936020850193829183518401925b838110614d2c5750505050510680600114614d1957600214614d0e575090565b603d90600019015390565b50603d9081600019820153600119015390565b85600491979293949701918251600190603f9082828260121c16880101518453828282600c1c16880101518385015382828260061c1688010151888501531685010151878201530195929190614cee565b50604051614d8a816133b4565b6000815290565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000080821015614ec6575b506d04ee2d6d415b85acef810000000080831015614eb7575b50662386f26fc1000080831015614ea8575b506305f5e10080831015614e99575b5061271080831015614e8a575b506064821015614e7a575b600a80921015614e70575b600190816021614e28828701614c19565b95860101905b614e3a575b5050505090565b600019019083906f181899199a1a9b1b9c1cb0b131b232b360811b8282061a835304918215614e6b57919082614e2e565b614e33565b9160010191614e17565b9190606460029104910191614e0c565b60049193920491019138614e01565b60089193920491019138614df4565b60109193920491019138614de5565b60209193920491019138614dd3565b604093508104915038614dba565b90614ede82614033565b614eeb60405191826133cf565b8281528092614c41601f1991614033565b909262ffffff9096959296169283156152bd57600896614f1d858954614026565b60115410615282576001600160801b038092169185830296818816978803613ddd57811696870361523d57614f5186614ed4565b986000906001600160401b0394854216925b898110614fed57505050505096614fdd6001600160a01b037f3c17cb77a104e5fa9f5e5427339add873947fe1b19af0177401348d86d2edece94614fba94614fe89a9b60405196879660a0885260a0880190613747565b998b60208801526040870152166060850152838803608085015216953395613475565b0390a3601054614026565b601055565b808d615002614ffa61534e565b9283926140d2565b5260408051906150118261333a565b8482526020918281018b8b1681528282019089825285600052601c85528a84600020935116906001600160401b0360801b905160801b16916001600160401b0360c01b905160c01b1691171790556001600160a01b038b169182156151fc576150996150938560005260026020526001600160a01b0360406000205416151590565b15615302565b8654846000526009825282600020556150b184614466565b6150ba8c6138a1565b83600052600682528260002081600052825284836000205584600052600782528260002055601d8152816000205480159081156151e5575b50156151825790600284939261512561509361517d989760005260026020526001600160a01b0360406000205416151590565b836000526003815282600020600181540190558460005252600020816001600160601b0360a01b82541617905560007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a46140c3565b614f63565b608491519062461bcd60e51b82526004820152603860248201527f41667465722075706772616465282920746f6b656e732063616e206e6f74206260448201527765207472616e7366657272656420666f722037206461797360401b6064820152fd5b62093a8091506151f59042613ffa565b11386150f2565b606491519062461bcd60e51b825280600483015260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152fd5b60405162461bcd60e51b815260206004820152601460248201527f496e636f7272656374206d696e742070726963650000000000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601360248201527213585e081cdd5c1c1b1e48195e18d959591959606a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152601760248201527f5175616e746974792063616e6e6f74206265207a65726f0000000000000000006044820152606490fd5b1561530957565b60405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606490fd5b601954156153cd576019546000198101818111613ddd5761536e816137c8565b90549060031b1c917ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a1156153b7576153b16129d2826137c8565b60195590565b634e487b7160e01b600052603160045260246000fd5b600c5460018101600c559056febb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fdc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c158d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac802a26469706673582212202086ade0891c51c66c0ac38b22f2b85dfa2572dc4b401923bcb3342ecbc6189664736f6c63430008150033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ 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.