More Info
Private Name Tags
ContractCreator
TokenTracker
Multichain Info
1 address found via
Latest 25 from a total of 58,759 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Request Randomne... | 16930094 | 22 mins ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16928293 | 1 hr ago | IN | 0 ETH | 0.0000001 | ||||
Request Randomne... | 16926494 | 2 hrs ago | IN | 0 ETH | 0.00000009 | ||||
Refund | 16924845 | 3 hrs ago | IN | 0 ETH | 0.00000002 | ||||
Request Randomne... | 16924693 | 3 hrs ago | IN | 0 ETH | 0.00000009 | ||||
Request Randomne... | 16922894 | 4 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16921093 | 5 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16919294 | 6 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Refund | 16919072 | 6 hrs ago | IN | 0 ETH | 0.00000001 | ||||
Request Randomne... | 16917494 | 7 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16915693 | 8 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16913894 | 9 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16912093 | 10 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16910294 | 11 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16908493 | 12 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16906695 | 13 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16904894 | 14 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16903094 | 15 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16901293 | 16 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16899494 | 17 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16897694 | 18 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16895894 | 19 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16894094 | 20 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16892294 | 21 hrs ago | IN | 0 ETH | 0.00000008 | ||||
Request Randomne... | 16890494 | 22 hrs ago | IN | 0 ETH | 0.00000008 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
16930097 | 21 mins ago | 0.01 ETH | ||||
16928300 | 1 hr ago | 0.01 ETH | ||||
16926498 | 2 hrs ago | 0.01 ETH | ||||
16924845 | 3 hrs ago | 0.05 ETH | ||||
16924698 | 3 hrs ago | 0.01 ETH | ||||
16922898 | 4 hrs ago | 0.01 ETH | ||||
16921097 | 5 hrs ago | 0.01 ETH | ||||
16919298 | 6 hrs ago | 0.01 ETH | ||||
16919072 | 6 hrs ago | 0.05 ETH | ||||
16917498 | 7 hrs ago | 0.01 ETH | ||||
16915698 | 8 hrs ago | 0.01 ETH | ||||
16913899 | 9 hrs ago | 0.01 ETH | ||||
16912098 | 10 hrs ago | 0.01 ETH | ||||
16910297 | 11 hrs ago | 0.01 ETH | ||||
16908497 | 12 hrs ago | 0.01 ETH | ||||
16906698 | 13 hrs ago | 0.01 ETH | ||||
16904897 | 14 hrs ago | 0.01 ETH | ||||
16903097 | 15 hrs ago | 0.01 ETH | ||||
16901296 | 16 hrs ago | 0.01 ETH | ||||
16899498 | 17 hrs ago | 0.01 ETH | ||||
16897697 | 18 hrs ago | 0.01 ETH | ||||
16895897 | 19 hrs ago | 0.01 ETH | ||||
16894099 | 20 hrs ago | 0.01 ETH | ||||
16892298 | 21 hrs ago | 0.01 ETH | ||||
16890498 | 22 hrs ago | 0.01 ETH |
Loading...
Loading
Contract Name:
BlastrLotteryNFT
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/utils/Strings.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/utils/Base64.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "./BlastrLottery.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 contract BlastrLotteryNFT is IERC4906, BlastrLottery { 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 maxSupply; uint256 public publicMintStartTime; address public factoryAddress; address public referrer; address public whitelistSigner; string public baseURI; string public preRevealImageURI; 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 IncorrectMaxSupply(); constructor( 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, LotteryConfig memory _lotteryConfig, address gelatoOperator_, address gelatoRequester_, uint256 _lotteryProtocolFeePercentage ) BlastrLottery(_lotteryConfig, gelatoOperator_, gelatoRequester_, _lotteryProtocolFeePercentage) { if (_maxSupply < 1) revert IncorrectMaxSupply(); // 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(); } /* 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"); require(block.timestamp >= lock.lockedAt + lock.lockPeriod, "Lock period not expired"); emit Refund(tokenId_, msg.sender, lock.value); emit MetadataUpdate(tokenId_); _removeTicket(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_) public { 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_); // Register the value upgradesValue += lock.value; // Delete the Lock from the mapping delete locks[tokenId_]; // Update TVL tvl -= lock.value; // Register the upgrade upgradedAt[tokenId_] = block.timestamp; // Add 9 more tickets for this token (upgraded = x10 chance to win) // There is no need to store the index in _ticketIndex as this token can not be refunded anymore for (uint8 i = 0; i < 9; i++) { tickets.push(tokenId_); } } function batchUpgrade(uint256[] calldata tokenIds_) external { for (uint i; i < tokenIds_.length; i++) { upgrade(tokenIds_[i]); } } function claimYield() external nonReentrant onlyOwner { 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'); } // Add compatibility for the batchRefund contract function addToStorage() external onlyOwner { blastrStorage.addCollection(address(this)); } /* Public functions */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721Enumerable) returns (bool) { return interfaceId == bytes4(0x49064906) || super.supportsInterface(interfaceId); } 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 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) }); // Add the ticket _ticketIndex[tokenId] = tickets.length; tickets.push(tokenId); _mint(_recipient, tokenId); } emit Mint(mintedTokens, msg.sender, _recipient, _msgValue, _quantity, _lockPeriod, mintType); tvl += _msgValue; // Upgrade the tickets if there is no value locked if (_mintPrice == 0) { for (uint256 i = 0; i < mintedTokens.length; i++) { uint256 tokenId = mintedTokens[i]; emit Upgrade(tokenId, _recipient, 0); emit MetadataUpdate(tokenId); // Delete the Lock from the mapping delete locks[tokenId]; // Register the upgrade upgradedAt[tokenId] = block.timestamp; // Add 9 more tickets for this token (upgraded = x10 chance to win) // There is no need to store the index in _ticketIndex as this token can not be refunded anymore for (uint8 j = 0; j < 9; j++) { tickets.push(tokenId); } } } } 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; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import {GelatoVRFConsumerBase} from "./vendor/GelatoVRFConsumerBase.sol"; /// @author BLASTR team contract BlastrLottery is ERC721Enumerable, ReentrancyGuard, Ownable, GelatoVRFConsumerBase { receive() external payable {} enum PrizeType { BlastGold, EthFromUpgrades, EthFromYield, Other } struct LotteryConfig { PrizeType prizeType; uint248 amount; } address private _gelatoOperator; address private _gelatoRequester; mapping(uint256 => uint256) internal _ticketIndex; LotteryConfig public lotteryConfig; uint256 public tvl; uint256 public upgradesValue; uint256 public protocolFeePercentage; uint256[] public tickets; event Winner( uint256 indexed requestId, uint256 indexed ticketId, address indexed winner, PrizeType prizeType, uint256 amount, bytes extraData ); error TransferFailed(); constructor( LotteryConfig memory _lotteryConfig, address gelatoOperator_, address gelatoRequester_, uint256 _protocolFeePercentage ) ERC721("", "") { lotteryConfig = _lotteryConfig; _gelatoOperator = gelatoOperator_; _gelatoRequester = gelatoRequester_; protocolFeePercentage = _protocolFeePercentage; } /* External functions */ function setLotteryConfig(LotteryConfig memory _lotteryConfig) external onlyOwner { lotteryConfig = _lotteryConfig; } function setGelatoRequester(address gelatoRequester_) external onlyOwner { _gelatoRequester = gelatoRequester_; } function setGelatoOperator(address gelatoOperator_) external onlyOwner { _gelatoOperator = gelatoOperator_; } function setProtocolFee(uint256 _protocolFeePercentage) external onlyOwner { protocolFeePercentage = _protocolFeePercentage; } function requestRandomness(bytes memory data) external returns (uint256) { require(msg.sender == _gelatoRequester, "Not a Gelato requester"); require(tickets.length > 0, 'No participants'); return _requestRandomness(data); } /* Public functions */ function claimableYield() public view returns (uint256) { return address(this).balance - tvl - upgradesValue; } /* Internal functions */ function _operator() internal view override returns (address) { return _gelatoOperator; } function _fulfillRandomness( uint256 randomness, uint256 requestId, bytes memory extraData ) internal override { _draw(randomness, requestId, extraData); } /* Private functions */ function _draw (uint256 randomness, uint256 requestId, bytes memory extraData) private nonReentrant { uint256 winnerIndex = randomness % tickets.length; uint256 winnerTicketId = tickets[winnerIndex]; address winner = ownerOf(winnerTicketId); // Send the eth to the winner if (lotteryConfig.prizeType == PrizeType.EthFromUpgrades) { require(upgradesValue >= lotteryConfig.amount, 'Not enough eth from upgrades to send'); upgradesValue -= lotteryConfig.amount; (bool success, ) = payable(winner).call{value: lotteryConfig.amount}(""); if (!success) revert TransferFailed(); } else if (lotteryConfig.prizeType == PrizeType.EthFromYield) { uint256 protocolFee = (lotteryConfig.amount * protocolFeePercentage) / 100; require(claimableYield() >= (lotteryConfig.amount + protocolFee), 'Not enough eth from yield to send'); if (protocolFee > 0) { (bool successFee, ) = payable(owner()).call{value: protocolFee}(""); if (!successFee) revert TransferFailed(); } (bool successWinner, ) = payable(winner).call{value: lotteryConfig.amount}(""); if (!successWinner) revert TransferFailed(); } emit Winner(requestId, winnerTicketId, winner, lotteryConfig.prizeType, lotteryConfig.amount, extraData); } function _removeTicket(uint256 ticketId) internal { uint256 lastTicketIndex = tickets.length - 1; uint256 ticketIndex = _ticketIndex[ticketId]; uint256 lastTicketId = tickets[lastTicketIndex]; tickets[ticketIndex] = lastTicketId; _ticketIndex[lastTicketId] = ticketIndex; delete _ticketIndex[ticketId]; tickets.pop(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IGelatoVRFConsumer} from "./IGelatoVRFConsumer.sol"; /// @title GelatoVRFConsumerBase /// @dev This contract can be inherit by upgradeable smart contracts as well. /// @dev This contract handles domain separation between consecutive randomness requests /// The contract has to be implemented by contracts willing to use the gelato VRF system. /// This base contract enhances the GelatoVRFConsumer by introducing request IDs and /// ensuring unique random values. /// for different request IDs by hashing them with the random number provided by drand. /// For security considerations, refer to the Gelato documentation. abstract contract GelatoVRFConsumerBase is IGelatoVRFConsumer { uint256 private constant _PERIOD = 3; uint256 private constant _GENESIS = 1692803367; bool[] public requestPending; mapping(uint256 => bytes32) public requestedHash; /// @notice Returns the address of the dedicated msg.sender. /// @dev The operator can be found on the Gelato dashboard after a VRF is deployed. /// @return Address of the operator. function _operator() internal view virtual returns (address); /// @notice User logic to handle the random value received. /// @param randomness The random number generated by Gelato VRF. /// @param requestId The ID for the randomness request. /// @param extraData Additional data from the randomness request. function _fulfillRandomness( uint256 randomness, uint256 requestId, bytes memory extraData ) internal virtual; /// @notice Requests randomness from the Gelato VRF. /// @dev The extraData parameter allows for additional data to be passed to /// the VRF, which is then forwarded to the callback. This is useful for /// request tracking purposes if requestId is not enough. /// @param extraData Additional data for the randomness request. /// @return requestId The ID for the randomness request. function _requestRandomness( bytes memory extraData ) internal returns (uint256 requestId) { requestId = uint256(requestPending.length); requestPending.push(); requestPending[requestId] = true; bytes memory data = abi.encode(requestId, extraData); uint256 round = _round(); bytes memory dataWithRound = abi.encode(round, data); bytes32 requestHash = keccak256(dataWithRound); requestedHash[requestId] = requestHash; emit RequestedRandomness(round, data); } /// @notice Callback function used by Gelato VRF to return the random number. /// The randomness is derived by hashing the provided randomness with the request ID. /// @param randomness The random number generated by Gelato VRF. /// @param dataWithRound Additional data provided by Gelato VRF containing request details. function fulfillRandomness( uint256 randomness, bytes calldata dataWithRound ) external { require(msg.sender == _operator(), "only operator"); (, bytes memory data) = abi.decode(dataWithRound, (uint256, bytes)); (uint256 requestId, bytes memory extraData) = abi.decode( data, (uint256, bytes) ); bytes32 requestHash = keccak256(dataWithRound); bool isValidRequestHash = requestHash == requestedHash[requestId]; require(requestPending[requestId], "request fulfilled or missing"); if (isValidRequestHash) { randomness = uint( keccak256( abi.encode( randomness, address(this), block.chainid, requestId ) ) ); _fulfillRandomness(randomness, requestId, extraData); requestPending[requestId] = false; delete requestedHash[requestId]; } delete requestedHash[requestId]; } /// @notice Computes and returns the round number of drand to request randomness from. function _round() private view returns (uint256 round) { // solhint-disable-next-line not-rely-on-time uint256 elapsedFromGenesis = block.timestamp - _GENESIS; uint256 currentRound = (elapsedFromGenesis / _PERIOD) + 1; round = block.chainid == 1 ? currentRound + 4 : currentRound + 1; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title IGelatoVRFConsumer /// @dev Interface for consuming random number provided by Drand. /// @notice This interface allows contracts to receive a random number provided by Gelato VRF. interface IGelatoVRFConsumer { /// @notice Event emitted when a randomness request is made. /// @param data The round of randomness to request. /// @param data Additional data associated with the request. event RequestedRandomness(uint256 round, bytes data); /// @notice Callback function used by Gelato to return the random number. /// @dev The random number is fetched from one among many drand endpoints /// and passed back to this function like in a Gelato Web3 Function. /// @param randomness The random number generated by drand. /// @param data Additional data provided by Gelato VRF or the user, typically unused. function fulfillRandomness( uint256 randomness, bytes calldata data ) external; }
// 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 { struct Lock { uint128 value; uint64 lockPeriod; uint64 lockedAt; } // 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 (Lock memory); 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
Contract ABI
API[{"inputs":[{"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"},{"components":[{"internalType":"enum BlastrLottery.PrizeType","name":"prizeType","type":"uint8"},{"internalType":"uint248","name":"amount","type":"uint248"}],"internalType":"struct BlastrLottery.LotteryConfig","name":"_lotteryConfig","type":"tuple"},{"internalType":"address","name":"gelatoOperator_","type":"address"},{"internalType":"address","name":"gelatoRequester_","type":"address"},{"internalType":"uint256","name":"_lotteryProtocolFeePercentage","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"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":false,"internalType":"uint256","name":"round","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"RequestedRandomness","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":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"ticketId","type":"uint256"},{"indexed":true,"internalType":"address","name":"winner","type":"address"},{"indexed":false,"internalType":"enum BlastrLottery.PrizeType","name":"prizeType","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"Winner","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":[],"name":"addToStorage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"}],"name":"batchUpgrade","outputs":[],"stateMutability":"nonpayable","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":"randomness","type":"uint256"},{"internalType":"bytes","name":"dataWithRound","type":"bytes"}],"name":"fulfillRandomness","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":"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":"lotteryConfig","outputs":[{"internalType":"enum BlastrLottery.PrizeType","name":"prizeType","type":"uint8"},{"internalType":"uint248","name":"amount","type":"uint248"}],"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":[],"name":"protocolFeePercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"uint256","name":"","type":"uint256"}],"name":"requestPending","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"requestRandomness","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"requestedHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"baseURI_","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"gelatoOperator_","type":"address"}],"name":"setGelatoOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"gelatoRequester_","type":"address"}],"name":"setGelatoRequester","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"enum BlastrLottery.PrizeType","name":"prizeType","type":"uint8"},{"internalType":"uint248","name":"amount","type":"uint248"}],"internalType":"struct BlastrLottery.LotteryConfig","name":"_lotteryConfig","type":"tuple"}],"name":"setLotteryConfig","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":[{"internalType":"uint256","name":"_protocolFeePercentage","type":"uint256"}],"name":"setProtocolFee","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":"","type":"uint256"}],"name":"tickets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"upgradesValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whitelistSigner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6101606040523462000dbc57600061014052620065588038038091620000288261016062000e07565b61016039610160810190610300811262000780576200004961016062000e2b565b916200005761018062000e2b565b6101a0516001600160401b0381116200078057826200007a916101600162000e40565b6101c0519094906001600160401b038111620007805783620000a0916101600162000e40565b6101e051610200519095919491906001600160401b038111620007805782620000cd916101600162000e40565b608052610220516001600160401b038111620007805782620000fa60409462000138936101600162000e40565b60a0526200010a61024062000e2b565b60c0526200011a61026062000e2b565b60e0526200012b8161028062000ec7565b6101205261032062000ec7565b6101005261025f1901126200078057604080519081018082116001600160401b0390911117620008fe57604081810190526103c0516004811015620007805781526103e0516001600160f81b038116810362000780576020820152620001a061040062000e2b565b620001ad61042062000e2b565b6102e0610160015191604051620001c48162000deb565b61014051815260405190620001d98262000deb565b6101405182528051906001600160401b038211620008fe576101405154600181811c929116801562000db1575b6020831014620008d95781601f84931162000d53575b506020906001601f84111462000cdd57610140519262000cd1575b50508160011b916000199060031b1c19161761014051555b8051906001600160401b038211620008fe576001805480821c929116801562000cc6575b6020831014620008d95781601f84931162000c6a575b506020906001601f84111462000bf157610140519262000be5575b50508160011b916000199060031b1c1916176001555b6001600a55600b8054336001600160a01b03198216811790925560405161014051909692916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3805190600482101562000bcb576020015160ff1960089190911b1660ff9190911617601155600e80546001600160a01b039283166001600160a01b031991821617909155600f80549390921692169190911790556014556001851062000bbc5750602180546001600160a01b039283166001600160a01b031991821617909155601c805493909216921691909117905582516001600160401b038111620008fe57601854600181811c9116801562000bb1575b6020821014620008d957601f811162000b61575b5060206001601f83111462000aec5781929394610140519262000ae0575b50508160011b916000199060031b1c1916176018555b8051906001600160401b038211620008fe57601954600181811c929116801562000ad5575b6020831014620008d95781601f84931162000a79575b506020906001601f84111462000a00576101405192620009f4575b50508160011b916000199060031b1c1916176019555b601a55608051516001600160401b038111620008fe57601f54600181811c91168015620009e9575b6020821014620008d957601f811162000999575b506020906001601f82111462000926578091610140519162000918575b508160011b916000199060031b1c191617601f555b60a051516001600160401b038111620008fe57602054600181811c91168015620008f3575b6020821014620008d957601f811162000885575b506020906001601f82111462000812578091610140519162000804575b508160011b916000199060031b1c1916176020555b60018060a01b0360c0511660018060a01b0319601d541617601d5560018060a01b0360e0511660018060a01b0319601e541617601e5560018060801b0380610120515116602354600160801b600160c01b039283602061012051015160801b169262ffffff60c01b9182604061012051015160c01b169362ffffff60d81b9485606061012051015191608061012051015115159860ff60f81b968760ff60f01b809c60f01b1696161717179160d81b1617176023556101005151169060245495602061010051015160801b1692604061010051015160c01b1693606061010051015160d81b16946080610100510151151560f01b1695161717171717602455734300000000000000000000000000000000000002803b15620007805760405163388a0bbd60e11b8152610140518160048183865af180156200078757620007f2575b50803b15620007805760405190634e606c4760e01b825281600481610140519361014051905af180156200078757620007d7575b5060215460405163102b8f8560e21b815290602090829060049082906001600160a01b03165afa9081156200078757610140519162000795575b50732536fe9ab3f511540f2f9e2ec2a805005c3dd800803b1562000780576040516336b91f2b60e01b81526001600160a01b03909216600483015261014051908290602490829084905af18015620007875762000765575b6040516155fc908162000f5c8239f35b620007709062000dc1565b6101405162000780573862000755565b6101405180fd5b6040513d61014051823e3d90fd5b90506020813d602011620007ce575b81620007b36020938362000e07565b810103126200078057620007c79062000e2b565b38620006fd565b3d9150620007a4565b620007e29062000dc1565b61014051620007805738620006c3565b620007fd9062000dc1565b386200068f565b905060a05101513862000538565b601f19811691602061014051526020610140512090610140515b8481106200086a575082600194106200084e575b5050811b016020556200054d565b60a051015160001960f88460031b161c19169055388062000840565b90916020600181928560a0510151815501930191016200082c565b6020610140515260206101405120601f830160051c81019160208410620008ce575b601f0160051c01905b818110620008bf57506200051b565b610140518155600101620008b0565b9091508190620008a7565b634e487b7160e01b61014051526022600452602461014051fd5b90607f169062000507565b634e487b7160e01b61014051526041600452602461014051fd5b9050608051015138620004cd565b601f19811691601f61014051526020610140512090610140515b8481106200097e5750826001941062000962575b5050811b01601f55620004e2565b608051015160001960f88460031b161c19169055388062000954565b90916020600181928560805101518155019301910162000940565b601f610140515260206101405120601f830160051c810160208410620009e1575b601f830160051c82018110620009d2575050620004b0565b610140518155600101620009ba565b5080620009ba565b90607f16906200049c565b0151905038806200045e565b925060196101405152602061014051209061014051935b601f198416851062000a5d576001945083601f1981161062000a43575b505050811b0160195562000474565b015160001960f88460031b161c1916905538808062000a34565b8181015183556020948501946001909301929091019062000a17565b9091506019610140515260206101405120601f840160051c81016020851062000acd575b90849392915b601f830160051c8201811062000abb57505062000443565b61014051815585945060010162000aa3565b508062000a9d565b91607f16916200042d565b015190503880620003f2565b601861014051526020610140512090610140515b601f198416811062000b485750600193949583601f1981161062000b2e575b505050811b0160185562000408565b015160001960f88460031b161c1916905538808062000b1f565b9091602060018192858a01518155019301910162000b00565b6018610140515260206101405120601f830160051c81016020841062000ba9575b601f830160051c8201811062000b9a575050620003d4565b61014051815560010162000b82565b508062000b82565b90607f1690620003c0565b6325ab076960e01b8152600490fd5b634e487b7160e01b61014051526021600452602461014051fd5b015190503880620002a4565b925060016101405152602061014051209061014051935b601f198416851062000c4e576001945083601f1981161062000c34575b505050811b01600155620002ba565b015160001960f88460031b161c1916905538808062000c25565b8181015183556020948501946001909301929091019062000c08565b9091506001610140515260206101405120601f840160051c81016020851062000cbe575b90849392915b601f830160051c8201811062000cac57505062000289565b61014051815585945060010162000c94565b508062000c8e565b91607f169162000273565b01519050388062000237565b61014080518052516020812090945091905b601f198416851062000d37576001945083601f1981161062000d1d575b505050811b0161014051556200024f565b015160001960f88460031b161c1916905538808062000d0c565b8181015183556020948501946001909301929091019062000cef565b90915061014051610140515260206101405120601f840160051c81016020851062000da9575b90849392915b601f830160051c8201811062000d975750506200021c565b61014051815585945060010162000d7f565b508062000d79565b91607f169162000206565b600080fd5b6001600160401b03811162000dd557604052565b634e487b7160e01b600052604160045260246000fd5b602081019081106001600160401b0382111762000dd557604052565b601f909101601f19168101906001600160401b0382119082101762000dd557604052565b51906001600160a01b038216820362000dbc57565b919080601f8401121562000dbc5782516001600160401b03811162000dd5576020906040519262000e7b83601f19601f850116018562000e07565b81845282828701011162000dbc5760005b81811062000ea257508260009394955001015290565b858101830151848201840152820162000e8c565b519062ffffff8216820362000dbc57565b91908260a091031262000dbc576040516001600160401b0360a082018181118382101762000dd5576040528351919384926001600160801b038116810362000dbc5783526020810151918216820362000dbc57608091602084015262000f306040820162000eb6565b604084015262000f436060820162000eb6565b6060840152015190811515820362000dbc576080015256fe60406080815260048036101561001f575b5050361561001d57600080fd5b005b600090813560e01c9081626059fd146130a857816301ffc9a71461300257816306fdde0314612fe4578163081812fc14612fbc578163095ea7b314612e4257816318160ddd14612e2357816323b872dd14612df9578163268e280314612d12578163269c759b14612ca4578163278ecde1146127945781632f745c591461276b5781633b198b361461274c578163406cf2291461226557816342842e0e1461223c57816345977d031461221f5781634d9b9426146121a05781634f6ccce71461211a57816350b44712146120ee57816353c838e01461201d57816355f804b314611e0357816359b39c6214611dc2578163608557c114611d215781636352211e14611cf157816368447c9314611cc95781636c0360eb14611cab57816370a0823114611c85578163715018a614611c2857816375ce7fff14611be9578163787dce3d14611bc75781637d583676146119a15781637e1c1757146119795781638da5cb5b146119515781638e50e509146119325781639106a059146118c457816395d89b4114611812578163966dae0e146117ea57816399c89e81146117565781639dbec6711461166f578163a22cb465146115a3578163a263a9eb14611577578163a68aa967146114f3578163a6bfef6114611478578163b3f6b99a14610fde578163b88d4fde14610f88578163bf4ad33814610e87578163c4f8f27b14610e5e578163c87b56dd14610e2a578163d338143814610db9578163d3cf00a314610d9a578163d5abeb0114610d7b578163d98de53e146108cb578163e0d8aafb14610836578163e4b3758b1461080d578163e5328e06146107ee578163e6dee7ed14610593578163e985e9c514610542578163ea66aeb3146104cf578163eb671cc51461048e578163ef81b4d414610462578163ef97ead814610428578163f2fde38b1461035f578163f4dadc611461030d575063fc5ab87c03610010573461030a578060031936011261030a57506011548151906103008260ff83166137ea565b60081c6020820152f35b80fd5b8391503461035b57602036600319011261035b57606092829135815260256020522054908051916001600160801b03811683526001600160401b038160801c16602084015260c01c90820152f35b8280fd5b8391503461035b57602036600319011261035b5761037b61341c565b9061038461380d565b6001600160a01b038092169283156103d6575050600b54826001600160601b0360a01b821617600b55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b8391503461035b57602036600319011261035b57359160225483101561030a5750610454602092613501565b91905490519160031b1c8152f35b82843461048a578160031936011261048a576020906001600160a01b03601e54169051908152f35b5080fd5b823461030a57602036600319011261030a576001600160a01b036104b061341c565b6104b861380d565b166001600160601b0360a01b600e541617600e5580f35b50503461030a57602036600319011261030a576104ea61341c565b916104f483613865565b6104fd81614fd1565b925b81811061051f5782516020808252819061051b908201876137b6565b0390f35b8061052d61053d9287613f2c565b6105378287614093565b52614084565b6104ff565b82843461048a578060031936011261048a5760209161055f61341c565b82610568613432565b926001600160a01b03809316815260058652209116600052825260ff81600020541690519015158152f35b83833461030a576020918260031936011261048a5783356001600160401b03811161035b576105c590369086016133b6565b916001600160a01b03600f541633036107ab576015541561077657600c5492600160401b841015610763579061063d9160018501600c5561060585613779565b505061061085613779565b81549060031b9060ff6001831b921b191617905583519283918688840152858084015260608301906133f7565b0390610651601f1992838101855284613343565b6364e6212619420142811161070557600390046001810190818111610750574660010361071857600501809111610705578495969750937fd91fc3685b930310b008ec37d2334870cab88a023ed8cc628a2e2ccd4e55d20294925b81516106d78a8201928684528480840152826106cb606082018a6133f7565b03908101835282613343565b51902091878152600d895220556106fc845192839283528588840152858301906133f7565b0390a151908152f35b634e487b7160e01b825260118852602482fd5b600201809111610705578495969750937fd91fc3685b930310b008ec37d2334870cab88a023ed8cc628a2e2ccd4e55d20294926106ac565b634e487b7160e01b835260118952602483fd5b634e487b7160e01b825260418652602482fd5b815162461bcd60e51b8152808601859052600f60248201526e4e6f207061727469636970616e747360881b6044820152606490fd5b815162461bcd60e51b8152808601859052601660248201527f4e6f7420612047656c61746f20726571756573746572000000000000000000006044820152606490fd5b82843461048a578160031936011261048a576020906012549051908152f35b8391503461035b57602036600319011261035b5760209282913581526026845220549051908152f35b82939150346108c757826003193601126108c75761085261380d565b6001600160a01b0360215416803b156108c257839060248451809681936350ba73bd60e11b835230878401525af180156108b85761088e578380f35b6001600160401b0383116108a55750523880808380f35b634e487b7160e01b845260419052602483fd5b82513d86823e3d90fd5b505050fd5b5050fd5b826020853660031901821361035b576108e26132aa565b936108eb614149565b60ff60235460f01c1615610d3a5761012c610908601b5442613fbb565b106109dd575b506109a7929360235461094d62ffffff8261093982809560c01c1680159081156109d0575b506140a7565b60d81c1680159081156109af575b506140fd565b338652602784526109648387209183168254613fe7565b9055602354657075626c696360d01b6001600160801b039351946109878661330d565b60068652850152823416926001600160401b038260801c16911633614ff9565b6001600a5580f35b9050338852602786526109c88589205484861690613fe7565b111588610947565b905083871611158b610933565b9291906001600160a01b039384602154168251906305391b2760e31b9182815285818581855afa908115610ba55788929187918991610d1d575b5060248751809b81936370a0823160e01b8352338a840152165afa978815610ba5578798610cea575b5087151580610cdb575b15610c3c57601790815493610a6562ffffff8c168096613fe7565b6014601a540410610be65787908688518094819382525afa908115610bdc579088918291610baf575b50602487518095819363ea66aeb360e01b8352338a840152165afa918215610ba5578792610b81575b508691875b898110610b2e575b50505090919293949550031561090e5782608492519162461bcd60e51b8352820152603060248201527f596f7520646f6e2774206f776e20656e6f756768206b65797320746f206d696e60448201526f742061736b6564207175616e7469747960801b6064820152fd5b610b388183614093565b51895260298852868920805415610b59575b50610b5490614084565b610abc565b93610b6e919460018091558454018455614084565b92848414610b7c578b610b4a565b610ac4565b610b9e9192503d8089833e610b968183613343565b81019061400b565b9089610ab7565b85513d89823e3d90fd5b610bcf9150883d8a11610bd5575b610bc78183613343565b810190613fc8565b8b610a8e565b503d610bbd565b86513d8a823e3d90fd5b865162461bcd60e51b8152808701899052602a60248201527f4d757374206e6f74206d696e74206d6f7265207468616e203525206f6620746f60448201526974616c20737570706c7960b01b6064820152608490fd5b845162461bcd60e51b8152808501879052606760248201527f5468652066697273742035206d696e206f66207075626c6963206d696e74206160448201527f726520726573657276656420666f7220424c41535452206b657920686f6c646560648201527f727320286d6178206d696e74207175616e746974793a203120706572206b6579608482015266206f776e65642960c81b60a482015260c490fd5b508762ffffff8a161115610a4a565b9097508581813d8311610d16575b610d028183613343565b81010312610d1257519689610a40565b8680fd5b503d610cf8565b610d349150823d8411610bd557610bc78183613343565b8b610a17565b82606492519162461bcd60e51b8352820152601960248201527f5075626c6963206d696e74206973206e6f7420616374697665000000000000006044820152fd5b82843461048a578160031936011261048a57602090601a549051908152f35b82843461048a578160031936011261048a57602090601b549051908152f35b82843461048a57602036600319011261048a577fe81fbf9dcd9efb641e9dd6a384b82aedac00c55a93402509bd9866fab1a92afa906001600160a01b03610dfe61341c565b610e0661380d565b16806001600160601b0360a01b601e541617601e558151903382526020820152a180f35b83833461030a57602036600319011261030a5750610e4b61051b923561468e565b90519182916020835260208301906133f7565b8391503461035b57602036600319011261035b576020928291358152600d845220549051908152f35b82843461048a577fca805018b1f306f78c930fd9dd300fc655fa266c44ad5e355f8c2d19d5ea8f6490610eb936613538565b610ec161380d565b610f6b6023546001600160801b03835116936020840151818501519162ffffff966080606088015197015115159460ff8060f01b8760f01b16838260f81b8416176001600160401b0360801b8760801b161762ffffff60c01b8860c01b161762ffffff60d81b8b60d81b161717918260235560f01c16159081610f7a575b50610f71575b6001600160401b03886001600160a01b03600b54169351998a9916951693169187614608565b0390a180f35b42601b55610f45565b60ff915060f01c168b610f3f565b90503461048a57608036600319011261048a57610fa361341c565b610fab613432565b906064356001600160401b038111610fda57610fd793610fcd913691016133b6565b91604435916139ee565b80f35b8480fd5b82843461048a578060031936011261048a576024926001600160401b038435818111610fda5761101190369084016135b7565b9190926001600160a01b039687600e5416330361144657838501948681870312611442576020958682013585811161143e579061104f9183016133b6565b948551860194888789880197031261143e5787870151968981015191821161143a570185603f8201121561143e57878101519061108b82613364565b966110988b519889613343565b8288528a838301011161143a576110c19392916110ba918b8b8a0191016133d4565b369161337f565b858151910120848852600d865286882054149760ff6110df86613779565b90549060031b1c16156113f8578798611104575b5050505090600d9184525281205580f35b909192939495809750518681019084358252308982015246606082015286608082015260808152611134816132f2565b51902061113f614149565b6015549081156113e65790611154910661347d565b90549060031b1c9261116584613928565b9260115460ff8116838110156113d4578b9190600181036112a85750505060135460115460081c9182821061125b57508a80836111a482958395613fbb565b6013558688165af16111b4613e05565b501561124d575091847fd4c141ac80ac9c94920abcce59da203aaf122455ce2609904c2fda07ec8012ef8998979593600d97955b61121a601154918b5193836112018660ff8197166137ea565b60081c8b85015260608d850152169660608301906133f7565b0390a46001600a5561122b81613779565b60ff82549160031b1b19169055808552828252848481205590918680806110f3565b87516312171d8360e31b8152fd5b836084918b8d519262461bcd60e51b8452830152808201527f4e6f7420656e6f756768206574682066726f6d20757067726164657320746f206044820152631cd95b9960e21b6064820152fd5b6002909b9997959493929a98969b146112ec575b5050507fd4c141ac80ac9c94920abcce59da203aaf122455ce2609904c2fda07ec8012ef600d96979885926111e8565b909192939597999496985060081c906064611309601454846145f5565b049161132e8361132861131f4760125490613fbb565b60135490613fbb565b92613fe7565b116113895750808a91611369575b5080808060115460081c8688165af1611353613e05565b501561124d579081808a989694999795936112bc565b8180809286600b54165af161137c613e05565b501561124d57888a61133c565b8260216084928b8d519362461bcd60e51b85528401528201527f4e6f7420656e6f756768206574682066726f6d207969656c6420746f2073656e6044820152601960fa1b6064820152fd5b634e487b7160e01b8c5260218452828cfd5b634e487b7160e01b8a5260128552838afd5b865162461bcd60e51b8152808401879052601c818401527f726571756573742066756c66696c6c6564206f72206d697373696e67000000006044820152606490fd5b8a80fd5b8980fd5b8780fd5b90600d606492602088519362461bcd60e51b85528401528201526c37b7363c9037b832b930ba37b960991b6044820152fd5b90503461048a57602036600319011261048a5780356001600160401b03918282116114ef57366023830112156114ef5781013591821161035b576024906005368385831b84010111610fda57845b8481106114d1578580f35b806114e5856114ea93851b8601013561446a565b614084565b6114c6565b8380fd5b82843461048a578160031936011261048a5760ff7fe151bf9d2a434324b5e13c5bdff9bd2e9ab2e30c657f586da54bbe88cf1d8b069161153161380d565b6024805460f084811b19821691811c8516158516811b9190911791829055600b5492516001600160a01b039390931683521c909116151560208201528060408101610f6b565b82843461048a578160031936011261048a5760209061159c61131f4760125490613fbb565b9051908152f35b9050823461035b578060031936011261035b576115be61341c565b9060243591821515809303610fda576001600160a01b03169283331461162d5750338452600560205280842083855260205280842060ff1981541660ff8416179055519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b6020606492519162461bcd60e51b8352820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152fd5b50503461030a578060031936011261030a5781519182826020938454611694816135e4565b9182855260019187838216918260001461172f5750506001146116d4575b50505061051b92916116c5910385613343565b519282849384528301906133f7565b91908680945083527fc97bfaf2f8ee708c303a06d134f5ecd8389ae0432af62dc132a24118292866bb5b82841061171757505050820101816116c561051b6116b2565b8054848a0186015288955087949093019281016116fe565b60ff19168782015293151560051b860190930193508492506116c5915061051b90506116b2565b82843461048a578160031936011261048a577ff2721e078a20e7f6ba187f7a54783e6e4cea86087bafc68840732db61dec47889061179261380d565b60ff6023548160f01b828260f01c161560f01b16908260f01b1916178060235560f01c1690816117e1575b600b5490516001600160a01b03909116815290151560208201528060408101610f6b565b42601b556117bd565b82843461048a578160031936011261048a576020906001600160a01b03601c54169051908152f35b50503461030a578060031936011261030a578151918282601954611835816135e4565b9081845260209560019187838216918260001461172f5750506001146118685750505061051b92916116c5910385613343565b9190869350601983527f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c96955b8284106118ac57505050820101816116c561051b6116b2565b8054848a018601528895508794909301928101611893565b50503461030a578060031936011261030a575060245490516001600160801b0382168152608082811c6001600160401b0316602083015260c083901c62ffffff908116604084015260d884901c16606083015260f09290921c60ff161515918101919091528060a081010390f35b82843461048a578160031936011261048a576020906014549051908152f35b82843461048a578160031936011261048a576020906001600160a01b03600b54169051908152f35b82843461048a578160031936011261048a576020906001600160a01b03602154169051908152f35b9050823461035b57602091826003193601126114ef576001600160401b038135818111611bc3576119d590369084016135b7565b9290916119e061380d565b8311611bb057506119f184546135e4565b601f8111611b4f575b5084601f8311600114611aad5790827f0e97d384f3f2db9658556130716bebad5af0675b729419b713437de32653febc93928791611aa2575b508260011b906000198460031b1c19161785555b611a5684519283923384614657565b0390a1611a64601f546135e4565b15611a6d578280f35b7f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91601a54825191858352820152a181808280f35b905081013587611a33565b8486527fc97bfaf2f8ee708c303a06d134f5ecd8389ae0432af62dc132a24118292866bb90601f198416875b87828210611b3957505090847f0e97d384f3f2db9658556130716bebad5af0675b729419b713437de32653febc9594939210611b1f575b5050600182811b018555611a47565b820135600019600385901b60f8161c191690558680611b10565b6001849582939588013581550194019201611ad9565b8486527fc97bfaf2f8ee708c303a06d134f5ecd8389ae0432af62dc132a24118292866bb601f840160051c810191868510611ba6575b601f0160051c01905b818110611b9b57506119fa565b868155600101611b8e565b9091508190611b85565b634e487b7160e01b865260419052602485fd5b8580fd5b90503461048a57602036600319011261048a57611be261380d565b3560145580f35b8391503461035b57602036600319011261035b573591600c5483101561030a575060ff611c17602093613779565b92905490519260031b1c1615158152f35b823461030a578060031936011261030a57611c4161380d565b806001600160a01b03600b546001600160601b0360a01b8116600b55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b82843461048a57602036600319011261048a5760209061159c611ca661341c565b613865565b82843461048a578160031936011261048a5761051b90610e4b6136dd565b82843461048a578160031936011261048a576020906001600160a01b03601d54169051908152f35b83833461030a57602036600319011261030a57506001600160a01b03611d1960209335613928565b915191168152f35b9050823461035b578060031936011261035b57805190808201908282106001600160401b03831117611daf57528135828110156114ef578152602435906001600160f81b03821682036114ef5760208101918252611d7d61380d565b519180831015611d9c575060ff908119905160081b1691161760115580f35b634e487b7160e01b845260219052602483fd5b634e487b7160e01b855260418452602485fd5b823461030a57602036600319011261030a576001600160a01b03611de461341c565b611dec61380d565b166001600160601b0360a01b600f541617600f5580f35b8391503461035b57602090816003193601126114ef576001600160401b038135818111611bc357611e3790369084016135b7565b929091611e4261380d565b8311611bb05750601f611e5581546135e4565b818111611fbf575b5085818411600114611efa579183917f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c9695947f78cd0c51de67bd306f7a477494a110772ec9e86ffcfb04448079856a62dbe3b5948991611eef575b508360011b906000198560031b1c19161790555b611edc85519283923384614657565b0390a1601a54825191858352820152a180f35b905082013589611eb9565b8187527fa03837a25210ee280c2113ff4b77ca23440b19d4866cca721c801278fd08d80790601f198516885b818110611fa85750918593917f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c9897967f78cd0c51de67bd306f7a477494a110772ec9e86ffcfb04448079856a62dbe3b5969410611f8e575b5050600183811b019055611ecd565b830135600019600386901b60f8161c191690558880611f7f565b919287600181928689013581550194019201611f26565b8187527fa03837a25210ee280c2113ff4b77ca23440b19d4866cca721c801278fd08d8078280860160051c820192878710612014575b0160051c01905b8181106120095750611e5d565b878155600101611ffc565b92508192611ff5565b82843461048a577f059691c8ca8b8a0a17d6d79c46d63bf67f157d28700329f2f842fc08c1cf4d6b9061204f36613538565b61205761380d565b610f6b6001600160801b0382511692602454906020840151818501519162ffffff96608060608801519701511515948160ff60f01b8760f01b169160ff60f81b16176001600160401b0360801b8560801b161762ffffff60c01b8660c01b161762ffffff60d81b8960d81b1617176024556001600160401b03886001600160a01b03600b54169351998a9916951693169187614608565b8391503461035b57602036600319011261035b57359160155483101561030a575061045460209261347d565b9190503461030a57602036600319011261030a575080359060085482101561214857602083610454846134ca565b608490602084519162461bcd60e51b8352820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b6064820152fd5b8284608036600319011261048a576121b661341c565b6001600160801b03906024358281168103610fda576044356001600160401b0381168103611bc3576064359162ffffff83168303610d1257610fd7956121fa61380d565b51946122058661330d565b600586526437bbb732b960d91b6020870152341693614ff9565b90503461048a57602036600319011261048a57610fd7903561446a565b82843461048a57610fd79061225036613448565b9192519261225d84613328565b8584526139ee565b9050823461035b578260031936011261035b57612280614149565b61228861380d565b61229861131f4760125490613fbb565b9182156127155783849184906001600160a01b039485602154168151926305391b2760e31b845260209182858381845afa94851561270b578b956126ec575b5083516331056e5760e21b81529483868481855afa9586156126e2578c966126c3575b5084516358710f4560e11b81529184838581845afa928d8415612686579186918695949394612691575b508751636e88a7bd60e01b815294859182905afa928d841561268657908c92919461264f575b50169a81612476575b50509091929394959697985089808080898d600b54165af1612373613e05565b501561246757866123db575b897f1895c62887d1ed7e831b47190e1164cd03e07077102c7891b069574cb27570d360c08b8b8b8b8b8b8b86600b54169680601d541693835198895216908701528501526060840152608083015260a0820152a16001600a5580f35b8989601d54169182612416575b508080809350898c89165af16123fc613e05565b5015612408578061237f565b82516312171d8360e31b8152fd5b80156123e8578180939a5061271061243182938c979c6145f5565b04809b5af161243e613e05565b5015612457578661244e91613fbb565b948989816123e8565b82516312171d8360e31b81528690fd5b5082516312171d8360e31b8152fd5b8c8b600b54169c8d8851906370a0823160e01b8252878201528781602481855afa908115612645578391612618575b50156125eb57875163ea66aeb360e01b81528681019e909e52818e602481845afa9d8e156125e157829e6125c5575b50819d825b81518110156125b1576124ec8183614093565b518a519063e4b3758b60e01b8252898201528981602481875afa9081156125a757859161257a575b506125275761252290614084565b6124d9565b50505050909192939495969798999a5060015b15612553575b50505b9088979695949392918b80612353565b61257292979850612569600592612710926145f5565b04048097613fbb565b948a80612540565b90508981813d83116125a0575b6125918183613343565b81010312610fda575138612514565b503d612587565b8b513d87823e3d90fd5b50505050909192939495969798999a61253a565b6125da919e503d8084833e610b968183613343565b9c8f6124d4565b88513d84823e3d90fd5b505098999a5061271091975061261292939495965061260a90896145f5565b048097613fbb565b94612543565b90508781813d831161263e575b61262f8183613343565b8101031261035b5751386124a5565b503d612625565b89513d85823e3d90fd5b86809295508193503d831161267f575b6126698183613343565b8101031261267b578a9051928e61234a565b8c80fd5b503d61265f565b8751903d90823e3d90fd5b9450925083813d83116126bc575b6126a98183613343565b8101031261267b5784849351928f612324565b503d61269f565b6126db919650843d8611610bd557610bc78183613343565b948c6122fa565b85513d8e823e3d90fd5b612704919550833d8511610bd557610bc78183613343565b938b6122d7565b84513d8d823e3d90fd5b6020606492519162461bcd60e51b835282015260126024820152712737903cb4b2b632103a379031b630b4b69760711b6044820152fd5b82843461048a578160031936011261048a576020906013549051908152f35b82843461048a578060031936011261048a5760209061159c61278b61341c565b60243590613f2c565b82843461048a5760208060031936011261035b5783356127b2614149565b6127da6127d58260005260026020526001600160a01b0360406000205416151590565b61436a565b6127e381613928565b926127fa6001600160a01b039485339116146143b6565b8185526025835280852092815193612811856132c1565b54946001600160801b03958681168087526001600160401b039184880191838260801c1683528689019160c01c825215612c6d57908280612857935116915116906143f6565b164210612c2a57845183518581529087166001600160801b0316602082015233907f21e12a7cad0da5928167e1084ea4d5fdf8d9af66657a2543a9ac76a0ca08147790604090a27ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7828451868152a16015546000199190828101908111612b8557858952601084526128ec858a20549161347d565b90549060031b1c806129176129008461347d565b819391549060031b91821b91600019901b19161790565b90558952601084528489205584885287848120556015548015612b7257820161293f8161347d565b8482549160031b1b1916905560155561295785613928565b8082169081612b98575050600854858952600984528489205561297985614437565b600854828101908111612b85578589526009845261299a858a2054916134ca565b90549060031b1c806129ae612900846134ca565b90558952600984528489205584885287848120556008548015612b725782016129d6816134ca565b8482549160031b1b1916905560085584885260268352838820548015908115612b5b575b5015612af75784918891612a0d84613928565b908484528b8652868420916001600160601b0360a01b92838154169055169182845260038652868420908154019055838352600285528583209081541690557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a48580808088885116335af1612a83613e05565b5015612ae757906025869284845252812055602254600160401b811015612ad457612ac9949550612900816001612abd9301602255613501565b90555116601254613fbb565b6012556001600a5580f35b634e487b7160e01b855260418652602485fd5b81516312171d8360e31b81528790fd5b835162461bcd60e51b8152808a01849052603860248201527f41667465722075706772616465282920746f6b656e732063616e206e6f74206260448201527765207472616e7366657272656420666f722037206461797360401b6064820152608490fd5b62093a809150612b6b9042613fbb565b118a6129fa565b634e487b7160e01b895260318a52602489fd5b634e487b7160e01b895260118a52602489fd5b612ba190613865565b90838201918211612c1757868a5260078552858a2054828103612be0575b50868a52898681205589526006845284892090895283528784812055612979565b818b5260068652868b20838c528652868b2054828c5260068752878c20828d52875280888d20558b5260078652868b20558b612bbf565b634e487b7160e01b8a5260118b5260248afd5b825162461bcd60e51b8152808901839052601760248201527f4c6f636b20706572696f64206e6f7420657870697265640000000000000000006044820152606490fd5b855162461bcd60e51b8152808c018690526011602482015270139bdd1a1a5b99c81d1bc81c99599d5b99607a1b6044820152606490fd5b50503461030a578060031936011261030a575060235490516001600160801b0382168152608082811c6001600160401b0316602083015260c083901c62ffffff908116604084015260d884901c16606083015260f09290921c60ff161515918101919091528060a081010390f35b9050823461035b576020806003193601126114ef578235612d31614149565b612d3961380d565b6001600160a01b039384600b5416845191630951888f60e01b8352309083015260248201528160448201528281606481897343000000000000000000000000000000000000025af18015612def57612dc5575b507fa1c8454e70ae3014662889130afe679a3c6067101b0c4225f0cbfd93fa66348b93600b5416918351928352820152a16001600a5580f35b8290813d8311612de8575b612dda8183613343565b81010312610fda5785612d8c565b503d612dd0565b84513d88823e3d90fd5b823461030a57610fd7612e0b36613448565b91612e1e612e198433613a89565b61398c565b613b51565b82843461048a578160031936011261048a576020906008549051908152f35b8391503461035b578160031936011261035b57612e5d61341c565b90602435926001600160a01b03918280612e7687613928565b16941693808514612f6f57803314908115612f50575b5015612ee8578486526020528420805473ffffffffffffffffffffffffffffffffffffffff191683179055612ec083613928565b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b6020608492519162461bcd60e51b8352820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152fd5b90508652600560205281862033875260205260ff828720541687612e8c565b506020608492519162461bcd60e51b8352820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152fd5b83833461030a57602036600319011261030a57506001600160a01b03611d196020933561394a565b82843461048a578160031936011261048a5761051b90610e4b61361e565b8391503461035b57602036600319011261035b57359063ffffffff60e01b821680920361035b5760209250632483248360e11b8214918215613048575b50519015158152f35b90915063780e9d6360e01b8114908115613065575b50908361303f565b6380ac58cd60e01b811491508115613097575b8115613086575b508361305d565b6301ffc9a760e01b1490508361307f565b635b5e139f60e01b81149150613078565b82848060031936011261048a576130bd6132aa565b6001600160401b0390602435828111610fda576130dd90369087016133b6565b946130e6614149565b6024549560ff8760f01c16156132675761317d6131859161313162ffffff8a61311e82809d60c01c16801590811561325a57506140a7565b60d81c16801590811561323857506140fd565b865160208101903360601b82526014815261314b8161330d565b5190207f19457468657265756d205369676e6564204d6573736167653a0a3332000000008952601c52603c88206142a3565b91909161419f565b6001600160a01b0380601e54169116036131f557506109a7939433865260286020526131b78487209183168254613fe7565b90556024546001600160801b039351936131d08561330d565b60078552667072697661746560c81b6020860152803416938260801c16911633614ff9565b606490602085519162461bcd60e51b8352820152601f60248201527f596f75722077616c6c6574206973206e6f742077686974656c69737465642e006044820152fd5b9050338a526028602052613252898b20548c891690613fe7565b11158b610947565b9050838a1611158e610933565b845162461bcd60e51b8152602081840152601a60248201527f50726976617465206d696e74206973206e6f74206163746976650000000000006044820152606490fd5b6004359062ffffff821682036132bc57565b600080fd5b606081019081106001600160401b038211176132dc57604052565b634e487b7160e01b600052604160045260246000fd5b60a081019081106001600160401b038211176132dc57604052565b604081019081106001600160401b038211176132dc57604052565b602081019081106001600160401b038211176132dc57604052565b90601f801991011681019081106001600160401b038211176132dc57604052565b6001600160401b0381116132dc57601f01601f191660200190565b92919261338b82613364565b916133996040519384613343565b8294818452818301116132bc578281602093846000960137010152565b9080601f830112156132bc578160206133d19335910161337f565b90565b60005b8381106133e75750506000910152565b81810151838201526020016133d7565b90602091613410815180928185528580860191016133d4565b601f01601f1916010190565b600435906001600160a01b03821682036132bc57565b602435906001600160a01b03821682036132bc57565b60609060031901126132bc576001600160a01b039060043582811681036132bc579160243590811681036132bc579060443590565b6015548110156134b45760156000527f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec4750190600090565b634e487b7160e01b600052603260045260246000fd5b6008548110156134b45760086000527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30190600090565b6022548110156134b45760226000527f61035b26e3e9eee00e0d72fd1ee8ddca6894550dca6916ea2ac6baa90d11e5100190600090565b60a09060031901126132bc57604051613550816132f2565b6004356001600160801b03811681036132bc5781526024356001600160401b03811681036132bc57602082015262ffffff60443581811681036132bc57604083015260643590811681036132bc57606082015260843580151581036132bc57608082015290565b9181601f840112156132bc578235916001600160401b0383116132bc57602083818601950101116132bc57565b90600182811c92168015613614575b60208310146135fe57565b634e487b7160e01b600052602260045260246000fd5b91607f16916135f3565b6040519060008260185491613632836135e4565b8083526020936001908181169081156136bd575060011461365e575b505061365c92500383613343565b565b9093915060186000527fb13d2d76d1f4b7be834882e410b3e3a8afaf69f83600ae24db354391d2378d2e936000915b8183106136a557505061365c9350820101388061364e565b8554888401850152948501948794509183019161368d565b91505061365c94925060ff191682840152151560051b820101388061364e565b60405190600082601f54916136f1836135e4565b8083526020936001908181169081156136bd575060011461371a57505061365c92500383613343565b90939150601f6000527fa03837a25210ee280c2113ff4b77ca23440b19d4866cca721c801278fd08d807936000915b81831061376157505061365c9350820101388061364e565b85548884018501529485019487945091830191613749565b90600c548210156134b457600c600052601f8260051c7fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c701921690565b90815180825260208080930193019160005b8281106137d6575050505090565b8351855293810193928101926001016137c8565b9060048210156137f75752565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b03600b5416330361382157565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b6001600160a01b0316801561388557600052600360205260406000205490565b60405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608490fd5b156138e357565b60405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152606490fd5b60005260026020526001600160a01b03604060002054166133d18115156138dc565b61397261396d8260005260026020526001600160a01b0360406000205416151590565b6138dc565b60005260046020526001600160a01b036040600020541690565b1561399357565b60405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201526c1c881bdc88185c1c1c9bdd9959609a1b6064820152608490fd5b90613a12939291613a02612e198433613a89565b613a0d838383613b51565b613e35565b15613a1957565b60405162461bcd60e51b815280613a3260048201613a36565b0390fd5b60809060208152603260208201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b60608201520190565b906001600160a01b038080613a9d84613928565b16931691838314938415613ad0575b508315613aba575b50505090565b613ac69192935061394a565b1614388080613ab4565b909350600052600560205260406000208260005260205260ff604060002054169238613aac565b15613afe57565b60405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201526437bbb732b960d91b6064820152608490fd5b90613b7790613b5f84613928565b6001600160a01b038481169390929183168414613af7565b818116938415613db45783613d085750600854856000526009602052604060002055613ba285614437565b828403613cd5575b506000908482526026602052604090818320548015908115613cbe575b5015613c595790613c05847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9493613bfe89613928565b1614613af7565b858252600460205284818320916001600160601b0360a01b928381541690558584526003602052808420600019815401905581845280842060018154019055878452600260205283209182541617905580a4565b815162461bcd60e51b815260206004820152603860248201527f41667465722075706772616465282920746f6b656e732063616e206e6f74206260448201527765207472616e7366657272656420666f722037206461797360401b6064820152608490fd5b62093a809150613cce9042613fbb565b1138613bc7565b613cde90613865565b60406000858152600660205281812083825260205286828220558681526007602052205538613baa565b848403613d16575b50613ba2565b613d1f90613865565b6000198101908111613d9e576000908682526020906007825260409182842054828103613d67575b508884528383812055868452600681528284209184525281205538613d10565b8785526006825283852083865282528385205488865260068352848620828752835280858720558552600782528385205538613d47565b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b3d15613e30573d90613e1682613364565b91613e246040519384613343565b82523d6000602084013e565b606090565b9290803b15613f2357613e86916020916001600160a01b039460405180958194829389630a85bd0160e11b9b8c865233600487015216602485015260448401526080606484015260848301906133f7565b03916000968791165af190829082613edb575b5050613ecd57613ea7613e05565b80519081613ec85760405162461bcd60e51b815280613a3260048201613a36565b602001fd5b6001600160e01b0319161490565b909192506020813d8211613f1b575b81613ef760209383613343565b8101031261048a5751906001600160e01b03198216820361030a5750903880613e99565b3d9150613eea565b50505050600190565b613f3581613865565b821015613f62576001600160a01b0316600052600660205260406000209060005260205260406000205490565b60405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b6064820152608490fd5b91908203918211613d9e57565b908160209103126132bc57516001600160a01b03811681036132bc5790565b91908201809211613d9e57565b6001600160401b0381116132dc5760051b60200190565b60209081818403126132bc578051906001600160401b0382116132bc57019180601f840112156132bc57825161404081613ff4565b9361404e6040519586613343565b818552838086019260051b8201019283116132bc578301905b828210614075575050505090565b81518152908301908301614067565b6000198114613d9e5760010190565b80518210156134b45760209160051b010190565b156140ae57565b60405162461bcd60e51b815260206004820152602160248201527f45786365656473206d6178206d696e747320706572207472616e73616374696f6044820152603760f91b6064820152608490fd5b1561410457565b60405162461bcd60e51b815260206004820152601c60248201527f45786365656473206d6178206d696e7473207065722077616c6c6574000000006044820152606490fd5b6002600a541461415a576002600a55565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b60058110156137f757806141b05750565b600181036141fd5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b6002810361424a5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b60031461425357565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b9060418151146000146142d1576142cd916020820151906060604084015193015160001a906142db565b9091565b5050600090600290565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831161435e5791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa156143515781516001600160a01b0381161561434b579190565b50600190565b50604051903d90823e3d90fd5b50505050600090600390565b1561437157565b60405162461bcd60e51b815260206004820152601760248201527f546f6b656e20494420646f6573206e6f742065786973740000000000000000006044820152606490fd5b156143bd57565b60405162461bcd60e51b81526020600482015260116024820152702737ba103a34329027232a1037bbb732b960791b6044820152606490fd5b9190916001600160401b0380809416911601918211613d9e57565b601554600160401b8110156132dc57612900816001614433930160155561347d565b9055565b600854600160401b8110156132dc5761290081600161443393016008556134ca565b60ff1660ff8114613d9e5760010190565b61448d6127d58260005260026020526001600160a01b0360406000205416151590565b6000818152602060268152604090818320546145c0576026906144c26144b286613928565b6001600160a01b031633146143b6565b8484526025815261458d8385208451906144db826132c1565b546001600160801b038082168084526001600160401b03608084901c168685015260c09290921c8784015286518981526020810192909252919033907f0c3fdcacbee530581c67c89a851ff8052aa367c589919df3056398ce311a237d90604090a27ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78487518a8152a161457482825116601354613fe7565b6013558787526025845286868120555116601254613fbb565b6012558484525242908220555b600960ff8216106145a9575050565b6145bb906145b683614411565b614459565b61459a565b606491519062461bcd60e51b82526004820152601060248201526f105b1c9958591e481d5c19dc9859195960821b6044820152fd5b81810292918115918404141715613d9e57565b94909695926001600160401b03906001600160801b0360a096946001600160a01b0360c08a019b16895216602088015216604086015262ffffff80921660608601521660808401521515910152565b91926060936001600160a01b03829316845260406020850152816040850152848401376000828201840152601f01601f1916010190565b6146ae8160005260026020526001600160a01b0360406000205416151590565b15614cc1576146bb6136dd565b5115614710576133d160206146d76146d16136dd565b93614e8e565b9260405193816146f086935180928680870191016133d4565b8201614704825180938680850191016133d4565b01038084520182613343565b908160005260266020526040600020541515600014614ca0576040516147358161330d565b600381526259657360e81b6020820152915b309260405191614756836132c1565b602a8352602083019260403685378051156134b457603084538051956001968710156134b4576078602183015360295b878111614c595750614c15576034614803916147d5956147a585614e8e565b906040519788937268747470733a2f2f626c617374722e78797a2f60681b602086015251809260338601906133d4565b8201602f60f81b60338201526147f482518093602087850191016133d4565b01036014810186520184613343565b61480c81614e8e565b9261481561361e565b9061481f83614e8e565b83600052602560205261483f6001600160801b0360406000205416614e8e565b93600052602560205261487260406000205461486c6001600160401b0391828160801c169060c01c6143f6565b16614e8e565b9260405196607b60f81b6020890152661134b2111d101160c91b60218901526148a581518092602060288c0191016133d4565b870161088b60f21b602882015268113730b6b2911d101160b91b602a8201526148d88251809360206033850191016133d4565b019761202360f01b60338a01526148f982518093602060358d0191016133d4565b61088b60f21b6035838b010152691134b6b0b3b2911d101160b11b6037838b0101526000986020549161492b836135e4565b92818116908115614beb5750600114614b83575b505050509260c1928592614b2b95614b30989961088b60f21b8152701132bc3a32b93730b62fbab936111d101160791b60028201526149888251809360206013850191016133d4565b019161088b60f21b60138401526e2261747472696275746573223a205b60881b6015840152607b60f81b60248401527f2274726169745f74797065223a202256616c7565206c6f636b656420287765696025840152620a488b60ea1b6045840152680113b30b63ab2911d160bd1b92836048820152614a118251809360206051850191016133d4565b01611f4b60f21b92836051830152607b60f81b60538301527f22646973706c61795f74797065223a202264617465222c00000000000000000060548301527f2274726169745f74797065223a202256616c7565206c6f636b656420756e7469606b830152621b088b60ea1b608b830152608e820152614a9a8251809360206097850191016133d4565b01906097820152607b60f81b60998201527f2274726169745f74797065223a20225570677261646564222c00000000000000609a82015269113b30b63ab2911d101160b11b60b3820152614af882518093602060bd850191016133d4565b01601160f91b60bd820152607d60f81b8060be830152605d60f81b60bf83015260c08201520360a1810184520182613343565b614d48565b6133d1603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000006020830152614b7381518092602086860191016133d4565b810103601d810184520182613343565b909192995060206000527fc97bfaf2f8ee708c303a06d134f5ecd8389ae0432af62dc132a24118292866bb906000915b848310614bd3575050509790970190960160410195828282614b3061493f565b8054848d018401604101526020909201918101614bb3565b60ff1916604193909501838101959095525050811515909102909101019650828282614b3061493f565b606460405162461bcd60e51b815260206004820152602060248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b90600f811660108110156134b45783518310156134b4576f181899199a1a9b1b9c1cb0b131b232b360811b901a8383016020015360041c908015613d9e5760001901614786565b604051614cac8161330d565b60028152614e6f60f01b602082015291614747565b60405162461bcd60e51b815260206004820152602760248201527f4552433732313a2055524920717565727920666f72206e6f6e6578697374656e6044820152663a103a37b5b2b760c91b6064820152608490fd5b90614d2082613364565b614d2d6040519182613343565b8281528092614d3e601f1991613364565b0190602036910137565b805115614e7a57604051614d5b816132c1565b604081527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208201527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f60408201528151600292838201809211613d9e576003918290046001600160fe1b0381168103613d9e57614ddd908594951b614d16565b936020850193829183518401925b838110614e295750505050510680600114614e1657600214614e0b575090565b603d90600019015390565b50603d9081600019820153600119015390565b85600491979293949701918251600190603f9082828260121c16880101518453828282600c1c16880101518385015382828260061c1688010151888501531685010151878201530195929190614deb565b50604051614e8781613328565b6000815290565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000080821015614fc3575b506d04ee2d6d415b85acef810000000080831015614fb4575b50662386f26fc1000080831015614fa5575b506305f5e10080831015614f96575b5061271080831015614f87575b506064821015614f77575b600a80921015614f6d575b600190816021614f25828701614d16565b95860101905b614f37575b5050505090565b600019019083906f181899199a1a9b1b9c1cb0b131b232b360811b8282061a835304918215614f6857919082614f2b565b614f30565b9160010191614f14565b9190606460029104910191614f09565b60049193920491019138614efe565b60089193920491019138614ef1565b60109193920491019138614ee2565b60209193920491019138614ed0565b604093508104915038614eb7565b90614fdb82613ff4565b614fe86040519182613343565b8281528092614d3e601f1991613ff4565b909194939262ffffff1692831561549d57600894615018858754613fe7565b601a5410615462576001600160801b038094169285840292858416938403613d9e57851692830361541d5761504c86614fd1565b9460006001600160401b0398894216915b8981106151b857505050506001600160a01b0316968791604097885191829160a0835260a0830161508e908a6137b6565b9460209a888c8601528c850152166060830152818403608083015233936150b4916133f7565b037f3c17cb77a104e5fa9f5e5427339add873947fe1b19af0177401348d86d2edece91a3601254906150e591613fe7565b601255156150f4575b50505050565b60005b81518110156151aa5761510a8183614093565b51857f0c3fdcacbee530581c67c89a851ff8052aa367c589919df3056398ce311a237d868051848152600088820152a27ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7848651838152a180600052602584526000858120556026845242856000205560005b600960ff82161061519857505061519390614084565b6150f7565b6151a5906145b683614411565b61517d565b5050505050388080806150ee565b6151c061552e565b806151cb838c614093565b528b8d6040908151906151dd826132c1565b8c8252602093848301911681528282019088825285600052602585528984600020935116906001600160401b0360801b905160801b16916001600160401b0360c01b905160c01b16911717905560155460108352816000205561523f83614411565b6001600160a01b0388169182156153dc576152796152738560005260026020526001600160a01b0360406000205416151590565b156154e2565b85548460005260098252826000205561529184614437565b61529a89613865565b8360005260068252826000208160005282528483600020558460005260078252826000205560268152816000205480159081156153c5575b50156153625790600284939261530561527361535d989760005260026020526001600160a01b0360406000205416151590565b836000526003815282600020600181540190558460005252600020816001600160601b0360a01b82541617905560007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4614084565b61505d565b608491519062461bcd60e51b82526004820152603860248201527f41667465722075706772616465282920746f6b656e732063616e206e6f74206260448201527765207472616e7366657272656420666f722037206461797360401b6064820152fd5b62093a8091506153d59042613fbb565b11386152d2565b606491519062461bcd60e51b825280600483015260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152fd5b60405162461bcd60e51b815260206004820152601460248201527f496e636f7272656374206d696e742070726963650000000000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601360248201527213585e081cdd5c1c1b1e48195e18d959591959606a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152601760248201527f5175616e746974792063616e6e6f74206265207a65726f0000000000000000006044820152606490fd5b156154e957565b60405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606490fd5b602254156155b95760225460001980820190828211613d9e5761555082613501565b90549060031b1c927ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1156155a35761559082613501565b909182549160031b1b1916905560225590565b634e487b7160e01b600052603160045260246000fd5b601654600181016016559056fea2646970667358221220c089ffbaba37ce3f2dcf4ca06afd5df0dd639082b30a88ace7b1bbdd5e5a449c64736f6c63430008150033000000000000000000000000b574b1c4233b61ecf8aa1fa6e6c694c4678ed4ee00000000000000000000000014fde5478709f0f8bd0ffb5de2030e0c618652d200000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000001869f000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000278d0000000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000068155a43676e00000000000000000000000000006726025532fbf0d8a9f71338e68373de96c0e1b9000000000000000000000000df808a2b1d20293cd37948fcfddb0f1132312c05000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e424c41535452204c6f7474657279000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a424c415354524c4f544f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006368747470733a2f2f617a7572652d706173736976652d71756f6b6b612d3339302e6d7970696e6174612e636c6f75642f697066732f516d5565343239737570516f684447354358323467706f4e41743865345a505966445832753474757365465042320000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x60406080815260048036101561001f575b5050361561001d57600080fd5b005b600090813560e01c9081626059fd146130a857816301ffc9a71461300257816306fdde0314612fe4578163081812fc14612fbc578163095ea7b314612e4257816318160ddd14612e2357816323b872dd14612df9578163268e280314612d12578163269c759b14612ca4578163278ecde1146127945781632f745c591461276b5781633b198b361461274c578163406cf2291461226557816342842e0e1461223c57816345977d031461221f5781634d9b9426146121a05781634f6ccce71461211a57816350b44712146120ee57816353c838e01461201d57816355f804b314611e0357816359b39c6214611dc2578163608557c114611d215781636352211e14611cf157816368447c9314611cc95781636c0360eb14611cab57816370a0823114611c85578163715018a614611c2857816375ce7fff14611be9578163787dce3d14611bc75781637d583676146119a15781637e1c1757146119795781638da5cb5b146119515781638e50e509146119325781639106a059146118c457816395d89b4114611812578163966dae0e146117ea57816399c89e81146117565781639dbec6711461166f578163a22cb465146115a3578163a263a9eb14611577578163a68aa967146114f3578163a6bfef6114611478578163b3f6b99a14610fde578163b88d4fde14610f88578163bf4ad33814610e87578163c4f8f27b14610e5e578163c87b56dd14610e2a578163d338143814610db9578163d3cf00a314610d9a578163d5abeb0114610d7b578163d98de53e146108cb578163e0d8aafb14610836578163e4b3758b1461080d578163e5328e06146107ee578163e6dee7ed14610593578163e985e9c514610542578163ea66aeb3146104cf578163eb671cc51461048e578163ef81b4d414610462578163ef97ead814610428578163f2fde38b1461035f578163f4dadc611461030d575063fc5ab87c03610010573461030a578060031936011261030a57506011548151906103008260ff83166137ea565b60081c6020820152f35b80fd5b8391503461035b57602036600319011261035b57606092829135815260256020522054908051916001600160801b03811683526001600160401b038160801c16602084015260c01c90820152f35b8280fd5b8391503461035b57602036600319011261035b5761037b61341c565b9061038461380d565b6001600160a01b038092169283156103d6575050600b54826001600160601b0360a01b821617600b55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b8391503461035b57602036600319011261035b57359160225483101561030a5750610454602092613501565b91905490519160031b1c8152f35b82843461048a578160031936011261048a576020906001600160a01b03601e54169051908152f35b5080fd5b823461030a57602036600319011261030a576001600160a01b036104b061341c565b6104b861380d565b166001600160601b0360a01b600e541617600e5580f35b50503461030a57602036600319011261030a576104ea61341c565b916104f483613865565b6104fd81614fd1565b925b81811061051f5782516020808252819061051b908201876137b6565b0390f35b8061052d61053d9287613f2c565b6105378287614093565b52614084565b6104ff565b82843461048a578060031936011261048a5760209161055f61341c565b82610568613432565b926001600160a01b03809316815260058652209116600052825260ff81600020541690519015158152f35b83833461030a576020918260031936011261048a5783356001600160401b03811161035b576105c590369086016133b6565b916001600160a01b03600f541633036107ab576015541561077657600c5492600160401b841015610763579061063d9160018501600c5561060585613779565b505061061085613779565b81549060031b9060ff6001831b921b191617905583519283918688840152858084015260608301906133f7565b0390610651601f1992838101855284613343565b6364e6212619420142811161070557600390046001810190818111610750574660010361071857600501809111610705578495969750937fd91fc3685b930310b008ec37d2334870cab88a023ed8cc628a2e2ccd4e55d20294925b81516106d78a8201928684528480840152826106cb606082018a6133f7565b03908101835282613343565b51902091878152600d895220556106fc845192839283528588840152858301906133f7565b0390a151908152f35b634e487b7160e01b825260118852602482fd5b600201809111610705578495969750937fd91fc3685b930310b008ec37d2334870cab88a023ed8cc628a2e2ccd4e55d20294926106ac565b634e487b7160e01b835260118952602483fd5b634e487b7160e01b825260418652602482fd5b815162461bcd60e51b8152808601859052600f60248201526e4e6f207061727469636970616e747360881b6044820152606490fd5b815162461bcd60e51b8152808601859052601660248201527f4e6f7420612047656c61746f20726571756573746572000000000000000000006044820152606490fd5b82843461048a578160031936011261048a576020906012549051908152f35b8391503461035b57602036600319011261035b5760209282913581526026845220549051908152f35b82939150346108c757826003193601126108c75761085261380d565b6001600160a01b0360215416803b156108c257839060248451809681936350ba73bd60e11b835230878401525af180156108b85761088e578380f35b6001600160401b0383116108a55750523880808380f35b634e487b7160e01b845260419052602483fd5b82513d86823e3d90fd5b505050fd5b5050fd5b826020853660031901821361035b576108e26132aa565b936108eb614149565b60ff60235460f01c1615610d3a5761012c610908601b5442613fbb565b106109dd575b506109a7929360235461094d62ffffff8261093982809560c01c1680159081156109d0575b506140a7565b60d81c1680159081156109af575b506140fd565b338652602784526109648387209183168254613fe7565b9055602354657075626c696360d01b6001600160801b039351946109878661330d565b60068652850152823416926001600160401b038260801c16911633614ff9565b6001600a5580f35b9050338852602786526109c88589205484861690613fe7565b111588610947565b905083871611158b610933565b9291906001600160a01b039384602154168251906305391b2760e31b9182815285818581855afa908115610ba55788929187918991610d1d575b5060248751809b81936370a0823160e01b8352338a840152165afa978815610ba5578798610cea575b5087151580610cdb575b15610c3c57601790815493610a6562ffffff8c168096613fe7565b6014601a540410610be65787908688518094819382525afa908115610bdc579088918291610baf575b50602487518095819363ea66aeb360e01b8352338a840152165afa918215610ba5578792610b81575b508691875b898110610b2e575b50505090919293949550031561090e5782608492519162461bcd60e51b8352820152603060248201527f596f7520646f6e2774206f776e20656e6f756768206b65797320746f206d696e60448201526f742061736b6564207175616e7469747960801b6064820152fd5b610b388183614093565b51895260298852868920805415610b59575b50610b5490614084565b610abc565b93610b6e919460018091558454018455614084565b92848414610b7c578b610b4a565b610ac4565b610b9e9192503d8089833e610b968183613343565b81019061400b565b9089610ab7565b85513d89823e3d90fd5b610bcf9150883d8a11610bd5575b610bc78183613343565b810190613fc8565b8b610a8e565b503d610bbd565b86513d8a823e3d90fd5b865162461bcd60e51b8152808701899052602a60248201527f4d757374206e6f74206d696e74206d6f7265207468616e203525206f6620746f60448201526974616c20737570706c7960b01b6064820152608490fd5b845162461bcd60e51b8152808501879052606760248201527f5468652066697273742035206d696e206f66207075626c6963206d696e74206160448201527f726520726573657276656420666f7220424c41535452206b657920686f6c646560648201527f727320286d6178206d696e74207175616e746974793a203120706572206b6579608482015266206f776e65642960c81b60a482015260c490fd5b508762ffffff8a161115610a4a565b9097508581813d8311610d16575b610d028183613343565b81010312610d1257519689610a40565b8680fd5b503d610cf8565b610d349150823d8411610bd557610bc78183613343565b8b610a17565b82606492519162461bcd60e51b8352820152601960248201527f5075626c6963206d696e74206973206e6f7420616374697665000000000000006044820152fd5b82843461048a578160031936011261048a57602090601a549051908152f35b82843461048a578160031936011261048a57602090601b549051908152f35b82843461048a57602036600319011261048a577fe81fbf9dcd9efb641e9dd6a384b82aedac00c55a93402509bd9866fab1a92afa906001600160a01b03610dfe61341c565b610e0661380d565b16806001600160601b0360a01b601e541617601e558151903382526020820152a180f35b83833461030a57602036600319011261030a5750610e4b61051b923561468e565b90519182916020835260208301906133f7565b8391503461035b57602036600319011261035b576020928291358152600d845220549051908152f35b82843461048a577fca805018b1f306f78c930fd9dd300fc655fa266c44ad5e355f8c2d19d5ea8f6490610eb936613538565b610ec161380d565b610f6b6023546001600160801b03835116936020840151818501519162ffffff966080606088015197015115159460ff8060f01b8760f01b16838260f81b8416176001600160401b0360801b8760801b161762ffffff60c01b8860c01b161762ffffff60d81b8b60d81b161717918260235560f01c16159081610f7a575b50610f71575b6001600160401b03886001600160a01b03600b54169351998a9916951693169187614608565b0390a180f35b42601b55610f45565b60ff915060f01c168b610f3f565b90503461048a57608036600319011261048a57610fa361341c565b610fab613432565b906064356001600160401b038111610fda57610fd793610fcd913691016133b6565b91604435916139ee565b80f35b8480fd5b82843461048a578060031936011261048a576024926001600160401b038435818111610fda5761101190369084016135b7565b9190926001600160a01b039687600e5416330361144657838501948681870312611442576020958682013585811161143e579061104f9183016133b6565b948551860194888789880197031261143e5787870151968981015191821161143a570185603f8201121561143e57878101519061108b82613364565b966110988b519889613343565b8288528a838301011161143a576110c19392916110ba918b8b8a0191016133d4565b369161337f565b858151910120848852600d865286882054149760ff6110df86613779565b90549060031b1c16156113f8578798611104575b5050505090600d9184525281205580f35b909192939495809750518681019084358252308982015246606082015286608082015260808152611134816132f2565b51902061113f614149565b6015549081156113e65790611154910661347d565b90549060031b1c9261116584613928565b9260115460ff8116838110156113d4578b9190600181036112a85750505060135460115460081c9182821061125b57508a80836111a482958395613fbb565b6013558688165af16111b4613e05565b501561124d575091847fd4c141ac80ac9c94920abcce59da203aaf122455ce2609904c2fda07ec8012ef8998979593600d97955b61121a601154918b5193836112018660ff8197166137ea565b60081c8b85015260608d850152169660608301906133f7565b0390a46001600a5561122b81613779565b60ff82549160031b1b19169055808552828252848481205590918680806110f3565b87516312171d8360e31b8152fd5b836084918b8d519262461bcd60e51b8452830152808201527f4e6f7420656e6f756768206574682066726f6d20757067726164657320746f206044820152631cd95b9960e21b6064820152fd5b6002909b9997959493929a98969b146112ec575b5050507fd4c141ac80ac9c94920abcce59da203aaf122455ce2609904c2fda07ec8012ef600d96979885926111e8565b909192939597999496985060081c906064611309601454846145f5565b049161132e8361132861131f4760125490613fbb565b60135490613fbb565b92613fe7565b116113895750808a91611369575b5080808060115460081c8688165af1611353613e05565b501561124d579081808a989694999795936112bc565b8180809286600b54165af161137c613e05565b501561124d57888a61133c565b8260216084928b8d519362461bcd60e51b85528401528201527f4e6f7420656e6f756768206574682066726f6d207969656c6420746f2073656e6044820152601960fa1b6064820152fd5b634e487b7160e01b8c5260218452828cfd5b634e487b7160e01b8a5260128552838afd5b865162461bcd60e51b8152808401879052601c818401527f726571756573742066756c66696c6c6564206f72206d697373696e67000000006044820152606490fd5b8a80fd5b8980fd5b8780fd5b90600d606492602088519362461bcd60e51b85528401528201526c37b7363c9037b832b930ba37b960991b6044820152fd5b90503461048a57602036600319011261048a5780356001600160401b03918282116114ef57366023830112156114ef5781013591821161035b576024906005368385831b84010111610fda57845b8481106114d1578580f35b806114e5856114ea93851b8601013561446a565b614084565b6114c6565b8380fd5b82843461048a578160031936011261048a5760ff7fe151bf9d2a434324b5e13c5bdff9bd2e9ab2e30c657f586da54bbe88cf1d8b069161153161380d565b6024805460f084811b19821691811c8516158516811b9190911791829055600b5492516001600160a01b039390931683521c909116151560208201528060408101610f6b565b82843461048a578160031936011261048a5760209061159c61131f4760125490613fbb565b9051908152f35b9050823461035b578060031936011261035b576115be61341c565b9060243591821515809303610fda576001600160a01b03169283331461162d5750338452600560205280842083855260205280842060ff1981541660ff8416179055519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b6020606492519162461bcd60e51b8352820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152fd5b50503461030a578060031936011261030a5781519182826020938454611694816135e4565b9182855260019187838216918260001461172f5750506001146116d4575b50505061051b92916116c5910385613343565b519282849384528301906133f7565b91908680945083527fc97bfaf2f8ee708c303a06d134f5ecd8389ae0432af62dc132a24118292866bb5b82841061171757505050820101816116c561051b6116b2565b8054848a0186015288955087949093019281016116fe565b60ff19168782015293151560051b860190930193508492506116c5915061051b90506116b2565b82843461048a578160031936011261048a577ff2721e078a20e7f6ba187f7a54783e6e4cea86087bafc68840732db61dec47889061179261380d565b60ff6023548160f01b828260f01c161560f01b16908260f01b1916178060235560f01c1690816117e1575b600b5490516001600160a01b03909116815290151560208201528060408101610f6b565b42601b556117bd565b82843461048a578160031936011261048a576020906001600160a01b03601c54169051908152f35b50503461030a578060031936011261030a578151918282601954611835816135e4565b9081845260209560019187838216918260001461172f5750506001146118685750505061051b92916116c5910385613343565b9190869350601983527f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c96955b8284106118ac57505050820101816116c561051b6116b2565b8054848a018601528895508794909301928101611893565b50503461030a578060031936011261030a575060245490516001600160801b0382168152608082811c6001600160401b0316602083015260c083901c62ffffff908116604084015260d884901c16606083015260f09290921c60ff161515918101919091528060a081010390f35b82843461048a578160031936011261048a576020906014549051908152f35b82843461048a578160031936011261048a576020906001600160a01b03600b54169051908152f35b82843461048a578160031936011261048a576020906001600160a01b03602154169051908152f35b9050823461035b57602091826003193601126114ef576001600160401b038135818111611bc3576119d590369084016135b7565b9290916119e061380d565b8311611bb057506119f184546135e4565b601f8111611b4f575b5084601f8311600114611aad5790827f0e97d384f3f2db9658556130716bebad5af0675b729419b713437de32653febc93928791611aa2575b508260011b906000198460031b1c19161785555b611a5684519283923384614657565b0390a1611a64601f546135e4565b15611a6d578280f35b7f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91601a54825191858352820152a181808280f35b905081013587611a33565b8486527fc97bfaf2f8ee708c303a06d134f5ecd8389ae0432af62dc132a24118292866bb90601f198416875b87828210611b3957505090847f0e97d384f3f2db9658556130716bebad5af0675b729419b713437de32653febc9594939210611b1f575b5050600182811b018555611a47565b820135600019600385901b60f8161c191690558680611b10565b6001849582939588013581550194019201611ad9565b8486527fc97bfaf2f8ee708c303a06d134f5ecd8389ae0432af62dc132a24118292866bb601f840160051c810191868510611ba6575b601f0160051c01905b818110611b9b57506119fa565b868155600101611b8e565b9091508190611b85565b634e487b7160e01b865260419052602485fd5b8580fd5b90503461048a57602036600319011261048a57611be261380d565b3560145580f35b8391503461035b57602036600319011261035b573591600c5483101561030a575060ff611c17602093613779565b92905490519260031b1c1615158152f35b823461030a578060031936011261030a57611c4161380d565b806001600160a01b03600b546001600160601b0360a01b8116600b55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b82843461048a57602036600319011261048a5760209061159c611ca661341c565b613865565b82843461048a578160031936011261048a5761051b90610e4b6136dd565b82843461048a578160031936011261048a576020906001600160a01b03601d54169051908152f35b83833461030a57602036600319011261030a57506001600160a01b03611d1960209335613928565b915191168152f35b9050823461035b578060031936011261035b57805190808201908282106001600160401b03831117611daf57528135828110156114ef578152602435906001600160f81b03821682036114ef5760208101918252611d7d61380d565b519180831015611d9c575060ff908119905160081b1691161760115580f35b634e487b7160e01b845260219052602483fd5b634e487b7160e01b855260418452602485fd5b823461030a57602036600319011261030a576001600160a01b03611de461341c565b611dec61380d565b166001600160601b0360a01b600f541617600f5580f35b8391503461035b57602090816003193601126114ef576001600160401b038135818111611bc357611e3790369084016135b7565b929091611e4261380d565b8311611bb05750601f611e5581546135e4565b818111611fbf575b5085818411600114611efa579183917f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c9695947f78cd0c51de67bd306f7a477494a110772ec9e86ffcfb04448079856a62dbe3b5948991611eef575b508360011b906000198560031b1c19161790555b611edc85519283923384614657565b0390a1601a54825191858352820152a180f35b905082013589611eb9565b8187527fa03837a25210ee280c2113ff4b77ca23440b19d4866cca721c801278fd08d80790601f198516885b818110611fa85750918593917f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c9897967f78cd0c51de67bd306f7a477494a110772ec9e86ffcfb04448079856a62dbe3b5969410611f8e575b5050600183811b019055611ecd565b830135600019600386901b60f8161c191690558880611f7f565b919287600181928689013581550194019201611f26565b8187527fa03837a25210ee280c2113ff4b77ca23440b19d4866cca721c801278fd08d8078280860160051c820192878710612014575b0160051c01905b8181106120095750611e5d565b878155600101611ffc565b92508192611ff5565b82843461048a577f059691c8ca8b8a0a17d6d79c46d63bf67f157d28700329f2f842fc08c1cf4d6b9061204f36613538565b61205761380d565b610f6b6001600160801b0382511692602454906020840151818501519162ffffff96608060608801519701511515948160ff60f01b8760f01b169160ff60f81b16176001600160401b0360801b8560801b161762ffffff60c01b8660c01b161762ffffff60d81b8960d81b1617176024556001600160401b03886001600160a01b03600b54169351998a9916951693169187614608565b8391503461035b57602036600319011261035b57359160155483101561030a575061045460209261347d565b9190503461030a57602036600319011261030a575080359060085482101561214857602083610454846134ca565b608490602084519162461bcd60e51b8352820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b6064820152fd5b8284608036600319011261048a576121b661341c565b6001600160801b03906024358281168103610fda576044356001600160401b0381168103611bc3576064359162ffffff83168303610d1257610fd7956121fa61380d565b51946122058661330d565b600586526437bbb732b960d91b6020870152341693614ff9565b90503461048a57602036600319011261048a57610fd7903561446a565b82843461048a57610fd79061225036613448565b9192519261225d84613328565b8584526139ee565b9050823461035b578260031936011261035b57612280614149565b61228861380d565b61229861131f4760125490613fbb565b9182156127155783849184906001600160a01b039485602154168151926305391b2760e31b845260209182858381845afa94851561270b578b956126ec575b5083516331056e5760e21b81529483868481855afa9586156126e2578c966126c3575b5084516358710f4560e11b81529184838581845afa928d8415612686579186918695949394612691575b508751636e88a7bd60e01b815294859182905afa928d841561268657908c92919461264f575b50169a81612476575b50509091929394959697985089808080898d600b54165af1612373613e05565b501561246757866123db575b897f1895c62887d1ed7e831b47190e1164cd03e07077102c7891b069574cb27570d360c08b8b8b8b8b8b8b86600b54169680601d541693835198895216908701528501526060840152608083015260a0820152a16001600a5580f35b8989601d54169182612416575b508080809350898c89165af16123fc613e05565b5015612408578061237f565b82516312171d8360e31b8152fd5b80156123e8578180939a5061271061243182938c979c6145f5565b04809b5af161243e613e05565b5015612457578661244e91613fbb565b948989816123e8565b82516312171d8360e31b81528690fd5b5082516312171d8360e31b8152fd5b8c8b600b54169c8d8851906370a0823160e01b8252878201528781602481855afa908115612645578391612618575b50156125eb57875163ea66aeb360e01b81528681019e909e52818e602481845afa9d8e156125e157829e6125c5575b50819d825b81518110156125b1576124ec8183614093565b518a519063e4b3758b60e01b8252898201528981602481875afa9081156125a757859161257a575b506125275761252290614084565b6124d9565b50505050909192939495969798999a5060015b15612553575b50505b9088979695949392918b80612353565b61257292979850612569600592612710926145f5565b04048097613fbb565b948a80612540565b90508981813d83116125a0575b6125918183613343565b81010312610fda575138612514565b503d612587565b8b513d87823e3d90fd5b50505050909192939495969798999a61253a565b6125da919e503d8084833e610b968183613343565b9c8f6124d4565b88513d84823e3d90fd5b505098999a5061271091975061261292939495965061260a90896145f5565b048097613fbb565b94612543565b90508781813d831161263e575b61262f8183613343565b8101031261035b5751386124a5565b503d612625565b89513d85823e3d90fd5b86809295508193503d831161267f575b6126698183613343565b8101031261267b578a9051928e61234a565b8c80fd5b503d61265f565b8751903d90823e3d90fd5b9450925083813d83116126bc575b6126a98183613343565b8101031261267b5784849351928f612324565b503d61269f565b6126db919650843d8611610bd557610bc78183613343565b948c6122fa565b85513d8e823e3d90fd5b612704919550833d8511610bd557610bc78183613343565b938b6122d7565b84513d8d823e3d90fd5b6020606492519162461bcd60e51b835282015260126024820152712737903cb4b2b632103a379031b630b4b69760711b6044820152fd5b82843461048a578160031936011261048a576020906013549051908152f35b82843461048a578060031936011261048a5760209061159c61278b61341c565b60243590613f2c565b82843461048a5760208060031936011261035b5783356127b2614149565b6127da6127d58260005260026020526001600160a01b0360406000205416151590565b61436a565b6127e381613928565b926127fa6001600160a01b039485339116146143b6565b8185526025835280852092815193612811856132c1565b54946001600160801b03958681168087526001600160401b039184880191838260801c1683528689019160c01c825215612c6d57908280612857935116915116906143f6565b164210612c2a57845183518581529087166001600160801b0316602082015233907f21e12a7cad0da5928167e1084ea4d5fdf8d9af66657a2543a9ac76a0ca08147790604090a27ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7828451868152a16015546000199190828101908111612b8557858952601084526128ec858a20549161347d565b90549060031b1c806129176129008461347d565b819391549060031b91821b91600019901b19161790565b90558952601084528489205584885287848120556015548015612b7257820161293f8161347d565b8482549160031b1b1916905560155561295785613928565b8082169081612b98575050600854858952600984528489205561297985614437565b600854828101908111612b85578589526009845261299a858a2054916134ca565b90549060031b1c806129ae612900846134ca565b90558952600984528489205584885287848120556008548015612b725782016129d6816134ca565b8482549160031b1b1916905560085584885260268352838820548015908115612b5b575b5015612af75784918891612a0d84613928565b908484528b8652868420916001600160601b0360a01b92838154169055169182845260038652868420908154019055838352600285528583209081541690557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a48580808088885116335af1612a83613e05565b5015612ae757906025869284845252812055602254600160401b811015612ad457612ac9949550612900816001612abd9301602255613501565b90555116601254613fbb565b6012556001600a5580f35b634e487b7160e01b855260418652602485fd5b81516312171d8360e31b81528790fd5b835162461bcd60e51b8152808a01849052603860248201527f41667465722075706772616465282920746f6b656e732063616e206e6f74206260448201527765207472616e7366657272656420666f722037206461797360401b6064820152608490fd5b62093a809150612b6b9042613fbb565b118a6129fa565b634e487b7160e01b895260318a52602489fd5b634e487b7160e01b895260118a52602489fd5b612ba190613865565b90838201918211612c1757868a5260078552858a2054828103612be0575b50868a52898681205589526006845284892090895283528784812055612979565b818b5260068652868b20838c528652868b2054828c5260068752878c20828d52875280888d20558b5260078652868b20558b612bbf565b634e487b7160e01b8a5260118b5260248afd5b825162461bcd60e51b8152808901839052601760248201527f4c6f636b20706572696f64206e6f7420657870697265640000000000000000006044820152606490fd5b855162461bcd60e51b8152808c018690526011602482015270139bdd1a1a5b99c81d1bc81c99599d5b99607a1b6044820152606490fd5b50503461030a578060031936011261030a575060235490516001600160801b0382168152608082811c6001600160401b0316602083015260c083901c62ffffff908116604084015260d884901c16606083015260f09290921c60ff161515918101919091528060a081010390f35b9050823461035b576020806003193601126114ef578235612d31614149565b612d3961380d565b6001600160a01b039384600b5416845191630951888f60e01b8352309083015260248201528160448201528281606481897343000000000000000000000000000000000000025af18015612def57612dc5575b507fa1c8454e70ae3014662889130afe679a3c6067101b0c4225f0cbfd93fa66348b93600b5416918351928352820152a16001600a5580f35b8290813d8311612de8575b612dda8183613343565b81010312610fda5785612d8c565b503d612dd0565b84513d88823e3d90fd5b823461030a57610fd7612e0b36613448565b91612e1e612e198433613a89565b61398c565b613b51565b82843461048a578160031936011261048a576020906008549051908152f35b8391503461035b578160031936011261035b57612e5d61341c565b90602435926001600160a01b03918280612e7687613928565b16941693808514612f6f57803314908115612f50575b5015612ee8578486526020528420805473ffffffffffffffffffffffffffffffffffffffff191683179055612ec083613928565b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b6020608492519162461bcd60e51b8352820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152fd5b90508652600560205281862033875260205260ff828720541687612e8c565b506020608492519162461bcd60e51b8352820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152fd5b83833461030a57602036600319011261030a57506001600160a01b03611d196020933561394a565b82843461048a578160031936011261048a5761051b90610e4b61361e565b8391503461035b57602036600319011261035b57359063ffffffff60e01b821680920361035b5760209250632483248360e11b8214918215613048575b50519015158152f35b90915063780e9d6360e01b8114908115613065575b50908361303f565b6380ac58cd60e01b811491508115613097575b8115613086575b508361305d565b6301ffc9a760e01b1490508361307f565b635b5e139f60e01b81149150613078565b82848060031936011261048a576130bd6132aa565b6001600160401b0390602435828111610fda576130dd90369087016133b6565b946130e6614149565b6024549560ff8760f01c16156132675761317d6131859161313162ffffff8a61311e82809d60c01c16801590811561325a57506140a7565b60d81c16801590811561323857506140fd565b865160208101903360601b82526014815261314b8161330d565b5190207f19457468657265756d205369676e6564204d6573736167653a0a3332000000008952601c52603c88206142a3565b91909161419f565b6001600160a01b0380601e54169116036131f557506109a7939433865260286020526131b78487209183168254613fe7565b90556024546001600160801b039351936131d08561330d565b60078552667072697661746560c81b6020860152803416938260801c16911633614ff9565b606490602085519162461bcd60e51b8352820152601f60248201527f596f75722077616c6c6574206973206e6f742077686974656c69737465642e006044820152fd5b9050338a526028602052613252898b20548c891690613fe7565b11158b610947565b9050838a1611158e610933565b845162461bcd60e51b8152602081840152601a60248201527f50726976617465206d696e74206973206e6f74206163746976650000000000006044820152606490fd5b6004359062ffffff821682036132bc57565b600080fd5b606081019081106001600160401b038211176132dc57604052565b634e487b7160e01b600052604160045260246000fd5b60a081019081106001600160401b038211176132dc57604052565b604081019081106001600160401b038211176132dc57604052565b602081019081106001600160401b038211176132dc57604052565b90601f801991011681019081106001600160401b038211176132dc57604052565b6001600160401b0381116132dc57601f01601f191660200190565b92919261338b82613364565b916133996040519384613343565b8294818452818301116132bc578281602093846000960137010152565b9080601f830112156132bc578160206133d19335910161337f565b90565b60005b8381106133e75750506000910152565b81810151838201526020016133d7565b90602091613410815180928185528580860191016133d4565b601f01601f1916010190565b600435906001600160a01b03821682036132bc57565b602435906001600160a01b03821682036132bc57565b60609060031901126132bc576001600160a01b039060043582811681036132bc579160243590811681036132bc579060443590565b6015548110156134b45760156000527f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec4750190600090565b634e487b7160e01b600052603260045260246000fd5b6008548110156134b45760086000527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30190600090565b6022548110156134b45760226000527f61035b26e3e9eee00e0d72fd1ee8ddca6894550dca6916ea2ac6baa90d11e5100190600090565b60a09060031901126132bc57604051613550816132f2565b6004356001600160801b03811681036132bc5781526024356001600160401b03811681036132bc57602082015262ffffff60443581811681036132bc57604083015260643590811681036132bc57606082015260843580151581036132bc57608082015290565b9181601f840112156132bc578235916001600160401b0383116132bc57602083818601950101116132bc57565b90600182811c92168015613614575b60208310146135fe57565b634e487b7160e01b600052602260045260246000fd5b91607f16916135f3565b6040519060008260185491613632836135e4565b8083526020936001908181169081156136bd575060011461365e575b505061365c92500383613343565b565b9093915060186000527fb13d2d76d1f4b7be834882e410b3e3a8afaf69f83600ae24db354391d2378d2e936000915b8183106136a557505061365c9350820101388061364e565b8554888401850152948501948794509183019161368d565b91505061365c94925060ff191682840152151560051b820101388061364e565b60405190600082601f54916136f1836135e4565b8083526020936001908181169081156136bd575060011461371a57505061365c92500383613343565b90939150601f6000527fa03837a25210ee280c2113ff4b77ca23440b19d4866cca721c801278fd08d807936000915b81831061376157505061365c9350820101388061364e565b85548884018501529485019487945091830191613749565b90600c548210156134b457600c600052601f8260051c7fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c701921690565b90815180825260208080930193019160005b8281106137d6575050505090565b8351855293810193928101926001016137c8565b9060048210156137f75752565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b03600b5416330361382157565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b6001600160a01b0316801561388557600052600360205260406000205490565b60405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608490fd5b156138e357565b60405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152606490fd5b60005260026020526001600160a01b03604060002054166133d18115156138dc565b61397261396d8260005260026020526001600160a01b0360406000205416151590565b6138dc565b60005260046020526001600160a01b036040600020541690565b1561399357565b60405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201526c1c881bdc88185c1c1c9bdd9959609a1b6064820152608490fd5b90613a12939291613a02612e198433613a89565b613a0d838383613b51565b613e35565b15613a1957565b60405162461bcd60e51b815280613a3260048201613a36565b0390fd5b60809060208152603260208201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b60608201520190565b906001600160a01b038080613a9d84613928565b16931691838314938415613ad0575b508315613aba575b50505090565b613ac69192935061394a565b1614388080613ab4565b909350600052600560205260406000208260005260205260ff604060002054169238613aac565b15613afe57565b60405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201526437bbb732b960d91b6064820152608490fd5b90613b7790613b5f84613928565b6001600160a01b038481169390929183168414613af7565b818116938415613db45783613d085750600854856000526009602052604060002055613ba285614437565b828403613cd5575b506000908482526026602052604090818320548015908115613cbe575b5015613c595790613c05847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9493613bfe89613928565b1614613af7565b858252600460205284818320916001600160601b0360a01b928381541690558584526003602052808420600019815401905581845280842060018154019055878452600260205283209182541617905580a4565b815162461bcd60e51b815260206004820152603860248201527f41667465722075706772616465282920746f6b656e732063616e206e6f74206260448201527765207472616e7366657272656420666f722037206461797360401b6064820152608490fd5b62093a809150613cce9042613fbb565b1138613bc7565b613cde90613865565b60406000858152600660205281812083825260205286828220558681526007602052205538613baa565b848403613d16575b50613ba2565b613d1f90613865565b6000198101908111613d9e576000908682526020906007825260409182842054828103613d67575b508884528383812055868452600681528284209184525281205538613d10565b8785526006825283852083865282528385205488865260068352848620828752835280858720558552600782528385205538613d47565b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b3d15613e30573d90613e1682613364565b91613e246040519384613343565b82523d6000602084013e565b606090565b9290803b15613f2357613e86916020916001600160a01b039460405180958194829389630a85bd0160e11b9b8c865233600487015216602485015260448401526080606484015260848301906133f7565b03916000968791165af190829082613edb575b5050613ecd57613ea7613e05565b80519081613ec85760405162461bcd60e51b815280613a3260048201613a36565b602001fd5b6001600160e01b0319161490565b909192506020813d8211613f1b575b81613ef760209383613343565b8101031261048a5751906001600160e01b03198216820361030a5750903880613e99565b3d9150613eea565b50505050600190565b613f3581613865565b821015613f62576001600160a01b0316600052600660205260406000209060005260205260406000205490565b60405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b6064820152608490fd5b91908203918211613d9e57565b908160209103126132bc57516001600160a01b03811681036132bc5790565b91908201809211613d9e57565b6001600160401b0381116132dc5760051b60200190565b60209081818403126132bc578051906001600160401b0382116132bc57019180601f840112156132bc57825161404081613ff4565b9361404e6040519586613343565b818552838086019260051b8201019283116132bc578301905b828210614075575050505090565b81518152908301908301614067565b6000198114613d9e5760010190565b80518210156134b45760209160051b010190565b156140ae57565b60405162461bcd60e51b815260206004820152602160248201527f45786365656473206d6178206d696e747320706572207472616e73616374696f6044820152603760f91b6064820152608490fd5b1561410457565b60405162461bcd60e51b815260206004820152601c60248201527f45786365656473206d6178206d696e7473207065722077616c6c6574000000006044820152606490fd5b6002600a541461415a576002600a55565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b60058110156137f757806141b05750565b600181036141fd5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b6002810361424a5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b60031461425357565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b9060418151146000146142d1576142cd916020820151906060604084015193015160001a906142db565b9091565b5050600090600290565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831161435e5791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa156143515781516001600160a01b0381161561434b579190565b50600190565b50604051903d90823e3d90fd5b50505050600090600390565b1561437157565b60405162461bcd60e51b815260206004820152601760248201527f546f6b656e20494420646f6573206e6f742065786973740000000000000000006044820152606490fd5b156143bd57565b60405162461bcd60e51b81526020600482015260116024820152702737ba103a34329027232a1037bbb732b960791b6044820152606490fd5b9190916001600160401b0380809416911601918211613d9e57565b601554600160401b8110156132dc57612900816001614433930160155561347d565b9055565b600854600160401b8110156132dc5761290081600161443393016008556134ca565b60ff1660ff8114613d9e5760010190565b61448d6127d58260005260026020526001600160a01b0360406000205416151590565b6000818152602060268152604090818320546145c0576026906144c26144b286613928565b6001600160a01b031633146143b6565b8484526025815261458d8385208451906144db826132c1565b546001600160801b038082168084526001600160401b03608084901c168685015260c09290921c8784015286518981526020810192909252919033907f0c3fdcacbee530581c67c89a851ff8052aa367c589919df3056398ce311a237d90604090a27ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78487518a8152a161457482825116601354613fe7565b6013558787526025845286868120555116601254613fbb565b6012558484525242908220555b600960ff8216106145a9575050565b6145bb906145b683614411565b614459565b61459a565b606491519062461bcd60e51b82526004820152601060248201526f105b1c9958591e481d5c19dc9859195960821b6044820152fd5b81810292918115918404141715613d9e57565b94909695926001600160401b03906001600160801b0360a096946001600160a01b0360c08a019b16895216602088015216604086015262ffffff80921660608601521660808401521515910152565b91926060936001600160a01b03829316845260406020850152816040850152848401376000828201840152601f01601f1916010190565b6146ae8160005260026020526001600160a01b0360406000205416151590565b15614cc1576146bb6136dd565b5115614710576133d160206146d76146d16136dd565b93614e8e565b9260405193816146f086935180928680870191016133d4565b8201614704825180938680850191016133d4565b01038084520182613343565b908160005260266020526040600020541515600014614ca0576040516147358161330d565b600381526259657360e81b6020820152915b309260405191614756836132c1565b602a8352602083019260403685378051156134b457603084538051956001968710156134b4576078602183015360295b878111614c595750614c15576034614803916147d5956147a585614e8e565b906040519788937268747470733a2f2f626c617374722e78797a2f60681b602086015251809260338601906133d4565b8201602f60f81b60338201526147f482518093602087850191016133d4565b01036014810186520184613343565b61480c81614e8e565b9261481561361e565b9061481f83614e8e565b83600052602560205261483f6001600160801b0360406000205416614e8e565b93600052602560205261487260406000205461486c6001600160401b0391828160801c169060c01c6143f6565b16614e8e565b9260405196607b60f81b6020890152661134b2111d101160c91b60218901526148a581518092602060288c0191016133d4565b870161088b60f21b602882015268113730b6b2911d101160b91b602a8201526148d88251809360206033850191016133d4565b019761202360f01b60338a01526148f982518093602060358d0191016133d4565b61088b60f21b6035838b010152691134b6b0b3b2911d101160b11b6037838b0101526000986020549161492b836135e4565b92818116908115614beb5750600114614b83575b505050509260c1928592614b2b95614b30989961088b60f21b8152701132bc3a32b93730b62fbab936111d101160791b60028201526149888251809360206013850191016133d4565b019161088b60f21b60138401526e2261747472696275746573223a205b60881b6015840152607b60f81b60248401527f2274726169745f74797065223a202256616c7565206c6f636b656420287765696025840152620a488b60ea1b6045840152680113b30b63ab2911d160bd1b92836048820152614a118251809360206051850191016133d4565b01611f4b60f21b92836051830152607b60f81b60538301527f22646973706c61795f74797065223a202264617465222c00000000000000000060548301527f2274726169745f74797065223a202256616c7565206c6f636b656420756e7469606b830152621b088b60ea1b608b830152608e820152614a9a8251809360206097850191016133d4565b01906097820152607b60f81b60998201527f2274726169745f74797065223a20225570677261646564222c00000000000000609a82015269113b30b63ab2911d101160b11b60b3820152614af882518093602060bd850191016133d4565b01601160f91b60bd820152607d60f81b8060be830152605d60f81b60bf83015260c08201520360a1810184520182613343565b614d48565b6133d1603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000006020830152614b7381518092602086860191016133d4565b810103601d810184520182613343565b909192995060206000527fc97bfaf2f8ee708c303a06d134f5ecd8389ae0432af62dc132a24118292866bb906000915b848310614bd3575050509790970190960160410195828282614b3061493f565b8054848d018401604101526020909201918101614bb3565b60ff1916604193909501838101959095525050811515909102909101019650828282614b3061493f565b606460405162461bcd60e51b815260206004820152602060248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b90600f811660108110156134b45783518310156134b4576f181899199a1a9b1b9c1cb0b131b232b360811b901a8383016020015360041c908015613d9e5760001901614786565b604051614cac8161330d565b60028152614e6f60f01b602082015291614747565b60405162461bcd60e51b815260206004820152602760248201527f4552433732313a2055524920717565727920666f72206e6f6e6578697374656e6044820152663a103a37b5b2b760c91b6064820152608490fd5b90614d2082613364565b614d2d6040519182613343565b8281528092614d3e601f1991613364565b0190602036910137565b805115614e7a57604051614d5b816132c1565b604081527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208201527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f60408201528151600292838201809211613d9e576003918290046001600160fe1b0381168103613d9e57614ddd908594951b614d16565b936020850193829183518401925b838110614e295750505050510680600114614e1657600214614e0b575090565b603d90600019015390565b50603d9081600019820153600119015390565b85600491979293949701918251600190603f9082828260121c16880101518453828282600c1c16880101518385015382828260061c1688010151888501531685010151878201530195929190614deb565b50604051614e8781613328565b6000815290565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000080821015614fc3575b506d04ee2d6d415b85acef810000000080831015614fb4575b50662386f26fc1000080831015614fa5575b506305f5e10080831015614f96575b5061271080831015614f87575b506064821015614f77575b600a80921015614f6d575b600190816021614f25828701614d16565b95860101905b614f37575b5050505090565b600019019083906f181899199a1a9b1b9c1cb0b131b232b360811b8282061a835304918215614f6857919082614f2b565b614f30565b9160010191614f14565b9190606460029104910191614f09565b60049193920491019138614efe565b60089193920491019138614ef1565b60109193920491019138614ee2565b60209193920491019138614ed0565b604093508104915038614eb7565b90614fdb82613ff4565b614fe86040519182613343565b8281528092614d3e601f1991613ff4565b909194939262ffffff1692831561549d57600894615018858754613fe7565b601a5410615462576001600160801b038094169285840292858416938403613d9e57851692830361541d5761504c86614fd1565b9460006001600160401b0398894216915b8981106151b857505050506001600160a01b0316968791604097885191829160a0835260a0830161508e908a6137b6565b9460209a888c8601528c850152166060830152818403608083015233936150b4916133f7565b037f3c17cb77a104e5fa9f5e5427339add873947fe1b19af0177401348d86d2edece91a3601254906150e591613fe7565b601255156150f4575b50505050565b60005b81518110156151aa5761510a8183614093565b51857f0c3fdcacbee530581c67c89a851ff8052aa367c589919df3056398ce311a237d868051848152600088820152a27ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7848651838152a180600052602584526000858120556026845242856000205560005b600960ff82161061519857505061519390614084565b6150f7565b6151a5906145b683614411565b61517d565b5050505050388080806150ee565b6151c061552e565b806151cb838c614093565b528b8d6040908151906151dd826132c1565b8c8252602093848301911681528282019088825285600052602585528984600020935116906001600160401b0360801b905160801b16916001600160401b0360c01b905160c01b16911717905560155460108352816000205561523f83614411565b6001600160a01b0388169182156153dc576152796152738560005260026020526001600160a01b0360406000205416151590565b156154e2565b85548460005260098252826000205561529184614437565b61529a89613865565b8360005260068252826000208160005282528483600020558460005260078252826000205560268152816000205480159081156153c5575b50156153625790600284939261530561527361535d989760005260026020526001600160a01b0360406000205416151590565b836000526003815282600020600181540190558460005252600020816001600160601b0360a01b82541617905560007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4614084565b61505d565b608491519062461bcd60e51b82526004820152603860248201527f41667465722075706772616465282920746f6b656e732063616e206e6f74206260448201527765207472616e7366657272656420666f722037206461797360401b6064820152fd5b62093a8091506153d59042613fbb565b11386152d2565b606491519062461bcd60e51b825280600483015260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152fd5b60405162461bcd60e51b815260206004820152601460248201527f496e636f7272656374206d696e742070726963650000000000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601360248201527213585e081cdd5c1c1b1e48195e18d959591959606a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152601760248201527f5175616e746974792063616e6e6f74206265207a65726f0000000000000000006044820152606490fd5b156154e957565b60405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606490fd5b602254156155b95760225460001980820190828211613d9e5761555082613501565b90549060031b1c927ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1156155a35761559082613501565b909182549160031b1b1916905560225590565b634e487b7160e01b600052603160045260246000fd5b601654600181016016559056fea2646970667358221220c089ffbaba37ce3f2dcf4ca06afd5df0dd639082b30a88ace7b1bbdd5e5a449c64736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000b574b1c4233b61ecf8aa1fa6e6c694c4678ed4ee00000000000000000000000014fde5478709f0f8bd0ffb5de2030e0c618652d200000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000001869f000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000278d0000000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000068155a43676e00000000000000000000000000006726025532fbf0d8a9f71338e68373de96c0e1b9000000000000000000000000df808a2b1d20293cd37948fcfddb0f1132312c05000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e424c41535452204c6f7474657279000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a424c415354524c4f544f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006368747470733a2f2f617a7572652d706173736976652d71756f6b6b612d3339302e6d7970696e6174612e636c6f75642f697066732f516d5565343239737570516f684447354358323467706f4e41743865345a505966445832753474757365465042320000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _storageAddress (address): 0xb574B1C4233b61ECF8Aa1fa6E6C694C4678ED4ee
Arg [1] : _factoryAddress (address): 0x14FDE5478709f0F8Bd0fFb5DE2030e0c618652D2
Arg [2] : name_ (string): BLASTR Lottery
Arg [3] : symbol_ (string): BLASTRLOTO
Arg [4] : _maxSupply (uint256): 99999
Arg [5] : baseURI_ (string):
Arg [6] : _preRevealImageURI (string): https://azure-passive-quokka-390.mypinata.cloud/ipfs/QmUe429supQohDG5CX24gpoNAt8e4ZPYfDX2u4tuseFPB2
Arg [7] : _referrer (address): 0x0000000000000000000000000000000000000000
Arg [8] : _whitelistSigner (address): 0x0000000000000000000000000000000000000000
Arg [9] : _publicMintConfig (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [10] : _privateMintConfig (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [11] : _lotteryConfig (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [12] : gelatoOperator_ (address): 0x6726025532fBf0d8A9f71338e68373DE96C0e1B9
Arg [13] : gelatoRequester_ (address): 0xDf808A2B1d20293Cd37948FCFDDb0f1132312C05
Arg [14] : _lotteryProtocolFeePercentage (uint256): 10
-----Encoded View---------------
34 Constructor Arguments found :
Arg [0] : 000000000000000000000000b574b1c4233b61ecf8aa1fa6e6c694c4678ed4ee
Arg [1] : 00000000000000000000000014fde5478709f0f8bd0ffb5de2030e0c618652d2
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000300
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000340
Arg [4] : 000000000000000000000000000000000000000000000000000000000001869f
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000380
Arg [6] : 00000000000000000000000000000000000000000000000000000000000003a0
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [9] : 00000000000000000000000000000000000000000000000000b1a2bc2ec50000
Arg [10] : 0000000000000000000000000000000000000000000000000000000000278d00
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000032
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000032
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [17] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [18] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [19] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [20] : 00000000000000000000000000000000000000000000000068155a43676e0000
Arg [21] : 0000000000000000000000006726025532fbf0d8a9f71338e68373de96c0e1b9
Arg [22] : 000000000000000000000000df808a2b1d20293cd37948fcfddb0f1132312c05
Arg [23] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [24] : 000000000000000000000000000000000000000000000000000000000000000e
Arg [25] : 424c41535452204c6f7474657279000000000000000000000000000000000000
Arg [26] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [27] : 424c415354524c4f544f00000000000000000000000000000000000000000000
Arg [28] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [29] : 0000000000000000000000000000000000000000000000000000000000000063
Arg [30] : 68747470733a2f2f617a7572652d706173736976652d71756f6b6b612d333930
Arg [31] : 2e6d7970696e6174612e636c6f75642f697066732f516d556534323973757051
Arg [32] : 6f684447354358323467706f4e41743865345a50596644583275347475736546
Arg [33] : 5042320000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.