Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
TokenTracker
Multichain Info
N/A
Latest 25 from a total of 126 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Withdraw | 7803985 | 15 days ago | IN | 0 ETH | 0.0006546 | ||||
Set Owner | 7775334 | 19 days ago | IN | 0 ETH | 0.00605557 | ||||
Mint | 7775318 | 19 days ago | IN | 0.0002056 ETH | 0.0677336 | ||||
Mint | 7729417 | 26 days ago | IN | 0.00020069 ETH | 0.00265346 | ||||
Pay Domain | 7722501 | 27 days ago | IN | 0.1 ETH | 0.00011245 | ||||
Pay Domain | 7722465 | 27 days ago | IN | 0.1 ETH | 0.00011618 | ||||
Pay Domain | 7722450 | 27 days ago | IN | 0.1 ETH | 0.00011225 | ||||
Pay Domain | 7722414 | 27 days ago | IN | 0.1 ETH | 0.00011065 | ||||
Pay Domain | 7722302 | 27 days ago | IN | 0.1 ETH | 0.0001099 | ||||
Pay Domain | 7722232 | 27 days ago | IN | 0.1 ETH | 0.00010569 | ||||
Pay Domain | 7722212 | 27 days ago | IN | 0.1 ETH | 0.00011544 | ||||
Pay Domain | 7722191 | 27 days ago | IN | 0.1 ETH | 0.00010951 | ||||
Pay Domain | 7722179 | 27 days ago | IN | 0.1 ETH | 0.00011035 | ||||
Set | 7652401 | 37 days ago | IN | 0 ETH | 0.03285527 | ||||
Set | 7652380 | 37 days ago | IN | 0 ETH | 0.00731672 | ||||
Set | 7652088 | 37 days ago | IN | 0 ETH | 0.01459814 | ||||
Set | 7652054 | 37 days ago | IN | 0 ETH | 0.02215377 | ||||
Set | 7652008 | 37 days ago | IN | 0 ETH | 0.03091332 | ||||
Set Many | 7645768 | 38 days ago | IN | 0 ETH | 0.02438995 | ||||
Set Many | 7645367 | 38 days ago | IN | 0 ETH | 0.02066972 | ||||
Set | 7644658 | 38 days ago | IN | 0 ETH | 0.00441901 | ||||
Pay Domain | 7603246 | 44 days ago | IN | 0.1 ETH | 0.00017702 | ||||
Pay Domain | 7603234 | 44 days ago | IN | 0.1 ETH | 0.00017553 | ||||
Pay Domain | 7603159 | 44 days ago | IN | 0.1 ETH | 0.00021972 | ||||
Pay Domain | 7603138 | 44 days ago | IN | 0.1 ETH | 0.00022315 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
Transfer | 7803985 | 15 days ago | 0.04147986 ETH | ||||
Transfer | 7775318 | 19 days ago | 0.00001869 ETH | ||||
Transfer | 7729417 | 26 days ago | 0.00001824 ETH | ||||
Transfer | 7722501 | 27 days ago | 0.099 ETH | ||||
Transfer | 7722465 | 27 days ago | 0.099 ETH | ||||
Transfer | 7722450 | 27 days ago | 0.099 ETH | ||||
Transfer | 7722414 | 27 days ago | 0.099 ETH | ||||
Transfer | 7722302 | 27 days ago | 0.099 ETH | ||||
Transfer | 7722232 | 27 days ago | 0.099 ETH | ||||
Transfer | 7722212 | 27 days ago | 0.099 ETH | ||||
Transfer | 7722191 | 27 days ago | 0.099 ETH | ||||
Transfer | 7722179 | 27 days ago | 0.099 ETH | ||||
Transfer | 7603246 | 44 days ago | 0.099 ETH | ||||
Transfer | 7603234 | 44 days ago | 0.099 ETH | ||||
Transfer | 7603159 | 44 days ago | 0.099 ETH | ||||
Transfer | 7603138 | 44 days ago | 0.099 ETH | ||||
Transfer | 7603122 | 44 days ago | 0.099 ETH | ||||
Transfer | 7603096 | 44 days ago | 0.099 ETH | ||||
Transfer | 7603091 | 44 days ago | 0.099 ETH | ||||
Transfer | 7554136 | 51 days ago | 0.099 ETH | ||||
Transfer | 7554110 | 51 days ago | 0.099 ETH | ||||
Transfer | 7553812 | 51 days ago | 0.99 ETH | ||||
Transfer | 7553519 | 51 days ago | 0.00000028 ETH | ||||
Transfer | 7223682 | 99 days ago | 0.099 ETH | ||||
Transfer | 7110981 | 116 days ago | 0.099 ETH |
Loading...
Loading
Contract Name:
DomainRegistry
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 1000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import {StringUtilsLib} from "./StringUtilsLib.sol"; import "./interfaces/IDomainRegistry.sol"; import "./interfaces/IMetadata.sol"; import "./RecordStorage.sol"; import "./PlusCodes.sol"; // Tangiblink Domain Registry Contract used for minting of plusCode identifiable Domain name NFT's, // and management of NFT key value pairs e.g. Key: ETH, Value: 0x... /// @custom:security-contact [email protected] contract DomainRegistry is IDomainRegistry, ERC721, ERC721URIStorage, ERC721Pausable, Ownable, ERC721Burnable, RecordStorage, PlusCodes { using SafeERC20 for IERC20; using StringUtilsLib for string; // Events event RefundOverpayment(address indexed account, uint256 amount); event NewBaseURI(string _newBaseURI); event IPriceFeedUpdate(address priceFeedContract); event IMetadataUpdate(address metadataContract); event ContractURIUpdated(); event FeePercentUpdate(uint256 percent); event Received(address indexed account, uint256 amount); event Withdraw(address indexed addressTo, uint256 amount); event WithdrawERC20(address indexed token, address indexed addressTo, uint256 amount); event PayAccount(address indexed addressTo, uint256 amount, uint256 paid, uint256 fee, string data); event PayDomain( address indexed addressTo, uint256 indexed tokenId, string plusCode, uint256 amount, uint256 paid, uint256 fee, string data ); // Custom Errors List error InvalidUSDWeiPrice(int256 _usdWei); error NotEnoughWei(uint256 _requires, uint256 _provided); error EmptyValue(); error LowBalance(); error InvalidPlusCode(string code); error IndexError(); // Storage string internal s_contractURI; string public s_baseURI; IMetadata internal s_metadata; uint256 public s_mintCostUsd; uint256 public s_feePercent; // 10_000 = 100% AggregatorV3Interface internal MATIC_USD_FEED; uint256[] public tokenIds; uint256 public constant MAX_UINT256 = type(uint256).max; struct UserInfo { address user; // address of user role uint64 expires; // unix timestamp, user expires } mapping(uint256 => UserInfo) internal _users; // Mapping token ID to UserInfo struct object mapping(uint256 => string) public s_tokenIdToPlusCode; constructor( string memory baseURI, address metadata, uint256 mintCostUsd, uint256 feePercent, address maticUsdFeed ) ERC721("Tangiblink Domains TEST", "TD") Ownable(_msgSender()) { s_baseURI = baseURI; s_metadata = IMetadata(metadata); s_mintCostUsd = mintCostUsd; s_feePercent = feePercent; MATIC_USD_FEED = AggregatorV3Interface(maticUsdFeed); } // Modifiers /** * @notice Modifier - Reverts if msgSender() is not the Owner or Approved to use the token * @param tokenId uint256 ID of the token */ modifier onlyApprovedOrOwner(uint256 tokenId) { _checkAuthorized(_ownerOf(tokenId), _msgSender(), tokenId); _; } /** * @notice Modifier - Reverts if msgSender() is not the Current User (or Approved, if the Current User is the token owner) * @param tokenId uint256 ID of the token */ modifier onlyUserOrApproved(uint256 tokenId) { if (!isUserOrApproved(_msgSender(), tokenId)) { revert ERC721InsufficientApproval(_msgSender(), tokenId); } _; } /** * @notice Modifier - Reverts for underpayment and refunds overpayment. */ modifier payment() { uint256 price = checkPrice(); if (msg.value < price) { revert NotEnoughWei(price, msg.value); } if (msg.value > price) { uint256 refundAmount = msg.value - price; payable(_msgSender()).transfer(refundAmount); emit RefundOverpayment(_msgSender(), refundAmount); } _; } // Emergency functions function pause() public override onlyOwner { _pause(); } function unpause() public override onlyOwner { _unpause(); } // Transferring /** * @dev Transfer domain ownership without resetting domain records. * @param to address of new domain owner * @param tokenId uint256 ID of the token to be transferred */ function setOwner(address to, uint256 tokenId) external override onlyApprovedOrOwner(tokenId) { _transfer(ownerOf(tokenId), to, tokenId); } function transferFrom( address from, address to, uint256 tokenId ) public override(ERC721, IERC721) onlyApprovedOrOwner(tokenId) { _reset(tokenId); _transfer(from, to, tokenId); } function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory data ) public override(ERC721, IERC721) onlyApprovedOrOwner(tokenId) { _reset(tokenId); _safeTransfer(from, to, tokenId, data); } function _update( address to, uint256 tokenId, address auth ) internal override(ERC721, ERC721Pausable) returns (address) { address from = super._update(to, tokenId, auth); // Ensures that NFT rentals mapping is reset if (from != to && _users[tokenId].user != address(0)) { delete _users[tokenId]; emit UpdateUser(tokenId, address(0), 0); emit MetadataUpdate(tokenId); } return from; } // Ownership /** * @dev Returns whether the given spender can transfer a given token ID. * @param spender address of the spender to query * @param tokenId uint256 ID of the token to be transferred * @return bool whether the msg.sender is approved for the given token ID, * is an operator of the owner, or is the owner of the token */ function isApprovedOrOwner(address spender, uint256 tokenId) external view override returns (bool) { address owner = _requireOwned(tokenId); return _isAuthorized(owner, spender, tokenId); } function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721URIStorage) returns (bool) { return interfaceId == type(IERC4907).interfaceId || super.supportsInterface(interfaceId); } /** * @notice Initiate the minting of an individual plusCode. * @param plusCode - The google Plus Code for the Domain name location. */ function mint(string memory plusCode) external payable override whenNotPaused payment { string memory _plusCode = checkCode(plusCode); if (bytes(_plusCode).length == 0) { revert InvalidPlusCode(plusCode); } uint256 tokenId = plusCodeToTokenId(_plusCode); _safeMint(_msgSender(), tokenId); tokenIds.push(tokenId); s_tokenIdToPlusCode[tokenId] = _plusCode; _setTokenURI(tokenId, _plusCode); } /** * @dev mints token with records * @param plusCode - The google Plus Code for the Domain name location. * @param keys New record keys * @param values New record values */ function mintWithRecords( string calldata plusCode, string[] calldata keys, string[] calldata values ) external payable override whenNotPaused payment { string memory _plusCode = checkCode(plusCode); if (bytes(_plusCode).length == 0) { revert InvalidPlusCode(plusCode); } uint256 tokenId = plusCodeToTokenId(_plusCode); _safeMint(_msgSender(), tokenId); tokenIds.push(tokenId); s_tokenIdToPlusCode[tokenId] = _plusCode; _setTokenURI(tokenId, _plusCode); _setMany(keys, values, tokenId); } /** * @notice Gets the price from the latest round data of Chainlink price feeds * @return usdPerWei The amount of USD in per unit of MATIC in wei. */ function getFeedData() public view override returns (int256) { (, int256 usdPerWei, , , ) = MATIC_USD_FEED.latestRoundData(); if (usdPerWei <= 0) { revert InvalidUSDWeiPrice(usdPerWei); } return usdPerWei; } /** * @notice Checks the price of minting a domain * @return maticWei The amount of MATIC in wei equivalent to the USD cost. */ function checkPrice() public view override returns (uint256) { uint256 usdPerWei = uint(getFeedData()); uint256 maticWei = ((1e18 / usdPerWei) * s_mintCostUsd) / 1e10; return maticWei; } /** * @notice Converts plusCode name string to a unique uint256 for use as Token ID. * @param plusCode - The google Plus Code for the Domain name location. */ function plusCodeToTokenId(string memory plusCode) public pure override returns (uint256) { return uint256(keccak256(abi.encodePacked(plusCode))); } /** * @notice Set a new Base URI for concatenation with Token ID to form the full Token URI. * @param _newBaseURI - The first fixed part of the full Token URI. */ function setBaseURI(string memory _newBaseURI) public override onlyOwner { s_baseURI = _newBaseURI; emit NewBaseURI(_newBaseURI); } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenURI`. */ function _baseURI() internal view override(ERC721) returns (string memory) { return s_baseURI; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenURI`. */ function getBaseURI() public view override returns (string memory) { return s_baseURI; } /** * @notice Returns the Plus Code for the given token ID * @param tokenId uint256 ID of the token */ function getPlusCode(uint256 tokenId) public view override returns (string memory) { return s_tokenIdToPlusCode[tokenId]; } /** * @notice Getter function for retrieving the Price Feed contract address */ function getPriceFeedContractAddress() public view override returns (address) { return address(MATIC_USD_FEED); } /** * @notice Getter function for retrieving the Metadata contract address */ function getMetadataContractAddress() public view override returns (address) { return address(s_metadata); } /** * @notice Gets the number of minted tokenIds */ function getTokenIdsCount() public view override returns (uint256 count) { return tokenIds.length; } /** * @notice Returns the array of token Ids stored in the tokenIds array */ function getTokenIdsArray(uint256 start, uint256 finish) public view override returns (uint256[] memory) { uint256 end = finish + 1; if (end > tokenIds.length) end = tokenIds.length; if (start >= end) revert IndexError(); uint256[] memory tokenIdsArray = new uint256[](end - start); for (uint256 i = 0; i < end - start; i++) { tokenIdsArray[i] = tokenIds[i + start]; } return tokenIdsArray; } /** * @notice Returns an array of Plus Codes stored in the s_tokenIdToPlusCode mapping */ function getPlusCodesArray(uint256 start, uint256 finish) public view override returns (string[] memory) { uint256 end = finish + 1; if (end > tokenIds.length) end = tokenIds.length; if (start >= end) revert IndexError(); string[] memory plusCodesArray = new string[](end - start); for (uint256 i = 0; i < end - start; i++) { plusCodesArray[i] = s_tokenIdToPlusCode[tokenIds[i + start]]; } return plusCodesArray; } /** * @notice Returns an array of token owners in the order of the tokenIds array */ function getOwnersArray(uint256 start, uint256 finish) public view override returns (address[] memory) { uint256 end = finish + 1; if (end > tokenIds.length) end = tokenIds.length; if (start >= end) revert IndexError(); address[] memory ownersArray = new address[](end - start); for (uint256 i = 0; i < end - start; i++) { ownersArray[i] = ownerOf(tokenIds[i + start]); } return ownersArray; } /** * @notice Returns an array of token users in the order of the tokenIds array */ function getUsersArray(uint256 start, uint256 finish) public view override returns (address[] memory) { uint256 end = finish + 1; if (end > tokenIds.length) end = tokenIds.length; if (start >= end) revert IndexError(); address[] memory ownersArray = new address[](end - start); for (uint256 i = 0; i < end - start; i++) { ownersArray[i] = userOf(tokenIds[i + start]); } return ownersArray; } /** * @notice Set a new Price Feed address for the Matic to USD conversion. * @param _newPriceFeedAddress address of the chainlink price feed. */ function updatePriceFeedContract(address _newPriceFeedAddress) public override onlyOwner { MATIC_USD_FEED = AggregatorV3Interface(_newPriceFeedAddress); emit IPriceFeedUpdate(_newPriceFeedAddress); } /** * @notice Set a new Contract address for the metadata generating contract. * @param _newMetaDataContract address of the metadata generating contract. */ function updateMetadataContract(address _newMetaDataContract) public override onlyOwner { s_metadata = IMetadata(_newMetaDataContract); emit IMetadataUpdate(_newMetaDataContract); emit BatchMetadataUpdate(0, MAX_UINT256); } /** * @notice Set a new Contract URI for OpenSea contract metadata. * @param _newContractURI URI of the contract level metadata. */ function setContractURI(string memory _newContractURI) public override onlyOwner { s_contractURI = _newContractURI; emit ContractURIUpdated(); } /** * @notice For OpenSea contract level metadata. */ function contractURI() public view override returns (string memory) { return s_contractURI; } /**@notice Gets the unique token metadata string for market place such as OpenSea * @param tokenId uint256 ID of the token */ function tokenURI(uint256 tokenId) public view override(ERC721, ERC721URIStorage) returns (string memory) { string memory URI = super.tokenURI(tokenId); if (address(s_metadata) != address(0)) { return s_metadata.getOnChainMetadata(tokenId); } else { return URI; } } /** * @dev This built-in function doesn't require any calldata, * it will get called if the data field is empty and the value field is not empty. * This allows the smart contract to receive ether just like a regular user account controlled by a private key would. */ receive() external payable { emit Received(msg.sender, msg.value); } /** * @dev Fallback function * it will get called if the data field is not empty. */ fallback() external payable { emit Received(msg.sender, msg.value); } /** * @notice Set a new payment fee percent. * Value of 1 = 0.01%, 100 = 1%, 1000 = 10%, 10000 = 100% * maximum fee can be set to 10000 (equivalent to 100%) * minimum fee can be set to 1 (equivalent to 0.01%) * @param _newFeePercent New fee percent division value. */ function setNewFeePercent(uint _newFeePercent) public override onlyOwner { uint maxPercentage = 10000; uint minPercentage = 1; if (_newFeePercent > maxPercentage) { s_feePercent = maxPercentage; } else { if (_newFeePercent < minPercentage) { s_feePercent = minPercentage; } else { s_feePercent = _newFeePercent; } } emit FeePercentUpdate(s_feePercent); } /** * @notice Gets the fee to deduct from a payment. Minimum of the current tx.gasprice. * @param amount The amount of the specified token to be withdrawn. * @param gasprice The current gasprice for the transaction. * @return fee The fee amount in MATIC wei. */ function getPaymentFee(uint amount, uint gasprice) public view override returns (uint) { uint fee = (amount * s_feePercent) / 10000; if (fee < gasprice) fee = gasprice; return fee; } /** * @notice Allows payment amount of native token to be sent to a domain user. * @param tokenId uint256 ID of the token * @param data string reason for transfer */ function payDomain(uint256 tokenId, string calldata data) public payable override returns (bool) { uint256 fee = getPaymentFee(msg.value, tx.gasprice); if (msg.value < fee) { revert NotEnoughWei(fee, msg.value); } uint256 paid = msg.value - fee; address addressTo = userOf(tokenId); payable(addressTo).transfer(paid); emit PayDomain(addressTo, tokenId, s_tokenIdToPlusCode[tokenId], msg.value, paid, fee, data); return true; } /** * @notice Allows payment amount of native token to be sent to a domain user. * @param addressTo The address to send the token to. * @param data string reason for transfer */ function payAccount(address payable addressTo, string calldata data) public payable override returns (bool) { uint256 fee = getPaymentFee(msg.value, tx.gasprice); if (msg.value < fee) { revert NotEnoughWei(fee, msg.value); } uint256 paid = msg.value - fee; addressTo.transfer(paid); emit PayAccount(addressTo, msg.value, paid, fee, data); return true; } /** * @notice Allows contract owner to withdraw an amount of native token from the contract balance. * @param addressTo The address to send the token to. * @param amount The amount of the specified token to be withdrawn. */ function withdraw(address payable addressTo, uint amount) public override onlyOwner returns (bool) { if (amount > address(this).balance) { revert LowBalance(); } addressTo.transfer(amount); emit Withdraw(addressTo, amount); return true; } /** * @notice Allows contract owner to withdraw an amount of a specified ERC20 token from the contract balance. * @param tokenAddress The address of the ERC-20 compliant token. * @param addressTo The address to send the token to. * @param amount The amount of the specified token to be withdrawn. */ function withdrawErc20( address tokenAddress, address payable addressTo, uint amount ) public override onlyOwner returns (bool) { IERC20 token = IERC20(tokenAddress); if (amount > token.balanceOf(address(this))) { revert LowBalance(); } token.safeTransfer(addressTo, amount); emit WithdrawERC20(tokenAddress, addressTo, amount); return true; } /** * @dev Existence of token. * @param tokenId uint256 ID of the token */ function exists(uint256 tokenId) public view override returns (bool) { return _ownerOf(tokenId) != address(0); } // Resolver Functions function set( string calldata key, string calldata value, uint256 tokenId ) external override whenNotPaused onlyUserOrApproved(tokenId) { _set(key, value, tokenId); } function setMany( string[] calldata keys, string[] calldata values, uint256 tokenId ) external override whenNotPaused onlyUserOrApproved(tokenId) { _setMany(keys, values, tokenId); } function setByHash( uint256 keyHash, string calldata value, uint256 tokenId ) external override whenNotPaused onlyUserOrApproved(tokenId) { _setByHash(keyHash, value, tokenId); } function setManyByHash( uint256[] calldata keyHashes, string[] calldata values, uint256 tokenId ) external override whenNotPaused onlyUserOrApproved(tokenId) { _setManyByHash(keyHashes, values, tokenId); } function reconfigure( string[] calldata keys, string[] calldata values, uint256 tokenId ) external override whenNotPaused onlyUserOrApproved(tokenId) { _reconfigure(keys, values, tokenId); } function reset(uint256 tokenId) external override whenNotPaused onlyUserOrApproved(tokenId) { _reset(tokenId); } // NFT Rentals /** * @notice set the user and expiry of an NFT Rental. Throws if `tokenId` is not valid NFT * @dev The zero address indicates there is no user * @param tokenId uint256 ID of the token * @param user The new user of the NFT * @param expires UNIX timestamp, The new user could use the NFT before expires * */ function setUser( uint256 tokenId, address user, uint64 expires ) public virtual override whenNotPaused onlyApprovedOrOwner(tokenId) { UserInfo storage info = _users[tokenId]; info.user = user; info.expires = expires; emit UpdateUser(tokenId, user, expires); emit MetadataUpdate(tokenId); } /** * @notice Get the user address of an NFT * @dev The zero address indicates that there is no user or the user is expired * @param tokenId uint256 ID of the token * @return The user address for this NFT */ function userOf(uint256 tokenId) public view override returns (address) { address owner = _requireOwned(tokenId); if (uint256(_users[tokenId].expires) >= block.timestamp) { return _users[tokenId].user; } else { return owner; } } /** * @notice Get the user expires of an NFT * @dev The max uint256 returned if the current user is the owner of the NFT * @param tokenId uint256 ID of the token * @return The user expires UNIX Time for this NFT */ function userExpires(uint256 tokenId) public view override returns (uint256) { _requireOwned(tokenId); uint256 expires = uint256(_users[tokenId].expires); if (expires >= block.timestamp) { return expires; } else { return MAX_UINT256; } } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * Requirements: * - `tokenId` must exist. * @param spender Address of account being queried * @param tokenId uint256 ID of the token */ function isUserOrApproved(address spender, uint256 tokenId) public view override returns (bool) { address owner = _requireOwned(tokenId); if (owner == userOf(tokenId)) { return (_isAuthorized(owner, spender, tokenId)); } else { return (spender == userOf(tokenId)); } } // Burning /**@notice Burns tokens * @param tokenId uint256 ID of the token */ function burn(uint256 tokenId) public override(ERC721Burnable, IDomainRegistry) { removeFromArrays(tokenId); _reset(tokenId); super.burn(tokenId); } /**@notice Deletes tokens from tokenIds array * @param tokenId uint256 ID of the token */ function removeFromArrays(uint256 tokenId) internal { for (uint i = 0; i < tokenIds.length; i++) { if (tokenIds[i] == tokenId) { for (i = i; i < tokenIds.length - 1; i++) { tokenIds[i] = tokenIds[i + 1]; } tokenIds.pop(); delete s_tokenIdToPlusCode[tokenId]; return; } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface AggregatorV3Interface { function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); function getRoundData(uint80 _roundId) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) pragma solidity ^0.8.20; /** * @dev Standard ERC20 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens. */ interface IERC20Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC20InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC20InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. * @param spender Address that may be allowed to operate on tokens without being their owner. * @param allowance Amount of tokens a `spender` is allowed to operate with. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC20InvalidApprover(address approver); /** * @dev Indicates a failure with the `spender` to be approved. Used in approvals. * @param spender Address that may be allowed to operate on tokens without being their owner. */ error ERC20InvalidSpender(address spender); } /** * @dev Standard ERC721 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens. */ interface IERC721Errors { /** * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20. * Used in balance queries. * @param owner Address of the current owner of a token. */ error ERC721InvalidOwner(address owner); /** * @dev Indicates a `tokenId` whose `owner` is the zero address. * @param tokenId Identifier number of a token. */ error ERC721NonexistentToken(uint256 tokenId); /** * @dev Indicates an error related to the ownership over a particular token. Used in transfers. * @param sender Address whose tokens are being transferred. * @param tokenId Identifier number of a token. * @param owner Address of the current owner of a token. */ error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC721InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC721InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param tokenId Identifier number of a token. */ error ERC721InsufficientApproval(address operator, uint256 tokenId); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC721InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC721InvalidOperator(address operator); } /** * @dev Standard ERC1155 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens. */ interface IERC1155Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. * @param tokenId Identifier number of a token. */ error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC1155InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC1155InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param owner Address of the current owner of a token. */ error ERC1155MissingApprovalForAll(address operator, address owner); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC1155InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC1155InvalidOperator(address operator); /** * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. * Used in batch transfers. * @param idsLength Length of the array of token identifiers * @param valuesLength Length of the array of token amounts */ error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4906.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; import {IERC721} from "./IERC721.sol"; /// @title EIP-721 Metadata Update Extension interface IERC4906 is IERC165, IERC721 { /// @dev This event emits when the metadata of a token is changed. /// So that the third-party platforms such as NFT market could /// timely update the images and related attributes of the NFT. event MetadataUpdate(uint256 _tokenId); /// @dev This event emits when the metadata of a range of tokens is changed. /// So that the third-party platforms such as NFT market could /// timely update the images and related attributes of the NFTs. event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); }
// SPDX-License-Identifier: MIT // 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.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC20Permit} from "../extensions/IERC20Permit.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev An operation with an ERC20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data); if (returndata.length != 0 && !abi.decode(returndata, (bool))) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol) pragma solidity ^0.8.20; import {IERC721} from "./IERC721.sol"; import {IERC721Receiver} from "./IERC721Receiver.sol"; import {IERC721Metadata} from "./extensions/IERC721Metadata.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[ERC721] 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); _checkOnERC721Received(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 ERC721 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 the provided `owner` for the given token or for all its assets * the `spender` for the specific `tokenId`. * * 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); _checkOnERC721Received(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 ERC721 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); _checkOnERC721Received(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; } /** * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. This will revert if the * recipient doesn't accept the token transfer. The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param data bytes optional data to send along with the call */ function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data) private { if (to.code.length > 0) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { if (retval != IERC721Receiver.onERC721Received.selector) { revert ERC721InvalidReceiver(to); } } catch (bytes memory reason) { if (reason.length == 0) { revert ERC721InvalidReceiver(to); } else { /// @solidity memory-safe-assembly assembly { revert(add(32, reason), mload(reason)) } } } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Burnable.sol) pragma solidity ^0.8.20; import {ERC721} from "../ERC721.sol"; import {Context} from "../../../utils/Context.sol"; /** * @title ERC721 Burnable Token * @dev ERC721 Token that can be burned (destroyed). */ abstract contract ERC721Burnable is Context, ERC721 { /** * @dev Burns `tokenId`. See {ERC721-_burn}. * * Requirements: * * - The caller must own `tokenId` or be an approved operator. */ function burn(uint256 tokenId) public virtual { // 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. _update(address(0), tokenId, _msgSender()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Pausable.sol) pragma solidity ^0.8.20; import {ERC721} from "../ERC721.sol"; import {Pausable} from "../../../utils/Pausable.sol"; /** * @dev ERC721 token with pausable token transfers, minting and burning. * * Useful for scenarios such as preventing trades until the end of an evaluation * period, or having an emergency switch for freezing all token transfers in the * event of a large bug. * * IMPORTANT: This contract does not include public pause and unpause functions. In * addition to inheriting this contract, you must define both functions, invoking the * {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate * access control, e.g. using {AccessControl} or {Ownable}. Not doing so will * make the contract pause mechanism of the contract unreachable, and thus unusable. */ abstract contract ERC721Pausable is ERC721, Pausable { /** * @dev See {ERC721-_update}. * * Requirements: * * - the contract must not be paused. */ function _update( address to, uint256 tokenId, address auth ) internal virtual override whenNotPaused returns (address) { return super._update(to, tokenId, auth); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721URIStorage.sol) pragma solidity ^0.8.20; import {ERC721} from "../ERC721.sol"; import {Strings} from "../../../utils/Strings.sol"; import {IERC4906} from "../../../interfaces/IERC4906.sol"; import {IERC165} from "../../../interfaces/IERC165.sol"; /** * @dev ERC721 token with storage based token URI management. */ abstract contract ERC721URIStorage is IERC4906, ERC721 { using Strings for uint256; // Interface ID as defined in ERC-4906. This does not correspond to a traditional interface ID as ERC-4906 only // defines events and does not include any external function. bytes4 private constant ERC4906_INTERFACE_ID = bytes4(0x49064906); // Optional mapping for token URIs mapping(uint256 tokenId => string) private _tokenURIs; /** * @dev See {IERC165-supportsInterface} */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, IERC165) returns (bool) { return interfaceId == ERC4906_INTERFACE_ID || super.supportsInterface(interfaceId); } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireOwned(tokenId); string memory _tokenURI = _tokenURIs[tokenId]; string memory base = _baseURI(); // If there is no base URI, return the token URI. if (bytes(base).length == 0) { return _tokenURI; } // If both are set, concatenate the baseURI and tokenURI (via string.concat). if (bytes(_tokenURI).length > 0) { return string.concat(base, _tokenURI); } return super.tokenURI(tokenId); } /** * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. * * Emits {MetadataUpdate}. */ function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { _tokenURIs[tokenId] = _tokenURI; emit MetadataUpdate(tokenId); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.20; import {IERC721} from "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or * {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the address zero. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.20; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be * reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert FailedInnerCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { bool private _paused; /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); /** * @dev The operation failed because the contract is paused. */ error EnforcedPause(); /** * @dev The operation failed because the contract is not paused. */ error ExpectedPause(); /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { if (paused()) { revert EnforcedPause(); } } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { if (!paused()) { revert ExpectedPause(); } } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { uint256 localValue = value; bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal * representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.6; import "./IERC4907.sol"; import "./IPlusCodes.sol"; import "./IRecordStorage.sol"; /** * @title Chainlink Functions client interface. */ interface IDomainRegistry is IERC4907, IPlusCodes { // Emergency functions function pause() external; function unpause() external; /** * @dev Transfer domain ownership without resetting domain records. * @param to address of new domain owner * @param tokenId uint256 ID of the token to be transferred */ function setOwner(address to, uint256 tokenId) external; /** * @dev Returns whether the given spender can transfer a given token ID. * @param spender address of the spender to query * @param tokenId uint256 ID of the token to be transferred * @return bool whether the msg.sender is approved for the given token ID, * is an operator of the owner, or is the owner of the token */ function isApprovedOrOwner(address spender, uint256 tokenId) external view returns (bool); /** * @notice Initiate the minting of an individual plusCode. * @param plusCode - The google Plus Code for the Domain name location. */ function mint(string memory plusCode) external payable; /** * @dev mints token with records * @param plusCode - The google Plus Code for the Domain name location. * @param keys New record keys * @param values New record values */ function mintWithRecords(string calldata plusCode, string[] calldata keys, string[] calldata values) external payable; /** * @notice Gets the price from the latest round data of Chainlink price feeds * @return usdPerWei The amount of USD in per unit of MATIC in wei. */ function getFeedData() external view returns (int256); /** * @notice Checks the price of minting a domain * @return maticWei The amount of MATIC in wei equivelent to the USD cost. */ function checkPrice() external view returns (uint256); /** * @notice Converts plusCode name string to a unique uint256 for use as Token ID. * @param plusCode - The google Plus Code for the Domain name location. */ function plusCodeToTokenId(string memory plusCode) external pure returns (uint256); /** * @notice Set a new Base URI for concatenation with Token ID to form the full Token URI. * @param _newBaseURI - The first fixed part of the full Token URI. */ function setBaseURI(string memory _newBaseURI) external; /** * @notice Get token baseURI */ function getBaseURI() external view returns (string memory); /** * @notice Get Plus Code from the token ID * @param tokenId The NFT to get the user address for * @return The Plus Code for this NFT */ function getPlusCode(uint256 tokenId) external view returns (string memory); /** * @notice Getter function for retrieving the Metadata contract address */ function getMetadataContractAddress() external view returns (address); /** * @notice Getter function for retrieving the Price Feed contract address */ function getPriceFeedContractAddress() external view returns (address); /** * @notice Gets the number of minted tokenIds */ function getTokenIdsCount() external view returns (uint256 count); /** * @notice Returns the array of token Ids stored in the tokenIds array */ function getTokenIdsArray(uint256 start, uint256 finish) external view returns (uint256[] memory); /** * @notice Returns the array of Plus Codes stored in the plusCodes array */ function getPlusCodesArray(uint256 start, uint256 finish) external view returns (string[] memory); /** * @notice Returns an array of token owners in the order of the tokenIds array */ function getOwnersArray(uint256 start, uint256 finish) external view returns (address[] memory); /** * @notice Returns an array of token users in the order of the tokenIds array */ function getUsersArray(uint256 start, uint256 finish) external view returns (address[] memory); /** * @notice Set a new Price Feed address for the Matic to USD conversion. * @param _newPriceFeedAddress address of the chainlink price feed. */ function updatePriceFeedContract(address _newPriceFeedAddress) external; /** * @notice Set a new Contract address for the metadata generating contract. * @param _newMetaDataContract address of the metadata generating contract. */ function updateMetadataContract(address _newMetaDataContract) external; /** * @notice Set a new Contract URI for OpenSea contract metadata. * @param _newContractURI URI of the contract level metadata. */ function setContractURI(string memory _newContractURI) external; /** * @notice For OpenSea contract level metadata. */ function contractURI() external view returns (string memory); /** * @notice Set a new payment fee percent. Value of 100 = 1%, 1000 = 10%, 10000 = 100% * @param _newFeePercent New fee percent division value. */ function setNewFeePercent(uint _newFeePercent) external; /** * @notice Gets the fee to deduct from a payment. * @param amount The amount of the specified token to be withdrawn. * @param gasprice The current gasprice for the transaction. * @return fee The fee amount in MATIC wei. */ function getPaymentFee(uint amount, uint gasprice) external view returns (uint256); /** * @notice Allows payment amount of native token to be sent to a user. * @param tokenId uint256 ID of the token * @param data string reason for transfer */ function payDomain(uint256 tokenId, string calldata data) external payable returns (bool); /** * @notice Allows payment amount of native token to be sent to a domain user. * @param addressTo The address to send the token to. * @param data string reason for transfer */ function payAccount(address payable addressTo, string calldata data) external payable returns (bool); /** * @notice Allows contract owner to withdraw an amount of native token from the contract balance. */ function withdraw(address payable addressTo, uint amount) external returns (bool); /** * @notice Allows contract owner to withdraw an amount of a specified ERC20 token from the contract balance. * @param tokenAddress The address of the ERC-20 compliant token. * @param addressTo The address to send to token to. * @param amount The amount of the specified token to be withdrawn. */ function withdrawErc20(address tokenAddress, address payable addressTo, uint amount) external returns (bool); /** * @dev Existence of token. * @param tokenId uint256 ID of the token */ function exists(uint256 tokenId) external view returns (bool); /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * Requirements: * - `tokenId` must exist. * @param spender Address of account being queried * @param tokenId uint256 ID of the token */ function isUserOrApproved(address spender, uint256 tokenId) external view returns (bool); /**@notice Burns tokens * @param tokenId uint256 ID of the token */ function burn(uint256 tokenId) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IERC4907 { // Logged when the user of a token assigns a new user or updates expires /** * @notice Emitted when the `user` of an NFT or the `expires` of the `user` is changed * The zero address for user indicates that there is no user address */ event UpdateUser(uint256 indexed tokenId, address indexed user, uint64 expires); /** * @notice set the user and expires of a NFT * @dev The zero address indicates there is no user * Throws if `tokenId` is not valid NFT * @param user The new user of the NFT * @param expires UNIX timestamp, The new user could use the NFT before expires */ function setUser(uint256 tokenId, address user, uint64 expires) external; /** * @notice Get the user address of an NFT * @dev The ownerOf address indicates there is no user or the user is expired * @param tokenId The NFT to get the user address for * @return The user address for this NFT */ function userOf(uint256 tokenId) external view returns (address); /** * @notice Get the user expires of an NFT * @dev The MAX uint256 value returned indicates that the user is the owner * @param tokenId The NFT to get the user expires for * @return The user expires for this NFT */ function userExpires(uint256 tokenId) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.6; /** * @title Chainlink Functions client interface. */ interface IMetadata { /** * @notice Sets the Domain Registry Address. Only performed once after Domain registry deployment. * @param domainRegistryAddress The Domain Registry address. */ function setDomainRegistry(address domainRegistryAddress) external; /** * @notice Compiles the NFT metadata data for marketplace access to metadata through TokenURI function. * @param tokenId uint256 ID of the token */ function getOnChainMetadata(uint256 tokenId) external view returns (string memory); /** * @notice Sets the svgStrings storage array */ function setSvgStringArray(string[] memory svgStringsArray) external; /** * @notice Sets the attributeStrings storage array */ function setAttributeStringArray(string[] memory attributeStringsArray) external; /** * @notice Returns the svgStrings storage array */ function getSvgStringArray() external view returns (string[] memory values); /** * @notice Returns the attributeStrings storage array */ function getAttributeStringArray() external view returns (string[] memory values); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /** * @title Chainlink Functions client interface. */ interface IPlusCodes { /** * @notice Utilizes checkCode function to determine if code is valid. * Returns boolean depending on validity * @param _code The google Plus Code */ function isValid(string memory _code) external pure returns (bool); /** * @notice Determines if a code is valid full Open Location Code. * To be valid, all characters must be from the Open Location Code character * set with only one separator. The separator can be in position eight only. * Not all possible combinations of Open Location Code characters decode to * valid latitude and longitude values. This checks that a code is valid * and also that the latitude and longitude values are legal. If the prefix * character is present, it must be the first character. * Example code: 8GWM4M34+8QR * Returns the Plus Code corrected to upper case if valid. * @param _code The google Plus Code */ function checkCode(string memory _code) external pure returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IRecordReader { /** * @dev Function to get record. * @param key The key to query the value of. * @param tokenId The token id to query. * @return The value string. */ function get(string calldata key, uint256 tokenId) external view returns (string memory); /** * @dev Function to get multiple record. * @param keys The keys to query the value of. * @param tokenId The token id to query. * @return The values. */ function getMany(string[] calldata keys, uint256 tokenId) external view returns (string[] memory); /** * @dev Function get value by provided key hash. * @param keyHash The key to query the value of. * @param tokenId The token id to query. */ function getByHash(uint256 keyHash, uint256 tokenId) external view returns (string memory key, string memory value); /** * @dev Function get values by provided key hashes. * @param keyHashes The key to query the value of. * @param tokenId The token id to query. */ function getManyByHash( uint256[] calldata keyHashes, uint256 tokenId ) external view returns (string[] memory keys, string[] memory values); /** * @dev Function get all keys associated with a token ID. * @param tokenId The token id to query. */ function getKeysOf( uint256 tokenId ) external view returns (string[] memory keys); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import './IRecordReader.sol'; interface IRecordStorage is IRecordReader { event Set(uint256 indexed tokenId, string indexed keyIndex, string indexed valueIndex, string key, string value); event NewKey(uint256 indexed tokenId, string indexed keyIndex, string key); event ResetRecords(uint256 indexed tokenId); /** * @dev Set record by key * @param key The key set the value of * @param value The value to set key to * @param tokenId ERC-721 token id to set */ function set( string calldata key, string calldata value, uint256 tokenId ) external; /** * @dev Set records by keys * @param keys The keys set the values of * @param values Records values * @param tokenId ERC-721 token id of the domain */ function setMany( string[] memory keys, string[] memory values, uint256 tokenId ) external; /** * @dev Set record by key hash * @param keyHash The key hash set the value of * @param value The value to set key to * @param tokenId ERC-721 token id to set */ function setByHash( uint256 keyHash, string calldata value, uint256 tokenId ) external; /** * @dev Set records by key hashes * @param keyHashes The key hashes set the values of * @param values Records values * @param tokenId ERC-721 token id of the domain */ function setManyByHash( uint256[] calldata keyHashes, string[] calldata values, uint256 tokenId ) external; /** * @dev Reset all existing key records for a token ID and set new ones * @param keys New record keys * @param values New record values * @param tokenId ERC-721 token id of the domain */ function reconfigure( string[] memory keys, string[] memory values, uint256 tokenId ) external; /** * @dev Function to reset all existing key records for a token ID. * @param tokenId ERC-721 token id to set. */ function reset(uint256 tokenId) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; abstract contract KeyStorage { mapping(uint256 => string) private _keys; function getKey(uint256 keyHash) public view returns (string memory) { return _keys[keyHash]; } function getKeys(uint256[] calldata hashes) public view returns (string[] memory values) { return _getKeys(hashes); } function addKey(string memory key) external { _addKey(uint256(keccak256(abi.encodePacked(key))), key); } function _existsKey(uint256 keyHash) internal view returns (bool) { return bytes(_keys[keyHash]).length > 0; } function _addKey(uint256 keyHash, string memory key) internal { if (!_existsKey(keyHash)) { _keys[keyHash] = key; } } function _getKeys(uint256[] memory hashes) internal view returns (string[] memory values) { values = new string[](hashes.length); for (uint256 i = 0; i < hashes.length; i++) { values[i] = _keys[hashes[i]]; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; import {StringUtilsLib} from "./StringUtilsLib.sol"; import {IPlusCodes} from "./interfaces/IPlusCodes.sol"; contract PlusCodes is IPlusCodes { using StringUtilsLib for string; constructor() {} // // Open Location Codes are short, 11 character codes (12 including '+') that can be used instead // of street addresses. The codes can be generated and decoded offline, and use // a reduced character set that minimises the chance of codes including words. // // A separator used to break the code into two parts to aid memorability. string private constant SEPARATOR_ = "+"; // The number of characters to place before the separator. uint private constant SEPARATOR_POSITION_ = 8; // The character used to pad codes. string private constant PADDING_CHARACTER_ = "0"; // The character set used to encode the values. string private constant CODE_ALPHABET_ = "23456789CFGHJMPQRVWX"; // The base to use to convert numbers to/from. uint private constant ENCODING_BASE_ = 20; // The maximum value for latitude in degrees. uint private constant LATITUDE_MAX_ = 180; // The maximum value for longitude in degrees. uint private constant LONGITUDE_MAX_ = 360; // The max number of digits to process in a Plus Code. uint private constant CODE_LENGTH_ = 12; /** * @notice Utilizes checkCode function to determine if code is valid. * Returns boolean depending on validity * @param _code The google Plus Code */ function isValid(string memory _code) public pure override returns (bool) { if(bytes(checkCode(_code)).length == 0) { return false; } return true; } /** * @notice Determines if a code is valid full Open Location Code. * To be valid, all characters must be from the Open Location Code character * set with only one separator. The separator can be in position eight only. * Not all possible combinations of Open Location Code characters decode to * valid latitude and longitude values. This checks that a code is valid * and also that the latitude and longitude values are legal. If the prefix * character is present, it must be the first character. * Example code: 8GWM4M34+8QR * Returns the Plus Code corrected to upper case if valid. * @param _code The google Plus Code */ function checkCode(string memory _code) public pure override returns (string memory) { // code length is correct? if (!(bytes(_code).length == CODE_LENGTH_)) { return ""; } string memory code = _code.toUpperCase(); // The separator is required. (bool sepExists, int256 sepPos) = code.matchStr(SEPARATOR_); if (!sepExists) { return ""; } // Code cannot contain more than one seperator // allIndexOf returns an additional index value of '0' at the end of all returned arrays as default. // therfore a string containing one character position will return an array length of 2. if (code.lastIndexOf(SEPARATOR_) != uint256(sepPos)) { return ""; } // Is seperator in an illegal position? if (uint256(sepPos) != SEPARATOR_POSITION_) { return ""; } // Check the code contains only valid characters and cannot be padded. for (uint i = 0; i < bytes(code).length; i++) { string memory ch = code.charAt(i); if (!CODE_ALPHABET_.includes(ch) && !SEPARATOR_.includes(ch)) { return ""; } } // Work out what the first latitude character indicates for latitude. string memory firstLatChar = code.charAt(0); uint256 firstLatValue = CODE_ALPHABET_.indexOf(firstLatChar.toUpperCase()) * ENCODING_BASE_; if (firstLatValue >= LATITUDE_MAX_) { // The code would decode to a latitude of >= 90 degrees. return ""; } // Work out what the first longitude character indicates for longitude. string memory firstLonChar = code.charAt(1); uint256 firstLngValue = CODE_ALPHABET_.indexOf(firstLonChar.toUpperCase()) * ENCODING_BASE_; if (firstLngValue >= LONGITUDE_MAX_) { // The code would decode to a longitude of >= 180 degrees. return ""; } return code; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./interfaces/IRecordStorage.sol"; import "./KeyStorage.sol"; abstract contract RecordStorage is KeyStorage, IRecordStorage { /// @dev mapping of tokenIds to keyIds to values mapping(uint256 => mapping(uint256 => string)) internal _records; /// @dev mapping of tokenIds to keyIds mapping(uint256 => uint256[]) internal _tokenKeys; function get(string calldata key, uint256 tokenId) external view override returns (string memory value) { value = _get(key, tokenId); } function getMany(string[] calldata keys, uint256 tokenId) external view override returns (string[] memory values) { values = new string[](keys.length); for (uint256 i = 0; i < keys.length; i++) { values[i] = _get(keys[i], tokenId); } } function getByHash( uint256 keyHash, uint256 tokenId ) external view override returns (string memory key, string memory value) { (key, value) = _getByHash(keyHash, tokenId); } function getManyByHash( uint256[] calldata keyHashes, uint256 tokenId ) external view override returns (string[] memory keys, string[] memory values) { keys = new string[](keyHashes.length); values = new string[](keyHashes.length); for (uint256 i = 0; i < keyHashes.length; i++) { (keys[i], values[i]) = _getByHash(keyHashes[i], tokenId); } } function getKeysOf(uint256 tokenId) external view override returns (string[] memory) { return _getKeys(_tokenKeys[tokenId]); } function _set(string calldata key, string calldata value, uint256 tokenId) internal { uint256 keyHash = uint256(keccak256(abi.encodePacked(key))); _addKey(keyHash, key); _set(keyHash, key, value, tokenId); } function _setMany(string[] calldata keys, string[] calldata values, uint256 tokenId) internal { for (uint256 i = 0; i < keys.length; i++) { _set(keys[i], values[i], tokenId); } } function _setByHash(uint256 keyHash, string calldata value, uint256 tokenId) internal { require(_existsKey(keyHash), "RecordStorage: KEY_NOT_FOUND"); _set(keyHash, getKey(keyHash), value, tokenId); } function _setManyByHash(uint256[] calldata keyHashes, string[] calldata values, uint256 tokenId) internal { for (uint256 i = 0; i < keyHashes.length; i++) { _setByHash(keyHashes[i], values[i], tokenId); } } function _reconfigure(string[] calldata keys, string[] calldata values, uint256 tokenId) internal { _reset(tokenId); _setMany(keys, values, tokenId); } function _reset(uint256 tokenId) internal { for(uint256 i = 0; i<_tokenKeys[tokenId].length; i++){ delete _records[tokenId][_tokenKeys[tokenId][i]]; } delete _tokenKeys[tokenId]; emit ResetRecords(tokenId); } function _get(string memory key, uint256 tokenId) private view returns (string memory) { return _get(uint256(keccak256(abi.encodePacked(key))), tokenId); } function _getByHash(uint256 keyHash, uint256 tokenId) private view returns (string memory key, string memory value) { key = getKey(keyHash); value = _get(keyHash, tokenId); } function _get(uint256 keyHash, uint256 tokenId) private view returns (string memory) { return _records[tokenId][keyHash]; } function _set(uint256 keyHash, string memory key, string memory value, uint256 tokenId) private { if (bytes(_records[tokenId][keyHash]).length == 0) { _tokenKeys[tokenId].push(keyHash); emit NewKey(tokenId, key, key); } _records[tokenId][keyHash] = value; emit Set(tokenId, key, value, key, value); } }
//SPDX-License-Identifier: MIT /* * @title String Utils Library for Solidity contracts. * @author Tega Osowa <https://tega-osowa-portfolio.netlify.app/> * * @dev This is a comprehensive string utils library for processing and programmatically * working with strings. This library is focused on making the use of strings more * user-friendly, or programmer friendly. * * The gas cost for implementing various operations would definitely defer, * depending on the size and length of the string being processed. For large strings, * pre-processing is advised, so as to reduce the gas cost. Operations like toLowerCase, * toUpperCase and isEqualCase, consumes much more gas than other operations, and is * advised to be used wisely, preferably on smaller strings. * All functions are written with simplicity in mind, and should be easy to use and * implement, please feel free to make any request or update for request to me, * it's still a work in progress, and this contribution is important to the Web3 Community. * Code Away */ pragma solidity ^0.8.18; library StringUtilsLib { /* * @dev Returns an array containing the splitted string. * @param text The string to split. * @param char The string to split by. * @param propsedLength The proposed length of the array. * @return A string array. */ function split( string memory text, string memory char, uint256 proposedLength ) internal pure returns (string[] memory) { text = string.concat(text, char); bytes memory nt = bytes(text); bytes memory nc = bytes(char); string[] memory array = new string[](proposedLength); uint256 pointA = 0; uint256 i = 0; uint256 visiblePoint = 0; while (i < nt.length) { bytes memory findBytes = new bytes(nc.length); uint256 count = 0; for ( uint256 a = i; a < ( (nc.length > (nt.length - i)) ? (nt.length - i) : (i + nc.length) ); a++ ) { findBytes[count] = bytes(text)[a]; count++; } string memory find = string(findBytes); if ( keccak256(abi.encodePacked(find)) == keccak256(abi.encodePacked(char)) ) { bytes memory findBytes1 = new bytes(i - pointA); uint256 count1 = 0; for (uint256 a = pointA; a < i; a++) { findBytes1[count1] = bytes(text)[a]; count1++; } array[visiblePoint] = string(findBytes1); visiblePoint++; i += nc.length; pointA = i; } else { i += 1; } } string[] memory n_array = new string[](visiblePoint); for (uint256 a = 0; a < (visiblePoint); a++) { n_array[a] = array[a]; } array = new string[](0); return n_array.length > 1 ? n_array : new string[](0); } /* * @dev Returns a bool stating true if the string is included in the text. * @param text The string to check. * @param search The string to search for. * @param propsedLength The proposed length of the array. * @return A bool which is true if the string is the text. */ function includes( string memory text, string memory search ) internal pure returns (bool) { bytes memory nt = bytes(text); bytes memory nc = bytes(search); bool exist = false; for (uint256 i = 0; i < nt.length; i++) { bytes memory findBytes = new bytes(nc.length); uint256 count = 0; for (uint256 a = i; a < (i + nc.length); a++) { findBytes[count] = bytes(text)[a]; count++; } string memory find = string(findBytes); if ( keccak256(abi.encodePacked(find)) == keccak256(abi.encodePacked(search)) ) { exist = true; break; } } return exist; } /* * @dev Replaces the first occurance of a string in the text with a new string. * @param text The string to check. * @param replace The string to search for. * @param newtext The string to replace with. * @return A new string which contains the replaced text. */ function replaceOne( string memory text, string memory replace, string memory newtext ) internal pure returns (string memory) { bytes memory nt = bytes(text); bytes memory nc = bytes(replace); bytes memory nrt = bytes(newtext); string memory replacedString = ""; for (uint256 i = 0; i < nt.length; i++) { bytes memory findBytes = new bytes(nc.length); uint256 count = 0; for (uint256 a = i; a < (i + nc.length); a++) { findBytes[count] = bytes(text)[a]; count++; } string memory find = string(findBytes); if ( keccak256(abi.encodePacked(find)) == keccak256(abi.encodePacked(replace)) ) { bytes memory findBytes1 = new bytes( (nt.length - nc.length) + nrt.length ); uint256 count1 = 0; for (uint256 a = 0; a < i; a++) { findBytes1[count1] = bytes(text)[a]; count1++; } for (uint256 a = 0; a < nrt.length; a++) { findBytes1[count1] = bytes(newtext)[a]; count1++; } for (uint256 a = (i + nc.length); a < (nt.length); a++) { findBytes1[count1] = bytes(text)[a]; count1++; } replacedString = string(findBytes1); break; } } return replacedString; } /* * @dev Replaces all occurance of a string in the text with a new string. * @param text The string to check. * @param replace The string to search for. * @param newtext The string to replace with. * @return A new string which contains the replaced text. */ function replaceAll( string memory text, string memory replace, string memory newtext ) internal pure returns (string memory) { bytes memory nt = bytes(text); bytes memory nc = bytes(replace); bytes memory nrt = bytes(newtext); string memory replacedString = ""; uint256 i = 0; uint256 pointA = 0; while (i < nt.length) { bytes memory findBytes = new bytes(nc.length); uint256 count = 0; for ( uint256 a = i; a < ( (nc.length > (nt.length - i)) ? (nt.length - i) : (i + nc.length) ); a++ ) { findBytes[count] = bytes(text)[a]; count++; } string memory find = string(findBytes); if ( keccak256(abi.encodePacked(find)) == keccak256(abi.encodePacked(replace)) ) { bytes memory findBytes1 = new bytes((i - pointA) + nrt.length); uint256 count1 = 0; for (uint256 a = pointA; a < i; a++) { findBytes1[count1] = bytes(text)[a]; count1++; } for (uint256 a = 0; a < nrt.length; a++) { findBytes1[count1] = bytes(newtext)[a]; count1++; } replacedString = string.concat( replacedString, string(findBytes1) ); i += nc.length; pointA = i; } else { i += 1; } } bytes memory findBytes2 = new bytes(nt.length - pointA); uint256 count2 = 0; for (uint256 a = pointA; a < nt.length; a++) { findBytes2[count2] = bytes(text)[a]; count2++; } replacedString = string.concat(replacedString, string(findBytes2)); return replacedString; } /* * @dev Matches a string with the text. * @param text The string to check. * @param matchtext The string to match with. * @return A bool and an int256 if the string was found and the index it was found at. */ function matchStr( string memory text, string memory matchtext ) internal pure returns (bool exist, int256 start) { bytes memory nt = bytes(text); bytes memory nc = bytes(matchtext); bool matchExist = false; int256 matchStart = -1; int256 count1 = 0; for (uint256 i = 0; i < nt.length; i++) { bytes memory findBytes = new bytes(nc.length); uint256 count = 0; for (uint256 a = i; a < (i + nc.length); a++) { findBytes[count] = bytes(text)[a]; count++; } string memory find = string(findBytes); if ( keccak256(abi.encodePacked(find)) == keccak256(abi.encodePacked(matchtext)) ) { matchExist = true; matchStart = count1; break; } count1++; } return (matchExist, matchStart); } /* * @dev Changes string to lowercase. * @param text The string to change. * @return A new string which is all lowercase. */ function toLowerCase( string memory text ) internal pure returns (string memory) { string memory charsString = "Aa;Bb;Cc;Dd;Ee;Ff;Gg;Hh;Ii;Jj;Kk;Ll;Mm;Nn;Oo;Pp;Qq;Rr;Ss;Tt;Uu;Vv;Ww;Xx;Yy;Zz"; string[] memory chars = split(charsString, ";", 40); bytes memory nt = bytes(text); string memory lowerCase = ""; for (uint256 i = 0; i < nt.length; i++) { bytes memory findBytes = new bytes(1); findBytes[0] = bytes(text)[i]; bool exist = false; for (uint256 a = 0; a < chars.length; a++) { bool contains = includes(chars[a], string(findBytes)); if (contains) { bytes memory findBytes1 = new bytes(1); findBytes1[0] = bytes(chars[a])[1]; lowerCase = string.concat(lowerCase, string(findBytes1)); exist = true; break; } } if (exist == false) { lowerCase = string.concat(lowerCase, string(findBytes)); } } return lowerCase; } /* * @dev Converts string to uppercase. * @param text The string to change. * @return A new string which is all uppercase. */ function toUpperCase( string memory text ) internal pure returns (string memory) { string memory charsString = "Aa;Bb;Cc;Dd;Ee;Ff;Gg;Hh;Ii;Jj;Kk;Ll;Mm;Nn;Oo;Pp;Qq;Rr;Ss;Tt;Uu;Vv;Ww;Xx;Yy;Zz"; string[] memory chars = split(charsString, ";", 40); bytes memory nt = bytes(text); string memory upperCase = ""; for (uint256 i = 0; i < nt.length; i++) { bytes memory findBytes = new bytes(1); findBytes[0] = bytes(text)[i]; bool exist = false; for (uint256 a = 0; a < chars.length; a++) { bool contains = includes(chars[a], string(findBytes)); if (contains) { bytes memory findBytes1 = new bytes(1); findBytes1[0] = bytes(chars[a])[0]; upperCase = string.concat(upperCase, string(findBytes1)); exist = true; break; } } if (exist == false) { upperCase = string.concat(upperCase, string(findBytes)); } } return upperCase; } /* * @dev Repeats a string as many times as repeatLength * @param text The string to repeat. * @param repeatLength The amount of times to repeat. * @return A new string which is which contains all repetations of the text */ function repeat( string memory text, uint256 repeatLength ) internal pure returns (string memory) { string memory repeatedString = ""; for (uint256 i = 0; i < repeatLength; i++) { repeatedString = string.concat(repeatedString, text); } return repeatedString; } /* * @dev Adds padding to the start of the string. * @param text The string to pad. * @param lengthCount The length needed for the string * @param padding The padding to string. * @return A new string which is padded at the start. */ function padStart( string memory text, uint256 lengthCount, string memory padding ) internal pure returns (string memory) { string memory paddedString = ""; bytes memory nt = bytes(text); for ( uint256 i = 0; i < ((lengthCount > nt.length ? lengthCount : nt.length) - nt.length); i++ ) { paddedString = string.concat(paddedString, padding); } return string.concat(paddedString, text); } /* * @dev Adds padding to the end of the string. * @param text The string to pad. * @param lengthCount The length needed for the string * @param padding The padding to string. * @return A new string which is padded at the end. */ function padEnd( string memory text, uint256 lengthCount, string memory padding ) internal pure returns (string memory) { string memory paddedString = ""; bytes memory nt = bytes(text); for ( uint256 i = 0; i < ((lengthCount > nt.length ? lengthCount : nt.length) - nt.length); i++ ) { paddedString = string.concat(paddedString, padding); } return string.concat(text, paddedString); } /* * Slice a section of string out of the string. * @param text The string to slice. * @param start The index to start slice * @param end The index to end slice. * @return A new string that does not contain from the @param start to the @param end. */ function slice( string memory text, uint256 start, uint256 end ) internal pure returns (string memory) { bytes memory nt = bytes(text); bytes memory findBytes = new bytes(nt.length - ((end - 1) + start)); uint256 count = 0; for (uint256 a = 0; a < start; a++) { findBytes[count] = bytes(text)[a]; count++; } for (uint256 a = end + 1; a < nt.length; a++) { findBytes[count] = bytes(text)[a]; count++; } string memory sliceString = string(findBytes); return sliceString; } /* * Checks if the text is equal to a string * @param text The string to check. * @param compare The string to check with * @return A bool which is true if the text is equal */ function isEqual( string memory text, string memory compare ) internal pure returns (bool) { return (keccak256(abi.encodePacked(text)) == keccak256(abi.encodePacked(compare))); } /* * Checks if the text is equal to a string in both upper and lowercase * @param text The string to check. * @param compare The string to check with * @return A bool which is true if the text is equal */ function isEqualCase( string memory text, string memory compare ) internal pure returns (bool) { return ((keccak256(abi.encodePacked(toUpperCase(text))) == keccak256(abi.encodePacked(toUpperCase(compare)))) && (keccak256(abi.encodePacked(toLowerCase(text))) == keccak256(abi.encodePacked(toLowerCase(compare))))); } /* * Creates a substring from the text. * @param text The string to create the string from. * @param start The index to start the sub string * @param end The index to end the sub string. * @return A new string that is a sub string of the text from the @param start to the @param end. */ function substring( string memory text, uint256 start, uint256 end ) internal pure returns (string memory) { bytes memory findBytes = new bytes((end + 1) - start); uint256 count = 0; for (uint256 a = start; a < (end + 1); a++) { findBytes[count] = bytes(text)[a]; count++; } string memory subString = string(findBytes); return subString; } /* * @dev Removes unnecesary space from the start of the string. * @param text The string to trim. * @return A new string which is trimmed at the start. */ function trimStart( string memory text ) internal pure returns (string memory) { bytes memory nt = bytes(text); uint256 i = 0; uint256 count = 0; while (i < nt.length) { bytes memory findBytes = new bytes(1); findBytes[0] = bytes(text)[i]; if (!isEqual(string(findBytes), " ")) { count = i; break; } i++; } string memory trimmedString = substring(text, count, nt.length - 1); return trimmedString; } /* * @dev Removes unnecesary space from the end of the string. * @param text The string to trim. * @return A new string which is trimmed at the end. */ function trimEnd(string memory text) internal pure returns (string memory) { bytes memory nt = bytes(text); uint256 i = nt.length - 1; uint256 count = 0; while (i >= 0) { bytes memory findBytes = new bytes(1); findBytes[0] = bytes(text)[i]; if (!isEqual(string(findBytes), " ")) { count = i; break; } i--; } string memory trimmedString = substring(text, 0, count); return trimmedString; } /* * @dev Removes unnecesary space from the start and end of the string. * @param text The string to trim. * @return A new string which is trimmed at the start and end. */ function trim(string memory text) internal pure returns (string memory) { string memory startTrim = trimStart(text); string memory trimmedString = trimEnd(startTrim); return trimmedString; } /* * @dev Gets the character at an index in the text. * @param text The string to search. * @param index The index to get. * @return the character at the index. */ function charAt( string memory text, uint256 index ) internal pure returns (string memory) { bytes memory findBytes = new bytes(1); findBytes[0] = bytes(text)[index]; return string(findBytes); } /* * @dev Gets the first index of a character in the text. * @param text The string to search. * @param char The character to get. * @return the index of the character. */ function indexOf( string memory text, string memory char ) internal pure returns (uint256) { bytes memory nt = bytes(text); uint256 count = 0; for (uint256 i = 0; i < nt.length; i++) { bytes memory findBytes = new bytes(1); findBytes[0] = bytes(text)[i]; if (isEqual(string(findBytes), char)) { count = i; break; } } return count; } /* * @dev Gets the last index of a character in the text. * @param text The string to search. * @param char The character to get. * @return the index of the character. */ function lastIndexOf( string memory text, string memory char ) internal pure returns (uint256) { bytes memory nt = bytes(text); uint256 count = 0; for (uint256 i = 0; i < nt.length; i++) { bytes memory findBytes = new bytes(1); findBytes[0] = bytes(text)[i]; if (isEqual(string(findBytes), char)) { count = i; } } return count; } /* * @dev Gets all the index of a character in the text. * @param text The string to search. * @param char The character to get. * @return the index of the character. */ function allIndexOf( string memory text, string memory char, uint256 proposedLength ) internal pure returns (uint256[] memory) { bytes memory nt = bytes(text); uint256[] memory array = new uint256[](proposedLength); uint256 visiblePoint = 0; for (uint256 i = 0; i < nt.length; i++) { bytes memory findBytes = new bytes(1); findBytes[0] = bytes(text)[i]; if (isEqual(string(findBytes), char)) { array[visiblePoint] = i; visiblePoint++; } } uint256[] memory n_array = new uint256[](visiblePoint + 1); for (uint256 a = 0; a < (visiblePoint + 1); a++) { n_array[a] = array[a]; } array = new uint256[](0); return n_array.length > 1 ? n_array : new uint256[](0); } /* * @dev Checks if the text starts with a string. * @param text The string to search. * @param start The string to check for. * @return A bool if the text starts with a string. */ function startsWith( string memory text, string memory start ) internal pure returns (bool) { bytes memory nt = bytes(text); bytes memory nc = bytes(start); bool startsWidthString = false; if (nt.length > nc.length) { bytes memory findBytes = new bytes(nc.length); uint256 count = 0; for (uint256 a = 0; a < nc.length; a++) { findBytes[count] = bytes(text)[a]; count++; } string memory find = string(findBytes); startsWidthString = isEqual(start, find); } return startsWidthString; } /* * @dev Checks if the text ends with a string. * @param text The string to search. * @param end The string to check for. * @return A bool if the text ends with a string. */ function endsWith( string memory text, string memory end ) internal pure returns (bool) { bytes memory nt = bytes(text); bytes memory nc = bytes(end); bool endsWidthString = false; if (nt.length > nc.length) { bytes memory findBytes = new bytes(nc.length); uint256 count = 0; for (uint256 a = (nt.length - nc.length); a < nt.length; a++) { findBytes[count] = bytes(text)[a]; count++; } string memory find = string(findBytes); endsWidthString = isEqual(end, find); } return endsWidthString; } /* * @dev Parses a string to the uint256 of the string. * @param text The string to parse. * @return The uint256 of the string. */ function parseInt(string memory text) internal pure returns (uint256) { uint256 number = 0; bytes memory nt = bytes(text); uint256[] memory numbers = new uint256[](10); numbers[0] = 0; numbers[1] = 1; numbers[2] = 2; numbers[3] = 3; numbers[4] = 4; numbers[5] = 5; numbers[6] = 6; numbers[7] = 7; numbers[8] = 8; numbers[9] = 9; string[] memory numbersString = new string[](10); numbersString[0] = "0"; numbersString[1] = "1"; numbersString[2] = "2"; numbersString[3] = "3"; numbersString[4] = "4"; numbersString[5] = "5"; numbersString[6] = "6"; numbersString[7] = "7"; numbersString[8] = "8"; numbersString[9] = "9"; for (uint256 i = 0; i < nt.length; i++) { bytes memory findBytes = new bytes(1); findBytes[0] = bytes(text)[i]; string memory numberStringToCheck = string(findBytes); uint256 checkNum = 0; for (uint256 a = 0; a < numbersString.length; a++) { if (isEqual(numbersString[a], numberStringToCheck)) { checkNum = a; break; } } uint256 numberToParse = numbers[checkNum]; string memory subString = substring(text, i, nt.length - 1); number += (numberToParse * (10 ** (bytes(subString).length - 1))); } return number; } function logBase10(uint256 number) private pure returns (uint256) { uint256 log = 0; while ((10 ** log) < number) { log++; } return log + 1; } /* * @dev Changes a uint256 to a string. * @param number The number to change. * @return The string. */ function parseString(uint256 number) internal pure returns (string memory) { uint256 subNum = 1; if (number > 0) { if ((number / subNum) > 9) { subNum *= 10; while ((number / subNum) > 9) { subNum *= 10; } } else if ((number / subNum) < 1) { subNum /= 10; while ((number / subNum) < 1) { subNum /= 10; } } } string[] memory numbersString = new string[](10); numbersString[0] = "0"; numbersString[1] = "1"; numbersString[2] = "2"; numbersString[3] = "3"; numbersString[4] = "4"; numbersString[5] = "5"; numbersString[6] = "6"; numbersString[7] = "7"; numbersString[8] = "8"; numbersString[9] = "9"; string memory text = ""; uint256 workingNumber = number; uint256 lengthOfNumber = logBase10(subNum); for (uint256 i = 0; i < lengthOfNumber; i++) { uint256 firstNumber = workingNumber / subNum; uint256 remainder = workingNumber % subNum; text = string.concat(text, numbersString[firstNumber]); workingNumber = remainder; subNum /= 10; } return text; } /* * Gets the length of the string. * @param text The string to ge length. * @return The uint256 length of the string. */ function length(string memory text) internal pure returns (uint256) { bytes memory nt = bytes(text); return nt.length; } }
{ "optimizer": { "enabled": true, "runs": 1000 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract ABI
API[{"inputs":[{"internalType":"string","name":"baseURI","type":"string"},{"internalType":"address","name":"metadata","type":"address"},{"internalType":"uint256","name":"mintCostUsd","type":"uint256"},{"internalType":"uint256","name":"feePercent","type":"uint256"},{"internalType":"address","name":"maticUsdFeed","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","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":[],"name":"EmptyValue","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"IndexError","type":"error"},{"inputs":[{"internalType":"string","name":"code","type":"string"}],"name":"InvalidPlusCode","type":"error"},{"inputs":[{"internalType":"int256","name":"_usdWei","type":"int256"}],"name":"InvalidUSDWeiPrice","type":"error"},{"inputs":[],"name":"LowBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"_requires","type":"uint256"},{"internalType":"uint256","name":"_provided","type":"uint256"}],"name":"NotEnoughWei","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":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","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":[],"name":"ContractURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"percent","type":"uint256"}],"name":"FeePercentUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"metadataContract","type":"address"}],"name":"IMetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"priceFeedContract","type":"address"}],"name":"IPriceFeedUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"MetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"_newBaseURI","type":"string"}],"name":"NewBaseURI","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"string","name":"keyIndex","type":"string"},{"indexed":false,"internalType":"string","name":"key","type":"string"}],"name":"NewKey","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addressTo","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"string","name":"data","type":"string"}],"name":"PayAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addressTo","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"string","name":"plusCode","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"string","name":"data","type":"string"}],"name":"PayDomain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Received","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RefundOverpayment","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ResetRecords","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"string","name":"keyIndex","type":"string"},{"indexed":true,"internalType":"string","name":"valueIndex","type":"string"},{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"string","name":"value","type":"string"}],"name":"Set","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint64","name":"expires","type":"uint64"}],"name":"UpdateUser","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addressTo","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"addressTo","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawERC20","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"MAX_UINT256","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"key","type":"string"}],"name":"addKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_code","type":"string"}],"name":"checkCode","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"checkPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"key","type":"string"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"get","outputs":[{"internalType":"string","name":"value","type":"string"}],"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":"getBaseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"keyHash","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getByHash","outputs":[{"internalType":"string","name":"key","type":"string"},{"internalType":"string","name":"value","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeedData","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"keyHash","type":"uint256"}],"name":"getKey","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"hashes","type":"uint256[]"}],"name":"getKeys","outputs":[{"internalType":"string[]","name":"values","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getKeysOf","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string[]","name":"keys","type":"string[]"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getMany","outputs":[{"internalType":"string[]","name":"values","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"keyHashes","type":"uint256[]"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getManyByHash","outputs":[{"internalType":"string[]","name":"keys","type":"string[]"},{"internalType":"string[]","name":"values","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMetadataContractAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"finish","type":"uint256"}],"name":"getOwnersArray","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"gasprice","type":"uint256"}],"name":"getPaymentFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getPlusCode","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"finish","type":"uint256"}],"name":"getPlusCodesArray","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPriceFeedContractAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"finish","type":"uint256"}],"name":"getTokenIdsArray","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokenIdsCount","outputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"finish","type":"uint256"}],"name":"getUsersArray","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isApprovedOrOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isUserOrApproved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_code","type":"string"}],"name":"isValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"string","name":"plusCode","type":"string"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"plusCode","type":"string"},{"internalType":"string[]","name":"keys","type":"string[]"},{"internalType":"string[]","name":"values","type":"string[]"}],"name":"mintWithRecords","outputs":[],"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":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"addressTo","type":"address"},{"internalType":"string","name":"data","type":"string"}],"name":"payAccount","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"data","type":"string"}],"name":"payDomain","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"plusCode","type":"string"}],"name":"plusCodeToTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"string[]","name":"keys","type":"string[]"},{"internalType":"string[]","name":"values","type":"string[]"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"reconfigure","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"reset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"s_baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"s_feePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"s_mintCostUsd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"s_tokenIdToPlusCode","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"key","type":"string"},{"internalType":"string","name":"value","type":"string"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_newBaseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"keyHash","type":"uint256"},{"internalType":"string","name":"value","type":"string"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"setByHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_newContractURI","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string[]","name":"keys","type":"string[]"},{"internalType":"string[]","name":"values","type":"string[]"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"setMany","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"keyHashes","type":"uint256[]"},{"internalType":"string[]","name":"values","type":"string[]"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"setManyByHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newFeePercent","type":"uint256"}],"name":"setNewFeePercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint64","name":"expires","type":"uint64"}],"name":"setUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newMetaDataContract","type":"address"}],"name":"updateMetadataContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newPriceFeedAddress","type":"address"}],"name":"updatePriceFeedContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"userExpires","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"userOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"addressTo","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address payable","name":"addressTo","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawErc20","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620061e9380380620061e98339810160408190526200003491620001c9565b336040518060400160405280601781526020017f54616e6769626c696e6b20446f6d61696e73205445535400000000000000000081525060405180604001604052806002815260200161151160f21b815250816000908162000097919062000366565b506001620000a6828262000366565b50506007805460ff19169055506001600160a01b038116620000e257604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b620000ed816200013c565b50600c620000fc868262000366565b50600d80546001600160a01b039586166001600160a01b031991821617909155600e93909355600f91909155601080549190931691161790555062000432565b600780546001600160a01b03838116610100818102610100600160a81b031985161790945560405193909204169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b0381168114620001c457600080fd5b919050565b600080600080600060a08688031215620001e257600080fd5b85516001600160401b0380821115620001fa57600080fd5b818801915088601f8301126200020f57600080fd5b81518181111562000224576200022462000196565b604051601f8201601f19908116603f011681019083821181831017156200024f576200024f62000196565b81604052828152602093508b848487010111156200026c57600080fd5b600091505b8282101562000290578482018401518183018501529083019062000271565b6000848483010152809950505050620002ab818901620001ac565b955050506040860151925060608601519150620002cb60808701620001ac565b90509295509295909350565b600181811c90821680620002ec57607f821691505b6020821081036200030d57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200036157600081815260208120601f850160051c810160208610156200033c5750805b601f850160051c820191505b818110156200035d5782815560010162000348565b5050505b505050565b81516001600160401b0381111562000382576200038262000196565b6200039a81620003938454620002d7565b8462000313565b602080601f831160018114620003d25760008415620003b95750858301515b600019600386901b1c1916600185901b1785556200035d565b600085815260208120601f198616915b828110156200040357888601518255948401946001909101908401620003e2565b5085821015620004225787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b615da780620004426000396000f3fe6080604052600436106104d45760003560e01c8063714c539811610279578063b85afd281161015e578063d85d3d27116100d6578063ef0cc9501161008a578063f2fde38b1161006f578063f2fde38b14610e19578063f3fef3a314610e39578063f5c1f76e14610e5957610511565b8063ef0cc95014610dd9578063f1dfaefb14610df957610511565b8063e8a3d485116100bb578063e8a3d48514610d5b578063e985e9c514610d70578063ec129eea14610db957610511565b8063d85d3d2714610d28578063e030565e14610d3b57610511565b8063c2f47cc81161012d578063ce92b33e11610112578063ce92b33e14610cc8578063d27998f714610ce8578063d58778d614610d0857610511565b8063c2f47cc814610c95578063c87b56dd14610ca857610511565b8063b85afd2814610c07578063b88d4fde14610c35578063bb5b27e114610c55578063c2f1f14a14610c7557610511565b806395d89b41116101f1578063a22cb465116101c0578063af1296d3116101a5578063af1296d314610bb2578063b14817dc14610bc7578063b5587dd714610be757610511565b8063a22cb46514610b72578063ab3b87fe14610b9257610511565b806395d89b4114610afd57806399f5a80714610b125780639bf35ca214610b325780639ec40d1c14610b5257610511565b80638da5cb5b116102485780638fc88c481161022d5780638fc88c4814610a90578063910bc4df14610ab0578063938e3d7b14610add57610511565b80638da5cb5b14610a585780638fc3047d14610a7b57610511565b8063714c5398146109f9578063715018a614610a0e5780637ef1a09814610a235780638456cb5914610a4357610511565b80633f4ba83a116103ba57806355f804b3116103325780636352211e116102e6578063672b9f81116102cb578063672b9f81146109955780636917a85e146109c357806370a08231146109d957610511565b80636352211e1461096057806365935e1b1461098057610511565b80635cd78c3a116103175780635cd78c3a146109005780635e5726ef146109135780635fe5afa21461093357610511565b806355f804b3146108c85780635c975abb146108e857610511565b8063438dac11116103895780634a72584d1161036e5780634a72584d146108505780634f558e791461087057806350382c1a146108a857610511565b8063438dac111461081057806347c816991461083057610511565b80633f4ba83a1461079b57806342842e0e146107b057806342966c68146107d0578063430c2081146107f057610511565b806323b872dd1161044d57806330347ebf1161041c5780633221f6db116104015780633221f6db1461075057806332f9b06a1461077057806333a581d21461078557610511565b806330347ebf14610712578063310bd74b1461073057610511565b806323b872dd1461068e57806326c0eff0146106ae57806326c7edf9146106ce57806327f18975146106f257610511565b8063095ea7b3116104a45780631bd8cc1a116104895780631bd8cc1a1461062e5780631be5e7ed1461065b57806322ae79611461067b57610511565b8063095ea7b3146105ec5780631593dee11461060e57610511565b80623379d71461054357806301ffc9a71461057a57806306fdde03146105aa578063081812fc146105cc57610511565b366105115760405134815233907f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f88525874906020015b60405180910390a2005b60405134815233907f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f8852587490602001610507565b34801561054f57600080fd5b50600d546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b34801561058657600080fd5b5061059a610595366004614f6d565b610e79565b6040519015158152602001610571565b3480156105b657600080fd5b506105bf610ebd565b6040516105719190614fda565b3480156105d857600080fd5b5061055d6105e7366004614fed565b610f4f565b3480156105f857600080fd5b5061060c61060736600461501b565b610f78565b005b34801561061a57600080fd5b5061059a610629366004615047565b610f87565b34801561063a57600080fd5b5061064e6106493660046150cd565b6110a2565b6040516105719190615171565b34801561066757600080fd5b506105bf6106763660046151c6565b611199565b61059a6106893660046151fe565b6111e4565b34801561069a57600080fd5b5061060c6106a9366004615047565b6112bd565b3480156106ba57600080fd5b506105bf6106c9366004614fed565b611301565b3480156106da57600080fd5b506106e4600f5481565b604051908152602001610571565b3480156106fe57600080fd5b5061060c61070d366004615253565b61139b565b34801561071e57600080fd5b506010546001600160a01b031661055d565b34801561073c57600080fd5b5061060c61074b366004614fed565b6113f6565b34801561075c57600080fd5b5061060c61076b366004614fed565b61141b565b34801561077c57600080fd5b506011546106e4565b34801561079157600080fd5b506106e460001981565b3480156107a757600080fd5b5061060c611492565b3480156107bc57600080fd5b5061060c6107cb366004615047565b6114a4565b3480156107dc57600080fd5b5061060c6107eb366004614fed565b6114c4565b3480156107fc57600080fd5b5061059a61080b36600461501b565b6114e2565b34801561081c57600080fd5b506106e461082b3660046152c7565b6114fb565b34801561083c57600080fd5b5061060c61084b3660046152e9565b61152b565b34801561085c57600080fd5b5061060c61086b36600461534b565b611554565b34801561087c57600080fd5b5061059a61088b366004614fed565b6000908152600260205260409020546001600160a01b0316151590565b3480156108b457600080fd5b5061060c6108c336600461544b565b611583565b3480156108d457600080fd5b5061060c6108e336600461544b565b6115b6565b3480156108f457600080fd5b5060075460ff1661059a565b61060c61090e366004615494565b611605565b34801561091f57600080fd5b506106e461092e36600461544b565b6117ab565b34801561093f57600080fd5b5061095361094e3660046152c7565b6117dc565b604051610571919061552e565b34801561096c57600080fd5b5061055d61097b366004614fed565b6118e0565b34801561098c57600080fd5b506105bf6118eb565b3480156109a157600080fd5b506109b56109b03660046152c7565b6118f8565b604051610571929190615572565b3480156109cf57600080fd5b506106e4600e5481565b3480156109e557600080fd5b506106e46109f43660046155a0565b611910565b348015610a0557600080fd5b506105bf611971565b348015610a1a57600080fd5b5061060c611980565b348015610a2f57600080fd5b5061060c610a3e3660046155a0565b611992565b348015610a4f57600080fd5b5061060c6119f5565b348015610a6457600080fd5b5060075461010090046001600160a01b031661055d565b348015610a8757600080fd5b506106e4611a05565b348015610a9c57600080fd5b506106e4610aab366004614fed565b611a45565b348015610abc57600080fd5b50610ad0610acb3660046152c7565b611a8e565b60405161057191906155bd565b348015610ae957600080fd5b5061060c610af836600461544b565b611b9e565b348015610b0957600080fd5b506105bf611bdf565b348015610b1e57600080fd5b5061064e610b2d3660046152c7565b611bee565b348015610b3e57600080fd5b50610ad0610b4d3660046152c7565b611d8f565b348015610b5e57600080fd5b506105bf610b6d36600461544b565b611e9f565b348015610b7e57600080fd5b5061060c610b8d36600461560c565b612120565b348015610b9e57600080fd5b5061060c610bad36600461501b565b61212b565b348015610bbe57600080fd5b506106e4612161565b348015610bd357600080fd5b5061064e610be2366004614fed565b612223565b348015610bf357600080fd5b506105bf610c02366004614fed565b61228f565b348015610c1357600080fd5b50610c27610c223660046150cd565b612331565b604051610571929190615645565b348015610c4157600080fd5b5061060c610c5036600461566a565b612455565b348015610c6157600080fd5b506105bf610c70366004614fed565b61248d565b348015610c8157600080fd5b5061055d610c90366004614fed565b6124aa565b61059a610ca33660046156ea565b6124fd565b348015610cb457600080fd5b506105bf610cc3366004614fed565b6125f4565b348015610cd457600080fd5b5061060c610ce3366004615253565b61269f565b348015610cf457600080fd5b5061060c610d033660046155a0565b6126c8565b348015610d1457600080fd5b506106e4610d23366004614fed565b612766565b61060c610d3636600461544b565b612787565b348015610d4757600080fd5b5061060c610d5636600461571d565b6128db565b348015610d6757600080fd5b506105bf6129bb565b348015610d7c57600080fd5b5061059a610d8b36600461576c565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b348015610dc557600080fd5b5061060c610dd4366004615253565b6129ca565b348015610de557600080fd5b5061059a610df436600461501b565b6129f3565b348015610e0557600080fd5b5061059a610e1436600461544b565b612a5a565b348015610e2557600080fd5b5061060c610e343660046155a0565b612a7d565b348015610e4557600080fd5b5061059a610e5436600461501b565b612ad1565b348015610e6557600080fd5b5061064e610e7436600461579a565b612b7f565b60006001600160e01b031982167fad092b5c000000000000000000000000000000000000000000000000000000001480610eb75750610eb782612bbd565b92915050565b606060008054610ecc906157dc565b80601f0160208091040260200160405190810160405280929190818152602001828054610ef8906157dc565b8015610f455780601f10610f1a57610100808354040283529160200191610f45565b820191906000526020600020905b815481529060010190602001808311610f2857829003601f168201915b5050505050905090565b6000610f5a82612bfb565b506000828152600460205260409020546001600160a01b0316610eb7565b610f83828233612c34565b5050565b6000610f91612c41565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015284906001600160a01b038216906370a0823190602401602060405180830381865afa158015610ff0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110149190615810565b8311156110345760405163fe382aa760e01b815260040160405180910390fd5b6110486001600160a01b0382168585612c8d565b836001600160a01b0316856001600160a01b03167f33c35f9541201e342d5e7467016e65a0a06182eb12a5f17103f71cec95b6cb298560405161108d91815260200190565b60405180910390a360019150505b9392505050565b60608267ffffffffffffffff8111156110bd576110bd61539e565b6040519080825280602002602001820160405280156110f057816020015b60608152602001906001900390816110db5790505b50905060005b838110156111915761116185858381811061111357611113615829565b9050602002810190611125919061583f565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250879250612d0d915050565b82828151811061117357611173615829565b602002602001018190525080806111899061589c565b9150506110f6565b509392505050565b60606111dc84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869250612d0d915050565b949350505050565b6000806111f1343a6114fb565b90508034101561122257604051632d74c84160e11b8152600481018290523460248201526044015b60405180910390fd5b600061122e82346158b5565b6040519091506001600160a01b0387169082156108fc029083906000818181858888f19350505050158015611267573d6000803e3d6000fd5b50856001600160a01b03167ff61a07121230585210fa1abd959f8da04c4c030b169c5a7dd2dd04a93d381b9a34838589896040516112a99594939291906158f1565b60405180910390a250600195945050505050565b806112e76112e0826000908152600260205260409020546001600160a01b031690565b3383612d42565b6112f082612da6565b6112fb848484612e69565b50505050565b6013602052600090815260409020805461131a906157dc565b80601f0160208091040260200160405190810160405280929190818152602001828054611346906157dc565b80156113935780601f1061136857610100808354040283529160200191611393565b820191906000526020600020905b81548152906001019060200180831161137657829003601f168201915b505050505081565b6113a3612f32565b806113af335b826129f3565b6113e157335b60405163177e802f60e01b81526001600160a01b03909116600482015260248101829052604401611219565b6113ee8686868686612f6f565b505050505050565b6113fe612f32565b80611408336113a9565b61141257336113b5565b610f8382612da6565b611423612c41565b61271060018183111561143a57600f829055611452565b8083101561144c57600f819055611452565b600f8390555b7f7188f446ea54aad8f9796527fa93140c34465d673bbcac6d4302763b37653d83600f5460405161148591815260200190565b60405180910390a1505050565b61149a612c41565b6114a2612fd2565b565b6114bf83838360405180602001604052806000815250612455565b505050565b6114cd81613024565b6114d681612da6565b6114df81613117565b50565b6000806114ee83612bfb565b90506111dc818585613123565b600080612710600f548561150f9190615922565b6115199190615939565b90508281101561109b57509092915050565b611533612f32565b8061153d336113a9565b61154757336113b5565b6113ee86868686866131a6565b61155c612f32565b80611566336113a9565b61157057336113b5565b61157c85858585613285565b5050505050565b6114df81604051602001611597919061595b565b6040516020818303038152906040528051906020012060001c8261333f565b6115be612c41565b600c6115ca82826159bd565b507f325d37e8fb549c86966f09bc3e6f62eb3afa93b255d6e3234338001f3d80bd86816040516115fa9190614fda565b60405180910390a150565b61160d612f32565b6000611617611a05565b90508034101561164357604051632d74c84160e11b815260048101829052346024820152604401611219565b803411156116bf57600061165782346158b5565b604051909150339082156108fc029083906000818181858888f19350505050158015611687573d6000803e3d6000fd5b5060405181815233907fc4df3884ed7590e8ca76a3638169a4560864d1c8cb3fd451e944de0bfe8a0ecc9060200160405180910390a2505b600061170088888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611e9f92505050565b9050805160000361172857878760405163172a347760e11b8152600401611219929190615a7d565b6000611733826117ab565b9050611740335b82613364565b60118054600181019091557f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6801819055600081815260136020526040902061178883826159bd565b50611793818361337e565b6117a087878787856133ce565b505050505050505050565b6000816040516020016117be919061595b565b60408051601f19818403018152919052805160209091012092915050565b606060006117eb836001615a91565b6011549091508111156117fd57506011545b80841061181d5760405163a857911360e01b815260040160405180910390fd5b600061182985836158b5565b67ffffffffffffffff8111156118415761184161539e565b60405190808252806020026020018201604052801561186a578160200160208202803683370190505b50905060005b61187a86846158b5565b8110156118d757601161188d8783615a91565b8154811061189d5761189d615829565b90600052602060002001548282815181106118ba576118ba615829565b6020908102919091010152806118cf8161589c565b915050611870565b50949350505050565b6000610eb782612bfb565b600c805461131a906157dc565b606080611905848461343c565b909590945092505050565b60006001600160a01b038216611955576040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152602401611219565b506001600160a01b031660009081526003602052604090205490565b6060600c8054610ecc906157dc565b611988612c41565b6114a2600061345d565b61199a612c41565b6010805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081527f890db4eb54cc623b3c73e4ba44f10a5be1496991c7aae2ebdd91ed5c04932165906020016115fa565b6119fd612c41565b6114a26134ce565b600080611a10612161565b905060006402540be400600e5483670de0b6b3a7640000611a319190615939565b611a3b9190615922565b61109b9190615939565b6000611a5082612bfb565b50600082815260126020526040902054600160a01b900467ffffffffffffffff16428110611a7e5792915050565b5060001992915050565b50919050565b60606000611a9d836001615a91565b601154909150811115611aaf57506011545b808410611acf5760405163a857911360e01b815260040160405180910390fd5b6000611adb85836158b5565b67ffffffffffffffff811115611af357611af361539e565b604051908082528060200260200182016040528015611b1c578160200160208202803683370190505b50905060005b611b2c86846158b5565b8110156118d757611b626011611b428884615a91565b81548110611b5257611b52615829565b90600052602060002001546118e0565b828281518110611b7457611b74615829565b6001600160a01b039092166020928302919091019091015280611b968161589c565b915050611b22565b611ba6612c41565b600b611bb282826159bd565b506040517fa5d4097edda6d87cb9329af83fb3712ef77eeb13738ffe43cc35a4ce305ad96290600090a150565b606060018054610ecc906157dc565b60606000611bfd836001615a91565b601154909150811115611c0f57506011545b808410611c2f5760405163a857911360e01b815260040160405180910390fd5b6000611c3b85836158b5565b67ffffffffffffffff811115611c5357611c5361539e565b604051908082528060200260200182016040528015611c8657816020015b6060815260200190600190039081611c715790505b50905060005b611c9686846158b5565b8110156118d757601360006011611cad8985615a91565b81548110611cbd57611cbd615829565b906000526020600020015481526020019081526020016000208054611ce1906157dc565b80601f0160208091040260200160405190810160405280929190818152602001828054611d0d906157dc565b8015611d5a5780601f10611d2f57610100808354040283529160200191611d5a565b820191906000526020600020905b815481529060010190602001808311611d3d57829003601f168201915b5050505050828281518110611d7157611d71615829565b60200260200101819052508080611d879061589c565b915050611c8c565b60606000611d9e836001615a91565b601154909150811115611db057506011545b808410611dd05760405163a857911360e01b815260040160405180910390fd5b6000611ddc85836158b5565b67ffffffffffffffff811115611df457611df461539e565b604051908082528060200260200182016040528015611e1d578160200160208202803683370190505b50905060005b611e2d86846158b5565b8110156118d757611e636011611e438884615a91565b81548110611e5357611e53615829565b90600052602060002001546124aa565b828281518110611e7557611e75615829565b6001600160a01b039092166020928302919091019091015280611e978161589c565b915050611e23565b6060600c825114611ebe57505060408051602081019091526000815290565b6000611ec98361350b565b9050600080611efa604051806040016040528060018152602001602b60f81b8152508461374190919063ffffffff16565b9150915081611f1b5750506040805160208101909152600081529392505050565b80611f48604051806040016040528060018152602001602b60f81b815250856138b590919063ffffffff16565b14611f655750506040805160208101909152600081529392505050565b60088114611f855750506040805160208101909152600081529392505050565b60005b835181101561203c576000611f9d8583613952565b60408051808201909152601481527f3233343536373839434647484a4d5051525657580000000000000000000000006020820152909150611fde90826139c5565b15801561200a57506040805180820190915260018152602b60f81b602082015261200890826139c5565b155b1561202957505060408051602081019091526000815295945050505050565b50806120348161589c565b915050611f88565b5060006120498482613952565b90506000601461209561205b8461350b565b60408051808201909152601481527f3233343536373839434647484a4d505152565758000000000000000000000000602082015290613b13565b61209f9190615922565b905060b481106120c357505060408051602081019091526000815295945050505050565b60006120d0866001613952565b9050600060146120e261205b8461350b565b6120ec9190615922565b90506101688110612113575050604080516020810190915260008152979650505050505050565b5094979650505050505050565b610f83338383613bb5565b8061214e6112e0826000908152600260205260409020546001600160a01b031690565b6114bf61215a836118e0565b8484612e69565b600080601060009054906101000a90046001600160a01b03166001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156121b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121db9190615abe565b5050509150506000811361221e576040517f4672cc9b00000000000000000000000000000000000000000000000000000000815260048101829052602401611219565b919050565b6060610eb7600a600084815260200190815260200160002080548060200260200160405190810160405280929190818152602001828054801561228557602002820191906000526020600020905b815481526020019060010190808311612271575b5050505050613c6d565b60008181526013602052604090208054606091906122ac906157dc565b80601f01602080910402602001604051908101604052809291908181526020018280546122d8906157dc565b80156123255780601f106122fa57610100808354040283529160200191612325565b820191906000526020600020905b81548152906001019060200180831161230857829003601f168201915b50505050509050919050565b6060808367ffffffffffffffff81111561234d5761234d61539e565b60405190808252806020026020018201604052801561238057816020015b606081526020019060019003908161236b5790505b5091508367ffffffffffffffff81111561239c5761239c61539e565b6040519080825280602002602001820160405280156123cf57816020015b60608152602001906001900390816123ba5790505b50905060005b8481101561244c576123ff8686838181106123f2576123f2615829565b905060200201358561343c565b84838151811061241157612411615829565b6020026020010184848151811061242a5761242a615829565b60200260200101829052829052505080806124449061589c565b9150506123d5565b50935093915050565b816124786112e0826000908152600260205260409020546001600160a01b031690565b61248183612da6565b61157c85858585613db0565b60008181526008602052604090208054606091906122ac906157dc565b6000806124b683612bfb565b60008481526012602052604090205490915042600160a01b90910467ffffffffffffffff1610610eb75750506000908152601260205260409020546001600160a01b031690565b60008061250a343a6114fb565b90508034101561253657604051632d74c84160e11b815260048101829052346024820152604401611219565b600061254282346158b5565b9050600061254f876124aa565b6040519091506001600160a01b0382169083156108fc029084906000818181858888f19350505050158015612588573d6000803e3d6000fd5b5086816001600160a01b03167f3038f50eed4db1e66532d22a12bb8a1b2afb7b76be123f0b7fb519efddd45e5d601360008b81526020019081526020016000203486888c8c6040516125df96959493929190615b0e565b60405180910390a35060019695505050505050565b6060600061260183613dc7565b600d549091506001600160a01b031615610eb757600d546040517f8419be1e000000000000000000000000000000000000000000000000000000008152600481018590526001600160a01b0390911690638419be1e90602401600060405180830381865afa158015612677573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261109b9190810190615bc4565b6126a7612f32565b806126b1336113a9565b6126bb57336113b5565b6113ee86868686866133ce565b6126d0612c41565b600d805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081527f2ce410f2911b731da01b611cabf31c231cd62c4bf630aad45ec80b5172f814ef9060200160405180910390a1604080516000815260001960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91016115fa565b6011818154811061277657600080fd5b600091825260209091200154905081565b61278f612f32565b6000612799611a05565b9050803410156127c557604051632d74c84160e11b815260048101829052346024820152604401611219565b803411156128415760006127d982346158b5565b604051909150339082156108fc029083906000818181858888f19350505050158015612809573d6000803e3d6000fd5b5060405181815233907fc4df3884ed7590e8ca76a3638169a4560864d1c8cb3fd451e944de0bfe8a0ecc9060200160405180910390a2505b600061284c83611e9f565b90508051600003612872578260405163172a347760e11b81526004016112199190614fda565b600061287d826117ab565b90506128883361173a565b60118054600181019091557f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c680181905560008181526013602052604090206128d083826159bd565b506112fb818361337e565b6128e3612f32565b826129066112e0826000908152600260205260409020546001600160a01b031690565b60008481526012602090815260409182902080546001600160a01b0387166001600160e01b03199091168117600160a01b67ffffffffffffffff881690810291909117835593519384529092909187917f4e06b4e7000e659094299b3533b47b6aa8ad048e95e872d23d1f4ee55af89cfe910160405180910390a36040518581527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a15050505050565b6060600b8054610ecc906157dc565b6129d2612f32565b806129dc336113a9565b6129e657336113b5565b6113ee8686868686613ec3565b6000806129ff83612bfb565b9050612a0a836124aa565b6001600160a01b0316816001600160a01b031603612a3557612a2d818585613123565b915050610eb7565b612a3e836124aa565b6001600160a01b0316846001600160a01b031614915050610eb7565b6000612a6582611e9f565b51600003612a7557506000919050565b506001919050565b612a85612c41565b6001600160a01b038116612ac8576040517f1e4fbdf700000000000000000000000000000000000000000000000000000000815260006004820152602401611219565b6114df8161345d565b6000612adb612c41565b47821115612afc5760405163fe382aa760e01b815260040160405180910390fd5b6040516001600160a01b0384169083156108fc029084906000818181858888f19350505050158015612b32573d6000803e3d6000fd5b50826001600160a01b03167f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a942436483604051612b6e91815260200190565b60405180910390a250600192915050565b606061109b838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613c6d92505050565b60006001600160e01b031982167f49064906000000000000000000000000000000000000000000000000000000001480610eb75750610eb782613ed9565b6000818152600260205260408120546001600160a01b031680610eb757604051637e27328960e01b815260048101849052602401611219565b6114bf8383836001613f74565b6007546001600160a01b036101009091041633146114a2576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401611219565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526114bf9084906140bf565b606061109b83604051602001612d23919061595b565b6040516020818303038152906040528051906020012060001c8361413b565b612d4d838383613123565b6114bf576001600160a01b038316612d7b57604051637e27328960e01b815260048101829052602401611219565b60405163177e802f60e01b81526001600160a01b038316600482015260248101829052604401611219565b60005b6000828152600a6020526040902054811015612e23576000828152600960209081526040808320600a9092528220805491929184908110612dec57612dec615829565b906000526020600020015481526020019081526020016000206000612e119190614eea565b80612e1b8161589c565b915050612da9565b506000818152600a60205260408120612e3b91614f24565b60405181907f185c30856dadb58bf097c1f665a52ada7029752dbcad008ea3fefc73bee8c9fe90600090a250565b6001600160a01b038216612e9357604051633250574960e11b815260006004820152602401611219565b6000612ea1838360006141e9565b90506001600160a01b038116612ecd57604051637e27328960e01b815260048101839052602401611219565b836001600160a01b0316816001600160a01b0316146112fb576040517f64283d7b0000000000000000000000000000000000000000000000000000000081526001600160a01b0380861660048301526024820184905282166044820152606401611219565b60075460ff16156114a2576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b848110156113ee57612fc0868683818110612f8f57612f8f615829565b90506020020135858584818110612fa857612fa8615829565b9050602002810190612fba919061583f565b85613285565b80612fca8161589c565b915050612f72565b612fda6142c1565b6007805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60005b601154811015610f8357816011828154811061304557613045615829565b906000526020600020015403613105575b601154613065906001906158b5565b8110156130c5576011613079826001615a91565b8154811061308957613089615829565b9060005260206000200154601182815481106130a7576130a7615829565b600091825260209091200155806130bd8161589c565b915050613056565b60118054806130d6576130d6615c32565b6000828152602080822083016000199081018390559092019092558382526013905260408120610f8391614eea565b8061310f8161589c565b915050613027565b610f83600082336141e9565b60006001600160a01b038316158015906111dc5750826001600160a01b0316846001600160a01b0316148061317d57506001600160a01b0380851660009081526005602090815260408083209387168352929052205460ff165b806111dc5750506000908152600460205260409020546001600160a01b03908116911614919050565b600085856040516020016131bb929190615c48565b60408051601f198184030181528282528051602091820120601f890182900482028401820190925287835290925061320f918391899089908190840183828082843760009201919091525061333f92505050565b6113ee8187878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8b0181900481028201810190925289815292508991508890819084018382808284376000920191909152508892506142fd915050565b61328e8461442b565b6132f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f5265636f726453746f726167653a204b45595f4e4f545f464f554e44000000006044820152606401611219565b6112fb846133018661248d565b85858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508792506142fd915050565b6133488261442b565b610f835760008281526008602052604090206114bf82826159bd565b610f83828260405180602001604052806000815250614451565b600082815260066020526040902061339682826159bd565b506040518281527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a15050565b60005b848110156113ee5761342a8686838181106133ee576133ee615829565b9050602002810190613400919061583f565b86868581811061341257613412615829565b9050602002810190613424919061583f565b866131a6565b806134348161589c565b9150506133d1565b6060806134488461248d565b9150613454848461413b565b90509250929050565b600780546001600160a01b038381166101008181027fffffffffffffffffffffff0000000000000000000000000000000000000000ff85161790945560405193909204169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6134d6612f32565b6007805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586130073390565b606060006040518060800160405280604d8152602001615d25604d91399050600061356d826040518060400160405280600181526020017f3b000000000000000000000000000000000000000000000000000000000000008152506028614468565b6040805160208101909152600080825291925085915b8251811015613737576040805160018082528183019092526000916020820181803683370190505090508782815181106135bf576135bf615829565b602001015160f81c60f81b816000815181106135dd576135dd615829565b60200101906001600160f81b031916908160001a9053506000805b86518110156136f257600061362688838151811061361857613618615829565b6020026020010151856139c5565b905080156136df5760408051600180825281830190925260009160208201818036833701905050905088838151811061366157613661615829565b602002602001015160008151811061367b5761367b615829565b602001015160f81c60f81b8160008151811061369957613699615829565b60200101906001600160f81b031916908160001a90535086816040516020016136c3929190615c58565b60405160208183030381529060405296506001935050506136f2565b50806136ea8161589c565b9150506135f8565b50801515600003613722578382604051602001613710929190615c58565b60405160208183030381529060405293505b5050808061372f9061589c565b915050613583565b5095945050505050565b60008083838260001981805b85518110156138a4576000855167ffffffffffffffff8111156137725761377261539e565b6040519080825280601f01601f19166020018201604052801561379c576020820181803683370190505b5090506000825b87516137af9085615a91565b81101561381c578c81815181106137c8576137c8615829565b602001015160f81c60f81b8383815181106137e5576137e5615829565b60200101906001600160f81b031916908160001a905350816138068161589c565b92505080806138149061589c565b9150506137a3565b506040518290613830908d9060200161595b565b6040516020818303038152906040528051906020012081604051602001613857919061595b565b604051602081830303815290604052805190602001200361388157600196508495505050506138a4565b8461388b81615c87565b955050505050808061389c9061589c565b91505061374d565b5091955093505050505b9250929050565b60008281805b82518110156118d7576040805160018082528183019092526000916020820181803683370190505090508682815181106138f7576138f7615829565b602001015160f81c60f81b8160008151811061391557613915615829565b60200101906001600160f81b031916908160001a9053506139368187614872565b1561393f578192505b508061394a8161589c565b9150506138bb565b6040805160018082528183019092526060916000919060208201818036833701905050905083838151811061398957613989615829565b602001015160f81c60f81b816000815181106139a7576139a7615829565b60200101906001600160f81b031916908160001a9053509392505050565b6000828282805b8351811015613737576000835167ffffffffffffffff8111156139f1576139f161539e565b6040519080825280601f01601f191660200182016040528015613a1b576020820181803683370190505b5090506000825b8551613a2e9085615a91565b811015613a9b57898181518110613a4757613a47615829565b602001015160f81c60f81b838381518110613a6457613a64615829565b60200101906001600160f81b031916908160001a90535081613a858161589c565b9250508080613a939061589c565b915050613a22565b506040518290613aaf908a9060200161595b565b6040516020818303038152906040528051906020012081604051602001613ad6919061595b565b6040516020818303038152906040528051906020012003613afd5760019450505050613737565b5050508080613b0b9061589c565b9150506139cc565b60008281805b82518110156118d757604080516001808252818301909252600091602082018180368337019050509050868281518110613b5557613b55615829565b602001015160f81c60f81b81600081518110613b7357613b73615829565b60200101906001600160f81b031916908160001a905350613b948187614872565b15613ba257819250506118d7565b5080613bad8161589c565b915050613b19565b6001600160a01b038216613c00576040517f5b08ba180000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401611219565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6060815167ffffffffffffffff811115613c8957613c8961539e565b604051908082528060200260200182016040528015613cbc57816020015b6060815260200190600190039081613ca75790505b50905060005b8251811015611a885760086000848381518110613ce157613ce1615829565b602002602001015181526020019081526020016000208054613d02906157dc565b80601f0160208091040260200160405190810160405280929190818152602001828054613d2e906157dc565b8015613d7b5780601f10613d5057610100808354040283529160200191613d7b565b820191906000526020600020905b815481529060010190602001808311613d5e57829003601f168201915b5050505050828281518110613d9257613d92615829565b60200260200101819052508080613da89061589c565b915050613cc2565b613dbb848484612e69565b6112fb848484846148cb565b6060613dd282612bfb565b5060008281526006602052604081208054613dec906157dc565b80601f0160208091040260200160405190810160405280929190818152602001828054613e18906157dc565b8015613e655780601f10613e3a57610100808354040283529160200191613e65565b820191906000526020600020905b815481529060010190602001808311613e4857829003601f168201915b505050505090506000613e76611971565b90508051600003613e88575092915050565b815115613eba578082604051602001613ea2929190615c58565b60405160208183030381529060405292505050919050565b6111dc846149ed565b613ecc81612da6565b61157c85858585856133ce565b60006001600160e01b031982167f80ac58cd000000000000000000000000000000000000000000000000000000001480613f3c57506001600160e01b031982167f5b5e139f00000000000000000000000000000000000000000000000000000000145b80610eb757507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614610eb7565b8080613f8857506001600160a01b03821615155b15614082576000613f9884612bfb565b90506001600160a01b03831615801590613fc45750826001600160a01b0316816001600160a01b031614155b8015613ff657506001600160a01b0380821660009081526005602090815260408083209387168352929052205460ff16155b15614038576040517fa9fbf51f0000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611219565b81156140805783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b50506000908152600460205260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b60006140d46001600160a01b03841683614a54565b905080516000141580156140f95750808060200190518101906140f79190615cb8565b155b156114bf576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611219565b60008181526009602090815260408083208584529091529020805460609190614163906157dc565b80601f016020809104026020016040519081016040528092919081815260200182805461418f906157dc565b80156141dc5780601f106141b1576101008083540402835291602001916141dc565b820191906000526020600020905b8154815290600101906020018083116141bf57829003601f168201915b5050505050905092915050565b6000806141f7858585614a62565b9050846001600160a01b0316816001600160a01b03161415801561423157506000848152601260205260409020546001600160a01b031615155b156111dc57600084815260126020908152604080832080546001600160e01b03191690555182815286917f4e06b4e7000e659094299b3533b47b6aa8ad048e95e872d23d1f4ee55af89cfe910160405180910390a36040518481527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a1949350505050565b60075460ff166114a2576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260096020908152604080832087845290915290208054614321906157dc565b905060000361439b576000818152600a60209081526040808320805460018101825590845291909220018590555161435a90849061595b565b6040518091039020817f7ae4f661958fbecc2f77be6b0eb280d2a6f604b29e1e7221c82b9da0c4af7f86856040516143929190614fda565b60405180910390a35b600081815260096020908152604080832087845290915290206143be83826159bd565b50816040516143cd919061595b565b6040518091039020836040516143e3919061595b565b6040518091039020827f851ffe8e74d5015261dba0a1f9e1b0e5d42c5af5d2ad1908fee897c7d80a0d92868660405161441d929190615572565b60405180910390a450505050565b60008181526008602052604081208054829190614447906157dc565b9050119050919050565b61445b8383614a77565b6114bf60008484846148cb565b6060838360405160200161447d929190615c58565b60408051601f198184030181529190529350838360008467ffffffffffffffff8111156144ac576144ac61539e565b6040519080825280602002602001820160405280156144df57816020015b60608152602001906001900390816144ca5790505b50905060008060005b8551821015614752576000855167ffffffffffffffff81111561450d5761450d61539e565b6040519080825280601f01601f191660200182016040528015614537576020820181803683370190505b5090506000835b84895161454b91906158b5565b88511161456357875161455e9086615a91565b614570565b84895161457091906158b5565b8110156145dd578c818151811061458957614589615829565b602001015160f81c60f81b8383815181106145a6576145a6615829565b60200101906001600160f81b031916908160001a905350816145c78161589c565b92505080806145d59061589c565b91505061453e565b5060405182906145f1908d9060200161595b565b6040516020818303038152906040528051906020012081604051602001614618919061595b565b604051602081830303815290604052805190602001200361473c57600061463f87876158b5565b67ffffffffffffffff8111156146575761465761539e565b6040519080825280601f01601f191660200182016040528015614681576020820181803683370190505b5090506000875b878110156146f6578f81815181106146a2576146a2615829565b602001015160f81c60f81b8383815181106146bf576146bf615829565b60200101906001600160f81b031916908160001a905350816146e08161589c565b92505080806146ee9061589c565b915050614688565b508189878151811061470a5761470a615829565b602002602001018190525085806147209061589c565b9650508951876147309190615a91565b9650869750505061474a565b614747600186615a91565b94505b5050506144e8565b60008167ffffffffffffffff81111561476d5761476d61539e565b6040519080825280602002602001820160405280156147a057816020015b606081526020019060019003908161478b5790505b50905060005b828110156147f8578581815181106147c0576147c0615829565b60200260200101518282815181106147da576147da615829565b602002602001018190525080806147f09061589c565b9150506147a6565b506040805160008082526020820190925290614824565b606081526020019060019003908161480f5790505b509450600181511161486157604080516000808252602082019092529061485b565b60608152602001906001900390816148465790505b50614863565b805b9b9a5050505050505050505050565b600081604051602001614885919061595b565b60405160208183030381529060405280519060200120836040516020016148ac919061595b565b6040516020818303038152906040528051906020012014905092915050565b6001600160a01b0383163b156112fb57604051630a85bd0160e11b81526001600160a01b0384169063150b7a029061490d903390889087908790600401615cd5565b6020604051808303816000875af1925050508015614948575060408051601f3d908101601f1916820190925261494591810190615d07565b60015b6149b1573d808015614976576040519150601f19603f3d011682016040523d82523d6000602084013e61497b565b606091505b5080516000036149a957604051633250574960e11b81526001600160a01b0385166004820152602401611219565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b1461157c57604051633250574960e11b81526001600160a01b0385166004820152602401611219565b60606149f882612bfb565b506000614a03611971565b90506000815111614a23576040518060200160405280600081525061109b565b80614a2d84614af5565b604051602001614a3e929190615c58565b6040516020818303038152906040529392505050565b606061109b83836000614b95565b6000614a6c612f32565b6111dc848484614c4b565b6001600160a01b038216614aa157604051633250574960e11b815260006004820152602401611219565b6000614aaf838360006141e9565b90506001600160a01b038116156114bf576040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152602401611219565b60606000614b0283614d51565b600101905060008167ffffffffffffffff811115614b2257614b2261539e565b6040519080825280601f01601f191660200182016040528015614b4c576020820181803683370190505b5090508181016020015b600019017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8504945084614b5657509392505050565b606081471015614bd3576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611219565b600080856001600160a01b03168486604051614bef919061595b565b60006040518083038185875af1925050503d8060008114614c2c576040519150601f19603f3d011682016040523d82523d6000602084013e614c31565b606091505b5091509150614c41868383614e33565b9695505050505050565b6000828152600260205260408120546001600160a01b0390811690831615614c7857614c78818486612d42565b6001600160a01b03811615614cb657614c95600085600080613f74565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b03851615614ce5576001600160a01b0385166000908152600360205260409020805460010190555b600084815260026020526040808220805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310614d9a577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310614dc6576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310614de457662386f26fc10000830492506010015b6305f5e1008310614dfc576305f5e100830492506008015b6127108310614e1057612710830492506004015b60648310614e22576064830492506002015b600a8310610eb75760010192915050565b606082614e4857614e4382614ea8565b61109b565b8151158015614e5f57506001600160a01b0384163b155b15614ea1576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611219565b508061109b565b805115614eb85780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b508054614ef6906157dc565b6000825580601f10614f06575050565b601f0160209004906000526020600020908101906114df9190614f3e565b50805460008255906000526020600020908101906114df91905b5b80821115614f535760008155600101614f3f565b5090565b6001600160e01b0319811681146114df57600080fd5b600060208284031215614f7f57600080fd5b813561109b81614f57565b60005b83811015614fa5578181015183820152602001614f8d565b50506000910152565b60008151808452614fc6816020860160208601614f8a565b601f01601f19169290920160200192915050565b60208152600061109b6020830184614fae565b600060208284031215614fff57600080fd5b5035919050565b6001600160a01b03811681146114df57600080fd5b6000806040838503121561502e57600080fd5b823561503981615006565b946020939093013593505050565b60008060006060848603121561505c57600080fd5b833561506781615006565b9250602084013561507781615006565b929592945050506040919091013590565b60008083601f84011261509a57600080fd5b50813567ffffffffffffffff8111156150b257600080fd5b6020830191508360208260051b85010111156138ae57600080fd5b6000806000604084860312156150e257600080fd5b833567ffffffffffffffff8111156150f957600080fd5b61510586828701615088565b909790965060209590950135949350505050565b600082825180855260208086019550808260051b84010181860160005b8481101561516457601f19868403018952615152838351614fae565b98840198925090830190600101615136565b5090979650505050505050565b60208152600061109b6020830184615119565b60008083601f84011261519657600080fd5b50813567ffffffffffffffff8111156151ae57600080fd5b6020830191508360208285010111156138ae57600080fd5b6000806000604084860312156151db57600080fd5b833567ffffffffffffffff8111156151f257600080fd5b61510586828701615184565b60008060006040848603121561521357600080fd5b833561521e81615006565b9250602084013567ffffffffffffffff81111561523a57600080fd5b61524686828701615184565b9497909650939450505050565b60008060008060006060868803121561526b57600080fd5b853567ffffffffffffffff8082111561528357600080fd5b61528f89838a01615088565b909750955060208801359150808211156152a857600080fd5b506152b588828901615088565b96999598509660400135949350505050565b600080604083850312156152da57600080fd5b50508035926020909101359150565b60008060008060006060868803121561530157600080fd5b853567ffffffffffffffff8082111561531957600080fd5b61532589838a01615184565b9097509550602088013591508082111561533e57600080fd5b506152b588828901615184565b6000806000806060858703121561536157600080fd5b84359350602085013567ffffffffffffffff81111561537f57600080fd5b61538b87828801615184565b9598909750949560400135949350505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156153dd576153dd61539e565b604052919050565b600067ffffffffffffffff8211156153ff576153ff61539e565b50601f01601f191660200190565b600061542061541b846153e5565b6153b4565b905082815283838301111561543457600080fd5b828260208301376000602084830101529392505050565b60006020828403121561545d57600080fd5b813567ffffffffffffffff81111561547457600080fd5b8201601f8101841361548557600080fd5b6111dc8482356020840161540d565b600080600080600080606087890312156154ad57600080fd5b863567ffffffffffffffff808211156154c557600080fd5b6154d18a838b01615184565b909850965060208901359150808211156154ea57600080fd5b6154f68a838b01615088565b9096509450604089013591508082111561550f57600080fd5b5061551c89828a01615088565b979a9699509497509295939492505050565b6020808252825182820181905260009190848201906040850190845b818110156155665783518352928401929184019160010161554a565b50909695505050505050565b6040815260006155856040830185614fae565b82810360208401526155978185614fae565b95945050505050565b6000602082840312156155b257600080fd5b813561109b81615006565b6020808252825182820181905260009190848201906040850190845b818110156155665783516001600160a01b0316835292840192918401916001016155d9565b80151581146114df57600080fd5b6000806040838503121561561f57600080fd5b823561562a81615006565b9150602083013561563a816155fe565b809150509250929050565b6040815260006156586040830185615119565b82810360208401526155978185615119565b6000806000806080858703121561568057600080fd5b843561568b81615006565b9350602085013561569b81615006565b925060408501359150606085013567ffffffffffffffff8111156156be57600080fd5b8501601f810187136156cf57600080fd5b6156de8782356020840161540d565b91505092959194509250565b6000806000604084860312156156ff57600080fd5b83359250602084013567ffffffffffffffff81111561523a57600080fd5b60008060006060848603121561573257600080fd5b83359250602084013561574481615006565b9150604084013567ffffffffffffffff8116811461576157600080fd5b809150509250925092565b6000806040838503121561577f57600080fd5b823561578a81615006565b9150602083013561563a81615006565b600080602083850312156157ad57600080fd5b823567ffffffffffffffff8111156157c457600080fd5b6157d085828601615088565b90969095509350505050565b600181811c908216806157f057607f821691505b602082108103611a8857634e487b7160e01b600052602260045260246000fd5b60006020828403121561582257600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261585657600080fd5b83018035915067ffffffffffffffff82111561587157600080fd5b6020019150368190038213156138ae57600080fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016158ae576158ae615886565b5060010190565b81810381811115610eb757610eb7615886565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8581528460208201528360408201526080606082015260006159176080830184866158c8565b979650505050505050565b8082028115828204841417610eb757610eb7615886565b60008261595657634e487b7160e01b600052601260045260246000fd5b500490565b6000825161596d818460208701614f8a565b9190910192915050565b601f8211156114bf57600081815260208120601f850160051c8101602086101561599e5750805b601f850160051c820191505b818110156113ee578281556001016159aa565b815167ffffffffffffffff8111156159d7576159d761539e565b6159eb816159e584546157dc565b84615977565b602080601f831160018114615a205760008415615a085750858301515b600019600386901b1c1916600185901b1785556113ee565b600085815260208120601f198616915b82811015615a4f57888601518255948401946001909101908401615a30565b5085821015615a6d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6020815260006111dc6020830184866158c8565b80820180821115610eb757610eb7615886565b805169ffffffffffffffffffff8116811461221e57600080fd5b600080600080600060a08688031215615ad657600080fd5b615adf86615aa4565b9450602086015193506040860151925060608601519150615b0260808701615aa4565b90509295509295909350565b60a081526000808854615b20816157dc565b8060a086015260c0600180841660008114615b425760018114615b5c57615b8d565b60ff1985168884015283151560051b880183019550615b8d565b8d60005260208060002060005b86811015615b845781548b8201870152908401908201615b69565b8a018501975050505b50505050508760208401528660408401528560608401528281036080840152615bb78185876158c8565b9998505050505050505050565b600060208284031215615bd657600080fd5b815167ffffffffffffffff811115615bed57600080fd5b8201601f81018413615bfe57600080fd5b8051615c0c61541b826153e5565b818152856020838501011115615c2157600080fd5b615597826020830160208601614f8a565b634e487b7160e01b600052603160045260246000fd5b8183823760009101908152919050565b60008351615c6a818460208801614f8a565b835190830190615c7e818360208801614f8a565b01949350505050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036158ae576158ae615886565b600060208284031215615cca57600080fd5b815161109b816155fe565b60006001600160a01b03808716835280861660208401525083604083015260806060830152614c416080830184614fae565b600060208284031215615d1957600080fd5b815161109b81614f5756fe41613b42623b43633b44643b45653b46663b47673b48683b49693b4a6a3b4b6b3b4c6c3b4d6d3b4e6e3b4f6f3b50703b51713b52723b53733b54743b55753b56763b57773b58783b59793b5a7aa26469706673582212200bcbf71bf3e9776e2788d9bed646e97de8aeb07449951b7281e8db61120dc8f264736f6c6343000814003300000000000000000000000000000000000000000000000000000000000000a00000000000000000000000007844435664403e5da4105b3400713d987295e45300000000000000000000000000000000000000000000000006f05b59d3b200000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000694aa1769357215de4fac081bf1f309adc325306000000000000000000000000000000000000000000000000000000000000001668747470733a2f2f74616e6769626c696e6b2e696f2f00000000000000000000
Deployed Bytecode
0x6080604052600436106104d45760003560e01c8063714c539811610279578063b85afd281161015e578063d85d3d27116100d6578063ef0cc9501161008a578063f2fde38b1161006f578063f2fde38b14610e19578063f3fef3a314610e39578063f5c1f76e14610e5957610511565b8063ef0cc95014610dd9578063f1dfaefb14610df957610511565b8063e8a3d485116100bb578063e8a3d48514610d5b578063e985e9c514610d70578063ec129eea14610db957610511565b8063d85d3d2714610d28578063e030565e14610d3b57610511565b8063c2f47cc81161012d578063ce92b33e11610112578063ce92b33e14610cc8578063d27998f714610ce8578063d58778d614610d0857610511565b8063c2f47cc814610c95578063c87b56dd14610ca857610511565b8063b85afd2814610c07578063b88d4fde14610c35578063bb5b27e114610c55578063c2f1f14a14610c7557610511565b806395d89b41116101f1578063a22cb465116101c0578063af1296d3116101a5578063af1296d314610bb2578063b14817dc14610bc7578063b5587dd714610be757610511565b8063a22cb46514610b72578063ab3b87fe14610b9257610511565b806395d89b4114610afd57806399f5a80714610b125780639bf35ca214610b325780639ec40d1c14610b5257610511565b80638da5cb5b116102485780638fc88c481161022d5780638fc88c4814610a90578063910bc4df14610ab0578063938e3d7b14610add57610511565b80638da5cb5b14610a585780638fc3047d14610a7b57610511565b8063714c5398146109f9578063715018a614610a0e5780637ef1a09814610a235780638456cb5914610a4357610511565b80633f4ba83a116103ba57806355f804b3116103325780636352211e116102e6578063672b9f81116102cb578063672b9f81146109955780636917a85e146109c357806370a08231146109d957610511565b80636352211e1461096057806365935e1b1461098057610511565b80635cd78c3a116103175780635cd78c3a146109005780635e5726ef146109135780635fe5afa21461093357610511565b806355f804b3146108c85780635c975abb146108e857610511565b8063438dac11116103895780634a72584d1161036e5780634a72584d146108505780634f558e791461087057806350382c1a146108a857610511565b8063438dac111461081057806347c816991461083057610511565b80633f4ba83a1461079b57806342842e0e146107b057806342966c68146107d0578063430c2081146107f057610511565b806323b872dd1161044d57806330347ebf1161041c5780633221f6db116104015780633221f6db1461075057806332f9b06a1461077057806333a581d21461078557610511565b806330347ebf14610712578063310bd74b1461073057610511565b806323b872dd1461068e57806326c0eff0146106ae57806326c7edf9146106ce57806327f18975146106f257610511565b8063095ea7b3116104a45780631bd8cc1a116104895780631bd8cc1a1461062e5780631be5e7ed1461065b57806322ae79611461067b57610511565b8063095ea7b3146105ec5780631593dee11461060e57610511565b80623379d71461054357806301ffc9a71461057a57806306fdde03146105aa578063081812fc146105cc57610511565b366105115760405134815233907f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f88525874906020015b60405180910390a2005b60405134815233907f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f8852587490602001610507565b34801561054f57600080fd5b50600d546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b34801561058657600080fd5b5061059a610595366004614f6d565b610e79565b6040519015158152602001610571565b3480156105b657600080fd5b506105bf610ebd565b6040516105719190614fda565b3480156105d857600080fd5b5061055d6105e7366004614fed565b610f4f565b3480156105f857600080fd5b5061060c61060736600461501b565b610f78565b005b34801561061a57600080fd5b5061059a610629366004615047565b610f87565b34801561063a57600080fd5b5061064e6106493660046150cd565b6110a2565b6040516105719190615171565b34801561066757600080fd5b506105bf6106763660046151c6565b611199565b61059a6106893660046151fe565b6111e4565b34801561069a57600080fd5b5061060c6106a9366004615047565b6112bd565b3480156106ba57600080fd5b506105bf6106c9366004614fed565b611301565b3480156106da57600080fd5b506106e4600f5481565b604051908152602001610571565b3480156106fe57600080fd5b5061060c61070d366004615253565b61139b565b34801561071e57600080fd5b506010546001600160a01b031661055d565b34801561073c57600080fd5b5061060c61074b366004614fed565b6113f6565b34801561075c57600080fd5b5061060c61076b366004614fed565b61141b565b34801561077c57600080fd5b506011546106e4565b34801561079157600080fd5b506106e460001981565b3480156107a757600080fd5b5061060c611492565b3480156107bc57600080fd5b5061060c6107cb366004615047565b6114a4565b3480156107dc57600080fd5b5061060c6107eb366004614fed565b6114c4565b3480156107fc57600080fd5b5061059a61080b36600461501b565b6114e2565b34801561081c57600080fd5b506106e461082b3660046152c7565b6114fb565b34801561083c57600080fd5b5061060c61084b3660046152e9565b61152b565b34801561085c57600080fd5b5061060c61086b36600461534b565b611554565b34801561087c57600080fd5b5061059a61088b366004614fed565b6000908152600260205260409020546001600160a01b0316151590565b3480156108b457600080fd5b5061060c6108c336600461544b565b611583565b3480156108d457600080fd5b5061060c6108e336600461544b565b6115b6565b3480156108f457600080fd5b5060075460ff1661059a565b61060c61090e366004615494565b611605565b34801561091f57600080fd5b506106e461092e36600461544b565b6117ab565b34801561093f57600080fd5b5061095361094e3660046152c7565b6117dc565b604051610571919061552e565b34801561096c57600080fd5b5061055d61097b366004614fed565b6118e0565b34801561098c57600080fd5b506105bf6118eb565b3480156109a157600080fd5b506109b56109b03660046152c7565b6118f8565b604051610571929190615572565b3480156109cf57600080fd5b506106e4600e5481565b3480156109e557600080fd5b506106e46109f43660046155a0565b611910565b348015610a0557600080fd5b506105bf611971565b348015610a1a57600080fd5b5061060c611980565b348015610a2f57600080fd5b5061060c610a3e3660046155a0565b611992565b348015610a4f57600080fd5b5061060c6119f5565b348015610a6457600080fd5b5060075461010090046001600160a01b031661055d565b348015610a8757600080fd5b506106e4611a05565b348015610a9c57600080fd5b506106e4610aab366004614fed565b611a45565b348015610abc57600080fd5b50610ad0610acb3660046152c7565b611a8e565b60405161057191906155bd565b348015610ae957600080fd5b5061060c610af836600461544b565b611b9e565b348015610b0957600080fd5b506105bf611bdf565b348015610b1e57600080fd5b5061064e610b2d3660046152c7565b611bee565b348015610b3e57600080fd5b50610ad0610b4d3660046152c7565b611d8f565b348015610b5e57600080fd5b506105bf610b6d36600461544b565b611e9f565b348015610b7e57600080fd5b5061060c610b8d36600461560c565b612120565b348015610b9e57600080fd5b5061060c610bad36600461501b565b61212b565b348015610bbe57600080fd5b506106e4612161565b348015610bd357600080fd5b5061064e610be2366004614fed565b612223565b348015610bf357600080fd5b506105bf610c02366004614fed565b61228f565b348015610c1357600080fd5b50610c27610c223660046150cd565b612331565b604051610571929190615645565b348015610c4157600080fd5b5061060c610c5036600461566a565b612455565b348015610c6157600080fd5b506105bf610c70366004614fed565b61248d565b348015610c8157600080fd5b5061055d610c90366004614fed565b6124aa565b61059a610ca33660046156ea565b6124fd565b348015610cb457600080fd5b506105bf610cc3366004614fed565b6125f4565b348015610cd457600080fd5b5061060c610ce3366004615253565b61269f565b348015610cf457600080fd5b5061060c610d033660046155a0565b6126c8565b348015610d1457600080fd5b506106e4610d23366004614fed565b612766565b61060c610d3636600461544b565b612787565b348015610d4757600080fd5b5061060c610d5636600461571d565b6128db565b348015610d6757600080fd5b506105bf6129bb565b348015610d7c57600080fd5b5061059a610d8b36600461576c565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b348015610dc557600080fd5b5061060c610dd4366004615253565b6129ca565b348015610de557600080fd5b5061059a610df436600461501b565b6129f3565b348015610e0557600080fd5b5061059a610e1436600461544b565b612a5a565b348015610e2557600080fd5b5061060c610e343660046155a0565b612a7d565b348015610e4557600080fd5b5061059a610e5436600461501b565b612ad1565b348015610e6557600080fd5b5061064e610e7436600461579a565b612b7f565b60006001600160e01b031982167fad092b5c000000000000000000000000000000000000000000000000000000001480610eb75750610eb782612bbd565b92915050565b606060008054610ecc906157dc565b80601f0160208091040260200160405190810160405280929190818152602001828054610ef8906157dc565b8015610f455780601f10610f1a57610100808354040283529160200191610f45565b820191906000526020600020905b815481529060010190602001808311610f2857829003601f168201915b5050505050905090565b6000610f5a82612bfb565b506000828152600460205260409020546001600160a01b0316610eb7565b610f83828233612c34565b5050565b6000610f91612c41565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015284906001600160a01b038216906370a0823190602401602060405180830381865afa158015610ff0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110149190615810565b8311156110345760405163fe382aa760e01b815260040160405180910390fd5b6110486001600160a01b0382168585612c8d565b836001600160a01b0316856001600160a01b03167f33c35f9541201e342d5e7467016e65a0a06182eb12a5f17103f71cec95b6cb298560405161108d91815260200190565b60405180910390a360019150505b9392505050565b60608267ffffffffffffffff8111156110bd576110bd61539e565b6040519080825280602002602001820160405280156110f057816020015b60608152602001906001900390816110db5790505b50905060005b838110156111915761116185858381811061111357611113615829565b9050602002810190611125919061583f565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250879250612d0d915050565b82828151811061117357611173615829565b602002602001018190525080806111899061589c565b9150506110f6565b509392505050565b60606111dc84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869250612d0d915050565b949350505050565b6000806111f1343a6114fb565b90508034101561122257604051632d74c84160e11b8152600481018290523460248201526044015b60405180910390fd5b600061122e82346158b5565b6040519091506001600160a01b0387169082156108fc029083906000818181858888f19350505050158015611267573d6000803e3d6000fd5b50856001600160a01b03167ff61a07121230585210fa1abd959f8da04c4c030b169c5a7dd2dd04a93d381b9a34838589896040516112a99594939291906158f1565b60405180910390a250600195945050505050565b806112e76112e0826000908152600260205260409020546001600160a01b031690565b3383612d42565b6112f082612da6565b6112fb848484612e69565b50505050565b6013602052600090815260409020805461131a906157dc565b80601f0160208091040260200160405190810160405280929190818152602001828054611346906157dc565b80156113935780601f1061136857610100808354040283529160200191611393565b820191906000526020600020905b81548152906001019060200180831161137657829003601f168201915b505050505081565b6113a3612f32565b806113af335b826129f3565b6113e157335b60405163177e802f60e01b81526001600160a01b03909116600482015260248101829052604401611219565b6113ee8686868686612f6f565b505050505050565b6113fe612f32565b80611408336113a9565b61141257336113b5565b610f8382612da6565b611423612c41565b61271060018183111561143a57600f829055611452565b8083101561144c57600f819055611452565b600f8390555b7f7188f446ea54aad8f9796527fa93140c34465d673bbcac6d4302763b37653d83600f5460405161148591815260200190565b60405180910390a1505050565b61149a612c41565b6114a2612fd2565b565b6114bf83838360405180602001604052806000815250612455565b505050565b6114cd81613024565b6114d681612da6565b6114df81613117565b50565b6000806114ee83612bfb565b90506111dc818585613123565b600080612710600f548561150f9190615922565b6115199190615939565b90508281101561109b57509092915050565b611533612f32565b8061153d336113a9565b61154757336113b5565b6113ee86868686866131a6565b61155c612f32565b80611566336113a9565b61157057336113b5565b61157c85858585613285565b5050505050565b6114df81604051602001611597919061595b565b6040516020818303038152906040528051906020012060001c8261333f565b6115be612c41565b600c6115ca82826159bd565b507f325d37e8fb549c86966f09bc3e6f62eb3afa93b255d6e3234338001f3d80bd86816040516115fa9190614fda565b60405180910390a150565b61160d612f32565b6000611617611a05565b90508034101561164357604051632d74c84160e11b815260048101829052346024820152604401611219565b803411156116bf57600061165782346158b5565b604051909150339082156108fc029083906000818181858888f19350505050158015611687573d6000803e3d6000fd5b5060405181815233907fc4df3884ed7590e8ca76a3638169a4560864d1c8cb3fd451e944de0bfe8a0ecc9060200160405180910390a2505b600061170088888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611e9f92505050565b9050805160000361172857878760405163172a347760e11b8152600401611219929190615a7d565b6000611733826117ab565b9050611740335b82613364565b60118054600181019091557f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6801819055600081815260136020526040902061178883826159bd565b50611793818361337e565b6117a087878787856133ce565b505050505050505050565b6000816040516020016117be919061595b565b60408051601f19818403018152919052805160209091012092915050565b606060006117eb836001615a91565b6011549091508111156117fd57506011545b80841061181d5760405163a857911360e01b815260040160405180910390fd5b600061182985836158b5565b67ffffffffffffffff8111156118415761184161539e565b60405190808252806020026020018201604052801561186a578160200160208202803683370190505b50905060005b61187a86846158b5565b8110156118d757601161188d8783615a91565b8154811061189d5761189d615829565b90600052602060002001548282815181106118ba576118ba615829565b6020908102919091010152806118cf8161589c565b915050611870565b50949350505050565b6000610eb782612bfb565b600c805461131a906157dc565b606080611905848461343c565b909590945092505050565b60006001600160a01b038216611955576040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152602401611219565b506001600160a01b031660009081526003602052604090205490565b6060600c8054610ecc906157dc565b611988612c41565b6114a2600061345d565b61199a612c41565b6010805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081527f890db4eb54cc623b3c73e4ba44f10a5be1496991c7aae2ebdd91ed5c04932165906020016115fa565b6119fd612c41565b6114a26134ce565b600080611a10612161565b905060006402540be400600e5483670de0b6b3a7640000611a319190615939565b611a3b9190615922565b61109b9190615939565b6000611a5082612bfb565b50600082815260126020526040902054600160a01b900467ffffffffffffffff16428110611a7e5792915050565b5060001992915050565b50919050565b60606000611a9d836001615a91565b601154909150811115611aaf57506011545b808410611acf5760405163a857911360e01b815260040160405180910390fd5b6000611adb85836158b5565b67ffffffffffffffff811115611af357611af361539e565b604051908082528060200260200182016040528015611b1c578160200160208202803683370190505b50905060005b611b2c86846158b5565b8110156118d757611b626011611b428884615a91565b81548110611b5257611b52615829565b90600052602060002001546118e0565b828281518110611b7457611b74615829565b6001600160a01b039092166020928302919091019091015280611b968161589c565b915050611b22565b611ba6612c41565b600b611bb282826159bd565b506040517fa5d4097edda6d87cb9329af83fb3712ef77eeb13738ffe43cc35a4ce305ad96290600090a150565b606060018054610ecc906157dc565b60606000611bfd836001615a91565b601154909150811115611c0f57506011545b808410611c2f5760405163a857911360e01b815260040160405180910390fd5b6000611c3b85836158b5565b67ffffffffffffffff811115611c5357611c5361539e565b604051908082528060200260200182016040528015611c8657816020015b6060815260200190600190039081611c715790505b50905060005b611c9686846158b5565b8110156118d757601360006011611cad8985615a91565b81548110611cbd57611cbd615829565b906000526020600020015481526020019081526020016000208054611ce1906157dc565b80601f0160208091040260200160405190810160405280929190818152602001828054611d0d906157dc565b8015611d5a5780601f10611d2f57610100808354040283529160200191611d5a565b820191906000526020600020905b815481529060010190602001808311611d3d57829003601f168201915b5050505050828281518110611d7157611d71615829565b60200260200101819052508080611d879061589c565b915050611c8c565b60606000611d9e836001615a91565b601154909150811115611db057506011545b808410611dd05760405163a857911360e01b815260040160405180910390fd5b6000611ddc85836158b5565b67ffffffffffffffff811115611df457611df461539e565b604051908082528060200260200182016040528015611e1d578160200160208202803683370190505b50905060005b611e2d86846158b5565b8110156118d757611e636011611e438884615a91565b81548110611e5357611e53615829565b90600052602060002001546124aa565b828281518110611e7557611e75615829565b6001600160a01b039092166020928302919091019091015280611e978161589c565b915050611e23565b6060600c825114611ebe57505060408051602081019091526000815290565b6000611ec98361350b565b9050600080611efa604051806040016040528060018152602001602b60f81b8152508461374190919063ffffffff16565b9150915081611f1b5750506040805160208101909152600081529392505050565b80611f48604051806040016040528060018152602001602b60f81b815250856138b590919063ffffffff16565b14611f655750506040805160208101909152600081529392505050565b60088114611f855750506040805160208101909152600081529392505050565b60005b835181101561203c576000611f9d8583613952565b60408051808201909152601481527f3233343536373839434647484a4d5051525657580000000000000000000000006020820152909150611fde90826139c5565b15801561200a57506040805180820190915260018152602b60f81b602082015261200890826139c5565b155b1561202957505060408051602081019091526000815295945050505050565b50806120348161589c565b915050611f88565b5060006120498482613952565b90506000601461209561205b8461350b565b60408051808201909152601481527f3233343536373839434647484a4d505152565758000000000000000000000000602082015290613b13565b61209f9190615922565b905060b481106120c357505060408051602081019091526000815295945050505050565b60006120d0866001613952565b9050600060146120e261205b8461350b565b6120ec9190615922565b90506101688110612113575050604080516020810190915260008152979650505050505050565b5094979650505050505050565b610f83338383613bb5565b8061214e6112e0826000908152600260205260409020546001600160a01b031690565b6114bf61215a836118e0565b8484612e69565b600080601060009054906101000a90046001600160a01b03166001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156121b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121db9190615abe565b5050509150506000811361221e576040517f4672cc9b00000000000000000000000000000000000000000000000000000000815260048101829052602401611219565b919050565b6060610eb7600a600084815260200190815260200160002080548060200260200160405190810160405280929190818152602001828054801561228557602002820191906000526020600020905b815481526020019060010190808311612271575b5050505050613c6d565b60008181526013602052604090208054606091906122ac906157dc565b80601f01602080910402602001604051908101604052809291908181526020018280546122d8906157dc565b80156123255780601f106122fa57610100808354040283529160200191612325565b820191906000526020600020905b81548152906001019060200180831161230857829003601f168201915b50505050509050919050565b6060808367ffffffffffffffff81111561234d5761234d61539e565b60405190808252806020026020018201604052801561238057816020015b606081526020019060019003908161236b5790505b5091508367ffffffffffffffff81111561239c5761239c61539e565b6040519080825280602002602001820160405280156123cf57816020015b60608152602001906001900390816123ba5790505b50905060005b8481101561244c576123ff8686838181106123f2576123f2615829565b905060200201358561343c565b84838151811061241157612411615829565b6020026020010184848151811061242a5761242a615829565b60200260200101829052829052505080806124449061589c565b9150506123d5565b50935093915050565b816124786112e0826000908152600260205260409020546001600160a01b031690565b61248183612da6565b61157c85858585613db0565b60008181526008602052604090208054606091906122ac906157dc565b6000806124b683612bfb565b60008481526012602052604090205490915042600160a01b90910467ffffffffffffffff1610610eb75750506000908152601260205260409020546001600160a01b031690565b60008061250a343a6114fb565b90508034101561253657604051632d74c84160e11b815260048101829052346024820152604401611219565b600061254282346158b5565b9050600061254f876124aa565b6040519091506001600160a01b0382169083156108fc029084906000818181858888f19350505050158015612588573d6000803e3d6000fd5b5086816001600160a01b03167f3038f50eed4db1e66532d22a12bb8a1b2afb7b76be123f0b7fb519efddd45e5d601360008b81526020019081526020016000203486888c8c6040516125df96959493929190615b0e565b60405180910390a35060019695505050505050565b6060600061260183613dc7565b600d549091506001600160a01b031615610eb757600d546040517f8419be1e000000000000000000000000000000000000000000000000000000008152600481018590526001600160a01b0390911690638419be1e90602401600060405180830381865afa158015612677573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261109b9190810190615bc4565b6126a7612f32565b806126b1336113a9565b6126bb57336113b5565b6113ee86868686866133ce565b6126d0612c41565b600d805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081527f2ce410f2911b731da01b611cabf31c231cd62c4bf630aad45ec80b5172f814ef9060200160405180910390a1604080516000815260001960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91016115fa565b6011818154811061277657600080fd5b600091825260209091200154905081565b61278f612f32565b6000612799611a05565b9050803410156127c557604051632d74c84160e11b815260048101829052346024820152604401611219565b803411156128415760006127d982346158b5565b604051909150339082156108fc029083906000818181858888f19350505050158015612809573d6000803e3d6000fd5b5060405181815233907fc4df3884ed7590e8ca76a3638169a4560864d1c8cb3fd451e944de0bfe8a0ecc9060200160405180910390a2505b600061284c83611e9f565b90508051600003612872578260405163172a347760e11b81526004016112199190614fda565b600061287d826117ab565b90506128883361173a565b60118054600181019091557f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c680181905560008181526013602052604090206128d083826159bd565b506112fb818361337e565b6128e3612f32565b826129066112e0826000908152600260205260409020546001600160a01b031690565b60008481526012602090815260409182902080546001600160a01b0387166001600160e01b03199091168117600160a01b67ffffffffffffffff881690810291909117835593519384529092909187917f4e06b4e7000e659094299b3533b47b6aa8ad048e95e872d23d1f4ee55af89cfe910160405180910390a36040518581527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a15050505050565b6060600b8054610ecc906157dc565b6129d2612f32565b806129dc336113a9565b6129e657336113b5565b6113ee8686868686613ec3565b6000806129ff83612bfb565b9050612a0a836124aa565b6001600160a01b0316816001600160a01b031603612a3557612a2d818585613123565b915050610eb7565b612a3e836124aa565b6001600160a01b0316846001600160a01b031614915050610eb7565b6000612a6582611e9f565b51600003612a7557506000919050565b506001919050565b612a85612c41565b6001600160a01b038116612ac8576040517f1e4fbdf700000000000000000000000000000000000000000000000000000000815260006004820152602401611219565b6114df8161345d565b6000612adb612c41565b47821115612afc5760405163fe382aa760e01b815260040160405180910390fd5b6040516001600160a01b0384169083156108fc029084906000818181858888f19350505050158015612b32573d6000803e3d6000fd5b50826001600160a01b03167f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a942436483604051612b6e91815260200190565b60405180910390a250600192915050565b606061109b838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613c6d92505050565b60006001600160e01b031982167f49064906000000000000000000000000000000000000000000000000000000001480610eb75750610eb782613ed9565b6000818152600260205260408120546001600160a01b031680610eb757604051637e27328960e01b815260048101849052602401611219565b6114bf8383836001613f74565b6007546001600160a01b036101009091041633146114a2576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401611219565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526114bf9084906140bf565b606061109b83604051602001612d23919061595b565b6040516020818303038152906040528051906020012060001c8361413b565b612d4d838383613123565b6114bf576001600160a01b038316612d7b57604051637e27328960e01b815260048101829052602401611219565b60405163177e802f60e01b81526001600160a01b038316600482015260248101829052604401611219565b60005b6000828152600a6020526040902054811015612e23576000828152600960209081526040808320600a9092528220805491929184908110612dec57612dec615829565b906000526020600020015481526020019081526020016000206000612e119190614eea565b80612e1b8161589c565b915050612da9565b506000818152600a60205260408120612e3b91614f24565b60405181907f185c30856dadb58bf097c1f665a52ada7029752dbcad008ea3fefc73bee8c9fe90600090a250565b6001600160a01b038216612e9357604051633250574960e11b815260006004820152602401611219565b6000612ea1838360006141e9565b90506001600160a01b038116612ecd57604051637e27328960e01b815260048101839052602401611219565b836001600160a01b0316816001600160a01b0316146112fb576040517f64283d7b0000000000000000000000000000000000000000000000000000000081526001600160a01b0380861660048301526024820184905282166044820152606401611219565b60075460ff16156114a2576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b848110156113ee57612fc0868683818110612f8f57612f8f615829565b90506020020135858584818110612fa857612fa8615829565b9050602002810190612fba919061583f565b85613285565b80612fca8161589c565b915050612f72565b612fda6142c1565b6007805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60005b601154811015610f8357816011828154811061304557613045615829565b906000526020600020015403613105575b601154613065906001906158b5565b8110156130c5576011613079826001615a91565b8154811061308957613089615829565b9060005260206000200154601182815481106130a7576130a7615829565b600091825260209091200155806130bd8161589c565b915050613056565b60118054806130d6576130d6615c32565b6000828152602080822083016000199081018390559092019092558382526013905260408120610f8391614eea565b8061310f8161589c565b915050613027565b610f83600082336141e9565b60006001600160a01b038316158015906111dc5750826001600160a01b0316846001600160a01b0316148061317d57506001600160a01b0380851660009081526005602090815260408083209387168352929052205460ff165b806111dc5750506000908152600460205260409020546001600160a01b03908116911614919050565b600085856040516020016131bb929190615c48565b60408051601f198184030181528282528051602091820120601f890182900482028401820190925287835290925061320f918391899089908190840183828082843760009201919091525061333f92505050565b6113ee8187878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8b0181900481028201810190925289815292508991508890819084018382808284376000920191909152508892506142fd915050565b61328e8461442b565b6132f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f5265636f726453746f726167653a204b45595f4e4f545f464f554e44000000006044820152606401611219565b6112fb846133018661248d565b85858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508792506142fd915050565b6133488261442b565b610f835760008281526008602052604090206114bf82826159bd565b610f83828260405180602001604052806000815250614451565b600082815260066020526040902061339682826159bd565b506040518281527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a15050565b60005b848110156113ee5761342a8686838181106133ee576133ee615829565b9050602002810190613400919061583f565b86868581811061341257613412615829565b9050602002810190613424919061583f565b866131a6565b806134348161589c565b9150506133d1565b6060806134488461248d565b9150613454848461413b565b90509250929050565b600780546001600160a01b038381166101008181027fffffffffffffffffffffff0000000000000000000000000000000000000000ff85161790945560405193909204169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6134d6612f32565b6007805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586130073390565b606060006040518060800160405280604d8152602001615d25604d91399050600061356d826040518060400160405280600181526020017f3b000000000000000000000000000000000000000000000000000000000000008152506028614468565b6040805160208101909152600080825291925085915b8251811015613737576040805160018082528183019092526000916020820181803683370190505090508782815181106135bf576135bf615829565b602001015160f81c60f81b816000815181106135dd576135dd615829565b60200101906001600160f81b031916908160001a9053506000805b86518110156136f257600061362688838151811061361857613618615829565b6020026020010151856139c5565b905080156136df5760408051600180825281830190925260009160208201818036833701905050905088838151811061366157613661615829565b602002602001015160008151811061367b5761367b615829565b602001015160f81c60f81b8160008151811061369957613699615829565b60200101906001600160f81b031916908160001a90535086816040516020016136c3929190615c58565b60405160208183030381529060405296506001935050506136f2565b50806136ea8161589c565b9150506135f8565b50801515600003613722578382604051602001613710929190615c58565b60405160208183030381529060405293505b5050808061372f9061589c565b915050613583565b5095945050505050565b60008083838260001981805b85518110156138a4576000855167ffffffffffffffff8111156137725761377261539e565b6040519080825280601f01601f19166020018201604052801561379c576020820181803683370190505b5090506000825b87516137af9085615a91565b81101561381c578c81815181106137c8576137c8615829565b602001015160f81c60f81b8383815181106137e5576137e5615829565b60200101906001600160f81b031916908160001a905350816138068161589c565b92505080806138149061589c565b9150506137a3565b506040518290613830908d9060200161595b565b6040516020818303038152906040528051906020012081604051602001613857919061595b565b604051602081830303815290604052805190602001200361388157600196508495505050506138a4565b8461388b81615c87565b955050505050808061389c9061589c565b91505061374d565b5091955093505050505b9250929050565b60008281805b82518110156118d7576040805160018082528183019092526000916020820181803683370190505090508682815181106138f7576138f7615829565b602001015160f81c60f81b8160008151811061391557613915615829565b60200101906001600160f81b031916908160001a9053506139368187614872565b1561393f578192505b508061394a8161589c565b9150506138bb565b6040805160018082528183019092526060916000919060208201818036833701905050905083838151811061398957613989615829565b602001015160f81c60f81b816000815181106139a7576139a7615829565b60200101906001600160f81b031916908160001a9053509392505050565b6000828282805b8351811015613737576000835167ffffffffffffffff8111156139f1576139f161539e565b6040519080825280601f01601f191660200182016040528015613a1b576020820181803683370190505b5090506000825b8551613a2e9085615a91565b811015613a9b57898181518110613a4757613a47615829565b602001015160f81c60f81b838381518110613a6457613a64615829565b60200101906001600160f81b031916908160001a90535081613a858161589c565b9250508080613a939061589c565b915050613a22565b506040518290613aaf908a9060200161595b565b6040516020818303038152906040528051906020012081604051602001613ad6919061595b565b6040516020818303038152906040528051906020012003613afd5760019450505050613737565b5050508080613b0b9061589c565b9150506139cc565b60008281805b82518110156118d757604080516001808252818301909252600091602082018180368337019050509050868281518110613b5557613b55615829565b602001015160f81c60f81b81600081518110613b7357613b73615829565b60200101906001600160f81b031916908160001a905350613b948187614872565b15613ba257819250506118d7565b5080613bad8161589c565b915050613b19565b6001600160a01b038216613c00576040517f5b08ba180000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401611219565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6060815167ffffffffffffffff811115613c8957613c8961539e565b604051908082528060200260200182016040528015613cbc57816020015b6060815260200190600190039081613ca75790505b50905060005b8251811015611a885760086000848381518110613ce157613ce1615829565b602002602001015181526020019081526020016000208054613d02906157dc565b80601f0160208091040260200160405190810160405280929190818152602001828054613d2e906157dc565b8015613d7b5780601f10613d5057610100808354040283529160200191613d7b565b820191906000526020600020905b815481529060010190602001808311613d5e57829003601f168201915b5050505050828281518110613d9257613d92615829565b60200260200101819052508080613da89061589c565b915050613cc2565b613dbb848484612e69565b6112fb848484846148cb565b6060613dd282612bfb565b5060008281526006602052604081208054613dec906157dc565b80601f0160208091040260200160405190810160405280929190818152602001828054613e18906157dc565b8015613e655780601f10613e3a57610100808354040283529160200191613e65565b820191906000526020600020905b815481529060010190602001808311613e4857829003601f168201915b505050505090506000613e76611971565b90508051600003613e88575092915050565b815115613eba578082604051602001613ea2929190615c58565b60405160208183030381529060405292505050919050565b6111dc846149ed565b613ecc81612da6565b61157c85858585856133ce565b60006001600160e01b031982167f80ac58cd000000000000000000000000000000000000000000000000000000001480613f3c57506001600160e01b031982167f5b5e139f00000000000000000000000000000000000000000000000000000000145b80610eb757507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614610eb7565b8080613f8857506001600160a01b03821615155b15614082576000613f9884612bfb565b90506001600160a01b03831615801590613fc45750826001600160a01b0316816001600160a01b031614155b8015613ff657506001600160a01b0380821660009081526005602090815260408083209387168352929052205460ff16155b15614038576040517fa9fbf51f0000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611219565b81156140805783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b50506000908152600460205260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b60006140d46001600160a01b03841683614a54565b905080516000141580156140f95750808060200190518101906140f79190615cb8565b155b156114bf576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611219565b60008181526009602090815260408083208584529091529020805460609190614163906157dc565b80601f016020809104026020016040519081016040528092919081815260200182805461418f906157dc565b80156141dc5780601f106141b1576101008083540402835291602001916141dc565b820191906000526020600020905b8154815290600101906020018083116141bf57829003601f168201915b5050505050905092915050565b6000806141f7858585614a62565b9050846001600160a01b0316816001600160a01b03161415801561423157506000848152601260205260409020546001600160a01b031615155b156111dc57600084815260126020908152604080832080546001600160e01b03191690555182815286917f4e06b4e7000e659094299b3533b47b6aa8ad048e95e872d23d1f4ee55af89cfe910160405180910390a36040518481527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a1949350505050565b60075460ff166114a2576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260096020908152604080832087845290915290208054614321906157dc565b905060000361439b576000818152600a60209081526040808320805460018101825590845291909220018590555161435a90849061595b565b6040518091039020817f7ae4f661958fbecc2f77be6b0eb280d2a6f604b29e1e7221c82b9da0c4af7f86856040516143929190614fda565b60405180910390a35b600081815260096020908152604080832087845290915290206143be83826159bd565b50816040516143cd919061595b565b6040518091039020836040516143e3919061595b565b6040518091039020827f851ffe8e74d5015261dba0a1f9e1b0e5d42c5af5d2ad1908fee897c7d80a0d92868660405161441d929190615572565b60405180910390a450505050565b60008181526008602052604081208054829190614447906157dc565b9050119050919050565b61445b8383614a77565b6114bf60008484846148cb565b6060838360405160200161447d929190615c58565b60408051601f198184030181529190529350838360008467ffffffffffffffff8111156144ac576144ac61539e565b6040519080825280602002602001820160405280156144df57816020015b60608152602001906001900390816144ca5790505b50905060008060005b8551821015614752576000855167ffffffffffffffff81111561450d5761450d61539e565b6040519080825280601f01601f191660200182016040528015614537576020820181803683370190505b5090506000835b84895161454b91906158b5565b88511161456357875161455e9086615a91565b614570565b84895161457091906158b5565b8110156145dd578c818151811061458957614589615829565b602001015160f81c60f81b8383815181106145a6576145a6615829565b60200101906001600160f81b031916908160001a905350816145c78161589c565b92505080806145d59061589c565b91505061453e565b5060405182906145f1908d9060200161595b565b6040516020818303038152906040528051906020012081604051602001614618919061595b565b604051602081830303815290604052805190602001200361473c57600061463f87876158b5565b67ffffffffffffffff8111156146575761465761539e565b6040519080825280601f01601f191660200182016040528015614681576020820181803683370190505b5090506000875b878110156146f6578f81815181106146a2576146a2615829565b602001015160f81c60f81b8383815181106146bf576146bf615829565b60200101906001600160f81b031916908160001a905350816146e08161589c565b92505080806146ee9061589c565b915050614688565b508189878151811061470a5761470a615829565b602002602001018190525085806147209061589c565b9650508951876147309190615a91565b9650869750505061474a565b614747600186615a91565b94505b5050506144e8565b60008167ffffffffffffffff81111561476d5761476d61539e565b6040519080825280602002602001820160405280156147a057816020015b606081526020019060019003908161478b5790505b50905060005b828110156147f8578581815181106147c0576147c0615829565b60200260200101518282815181106147da576147da615829565b602002602001018190525080806147f09061589c565b9150506147a6565b506040805160008082526020820190925290614824565b606081526020019060019003908161480f5790505b509450600181511161486157604080516000808252602082019092529061485b565b60608152602001906001900390816148465790505b50614863565b805b9b9a5050505050505050505050565b600081604051602001614885919061595b565b60405160208183030381529060405280519060200120836040516020016148ac919061595b565b6040516020818303038152906040528051906020012014905092915050565b6001600160a01b0383163b156112fb57604051630a85bd0160e11b81526001600160a01b0384169063150b7a029061490d903390889087908790600401615cd5565b6020604051808303816000875af1925050508015614948575060408051601f3d908101601f1916820190925261494591810190615d07565b60015b6149b1573d808015614976576040519150601f19603f3d011682016040523d82523d6000602084013e61497b565b606091505b5080516000036149a957604051633250574960e11b81526001600160a01b0385166004820152602401611219565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b1461157c57604051633250574960e11b81526001600160a01b0385166004820152602401611219565b60606149f882612bfb565b506000614a03611971565b90506000815111614a23576040518060200160405280600081525061109b565b80614a2d84614af5565b604051602001614a3e929190615c58565b6040516020818303038152906040529392505050565b606061109b83836000614b95565b6000614a6c612f32565b6111dc848484614c4b565b6001600160a01b038216614aa157604051633250574960e11b815260006004820152602401611219565b6000614aaf838360006141e9565b90506001600160a01b038116156114bf576040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152602401611219565b60606000614b0283614d51565b600101905060008167ffffffffffffffff811115614b2257614b2261539e565b6040519080825280601f01601f191660200182016040528015614b4c576020820181803683370190505b5090508181016020015b600019017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8504945084614b5657509392505050565b606081471015614bd3576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611219565b600080856001600160a01b03168486604051614bef919061595b565b60006040518083038185875af1925050503d8060008114614c2c576040519150601f19603f3d011682016040523d82523d6000602084013e614c31565b606091505b5091509150614c41868383614e33565b9695505050505050565b6000828152600260205260408120546001600160a01b0390811690831615614c7857614c78818486612d42565b6001600160a01b03811615614cb657614c95600085600080613f74565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b03851615614ce5576001600160a01b0385166000908152600360205260409020805460010190555b600084815260026020526040808220805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310614d9a577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310614dc6576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310614de457662386f26fc10000830492506010015b6305f5e1008310614dfc576305f5e100830492506008015b6127108310614e1057612710830492506004015b60648310614e22576064830492506002015b600a8310610eb75760010192915050565b606082614e4857614e4382614ea8565b61109b565b8151158015614e5f57506001600160a01b0384163b155b15614ea1576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611219565b508061109b565b805115614eb85780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b508054614ef6906157dc565b6000825580601f10614f06575050565b601f0160209004906000526020600020908101906114df9190614f3e565b50805460008255906000526020600020908101906114df91905b5b80821115614f535760008155600101614f3f565b5090565b6001600160e01b0319811681146114df57600080fd5b600060208284031215614f7f57600080fd5b813561109b81614f57565b60005b83811015614fa5578181015183820152602001614f8d565b50506000910152565b60008151808452614fc6816020860160208601614f8a565b601f01601f19169290920160200192915050565b60208152600061109b6020830184614fae565b600060208284031215614fff57600080fd5b5035919050565b6001600160a01b03811681146114df57600080fd5b6000806040838503121561502e57600080fd5b823561503981615006565b946020939093013593505050565b60008060006060848603121561505c57600080fd5b833561506781615006565b9250602084013561507781615006565b929592945050506040919091013590565b60008083601f84011261509a57600080fd5b50813567ffffffffffffffff8111156150b257600080fd5b6020830191508360208260051b85010111156138ae57600080fd5b6000806000604084860312156150e257600080fd5b833567ffffffffffffffff8111156150f957600080fd5b61510586828701615088565b909790965060209590950135949350505050565b600082825180855260208086019550808260051b84010181860160005b8481101561516457601f19868403018952615152838351614fae565b98840198925090830190600101615136565b5090979650505050505050565b60208152600061109b6020830184615119565b60008083601f84011261519657600080fd5b50813567ffffffffffffffff8111156151ae57600080fd5b6020830191508360208285010111156138ae57600080fd5b6000806000604084860312156151db57600080fd5b833567ffffffffffffffff8111156151f257600080fd5b61510586828701615184565b60008060006040848603121561521357600080fd5b833561521e81615006565b9250602084013567ffffffffffffffff81111561523a57600080fd5b61524686828701615184565b9497909650939450505050565b60008060008060006060868803121561526b57600080fd5b853567ffffffffffffffff8082111561528357600080fd5b61528f89838a01615088565b909750955060208801359150808211156152a857600080fd5b506152b588828901615088565b96999598509660400135949350505050565b600080604083850312156152da57600080fd5b50508035926020909101359150565b60008060008060006060868803121561530157600080fd5b853567ffffffffffffffff8082111561531957600080fd5b61532589838a01615184565b9097509550602088013591508082111561533e57600080fd5b506152b588828901615184565b6000806000806060858703121561536157600080fd5b84359350602085013567ffffffffffffffff81111561537f57600080fd5b61538b87828801615184565b9598909750949560400135949350505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156153dd576153dd61539e565b604052919050565b600067ffffffffffffffff8211156153ff576153ff61539e565b50601f01601f191660200190565b600061542061541b846153e5565b6153b4565b905082815283838301111561543457600080fd5b828260208301376000602084830101529392505050565b60006020828403121561545d57600080fd5b813567ffffffffffffffff81111561547457600080fd5b8201601f8101841361548557600080fd5b6111dc8482356020840161540d565b600080600080600080606087890312156154ad57600080fd5b863567ffffffffffffffff808211156154c557600080fd5b6154d18a838b01615184565b909850965060208901359150808211156154ea57600080fd5b6154f68a838b01615088565b9096509450604089013591508082111561550f57600080fd5b5061551c89828a01615088565b979a9699509497509295939492505050565b6020808252825182820181905260009190848201906040850190845b818110156155665783518352928401929184019160010161554a565b50909695505050505050565b6040815260006155856040830185614fae565b82810360208401526155978185614fae565b95945050505050565b6000602082840312156155b257600080fd5b813561109b81615006565b6020808252825182820181905260009190848201906040850190845b818110156155665783516001600160a01b0316835292840192918401916001016155d9565b80151581146114df57600080fd5b6000806040838503121561561f57600080fd5b823561562a81615006565b9150602083013561563a816155fe565b809150509250929050565b6040815260006156586040830185615119565b82810360208401526155978185615119565b6000806000806080858703121561568057600080fd5b843561568b81615006565b9350602085013561569b81615006565b925060408501359150606085013567ffffffffffffffff8111156156be57600080fd5b8501601f810187136156cf57600080fd5b6156de8782356020840161540d565b91505092959194509250565b6000806000604084860312156156ff57600080fd5b83359250602084013567ffffffffffffffff81111561523a57600080fd5b60008060006060848603121561573257600080fd5b83359250602084013561574481615006565b9150604084013567ffffffffffffffff8116811461576157600080fd5b809150509250925092565b6000806040838503121561577f57600080fd5b823561578a81615006565b9150602083013561563a81615006565b600080602083850312156157ad57600080fd5b823567ffffffffffffffff8111156157c457600080fd5b6157d085828601615088565b90969095509350505050565b600181811c908216806157f057607f821691505b602082108103611a8857634e487b7160e01b600052602260045260246000fd5b60006020828403121561582257600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261585657600080fd5b83018035915067ffffffffffffffff82111561587157600080fd5b6020019150368190038213156138ae57600080fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016158ae576158ae615886565b5060010190565b81810381811115610eb757610eb7615886565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8581528460208201528360408201526080606082015260006159176080830184866158c8565b979650505050505050565b8082028115828204841417610eb757610eb7615886565b60008261595657634e487b7160e01b600052601260045260246000fd5b500490565b6000825161596d818460208701614f8a565b9190910192915050565b601f8211156114bf57600081815260208120601f850160051c8101602086101561599e5750805b601f850160051c820191505b818110156113ee578281556001016159aa565b815167ffffffffffffffff8111156159d7576159d761539e565b6159eb816159e584546157dc565b84615977565b602080601f831160018114615a205760008415615a085750858301515b600019600386901b1c1916600185901b1785556113ee565b600085815260208120601f198616915b82811015615a4f57888601518255948401946001909101908401615a30565b5085821015615a6d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6020815260006111dc6020830184866158c8565b80820180821115610eb757610eb7615886565b805169ffffffffffffffffffff8116811461221e57600080fd5b600080600080600060a08688031215615ad657600080fd5b615adf86615aa4565b9450602086015193506040860151925060608601519150615b0260808701615aa4565b90509295509295909350565b60a081526000808854615b20816157dc565b8060a086015260c0600180841660008114615b425760018114615b5c57615b8d565b60ff1985168884015283151560051b880183019550615b8d565b8d60005260208060002060005b86811015615b845781548b8201870152908401908201615b69565b8a018501975050505b50505050508760208401528660408401528560608401528281036080840152615bb78185876158c8565b9998505050505050505050565b600060208284031215615bd657600080fd5b815167ffffffffffffffff811115615bed57600080fd5b8201601f81018413615bfe57600080fd5b8051615c0c61541b826153e5565b818152856020838501011115615c2157600080fd5b615597826020830160208601614f8a565b634e487b7160e01b600052603160045260246000fd5b8183823760009101908152919050565b60008351615c6a818460208801614f8a565b835190830190615c7e818360208801614f8a565b01949350505050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036158ae576158ae615886565b600060208284031215615cca57600080fd5b815161109b816155fe565b60006001600160a01b03808716835280861660208401525083604083015260806060830152614c416080830184614fae565b600060208284031215615d1957600080fd5b815161109b81614f5756fe41613b42623b43633b44643b45653b46663b47673b48683b49693b4a6a3b4b6b3b4c6c3b4d6d3b4e6e3b4f6f3b50703b51713b52723b53733b54743b55753b56763b57773b58783b59793b5a7aa26469706673582212200bcbf71bf3e9776e2788d9bed646e97de8aeb07449951b7281e8db61120dc8f264736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000007844435664403e5da4105b3400713d987295e45300000000000000000000000000000000000000000000000006f05b59d3b200000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000694aa1769357215de4fac081bf1f309adc325306000000000000000000000000000000000000000000000000000000000000001668747470733a2f2f74616e6769626c696e6b2e696f2f00000000000000000000
-----Decoded View---------------
Arg [0] : baseURI (string): https://tangiblink.io/
Arg [1] : metadata (address): 0x7844435664403E5da4105b3400713D987295e453
Arg [2] : mintCostUsd (uint256): 500000000000000000
Arg [3] : feePercent (uint256): 100
Arg [4] : maticUsdFeed (address): 0x694AA1769357215DE4FAC081bf1f309aDC325306
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [1] : 0000000000000000000000007844435664403e5da4105b3400713d987295e453
Arg [2] : 00000000000000000000000000000000000000000000000006f05b59d3b20000
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [4] : 000000000000000000000000694aa1769357215de4fac081bf1f309adc325306
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000016
Arg [6] : 68747470733a2f2f74616e6769626c696e6b2e696f2f00000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.