More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 10 from a total of 10 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Mint | 21838560 | 62 days ago | IN | 0.07233 ETH | 0.00069468 | ||||
Mint | 21765131 | 73 days ago | IN | 0.07233 ETH | 0.00221575 | ||||
Mint | 21765129 | 73 days ago | IN | 0.07233 ETH | 0.00232292 | ||||
Mint | 21736690 | 77 days ago | IN | 0.07233 ETH | 0.00052851 | ||||
Transfer From | 21731283 | 77 days ago | IN | 0 ETH | 0.00055865 | ||||
Transfer From | 21731232 | 77 days ago | IN | 0 ETH | 0.00048207 | ||||
Transfer From | 21731222 | 77 days ago | IN | 0 ETH | 0.00054798 | ||||
Mint | 21731176 | 77 days ago | IN | 0.07233 ETH | 0.00099289 | ||||
Mint | 21731174 | 77 days ago | IN | 0.07233 ETH | 0.00098613 | ||||
Mint | 21731172 | 77 days ago | IN | 0.07233 ETH | 0.00100438 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
TheMergeTree
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 1824 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.28; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "@openzeppelin/contracts/utils/Base64.sol"; import "./utils/StringUtils.sol"; import "./TheMergeTreesRenderer.sol"; import "./interfaces/ITreeSeeder.sol"; import "./interfaces/IToken.sol"; // _-_ // /~~ ~~\ // /~ ~\ // ( ) // \ _- -_ / // ^ \\ // ^ // | | // | | // | | // / \ /// @title TheMergeTree /// @author Anthony Graignic (@agraignic) contract TheMergeTree is IToken, ERC721Enumerable, Ownable { using Strings for uint256; error NotFounders(); error NotNFTOwner(); error SeederAlreadyLocked(); error BelowMinPrice(uint256 required, uint256 value); error NotColorPicker(); error UnapprovedContract(); error FoundersNotThanked(); error AboveMaxBalancePerAddress(); error StagHuntNotStarted(); error StagHuntStarted(); error NotEnoughCooperation(uint256 coop); error NotMatureTree(); error NothingToClaim(); ///@dev The internal token ID tracker uint256 private _nextTokenId; /// @notice Contract URI used by OpenSea to get contract details string private _contractUriIpfsHash = "bafkreie6rjitehhq73ycddh7q4bojntobi3xev4eloi4rqfnlhwuyj3tqe"; /// @dev Store init block.number for growth reference /// Because we knew. uint256 public immutable initBlockNumber; /// Creator address address payable public founders; /// The Merge Tree token seeder ITreeSeeder public seeder; /// Whether the seeder can be updated bool public isSeederLocked; uint8 internal constant MAX_SEGMENTS = 6; uint32 internal constant MAX_LENGTH = 227; // 138m for real trees mapping(uint256 => ITreeSeeder.Tree) public trees; /// @dev 32bits RGBA common colors selected by holders uint256 public colors; /// @notice Number for select color picker priviledge each % NFTs uint256 public constant COLOR_PICKER_SELECTOR = 12; /// @notice Has the stag hunt started after the open mint? bool public hasStagHuntStarted; /// @notice Initial supply before the stag hunt uint256 public constant BEFORE_HUNT_SUPPLY = 103; /// @notice Maximum number of NFTs owned per address before the stag hunt /// @dev initially a constant but immutable for testing purposes uint256 public immutable beforeHuntLimitPerAddress; /// @notice Mint price before the stag hunt uint256 public constant OPEN_MINT_PRICE = .07233 ether; /// @notice Price to kill a hare as a growth decline spiral protection // Correlated to Dunbar's number of 150 stable relationships uint256 public constant HARE_KILL_PRICE = .0004822 ether; /// @notice Control decline of the trees until a block number uint256 public declineUntil; /// @dev allow more fine control on growth uint256 public growthDivider; /// @dev allow more fine control on growth decline uint256 public growthDeclineBlocks; ///@dev Mapping between tokenId hare killers and their decline end block mapping(uint256 => uint256) public tokenIdsDeclineUntil; /// @notice Cooperation threshold for the stag hunt, 51.00% uint256 public constant COOPERATION_THRESHOLD = 5100; ///@notice Total number of pending claims ///@dev Used to calculate cooperation percentage efficiently uint256 public totalPendingClaim; /// @notice Number of pending NFT to claims for each address mapping(address => uint32) public pendingClaims; /// @notice List of approved contracts to be used as marker (=leaf) mapping(address => bool) public approvedComposableTokenForMarker; /// @dev Structure for an EIP-4883 token struct Token { address tokenAddress; uint256 tokenId; } /// @notice List of personalized markers mapping(uint256 => Token) private _markerTokenForTokenId; constructor( address _initialOwner, address payable _creator, uint256 _beforeHuntLimitPerAddress, ITreeSeeder _seeder ) ERC721("TheMergeTree", "MTREE") Ownable(_initialOwner) { founders = _creator; seeder = _seeder; initBlockNumber = block.number; beforeHuntLimitPerAddress = _beforeHuntLimitPerAddress; declineUntil = 0; growthDivider = 8292; growthDeclineBlocks = 211810; totalPendingClaim = 0; colors = (0x000000FF << TheMergeTreesRenderer.COLOR_LENGTH) | 0x0B6623FF; // Artist's proofs _mintTo(founders, _nextTokenId++); _mintTo(founders, _nextTokenId++); _mintTo(founders, _nextTokenId++); } /// @notice The IPFS URI of contract-level metadata. function contractURI() external view returns (string memory) { return string(abi.encodePacked("ipfs://", _contractUriIpfsHash)); } /// @notice Mint a Merge Tree to the minter before the stag hunt. /// @dev Call _mintTo with the to address. function mint() external payable override returns (uint256) { if (!hasStagHuntStarted && _nextTokenId < BEFORE_HUNT_SUPPLY) { if (balanceOf(msg.sender) >= beforeHuntLimitPerAddress) { revert AboveMaxBalancePerAddress(); } if (msg.value < OPEN_MINT_PRICE) { revert BelowMinPrice(OPEN_MINT_PRICE, msg.value); } if (_nextTokenId >= BEFORE_HUNT_SUPPLY - 1) { hasStagHuntStarted = true; } return _mintTo(msg.sender, _nextTokenId++); } else { revert StagHuntStarted(); } } /// @notice Claim Merge Tree(s) earned from previous stag hunt(s) /// @dev The mint loop could have been optimized, but others ERC721's impl made gas increase elsewhere so kept it simple function claim(uint32 quantity) external override { if ( pendingClaims[msg.sender] > 0 && quantity <= pendingClaims[msg.sender] ) { totalPendingClaim -= quantity; pendingClaims[msg.sender] = pendingClaims[msg.sender] - quantity; uint256 localNextTokenId = _nextTokenId; for (uint32 i = 0; i < quantity; i++) { _mintTo(msg.sender, localNextTokenId++); } _nextTokenId = localNextTokenId; } else { revert NothingToClaim(); } } /// @notice Mint the Merge Tree `tokenId` and transfer it `to` address function _mintTo(address to, uint256 tokenId) internal returns (uint256) { ITreeSeeder.Tree memory tree = trees[tokenId] = seeder.generateTree( tokenId, initBlockNumber ); _mint(to, tokenId); emit MergeTreeCreated(tokenId, tree); return tokenId; } /// @notice Clone a Merge Tree from a hare hunt function _clone( address to, uint256 hareTokenId, uint256 tokenId ) internal returns (uint256) { trees[tokenId] = seeder.cloneTree(initBlockNumber, trees[hareTokenId]); _mint(to, tokenId); emit MergeTreeCloned(hareTokenId, tokenId); return tokenId; } /// @dev Check token existence before rendering function _exists(uint256 tokenId) internal view returns (bool) { return _ownerOf(tokenId) != address(0); } /// @inheritdoc ERC721 function tokenURI( uint256 tokenId ) public view override returns (string memory) { if (!_exists(tokenId)) { revert ERC721NonexistentToken(tokenId); } ITreeSeeder.Tree memory tree = trees[tokenId]; string memory tokenName = string( abi.encodePacked("The Merge Tree #", tokenId.toString()) ); bool grow = declineUntil == 0 || block.number > declineUntil; string memory description; if (grow) { description = string(abi.encodePacked("A beautiful growing tree")); } else { description = string(abi.encodePacked("A declining tree")); } string memory image = Base64.encode( bytes(_generateSVGforTokenId(tokenId, tokenName, grow)) ); string memory boolTraits = string( abi.encodePacked( '},{"trait_type":"animated","value":', tree.animated ? "1" : "0", '},{"trait_type":"color_picker","value":', tokenId % COLOR_PICKER_SELECTOR == 0 ? "1" : "0" ) ); string memory dynamicTraits = string( abi.encodePacked( '},{"trait_type":"segments","value":', StringUtils.uint2str(tree.segments), '},{"trait_type":"stags","value":', StringUtils.uint2str(tree.stags), '},{"trait_type":"hares","value":', StringUtils.uint2str(tree.hares) ) ); string memory metadataTraits = string( abi.encodePacked( string( abi.encodePacked( '","attributes":[{"trait_type":"initLength","value":', StringUtils.uint2str(tree.initLength), '},{"trait_type":"diameter","value":', StringUtils.uint2str(tree.diameter), '},{"trait_type":"branches","value":', StringUtils.uint2str(tree.branches), '},{"trait_type":"angle","value":', StringUtils.uint2str(tree.angle), '},{"trait_type":"D","value":', StringUtils.uint2str(tree.d), '},{"trait_type":"delta","value":', StringUtils.uint2str(tree.delta) ) ), boolTraits, dynamicTraits ) ); return string( abi.encodePacked( "data:application/json;base64,", Base64.encode( bytes( abi.encodePacked( '{"name":"', tokenName, '","description":"', description, '","external_url":"https://themergetrees.xyz/trees/', tokenId.toString(), metadataTraits, '}],"image":"', "data:image/svg+xml;base64,", image, '"}' ) ) ) ) ); } /// @notice Generate whole SVG image from tokenId and tokenName for SVG title a11y /// @return full SVG file function _generateSVGforTokenId( uint256 tokenId, string memory tokenName, bool grow ) internal view returns (string memory) { string memory svg = string( abi.encodePacked( '<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>', tokenName, "</title>", _renderSky(grow), _renderTokenById(tokenId, grow), _renderGrass(grow), "</svg>" ) ); return svg; } /// @notice Render the sky behind the tree function _renderSky(bool grow) internal pure returns (string memory) { return string( abi.encodePacked( '<defs><linearGradient id="sky" gradientTransform="rotate(90)"><stop stop-color="#', grow ? 'bae6fd"/><stop stop-color="#f0f9ff' : 'fff7ed"/><stop stop-color="#fed7aa', '" offset="66%"/></linearGradient></defs><rect width="1024" height="1024" fill="url(#sky)"/>' ) ); } /// @notice Render the grass below the tree function _renderGrass(bool grow) internal pure returns (string memory) { return string( abi.encodePacked( '<rect width="1024" height="24" y="1000" fill="', grow ? "#2e8b57" : "#660000", '"/>' ) ); } /// @notice Render the holder's marker function _renderMarker( uint256 tokenId ) internal view returns (string memory markerRender) { markerRender = ""; Token memory markerToken = _markerTokenForTokenId[tokenId]; if (markerToken.tokenAddress != address(0)) { if ( ERC721(markerToken.tokenAddress).ownerOf(markerToken.tokenId) == ownerOf(tokenId) ) { markerRender = IERC4883(markerToken.tokenAddress) .renderTokenById(markerToken.tokenId); } } } /// @notice Render the fractal tree or text from tokenId /// Length is computed at each block /// @return Tree SVG (defs + groups + line), must be encapsulated in <svg> function _renderTokenById( uint256 tokenId, bool grow ) internal view returns (string memory) { ITreeSeeder.Tree memory tree = trees[tokenId]; if (tree.segments < 2) { return string( abi.encodePacked( '<text dominant-baseline="middle" text-anchor="middle" x="50%" y="50%" font-size="500%" fill="#', grow ? '006616">Spes messis in semine' : '660000">Erysichthon was here', "</text>" ) ); } uint256 blocksMined = block.number - initBlockNumber - tree.mintedSince; uint32 lengthVariation = uint32(blocksMined / growthDivider); if (!grow) { lengthVariation = uint32( (blocksMined * (declineUntil - block.number)) / (growthDivider * declineUntil) ); } uint32 lengthAfterBlocksMined = tree.initLength + lengthVariation; // uint32 max(lengthAfterBlocksMined, MAX_LENGTH) uint32 length = lengthAfterBlocksMined >= MAX_LENGTH ? MAX_LENGTH : lengthAfterBlocksMined; return TheMergeTreesRenderer.render( tree, length, colors, grow, _renderMarker(tokenId) ); } /// @inheritdoc IERC4883 function renderTokenById( uint256 tokenId ) external view override returns (string memory) { if (!_exists(tokenId)) { revert ERC721NonexistentToken(tokenId); } bool grow = declineUntil == 0 || block.number > declineUntil; return string( abi.encodePacked( '<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">', _renderTokenById(tokenId, grow), "</svg>" ) ); } /// @inheritdoc ERC721 function _update( address to, uint256 tokenId, address auth ) internal virtual override returns (address) { bool grow = declineUntil == 0 || block.number > declineUntil; if (grow) { trees[tokenId].segments = trees[tokenId].segments >= MAX_SEGMENTS ? MAX_SEGMENTS : trees[tokenId].segments + 1; } else { trees[tokenId].segments = trees[tokenId].segments < 2 ? 0 : trees[tokenId].segments - 1; } emit MetadataUpdate(tokenId); return super._update(to, tokenId, auth); } // The following functions are override as required by Solidity. /// @inheritdoc ERC721 function supportsInterface( bytes4 interfaceId ) public view override(ERC721Enumerable, IERC165) returns (bool) { return interfaceId == this.royaltyInfo.selector || interfaceId == type(IERC4883).interfaceId || // interfaceId == type(IERC4906).interfaceId || interfaceId == bytes4(0x49064906) || super.supportsInterface(interfaceId); } ///@notice Compute cooperation percentage e.g. 1755->17.55% function cooperation() public view returns (uint256) { uint256 count = 0; uint256 supply = totalSupply(); for (uint256 i = 0; i < supply; i++) { if ( trees[i].segments >= MAX_SEGMENTS && block.number > tokenIdsDeclineUntil[i] ) { count++; } } return (count * 10000) / (supply + totalPendingClaim); } //////////////////////////////////////////////////// ///// NFT owner's actions // //////////////////////////////////////////////////// /// @notice Trigger the stag hunt with your mature tree (segments at max). /// The stag hunt should have started and there should be enough mature trees to get the stag rewards (=cooperation). /// @dev all computations for cooperation is done here to avoid gas waste elsewhere e.g. in transfer. function huntStag(uint256 tokenId) external override { if (!hasStagHuntStarted) { revert StagHuntNotStarted(); } if (msg.sender != ownerOf(tokenId)) { revert NotNFTOwner(); } if (trees[tokenId].segments < MAX_SEGMENTS) { revert NotMatureTree(); } uint256 supply = totalSupply(); uint256[] memory matchingIds = new uint256[](supply); uint256 count = 0; for (uint256 i = 0; i < supply; i++) { // Check tree maturity while excluding hare killers if (trees[i].segments >= MAX_SEGMENTS) { if (block.number > tokenIdsDeclineUntil[i]) { matchingIds[count] = i; count++; } } // Reset animations if (tokenIdsDeclineUntil[i] > 0) { trees[i].animated = false; tokenIdsDeclineUntil[i] = 0; } } uint256 coop = (count * 10000) / (supply + totalPendingClaim); if (coop > COOPERATION_THRESHOLD) { uint256[] memory filteredMatureTreesTokenIds = new uint256[](count); totalPendingClaim = totalPendingClaim + count; declineUntil = 0; for (uint256 i = 0; i < count; i++) { filteredMatureTreesTokenIds[i] = matchingIds[i]; // Cut mature trees trees[matchingIds[i]].segments = 1; trees[matchingIds[i]].stags++; pendingClaims[ownerOf(matchingIds[i])]++; } emit BatchMetadataUpdate(0, _nextTokenId - 1); emit StagKilled(tokenId, filteredMatureTreesTokenIds); } else { revert NotEnoughCooperation(coop); } } /// @notice Hunt a hare with your tree. /// The stag hunt should have started and you should be the owner of the tree. /// This will give special rewards to your tree while cutting it. function huntHare(uint256 tokenId) external payable override { if (!hasStagHuntStarted) { revert StagHuntNotStarted(); } if (msg.sender != ownerOf(tokenId)) { revert NotNFTOwner(); } uint256 minPrice = (1 + trees[tokenId].hares) * HARE_KILL_PRICE * totalSupply(); if (msg.value < minPrice) { revert BelowMinPrice(minPrice, msg.value); } if (declineUntil == 0) { declineUntil = block.number + growthDeclineBlocks; } else { declineUntil = declineUntil + growthDeclineBlocks; } tokenIdsDeclineUntil[tokenId] = declineUntil; trees[tokenId].hares++; uint256 clonedTokenId = _clone(msg.sender, tokenId, _nextTokenId++); trees[tokenId].animated = true; tokenIdsDeclineUntil[clonedTokenId] = declineUntil; emit BatchMetadataUpdate(0, _nextTokenId - 1); emit HareKilled(tokenId); } /// @notice Burn a tree. function burn(uint256 tokenId) external override { if (msg.sender != ownerOf(tokenId)) { revert NotNFTOwner(); } _burn(tokenId); delete trees[tokenId]; delete _markerTokenForTokenId[tokenId]; delete tokenIdsDeclineUntil[tokenId]; emit MergeTreeBurned(tokenId); } /// @notice Toggle color bit if you are the owner of `tokenId`. This will impact all trees' colors. /// Trees share the same colors, each encoded in 32 bits to encourage beneficial cooperation. function toggleColor(uint256 tokenId) external override { if (msg.sender != ownerOf(tokenId)) { revert NotNFTOwner(); } if (tokenId % COLOR_PICKER_SELECTOR != 0) { revert NotColorPicker(); } colors = colors ^ (1 << (tokenId / COLOR_PICKER_SELECTOR)); } /// @notice Set the marker at the end of each apex branch. /// The marker must be composable SVG NFT (ERC-4883) from an approved contract. /// The caller must be the owner of the marker NFT and the Merge Tree NFT. function setMarker( uint256 tokenId, address markerTokenContract, uint256 markerTokenId ) external override { if (!approvedComposableTokenForMarker[markerTokenContract]) { revert UnapprovedContract(); } if ( msg.sender != ownerOf(tokenId) || msg.sender != ERC721(markerTokenContract).ownerOf(markerTokenId) ) { revert NotNFTOwner(); } _markerTokenForTokenId[tokenId] = Token( markerTokenContract, markerTokenId ); emit MetadataUpdate(tokenId); emit MergeTreeMarkerUpdated(tokenId); } //////////////////////////////////////////////////// ///// Royalties // //////////////////////////////////////////////////// /// @dev Royalties are the same for every token that's why we don't use OZ's impl. function royaltyInfo( uint256, uint256 amount ) public view returns (address, uint256) { // theMergeTreesDAO, 0% return (owner(), (amount * 0) / 10000); } //////////////////////////////////////////////////// ///// Owner // //////////////////////////////////////////////////// /// @dev Allow owner to update contract URI IPFS hash function setContractURIHash( string memory newContractUriIpfsHash ) external onlyOwner { _contractUriIpfsHash = newContractUriIpfsHash; } /// @notice Approve or not a token as a composable marker, only by owner /// Require that at least 3 tokens are sent as a gift to the Founders team. function setComposableMarkerApproval( address markerTokenContract, bool approved ) external override onlyOwner { if (ERC721(markerTokenContract).balanceOf(founders) < 3) { revert FoundersNotThanked(); } approvedComposableTokenForMarker[markerTokenContract] = approved; emit ComposableMarkerApproval(markerTokenContract, approved); } ///@notice Reset tree common colors to default, only by owner function resetColors() external override onlyOwner { colors = (0x000000FF << TheMergeTreesRenderer.COLOR_LENGTH) | 0x0B6623FF; } /// @notice Set growth divider, only by owner function setGrowthDivider( uint256 newGrowthDivider ) external override onlyOwner { growthDivider = newGrowthDivider; emit GrowthDividerUpdated(newGrowthDivider); } /// @notice Set growth decline blocks after hare kill, only by owner function setGrowthDeclineBlocks( uint256 newGrowthDeclineBlocks ) external override onlyOwner { growthDeclineBlocks = newGrowthDeclineBlocks; emit GrowthDeclineBlocksUpdated(newGrowthDeclineBlocks); } /// @notice Set the token seeder. /// @dev Only callable by the owner when not locked. function setSeeder(ITreeSeeder _seeder) external override onlyOwner { if (isSeederLocked) { revert SeederAlreadyLocked(); } seeder = _seeder; emit SeederUpdated(_seeder); } /// @notice Lock the seeder. /// @dev This cannot be reversed and is only callable by the owner when not locked. function lockSeeder() external override onlyOwner { if (isSeederLocked) { revert SeederAlreadyLocked(); } isSeederLocked = true; emit SeederLocked(); } //////////////////////////////////////////////////// ///// Founders // //////////////////////////////////////////////////// function withdraw() external { if (msg.sender != founders && msg.sender != owner()) { revert NotFounders(); } (bool success, ) = founders.call{value: address(this).balance}(""); require(success, "Transfer failed."); } /// @notice Allow founders to set its address function setFounders(address payable newFounders) external override { if (msg.sender != founders) { revert NotFounders(); } founders = newFounders; emit FoundersUpdated(newFounders); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC6093.sol) pragma solidity ^0.8.20; /** * @dev Standard ERC-20 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens. */ interface IERC20Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC20InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC20InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. * @param spender Address that may be allowed to operate on tokens without being their owner. * @param allowance Amount of tokens a `spender` is allowed to operate with. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC20InvalidApprover(address approver); /** * @dev Indicates a failure with the `spender` to be approved. Used in approvals. * @param spender Address that may be allowed to operate on tokens without being their owner. */ error ERC20InvalidSpender(address spender); } /** * @dev Standard ERC-721 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens. */ interface IERC721Errors { /** * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20. * Used in balance queries. * @param owner Address of the current owner of a token. */ error ERC721InvalidOwner(address owner); /** * @dev Indicates a `tokenId` whose `owner` is the zero address. * @param tokenId Identifier number of a token. */ error ERC721NonexistentToken(uint256 tokenId); /** * @dev Indicates an error related to the ownership over a particular token. Used in transfers. * @param sender Address whose tokens are being transferred. * @param tokenId Identifier number of a token. * @param owner Address of the current owner of a token. */ error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC721InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC721InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param tokenId Identifier number of a token. */ error ERC721InsufficientApproval(address operator, uint256 tokenId); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC721InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC721InvalidOperator(address operator); } /** * @dev Standard ERC-1155 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens. */ interface IERC1155Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. * @param tokenId Identifier number of a token. */ error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC1155InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC1155InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param owner Address of the current owner of a token. */ error ERC1155MissingApprovalForAll(address operator, address owner); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC1155InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC1155InvalidOperator(address operator); /** * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. * Used in batch transfers. * @param idsLength Length of the array of token identifiers * @param valuesLength Length of the array of token amounts */ error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC4906.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; import {IERC721} from "./IERC721.sol"; /// @title ERC-721 Metadata Update Extension interface IERC4906 is IERC165, IERC721 { /// @dev This event emits when the metadata of a token is changed. /// So that the third-party platforms such as NFT market could /// timely update the images and related attributes of the NFT. event MetadataUpdate(uint256 _tokenId); /// @dev This event emits when the metadata of a range of tokens is changed. /// So that the third-party platforms such as NFT market could /// timely update the images and related attributes of the NFTs. event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721.sol) pragma solidity ^0.8.20; import {IERC721} from "../token/ERC721/IERC721.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/ERC721.sol) pragma solidity ^0.8.20; import {IERC721} from "./IERC721.sol"; import {IERC721Metadata} from "./extensions/IERC721Metadata.sol"; import {ERC721Utils} from "./utils/ERC721Utils.sol"; import {Context} from "../../utils/Context.sol"; import {Strings} from "../../utils/Strings.sol"; import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol"; import {IERC721Errors} from "../../interfaces/draft-IERC6093.sol"; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC-721] Non-Fungible Token Standard, including * the Metadata extension, but not including the Enumerable extension, which is available separately as * {ERC721Enumerable}. */ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Errors { using Strings for uint256; // Token name string private _name; // Token symbol string private _symbol; mapping(uint256 tokenId => address) private _owners; mapping(address owner => uint256) private _balances; mapping(uint256 tokenId => address) private _tokenApprovals; mapping(address owner => mapping(address operator => 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 returns (uint256) { if (owner == address(0)) { revert ERC721InvalidOwner(address(0)); } return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual returns (address) { return _requireOwned(tokenId); } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual returns (string memory) { _requireOwned(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string.concat(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 { _approve(to, tokenId, _msgSender()); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual returns (address) { _requireOwned(tokenId); return _getApproved(tokenId); } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom(address from, address to, uint256 tokenId) public virtual { if (to == address(0)) { revert ERC721InvalidReceiver(address(0)); } // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. address previousOwner = _update(to, tokenId, _msgSender()); if (previousOwner != from) { revert ERC721IncorrectOwner(from, tokenId, previousOwner); } } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom(address from, address to, uint256 tokenId) public { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual { transferFrom(from, to, tokenId); ERC721Utils.checkOnERC721Received(_msgSender(), from, to, tokenId, data); } /** * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist * * IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the * core ERC-721 logic MUST be matched with the use of {_increaseBalance} to keep balances * consistent with ownership. The invariant to preserve is 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`. */ function _ownerOf(uint256 tokenId) internal view virtual returns (address) { return _owners[tokenId]; } /** * @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted. */ function _getApproved(uint256 tokenId) internal view virtual returns (address) { return _tokenApprovals[tokenId]; } /** * @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in * particular (ignoring whether it is owned by `owner`). * * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this * assumption. */ function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) { return spender != address(0) && (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender); } /** * @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner. * Reverts if: * - `spender` does not have approval from `owner` for `tokenId`. * - `spender` does not have approval to manage all of `owner`'s assets. * * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this * assumption. */ function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual { if (!_isAuthorized(owner, spender, tokenId)) { if (owner == address(0)) { revert ERC721NonexistentToken(tokenId); } else { revert ERC721InsufficientApproval(spender, tokenId); } } } /** * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override. * * NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that * a uint256 would ever overflow from increments when these increments are bounded to uint128 values. * * WARNING: Increasing an account's balance using this function tends to be paired with an override of the * {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership * remain consistent with one another. */ function _increaseBalance(address account, uint128 value) internal virtual { unchecked { _balances[account] += value; } } /** * @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. * * The `auth` argument is optional. If the value passed is non 0, then this function will check that * `auth` is either the owner of the token, or approved to operate on the token (by the owner). * * Emits a {Transfer} event. * * NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}. */ function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) { address from = _ownerOf(tokenId); // Perform (optional) operator check if (auth != address(0)) { _checkAuthorized(from, auth, tokenId); } // Execute the update if (from != address(0)) { // Clear approval. No need to re-authorize or emit the Approval event _approve(address(0), tokenId, address(0), false); unchecked { _balances[from] -= 1; } } if (to != address(0)) { unchecked { _balances[to] += 1; } } _owners[tokenId] = to; emit Transfer(from, to, tokenId); return from; } /** * @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 { if (to == address(0)) { revert ERC721InvalidReceiver(address(0)); } address previousOwner = _update(to, tokenId, address(0)); if (previousOwner != address(0)) { revert ERC721InvalidSender(address(0)); } } /** * @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance. * * 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 { _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); ERC721Utils.checkOnERC721Received(_msgSender(), address(0), to, tokenId, data); } /** * @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 { address previousOwner = _update(address(0), tokenId, address(0)); if (previousOwner == address(0)) { revert ERC721NonexistentToken(tokenId); } } /** * @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 { if (to == address(0)) { revert ERC721InvalidReceiver(address(0)); } address previousOwner = _update(to, tokenId, address(0)); if (previousOwner == address(0)) { revert ERC721NonexistentToken(tokenId); } else if (previousOwner != from) { revert ERC721IncorrectOwner(from, tokenId, previousOwner); } } /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients * are aware of the ERC-721 standard 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 like {safeTransferFrom} in the sense that it invokes * {IERC721Receiver-onERC721Received} on the receiver, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `tokenId` token must exist and be owned by `from`. * - `to` cannot be the zero address. * - `from` cannot be the zero address. * - 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) internal { _safeTransfer(from, to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual { _transfer(from, to, tokenId); ERC721Utils.checkOnERC721Received(_msgSender(), from, to, tokenId, data); } /** * @dev Approve `to` to operate on `tokenId` * * The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is * either the owner of the token, or approved to operate on all tokens held by this owner. * * Emits an {Approval} event. * * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. */ function _approve(address to, uint256 tokenId, address auth) internal { _approve(to, tokenId, auth, true); } /** * @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not * emitted in the context of transfers. */ function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual { // Avoid reading the owner unless necessary if (emitEvent || auth != address(0)) { address owner = _requireOwned(tokenId); // We do not use _isAuthorized because single-token approvals should not be able to call approve if (auth != address(0) && owner != auth && !isApprovedForAll(owner, auth)) { revert ERC721InvalidApprover(auth); } if (emitEvent) { emit Approval(owner, to, tokenId); } } _tokenApprovals[tokenId] = to; } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Requirements: * - operator can't be the address zero. * * Emits an {ApprovalForAll} event. */ function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { if (operator == address(0)) { revert ERC721InvalidOperator(operator); } _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned). * Returns the owner. * * Overrides to ownership logic should be done to {_ownerOf}. */ function _requireOwned(uint256 tokenId) internal view returns (address) { address owner = _ownerOf(tokenId); if (owner == address(0)) { revert ERC721NonexistentToken(tokenId); } return owner; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/extensions/ERC721Enumerable.sol) pragma solidity ^0.8.20; import {ERC721} from "../ERC721.sol"; import {IERC721Enumerable} from "./IERC721Enumerable.sol"; import {IERC165} from "../../../utils/introspection/ERC165.sol"; /** * @dev This implements an optional extension of {ERC721} defined in the ERC that adds enumerability * of all the token ids in the contract as well as all token ids owned by each account. * * CAUTION: {ERC721} extensions that implement custom `balanceOf` logic, such as {ERC721Consecutive}, * interfere with enumerability and should not be used together with {ERC721Enumerable}. */ abstract contract ERC721Enumerable is ERC721, IERC721Enumerable { mapping(address owner => mapping(uint256 index => uint256)) private _ownedTokens; mapping(uint256 tokenId => uint256) private _ownedTokensIndex; uint256[] private _allTokens; mapping(uint256 tokenId => uint256) private _allTokensIndex; /** * @dev An `owner`'s token query was out of bounds for `index`. * * NOTE: The owner being `address(0)` indicates a global out of bounds index. */ error ERC721OutOfBoundsIndex(address owner, uint256 index); /** * @dev Batch mint is not allowed. */ error ERC721EnumerableForbiddenBatchMint(); /** * @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 returns (uint256) { if (index >= balanceOf(owner)) { revert ERC721OutOfBoundsIndex(owner, index); } return _ownedTokens[owner][index]; } /** * @dev See {IERC721Enumerable-totalSupply}. */ function totalSupply() public view virtual returns (uint256) { return _allTokens.length; } /** * @dev See {IERC721Enumerable-tokenByIndex}. */ function tokenByIndex(uint256 index) public view virtual returns (uint256) { if (index >= totalSupply()) { revert ERC721OutOfBoundsIndex(address(0), index); } return _allTokens[index]; } /** * @dev See {ERC721-_update}. */ function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) { address previousOwner = super._update(to, tokenId, auth); if (previousOwner == address(0)) { _addTokenToAllTokensEnumeration(tokenId); } else if (previousOwner != to) { _removeTokenFromOwnerEnumeration(previousOwner, tokenId); } if (to == address(0)) { _removeTokenFromAllTokensEnumeration(tokenId); } else if (previousOwner != to) { _addTokenToOwnerEnumeration(to, tokenId); } return previousOwner; } /** * @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 = balanceOf(to) - 1; _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 = balanceOf(from); uint256 tokenIndex = _ownedTokensIndex[tokenId]; mapping(uint256 index => uint256) storage _ownedTokensByOwner = _ownedTokens[from]; // When the token to delete is the last token, the swap operation is unnecessary if (tokenIndex != lastTokenIndex) { uint256 lastTokenId = _ownedTokensByOwner[lastTokenIndex]; _ownedTokensByOwner[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 _ownedTokensByOwner[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(); } /** * See {ERC721-_increaseBalance}. We need that to account tokens that were minted in batch */ function _increaseBalance(address account, uint128 amount) internal virtual override { if (amount > 0) { revert ERC721EnumerableForbiddenBatchMint(); } super._increaseBalance(account, amount); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Enumerable.sol) pragma solidity ^0.8.20; import {IERC721} from "../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 (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.20; import {IERC721} from "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC-721 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 ERC-721 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 ERC-721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the address zero. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.20; /** * @title ERC-721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC-721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be * reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/utils/ERC721Utils.sol) pragma solidity ^0.8.20; import {IERC721Receiver} from "../IERC721Receiver.sol"; import {IERC721Errors} from "../../../interfaces/draft-IERC6093.sol"; /** * @dev Library that provide common ERC-721 utility functions. * * See https://eips.ethereum.org/EIPS/eip-721[ERC-721]. * * _Available since v5.1._ */ library ERC721Utils { /** * @dev Performs an acceptance check for the provided `operator` by calling {IERC721-onERC721Received} * on the `to` address. The `operator` is generally the address that initiated the token transfer (i.e. `msg.sender`). * * The acceptance call is not executed and treated as a no-op if the target address doesn't contain code (i.e. an EOA). * Otherwise, the recipient must implement {IERC721Receiver-onERC721Received} and return the acceptance magic value to accept * the transfer. */ function checkOnERC721Received( address operator, address from, address to, uint256 tokenId, bytes memory data ) internal { if (to.code.length > 0) { try IERC721Receiver(to).onERC721Received(operator, from, tokenId, data) returns (bytes4 retval) { if (retval != IERC721Receiver.onERC721Received.selector) { // Token rejected revert IERC721Errors.ERC721InvalidReceiver(to); } } catch (bytes memory reason) { if (reason.length == 0) { // non-IERC721Receiver implementer revert IERC721Errors.ERC721InvalidReceiver(to); } else { assembly ("memory-safe") { revert(add(32, reason), mload(reason)) } } } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Base64.sol) pragma solidity ^0.8.20; /** * @dev Provides a set of functions to operate with Base64 strings. */ library Base64 { /** * @dev Base64 Encoding/Decoding Table * See sections 4 and 5 of https://datatracker.ietf.org/doc/html/rfc4648 */ string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; string internal constant _TABLE_URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; /** * @dev Converts a `bytes` to its Bytes64 `string` representation. */ function encode(bytes memory data) internal pure returns (string memory) { return _encode(data, _TABLE, true); } /** * @dev Converts a `bytes` to its Bytes64Url `string` representation. * Output is not padded with `=` as specified in https://www.rfc-editor.org/rfc/rfc4648[rfc4648]. */ function encodeURL(bytes memory data) internal pure returns (string memory) { return _encode(data, _TABLE_URL, false); } /** * @dev Internal table-agnostic conversion */ function _encode(bytes memory data, string memory table, bool withPadding) private 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 ""; // If padding is enabled, the final length should be `bytes` data length divided by 3 rounded up and then // multiplied by 4 so that it leaves room for padding the last chunk // - `data.length + 2` -> Prepare for division rounding up // - `/ 3` -> Number of 3-bytes chunks (rounded up) // - `4 *` -> 4 characters for each chunk // This is equivalent to: 4 * Math.ceil(data.length / 3) // // If padding is disabled, the final length should be `bytes` data length multiplied by 4/3 rounded up as // opposed to when padding is required to fill the last chunk. // - `4 * data.length` -> 4 characters for each chunk // - ` + 2` -> Prepare for division rounding up // - `/ 3` -> Number of 3-bytes chunks (rounded up) // This is equivalent to: Math.ceil((4 * data.length) / 3) uint256 resultLength = withPadding ? 4 * ((data.length + 2) / 3) : (4 * data.length + 2) / 3; string memory result = new string(resultLength); assembly ("memory-safe") { // Prepare the lookup table (skip the first "length" byte) let tablePtr := add(table, 1) // Prepare result pointer, jump over length let resultPtr := add(result, 0x20) let dataPtr := data let endPtr := add(data, mload(data)) // In some cases, the last iteration will read bytes after the end of the data. We cache the value, and // set it to zero to make sure no dirty bytes are read in that section. let afterPtr := add(endPtr, 0x20) let afterCache := mload(afterPtr) mstore(afterPtr, 0x00) // Run over the input, 3 bytes at a time for { } lt(dataPtr, endPtr) { } { // Advance 3 bytes dataPtr := add(dataPtr, 3) let input := mload(dataPtr) // To write each character, shift the 3 byte (24 bits) chunk // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) // and apply logical AND with 0x3F to bitmask the least significant 6 bits. // Use this as an index into the lookup table, mload an entire word // so the desired character is in the least significant byte, and // mstore8 this least significant byte into the result and continue. 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 } // Reset the value that was cached mstore(afterPtr, afterCache) if withPadding { // 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 (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * 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[ERC section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/math/Math.sol) pragma solidity ^0.8.20; import {Panic} from "../Panic.sol"; import {SafeCast} from "./SafeCast.sol"; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an success flag (no overflow). */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow). */ function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow). */ function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a success flag (no division by zero). */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero). */ function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant. * * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone. * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute * one branch when needed, making this function more expensive. */ function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) { unchecked { // branchless ternary works because: // b ^ (a ^ b) == a // b ^ 0 == b return b ^ ((a ^ b) * SafeCast.toUint(condition)); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return ternary(a > b, a, b); } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return ternary(a < b, a, b); } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. Panic.panic(Panic.DIVISION_BY_ZERO); } // The following calculation ensures accurate ceiling division without overflow. // Since a is non-zero, (a - 1) / b will not overflow. // The largest possible result occurs when (a - 1) / b is type(uint256).max, // but the largest value we can obtain is type(uint256).max - 1, which happens // when a = type(uint256).max and b = 1. unchecked { return SafeCast.toUint(a > 0) * ((a - 1) / b + 1); } } /** * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * * 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²⁵⁶ and mod 2²⁵⁶ - 1, then use // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2²⁵⁶ + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0. if (denominator <= prod1) { Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_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. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2²⁵⁶ / 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²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv ≡ 1 mod 2⁴. 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⁸ inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶ inverse *= 2 - denominator * inverse; // inverse mod 2³² inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴ inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸ inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶ // 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²⁵⁶. Since the preconditions guarantee that the outcome is // less than 2²⁵⁶, 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; } } /** * @dev 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) { return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0); } /** * @dev Calculate the modular multiplicative inverse of a number in Z/nZ. * * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0. * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible. * * If the input value is not inversible, 0 is returned. * * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}. */ function invMod(uint256 a, uint256 n) internal pure returns (uint256) { unchecked { if (n == 0) return 0; // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version) // Used to compute integers x and y such that: ax + ny = gcd(a, n). // When the gcd is 1, then the inverse of a modulo n exists and it's x. // ax + ny = 1 // ax = 1 + (-y)n // ax ≡ 1 (mod n) # x is the inverse of a modulo n // If the remainder is 0 the gcd is n right away. uint256 remainder = a % n; uint256 gcd = n; // Therefore the initial coefficients are: // ax + ny = gcd(a, n) = n // 0a + 1n = n int256 x = 0; int256 y = 1; while (remainder != 0) { uint256 quotient = gcd / remainder; (gcd, remainder) = ( // The old remainder is the next gcd to try. remainder, // Compute the next remainder. // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd // where gcd is at most n (capped to type(uint256).max) gcd - remainder * quotient ); (x, y) = ( // Increment the coefficient of a. y, // Decrement the coefficient of n. // Can overflow, but the result is casted to uint256 so that the // next value of y is "wrapped around" to a value between 0 and n - 1. x - y * int256(quotient) ); } if (gcd != 1) return 0; // No inverse exists. return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative. } } /** * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`. * * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that * `a**(p-2)` is the modular multiplicative inverse of a in Fp. * * NOTE: this function does NOT check that `p` is a prime greater than `2`. */ function invModPrime(uint256 a, uint256 p) internal view returns (uint256) { unchecked { return Math.modExp(a, p - 2, p); } } /** * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m) * * Requirements: * - modulus can't be zero * - underlying staticcall to precompile must succeed * * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make * sure the chain you're using it on supports the precompiled contract for modular exponentiation * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, * the underlying function will succeed given the lack of a revert, but the result may be incorrectly * interpreted as 0. */ function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) { (bool success, uint256 result) = tryModExp(b, e, m); if (!success) { Panic.panic(Panic.DIVISION_BY_ZERO); } return result; } /** * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m). * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying * to operate modulo 0 or if the underlying precompile reverted. * * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack * of a revert, but the result may be incorrectly interpreted as 0. */ function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) { if (m == 0) return (false, 0); assembly ("memory-safe") { let ptr := mload(0x40) // | Offset | Content | Content (Hex) | // |-----------|------------|--------------------------------------------------------------------| // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x60:0x7f | value of b | 0x<.............................................................b> | // | 0x80:0x9f | value of e | 0x<.............................................................e> | // | 0xa0:0xbf | value of m | 0x<.............................................................m> | mstore(ptr, 0x20) mstore(add(ptr, 0x20), 0x20) mstore(add(ptr, 0x40), 0x20) mstore(add(ptr, 0x60), b) mstore(add(ptr, 0x80), e) mstore(add(ptr, 0xa0), m) // Given the result < m, it's guaranteed to fit in 32 bytes, // so we can use the memory scratch space located at offset 0. success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20) result := mload(0x00) } } /** * @dev Variant of {modExp} that supports inputs of arbitrary length. */ function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) { (bool success, bytes memory result) = tryModExp(b, e, m); if (!success) { Panic.panic(Panic.DIVISION_BY_ZERO); } return result; } /** * @dev Variant of {tryModExp} that supports inputs of arbitrary length. */ function tryModExp( bytes memory b, bytes memory e, bytes memory m ) internal view returns (bool success, bytes memory result) { if (_zeroBytes(m)) return (false, new bytes(0)); uint256 mLen = m.length; // Encode call args in result and move the free memory pointer result = abi.encodePacked(b.length, e.length, mLen, b, e, m); assembly ("memory-safe") { let dataPtr := add(result, 0x20) // Write result on top of args to avoid allocating extra memory. success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen) // Overwrite the length. // result.length > returndatasize() is guaranteed because returndatasize() == m.length mstore(result, mLen) // Set the memory pointer after the returned data. mstore(0x40, add(dataPtr, mLen)) } } /** * @dev Returns whether the provided byte array is zero. */ function _zeroBytes(bytes memory byteArray) private pure returns (bool) { for (uint256 i = 0; i < byteArray.length; ++i) { if (byteArray[i] != 0) { return false; } } return true; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * This method is based on Newton's method for computing square roots; the algorithm is restricted to only * using integer operations. */ function sqrt(uint256 a) internal pure returns (uint256) { unchecked { // Take care of easy edge cases when a == 0 or a == 1 if (a <= 1) { return a; } // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between // the current value as `ε_n = | x_n - sqrt(a) |`. // // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is // bigger than any uint256. // // By noticing that // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)` // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar // to the msb function. uint256 aa = a; uint256 xn = 1; if (aa >= (1 << 128)) { aa >>= 128; xn <<= 64; } if (aa >= (1 << 64)) { aa >>= 64; xn <<= 32; } if (aa >= (1 << 32)) { aa >>= 32; xn <<= 16; } if (aa >= (1 << 16)) { aa >>= 16; xn <<= 8; } if (aa >= (1 << 8)) { aa >>= 8; xn <<= 4; } if (aa >= (1 << 4)) { aa >>= 4; xn <<= 2; } if (aa >= (1 << 2)) { xn <<= 1; } // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1). // // We can refine our estimation by noticing that the middle of that interval minimizes the error. // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2). // This is going to be our x_0 (and ε_0) xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2) // From here, Newton's method give us: // x_{n+1} = (x_n + a / x_n) / 2 // // One should note that: // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a // = ((x_n² + a) / (2 * x_n))² - a // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²) // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²) // = (x_n² - a)² / (2 * x_n)² // = ((x_n² - a) / (2 * x_n))² // ≥ 0 // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n // // This gives us the proof of quadratic convergence of the sequence: // ε_{n+1} = | x_{n+1} - sqrt(a) | // = | (x_n + a / x_n) / 2 - sqrt(a) | // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) | // = | (x_n - sqrt(a))² / (2 * x_n) | // = | ε_n² / (2 * x_n) | // = ε_n² / | (2 * x_n) | // // For the first iteration, we have a special case where x_0 is known: // ε_1 = ε_0² / | (2 * x_0) | // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2))) // ≤ 2**(2*e-4) / (3 * 2**(e-1)) // ≤ 2**(e-3) / 3 // ≤ 2**(e-3-log2(3)) // ≤ 2**(e-4.5) // // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n: // ε_{n+1} = ε_n² / | (2 * x_n) | // ≤ (2**(e-k))² / (2 * 2**(e-1)) // ≤ 2**(2*e-2*k) / 2**e // ≤ 2**(e-2*k) xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5 xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9 xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18 xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36 xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72 // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either // sqrt(a) or sqrt(a) + 1. return xn - SafeCast.toUint(xn > a / xn); } } /** * @dev 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; uint256 exp; unchecked { exp = 128 * SafeCast.toUint(value > (1 << 128) - 1); value >>= exp; result += exp; exp = 64 * SafeCast.toUint(value > (1 << 64) - 1); value >>= exp; result += exp; exp = 32 * SafeCast.toUint(value > (1 << 32) - 1); value >>= exp; result += exp; exp = 16 * SafeCast.toUint(value > (1 << 16) - 1); value >>= exp; result += exp; exp = 8 * SafeCast.toUint(value > (1 << 8) - 1); value >>= exp; result += exp; exp = 4 * SafeCast.toUint(value > (1 << 4) - 1); value >>= exp; result += exp; exp = 2 * SafeCast.toUint(value > (1 << 2) - 1); value >>= exp; result += exp; result += SafeCast.toUint(value > 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; uint256 isGt; unchecked { isGt = SafeCast.toUint(value > (1 << 128) - 1); value >>= isGt * 128; result += isGt * 16; isGt = SafeCast.toUint(value > (1 << 64) - 1); value >>= isGt * 64; result += isGt * 8; isGt = SafeCast.toUint(value > (1 << 32) - 1); value >>= isGt * 32; result += isGt * 4; isGt = SafeCast.toUint(value > (1 << 16) - 1); value >>= isGt * 16; result += isGt * 2; result += SafeCast.toUint(value > (1 << 8) - 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.20; /** * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeCast { /** * @dev Value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); /** * @dev An int value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedIntToUint(int256 value); /** * @dev Value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); /** * @dev An uint value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedUintToInt(uint256 value); /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits */ function toUint248(uint256 value) internal pure returns (uint248) { if (value > type(uint248).max) { revert SafeCastOverflowedUintDowncast(248, value); } return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits */ function toUint240(uint256 value) internal pure returns (uint240) { if (value > type(uint240).max) { revert SafeCastOverflowedUintDowncast(240, value); } return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits */ function toUint232(uint256 value) internal pure returns (uint232) { if (value > type(uint232).max) { revert SafeCastOverflowedUintDowncast(232, value); } return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits */ function toUint224(uint256 value) internal pure returns (uint224) { if (value > type(uint224).max) { revert SafeCastOverflowedUintDowncast(224, value); } return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits */ function toUint216(uint256 value) internal pure returns (uint216) { if (value > type(uint216).max) { revert SafeCastOverflowedUintDowncast(216, value); } return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits */ function toUint208(uint256 value) internal pure returns (uint208) { if (value > type(uint208).max) { revert SafeCastOverflowedUintDowncast(208, value); } return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits */ function toUint200(uint256 value) internal pure returns (uint200) { if (value > type(uint200).max) { revert SafeCastOverflowedUintDowncast(200, value); } return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits */ function toUint192(uint256 value) internal pure returns (uint192) { if (value > type(uint192).max) { revert SafeCastOverflowedUintDowncast(192, value); } return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits */ function toUint184(uint256 value) internal pure returns (uint184) { if (value > type(uint184).max) { revert SafeCastOverflowedUintDowncast(184, value); } return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits */ function toUint176(uint256 value) internal pure returns (uint176) { if (value > type(uint176).max) { revert SafeCastOverflowedUintDowncast(176, value); } return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits */ function toUint168(uint256 value) internal pure returns (uint168) { if (value > type(uint168).max) { revert SafeCastOverflowedUintDowncast(168, value); } return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits */ function toUint160(uint256 value) internal pure returns (uint160) { if (value > type(uint160).max) { revert SafeCastOverflowedUintDowncast(160, value); } return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits */ function toUint152(uint256 value) internal pure returns (uint152) { if (value > type(uint152).max) { revert SafeCastOverflowedUintDowncast(152, value); } return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits */ function toUint144(uint256 value) internal pure returns (uint144) { if (value > type(uint144).max) { revert SafeCastOverflowedUintDowncast(144, value); } return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits */ function toUint136(uint256 value) internal pure returns (uint136) { if (value > type(uint136).max) { revert SafeCastOverflowedUintDowncast(136, value); } return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { if (value > type(uint128).max) { revert SafeCastOverflowedUintDowncast(128, value); } return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits */ function toUint120(uint256 value) internal pure returns (uint120) { if (value > type(uint120).max) { revert SafeCastOverflowedUintDowncast(120, value); } return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits */ function toUint112(uint256 value) internal pure returns (uint112) { if (value > type(uint112).max) { revert SafeCastOverflowedUintDowncast(112, value); } return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits */ function toUint104(uint256 value) internal pure returns (uint104) { if (value > type(uint104).max) { revert SafeCastOverflowedUintDowncast(104, value); } return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits */ function toUint96(uint256 value) internal pure returns (uint96) { if (value > type(uint96).max) { revert SafeCastOverflowedUintDowncast(96, value); } return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits */ function toUint88(uint256 value) internal pure returns (uint88) { if (value > type(uint88).max) { revert SafeCastOverflowedUintDowncast(88, value); } return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits */ function toUint80(uint256 value) internal pure returns (uint80) { if (value > type(uint80).max) { revert SafeCastOverflowedUintDowncast(80, value); } return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits */ function toUint72(uint256 value) internal pure returns (uint72) { if (value > type(uint72).max) { revert SafeCastOverflowedUintDowncast(72, value); } return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { if (value > type(uint64).max) { revert SafeCastOverflowedUintDowncast(64, value); } return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits */ function toUint56(uint256 value) internal pure returns (uint56) { if (value > type(uint56).max) { revert SafeCastOverflowedUintDowncast(56, value); } return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits */ function toUint48(uint256 value) internal pure returns (uint48) { if (value > type(uint48).max) { revert SafeCastOverflowedUintDowncast(48, value); } return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits */ function toUint40(uint256 value) internal pure returns (uint40) { if (value > type(uint40).max) { revert SafeCastOverflowedUintDowncast(40, value); } return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { if (value > type(uint32).max) { revert SafeCastOverflowedUintDowncast(32, value); } return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits */ function toUint24(uint256 value) internal pure returns (uint24) { if (value > type(uint24).max) { revert SafeCastOverflowedUintDowncast(24, value); } return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { if (value > type(uint16).max) { revert SafeCastOverflowedUintDowncast(16, value); } return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits */ function toUint8(uint256 value) internal pure returns (uint8) { if (value > type(uint8).max) { revert SafeCastOverflowedUintDowncast(8, value); } return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { if (value < 0) { revert SafeCastOverflowedIntToUint(value); } return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(248, value); } } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(240, value); } } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(232, value); } } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(224, value); } } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(216, value); } } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(208, value); } } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(200, value); } } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(192, value); } } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(184, value); } } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(176, value); } } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(168, value); } } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(160, value); } } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(152, value); } } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(144, value); } } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(136, value); } } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(128, value); } } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(120, value); } } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(112, value); } } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(104, value); } } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(96, value); } } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(88, value); } } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(80, value); } } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(72, value); } } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(64, value); } } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(56, value); } } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(48, value); } } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(40, value); } } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(32, value); } } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(24, value); } } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(16, value); } } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(8, value); } } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive if (value > uint256(type(int256).max)) { revert SafeCastOverflowedUintToInt(value); } return int256(value); } /** * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump. */ function toUint(bool b) internal pure returns (uint256 u) { assembly ("memory-safe") { u := iszero(iszero(b)) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; import {SafeCast} from "./SafeCast.sol"; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant. * * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone. * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute * one branch when needed, making this function more expensive. */ function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) { unchecked { // branchless ternary works because: // b ^ (a ^ b) == a // b ^ 0 == b return b ^ ((a ^ b) * int256(SafeCast.toUint(condition))); } } /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return ternary(a > b, a, b); } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return ternary(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 { // Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson. // Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift, // taking advantage of the most significant (or "sign" bit) in two's complement representation. // This opcode adds new most significant bits set to the value of the previous most significant bit. As a result, // the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative). int256 mask = n >> 255; // A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it. return uint256((n + mask) ^ mask); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol) pragma solidity ^0.8.20; /** * @dev Helper library for emitting standardized panic codes. * * ```solidity * contract Example { * using Panic for uint256; * * // Use any of the declared internal constants * function foo() { Panic.GENERIC.panic(); } * * // Alternatively * function foo() { Panic.panic(Panic.GENERIC); } * } * ``` * * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil]. * * _Available since v5.1._ */ // slither-disable-next-line unused-state library Panic { /// @dev generic / unspecified error uint256 internal constant GENERIC = 0x00; /// @dev used by the assert() builtin uint256 internal constant ASSERT = 0x01; /// @dev arithmetic underflow or overflow uint256 internal constant UNDER_OVERFLOW = 0x11; /// @dev division or modulo by zero uint256 internal constant DIVISION_BY_ZERO = 0x12; /// @dev enum conversion error uint256 internal constant ENUM_CONVERSION_ERROR = 0x21; /// @dev invalid encoding in storage uint256 internal constant STORAGE_ENCODING_ERROR = 0x22; /// @dev empty array pop uint256 internal constant EMPTY_ARRAY_POP = 0x31; /// @dev array out of bounds access uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32; /// @dev resource error (too large allocation or too large array) uint256 internal constant RESOURCE_ERROR = 0x41; /// @dev calling invalid internal function uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51; /// @dev Reverts with a panic code. Recommended to use with /// the internal constants with predefined codes. function panic(uint256 code) internal pure { assembly ("memory-safe") { mstore(0x00, 0x4e487b71) mstore(0x20, code) revert(0x1c, 0x24) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; assembly ("memory-safe") { ptr := add(buffer, add(32, length)) } while (true) { ptr--; assembly ("memory-safe") { mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { uint256 localValue = value; bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal * representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); } /** * @dev Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal * representation, according to EIP-55. */ function toChecksumHexString(address addr) internal pure returns (string memory) { bytes memory buffer = bytes(toHexString(addr)); // hash the hex part of buffer (skip length + 2 bytes, length 40) uint256 hashValue; assembly ("memory-safe") { hashValue := shr(96, keccak256(add(buffer, 0x22), 40)) } for (uint256 i = 41; i > 1; --i) { // possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f) if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) { // case shift by xoring with 0x20 buffer[i] ^= 0x20; } hashValue >>= 4; } return string(buffer); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.6; import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /// @dev Interface of the EIP-4883 Non-Fungible Token Standard, as defined in the /// https://eips.ethereum.org/EIPS/eip-4883. /// The EIP is still in DRAFT, waiting for FINAL for INTERFACE_ID interface IERC4883 is IERC165 { /// @notice Render a SVG NFT for on-chain composition /// @param id desired token id of SVG NFT /// @return the SVG body for the specified token id and must either be an empty string or valid SVG element(s). function renderTokenById(uint256 id) external view returns (string memory); }
// SPDX-License-Identifier: GPL-3.0 // _-_ // /~~ ~~\ // /~ ~\ // ( ) // \ _- -_ / // ^ \\ // ^ // | | // | | // | | // / \ /// @title Interface for Token pragma solidity ^0.8.6; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import {IERC4906} from "@openzeppelin/contracts/interfaces/IERC4906.sol"; import "./ITreeSeeder.sol"; import "./IERC4883.sol"; interface IToken is IERC721, IERC4883, IERC4906 { event StagKilled(uint256 indexed hunterTokenId, uint256[] tokenIds); event HareKilled(uint256 indexed hunterTokenId); event MergeTreeCreated(uint256 indexed tokenId, ITreeSeeder.Tree tree); event MergeTreeCloned(uint256 indexed hareTokenId, uint256 indexed tokenId); event MergeTreeBurned(uint256 indexed tokenId); event MergeTreeMarkerUpdated(uint256 indexed tokenId); event ComposableMarkerApproval(address tokenContract, bool approved); event GrowthDividerUpdated(uint256 newGrowthDivider); event GrowthDeclineBlocksUpdated(uint256 newGrowthDeclineBlocks); event DeclineUntil(uint256 blockNumber); event FoundersUpdated(address founders); event SeederUpdated(ITreeSeeder seeder); event SeederLocked(); function mint() external payable returns (uint256); function cooperation() external view returns (uint256); function huntStag(uint256 tokenId) external; function huntHare(uint256 tokenId) external payable; function claim(uint32 quantity) external; function burn(uint256 tokenId) external; function toggleColor(uint256 tokenId) external; function setMarker( uint256 tokenId, address markerTokenContract, uint256 markerTokenId ) external; function setComposableMarkerApproval( address tokenContract, bool approved ) external; function resetColors() external; function setGrowthDivider(uint256 newGrowthDivider) external; function setGrowthDeclineBlocks(uint256 newGrowthDeclineBlocks) external; function setSeeder(ITreeSeeder seeder) external; function lockSeeder() external; function setFounders(address payable newFounders) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.6; // _-_ // /~~ ~~\ // /~ ~\ // ( ) // \ _- -_ / // ^ \\ // ^ // | | // | | // | | // / \ /// @title Interface for TheMergeTreeSeeder interface ITreeSeeder { /// @notice Tree structure struct Tree { uint16 initLength; uint16 diameter; uint8 segments; uint8 branches; bool animated; uint16 angle; /// @dev D: fractal dimension (Hausdorff) of the tree skeleton (for length calculation) /// 2 < D < 3 /// Stored as an index of the precomputed values (see TheMergeTreesRenderer.sol) uint8 d; /// @dev the Leonardo exponent (for diameter calculation) /// 1.93 < delta < 2.21 for infinite branching /// Stored as an index of the precomputed values (see TheMergeTreesRenderer.sol) uint8 delta; uint8 stags; uint8 hares; uint128 mintedSince; } function generateTree( uint256 tokenId, uint256 contractInitBlockNumber ) external view returns (Tree memory); function cloneTree( uint256 contractInitBlockNumber, Tree memory tree ) external view returns (Tree memory); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.28; import "./interfaces/ITreeSeeder.sol"; import "./utils/StringUtils.sol"; import "./utils/HexStrings.sol"; // _-_ // /~~ ~~\ // /~ ~\ // ( ) // \ _- -_ / // ^ \\ // ^ // | | // | | // | | // / \ /// @title The Merge Trees Renderer, converting on-chain data to a SVG fractal tree. /// @author Anthony Graignic (@agraignic) library TheMergeTreesRenderer { // Computed values of 1..16**(1/X) // with x = [1.93, 2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3] uint256 private constant FRACTIONAL_POW_HEX_TABLE_1_93 = 0x0004c38300047b5000042e9e0003dc6e00038355000321230002b23200022f6a; uint256 private constant FRACTIONAL_POW_HEX_TABLE_2 = 0x000493e0000450da0004097f0003bcd40003697600030d400002a4950002286d; uint256 private constant FRACTIONAL_POW_HEX_TABLE_2_1 = 0x0004582400041b7c0003dab4000394de000348a00002f3e20002931d00021f62; uint256 private constant FRACTIONAL_POW_HEX_TABLE_2_2 = 0x0004247d0003ed340003b202000371fe00032bd80002dd8a000283a00002174b; uint256 private constant FRACTIONAL_POW_HEX_TABLE_2_3 = 0x0003f76c0003c4bc00038e510003534e0003126e0002c9b7000275cd00021002; uint256 private constant FRACTIONAL_POW_HEX_TABLE_2_4 = 0x0003cfcc0003a11100036ec90003381e0002fbd40002b803000269640002096b; uint256 private constant FRACTIONAL_POW_HEX_TABLE_2_5 = 0x0003acb60003816b000352be00031fdf0002e79d0002a81e00025e300002036e; uint256 private constant FRACTIONAL_POW_HEX_TABLE_2_6 = 0x00038d710003652a000339a700030a1f0002d56d000299c4000254070001fdf7; uint256 private constant FRACTIONAL_POW_HEX_TABLE_2_7 = 0x0003716b00034bcb000323140002f6830002c4fc00028cbf00024ac60001f8f4; uint256 private constant FRACTIONAL_POW_HEX_TABLE_2_8 = 0x0003582b000334e700030eac0002e4bf0002b60d000280e30002424f0001f458; uint256 private constant FRACTIONAL_POW_HEX_TABLE_2_9 = 0x00034150000320250002fc230002d4950002a86e0002760900023a890001f017; uint256 private constant FRACTIONAL_POW_HEX_TABLE_3 = 0x00032c8800030d400002eb3d0002c5d000029bf500026c14000233600001ec28; uint32 private constant MULTIPLIER = 10 ** 8; /// @dev 32 bits per color #FFFFFFAA uint16 internal constant COLOR_LENGTH = 32; /// @dev Segment for defining lines struct Segment { uint8 depth; uint8 level; bool markerEnd; uint8 branches; uint16 angle; uint8 dIndex; uint8 deltaIndex; } function render( ITreeSeeder.Tree memory _tree, uint32 _length, uint256 colors, bool grow, string memory markerRender ) public pure returns (string memory treeRender) { treeRender = string( abi.encodePacked( '<defs><g id="stem"><line x1="0" y1="0" x2="0" y2="-1" stroke="#', getColor(colors, 1), '" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1" stroke-dashoffset="0" stroke-width="', StringUtils.uint2str(_tree.diameter / _length), ".", StringUtils.uint2strFixedLength( ((_tree.diameter * 1000) / _length), 3 ), '">', _tree.animated ? grow ? '<animate attributeName="stroke-dashoffset" dur="12s" repeatCount="indefinite" values="1;.1;.07;.05;0"/>' : '<animate attributeName="stroke-dashoffset" dur="12s" repeatCount="indefinite" values="0;.05;.07;.1;1"/>' : "", "</line></g>" ) ); for (uint8 depth = _tree.segments - 1; depth > 0; depth--) { treeRender = string( abi.encodePacked( treeRender, drawSegment( Segment( depth, _tree.segments - depth, false, _tree.branches, _tree.angle, _tree.d, _tree.delta ) ) ) ); } if (_tree.animated) { treeRender = string( abi.encodePacked( treeRender, grow ? '<animate href="#leaf" xlink:href="#leaf" attributeType="CSS" attributeName="opacity" values="0;.9;1" dur="12s" repeatCount="indefinite"/>' : '<animate href="#leaf" xlink:href="#leaf" attributeType="CSS" attributeName="opacity" values="1;.9;0" dur="12s" repeatCount="indefinite"/>' ) ); } treeRender = string( abi.encodePacked( treeRender, '</defs><g transform="translate(512, 1000) scale(', StringUtils.uint2str(_length), ')"><use href="#l', StringUtils.uint2str(_tree.segments - 1), '" xlink:href="#l', StringUtils.uint2str(_tree.segments - 1), '"/></g>' ) ); treeRender = string( abi.encodePacked( treeRender, renderMarkerP( bytes(markerRender).length > 0 ? markerRender : string( abi.encodePacked( '<svg viewBox="0 0 2 2"><circle cx="1" cy="1" r="1" fill="#', getColor(colors, 0), '"/></svg>' ) ), _tree.stags + _tree.hares ) ) ); return treeRender; } function drawSegment( Segment memory _segment ) internal pure returns (string memory segmentBranchesRender) { // Solidity only support uint as pow exponent so created a table // Length is calculated based on D: fractal dimension (Hausdorff) of the tree skeleton uint32 scaleLength = computeScale(_segment.depth, _segment.dIndex); // Diameter is calculated based on delta: the Leonardo exponent. uint32 scaleDiameter = computeScale( _segment.depth, _segment.deltaIndex ); if (_segment.branches < 4) { segmentBranchesRender = string( abi.encodePacked( '<g id="l', StringUtils.uint2str(_segment.level), _segment.level == 1 ? '" marker-end="url(#leaf)"><use href="#l' : '"><use href="#l', StringUtils.uint2str(_segment.level - 1), '" xlink:href="#l', StringUtils.uint2str(_segment.level - 1), '" transform="translate(0,-1) rotate(-', StringUtils.uint2str(_segment.angle), ") scale(.", StringUtils.uint2str(scaleDiameter), ",.", StringUtils.uint2str(scaleLength), ')"/>' ) ); segmentBranchesRender = string( abi.encodePacked( segmentBranchesRender, '<use href="#l', StringUtils.uint2str(_segment.level - 1), '" xlink:href="#l', StringUtils.uint2str(_segment.level - 1), '" transform="translate(0,-1) rotate(', StringUtils.uint2str(_segment.angle), ") scale(.", StringUtils.uint2str(scaleDiameter), ",.", StringUtils.uint2str(scaleLength), ')"/>' ) ); if (_segment.branches == 3) { segmentBranchesRender = string( abi.encodePacked( segmentBranchesRender, '<use href="#l', StringUtils.uint2str(_segment.level - 1), '" xlink:href="#l', StringUtils.uint2str(_segment.level - 1), '" transform="translate(0,-1) scale(.', StringUtils.uint2str(scaleDiameter), ",.", StringUtils.uint2str(scaleLength), ')"/>' ) ); } } else { segmentBranchesRender = string( abi.encodePacked( '<g id="l', StringUtils.uint2str(_segment.level), _segment.level == 1 ? '" marker-end="url(#leaf)"><use href="#l' : '"><use href="#l', StringUtils.uint2str(_segment.level - 1), '" xlink:href="#l', StringUtils.uint2str(_segment.level - 1), '" transform="translate(0,-1) rotate(-', StringUtils.uint2str((_segment.angle * 3) / 2), ") scale(.", StringUtils.uint2str(scaleDiameter), ",.", StringUtils.uint2str(scaleLength), ')"/>' ) ); segmentBranchesRender = string( abi.encodePacked( segmentBranchesRender, '<use href="#l', StringUtils.uint2str(_segment.level - 1), '" xlink:href="#l', StringUtils.uint2str(_segment.level - 1), '" transform="translate(0,-1) rotate(-', StringUtils.uint2str(_segment.angle / 2), ") scale(.", StringUtils.uint2str(scaleDiameter), ",.", StringUtils.uint2str(scaleLength), ')"/>' ) ); segmentBranchesRender = string( abi.encodePacked( segmentBranchesRender, '<use href="#l', StringUtils.uint2str(_segment.level - 1), '" xlink:href="#l', StringUtils.uint2str(_segment.level - 1), '" transform="translate(0,-1) rotate(', StringUtils.uint2str(_segment.angle / 2), ") scale(.", StringUtils.uint2str(scaleDiameter), ",.", StringUtils.uint2str(scaleLength), ')"/>' ) ); segmentBranchesRender = string( abi.encodePacked( segmentBranchesRender, '<use href="#l', StringUtils.uint2str(_segment.level - 1), '" xlink:href="#l', StringUtils.uint2str(_segment.level - 1), '" transform="translate(0,-1) rotate(', StringUtils.uint2str((_segment.angle * 3) / 2), ") scale(.", StringUtils.uint2str(scaleDiameter), ",.", StringUtils.uint2str(scaleLength), ')"/>' ) ); } segmentBranchesRender = string( abi.encodePacked( segmentBranchesRender, '<use href="#stem" xlink:href="#stem"/></g>' ) ); return segmentBranchesRender; } /// @dev Define the marker at the end of the last segment /// Define a dedicated <def> block to be on top of tree drawing function renderMarkerP( string memory tokenRender, uint8 cuts ) internal pure returns (string memory markerRender) { markerRender = string( abi.encodePacked( '<defs><marker id="leaf" orient="auto" markerUnits="userSpaceOnUse" refX="50%" refY="50%" viewBox="0 0 1024 1024" markerWidth="1.', StringUtils.uint2str(cuts), '" markerHeight="1.', StringUtils.uint2str(cuts), '">', tokenRender, "</marker></defs>" ) ); } /// @dev Compute scale (l_k+1/l_k) function computeScale( uint8 _level, uint8 index ) internal pure returns (uint32 scale) { uint256 precomputedValue = FRACTIONAL_POW_HEX_TABLE_2_2; if (index == 0) { precomputedValue = FRACTIONAL_POW_HEX_TABLE_1_93; } else if (index == 1) { precomputedValue = FRACTIONAL_POW_HEX_TABLE_2; } else if (index == 2) { precomputedValue = FRACTIONAL_POW_HEX_TABLE_2_1; // } else if (index == 3) { // precomputedValue = FRACTIONAL_POW_HEX_TABLE_2_2; } else if (index == 4) { precomputedValue = FRACTIONAL_POW_HEX_TABLE_2_3; } else if (index == 5) { precomputedValue = FRACTIONAL_POW_HEX_TABLE_2_4; } else if (index == 6) { precomputedValue = FRACTIONAL_POW_HEX_TABLE_2_5; } else if (index == 7) { precomputedValue = FRACTIONAL_POW_HEX_TABLE_2_6; } else if (index == 8) { precomputedValue = FRACTIONAL_POW_HEX_TABLE_2_7; } else if (index == 9) { precomputedValue = FRACTIONAL_POW_HEX_TABLE_2_8; } else if (index == 10) { precomputedValue = FRACTIONAL_POW_HEX_TABLE_2_9; } else if (index == 11) { precomputedValue = FRACTIONAL_POW_HEX_TABLE_3; } return MULTIPLIER / uint32((precomputedValue >> (32 * (_level - 1))) & 0xFFFFFFFF); } function getColor( uint256 colors, uint8 index ) internal pure returns (string memory) { uint256 shiftedColors = colors >> (COLOR_LENGTH * index); return HexStrings.toHexString(shiftedColors, 4); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; library HexStrings { bytes16 internal constant ALPHABET = "0123456789abcdef"; /// @dev uint to hex string without prefix /// inspired by OpenZeppelin Strings.sol https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Strings.sol function toHexString( uint256 value, uint256 length ) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length); for (uint256 i = buffer.length; i > 0; i--) { buffer[i - 1] = ALPHABET[value & 0xf]; value >>= 4; } return string(buffer); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; library StringUtils { /// @dev convert an uint to string function uint2str( uint256 _i ) internal pure returns (string memory _uintAsString) { if (_i == 0) { return "0"; } uint256 j = _i; uint256 len; while (j != 0) { len++; j /= 10; } bytes memory bstr = new bytes(len); uint256 k = len; while (_i != 0) { k = k - 1; uint8 temp = (48 + uint8(_i - (_i / 10) * 10)); bytes1 b1 = bytes1(temp); bstr[k] = b1; _i /= 10; } return string(bstr); } /// @dev convert an uint to a fixed-length string e.g. 84 => 084, useful for float numbers function uint2strFixedLength( uint256 _i, uint256 _length ) internal pure returns (string memory _uintAsString) { bytes memory bstr = new bytes(_length); uint256 k = _length; while (k != 0) { k = k - 1; uint8 temp = (48 + uint8(_i - (_i / 10) * 10)); bytes1 b1 = bytes1(temp); bstr[k] = b1; _i /= 10; } return string(bstr); } }
{ "optimizer": { "enabled": true, "runs": 1824 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": { "contracts/TheMergeTreesRenderer.sol": { "TheMergeTreesRenderer": "0x68e9f40244b628F08E20F5A0CD37d205095F36C3" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_initialOwner","type":"address"},{"internalType":"address payable","name":"_creator","type":"address"},{"internalType":"uint256","name":"_beforeHuntLimitPerAddress","type":"uint256"},{"internalType":"contract ITreeSeeder","name":"_seeder","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AboveMaxBalancePerAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"required","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"BelowMinPrice","type":"error"},{"inputs":[],"name":"ERC721EnumerableForbiddenBatchMint","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721IncorrectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721InsufficientApproval","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC721InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC721InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC721InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC721InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonexistentToken","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"ERC721OutOfBoundsIndex","type":"error"},{"inputs":[],"name":"FoundersNotThanked","type":"error"},{"inputs":[],"name":"NotColorPicker","type":"error"},{"inputs":[{"internalType":"uint256","name":"coop","type":"uint256"}],"name":"NotEnoughCooperation","type":"error"},{"inputs":[],"name":"NotFounders","type":"error"},{"inputs":[],"name":"NotMatureTree","type":"error"},{"inputs":[],"name":"NotNFTOwner","type":"error"},{"inputs":[],"name":"NothingToClaim","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"SeederAlreadyLocked","type":"error"},{"inputs":[],"name":"StagHuntNotStarted","type":"error"},{"inputs":[],"name":"StagHuntStarted","type":"error"},{"inputs":[],"name":"UnapprovedContract","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":"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":"tokenContract","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ComposableMarkerApproval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"DeclineUntil","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"founders","type":"address"}],"name":"FoundersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newGrowthDeclineBlocks","type":"uint256"}],"name":"GrowthDeclineBlocksUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newGrowthDivider","type":"uint256"}],"name":"GrowthDividerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"hunterTokenId","type":"uint256"}],"name":"HareKilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"MergeTreeBurned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"hareTokenId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"MergeTreeCloned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"uint16","name":"initLength","type":"uint16"},{"internalType":"uint16","name":"diameter","type":"uint16"},{"internalType":"uint8","name":"segments","type":"uint8"},{"internalType":"uint8","name":"branches","type":"uint8"},{"internalType":"bool","name":"animated","type":"bool"},{"internalType":"uint16","name":"angle","type":"uint16"},{"internalType":"uint8","name":"d","type":"uint8"},{"internalType":"uint8","name":"delta","type":"uint8"},{"internalType":"uint8","name":"stags","type":"uint8"},{"internalType":"uint8","name":"hares","type":"uint8"},{"internalType":"uint128","name":"mintedSince","type":"uint128"}],"indexed":false,"internalType":"struct ITreeSeeder.Tree","name":"tree","type":"tuple"}],"name":"MergeTreeCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"MergeTreeMarkerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"MetadataUpdate","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":[],"name":"SeederLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ITreeSeeder","name":"seeder","type":"address"}],"name":"SeederUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"hunterTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"StagKilled","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"},{"inputs":[],"name":"BEFORE_HUNT_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"COLOR_PICKER_SELECTOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"COOPERATION_THRESHOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HARE_KILL_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPEN_MINT_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"approvedComposableTokenForMarker","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"beforeHuntLimitPerAddress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"quantity","type":"uint32"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"colors","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cooperation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"declineUntil","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"founders","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"growthDeclineBlocks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"growthDivider","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hasStagHuntStarted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"huntHare","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"huntStag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":[],"name":"isSeederLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockSeeder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pendingClaims","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"renderTokenById","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resetColors","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"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":"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":[],"name":"seeder","outputs":[{"internalType":"contract ITreeSeeder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"markerTokenContract","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setComposableMarkerApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newContractUriIpfsHash","type":"string"}],"name":"setContractURIHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newFounders","type":"address"}],"name":"setFounders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newGrowthDeclineBlocks","type":"uint256"}],"name":"setGrowthDeclineBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newGrowthDivider","type":"uint256"}],"name":"setGrowthDivider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"markerTokenContract","type":"address"},{"internalType":"uint256","name":"markerTokenId","type":"uint256"}],"name":"setMarker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ITreeSeeder","name":"_seeder","type":"address"}],"name":"setSeeder","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":"tokenId","type":"uint256"}],"name":"toggleColor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenIdsDeclineUntil","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":[],"name":"totalPendingClaim","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":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"trees","outputs":[{"internalType":"uint16","name":"initLength","type":"uint16"},{"internalType":"uint16","name":"diameter","type":"uint16"},{"internalType":"uint8","name":"segments","type":"uint8"},{"internalType":"uint8","name":"branches","type":"uint8"},{"internalType":"bool","name":"animated","type":"bool"},{"internalType":"uint16","name":"angle","type":"uint16"},{"internalType":"uint8","name":"d","type":"uint8"},{"internalType":"uint8","name":"delta","type":"uint8"},{"internalType":"uint8","name":"stags","type":"uint8"},{"internalType":"uint8","name":"hares","type":"uint8"},{"internalType":"uint128","name":"mintedSince","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
610120604052603b60c081815290616cd560e039600c906100209082610e0b565b5034801561002d57600080fd5b50604051616d10380380616d1083398101604081905261004c91610ee1565b836040518060400160405280600c81526020016b5468654d657267655472656560a01b815250604051806040016040528060058152602001644d5452454560d81b815250816000908161009f9190610e0b565b5060016100ac8282610e0b565b5050506001600160a01b0381166100de57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b6100e7816101ab565b50600d80546001600160a01b038086166001600160a01b03199283168117909355600e8054918516919092161790554360805260a08390526000601281905561206460135562033b62601455601681905564ff0b6623ff601055600b805461015f939290919061015683610f4c565b909155506101fd565b50600d54600b8054610180926001600160a01b031691600061015683610f4c565b50600d54600b80546101a1926001600160a01b031691600061015683610f4c565b505050505061121f565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600e54608051604051630f642e7960e01b815260048101849052602481019190915260009182916001600160a01b0390911690630f642e799060440161016060405180830381865afa158015610257573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061027b9190610fdd565b600f600085815260200190815260200160002060008201518160000160006101000a81548161ffff021916908361ffff16021790555060208201518160000160026101000a81548161ffff021916908361ffff16021790555060408201518160000160046101000a81548160ff021916908360ff16021790555060608201518160000160056101000a81548160ff021916908360ff16021790555060808201518160000160066101000a81548160ff02191690831515021790555060a08201518160000160076101000a81548161ffff021916908361ffff16021790555060c08201518160000160096101000a81548160ff021916908360ff16021790555060e082015181600001600a6101000a81548160ff021916908360ff16021790555061010082015181600001600b6101000a81548160ff021916908360ff16021790555061012082015181600001600c6101000a81548160ff021916908360ff16021790555061014082015181600001600d6101000a8154816001600160801b0302191690836001600160801b031602179055509050604051806101600160405290816000820160009054906101000a900461ffff1661ffff1661ffff1681526020016000820160029054906101000a900461ffff1661ffff1661ffff1681526020016000820160049054906101000a900460ff1660ff1660ff1681526020016000820160059054906101000a900460ff1660ff1660ff1681526020016000820160069054906101000a900460ff161515151581526020016000820160079054906101000a900461ffff1661ffff1661ffff1681526020016000820160099054906101000a900460ff1660ff1660ff16815260200160008201600a9054906101000a900460ff1660ff1660ff16815260200160008201600b9054906101000a900460ff1660ff1660ff16815260200160008201600c9054906101000a900460ff1660ff1660ff16815260200160008201600d9054906101000a90046001600160801b03166001600160801b03166001600160801b031681525050905061058584846105c860201b60201c565b827f10ca4a29cf8444f5e8a109a26a3724a6e6d54c9c83d5b4c240f474f8e1910d62826040516105b591906110bc565b60405180910390a2829150505b92915050565b6001600160a01b0382166105f257604051633250574960e11b8152600060048201526024016100d5565b60006105ff838383610631565b90506001600160a01b0381161561062c576040516339e3563760e11b8152600060048201526024016100d5565b505050565b60008060125460001480610646575060125443115b905080156106cf576000848152600f6020526040902054600664010000000090910460ff16101561069b576000848152600f602052604090205461069690640100000000900460ff1660016111ae565b61069e565b60065b6000858152600f60205260409020805460ff929092166401000000000260ff60201b1990921691909117905561074c565b6000848152600f6020526040902054600264010000000090910460ff161061071c576000848152600f602052604090205461071790600190640100000000900460ff166111c7565b61071f565b60005b6000858152600f60205260409020805460ff929092166401000000000260ff60201b199092169190911790555b6040518481527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a161078a858585610793565b95945050505050565b6000806107a1858585610868565b90506001600160a01b0381166107fe576107f984600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b610821565b846001600160a01b0316816001600160a01b031614610821576108218185610960565b6001600160a01b03851661083d57610838846109e1565b610860565b846001600160a01b0316816001600160a01b031614610860576108608585610a90565b949350505050565b6000828152600260205260408120546001600160a01b039081169083161561089557610895818486610ae0565b6001600160a01b038116156108d2576108b16000858180610b44565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b03851615610901576001600160a01b0385166000908152600360205260409020805460010190555b60008481526002602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b600061096b83610c69565b6000838152600760209081526040808320546001600160a01b03881684526006909252909120919250908183146109c257600083815260208281526040808320548584528184208190558352600790915290208290555b6000938452600760209081526040808620869055938552525081205550565b6008546000906109f3906001906111e0565b60008381526009602052604081205460088054939450909284908110610a1b57610a1b6111f3565b906000526020600020015490508060088381548110610a3c57610a3c6111f3565b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480610a7457610a74611209565b6001900381819060005260206000200160009055905550505050565b60006001610a9d84610c69565b610aa791906111e0565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b610aeb838383610cb1565b61062c576001600160a01b038316610b1957604051637e27328960e01b8152600481018290526024016100d5565b60405163177e802f60e01b81526001600160a01b0383166004820152602481018290526044016100d5565b8080610b5857506001600160a01b03821615155b15610c39576000610b6884610d34565b90506001600160a01b03831615801590610b945750826001600160a01b0316816001600160a01b031614155b8015610bc657506001600160a01b0380821660009081526005602090815260408083209387168352929052205460ff16155b15610bef5760405163a9fbf51f60e01b81526001600160a01b03841660048201526024016100d5565b8115610c375783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260046020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b60006001600160a01b038216610c95576040516322718ad960e21b8152600060048201526024016100d5565b506001600160a01b031660009081526003602052604090205490565b60006001600160a01b038316158015906108605750826001600160a01b0316846001600160a01b03161480610d0b57506001600160a01b0380851660009081526005602090815260408083209387168352929052205460ff165b806108605750506000908152600460205260409020546001600160a01b03908116911614919050565b6000818152600260205260408120546001600160a01b0316806105c257604051637e27328960e01b8152600481018490526024016100d5565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680610d9757607f821691505b602082108103610db757634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561062c57806000526020600020601f840160051c81016020851015610de45750805b601f840160051c820191505b81811015610e045760008155600101610df0565b5050505050565b81516001600160401b03811115610e2457610e24610d6d565b610e3881610e328454610d83565b84610dbd565b6020601f821160018114610e6c5760008315610e545750848201515b600019600385901b1c1916600184901b178455610e04565b600084815260208120601f198516915b82811015610e9c5787850151825560209485019460019092019101610e7c565b5084821015610eba5786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b6001600160a01b0381168114610ede57600080fd5b50565b60008060008060808587031215610ef757600080fd5b8451610f0281610ec9565b6020860151909450610f1381610ec9565b604086015160608701519194509250610f2b81610ec9565b939692955090935050565b634e487b7160e01b600052601160045260246000fd5b600060018201610f5e57610f5e610f36565b5060010190565b60405161016081016001600160401b0381118282101715610f8857610f88610d6d565b60405290565b805161ffff81168114610fa057600080fd5b919050565b805160ff81168114610fa057600080fd5b80518015158114610fa057600080fd5b80516001600160801b0381168114610fa057600080fd5b6000610160828403128015610ff157600080fd5b50610ffa610f65565b61100383610f8e565b815261101160208401610f8e565b602082015261102260408401610fa5565b604082015261103360608401610fa5565b606082015261104460808401610fb6565b608082015261105560a08401610f8e565b60a082015261106660c08401610fa5565b60c082015261107760e08401610fa5565b60e08201526110896101008401610fa5565b61010082015261109c6101208401610fa5565b6101208201526110af6101408401610fc6565b6101408201529392505050565b815161ffff168152610160810160208301516110de602084018261ffff169052565b5060408301516110f3604084018260ff169052565b506060830151611108606084018260ff169052565b50608083015161111c608084018215159052565b5060a083015161113260a084018261ffff169052565b5060c083015161114760c084018260ff169052565b5060e083015161115c60e084018260ff169052565b5061010083015161117361010084018260ff169052565b5061012083015161118a61012084018260ff169052565b506101408301516111a76101408401826001600160801b03169052565b5092915050565b60ff81811683821601908111156105c2576105c2610f36565b60ff82811682821603908111156105c2576105c2610f36565b818103818111156105c2576105c2610f36565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b60805160a051615a7561126060003960008181610bad0152610e9a015260008181610545015281816127d101528181612e70015261331d0152615a756000f3fe60806040526004361061038c5760003560e01c80635f295a67116101dc578063a22cb46511610102578063d50b31eb116100a0578063f33ae73a1161006f578063f33ae73a14610b5a578063f8e5802414610b6f578063fb0bbb0514610b85578063fe98248a14610b9b57600080fd5b8063d50b31eb14610abc578063e8a3d48514610adc578063e985e9c514610af1578063f2fde38b14610b3a57600080fd5b8063baedc1c4116100dc578063baedc1c414610a13578063c87b56dd14610a33578063c8fc0c2314610a53578063ca78533d14610a7457600080fd5b8063a22cb465146109b3578063a2d6c6da146109d3578063b88d4fde146109f357600080fd5b80637a5080221161017a57806390486b451161014957806390486b451461094d57806391a53eee1461096357806395d89b41146109835780639b7ccd6c1461099857600080fd5b80637a508022146108135780637fedbbac146108fc57806380d5ded51461091c5780638da5cb5b1461092f57600080fd5b8063684931ed116101b6578063684931ed1461079e57806370a08231146107be578063715018a6146107de57806375c14292146107f357600080fd5b80635f295a671461074d57806362747679146107625780636352211e1461077e57600080fd5b806322c3a117116102c157806342842e0e1161025f5780634f6ccce71161022e5780634f6ccce7146106e2578063502ae84d146107025780635aa1d0ce146107185780635dad667c1461072d57600080fd5b806342842e0e1461066857806342966c681461068857806349f4ff99146106a85780634e9827ef146106c857600080fd5b80632f745c591161029b5780632f745c59146105f35780633ccfd60b14610613578063403b58b014610628578063411b007e1461064857600080fd5b806322c3a1171461056757806323b872dd146105945780632a55205a146105b457600080fd5b806318160ddd1161032e578063201afd8311610308578063201afd83146104e857806320a479711461050857806320a8480f1461051d57806321615f6e1461053357600080fd5b806318160ddd1461048d5780631d2ada7e146104a25780631e73cea2146104b857600080fd5b8063081812fc1161036a578063081812fc1461040a578063095ea7b31461044257806311f07544146104625780631249c58b1461048557600080fd5b806301ffc9a71461039157806304951891146103c657806306fdde03146103e8575b600080fd5b34801561039d57600080fd5b506103b16103ac3660046143b8565b610bcf565b60405190151581526020015b60405180910390f35b3480156103d257600080fd5b506103e66103e13660046143d5565b610c7b565b005b3480156103f457600080fd5b506103fd610db1565b6040516103bd919061444b565b34801561041657600080fd5b5061042a61042536600461445e565b610e43565b6040516001600160a01b0390911681526020016103bd565b34801561044e57600080fd5b506103e661045d36600461448c565b610e6c565b34801561046e57600080fd5b50610477600c81565b6040519081526020016103bd565b610477610e7b565b34801561049957600080fd5b50600854610477565b3480156104ae57600080fd5b5061047760165481565b3480156104c457600080fd5b506103b16104d33660046144b8565b60186020526000908152604090205460ff1681565b3480156104f457600080fd5b506103e66105033660046144b8565b610fc8565b34801561051457600080fd5b5061047761106e565b34801561052957600080fd5b506104776113ec81565b34801561053f57600080fd5b506104777f000000000000000000000000000000000000000000000000000000000000000081565b34801561057357600080fd5b5061047761058236600461445e565b60156020526000908152604090205481565b3480156105a057600080fd5b506103e66105af3660046144d5565b611106565b3480156105c057600080fd5b506105d46105cf366004614516565b6111aa565b604080516001600160a01b0390931683526020830191909152016103bd565b3480156105ff57600080fd5b5061047761060e36600461448c565b6111e2565b34801561061f57600080fd5b506103e6611260565b34801561063457600080fd5b506103e661064336600461445e565b61137a565b34801561065457600080fd5b50600d5461042a906001600160a01b031681565b34801561067457600080fd5b506103e66106833660046144d5565b611816565b34801561069457600080fd5b506103e66106a336600461445e565b611836565b3480156106b457600080fd5b506103e66106c336600461445e565b61190c565b3480156106d457600080fd5b506011546103b19060ff1681565b3480156106ee57600080fd5b506104776106fd36600461445e565b611949565b34801561070e57600080fd5b5061047760135481565b34801561072457600080fd5b506103e66119bb565b34801561073957600080fd5b506103e661074836600461445e565b6119ce565b34801561075957600080fd5b506103e6611a66565b34801561076e57600080fd5b50610477670100f7c0749aa00081565b34801561078a57600080fd5b5061042a61079936600461445e565b611b0b565b3480156107aa57600080fd5b50600e5461042a906001600160a01b031681565b3480156107ca57600080fd5b506104776107d93660046144b8565b611b16565b3480156107ea57600080fd5b506103e6611b77565b3480156107ff57600080fd5b506103e661080e366004614538565b611b8b565b34801561081f57600080fd5b506108e561082e36600461445e565b600f6020526000908152604090205461ffff8082169162010000810482169160ff640100000000830481169265010000000000810482169266010000000000008204831692670100000000000000830490911691690100000000000000000081048216916a010000000000000000000082048116916b01000000000000000000000081048216916c01000000000000000000000000820416906001600160801b036d0100000000000000000000000000909104168b565b6040516103bd9b9a9998979695949392919061455f565b34801561090857600080fd5b506103e661091736600461445e565b611d6f565b6103e661092a36600461445e565b611dac565b34801561093b57600080fd5b50600a546001600160a01b031661042a565b34801561095957600080fd5b5061047760145481565b34801561096f57600080fd5b506103e661097e3660046145ee565b61201e565b34801561098f57600080fd5b506103fd61214a565b3480156109a457600080fd5b506104776601b68eefb5f00081565b3480156109bf57600080fd5b506103e66109ce3660046145ee565b612159565b3480156109df57600080fd5b506103fd6109ee36600461445e565b612164565b3480156109ff57600080fd5b506103e6610a0e3660046146fe565b6121e6565b348015610a1f57600080fd5b506103e6610a2e36600461477e565b6121fe565b348015610a3f57600080fd5b506103fd610a4e36600461445e565b612212565b348015610a5f57600080fd5b50600e546103b190600160a01b900460ff1681565b348015610a8057600080fd5b50610aa7610a8f3660046144b8565b60176020526000908152604090205463ffffffff1681565b60405163ffffffff90911681526020016103bd565b348015610ac857600080fd5b506103e6610ad73660046144b8565b61263e565b348015610ae857600080fd5b506103fd6126e5565b348015610afd57600080fd5b506103b1610b0c3660046147c7565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b348015610b4657600080fd5b506103e6610b553660046144b8565b61270d565b348015610b6657600080fd5b50610477606781565b348015610b7b57600080fd5b5061047760105481565b348015610b9157600080fd5b5061047760125481565b348015610ba757600080fd5b506104777f000000000000000000000000000000000000000000000000000000000000000081565b60006001600160e01b031982167f2a55205a000000000000000000000000000000000000000000000000000000001480610c3257506001600160e01b031982167fa2d6c6da00000000000000000000000000000000000000000000000000000000145b80610c6657506001600160e01b031982167f4906490600000000000000000000000000000000000000000000000000000000145b80610c755750610c7582612761565b92915050565b3360009081526017602052604090205463ffffffff1615801590610cb857503360009081526017602052604090205463ffffffff90811690821611155b15610d7c578063ffffffff1660166000828254610cd5919061480b565b909155505033600090815260176020526040902054610cfb90829063ffffffff1661481e565b33600090815260176020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff9390931692909217909155600b54905b8263ffffffff168163ffffffff161015610d7557610d6c3383610d658161483a565b945061279f565b50600101610d43565b50600b5550565b6040517f969bf72800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b606060008054610dc090614853565b80601f0160208091040260200160405190810160405280929190818152602001828054610dec90614853565b8015610e395780601f10610e0e57610100808354040283529160200191610e39565b820191906000526020600020905b815481529060010190602001808311610e1c57829003601f168201915b5050505050905090565b6000610e4e82612b95565b506000828152600460205260409020546001600160a01b0316610c75565b610e77828233612bce565b5050565b60115460009060ff16158015610e9357506067600b54105b15610f96577f0000000000000000000000000000000000000000000000000000000000000000610ec233611b16565b10610ef9576040517f328d3cba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b670100f7c0749aa000341015610f50576040517fde759846000000000000000000000000000000000000000000000000000000008152670100f7c0749aa00060048201523460248201526044015b60405180910390fd5b610f5c6001606761480b565b600b5410610f72576011805460ff191660011790555b600b8054610f91913391906000610f888361483a565b9190505561279f565b905090565b6040517fa52c466000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d546001600160a01b0316331461100c576040517fac2308c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081527f5f952e8714912176e13b8b0673378185e6540e5a1f0c430884b1da9253bae152906020015b60405180910390a150565b6000808061107b60085490565b905060005b818110156110db576000818152600f6020526040902054600664010000000090910460ff16108015906110c0575060008181526015602052604090205443115b156110d357826110cf8161483a565b9350505b600101611080565b506016546110e99082614887565b6110f58361271061489a565b6110ff91906148c7565b9250505090565b6001600160a01b03821661113057604051633250574960e11b815260006004820152602401610f47565b600061113d838333612bdb565b9050836001600160a01b0316816001600160a01b0316146111a4576040517f64283d7b0000000000000000000000000000000000000000000000000000000081526001600160a01b0380861660048301526024820184905282166044820152606401610f47565b50505050565b6000806111bf600a546001600160a01b031690565b6127106111cd85600061489a565b6111d791906148c7565b915091509250929050565b60006111ed83611b16565b8210611237576040517fa57d13dc0000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260248101839052604401610f47565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b600d546001600160a01b031633148015906112865750600a546001600160a01b03163314155b156112bd576040517fac2308c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d546040516000916001600160a01b03169047908381818185875af1925050503d806000811461130a576040519150601f19603f3d011682016040523d82523d6000602084013e61130f565b606091505b5050905080610dae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5472616e73666572206661696c65642e000000000000000000000000000000006044820152606401610f47565b60115460ff166113b6576040517fa38ee6e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113bf81611b0b565b6001600160a01b0316336001600160a01b0316146113f057604051631022318760e21b815260040160405180910390fd5b6000818152600f6020526040902054600664010000000090910460ff161015611445576040517f9e6153fd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061145060085490565b905060008167ffffffffffffffff81111561146d5761146d614627565b604051908082528060200260200182016040528015611496578160200160208202803683370190505b5090506000805b8381101561154d576000818152600f6020526040902054600664010000000090910460ff16106115095760008181526015602052604090205443111561150957808383815181106114f0576114f06148db565b6020908102919091010152816115058161483a565b9250505b60008181526015602052604090205415611545576000818152600f60209081526040808320805466ff0000000000001916905560159091528120555b60010161149d565b5060006016548461155e9190614887565b61156a8361271061489a565b61157491906148c7565b90506113ec8111156117da5760008267ffffffffffffffff81111561159b5761159b614627565b6040519080825280602002602001820160405280156115c4578160200160208202803683370190505b509050826016546115d59190614887565b601655600060128190555b83811015611751578481815181106115fa576115fa6148db565b6020026020010151828281518110611614576116146148db565b6020026020010181815250506001600f6000878481518110611638576116386148db565b6020026020010151815260200190815260200160002060000160046101000a81548160ff021916908360ff160217905550600f600086838151811061167f5761167f6148db565b602090810291909101810151825281019190915260400160002080546b010000000000000000000000900460ff1690600b6116b9836148f1565b91906101000a81548160ff021916908360ff16021790555050601760006116f88784815181106116eb576116eb6148db565b6020026020010151611b0b565b6001600160a01b0316815260208101919091526040016000908120805463ffffffff169161172583614910565b91906101000a81548163ffffffff021916908363ffffffff1602179055505080806001019150506115e0565b507f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c60006001600b54611784919061480b565b6040805192835260208301919091520160405180910390a1857f91d97924a4649f48d15ce92530886b3ccce4e916bc90ec1566ae1e0d91dcdf3d826040516117cc919061492c565b60405180910390a25061180f565b6040517f3a83c94500000000000000000000000000000000000000000000000000000000815260048101829052602401610f47565b5050505050565b611831838383604051806020016040528060008152506121e6565b505050565b61183f81611b0b565b6001600160a01b0316336001600160a01b03161461187057604051631022318760e21b815260040160405180910390fd5b61187981612d41565b6000818152600f6020908152604080832080547fffffff000000000000000000000000000000000000000000000000000000000016905560198252808320805473ffffffffffffffffffffffffffffffffffffffff1916815560010183905560159091528082208290555182917f46528d92bcf2945ce329208a44d1bb48172cc09d5d03d44450072c1371f5affb91a250565b611914612d7c565b60138190556040518181527ffe371b3c294b50939cb7d062668a0e2cee39975006d8513d4bafe1e86e3b41a990602001611063565b600061195460085490565b8210611996576040517fa57d13dc0000000000000000000000000000000000000000000000000000000081526000600482015260248101839052604401610f47565b600882815481106119a9576119a96148db565b90600052602060002001549050919050565b6119c3612d7c565b64ff0b6623ff601055565b6119d781611b0b565b6001600160a01b0316336001600160a01b031614611a0857604051631022318760e21b815260040160405180910390fd5b611a13600c8261496f565b15611a4a576040517ffee4821d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a55600c826148c7565b6001901b6010541860108190555050565b611a6e612d7c565b600e54600160a01b900460ff1615611ab2576040517f7d6257d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16600160a01b1790556040517ff59561f22794afcfb1e6be5c4733f5449fd167252a96b74bb06d341fb0dac7ed90600090a1565b6000610c7582612b95565b60006001600160a01b038216611b5b576040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152602401610f47565b506001600160a01b031660009081526003602052604090205490565b611b7f612d7c565b611b896000612dc2565b565b6001600160a01b03821660009081526018602052604090205460ff16611bdd576040517f7d7f3db300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611be683611b0b565b6001600160a01b0316336001600160a01b0316141580611c9957506040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018290526001600160a01b03831690636352211e90602401602060405180830381865afa158015611c5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c839190614983565b6001600160a01b0316336001600160a01b031614155b15611cb757604051631022318760e21b815260040160405180910390fd5b6040805180820182526001600160a01b03848116825260208083018581526000888152601983528590209351845473ffffffffffffffffffffffffffffffffffffffff19169316929092178355905160019092019190915590518481527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7910160405180910390a160405183907f49251b4fc49c7a77c5701bd8b2988d065e1741d507ce2a3a796200f46b3b220590600090a2505050565b611d77612d7c565b60148190556040518181527f10211f882638170b5cb679ca2d39a16fca322a439ac4bc20872572b03fb75d1090602001611063565b60115460ff16611de8576040517fa38ee6e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611df181611b0b565b6001600160a01b0316336001600160a01b031614611e2257604051631022318760e21b815260040160405180910390fd5b6000611e2d60085490565b6000838152600f60205260409020546601b68eefb5f00090611e63906c01000000000000000000000000900460ff1660016149a0565b60ff16611e70919061489a565b611e7a919061489a565b905080341015611ebf576040517fde75984600000000000000000000000000000000000000000000000000000000815260048101829052346024820152604401610f47565b601254600003611ede57601454611ed69043614887565b601255611ef2565b601454601254611eee9190614887565b6012555b601254600083815260156020908152604080832093909355600f90522080546c01000000000000000000000000900460ff1690600c611f30836148f1565b91906101000a81548160ff021916908360ff160217905550506000611f6c3384600b6000815480929190611f639061483a565b91905055612e21565b6000848152600f60209081526040808320805466ff000000000000191666010000000000001790556012548484526015909252822055600b549192507f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91611fd69060019061480b565b6040805192835260208301919091520160405180910390a160405183907f3c33d341350cfc092f5fb4dd226ea61549e742eb7487dc9a1d386a1eac8118b390600090a2505050565b612026612d7c565b600d546040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526003918416906370a0823190602401602060405180830381865afa15801561208b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120af91906149b9565b10156120e7576040517ff840408600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038216600081815260186020908152604091829020805460ff19168515159081179091558251938452908301527fa56a0776bcbac9c44610bf91448131516d7be439d528c569ad2a43a91e23259a910160405180910390a15050565b606060018054610dc090614853565b610e773383836130ae565b6000818152600260205260409020546060906001600160a01b031661219f57604051637e27328960e01b815260048101839052602401610f47565b6000601254600014806121b3575060125443115b90506121bf8382613166565b6040516020016121cf91906149ee565b604051602081830303815290604052915050919050565b6121f1848484611106565b6111a43385858585613466565b612206612d7c565b600c610e778282614b13565b6000818152600260205260409020546060906001600160a01b031661224d57604051637e27328960e01b815260048101839052602401610f47565b6000828152600f60209081526040808320815161016081018352905461ffff8082168352620100008204811694830194909452640100000000810460ff908116938301939093526501000000000081048316606083015266010000000000008104831615156080830152670100000000000000810490931660a082015269010000000000000000008304821660c08201526a01000000000000000000008304821660e08201526b010000000000000000000000830482166101008201526c0100000000000000000000000083049091166101208201526d01000000000000000000000000009091046001600160801b03166101408201529061234e846135c2565b60405160200161235e9190614bd2565b6040516020818303038152906040529050600060125460001480612383575060125443115b9050606081156123cf576040517f412062656175746966756c2067726f77696e67207472656500000000000000006020820152603801604051602081830303815290604052905061240d565b6040517f41206465636c696e696e67207472656500000000000000000000000000000000602082015260300160405160208183030381529060405290505b600061242261241d888686613663565b6136b0565b90506000856080015161244e57604051806040016040528060018152602001600360fc1b815250612469565b604051806040016040528060018152602001603160f81b8152505b612474600c8a61496f565b1561249857604051806040016040528060018152602001600360fc1b8152506124b3565b604051806040016040528060018152602001603160f81b8152505b6040516020016124c4929190614c17565b604051602081830303815290604052905060006124e7876040015160ff166136d6565b6124f888610100015160ff166136d6565b61250989610120015160ff166136d6565b60405160200161251b93929190614cca565b6040516020818303038152906040529050600061253f886000015161ffff166136d6565b612550896020015161ffff166136d6565b6125608a6060015160ff166136d6565b6125718b60a0015161ffff166136d6565b6125818c60c0015160ff166136d6565b6125918d60e0015160ff166136d6565b6040516020016125a696959493929190614d9a565b60408051601f19818403018152908290526125c79185908590602001614f35565b604051602081830303815290604052905061261087866125e68d6135c2565b84886040516020016125fc959493929190614f78565b6040516020818303038152906040526136b0565b6040516020016126209190615104565b60405160208183030381529060405298505050505050505050919050565b612646612d7c565b600e54600160a01b900460ff161561268a576040517f7d6257d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081527fb3025222d01ce9a26c7f9d52bc3bfd0352366bd90a793c273fbfe1c81e0e288e90602001611063565b6060600c6040516020016126f99190615149565b604051602081830303815290604052905090565b612715612d7c565b6001600160a01b038116612758576040517f1e4fbdf700000000000000000000000000000000000000000000000000000000815260006004820152602401610f47565b610dae81612dc2565b60006001600160e01b031982167f780e9d63000000000000000000000000000000000000000000000000000000001480610c755750610c758261381a565b600e546040517f0f642e79000000000000000000000000000000000000000000000000000000008152600481018390527f0000000000000000000000000000000000000000000000000000000000000000602482015260009182916001600160a01b0390911690630f642e799060440161016060405180830381865afa15801561282d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128519190615237565b600f600085815260200190815260200160002060008201518160000160006101000a81548161ffff021916908361ffff16021790555060208201518160000160026101000a81548161ffff021916908361ffff16021790555060408201518160000160046101000a81548160ff021916908360ff16021790555060608201518160000160056101000a81548160ff021916908360ff16021790555060808201518160000160066101000a81548160ff02191690831515021790555060a08201518160000160076101000a81548161ffff021916908361ffff16021790555060c08201518160000160096101000a81548160ff021916908360ff16021790555060e082015181600001600a6101000a81548160ff021916908360ff16021790555061010082015181600001600b6101000a81548160ff021916908360ff16021790555061012082015181600001600c6101000a81548160ff021916908360ff16021790555061014082015181600001600d6101000a8154816001600160801b0302191690836001600160801b031602179055509050604051806101600160405290816000820160009054906101000a900461ffff1661ffff1661ffff1681526020016000820160029054906101000a900461ffff1661ffff1661ffff1681526020016000820160049054906101000a900460ff1660ff1660ff1681526020016000820160059054906101000a900460ff1660ff1660ff1681526020016000820160069054906101000a900460ff161515151581526020016000820160079054906101000a900461ffff1661ffff1661ffff1681526020016000820160099054906101000a900460ff1660ff1660ff16815260200160008201600a9054906101000a900460ff1660ff1660ff16815260200160008201600b9054906101000a900460ff1660ff1660ff16815260200160008201600c9054906101000a900460ff1660ff1660ff16815260200160008201600d9054906101000a90046001600160801b03166001600160801b03166001600160801b0316815250509050612b5584846138b5565b827f10ca4a29cf8444f5e8a109a26a3724a6e6d54c9c83d5b4c240f474f8e1910d6282604051612b8591906153fc565b60405180910390a2509092915050565b6000818152600260205260408120546001600160a01b031680610c7557604051637e27328960e01b815260048101849052602401610f47565b6118318383836001613933565b60008060125460001480612bf0575060125443115b90508015612c7a576000848152600f6020526040902054600664010000000090910460ff161015612c45576000848152600f6020526040902054612c4090640100000000900460ff1660016149a0565b612c48565b60065b6000858152600f60205260409020805460ff929092166401000000000264ff0000000019909216919091179055612cf8565b6000848152600f6020526040902054600264010000000090910460ff1610612cc7576000848152600f6020526040902054612cc290600190640100000000900460ff1661540b565b612cca565b60005b6000858152600f60205260409020805460ff929092166401000000000264ff00000000199092169190911790555b6040518481527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a1612d36858585613a7e565b9150505b9392505050565b6000612d506000836000612bdb565b90506001600160a01b038116610e7757604051637e27328960e01b815260048101839052602401610f47565b600a546001600160a01b03163314611b89576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401610f47565b600a80546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600e546000838152600f602052604080822090517fb15e400400000000000000000000000000000000000000000000000000000000815291926001600160a01b03169163b15e400491612e99917f00000000000000000000000000000000000000000000000000000000000000009190600401615424565b61016060405180830381865afa158015612eb7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612edb9190615237565b600f600084815260200190815260200160002060008201518160000160006101000a81548161ffff021916908361ffff16021790555060208201518160000160026101000a81548161ffff021916908361ffff16021790555060408201518160000160046101000a81548160ff021916908360ff16021790555060608201518160000160056101000a81548160ff021916908360ff16021790555060808201518160000160066101000a81548160ff02191690831515021790555060a08201518160000160076101000a81548161ffff021916908361ffff16021790555060c08201518160000160096101000a81548160ff021916908360ff16021790555060e082015181600001600a6101000a81548160ff021916908360ff16021790555061010082015181600001600b6101000a81548160ff021916908360ff16021790555061012082015181600001600c6101000a81548160ff021916908360ff16021790555061014082015181600001600d6101000a8154816001600160801b0302191690836001600160801b0316021790555090505061307a84836138b5565b604051829084907f694caf5e0a9f144c344d2e9ffb42f0c73fb313bcfab97d9689f551c7eb990fb690600090a35092915050565b6001600160a01b0382166130f9576040517f5b08ba180000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610f47565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000828152600f6020908152604091829020825161016081018452905461ffff808216835262010000820481169383019390935260ff64010000000082048116948301859052650100000000008204811660608481019190915266010000000000008304821615156080850152670100000000000000830490941660a084015269010000000000000000008204811660c08401526a01000000000000000000008204811660e08401526b010000000000000000000000820481166101008401526c010000000000000000000000008204166101208301526001600160801b036d01000000000000000000000000009091041661014082015290916002111561330657826132a8576040518060400160405280601c81526020017f363630303030223e4572797369636874686f6e207761732068657265000000008152506132df565b6040518060400160405280601d81526020017f303036363136223e53706573206d657373697320696e2073656d696e650000008152505b6040516020016132ef91906154d3565b604051602081830303815290604052915050610c75565b6101408101516000906001600160801b03166133427f00000000000000000000000000000000000000000000000000000000000000004361480b565b61334c919061480b565b905060006013548261335e91906148c7565b90508461339a57601254601354613375919061489a565b43601254613383919061480b565b61338d908461489a565b61339791906148c7565b90505b82516000906133ae90839061ffff1661558b565b9050600060e363ffffffff831610156133c757816133ca565b60e35b90507368e9f40244b628f08e20f5a0cd37d205095f36c363b17c978d86836010548b6133f58e613b53565b6040518663ffffffff1660e01b81526004016134159594939291906155a7565b600060405180830381865af4158015613432573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261345a91908101906155f2565b98975050505050505050565b6001600160a01b0383163b1561180f576040517f150b7a020000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063150b7a02906134c1908890889087908790600401615669565b6020604051808303816000875af19250505080156134fc575060408051601f3d908101601f191682019092526134f9918101906156aa565b60015b613565573d80801561352a576040519150601f19603f3d011682016040523d82523d6000602084013e61352f565b606091505b50805160000361355d57604051633250574960e11b81526001600160a01b0385166004820152602401610f47565b805181602001fd5b6001600160e01b031981167f150b7a0200000000000000000000000000000000000000000000000000000000146135ba57604051633250574960e11b81526001600160a01b0385166004820152602401610f47565b505050505050565b606060006135cf83613ccc565b600101905060008167ffffffffffffffff8111156135ef576135ef614627565b6040519080825280601f01601f191660200182016040528015613619576020820181803683370190505b5090508181016020015b600019017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8504945084613623575b509392505050565b606060008361367184613dae565b61367b8786613166565b61368486613e13565b60405160200161369794939291906156c7565b60408051808303601f1901815291905295945050505050565b6060610c7582604051806060016040528060408152602001615a00604091396001613e9c565b6060816000036136fd5750506040805180820190915260018152600360fc1b602082015290565b8160005b811561372757806137118161483a565b91506137209050600a836148c7565b9150613701565b60008167ffffffffffffffff81111561374257613742614627565b6040519080825280601f01601f19166020018201604052801561376c576020820181803683370190505b509050815b85156138115761378260018261480b565b90506000613791600a886148c7565b61379c90600a61489a565b6137a6908861480b565b6137b19060306149a0565b905060008160f81b9050808484815181106137ce576137ce6148db565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350613808600a896148c7565b97505050613771565b50949350505050565b60006001600160e01b031982167f80ac58cd00000000000000000000000000000000000000000000000000000000148061387d57506001600160e01b031982167f5b5e139f00000000000000000000000000000000000000000000000000000000145b80610c7557507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614610c75565b6001600160a01b0382166138df57604051633250574960e11b815260006004820152602401610f47565b60006138ed83836000612bdb565b90506001600160a01b03811615611831576040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152602401610f47565b808061394757506001600160a01b03821615155b15613a4157600061395784612b95565b90506001600160a01b038316158015906139835750826001600160a01b0316816001600160a01b031614155b80156139b557506001600160a01b0380821660009081526005602090815260408083209387168352929052205460ff16155b156139f7576040517fa9fbf51f0000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610f47565b8115613a3f5783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b50506000908152600460205260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b600080613a8c85858561401c565b90506001600160a01b038116613ae957613ae484600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b613b0c565b846001600160a01b0316816001600160a01b031614613b0c57613b0c8185614122565b6001600160a01b038516613b2857613b23846141a3565b613b4b565b846001600160a01b0316816001600160a01b031614613b4b57613b4b8585614252565b949350505050565b6040805160208082018352600080835284815260198252839020835180850190945280546001600160a01b03168085526001909101549184019190915290919015613cc657613ba183611b0b565b6001600160a01b031681600001516001600160a01b0316636352211e83602001516040518263ffffffff1660e01b8152600401613be091815260200190565b602060405180830381865afa158015613bfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c219190614983565b6001600160a01b031603613cc657805160208201516040517fa2d6c6da0000000000000000000000000000000000000000000000000000000081526001600160a01b039092169163a2d6c6da91613c7e9160040190815260200190565b600060405180830381865afa158015613c9b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613cc391908101906155f2565b91505b50919050565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310613d15577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310613d41576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310613d5f57662386f26fc10000830492506010015b6305f5e1008310613d77576305f5e100830492506008015b6127108310613d8b57612710830492506004015b60648310613d9d576064830492506002015b600a8310610c755760010192915050565b606081613dd3576040518060600160405280602281526020016159bc60229139613ded565b6040518060600160405280602281526020016159de602291395b604051602001613dfd919061580f565b6040516020818303038152906040529050919050565b606081613e55576040518060400160405280600781526020017f2336363030303000000000000000000000000000000000000000000000000000815250613e8c565b6040518060400160405280600781526020017f23326538623537000000000000000000000000000000000000000000000000008152505b604051602001613dfd9190615913565b60608351600003613ebc5750604080516020810190915260008152612d3a565b600082613eed57600385516004613ed3919061489a565b613ede906002614887565b613ee891906148c7565b613f12565b600385516002613efd9190614887565b613f0791906148c7565b613f1290600461489a565b905060008167ffffffffffffffff811115613f2f57613f2f614627565b6040519080825280601f01601f191660200182016040528015613f59576020820181803683370190505b50905060018501602082018788518901602081018051600082525b82841015613fcf576003840193508351603f8160121c168701518653600186019550603f81600c1c168701518653600186019550603f8160061c168701518653600186019550603f8116870151865350600185019450613f74565b90525050851561401057600388510660018114613ff357600281146140065761400e565b603d6001830353603d600283035361400e565b603d60018303535b505b50909695505050505050565b6000828152600260205260408120546001600160a01b0390811690831615614049576140498184866142a2565b6001600160a01b0381161561408757614066600085600080613933565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b038516156140b6576001600160a01b0385166000908152600360205260409020805460010190555b600084815260026020526040808220805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b600061412d83611b16565b6000838152600760209081526040808320546001600160a01b038816845260069092529091209192509081831461418457600083815260208281526040808320548584528184208190558352600790915290208290555b6000938452600760209081526040808620869055938552525081205550565b6008546000906141b59060019061480b565b600083815260096020526040812054600880549394509092849081106141dd576141dd6148db565b9060005260206000200154905080600883815481106141fe576141fe6148db565b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480614236576142366159a5565b6001900381819060005260206000200160009055905550505050565b6000600161425f84611b16565b614269919061480b565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b6142ad83838361431f565b611831576001600160a01b0383166142db57604051637e27328960e01b815260048101829052602401610f47565b6040517f177e802f0000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260248101829052604401610f47565b60006001600160a01b03831615801590613b4b5750826001600160a01b0316846001600160a01b0316148061437957506001600160a01b0380851660009081526005602090815260408083209387168352929052205460ff165b80613b4b5750506000908152600460205260409020546001600160a01b03908116911614919050565b6001600160e01b031981168114610dae57600080fd5b6000602082840312156143ca57600080fd5b8135612d3a816143a2565b6000602082840312156143e757600080fd5b813563ffffffff81168114612d3a57600080fd5b60005b838110156144165781810151838201526020016143fe565b50506000910152565b600081518084526144378160208601602086016143fb565b601f01601f19169290920160200192915050565b602081526000612d3a602083018461441f565b60006020828403121561447057600080fd5b5035919050565b6001600160a01b0381168114610dae57600080fd5b6000806040838503121561449f57600080fd5b82356144aa81614477565b946020939093013593505050565b6000602082840312156144ca57600080fd5b8135612d3a81614477565b6000806000606084860312156144ea57600080fd5b83356144f581614477565b9250602084013561450581614477565b929592945050506040919091013590565b6000806040838503121561452957600080fd5b50508035926020909101359150565b60008060006060848603121561454d57600080fd5b83359250602084013561450581614477565b61ffff8c811682528b8116602083015260ff8b811660408401528a1660608301528815156080830152871660a082015261016081016145a360c083018860ff169052565b60ff861660e083015260ff851661010083015260ff84166101208301526001600160801b0383166101408301529c9b505050505050505050505050565b8015158114610dae57600080fd5b6000806040838503121561460157600080fd5b823561460c81614477565b9150602083013561461c816145e0565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051610160810167ffffffffffffffff8111828210171561466157614661614627565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561469057614690614627565b604052919050565b600067ffffffffffffffff8211156146b2576146b2614627565b50601f01601f191660200190565b60006146d36146ce84614698565b614667565b90508281528383830111156146e757600080fd5b828260208301376000602084830101529392505050565b6000806000806080858703121561471457600080fd5b843561471f81614477565b9350602085013561472f81614477565b925060408501359150606085013567ffffffffffffffff81111561475257600080fd5b8501601f8101871361476357600080fd5b614772878235602084016146c0565b91505092959194509250565b60006020828403121561479057600080fd5b813567ffffffffffffffff8111156147a757600080fd5b8201601f810184136147b857600080fd5b613b4b848235602084016146c0565b600080604083850312156147da57600080fd5b82356147e581614477565b9150602083013561461c81614477565b634e487b7160e01b600052601160045260246000fd5b81810381811115610c7557610c756147f5565b63ffffffff8281168282160390811115610c7557610c756147f5565b60006001820161484c5761484c6147f5565b5060010190565b600181811c9082168061486757607f821691505b602082108103613cc657634e487b7160e01b600052602260045260246000fd5b80820180821115610c7557610c756147f5565b8082028115828204841417610c7557610c756147f5565b634e487b7160e01b600052601260045260246000fd5b6000826148d6576148d66148b1565b500490565b634e487b7160e01b600052603260045260246000fd5b600060ff821660ff8103614907576149076147f5565b60010192915050565b600063ffffffff821663ffffffff8103614907576149076147f5565b602080825282518282018190526000918401906040840190835b81811015614964578351835260209384019390920191600101614946565b509095945050505050565b60008261497e5761497e6148b1565b500690565b60006020828403121561499557600080fd5b8151612d3a81614477565b60ff8181168382160190811115610c7557610c756147f5565b6000602082840312156149cb57600080fd5b5051919050565b600081516149e48185602086016143fb565b9290920192915050565b7f3c7376672076696577426f783d22302030203130323420313032342220786d6c81527f6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737667222060208201527f786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f72672f3160408201527f3939392f786c696e6b223e000000000000000000000000000000000000000000606082015260008251614a9881606b8501602087016143fb565b7f3c2f7376673e0000000000000000000000000000000000000000000000000000606b939091019283015250607101919050565b601f82111561183157806000526020600020601f840160051c81016020851015614af35750805b601f840160051c820191505b8181101561180f5760008155600101614aff565b815167ffffffffffffffff811115614b2d57614b2d614627565b614b4181614b3b8454614853565b84614acc565b6020601f821160018114614b755760008315614b5d5750848201515b600019600385901b1c1916600184901b17845561180f565b600084815260208120601f198516915b82811015614ba55787850151825560209485019460019092019101614b85565b5084821015614bc35786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b7f546865204d657267652054726565202300000000000000000000000000000000815260008251614c0a8160108501602087016143fb565b9190910160100192915050565b7f7d2c7b2274726169745f74797065223a22616e696d61746564222c2276616c7581526232911d60e91b602082015260008351614c5b8160238501602088016143fb565b7f7d2c7b2274726169745f74797065223a22636f6c6f725f7069636b6572222c226023918401918201527f76616c7565223a0000000000000000000000000000000000000000000000000060438201528351614cbe81604a8401602088016143fb565b01604a01949350505050565b7f7d2c7b2274726169745f74797065223a227365676d656e7473222c2276616c7581526232911d60e91b602082015260008451614d0e8160238501602089016143fb565b7f7d2c7b2274726169745f74797065223a227374616773222c2276616c7565223a6023918401918201528451614d4b8160438401602089016143fb565b6023818301019150507f7d2c7b2274726169745f74797065223a226861726573222c2276616c7565223a60208201528351614d8d8160408401602088016143fb565b0160400195945050505050565b7f222c2261747472696275746573223a5b7b2274726169745f74797065223a226981527f6e69744c656e677468222c2276616c7565223a00000000000000000000000000602082015260008751614df8816033850160208c016143fb565b7f7d2c7b2274726169745f74797065223a226469616d65746572222c2276616c756033918401918201526232911d60e91b60538201528751614e41816056840160208c016143fb565b6033818301019150507f7d2c7b2274726169745f74797065223a226272616e63686573222c2276616c7560238201526232911d60e91b6043820152614f28614f22614ef9614ef3614eca614ec4614e9b604688018e6149d2565b7f7d2c7b2274726169745f74797065223a22616e676c65222c2276616c7565223a815260200190565b8b6149d2565b7f7d2c7b2274726169745f74797065223a2244222c2276616c7565223a000000008152601c0190565b886149d2565b7f7d2c7b2274726169745f74797065223a2264656c7461222c2276616c7565223a815260200190565b856149d2565b9998505050505050505050565b60008451614f478184602089016143fb565b845190830190614f5b8183602089016143fb565b8451910190614f6e8183602088016143fb565b0195945050505050565b7f7b226e616d65223a220000000000000000000000000000000000000000000000815260008651614fb0816009850160208b016143fb565b7f222c226465736372697074696f6e223a220000000000000000000000000000006009918401918201528651614fed81601a840160208b016143fb565b6009818301019150507f222c2265787465726e616c5f75726c223a2268747470733a2f2f7468656d657260118201527f676574726565732e78797a2f74726565732f000000000000000000000000000060318201528551615055816043840160208a016143fb565b60118183010191505084516150718160328401602089016143fb565b614f286150db6150d56150ac6032858701017f7d5d2c22696d616765223a2200000000000000000000000000000000000000008152600c0190565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c0000000000008152601a0190565b876149d2565b7f227d000000000000000000000000000000000000000000000000000000000000815260020190565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081526000825161513c81601d8501602087016143fb565b91909101601d0192915050565b7f697066733a2f2f000000000000000000000000000000000000000000000000008152600080835461517a81614853565b60018216801561519157600181146151ac576151e2565b60ff19831660078701526007821515830287010193506151e2565b86600052602060002060005b838110156151d7578154888201600701526001909101906020016151b8565b505060078287010193505b509195945050505050565b805161ffff811681146151ff57600080fd5b919050565b805160ff811681146151ff57600080fd5b80516151ff816145e0565b80516001600160801b03811681146151ff57600080fd5b600061016082840312801561524b57600080fd5b5061525461463d565b61525d836151ed565b815261526b602084016151ed565b602082015261527c60408401615204565b604082015261528d60608401615204565b606082015261529e60808401615215565b60808201526152af60a084016151ed565b60a08201526152c060c08401615204565b60c08201526152d160e08401615204565b60e08201526152e36101008401615204565b6101008201526152f66101208401615204565b6101208201526153096101408401615220565b6101408201529392505050565b805161ffff1682526020810151615333602084018261ffff169052565b506040810151615348604084018260ff169052565b50606081015161535d606084018260ff169052565b506080810151615371608084018215159052565b5060a081015161538760a084018261ffff169052565b5060c081015161539c60c084018260ff169052565b5060e08101516153b160e084018260ff169052565b506101008101516153c861010084018260ff169052565b506101208101516153df61012084018260ff169052565b506101408101516118316101408401826001600160801b03169052565b6101608101610c758284615316565b60ff8281168282160390811115610c7557610c756147f5565b828152815461ffff81166020830152610180820190601081901c61ffff166040840152602081901c60ff166060840152602881901c60ff16608084015261547560a0840160ff8360301c1615159052565b603881901c61ffff1660c0840152604881901c60ff1660e0840152605081901c60ff16610100840152605881901c60ff16610120840152606081901c60ff16610140840152606881901c6001600160801b031661016084015261365b565b7f3c7465787420646f6d696e616e742d626173656c696e653d226d6964646c652281527f20746578742d616e63686f723d226d6964646c652220783d223530252220793d60208201527f223530252220666f6e742d73697a653d2235303025222066696c6c3d2223000060408201526000825161555781605e8501602087016143fb565b7f3c2f746578743e00000000000000000000000000000000000000000000000000605e939091019283015250606501919050565b63ffffffff8181168382160190811115610c7557610c756147f5565b6155b18187615316565b63ffffffff8516610160820152836101808201528215156101a08201526101e06101c082015260006155e76101e083018461441f565b979650505050505050565b60006020828403121561560457600080fd5b815167ffffffffffffffff81111561561b57600080fd5b8201601f8101841361562c57600080fd5b805161563a6146ce82614698565b81815285602083850101111561564f57600080fd5b6156608260208301602086016143fb565b95945050505050565b6001600160a01b03851681526001600160a01b03841660208201528260408201526080606082015260006156a0608083018461441f565b9695505050505050565b6000602082840312156156bc57600080fd5b8151612d3a816143a2565b7f3c7376672076696577426f783d22302030203130323420313032342220786d6c81527f6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737667222060208201527f786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f72672f3160408201527f3939392f786c696e6b223e3c7469746c653e0000000000000000000000000000606082015260008551615771816072850160208a016143fb565b7f3c2f7469746c653e00000000000000000000000000000000000000000000000060729184019182015285516157ae81607a840160208a016143fb565b60728183010191505084516157ca8160088401602089016143fb565b84519101600801906157e08183602088016143fb565b61345a8183017f3c2f7376673e0000000000000000000000000000000000000000000000000000815260060190565b7f3c646566733e3c6c696e6561724772616469656e742069643d22736b7922206781527f72616469656e745472616e73666f726d3d22726f7461746528393029223e3c7360208201527f746f702073746f702d636f6c6f723d22230000000000000000000000000000006040820152600082516158938160518501602087016143fb565b7f22206f66667365743d22363625222f3e3c2f6c696e6561724772616469656e7460519390910192830152507f3e3c2f646566733e3c726563742077696474683d22313032342220686569676860718201527f743d2231303234222066696c6c3d2275726c2823736b7929222f3e0000000000609182015260ac01919050565b7f3c726563742077696474683d223130323422206865696768743d22323422207981527f3d2231303030222066696c6c3d2200000000000000000000000000000000000060208201526000825161597181602e8501602087016143fb565b7f222f3e0000000000000000000000000000000000000000000000000000000000602e939091019283015250603101919050565b634e487b7160e01b600052603160045260246000fdfe666666376564222f3e3c73746f702073746f702d636f6c6f723d2223666564376161626165366664222f3e3c73746f702073746f702d636f6c6f723d22236630663966664142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa26469706673582212207721b3c9174ae1873e8f0fd57129ec289a8f0f643425aaea69de55032df4c52364736f6c634300081c00336261666b7265696536726a69746568687137337963646468377134626f6a6e746f62693378657634656c6f69347271666e6c687775796a33747165000000000000000000000000570a07c430d637990591f5288e7959ce94e3a9230000000000000000000000000333232cc77f8c0bc2287a7b248ed3f5aba5234e0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000f8f32794db9185593890b8c10dce025788b133fb
Deployed Bytecode
0x60806040526004361061038c5760003560e01c80635f295a67116101dc578063a22cb46511610102578063d50b31eb116100a0578063f33ae73a1161006f578063f33ae73a14610b5a578063f8e5802414610b6f578063fb0bbb0514610b85578063fe98248a14610b9b57600080fd5b8063d50b31eb14610abc578063e8a3d48514610adc578063e985e9c514610af1578063f2fde38b14610b3a57600080fd5b8063baedc1c4116100dc578063baedc1c414610a13578063c87b56dd14610a33578063c8fc0c2314610a53578063ca78533d14610a7457600080fd5b8063a22cb465146109b3578063a2d6c6da146109d3578063b88d4fde146109f357600080fd5b80637a5080221161017a57806390486b451161014957806390486b451461094d57806391a53eee1461096357806395d89b41146109835780639b7ccd6c1461099857600080fd5b80637a508022146108135780637fedbbac146108fc57806380d5ded51461091c5780638da5cb5b1461092f57600080fd5b8063684931ed116101b6578063684931ed1461079e57806370a08231146107be578063715018a6146107de57806375c14292146107f357600080fd5b80635f295a671461074d57806362747679146107625780636352211e1461077e57600080fd5b806322c3a117116102c157806342842e0e1161025f5780634f6ccce71161022e5780634f6ccce7146106e2578063502ae84d146107025780635aa1d0ce146107185780635dad667c1461072d57600080fd5b806342842e0e1461066857806342966c681461068857806349f4ff99146106a85780634e9827ef146106c857600080fd5b80632f745c591161029b5780632f745c59146105f35780633ccfd60b14610613578063403b58b014610628578063411b007e1461064857600080fd5b806322c3a1171461056757806323b872dd146105945780632a55205a146105b457600080fd5b806318160ddd1161032e578063201afd8311610308578063201afd83146104e857806320a479711461050857806320a8480f1461051d57806321615f6e1461053357600080fd5b806318160ddd1461048d5780631d2ada7e146104a25780631e73cea2146104b857600080fd5b8063081812fc1161036a578063081812fc1461040a578063095ea7b31461044257806311f07544146104625780631249c58b1461048557600080fd5b806301ffc9a71461039157806304951891146103c657806306fdde03146103e8575b600080fd5b34801561039d57600080fd5b506103b16103ac3660046143b8565b610bcf565b60405190151581526020015b60405180910390f35b3480156103d257600080fd5b506103e66103e13660046143d5565b610c7b565b005b3480156103f457600080fd5b506103fd610db1565b6040516103bd919061444b565b34801561041657600080fd5b5061042a61042536600461445e565b610e43565b6040516001600160a01b0390911681526020016103bd565b34801561044e57600080fd5b506103e661045d36600461448c565b610e6c565b34801561046e57600080fd5b50610477600c81565b6040519081526020016103bd565b610477610e7b565b34801561049957600080fd5b50600854610477565b3480156104ae57600080fd5b5061047760165481565b3480156104c457600080fd5b506103b16104d33660046144b8565b60186020526000908152604090205460ff1681565b3480156104f457600080fd5b506103e66105033660046144b8565b610fc8565b34801561051457600080fd5b5061047761106e565b34801561052957600080fd5b506104776113ec81565b34801561053f57600080fd5b506104777f00000000000000000000000000000000000000000000000000000000014b3da081565b34801561057357600080fd5b5061047761058236600461445e565b60156020526000908152604090205481565b3480156105a057600080fd5b506103e66105af3660046144d5565b611106565b3480156105c057600080fd5b506105d46105cf366004614516565b6111aa565b604080516001600160a01b0390931683526020830191909152016103bd565b3480156105ff57600080fd5b5061047761060e36600461448c565b6111e2565b34801561061f57600080fd5b506103e6611260565b34801561063457600080fd5b506103e661064336600461445e565b61137a565b34801561065457600080fd5b50600d5461042a906001600160a01b031681565b34801561067457600080fd5b506103e66106833660046144d5565b611816565b34801561069457600080fd5b506103e66106a336600461445e565b611836565b3480156106b457600080fd5b506103e66106c336600461445e565b61190c565b3480156106d457600080fd5b506011546103b19060ff1681565b3480156106ee57600080fd5b506104776106fd36600461445e565b611949565b34801561070e57600080fd5b5061047760135481565b34801561072457600080fd5b506103e66119bb565b34801561073957600080fd5b506103e661074836600461445e565b6119ce565b34801561075957600080fd5b506103e6611a66565b34801561076e57600080fd5b50610477670100f7c0749aa00081565b34801561078a57600080fd5b5061042a61079936600461445e565b611b0b565b3480156107aa57600080fd5b50600e5461042a906001600160a01b031681565b3480156107ca57600080fd5b506104776107d93660046144b8565b611b16565b3480156107ea57600080fd5b506103e6611b77565b3480156107ff57600080fd5b506103e661080e366004614538565b611b8b565b34801561081f57600080fd5b506108e561082e36600461445e565b600f6020526000908152604090205461ffff8082169162010000810482169160ff640100000000830481169265010000000000810482169266010000000000008204831692670100000000000000830490911691690100000000000000000081048216916a010000000000000000000082048116916b01000000000000000000000081048216916c01000000000000000000000000820416906001600160801b036d0100000000000000000000000000909104168b565b6040516103bd9b9a9998979695949392919061455f565b34801561090857600080fd5b506103e661091736600461445e565b611d6f565b6103e661092a36600461445e565b611dac565b34801561093b57600080fd5b50600a546001600160a01b031661042a565b34801561095957600080fd5b5061047760145481565b34801561096f57600080fd5b506103e661097e3660046145ee565b61201e565b34801561098f57600080fd5b506103fd61214a565b3480156109a457600080fd5b506104776601b68eefb5f00081565b3480156109bf57600080fd5b506103e66109ce3660046145ee565b612159565b3480156109df57600080fd5b506103fd6109ee36600461445e565b612164565b3480156109ff57600080fd5b506103e6610a0e3660046146fe565b6121e6565b348015610a1f57600080fd5b506103e6610a2e36600461477e565b6121fe565b348015610a3f57600080fd5b506103fd610a4e36600461445e565b612212565b348015610a5f57600080fd5b50600e546103b190600160a01b900460ff1681565b348015610a8057600080fd5b50610aa7610a8f3660046144b8565b60176020526000908152604090205463ffffffff1681565b60405163ffffffff90911681526020016103bd565b348015610ac857600080fd5b506103e6610ad73660046144b8565b61263e565b348015610ae857600080fd5b506103fd6126e5565b348015610afd57600080fd5b506103b1610b0c3660046147c7565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b348015610b4657600080fd5b506103e6610b553660046144b8565b61270d565b348015610b6657600080fd5b50610477606781565b348015610b7b57600080fd5b5061047760105481565b348015610b9157600080fd5b5061047760125481565b348015610ba757600080fd5b506104777f000000000000000000000000000000000000000000000000000000000000000381565b60006001600160e01b031982167f2a55205a000000000000000000000000000000000000000000000000000000001480610c3257506001600160e01b031982167fa2d6c6da00000000000000000000000000000000000000000000000000000000145b80610c6657506001600160e01b031982167f4906490600000000000000000000000000000000000000000000000000000000145b80610c755750610c7582612761565b92915050565b3360009081526017602052604090205463ffffffff1615801590610cb857503360009081526017602052604090205463ffffffff90811690821611155b15610d7c578063ffffffff1660166000828254610cd5919061480b565b909155505033600090815260176020526040902054610cfb90829063ffffffff1661481e565b33600090815260176020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff9390931692909217909155600b54905b8263ffffffff168163ffffffff161015610d7557610d6c3383610d658161483a565b945061279f565b50600101610d43565b50600b5550565b6040517f969bf72800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b606060008054610dc090614853565b80601f0160208091040260200160405190810160405280929190818152602001828054610dec90614853565b8015610e395780601f10610e0e57610100808354040283529160200191610e39565b820191906000526020600020905b815481529060010190602001808311610e1c57829003601f168201915b5050505050905090565b6000610e4e82612b95565b506000828152600460205260409020546001600160a01b0316610c75565b610e77828233612bce565b5050565b60115460009060ff16158015610e9357506067600b54105b15610f96577f0000000000000000000000000000000000000000000000000000000000000003610ec233611b16565b10610ef9576040517f328d3cba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b670100f7c0749aa000341015610f50576040517fde759846000000000000000000000000000000000000000000000000000000008152670100f7c0749aa00060048201523460248201526044015b60405180910390fd5b610f5c6001606761480b565b600b5410610f72576011805460ff191660011790555b600b8054610f91913391906000610f888361483a565b9190505561279f565b905090565b6040517fa52c466000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d546001600160a01b0316331461100c576040517fac2308c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081527f5f952e8714912176e13b8b0673378185e6540e5a1f0c430884b1da9253bae152906020015b60405180910390a150565b6000808061107b60085490565b905060005b818110156110db576000818152600f6020526040902054600664010000000090910460ff16108015906110c0575060008181526015602052604090205443115b156110d357826110cf8161483a565b9350505b600101611080565b506016546110e99082614887565b6110f58361271061489a565b6110ff91906148c7565b9250505090565b6001600160a01b03821661113057604051633250574960e11b815260006004820152602401610f47565b600061113d838333612bdb565b9050836001600160a01b0316816001600160a01b0316146111a4576040517f64283d7b0000000000000000000000000000000000000000000000000000000081526001600160a01b0380861660048301526024820184905282166044820152606401610f47565b50505050565b6000806111bf600a546001600160a01b031690565b6127106111cd85600061489a565b6111d791906148c7565b915091509250929050565b60006111ed83611b16565b8210611237576040517fa57d13dc0000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260248101839052604401610f47565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b600d546001600160a01b031633148015906112865750600a546001600160a01b03163314155b156112bd576040517fac2308c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d546040516000916001600160a01b03169047908381818185875af1925050503d806000811461130a576040519150601f19603f3d011682016040523d82523d6000602084013e61130f565b606091505b5050905080610dae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5472616e73666572206661696c65642e000000000000000000000000000000006044820152606401610f47565b60115460ff166113b6576040517fa38ee6e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113bf81611b0b565b6001600160a01b0316336001600160a01b0316146113f057604051631022318760e21b815260040160405180910390fd5b6000818152600f6020526040902054600664010000000090910460ff161015611445576040517f9e6153fd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061145060085490565b905060008167ffffffffffffffff81111561146d5761146d614627565b604051908082528060200260200182016040528015611496578160200160208202803683370190505b5090506000805b8381101561154d576000818152600f6020526040902054600664010000000090910460ff16106115095760008181526015602052604090205443111561150957808383815181106114f0576114f06148db565b6020908102919091010152816115058161483a565b9250505b60008181526015602052604090205415611545576000818152600f60209081526040808320805466ff0000000000001916905560159091528120555b60010161149d565b5060006016548461155e9190614887565b61156a8361271061489a565b61157491906148c7565b90506113ec8111156117da5760008267ffffffffffffffff81111561159b5761159b614627565b6040519080825280602002602001820160405280156115c4578160200160208202803683370190505b509050826016546115d59190614887565b601655600060128190555b83811015611751578481815181106115fa576115fa6148db565b6020026020010151828281518110611614576116146148db565b6020026020010181815250506001600f6000878481518110611638576116386148db565b6020026020010151815260200190815260200160002060000160046101000a81548160ff021916908360ff160217905550600f600086838151811061167f5761167f6148db565b602090810291909101810151825281019190915260400160002080546b010000000000000000000000900460ff1690600b6116b9836148f1565b91906101000a81548160ff021916908360ff16021790555050601760006116f88784815181106116eb576116eb6148db565b6020026020010151611b0b565b6001600160a01b0316815260208101919091526040016000908120805463ffffffff169161172583614910565b91906101000a81548163ffffffff021916908363ffffffff1602179055505080806001019150506115e0565b507f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c60006001600b54611784919061480b565b6040805192835260208301919091520160405180910390a1857f91d97924a4649f48d15ce92530886b3ccce4e916bc90ec1566ae1e0d91dcdf3d826040516117cc919061492c565b60405180910390a25061180f565b6040517f3a83c94500000000000000000000000000000000000000000000000000000000815260048101829052602401610f47565b5050505050565b611831838383604051806020016040528060008152506121e6565b505050565b61183f81611b0b565b6001600160a01b0316336001600160a01b03161461187057604051631022318760e21b815260040160405180910390fd5b61187981612d41565b6000818152600f6020908152604080832080547fffffff000000000000000000000000000000000000000000000000000000000016905560198252808320805473ffffffffffffffffffffffffffffffffffffffff1916815560010183905560159091528082208290555182917f46528d92bcf2945ce329208a44d1bb48172cc09d5d03d44450072c1371f5affb91a250565b611914612d7c565b60138190556040518181527ffe371b3c294b50939cb7d062668a0e2cee39975006d8513d4bafe1e86e3b41a990602001611063565b600061195460085490565b8210611996576040517fa57d13dc0000000000000000000000000000000000000000000000000000000081526000600482015260248101839052604401610f47565b600882815481106119a9576119a96148db565b90600052602060002001549050919050565b6119c3612d7c565b64ff0b6623ff601055565b6119d781611b0b565b6001600160a01b0316336001600160a01b031614611a0857604051631022318760e21b815260040160405180910390fd5b611a13600c8261496f565b15611a4a576040517ffee4821d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a55600c826148c7565b6001901b6010541860108190555050565b611a6e612d7c565b600e54600160a01b900460ff1615611ab2576040517f7d6257d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16600160a01b1790556040517ff59561f22794afcfb1e6be5c4733f5449fd167252a96b74bb06d341fb0dac7ed90600090a1565b6000610c7582612b95565b60006001600160a01b038216611b5b576040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152602401610f47565b506001600160a01b031660009081526003602052604090205490565b611b7f612d7c565b611b896000612dc2565b565b6001600160a01b03821660009081526018602052604090205460ff16611bdd576040517f7d7f3db300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611be683611b0b565b6001600160a01b0316336001600160a01b0316141580611c9957506040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018290526001600160a01b03831690636352211e90602401602060405180830381865afa158015611c5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c839190614983565b6001600160a01b0316336001600160a01b031614155b15611cb757604051631022318760e21b815260040160405180910390fd5b6040805180820182526001600160a01b03848116825260208083018581526000888152601983528590209351845473ffffffffffffffffffffffffffffffffffffffff19169316929092178355905160019092019190915590518481527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7910160405180910390a160405183907f49251b4fc49c7a77c5701bd8b2988d065e1741d507ce2a3a796200f46b3b220590600090a2505050565b611d77612d7c565b60148190556040518181527f10211f882638170b5cb679ca2d39a16fca322a439ac4bc20872572b03fb75d1090602001611063565b60115460ff16611de8576040517fa38ee6e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611df181611b0b565b6001600160a01b0316336001600160a01b031614611e2257604051631022318760e21b815260040160405180910390fd5b6000611e2d60085490565b6000838152600f60205260409020546601b68eefb5f00090611e63906c01000000000000000000000000900460ff1660016149a0565b60ff16611e70919061489a565b611e7a919061489a565b905080341015611ebf576040517fde75984600000000000000000000000000000000000000000000000000000000815260048101829052346024820152604401610f47565b601254600003611ede57601454611ed69043614887565b601255611ef2565b601454601254611eee9190614887565b6012555b601254600083815260156020908152604080832093909355600f90522080546c01000000000000000000000000900460ff1690600c611f30836148f1565b91906101000a81548160ff021916908360ff160217905550506000611f6c3384600b6000815480929190611f639061483a565b91905055612e21565b6000848152600f60209081526040808320805466ff000000000000191666010000000000001790556012548484526015909252822055600b549192507f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91611fd69060019061480b565b6040805192835260208301919091520160405180910390a160405183907f3c33d341350cfc092f5fb4dd226ea61549e742eb7487dc9a1d386a1eac8118b390600090a2505050565b612026612d7c565b600d546040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526003918416906370a0823190602401602060405180830381865afa15801561208b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120af91906149b9565b10156120e7576040517ff840408600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038216600081815260186020908152604091829020805460ff19168515159081179091558251938452908301527fa56a0776bcbac9c44610bf91448131516d7be439d528c569ad2a43a91e23259a910160405180910390a15050565b606060018054610dc090614853565b610e773383836130ae565b6000818152600260205260409020546060906001600160a01b031661219f57604051637e27328960e01b815260048101839052602401610f47565b6000601254600014806121b3575060125443115b90506121bf8382613166565b6040516020016121cf91906149ee565b604051602081830303815290604052915050919050565b6121f1848484611106565b6111a43385858585613466565b612206612d7c565b600c610e778282614b13565b6000818152600260205260409020546060906001600160a01b031661224d57604051637e27328960e01b815260048101839052602401610f47565b6000828152600f60209081526040808320815161016081018352905461ffff8082168352620100008204811694830194909452640100000000810460ff908116938301939093526501000000000081048316606083015266010000000000008104831615156080830152670100000000000000810490931660a082015269010000000000000000008304821660c08201526a01000000000000000000008304821660e08201526b010000000000000000000000830482166101008201526c0100000000000000000000000083049091166101208201526d01000000000000000000000000009091046001600160801b03166101408201529061234e846135c2565b60405160200161235e9190614bd2565b6040516020818303038152906040529050600060125460001480612383575060125443115b9050606081156123cf576040517f412062656175746966756c2067726f77696e67207472656500000000000000006020820152603801604051602081830303815290604052905061240d565b6040517f41206465636c696e696e67207472656500000000000000000000000000000000602082015260300160405160208183030381529060405290505b600061242261241d888686613663565b6136b0565b90506000856080015161244e57604051806040016040528060018152602001600360fc1b815250612469565b604051806040016040528060018152602001603160f81b8152505b612474600c8a61496f565b1561249857604051806040016040528060018152602001600360fc1b8152506124b3565b604051806040016040528060018152602001603160f81b8152505b6040516020016124c4929190614c17565b604051602081830303815290604052905060006124e7876040015160ff166136d6565b6124f888610100015160ff166136d6565b61250989610120015160ff166136d6565b60405160200161251b93929190614cca565b6040516020818303038152906040529050600061253f886000015161ffff166136d6565b612550896020015161ffff166136d6565b6125608a6060015160ff166136d6565b6125718b60a0015161ffff166136d6565b6125818c60c0015160ff166136d6565b6125918d60e0015160ff166136d6565b6040516020016125a696959493929190614d9a565b60408051601f19818403018152908290526125c79185908590602001614f35565b604051602081830303815290604052905061261087866125e68d6135c2565b84886040516020016125fc959493929190614f78565b6040516020818303038152906040526136b0565b6040516020016126209190615104565b60405160208183030381529060405298505050505050505050919050565b612646612d7c565b600e54600160a01b900460ff161561268a576040517f7d6257d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081527fb3025222d01ce9a26c7f9d52bc3bfd0352366bd90a793c273fbfe1c81e0e288e90602001611063565b6060600c6040516020016126f99190615149565b604051602081830303815290604052905090565b612715612d7c565b6001600160a01b038116612758576040517f1e4fbdf700000000000000000000000000000000000000000000000000000000815260006004820152602401610f47565b610dae81612dc2565b60006001600160e01b031982167f780e9d63000000000000000000000000000000000000000000000000000000001480610c755750610c758261381a565b600e546040517f0f642e79000000000000000000000000000000000000000000000000000000008152600481018390527f00000000000000000000000000000000000000000000000000000000014b3da0602482015260009182916001600160a01b0390911690630f642e799060440161016060405180830381865afa15801561282d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128519190615237565b600f600085815260200190815260200160002060008201518160000160006101000a81548161ffff021916908361ffff16021790555060208201518160000160026101000a81548161ffff021916908361ffff16021790555060408201518160000160046101000a81548160ff021916908360ff16021790555060608201518160000160056101000a81548160ff021916908360ff16021790555060808201518160000160066101000a81548160ff02191690831515021790555060a08201518160000160076101000a81548161ffff021916908361ffff16021790555060c08201518160000160096101000a81548160ff021916908360ff16021790555060e082015181600001600a6101000a81548160ff021916908360ff16021790555061010082015181600001600b6101000a81548160ff021916908360ff16021790555061012082015181600001600c6101000a81548160ff021916908360ff16021790555061014082015181600001600d6101000a8154816001600160801b0302191690836001600160801b031602179055509050604051806101600160405290816000820160009054906101000a900461ffff1661ffff1661ffff1681526020016000820160029054906101000a900461ffff1661ffff1661ffff1681526020016000820160049054906101000a900460ff1660ff1660ff1681526020016000820160059054906101000a900460ff1660ff1660ff1681526020016000820160069054906101000a900460ff161515151581526020016000820160079054906101000a900461ffff1661ffff1661ffff1681526020016000820160099054906101000a900460ff1660ff1660ff16815260200160008201600a9054906101000a900460ff1660ff1660ff16815260200160008201600b9054906101000a900460ff1660ff1660ff16815260200160008201600c9054906101000a900460ff1660ff1660ff16815260200160008201600d9054906101000a90046001600160801b03166001600160801b03166001600160801b0316815250509050612b5584846138b5565b827f10ca4a29cf8444f5e8a109a26a3724a6e6d54c9c83d5b4c240f474f8e1910d6282604051612b8591906153fc565b60405180910390a2509092915050565b6000818152600260205260408120546001600160a01b031680610c7557604051637e27328960e01b815260048101849052602401610f47565b6118318383836001613933565b60008060125460001480612bf0575060125443115b90508015612c7a576000848152600f6020526040902054600664010000000090910460ff161015612c45576000848152600f6020526040902054612c4090640100000000900460ff1660016149a0565b612c48565b60065b6000858152600f60205260409020805460ff929092166401000000000264ff0000000019909216919091179055612cf8565b6000848152600f6020526040902054600264010000000090910460ff1610612cc7576000848152600f6020526040902054612cc290600190640100000000900460ff1661540b565b612cca565b60005b6000858152600f60205260409020805460ff929092166401000000000264ff00000000199092169190911790555b6040518481527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a1612d36858585613a7e565b9150505b9392505050565b6000612d506000836000612bdb565b90506001600160a01b038116610e7757604051637e27328960e01b815260048101839052602401610f47565b600a546001600160a01b03163314611b89576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401610f47565b600a80546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600e546000838152600f602052604080822090517fb15e400400000000000000000000000000000000000000000000000000000000815291926001600160a01b03169163b15e400491612e99917f00000000000000000000000000000000000000000000000000000000014b3da09190600401615424565b61016060405180830381865afa158015612eb7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612edb9190615237565b600f600084815260200190815260200160002060008201518160000160006101000a81548161ffff021916908361ffff16021790555060208201518160000160026101000a81548161ffff021916908361ffff16021790555060408201518160000160046101000a81548160ff021916908360ff16021790555060608201518160000160056101000a81548160ff021916908360ff16021790555060808201518160000160066101000a81548160ff02191690831515021790555060a08201518160000160076101000a81548161ffff021916908361ffff16021790555060c08201518160000160096101000a81548160ff021916908360ff16021790555060e082015181600001600a6101000a81548160ff021916908360ff16021790555061010082015181600001600b6101000a81548160ff021916908360ff16021790555061012082015181600001600c6101000a81548160ff021916908360ff16021790555061014082015181600001600d6101000a8154816001600160801b0302191690836001600160801b0316021790555090505061307a84836138b5565b604051829084907f694caf5e0a9f144c344d2e9ffb42f0c73fb313bcfab97d9689f551c7eb990fb690600090a35092915050565b6001600160a01b0382166130f9576040517f5b08ba180000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610f47565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000828152600f6020908152604091829020825161016081018452905461ffff808216835262010000820481169383019390935260ff64010000000082048116948301859052650100000000008204811660608481019190915266010000000000008304821615156080850152670100000000000000830490941660a084015269010000000000000000008204811660c08401526a01000000000000000000008204811660e08401526b010000000000000000000000820481166101008401526c010000000000000000000000008204166101208301526001600160801b036d01000000000000000000000000009091041661014082015290916002111561330657826132a8576040518060400160405280601c81526020017f363630303030223e4572797369636874686f6e207761732068657265000000008152506132df565b6040518060400160405280601d81526020017f303036363136223e53706573206d657373697320696e2073656d696e650000008152505b6040516020016132ef91906154d3565b604051602081830303815290604052915050610c75565b6101408101516000906001600160801b03166133427f00000000000000000000000000000000000000000000000000000000014b3da04361480b565b61334c919061480b565b905060006013548261335e91906148c7565b90508461339a57601254601354613375919061489a565b43601254613383919061480b565b61338d908461489a565b61339791906148c7565b90505b82516000906133ae90839061ffff1661558b565b9050600060e363ffffffff831610156133c757816133ca565b60e35b90507368e9f40244b628f08e20f5a0cd37d205095f36c363b17c978d86836010548b6133f58e613b53565b6040518663ffffffff1660e01b81526004016134159594939291906155a7565b600060405180830381865af4158015613432573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261345a91908101906155f2565b98975050505050505050565b6001600160a01b0383163b1561180f576040517f150b7a020000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063150b7a02906134c1908890889087908790600401615669565b6020604051808303816000875af19250505080156134fc575060408051601f3d908101601f191682019092526134f9918101906156aa565b60015b613565573d80801561352a576040519150601f19603f3d011682016040523d82523d6000602084013e61352f565b606091505b50805160000361355d57604051633250574960e11b81526001600160a01b0385166004820152602401610f47565b805181602001fd5b6001600160e01b031981167f150b7a0200000000000000000000000000000000000000000000000000000000146135ba57604051633250574960e11b81526001600160a01b0385166004820152602401610f47565b505050505050565b606060006135cf83613ccc565b600101905060008167ffffffffffffffff8111156135ef576135ef614627565b6040519080825280601f01601f191660200182016040528015613619576020820181803683370190505b5090508181016020015b600019017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8504945084613623575b509392505050565b606060008361367184613dae565b61367b8786613166565b61368486613e13565b60405160200161369794939291906156c7565b60408051808303601f1901815291905295945050505050565b6060610c7582604051806060016040528060408152602001615a00604091396001613e9c565b6060816000036136fd5750506040805180820190915260018152600360fc1b602082015290565b8160005b811561372757806137118161483a565b91506137209050600a836148c7565b9150613701565b60008167ffffffffffffffff81111561374257613742614627565b6040519080825280601f01601f19166020018201604052801561376c576020820181803683370190505b509050815b85156138115761378260018261480b565b90506000613791600a886148c7565b61379c90600a61489a565b6137a6908861480b565b6137b19060306149a0565b905060008160f81b9050808484815181106137ce576137ce6148db565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350613808600a896148c7565b97505050613771565b50949350505050565b60006001600160e01b031982167f80ac58cd00000000000000000000000000000000000000000000000000000000148061387d57506001600160e01b031982167f5b5e139f00000000000000000000000000000000000000000000000000000000145b80610c7557507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614610c75565b6001600160a01b0382166138df57604051633250574960e11b815260006004820152602401610f47565b60006138ed83836000612bdb565b90506001600160a01b03811615611831576040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152602401610f47565b808061394757506001600160a01b03821615155b15613a4157600061395784612b95565b90506001600160a01b038316158015906139835750826001600160a01b0316816001600160a01b031614155b80156139b557506001600160a01b0380821660009081526005602090815260408083209387168352929052205460ff16155b156139f7576040517fa9fbf51f0000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610f47565b8115613a3f5783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b50506000908152600460205260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b600080613a8c85858561401c565b90506001600160a01b038116613ae957613ae484600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b613b0c565b846001600160a01b0316816001600160a01b031614613b0c57613b0c8185614122565b6001600160a01b038516613b2857613b23846141a3565b613b4b565b846001600160a01b0316816001600160a01b031614613b4b57613b4b8585614252565b949350505050565b6040805160208082018352600080835284815260198252839020835180850190945280546001600160a01b03168085526001909101549184019190915290919015613cc657613ba183611b0b565b6001600160a01b031681600001516001600160a01b0316636352211e83602001516040518263ffffffff1660e01b8152600401613be091815260200190565b602060405180830381865afa158015613bfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c219190614983565b6001600160a01b031603613cc657805160208201516040517fa2d6c6da0000000000000000000000000000000000000000000000000000000081526001600160a01b039092169163a2d6c6da91613c7e9160040190815260200190565b600060405180830381865afa158015613c9b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613cc391908101906155f2565b91505b50919050565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310613d15577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310613d41576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310613d5f57662386f26fc10000830492506010015b6305f5e1008310613d77576305f5e100830492506008015b6127108310613d8b57612710830492506004015b60648310613d9d576064830492506002015b600a8310610c755760010192915050565b606081613dd3576040518060600160405280602281526020016159bc60229139613ded565b6040518060600160405280602281526020016159de602291395b604051602001613dfd919061580f565b6040516020818303038152906040529050919050565b606081613e55576040518060400160405280600781526020017f2336363030303000000000000000000000000000000000000000000000000000815250613e8c565b6040518060400160405280600781526020017f23326538623537000000000000000000000000000000000000000000000000008152505b604051602001613dfd9190615913565b60608351600003613ebc5750604080516020810190915260008152612d3a565b600082613eed57600385516004613ed3919061489a565b613ede906002614887565b613ee891906148c7565b613f12565b600385516002613efd9190614887565b613f0791906148c7565b613f1290600461489a565b905060008167ffffffffffffffff811115613f2f57613f2f614627565b6040519080825280601f01601f191660200182016040528015613f59576020820181803683370190505b50905060018501602082018788518901602081018051600082525b82841015613fcf576003840193508351603f8160121c168701518653600186019550603f81600c1c168701518653600186019550603f8160061c168701518653600186019550603f8116870151865350600185019450613f74565b90525050851561401057600388510660018114613ff357600281146140065761400e565b603d6001830353603d600283035361400e565b603d60018303535b505b50909695505050505050565b6000828152600260205260408120546001600160a01b0390811690831615614049576140498184866142a2565b6001600160a01b0381161561408757614066600085600080613933565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b038516156140b6576001600160a01b0385166000908152600360205260409020805460010190555b600084815260026020526040808220805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b600061412d83611b16565b6000838152600760209081526040808320546001600160a01b038816845260069092529091209192509081831461418457600083815260208281526040808320548584528184208190558352600790915290208290555b6000938452600760209081526040808620869055938552525081205550565b6008546000906141b59060019061480b565b600083815260096020526040812054600880549394509092849081106141dd576141dd6148db565b9060005260206000200154905080600883815481106141fe576141fe6148db565b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480614236576142366159a5565b6001900381819060005260206000200160009055905550505050565b6000600161425f84611b16565b614269919061480b565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b6142ad83838361431f565b611831576001600160a01b0383166142db57604051637e27328960e01b815260048101829052602401610f47565b6040517f177e802f0000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260248101829052604401610f47565b60006001600160a01b03831615801590613b4b5750826001600160a01b0316846001600160a01b0316148061437957506001600160a01b0380851660009081526005602090815260408083209387168352929052205460ff165b80613b4b5750506000908152600460205260409020546001600160a01b03908116911614919050565b6001600160e01b031981168114610dae57600080fd5b6000602082840312156143ca57600080fd5b8135612d3a816143a2565b6000602082840312156143e757600080fd5b813563ffffffff81168114612d3a57600080fd5b60005b838110156144165781810151838201526020016143fe565b50506000910152565b600081518084526144378160208601602086016143fb565b601f01601f19169290920160200192915050565b602081526000612d3a602083018461441f565b60006020828403121561447057600080fd5b5035919050565b6001600160a01b0381168114610dae57600080fd5b6000806040838503121561449f57600080fd5b82356144aa81614477565b946020939093013593505050565b6000602082840312156144ca57600080fd5b8135612d3a81614477565b6000806000606084860312156144ea57600080fd5b83356144f581614477565b9250602084013561450581614477565b929592945050506040919091013590565b6000806040838503121561452957600080fd5b50508035926020909101359150565b60008060006060848603121561454d57600080fd5b83359250602084013561450581614477565b61ffff8c811682528b8116602083015260ff8b811660408401528a1660608301528815156080830152871660a082015261016081016145a360c083018860ff169052565b60ff861660e083015260ff851661010083015260ff84166101208301526001600160801b0383166101408301529c9b505050505050505050505050565b8015158114610dae57600080fd5b6000806040838503121561460157600080fd5b823561460c81614477565b9150602083013561461c816145e0565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051610160810167ffffffffffffffff8111828210171561466157614661614627565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561469057614690614627565b604052919050565b600067ffffffffffffffff8211156146b2576146b2614627565b50601f01601f191660200190565b60006146d36146ce84614698565b614667565b90508281528383830111156146e757600080fd5b828260208301376000602084830101529392505050565b6000806000806080858703121561471457600080fd5b843561471f81614477565b9350602085013561472f81614477565b925060408501359150606085013567ffffffffffffffff81111561475257600080fd5b8501601f8101871361476357600080fd5b614772878235602084016146c0565b91505092959194509250565b60006020828403121561479057600080fd5b813567ffffffffffffffff8111156147a757600080fd5b8201601f810184136147b857600080fd5b613b4b848235602084016146c0565b600080604083850312156147da57600080fd5b82356147e581614477565b9150602083013561461c81614477565b634e487b7160e01b600052601160045260246000fd5b81810381811115610c7557610c756147f5565b63ffffffff8281168282160390811115610c7557610c756147f5565b60006001820161484c5761484c6147f5565b5060010190565b600181811c9082168061486757607f821691505b602082108103613cc657634e487b7160e01b600052602260045260246000fd5b80820180821115610c7557610c756147f5565b8082028115828204841417610c7557610c756147f5565b634e487b7160e01b600052601260045260246000fd5b6000826148d6576148d66148b1565b500490565b634e487b7160e01b600052603260045260246000fd5b600060ff821660ff8103614907576149076147f5565b60010192915050565b600063ffffffff821663ffffffff8103614907576149076147f5565b602080825282518282018190526000918401906040840190835b81811015614964578351835260209384019390920191600101614946565b509095945050505050565b60008261497e5761497e6148b1565b500690565b60006020828403121561499557600080fd5b8151612d3a81614477565b60ff8181168382160190811115610c7557610c756147f5565b6000602082840312156149cb57600080fd5b5051919050565b600081516149e48185602086016143fb565b9290920192915050565b7f3c7376672076696577426f783d22302030203130323420313032342220786d6c81527f6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737667222060208201527f786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f72672f3160408201527f3939392f786c696e6b223e000000000000000000000000000000000000000000606082015260008251614a9881606b8501602087016143fb565b7f3c2f7376673e0000000000000000000000000000000000000000000000000000606b939091019283015250607101919050565b601f82111561183157806000526020600020601f840160051c81016020851015614af35750805b601f840160051c820191505b8181101561180f5760008155600101614aff565b815167ffffffffffffffff811115614b2d57614b2d614627565b614b4181614b3b8454614853565b84614acc565b6020601f821160018114614b755760008315614b5d5750848201515b600019600385901b1c1916600184901b17845561180f565b600084815260208120601f198516915b82811015614ba55787850151825560209485019460019092019101614b85565b5084821015614bc35786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b7f546865204d657267652054726565202300000000000000000000000000000000815260008251614c0a8160108501602087016143fb565b9190910160100192915050565b7f7d2c7b2274726169745f74797065223a22616e696d61746564222c2276616c7581526232911d60e91b602082015260008351614c5b8160238501602088016143fb565b7f7d2c7b2274726169745f74797065223a22636f6c6f725f7069636b6572222c226023918401918201527f76616c7565223a0000000000000000000000000000000000000000000000000060438201528351614cbe81604a8401602088016143fb565b01604a01949350505050565b7f7d2c7b2274726169745f74797065223a227365676d656e7473222c2276616c7581526232911d60e91b602082015260008451614d0e8160238501602089016143fb565b7f7d2c7b2274726169745f74797065223a227374616773222c2276616c7565223a6023918401918201528451614d4b8160438401602089016143fb565b6023818301019150507f7d2c7b2274726169745f74797065223a226861726573222c2276616c7565223a60208201528351614d8d8160408401602088016143fb565b0160400195945050505050565b7f222c2261747472696275746573223a5b7b2274726169745f74797065223a226981527f6e69744c656e677468222c2276616c7565223a00000000000000000000000000602082015260008751614df8816033850160208c016143fb565b7f7d2c7b2274726169745f74797065223a226469616d65746572222c2276616c756033918401918201526232911d60e91b60538201528751614e41816056840160208c016143fb565b6033818301019150507f7d2c7b2274726169745f74797065223a226272616e63686573222c2276616c7560238201526232911d60e91b6043820152614f28614f22614ef9614ef3614eca614ec4614e9b604688018e6149d2565b7f7d2c7b2274726169745f74797065223a22616e676c65222c2276616c7565223a815260200190565b8b6149d2565b7f7d2c7b2274726169745f74797065223a2244222c2276616c7565223a000000008152601c0190565b886149d2565b7f7d2c7b2274726169745f74797065223a2264656c7461222c2276616c7565223a815260200190565b856149d2565b9998505050505050505050565b60008451614f478184602089016143fb565b845190830190614f5b8183602089016143fb565b8451910190614f6e8183602088016143fb565b0195945050505050565b7f7b226e616d65223a220000000000000000000000000000000000000000000000815260008651614fb0816009850160208b016143fb565b7f222c226465736372697074696f6e223a220000000000000000000000000000006009918401918201528651614fed81601a840160208b016143fb565b6009818301019150507f222c2265787465726e616c5f75726c223a2268747470733a2f2f7468656d657260118201527f676574726565732e78797a2f74726565732f000000000000000000000000000060318201528551615055816043840160208a016143fb565b60118183010191505084516150718160328401602089016143fb565b614f286150db6150d56150ac6032858701017f7d5d2c22696d616765223a2200000000000000000000000000000000000000008152600c0190565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c0000000000008152601a0190565b876149d2565b7f227d000000000000000000000000000000000000000000000000000000000000815260020190565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081526000825161513c81601d8501602087016143fb565b91909101601d0192915050565b7f697066733a2f2f000000000000000000000000000000000000000000000000008152600080835461517a81614853565b60018216801561519157600181146151ac576151e2565b60ff19831660078701526007821515830287010193506151e2565b86600052602060002060005b838110156151d7578154888201600701526001909101906020016151b8565b505060078287010193505b509195945050505050565b805161ffff811681146151ff57600080fd5b919050565b805160ff811681146151ff57600080fd5b80516151ff816145e0565b80516001600160801b03811681146151ff57600080fd5b600061016082840312801561524b57600080fd5b5061525461463d565b61525d836151ed565b815261526b602084016151ed565b602082015261527c60408401615204565b604082015261528d60608401615204565b606082015261529e60808401615215565b60808201526152af60a084016151ed565b60a08201526152c060c08401615204565b60c08201526152d160e08401615204565b60e08201526152e36101008401615204565b6101008201526152f66101208401615204565b6101208201526153096101408401615220565b6101408201529392505050565b805161ffff1682526020810151615333602084018261ffff169052565b506040810151615348604084018260ff169052565b50606081015161535d606084018260ff169052565b506080810151615371608084018215159052565b5060a081015161538760a084018261ffff169052565b5060c081015161539c60c084018260ff169052565b5060e08101516153b160e084018260ff169052565b506101008101516153c861010084018260ff169052565b506101208101516153df61012084018260ff169052565b506101408101516118316101408401826001600160801b03169052565b6101608101610c758284615316565b60ff8281168282160390811115610c7557610c756147f5565b828152815461ffff81166020830152610180820190601081901c61ffff166040840152602081901c60ff166060840152602881901c60ff16608084015261547560a0840160ff8360301c1615159052565b603881901c61ffff1660c0840152604881901c60ff1660e0840152605081901c60ff16610100840152605881901c60ff16610120840152606081901c60ff16610140840152606881901c6001600160801b031661016084015261365b565b7f3c7465787420646f6d696e616e742d626173656c696e653d226d6964646c652281527f20746578742d616e63686f723d226d6964646c652220783d223530252220793d60208201527f223530252220666f6e742d73697a653d2235303025222066696c6c3d2223000060408201526000825161555781605e8501602087016143fb565b7f3c2f746578743e00000000000000000000000000000000000000000000000000605e939091019283015250606501919050565b63ffffffff8181168382160190811115610c7557610c756147f5565b6155b18187615316565b63ffffffff8516610160820152836101808201528215156101a08201526101e06101c082015260006155e76101e083018461441f565b979650505050505050565b60006020828403121561560457600080fd5b815167ffffffffffffffff81111561561b57600080fd5b8201601f8101841361562c57600080fd5b805161563a6146ce82614698565b81815285602083850101111561564f57600080fd5b6156608260208301602086016143fb565b95945050505050565b6001600160a01b03851681526001600160a01b03841660208201528260408201526080606082015260006156a0608083018461441f565b9695505050505050565b6000602082840312156156bc57600080fd5b8151612d3a816143a2565b7f3c7376672076696577426f783d22302030203130323420313032342220786d6c81527f6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737667222060208201527f786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f72672f3160408201527f3939392f786c696e6b223e3c7469746c653e0000000000000000000000000000606082015260008551615771816072850160208a016143fb565b7f3c2f7469746c653e00000000000000000000000000000000000000000000000060729184019182015285516157ae81607a840160208a016143fb565b60728183010191505084516157ca8160088401602089016143fb565b84519101600801906157e08183602088016143fb565b61345a8183017f3c2f7376673e0000000000000000000000000000000000000000000000000000815260060190565b7f3c646566733e3c6c696e6561724772616469656e742069643d22736b7922206781527f72616469656e745472616e73666f726d3d22726f7461746528393029223e3c7360208201527f746f702073746f702d636f6c6f723d22230000000000000000000000000000006040820152600082516158938160518501602087016143fb565b7f22206f66667365743d22363625222f3e3c2f6c696e6561724772616469656e7460519390910192830152507f3e3c2f646566733e3c726563742077696474683d22313032342220686569676860718201527f743d2231303234222066696c6c3d2275726c2823736b7929222f3e0000000000609182015260ac01919050565b7f3c726563742077696474683d223130323422206865696768743d22323422207981527f3d2231303030222066696c6c3d2200000000000000000000000000000000000060208201526000825161597181602e8501602087016143fb565b7f222f3e0000000000000000000000000000000000000000000000000000000000602e939091019283015250603101919050565b634e487b7160e01b600052603160045260246000fdfe666666376564222f3e3c73746f702073746f702d636f6c6f723d2223666564376161626165366664222f3e3c73746f702073746f702d636f6c6f723d22236630663966664142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa26469706673582212207721b3c9174ae1873e8f0fd57129ec289a8f0f643425aaea69de55032df4c52364736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000570a07c430d637990591f5288e7959ce94e3a9230000000000000000000000000333232cc77f8c0bc2287a7b248ed3f5aba5234e0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000f8f32794db9185593890b8c10dce025788b133fb
-----Decoded View---------------
Arg [0] : _initialOwner (address): 0x570a07C430d637990591f5288E7959cE94e3a923
Arg [1] : _creator (address): 0x0333232cC77f8c0bc2287a7b248ED3F5abA5234E
Arg [2] : _beforeHuntLimitPerAddress (uint256): 3
Arg [3] : _seeder (address): 0xF8f32794Db9185593890B8c10DcE025788B133FB
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000570a07c430d637990591f5288e7959ce94e3a923
Arg [1] : 0000000000000000000000000333232cc77f8c0bc2287a7b248ed3f5aba5234e
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [3] : 000000000000000000000000f8f32794db9185593890b8c10dce025788b133fb
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $1,580.19 | 0.5063 | $800.07 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.