Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 133 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Approve Admin | 18842508 | 336 days ago | IN | 0 ETH | 0.00321723 | ||||
Buy | 18690094 | 358 days ago | IN | 0.1 ETH | 0.0087099 | ||||
Buy | 18690068 | 358 days ago | IN | 0.1 ETH | 0.01007333 | ||||
Buy | 18689764 | 358 days ago | IN | 0.1 ETH | 0.0075697 | ||||
Buy | 18689273 | 358 days ago | IN | 0.5 ETH | 0.01341755 | ||||
Buy | 18688770 | 358 days ago | IN | 0.2 ETH | 0.01004982 | ||||
Buy | 18688060 | 358 days ago | IN | 0.1 ETH | 0.00842042 | ||||
Buy | 18687911 | 358 days ago | IN | 0.1 ETH | 0.01342836 | ||||
Buy | 18687906 | 358 days ago | IN | 0.1 ETH | 0.0040597 | ||||
Buy | 18687396 | 358 days ago | IN | 0.1 ETH | 0.01416887 | ||||
Buy | 18686765 | 358 days ago | IN | 0.2 ETH | 0.02209378 | ||||
Buy | 18684469 | 358 days ago | IN | 0.2 ETH | 0.00883386 | ||||
Buy | 18683792 | 359 days ago | IN | 0.1 ETH | 0.00622072 | ||||
Buy | 18679873 | 359 days ago | IN | 0.1 ETH | 0.02505492 | ||||
Buy | 18678961 | 359 days ago | IN | 0.2 ETH | 0.00955041 | ||||
Buy | 18678957 | 359 days ago | IN | 0.2 ETH | 0.0100966 | ||||
Buy | 18677505 | 359 days ago | IN | 0.1 ETH | 0.00772903 | ||||
Buy | 18677433 | 359 days ago | IN | 0.5 ETH | 0.01603542 | ||||
Buy | 18677207 | 359 days ago | IN | 0.1 ETH | 0.00686195 | ||||
Buy | 18677130 | 360 days ago | IN | 0.5 ETH | 0.01687391 | ||||
Buy | 18676197 | 360 days ago | IN | 0.7 ETH | 0.01756951 | ||||
Buy | 18675574 | 360 days ago | IN | 0.1 ETH | 0.00702185 | ||||
Buy | 18675340 | 360 days ago | IN | 0.2 ETH | 0.0084208 | ||||
Buy | 18674298 | 360 days ago | IN | 0.2 ETH | 0.00945002 | ||||
Buy | 18674295 | 360 days ago | IN | 0.2 ETH | 0.00210938 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
18690094 | 358 days ago | 0.099 ETH | ||||
18690094 | 358 days ago | 0.001 ETH | ||||
18690068 | 358 days ago | 0.099 ETH | ||||
18690068 | 358 days ago | 0.001 ETH | ||||
18689764 | 358 days ago | 0.099 ETH | ||||
18689764 | 358 days ago | 0.001 ETH | ||||
18689273 | 358 days ago | 0.495 ETH | ||||
18689273 | 358 days ago | 0.005 ETH | ||||
18688770 | 358 days ago | 0.198 ETH | ||||
18688770 | 358 days ago | 0.002 ETH | ||||
18688060 | 358 days ago | 0.099 ETH | ||||
18688060 | 358 days ago | 0.001 ETH | ||||
18687911 | 358 days ago | 0.099 ETH | ||||
18687911 | 358 days ago | 0.001 ETH | ||||
18687396 | 358 days ago | 0.099 ETH | ||||
18687396 | 358 days ago | 0.001 ETH | ||||
18686765 | 358 days ago | 0.198 ETH | ||||
18686765 | 358 days ago | 0.002 ETH | ||||
18684469 | 358 days ago | 0.198 ETH | ||||
18684469 | 358 days ago | 0.002 ETH | ||||
18683792 | 359 days ago | 0.099 ETH | ||||
18683792 | 359 days ago | 0.001 ETH | ||||
18679873 | 359 days ago | 0.099 ETH | ||||
18679873 | 359 days ago | 0.001 ETH | ||||
18678961 | 359 days ago | 0.198 ETH |
Loading...
Loading
Contract Name:
OnchainBuy
Compiler Version
v0.8.7+commit.e28d00a7
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; pragma experimental ABIEncoderV2; import {IERC721, IERC165} from "../../openzeppelin/token/ERC721/IERC721.sol"; import {IERC1155} from "../../openzeppelin/token/ERC1155/IERC1155.sol"; import {ReentrancyGuard} from "../../openzeppelin/security/ReentrancyGuard.sol"; import {IERC20} from "../../openzeppelin/token/ERC20/IERC20.sol"; import {SafeERC20} from "../../openzeppelin/token/ERC20/utils/SafeERC20.sol"; import {AdminControl} from "../../manifold/libraries-solidity/access/AdminControl.sol"; import {IERC721CreatorCore} from "../../manifold/creator-core/core/IERC721CreatorCore.sol"; import {IERC1155CreatorCore} from "../../manifold/creator-core/core/IERC1155CreatorCore.sol"; import {ECDSA} from "../../openzeppelin/utils/cryptography/ECDSA.sol"; interface IPriceFeed { function getLatestPrice( uint256 amount, address fiat ) external view returns (uint256); } interface IRoyaltyEngine { function getRoyalty( address collectionAddress, uint256 tokenId ) external view returns (address payable[] memory, uint256[] memory); } interface ITokenGating { function acquireGating( address collectionAddress, uint256 tokenId, address walletAddress ) external returns (bool); } /** * @title An onchain payment for buy now flow where owners can list the tokens for sale and the buyers can buy the token using the buy function */ contract OnchainBuy is ReentrancyGuard, AdminControl { using SafeERC20 for IERC20; using ECDSA for bytes32; /// @notice The metadata for a given Order /// @param nftStartTokenId the Nft token Id listed From /// @param nftEndTokenId the NFT token Id listed To /// @param maxCap the total supply for minting /// @param nftContractAddress the nft contract address /// @param minimumFiatPrice the minimum price of the listed tokens /// @param minimumCryptoPrice the cryptoprice of provided crypto /// @param paymentCurrency the payment currency for seller requirement /// @param paymentSettlement the settlement address and payment percentage provided in basis points /// @param TransactionStatus the status to be minted or transfered /// @param PaymentStatus the status to get the price from fiat conversion or crypto price provided /// @param tokenGatingContract the address of the gating contract struct PriceList { uint64 nftStartTokenId; uint64 nftEndTokenId; uint64 maxCap; address nftContractAddress; uint256 minimumFiatPrice; // in USD uint256[] minimumCryptoPrice; // in Crypto address[] paymentCurrency; // in ETH/ERC20 settlementList paymentSettlement; TransactionStatus transactionStatus; PaymentStatus paymentStatus; address tokenGatingContract; } /// @notice The metadata for a given Order /// @param paymentSettlementAddress the settlement address for the listed tokens /// @param taxSettlementAddress the taxsettlement address for settlement of tax fee /// @param commissionAddress the commission address for settlement of commission fee /// @param platformSettlementAddress the platform address for settlement of platform fee /// @param commissionFeePercentage the commission fee given in basis points /// @param platformFeePercentage the platform fee given in basis points struct settlementList { address payable paymentSettlementAddress; address payable taxSettlementAddress; address payable commissionAddress; address payable platformSettlementAddress; uint16 commissionFeePercentage; // in basis points uint16 platformFeePercentage; // in basis points } /// @notice The details to be provided to buy the token /// @param saleId the Id of the created sale /// @param tokenOwner the owner of the nft token /// @param tokenId the token Id of the owner owns /// @param tokenQuantity the token Quantity only required if minting /// @param quantity the quantity of tokens for 1155 only /// @param buyer the person who buys the nft /// @param paymentToken the type of payment currency that the buyers pay out /// @param paymentAmount the amount to be paid in the payment currency /// @param gatedCollection the gated nft collection need to be verified /// @param gatedTokenId the tokenId which was gated struct BuyList { string saleId; address tokenOwner; uint256 tokenId; uint64 tokenQuantity; uint64 quantity; address buyer; address paymentToken; uint256 paymentAmount; address gatedColletion; uint256 gatedTokenId; } struct Discount { uint16 discountPercentage; uint32 expirationTime; string nonce; bytes signature; address signer; } // TransactionStatus shows the preference for mint or transfer enum TransactionStatus { mint, transfer } // PaymentStatus shows the preference for fiat conversion or direct crypto enum PaymentStatus { fiat, crypto } // Fee percentage to the Platform uint16 private platformFeePercentage; // maxQuantity for 1155 NFT-tokens uint64 private max1155Quantity; // admin approval requirement bool adminApprovalRequired; // Platform Address address payable private platformAddress; // The address of the Price Feed Aggregator to use via this contract IPriceFeed private priceFeedAddress; // The address of the royaltySupport to use via this contract IRoyaltyEngine private royaltySupport; // listing the sale details in sale Id mapping(string => PriceList) public listings; // tokens used to be compared with maxCap mapping(string => uint256) public tokensUsed; // validating saleId mapping(string => bool) usedSaleId; // Discount validation mapping(bytes => bool) public discountUsed; // Interface ID constants bytes4 private constant ERC721_INTERFACE_ID = 0x80ac58cd; bytes4 private constant ERC1155_INTERFACE_ID = 0xd9b67a26; /// @notice Emitted when sale is created /// @param saleList contains the details of sale created /// @param CreatedOrUpdated the details provide whether sale is created or updated event saleCreated(PriceList saleList, string CreatedOrUpdated); /// @notice Emitted when sale is closed /// @param saleId contains the details of cancelled sale event saleClosed(string saleId); /// @notice Emitted when an Buy Event is completed /// @param tokenContract The NFT Contract address /// @param buyingDetails consist of buyer details /// @param MintedtokenId consist of minted tokenId details /// @param tax paid to the taxsettlement Address /// @param paymentAmount total amount paid by buyer /// @param totalAmount the amount paid by the buyer event BuyExecuted( address indexed tokenContract, BuyList buyingDetails, uint256[] MintedtokenId, uint256 tax, uint256 paymentAmount, uint256 totalAmount ); /// @notice Emitted when an Royalty Payout is executed /// @param tokenId The NFT tokenId /// @param tokenContract The NFT Contract address /// @param recipient Address of the Royalty Recipient /// @param amount Amount sent to the royalty recipient address event RoyaltyPayout( address tokenContract, uint256 tokenId, address recipient, uint256 amount ); /// @param _platformAddress The Platform Address /// @param _platformFeePercentage The Platform fee percentage /// @param _max1155Quantity The max quantity we support for 1155 Nfts /// @param _priceFeedAddress the address of the pricefeed /// @param _royaltycontract the address to get the royalty data /// @param _adminApprovalRequired the bool data to specify the admin approval requirement constructor( address _platformAddress, uint16 _platformFeePercentage, uint64 _max1155Quantity, IPriceFeed _priceFeedAddress, IRoyaltyEngine _royaltycontract, bool _adminApprovalRequired ) { require(_platformAddress != address(0), "Invalid Platform Address"); require( _platformFeePercentage < 10000, "platformFee should be less than 10000" ); platformAddress = payable(_platformAddress); platformFeePercentage = _platformFeePercentage; max1155Quantity = _max1155Quantity; priceFeedAddress = _priceFeedAddress; royaltySupport = _royaltycontract; adminApprovalRequired = _adminApprovalRequired; } /** * @notice creating a batch sales using batch details . * @param list gives the listing details to create a sale * @param saleId consist of the id of the listed sale */ function createOrUpdateSale( PriceList calldata list, string calldata saleId ) external adminRequired { uint16 totalFeeBasisPoints; // checks for platform and commission fee to be less than 100 % if (list.paymentSettlement.platformFeePercentage != 0) { totalFeeBasisPoints += (list .paymentSettlement .platformFeePercentage + list.paymentSettlement.commissionFeePercentage); } else { totalFeeBasisPoints += (platformFeePercentage + list.paymentSettlement.commissionFeePercentage); } require( totalFeeBasisPoints < 10000, "The total fee basis point should be less than 10000" ); // checks for valuable token start and end id for listing if (list.nftStartTokenId > 0 && list.nftEndTokenId > 0) { require( list.nftEndTokenId >= list.nftStartTokenId, "This is not a valid NFT start or end token ID. Please verify that the range provided is correct" ); } // array for paymentCurrency and minimumPrice to be of same length require( list.paymentCurrency.length == list.minimumCryptoPrice.length, "should provide equal length in price and payment address" ); // checks to provide maxcap while listing only for minting if (list.transactionStatus == TransactionStatus.mint) { require(list.maxCap != 0, "should provide maxCap for minting"); require( list.nftStartTokenId == 0 && list.nftEndTokenId == 0, "The NFTstarttokenid and NFTendtokenid should be 0 for minting" ); } else { require( list.maxCap == 0, "maxCap should be 0 for preminted tokens" ); } // checks to provide only supported interface for nftContractAddress require( IERC165(list.nftContractAddress).supportsInterface( ERC721_INTERFACE_ID ) || IERC165(list.nftContractAddress).supportsInterface( ERC1155_INTERFACE_ID ), "should provide only supported contract interfaces ERC 721/1155" ); // checks for paymentSettlementAddress should not be zero require( list.paymentSettlement.paymentSettlementAddress != address(0), "should provide valid wallet address for settlement" ); // checks for taxSettlelentAddress should not be zero require( list.paymentSettlement.taxSettlementAddress != address(0), "should provide valid wallet address for tax settlement" ); if (!usedSaleId[saleId]) { listings[saleId] = list; usedSaleId[saleId] = true; emit saleCreated(list, "saleCreated"); } else if (usedSaleId[saleId]) { listings[saleId] = list; emit saleCreated(list, "saleUpdated"); } } /** * @notice End an sale, finalizing and paying out the respective parties. * @param list gives the listing details to buy the nfts * @param tax the amount of tax to be paid by the buyer */ function buy( BuyList memory list, uint256 tax, Discount calldata discount ) external payable nonReentrant returns (uint256[] memory nftTokenId) { settlementList memory settlement = listings[list.saleId] .paymentSettlement; PriceList memory saleList = listings[list.saleId]; // checks for saleId is created for sale require(usedSaleId[list.saleId], "unsupported sale"); // should be called by the contract admins or by the buyer require( isAdmin(msg.sender) || list.buyer == msg.sender, "Only the buyer or admin or owner of this contract can call this function" ); if (saleList.tokenGatingContract != address(0)) { require( ITokenGating(saleList.tokenGatingContract).acquireGating( list.gatedColletion, list.gatedTokenId, list.buyer ), "please provede the required gated collection and token details to buy the nft" ); } uint16 discountinBps; if (discount.discountPercentage > 0 || adminApprovalRequired ) { if(discount.discountPercentage > 0) { require( discount.discountPercentage < 10000, "The total fee basis point should be less than 10000" ); } require( isAdmin(discount.signer), "only owner or admin can sign for discount" ); require( !discountUsed[discount.signature], "signature already applied" ); require( _verifySignature( list.buyer, discount.discountPercentage, discount.expirationTime, discount.signer, discount.nonce, discount.signature ), "invalid discount signature" ); discountUsed[discount.signature] = true; discountinBps = discount.discountPercentage; } // handling the errors before buying the NFT (uint256 minimumPrice, address tokenContract) = errorHandling( list.saleId, list.tokenId, list.tokenQuantity, list.quantity, list.paymentToken, (list.paymentAmount + tax), list.buyer, discountinBps ); // Transferring the NFT tokens to the buyer nftTokenId = _tokenTransaction( list.saleId, list.tokenOwner, tokenContract, list.buyer, list.tokenId, list.tokenQuantity, list.quantity, saleList.transactionStatus ); // transferring the tax amount given by buyer as tax to taxSettlementAddress if (tax > 0) { _handlePayment( list.buyer, settlement.taxSettlementAddress, list.paymentToken, tax ); } paymentTransaction( list.saleId, list.paymentAmount, list.buyer, list.paymentToken, list.tokenId, tokenContract, saleList.transactionStatus ); emit BuyExecuted( tokenContract, list, nftTokenId, tax, minimumPrice, list.paymentAmount ); return nftTokenId; } /** * @notice payment settlement happens to all settlement address. * @param _saleId consist of the id of the listed sale * @param _totalAmount the totalAmount to be paid by the seller * @param _paymentToken the selected currency the payment is made * @param _transferredTokenId the tokenId of the transferred token * @param _tokenContract the nftcontract address of the supported sale * @param _status the transaction status for mint or transfer */ function paymentTransaction( string memory _saleId, uint256 _totalAmount, address _paymentFrom, address _paymentToken, uint256 _transferredTokenId, address _tokenContract, TransactionStatus _status ) private { settlementList memory settlement = listings[_saleId].paymentSettlement; uint256 totalCommession; // transferring the platformFee amount to the platformSettlementAddress if ( settlement.platformSettlementAddress != address(0) && settlement.platformFeePercentage > 0 ) { _handlePayment( _paymentFrom, settlement.platformSettlementAddress, _paymentToken, totalCommession += ((_totalAmount * settlement.platformFeePercentage) / 10000) ); } else if (platformAddress != address(0) && platformFeePercentage > 0) { _handlePayment( _paymentFrom, platformAddress, _paymentToken, totalCommession += ((_totalAmount * platformFeePercentage) / 10000) ); } // transferring the commissionfee amount to the commissionAddress if ( settlement.commissionAddress != address(0) && settlement.commissionFeePercentage > 0 ) { totalCommession += ((_totalAmount * settlement.commissionFeePercentage) / 10000); _handlePayment( _paymentFrom, settlement.commissionAddress, _paymentToken, ((_totalAmount * settlement.commissionFeePercentage) / 10000) ); } _totalAmount = _totalAmount - totalCommession; // Royalty Fee Payout Settlement if (royaltySupport != IRoyaltyEngine(address(0))) { _totalAmount = royaltyPayout( _paymentFrom, _transferredTokenId, _tokenContract, _totalAmount, _paymentToken, _status ); } // Transfer the balance to the paymentSettlementAddress _handlePayment( _paymentFrom, settlement.paymentSettlementAddress, _paymentToken, _totalAmount ); } /** * @notice handling the errors while buying the nfts. * @param _saleId the Id of the created sale * @param _tokenId the token Id of the owner owns * @param _tokenQuantity the token Quantity only required if minting * @param _quantity the quantity of tokens for 1155 only * @param _paymentToken the type of payment currency that the buyers pays * @param _paymentAmount the amount to be paid in the payment currency * @param _payee address of the buyer who buys the token */ function errorHandling( string memory _saleId, uint256 _tokenId, uint256 _tokenQuantity, uint256 _quantity, address _paymentToken, uint256 _paymentAmount, address _payee, uint16 _discountBps ) private view returns (uint256 _minimumPrice, address _tokenContract) { PriceList memory saleList = listings[_saleId]; // checks the nft to be buyed is supported in the saleId if (saleList.nftStartTokenId == 0 && saleList.nftEndTokenId > 0) { require( _tokenId <= saleList.nftEndTokenId, "This is not a valid tokenId. Please verify that the tokenId provided is correct" ); } else if ( saleList.nftStartTokenId > 0 && saleList.nftEndTokenId == 0 ) { require( _tokenId >= saleList.nftStartTokenId, "This is not a valid tokenId. Please verify that the tokenId provided is correct" ); } else if (saleList.nftStartTokenId > 0 && saleList.nftEndTokenId > 0) { require( _tokenId >= saleList.nftStartTokenId && _tokenId <= saleList.nftEndTokenId, "This is not a valid tokenId. Please verify that the tokenId provided is correct" ); } // getting the payment currency and the price using saleId _tokenContract = saleList.nftContractAddress; // getting the price using saleId if (saleList.paymentStatus == PaymentStatus.fiat) { _minimumPrice = priceFeedAddress.getLatestPrice( saleList.minimumFiatPrice, _paymentToken ); } else if (saleList.paymentStatus == PaymentStatus.crypto) { for (uint256 i; i < saleList.paymentCurrency.length; i++) { if (saleList.paymentCurrency[i] == _paymentToken) { _minimumPrice = saleList.minimumCryptoPrice[i]; break; } } } // check for the minimumPrice we get should not be zero require( _minimumPrice != 0, "Please provide valid supported ERC20/ETH address" ); if (_discountBps > 0) { _minimumPrice = _minimumPrice - ((_minimumPrice * _discountBps) / 10000); } if (saleList.transactionStatus == TransactionStatus.mint) { // checks for tokenQuantity for 1155 NFTs require( _quantity <= max1155Quantity, "The maximum quantity allowed to purchase at one time should not be more than defined in max1155Quantity" ); if ( IERC165(_tokenContract).supportsInterface(ERC721_INTERFACE_ID) ) { _minimumPrice = (_minimumPrice * _tokenQuantity); } else if ( IERC165(_tokenContract).supportsInterface(ERC1155_INTERFACE_ID) ) { if ( IERC1155CreatorCore(_tokenContract).totalSupply(_tokenId) == 0 ) { /* multiplying the total number of tokens and quantity with amount to get the total price for 1155 nfts ofr minting*/ _minimumPrice = (_minimumPrice * _tokenQuantity * _quantity); } else { /* multiplying the total number of tokens with amount to get the total price for 721 nfts for minting*/ _minimumPrice = (_minimumPrice * _quantity); } } } else if (saleList.transactionStatus == TransactionStatus.transfer) { _minimumPrice = (_minimumPrice * _quantity); } if (_paymentToken == address(0)) { require( msg.value == _paymentAmount && _paymentAmount >= _minimumPrice, "Insufficient funds or invalid amount. You need to pass a valid amount to complete this transaction" ); } else { // checks the buyer has sufficient amount to buy the nft require( IERC20(_paymentToken).balanceOf(_payee) >= _paymentAmount && _paymentAmount >= _minimumPrice, "Insufficient funds. You should have sufficient balance to complete this transaction" ); // checks the buyer has provided approval for the contract to transfer the amount require( IERC20(_paymentToken).allowance(_payee, address(this)) >= _paymentAmount, "Insufficient approval from an ERC20 Token. Please provide approval to this contract and try again" ); } } /** * @notice handling royaltyPayout while buying the nfts. * @param _buyer the address of the buyer * @param _tokenId the token Id of the nft * @param _tokenContract the address of the nft contract * @param _amount the amount to be paid in the payment currency * @param _paymentToken the type of payment currency that the buyers pays * @param _status the status of minting or transferring of nfts */ function royaltyPayout( address _buyer, uint256 _tokenId, address _tokenContract, uint256 _amount, address _paymentToken, TransactionStatus _status ) private returns (uint256 remainingProfit) { if (_status == TransactionStatus.transfer) { // royalty payout for already minted tokens remainingProfit = _handleRoyaltyEnginePayout( _buyer, _tokenContract, _tokenId, _amount, _paymentToken ); } } /// @notice The details to be provided to buy the token /// @param _saleId the Id of the created sale /// @param _tokenOwner the owner of the nft token /// @param _tokenContract the address of the nft contract /// @param _buyer the address of the buyer /// @param _tokenId the token Id to be buyed by the buyer /// @param _tokenQuantity the token Quantity only required if minting /// @param _quantity the quantity of tokens for 1155 only /// @param _status the status of minting or transferring of nfts function _tokenTransaction( string memory _saleId, address _tokenOwner, address _tokenContract, address _buyer, uint256 _tokenId, uint256 _tokenQuantity, uint256 _quantity, TransactionStatus _status ) private returns (uint256[] memory nftTokenId) { if (IERC165(_tokenContract).supportsInterface(ERC721_INTERFACE_ID)) { if (_status == TransactionStatus.transfer) { require( IERC721(_tokenContract).ownerOf(_tokenId) == _tokenOwner, "Invalid NFT Owner Address. Please check and try again" ); // Transferring the ERC721 IERC721(_tokenContract).safeTransferFrom( _tokenOwner, _buyer, _tokenId ); } else if (_status == TransactionStatus.mint) { require( tokensUsed[_saleId] + _tokenQuantity <= listings[_saleId].maxCap, "The maximum quantity allowed to purchase ERC721 token has been sold out. Please contact the sale owner for more details" ); // Minting the ERC721 in a batch nftTokenId = IERC721CreatorCore(_tokenContract) .mintExtensionBatch(_buyer, uint16(_tokenQuantity)); tokensUsed[_saleId] = tokensUsed[_saleId] + _tokenQuantity; } } else if ( IERC165(_tokenContract).supportsInterface(ERC1155_INTERFACE_ID) ) { if (_status == TransactionStatus.transfer) { uint256 ownerBalance = IERC1155(_tokenContract).balanceOf( _tokenOwner, _tokenId ); require( _quantity <= ownerBalance && _quantity > 0, "Insufficient token balance from the owner" ); // Transferring the ERC1155 IERC1155(_tokenContract).safeTransferFrom( _tokenOwner, _buyer, _tokenId, _quantity, "0x" ); } else if (_status == TransactionStatus.mint) { address[] memory to = new address[](1); uint256[] memory amounts = new uint256[](_tokenQuantity); string[] memory uris; to[0] = _buyer; amounts[0] = _quantity; if ( IERC1155CreatorCore(_tokenContract).totalSupply(_tokenId) == 0 ) { require( tokensUsed[_saleId] < listings[_saleId].maxCap, "The maximum quantity allowed to purchase ERC1155 token has been sold out. Please contact the sale owner for more details" ); for (uint256 i; i < _tokenQuantity; i++) { amounts[i] = _quantity; } // Minting ERC1155 of already existing tokens nftTokenId = IERC1155CreatorCore(_tokenContract) .mintExtensionNew(to, amounts, uris); tokensUsed[_saleId] = tokensUsed[_saleId] + _tokenQuantity; } else if ( IERC1155CreatorCore(_tokenContract).totalSupply(_tokenId) > 0 ) { uint256[] memory tokenId = new uint256[](1); tokenId[0] = _tokenId; // Minting new ERC1155 tokens IERC1155CreatorCore(_tokenContract).mintExtensionExisting( to, tokenId, amounts ); } } } return nftTokenId; } /// @notice Settle the Payment based on the given parameters /// @param _from Address from whom the amount to be transferred /// @param _to Address to whom need to settle the payment /// @param _paymentToken Address of the ERC20 Payment Token /// @param _amount Amount to be transferred function _handlePayment( address _from, address payable _to, address _paymentToken, uint256 _amount ) private { bool success; if (_paymentToken == address(0)) { // transferreng the native currency (success, ) = _to.call{value: _amount}(new bytes(0)); require(success, "unable to debit native balance please try again"); } else { // transferring ERC20 currency IERC20(_paymentToken).safeTransferFrom(_from, _to, _amount); } } /// @notice Settle the Royalty Payment based on the given parameters /// @param _buyer the address of the buyer /// @param _tokenContract The NFT Contract address /// @param _tokenId The NFT tokenId /// @param _amount Amount to be transferred /// @param _payoutCurrency Address of the ERC20 Payout function _handleRoyaltyEnginePayout( address _buyer, address _tokenContract, uint256 _tokenId, uint256 _amount, address _payoutCurrency ) private returns (uint256) { // Store the initial amount uint256 amountRemaining = _amount; uint256 feeAmount; // Verifying whether the token contract supports Royalties of supported interfaces ( address payable[] memory recipients, uint256[] memory bps // Royalty amount denominated in basis points ) = royaltySupport.getRoyalty(_tokenContract, _tokenId); // Store the number of recipients uint256 totalRecipients = recipients.length; // If there are no royalties, return the initial amount if (totalRecipients == 0) return _amount; // Payout each royalty for (uint256 i = 0; i < totalRecipients; ) { // Cache the recipient and amount address payable recipient = recipients[i]; feeAmount = (bps[i] * _amount) / 10000; // Ensure that we aren't somehow paying out more than we have require( amountRemaining >= feeAmount, "insolvent: unable to complete royalty" ); _handlePayment(_buyer, recipient, _payoutCurrency, feeAmount); emit RoyaltyPayout(_tokenContract, _tokenId, recipient, feeAmount); // Cannot underflow as remaining amount is ensured to be greater than or equal to royalty amount unchecked { amountRemaining -= feeAmount; ++i; } } return amountRemaining; } function _verifySignature( address buyer, uint16 discountPercentage, uint32 expirationTime, address _signer, string calldata nonce, bytes calldata _signature ) internal view returns (bool) { require( expirationTime >= block.timestamp, "discount signature is already expired" ); return keccak256( abi.encodePacked( buyer, discountPercentage, expirationTime, nonce, "ONCHAINBUY", block.chainid ) ).toEthSignedMessageHash().recover(_signature) == _signer; } /// @notice get the listings currency and price /// @param saleId to get the details of sale function getListingPrice( string calldata saleId ) external view returns ( uint256[] memory minimumCryptoPrice, address[] memory paymentCurrency ) { minimumCryptoPrice = listings[saleId].minimumCryptoPrice; paymentCurrency = listings[saleId].paymentCurrency; } /// @notice get contract state details function getContractData() external view returns ( address _platformAddress, uint16 _platformFeePercentage, IPriceFeed _priceFeedAddress, IRoyaltyEngine _royaltySupport, uint64 _max1155Quantity ) { _platformAddress = platformAddress; _platformFeePercentage = platformFeePercentage; _priceFeedAddress = priceFeedAddress; _royaltySupport = royaltySupport; _max1155Quantity = max1155Quantity; } /// @notice Withdraw the funds to owner function withdraw(address paymentCurrency) external adminRequired { bool success; address payable to = payable(msg.sender); if (paymentCurrency == address(0)) { (success, ) = to.call{value: address(this).balance}(new bytes(0)); require(success, "withdraw to withdraw funds. Please try again"); } else if (paymentCurrency != address(0)) { // transferring ERC20 currency uint256 amount = IERC20(paymentCurrency).balanceOf(address(this)); IERC20(paymentCurrency).safeTransfer(to, amount); } } /// @notice cancel the sale of a listed token /// @param saleId to cancel the sale function cancelSale(string memory saleId) external adminRequired { require( usedSaleId[saleId], "the saleId you have entered is invalid. Please validate" ); delete (listings[saleId]); emit saleClosed(saleId); } /// @notice set contract state details /// @param _platformAddress The Platform Address /// @param _platformFeePercentage The Platform fee percentage /// @param _max1155Quantity maxQuantity we support for 1155 NFTs /// @param _royaltyContract The contract intracts to get the royalty fee /// @param _pricefeed The contract intracts to get the chainlink feeded price function setContractData( address payable _platformAddress, uint16 _platformFeePercentage, uint64 _max1155Quantity, address _royaltyContract, address _pricefeed ) external adminRequired { platformAddress = _platformAddress; platformFeePercentage = _platformFeePercentage; max1155Quantity = _max1155Quantity; royaltySupport = IRoyaltyEngine(_royaltyContract); priceFeedAddress = IPriceFeed(_pricefeed); } /// @notice set Admin approval requirement /// @param approval addmin approval as a boolean function setAdminApproval(bool approval) external adminRequired { adminApprovalRequired = approval; } /// @notice get royalty payout details /// @param collectionAddress the nft contract address /// @param tokenId the nft token Id function getRoyaltyInfo( address collectionAddress, uint256 tokenId ) external view returns (address payable[] memory recipients, uint256[] memory bps) { ( recipients, bps // Royalty amount denominated in basis points ) = royaltySupport.getRoyalty(collectionAddress, tokenId); } receive() external payable {} fallback() external payable {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.0 (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } else if (error == RecoverError.InvalidSignatureV) { revert("ECDSA: invalid signature 'v' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { // Check the signature length // - case 65: r,s,v signature (standard) // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._ if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else if (signature.length == 64) { bytes32 r; bytes32 vs; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) vs := mload(add(signature, 0x40)) } return tryRecover(hash, r, vs); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s; uint8 v; assembly { s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) v := add(shr(255, vs), 27) } return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } if (v != 27 && v != 28) { return (address(0), RecoverError.InvalidSignatureV); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz import "./CreatorCore.sol"; /** * @dev Core ERC1155 creator interface */ interface IERC1155CreatorCore is ICreatorCore { /** * @dev mint a token with no extension. Can only be called by an admin. * * @param to - Can be a single element array (all tokens go to same address) or multi-element array (single token to many recipients) * @param amounts - Can be a single element array (all recipients get the same amount) or a multi-element array * @param uris - If no elements, all tokens use the default uri. * If any element is an empty string, the corresponding token uses the default uri. * * * Requirements: If to is a multi-element array, then uris must be empty or single element array * If to is a multi-element array, then amounts must be a single element array or a multi-element array of the same size * If to is a single element array, uris must be empty or the same length as amounts * * Examples: * mintBaseNew(['0x....1', '0x....2'], [1], []) * Mints a single new token, and gives 1 each to '0x....1' and '0x....2'. Token uses default uri. * * mintBaseNew(['0x....1', '0x....2'], [1, 2], []) * Mints a single new token, and gives 1 to '0x....1' and 2 to '0x....2'. Token uses default uri. * * mintBaseNew(['0x....1'], [1, 2], ["", "http://token2.com"]) * Mints two new tokens to '0x....1'. 1 of the first token, 2 of the second. 1st token uses default uri, second uses "http://token2.com". * * @return Returns list of tokenIds minted */ function mintBaseNew(address[] calldata to, uint256[] calldata amounts, string[] calldata uris) external returns (uint256[] memory); /** * @dev batch mint existing token with no extension. Can only be called by an admin. * * @param to - Can be a single element array (all tokens go to same address) or multi-element array (single token to many recipients) * @param tokenIds - Can be a single element array (all recipients get the same token) or a multi-element array * @param amounts - Can be a single element array (all recipients get the same amount) or a multi-element array * * Requirements: If any of the parameters are multi-element arrays, they need to be the same length as other multi-element arrays * * Examples: * mintBaseExisting(['0x....1', '0x....2'], [1], [10]) * Mints 10 of tokenId 1 to each of '0x....1' and '0x....2'. * * mintBaseExisting(['0x....1', '0x....2'], [1, 2], [10, 20]) * Mints 10 of tokenId 1 to '0x....1' and 20 of tokenId 2 to '0x....2'. * * mintBaseExisting(['0x....1'], [1, 2], [10, 20]) * Mints 10 of tokenId 1 and 20 of tokenId 2 to '0x....1'. * * mintBaseExisting(['0x....1', '0x....2'], [1], [10, 20]) * Mints 10 of tokenId 1 to '0x....1' and 20 of tokenId 1 to '0x....2'. * */ function mintBaseExisting(address[] calldata to, uint256[] calldata tokenIds, uint256[] calldata amounts) external; /** * @dev mint a token from an extension. Can only be called by a registered extension. * * @param to - Can be a single element array (all tokens go to same address) or multi-element array (single token to many recipients) * @param amounts - Can be a single element array (all recipients get the same amount) or a multi-element array * @param uris - If no elements, all tokens use the default uri. * If any element is an empty string, the corresponding token uses the default uri. * * * Requirements: If to is a multi-element array, then uris must be empty or single element array * If to is a multi-element array, then amounts must be a single element array or a multi-element array of the same size * If to is a single element array, uris must be empty or the same length as amounts * * Examples: * mintExtensionNew(['0x....1', '0x....2'], [1], []) * Mints a single new token, and gives 1 each to '0x....1' and '0x....2'. Token uses default uri. * * mintExtensionNew(['0x....1', '0x....2'], [1, 2], []) * Mints a single new token, and gives 1 to '0x....1' and 2 to '0x....2'. Token uses default uri. * * mintExtensionNew(['0x....1'], [1, 2], ["", "http://token2.com"]) * Mints two new tokens to '0x....1'. 1 of the first token, 2 of the second. 1st token uses default uri, second uses "http://token2.com". * * @return Returns list of tokenIds minted */ function mintExtensionNew(address[] calldata to, uint256[] calldata amounts, string[] calldata uris) external returns (uint256[] memory); /** * @dev batch mint existing token from extension. Can only be called by a registered extension. * * @param to - Can be a single element array (all tokens go to same address) or multi-element array (single token to many recipients) * @param tokenIds - Can be a single element array (all recipients get the same token) or a multi-element array * @param amounts - Can be a single element array (all recipients get the same amount) or a multi-element array * * Requirements: If any of the parameters are multi-element arrays, they need to be the same length as other multi-element arrays * * Examples: * mintExtensionExisting(['0x....1', '0x....2'], [1], [10]) * Mints 10 of tokenId 1 to each of '0x....1' and '0x....2'. * * mintExtensionExisting(['0x....1', '0x....2'], [1, 2], [10, 20]) * Mints 10 of tokenId 1 to '0x....1' and 20 of tokenId 2 to '0x....2'. * * mintExtensionExisting(['0x....1'], [1, 2], [10, 20]) * Mints 10 of tokenId 1 and 20 of tokenId 2 to '0x....1'. * * mintExtensionExisting(['0x....1', '0x....2'], [1], [10, 20]) * Mints 10 of tokenId 1 to '0x....1' and 20 of tokenId 1 to '0x....2'. * */ function mintExtensionExisting(address[] calldata to, uint256[] calldata tokenIds, uint256[] calldata amounts) external; /** * @dev burn tokens. Can only be called by token owner or approved address. * On burn, calls back to the registered extension's onBurn method */ function burn(address account, uint256[] calldata tokenIds, uint256[] calldata amounts) external; /** * @dev Total amount of tokens in with a given tokenId. */ function totalSupply(uint256 tokenId) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz import "./ICreatorCore.sol"; /** * @dev Core ERC721 creator interface */ interface IERC721CreatorCore is ICreatorCore { /** * @dev mint a token with no extension. Can only be called by an admin. * Returns tokenId minted */ function mintBase(address to) external returns (uint256); /** * @dev mint a token with no extension. Can only be called by an admin. * Returns tokenId minted */ function mintBase(address to, string calldata uri) external returns (uint256); /** * @dev batch mint a token with no extension. Can only be called by an admin. * Returns tokenId minted */ function mintBaseBatch(address to, uint16 count) external returns (uint256[] memory); /** * @dev batch mint a token with no extension. Can only be called by an admin. * Returns tokenId minted */ function mintBaseBatch(address to, string[] calldata uris) external returns (uint256[] memory); /** * @dev mint a token. Can only be called by a registered extension. * Returns tokenId minted */ function mintExtension(address to) external returns (uint256); /** * @dev mint a token. Can only be called by a registered extension. * Returns tokenId minted */ function mintExtension(address to, string calldata uri) external returns (uint256); /** * @dev batch mint a token. Can only be called by a registered extension. * Returns tokenIds minted */ function mintExtensionBatch(address to, uint16 count) external returns (uint256[] memory); /** * @dev batch mint a token. Can only be called by a registered extension. * Returns tokenId minted */ function mintExtensionBatch(address to, string[] calldata uris) external returns (uint256[] memory); /** * @dev burn a token. Can only be called by token owner or approved address. * On burn, calls back to the registered extension's onBurn method */ function burn(uint256 tokenId) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz import "../../../openzeppelin/utils/introspection/ERC165.sol"; import "../../../openzeppelin/utils/structs/EnumerableSet.sol"; import "../../../openzeppelin/access/Ownable.sol"; import "./IAdminControl.sol"; abstract contract AdminControl is Ownable, IAdminControl, ERC165 { using EnumerableSet for EnumerableSet.AddressSet; // Track registered admins EnumerableSet.AddressSet private _admins; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IAdminControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Only allows approved admins to call the specified function */ modifier adminRequired() { require( owner() == msg.sender || _admins.contains(msg.sender), "AdminControl: Must be owner or admin" ); _; } /** * @dev See {IAdminControl-getAdmins}. */ function getAdmins() external view override returns (address[] memory admins) { admins = new address[](_admins.length()); for (uint256 i = 0; i < _admins.length(); i++) { admins[i] = _admins.at(i); } return admins; } /** * @dev See {IAdminControl-approveAdmin}. */ function approveAdmin(address admin) external override onlyOwner { if (!_admins.contains(admin)) { emit AdminApproved(admin, msg.sender); _admins.add(admin); } } /** * @dev See {IAdminControl-revokeAdmin}. */ function revokeAdmin(address admin) external override onlyOwner { if (_admins.contains(admin)) { emit AdminRevoked(admin, msg.sender); _admins.remove(admin); } } /** * @dev See {IAdminControl-isAdmin}. */ function isAdmin(address admin) public view override returns (bool) { return (owner() == admin || _admins.contains(admin)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.0 (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../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; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @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, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.0 (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) 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 `amount` 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 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @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); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; /// @custom:oz-upgrades-unsafe-allow constructor constructor () { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.0 (token/ERC1155/IERC1155.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[EIP]. * * _Available since v3.1._ */ interface IERC1155 is IERC165 { /** * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the amount of tokens of token type `id` owned by `account`. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the caller. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.0 (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, 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 be 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: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * 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 Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns 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); /** * @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; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.0 (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.0 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.0 (utils/Address.sol) pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // 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 assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz import "../../../openzeppelin/utils/introspection/IERC165.sol"; /** * @dev Interface for admin control */ interface IAdminControl is IERC165 { event AdminApproved(address indexed account, address indexed sender); event AdminRevoked(address indexed account, address indexed sender); /** * @dev gets address of all admins */ function getAdmins() external view returns (address[] memory); /** * @dev add an admin. Can only be called by contract owner. */ function approveAdmin(address admin) external; /** * @dev remove an admin. Can only be called by contract owner. */ function revokeAdmin(address admin) external; /** * @dev checks whether or not given address is an admin * Returns True if they are */ function isAdmin(address admin) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.0 (utils/structs/EnumerableSet.sol) pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { return _values(set._inner); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.0 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz import "../../../openzeppelin/utils/introspection/IERC165.sol"; /** * @dev Core creator interface */ interface ICreatorCore is IERC165 { event ExtensionRegistered( address indexed extension, address indexed sender ); event ExtensionUnregistered( address indexed extension, address indexed sender ); event ExtensionBlacklisted( address indexed extension, address indexed sender ); event MintPermissionsUpdated( address indexed extension, address indexed permissions, address indexed sender ); event RoyaltiesUpdated( uint256 indexed tokenId, address payable[] receivers, uint256[] basisPoints ); event DefaultRoyaltiesUpdated( address payable[] receivers, uint256[] basisPoints ); event ExtensionRoyaltiesUpdated( address indexed extension, address payable[] receivers, uint256[] basisPoints ); event ExtensionApproveTransferUpdated( address indexed extension, bool enabled ); /** * @dev gets address of all extensions */ function getExtensions() external view returns (address[] memory); /** * @dev add an extension. Can only be called by contract owner or admin. * extension address must point to a contract implementing ICreatorExtension. * Returns True if newly added, False if already added. */ function registerExtension(address extension, string calldata baseURI) external; /** * @dev add an extension. Can only be called by contract owner or admin. * extension address must point to a contract implementing ICreatorExtension. * Returns True if newly added, False if already added. */ function registerExtension( address extension, string calldata baseURI, bool baseURIIdentical ) external; /** * @dev add an extension. Can only be called by contract owner or admin. * Returns True if removed, False if already removed. */ function unregisterExtension(address extension) external; /** * @dev blacklist an extension. Can only be called by contract owner or admin. * This function will destroy all ability to reference the metadata of any tokens created * by the specified extension. It will also unregister the extension if needed. * Returns True if removed, False if already removed. */ function blacklistExtension(address extension) external; /** * @dev set the baseTokenURI of an extension. Can only be called by extension. */ function setBaseTokenURIExtension(string calldata uri) external; /** * @dev set the baseTokenURI of an extension. Can only be called by extension. * For tokens with no uri configured, tokenURI will return "uri+tokenId" */ function setBaseTokenURIExtension(string calldata uri, bool identical) external; /** * @dev set the common prefix of an extension. Can only be called by extension. * If configured, and a token has a uri set, tokenURI will return "prefixURI+tokenURI" * Useful if you want to use ipfs/arweave */ function setTokenURIPrefixExtension(string calldata prefix) external; /** * @dev set the tokenURI of a token extension. Can only be called by extension that minted token. */ function setTokenURIExtension(uint256 tokenId, string calldata uri) external; /** * @dev set the tokenURI of a token extension for multiple tokens. Can only be called by extension that minted token. */ function setTokenURIExtension( uint256[] memory tokenId, string[] calldata uri ) external; /** * @dev set the baseTokenURI for tokens with no extension. Can only be called by owner/admin. * For tokens with no uri configured, tokenURI will return "uri+tokenId" */ function setBaseTokenURI(string calldata uri) external; /** * @dev set the common prefix for tokens with no extension. Can only be called by owner/admin. * If configured, and a token has a uri set, tokenURI will return "prefixURI+tokenURI" * Useful if you want to use ipfs/arweave */ function setTokenURIPrefix(string calldata prefix) external; /** * @dev set the tokenURI of a token with no extension. Can only be called by owner/admin. */ function setTokenURI(uint256 tokenId, string calldata uri) external; /** * @dev set the tokenURI of multiple tokens with no extension. Can only be called by owner/admin. */ function setTokenURI(uint256[] memory tokenIds, string[] calldata uris) external; /** * @dev set a permissions contract for an extension. Used to control minting. */ function setMintPermissions(address extension, address permissions) external; /** * @dev Configure so transfers of tokens created by the caller (must be extension) gets approval * from the extension before transferring */ function setApproveTransferExtension(bool enabled) external; /** * @dev get the extension of a given token */ function tokenExtension(uint256 tokenId) external view returns (address); /** * @dev Set default royalties */ function setRoyalties( address payable[] calldata receivers, uint256[] calldata basisPoints ) external; /** * @dev Set royalties of a token */ function setRoyalties( uint256 tokenId, address payable[] calldata receivers, uint256[] calldata basisPoints ) external; /** * @dev Set royalties of an extension */ function setRoyaltiesExtension( address extension, address payable[] calldata receivers, uint256[] calldata basisPoints ) external; /** * @dev Get royalites of a token. Returns list of receivers and basisPoints */ function getRoyalties(uint256 tokenId) external view returns (address payable[] memory, uint256[] memory); // Royalty support for various other standards function getFeeRecipients(uint256 tokenId) external view returns (address payable[] memory); function getFeeBps(uint256 tokenId) external view returns (uint256[] memory); function getFees(uint256 tokenId) external view returns (address payable[] memory, uint256[] memory); function royaltyInfo(uint256 tokenId, uint256 value) external view returns (address, uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz import "../../../openzeppelin/security/ReentrancyGuard.sol"; import "../../../openzeppelin/utils/Strings.sol"; import "../../../openzeppelin/utils/introspection/ERC165.sol"; import "../../../openzeppelin/utils/introspection/ERC165Checker.sol"; import "../../../openzeppelin/utils/structs/EnumerableSet.sol"; import "../../../openzeppelin-upgradeable/utils/AddressUpgradeable.sol"; import "../extensions/ICreatorExtensionTokenURI.sol"; import "./ICreatorCore.sol"; /** * @dev Core creator implementation */ abstract contract CreatorCore is ReentrancyGuard, ICreatorCore, ERC165 { using Strings for uint256; using EnumerableSet for EnumerableSet.AddressSet; using AddressUpgradeable for address; /// @custom:oz-upgrades-unsafe-allow state-variable-assignment uint256 _tokenCount = 0; // Track registered extensions data EnumerableSet.AddressSet internal _extensions; EnumerableSet.AddressSet internal _blacklistedExtensions; mapping(address => address) internal _extensionPermissions; mapping(address => bool) internal _extensionApproveTransfers; // For tracking which extension a token was minted by mapping(uint256 => address) internal _tokensExtension; // The baseURI for a given extension mapping(address => string) private _extensionBaseURI; mapping(address => bool) private _extensionBaseURIIdentical; // The prefix for any tokens with a uri configured mapping(address => string) private _extensionURIPrefix; // Mapping for individual token URIs mapping(uint256 => string) internal _tokenURIs; // Royalty configurations mapping(address => address payable[]) internal _extensionRoyaltyReceivers; mapping(address => uint256[]) internal _extensionRoyaltyBPS; mapping(uint256 => address payable[]) internal _tokenRoyaltyReceivers; mapping(uint256 => uint256[]) internal _tokenRoyaltyBPS; /** * External interface identifiers for royalties */ /** * @dev CreatorCore * * bytes4(keccak256('getRoyalties(uint256)')) == 0xbb3bafd6 * * => 0xbb3bafd6 = 0xbb3bafd6 */ bytes4 private constant _INTERFACE_ID_ROYALTIES_CREATORCORE = 0xbb3bafd6; /** * @dev Rarible: RoyaltiesV1 * * bytes4(keccak256('getFeeRecipients(uint256)')) == 0xb9c4d9fb * bytes4(keccak256('getFeeBps(uint256)')) == 0x0ebd4c7f * * => 0xb9c4d9fb ^ 0x0ebd4c7f = 0xb7799584 */ bytes4 private constant _INTERFACE_ID_ROYALTIES_RARIBLE = 0xb7799584; /** * @dev Foundation * * bytes4(keccak256('getFees(uint256)')) == 0xd5a06d4c * * => 0xd5a06d4c = 0xd5a06d4c */ bytes4 private constant _INTERFACE_ID_ROYALTIES_FOUNDATION = 0xd5a06d4c; /** * @dev EIP-2981 * * bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a * * => 0x2a55205a = 0x2a55205a */ bytes4 private constant _INTERFACE_ID_ROYALTIES_EIP2981 = 0x2a55205a; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(ICreatorCore).interfaceId || super.supportsInterface(interfaceId) || interfaceId == _INTERFACE_ID_ROYALTIES_CREATORCORE || interfaceId == _INTERFACE_ID_ROYALTIES_RARIBLE || interfaceId == _INTERFACE_ID_ROYALTIES_FOUNDATION || interfaceId == _INTERFACE_ID_ROYALTIES_EIP2981; } /** * @dev Only allows registered extensions to call the specified function */ modifier extensionRequired() { require( _extensions.contains(msg.sender), "Must be registered extension" ); _; } /** * @dev Only allows non-blacklisted extensions */ modifier nonBlacklistRequired(address extension) { require( !_blacklistedExtensions.contains(extension), "Extension blacklisted" ); _; } /** * @dev See {ICreatorCore-getExtensions}. */ function getExtensions() external view override returns (address[] memory extensions) { extensions = new address[](_extensions.length()); for (uint256 i = 0; i < _extensions.length(); i++) { extensions[i] = _extensions.at(i); } return extensions; } /** * @dev Register an extension */ function _registerExtension( address extension, string calldata baseURI, bool baseURIIdentical ) internal { require(extension != address(this), "Creator: Invalid"); require( extension.isContract(), "Creator: Extension must be a contract" ); if (!_extensions.contains(extension)) { _extensionBaseURI[extension] = baseURI; _extensionBaseURIIdentical[extension] = baseURIIdentical; emit ExtensionRegistered(extension, msg.sender); _extensions.add(extension); } } /** * @dev Unregister an extension */ function _unregisterExtension(address extension) internal { if (_extensions.contains(extension)) { emit ExtensionUnregistered(extension, msg.sender); _extensions.remove(extension); } } /** * @dev Blacklist an extension */ function _blacklistExtension(address extension) internal { require(extension != address(this), "Cannot blacklist yourself"); if (_extensions.contains(extension)) { emit ExtensionUnregistered(extension, msg.sender); _extensions.remove(extension); } if (!_blacklistedExtensions.contains(extension)) { emit ExtensionBlacklisted(extension, msg.sender); _blacklistedExtensions.add(extension); } } /** * @dev Set base token uri for an extension */ function _setBaseTokenURIExtension(string calldata uri, bool identical) internal { _extensionBaseURI[msg.sender] = uri; _extensionBaseURIIdentical[msg.sender] = identical; } /** * @dev Set token uri prefix for an extension */ function _setTokenURIPrefixExtension(string calldata prefix) internal { _extensionURIPrefix[msg.sender] = prefix; } /** * @dev Set token uri for a token of an extension */ function _setTokenURIExtension(uint256 tokenId, string calldata uri) internal { require(_tokensExtension[tokenId] == msg.sender, "Invalid token"); _tokenURIs[tokenId] = uri; } /** * @dev Set base token uri for tokens with no extension */ function _setBaseTokenURI(string memory uri) internal { _extensionBaseURI[address(this)] = uri; } /** * @dev Set token uri prefix for tokens with no extension */ function _setTokenURIPrefix(string calldata prefix) internal { _extensionURIPrefix[address(this)] = prefix; } /** * @dev Set token uri for a token with no extension */ function _setTokenURI(uint256 tokenId, string calldata uri) internal { require(_tokensExtension[tokenId] == address(this), "Invalid token"); _tokenURIs[tokenId] = uri; } /** * @dev Retrieve a token's URI */ function _tokenURI(uint256 tokenId) internal view returns (string memory) { address extension = _tokensExtension[tokenId]; require( !_blacklistedExtensions.contains(extension), "Extension blacklisted" ); if (bytes(_tokenURIs[tokenId]).length != 0) { if (bytes(_extensionURIPrefix[extension]).length != 0) { return string( abi.encodePacked( _extensionURIPrefix[extension], _tokenURIs[tokenId] ) ); } return _tokenURIs[tokenId]; } if ( ERC165Checker.supportsInterface( extension, type(ICreatorExtensionTokenURI).interfaceId ) ) { return ICreatorExtensionTokenURI(extension).tokenURI( address(this), tokenId ); } if (bytes(_extensionBaseURI[extension]).length != 0) { if (!_extensionBaseURIIdentical[extension]) { return string( abi.encodePacked( _extensionBaseURI[extension], tokenId.toString() ) ); } else { return _extensionBaseURI[extension]; } } else { if (!_extensionBaseURIIdentical[address(this)]) { return string( abi.encodePacked( _extensionBaseURI[address(this)], tokenId.toString() ) ); }else{ return _extensionBaseURI[address(this)]; } } } /** * Get token extension */ function _tokenExtension(uint256 tokenId) internal view returns (address extension) { extension = _tokensExtension[tokenId]; require(extension != address(this), "No extension for token"); require( !_blacklistedExtensions.contains(extension), "Extension blacklisted" ); return extension; } /** * Helper to get royalties for a token */ function _getRoyalties(uint256 tokenId) internal view returns (address payable[] storage, uint256[] storage) { return (_getRoyaltyReceivers(tokenId), _getRoyaltyBPS(tokenId)); } /** * Helper to get royalty receivers for a token */ function _getRoyaltyReceivers(uint256 tokenId) internal view returns (address payable[] storage) { if (_tokenRoyaltyReceivers[tokenId].length > 0) { return _tokenRoyaltyReceivers[tokenId]; } else if ( _extensionRoyaltyReceivers[_tokensExtension[tokenId]].length > 0 ) { return _extensionRoyaltyReceivers[_tokensExtension[tokenId]]; } return _extensionRoyaltyReceivers[address(this)]; } /** * Helper to get royalty basis points for a token */ function _getRoyaltyBPS(uint256 tokenId) internal view returns (uint256[] storage) { if (_tokenRoyaltyBPS[tokenId].length > 0) { return _tokenRoyaltyBPS[tokenId]; } else if (_extensionRoyaltyBPS[_tokensExtension[tokenId]].length > 0) { return _extensionRoyaltyBPS[_tokensExtension[tokenId]]; } return _extensionRoyaltyBPS[address(this)]; } function _getRoyaltyInfo(uint256 tokenId, uint256 value) internal view returns (address receiver, uint256 amount) { address payable[] storage receivers = _getRoyaltyReceivers(tokenId); require(receivers.length <= 1, "More than 1 royalty receiver"); if (receivers.length == 0) { return (address(this), 0); } return (receivers[0], (_getRoyaltyBPS(tokenId)[0] * value) / 10000); } /** * Set royalties for a token */ function _setRoyalties( uint256 tokenId, address payable[] calldata receivers, uint256[] calldata basisPoints ) internal { require(receivers.length == basisPoints.length, "Invalid input"); uint256 totalBasisPoints; for (uint256 i = 0; i < basisPoints.length; i++) { totalBasisPoints += basisPoints[i]; } require(totalBasisPoints < 10000, "Invalid total royalties"); _tokenRoyaltyReceivers[tokenId] = receivers; _tokenRoyaltyBPS[tokenId] = basisPoints; emit RoyaltiesUpdated(tokenId, receivers, basisPoints); } /** * Set royalties for all tokens of an extension */ function _setRoyaltiesExtension( address extension, address payable[] calldata receivers, uint256[] calldata basisPoints ) internal { require(receivers.length == basisPoints.length, "Invalid input"); uint256 totalBasisPoints; for (uint256 i = 0; i < basisPoints.length; i++) { totalBasisPoints += basisPoints[i]; } require(totalBasisPoints < 10000, "Invalid total royalties"); _extensionRoyaltyReceivers[extension] = receivers; _extensionRoyaltyBPS[extension] = basisPoints; if (extension == address(this)) { emit DefaultRoyaltiesUpdated(receivers, basisPoints); } else { emit ExtensionRoyaltiesUpdated(extension, receivers, basisPoints); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.0 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @author: manifold.xyz import "../../../openzeppelin/utils/introspection/IERC165.sol"; /** * @dev Implement this if you want your extension to have overloadable URI's */ interface ICreatorExtensionTokenURI is IERC165 { /** * Get the uri for a given creator/tokenId */ function tokenURI(address creator, uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.0 (utils/Address.sol) pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // 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 assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.0 (utils/introspection/ERC165Checker.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Library used to query support of an interface declared via {IERC165}. * * Note that these functions return the actual result of the query: they do not * `revert` if an interface is not supported. It is up to the caller to decide * what to do in these cases. */ library ERC165Checker { // As per the EIP-165 spec, no interface should ever match 0xffffffff bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff; /** * @dev Returns true if `account` supports the {IERC165} interface, */ function supportsERC165(address account) internal view returns (bool) { // Any contract that implements ERC165 must explicitly indicate support of // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid return _supportsERC165Interface(account, type(IERC165).interfaceId) && !_supportsERC165Interface(account, _INTERFACE_ID_INVALID); } /** * @dev Returns true if `account` supports the interface defined by * `interfaceId`. Support for {IERC165} itself is queried automatically. * * See {IERC165-supportsInterface}. */ function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { // query support of both ERC165 as per the spec and support of _interfaceId return supportsERC165(account) && _supportsERC165Interface(account, interfaceId); } /** * @dev Returns a boolean array where each value corresponds to the * interfaces passed in and whether they're supported or not. This allows * you to batch check interfaces for a contract where your expectation * is that some interfaces may not be supported. * * See {IERC165-supportsInterface}. * * _Available since v3.4._ */ function getSupportedInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool[] memory) { // an array of booleans corresponding to interfaceIds and whether they're supported or not bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length); // query support of ERC165 itself if (supportsERC165(account)) { // query support of each interface in interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]); } } return interfaceIdsSupported; } /** * @dev Returns true if `account` supports all the interfaces defined in * `interfaceIds`. Support for {IERC165} itself is queried automatically. * * Batch-querying can lead to gas savings by skipping repeated checks for * {IERC165} support. * * See {IERC165-supportsInterface}. */ function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { // query support of ERC165 itself if (!supportsERC165(account)) { return false; } // query support of each interface in _interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { if (!_supportsERC165Interface(account, interfaceIds[i])) { return false; } } // all interfaces supported return true; } /** * @notice Query if a contract implements an interface, does not check ERC165 support * @param account The address of the contract to query for support of an interface * @param interfaceId The interface identifier, as specified in ERC-165 * @return true if the contract at account indicates support of the interface with * identifier interfaceId, false otherwise * @dev Assumes that account contains a contract that supports ERC165, otherwise * the behavior of this method is undefined. This precondition can be checked * with {supportsERC165}. * Interface identification is specified in ERC-165. */ function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) { bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId); (bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams); if (result.length < 32) return false; return success && abi.decode(result, (bool)); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_platformAddress","type":"address"},{"internalType":"uint16","name":"_platformFeePercentage","type":"uint16"},{"internalType":"uint64","name":"_max1155Quantity","type":"uint64"},{"internalType":"contract IPriceFeed","name":"_priceFeedAddress","type":"address"},{"internalType":"contract IRoyaltyEngine","name":"_royaltycontract","type":"address"},{"internalType":"bool","name":"_adminApprovalRequired","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"AdminApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"AdminRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenContract","type":"address"},{"components":[{"internalType":"string","name":"saleId","type":"string"},{"internalType":"address","name":"tokenOwner","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint64","name":"tokenQuantity","type":"uint64"},{"internalType":"uint64","name":"quantity","type":"uint64"},{"internalType":"address","name":"buyer","type":"address"},{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"paymentAmount","type":"uint256"},{"internalType":"address","name":"gatedColletion","type":"address"},{"internalType":"uint256","name":"gatedTokenId","type":"uint256"}],"indexed":false,"internalType":"struct OnchainBuy.BuyList","name":"buyingDetails","type":"tuple"},{"indexed":false,"internalType":"uint256[]","name":"MintedtokenId","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"tax","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paymentAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalAmount","type":"uint256"}],"name":"BuyExecuted","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":"tokenContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RoyaltyPayout","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"saleId","type":"string"}],"name":"saleClosed","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint64","name":"nftStartTokenId","type":"uint64"},{"internalType":"uint64","name":"nftEndTokenId","type":"uint64"},{"internalType":"uint64","name":"maxCap","type":"uint64"},{"internalType":"address","name":"nftContractAddress","type":"address"},{"internalType":"uint256","name":"minimumFiatPrice","type":"uint256"},{"internalType":"uint256[]","name":"minimumCryptoPrice","type":"uint256[]"},{"internalType":"address[]","name":"paymentCurrency","type":"address[]"},{"components":[{"internalType":"address payable","name":"paymentSettlementAddress","type":"address"},{"internalType":"address payable","name":"taxSettlementAddress","type":"address"},{"internalType":"address payable","name":"commissionAddress","type":"address"},{"internalType":"address payable","name":"platformSettlementAddress","type":"address"},{"internalType":"uint16","name":"commissionFeePercentage","type":"uint16"},{"internalType":"uint16","name":"platformFeePercentage","type":"uint16"}],"internalType":"struct OnchainBuy.settlementList","name":"paymentSettlement","type":"tuple"},{"internalType":"enum OnchainBuy.TransactionStatus","name":"transactionStatus","type":"uint8"},{"internalType":"enum OnchainBuy.PaymentStatus","name":"paymentStatus","type":"uint8"},{"internalType":"address","name":"tokenGatingContract","type":"address"}],"indexed":false,"internalType":"struct OnchainBuy.PriceList","name":"saleList","type":"tuple"},{"indexed":false,"internalType":"string","name":"CreatedOrUpdated","type":"string"}],"name":"saleCreated","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"approveAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"saleId","type":"string"},{"internalType":"address","name":"tokenOwner","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint64","name":"tokenQuantity","type":"uint64"},{"internalType":"uint64","name":"quantity","type":"uint64"},{"internalType":"address","name":"buyer","type":"address"},{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"paymentAmount","type":"uint256"},{"internalType":"address","name":"gatedColletion","type":"address"},{"internalType":"uint256","name":"gatedTokenId","type":"uint256"}],"internalType":"struct OnchainBuy.BuyList","name":"list","type":"tuple"},{"internalType":"uint256","name":"tax","type":"uint256"},{"components":[{"internalType":"uint16","name":"discountPercentage","type":"uint16"},{"internalType":"uint32","name":"expirationTime","type":"uint32"},{"internalType":"string","name":"nonce","type":"string"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"signer","type":"address"}],"internalType":"struct OnchainBuy.Discount","name":"discount","type":"tuple"}],"name":"buy","outputs":[{"internalType":"uint256[]","name":"nftTokenId","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"saleId","type":"string"}],"name":"cancelSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"nftStartTokenId","type":"uint64"},{"internalType":"uint64","name":"nftEndTokenId","type":"uint64"},{"internalType":"uint64","name":"maxCap","type":"uint64"},{"internalType":"address","name":"nftContractAddress","type":"address"},{"internalType":"uint256","name":"minimumFiatPrice","type":"uint256"},{"internalType":"uint256[]","name":"minimumCryptoPrice","type":"uint256[]"},{"internalType":"address[]","name":"paymentCurrency","type":"address[]"},{"components":[{"internalType":"address payable","name":"paymentSettlementAddress","type":"address"},{"internalType":"address payable","name":"taxSettlementAddress","type":"address"},{"internalType":"address payable","name":"commissionAddress","type":"address"},{"internalType":"address payable","name":"platformSettlementAddress","type":"address"},{"internalType":"uint16","name":"commissionFeePercentage","type":"uint16"},{"internalType":"uint16","name":"platformFeePercentage","type":"uint16"}],"internalType":"struct OnchainBuy.settlementList","name":"paymentSettlement","type":"tuple"},{"internalType":"enum OnchainBuy.TransactionStatus","name":"transactionStatus","type":"uint8"},{"internalType":"enum OnchainBuy.PaymentStatus","name":"paymentStatus","type":"uint8"},{"internalType":"address","name":"tokenGatingContract","type":"address"}],"internalType":"struct OnchainBuy.PriceList","name":"list","type":"tuple"},{"internalType":"string","name":"saleId","type":"string"}],"name":"createOrUpdateSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"discountUsed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAdmins","outputs":[{"internalType":"address[]","name":"admins","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractData","outputs":[{"internalType":"address","name":"_platformAddress","type":"address"},{"internalType":"uint16","name":"_platformFeePercentage","type":"uint16"},{"internalType":"contract IPriceFeed","name":"_priceFeedAddress","type":"address"},{"internalType":"contract IRoyaltyEngine","name":"_royaltySupport","type":"address"},{"internalType":"uint64","name":"_max1155Quantity","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"saleId","type":"string"}],"name":"getListingPrice","outputs":[{"internalType":"uint256[]","name":"minimumCryptoPrice","type":"uint256[]"},{"internalType":"address[]","name":"paymentCurrency","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collectionAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getRoyaltyInfo","outputs":[{"internalType":"address payable[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"bps","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"listings","outputs":[{"internalType":"uint64","name":"nftStartTokenId","type":"uint64"},{"internalType":"uint64","name":"nftEndTokenId","type":"uint64"},{"internalType":"uint64","name":"maxCap","type":"uint64"},{"internalType":"address","name":"nftContractAddress","type":"address"},{"internalType":"uint256","name":"minimumFiatPrice","type":"uint256"},{"components":[{"internalType":"address payable","name":"paymentSettlementAddress","type":"address"},{"internalType":"address payable","name":"taxSettlementAddress","type":"address"},{"internalType":"address payable","name":"commissionAddress","type":"address"},{"internalType":"address payable","name":"platformSettlementAddress","type":"address"},{"internalType":"uint16","name":"commissionFeePercentage","type":"uint16"},{"internalType":"uint16","name":"platformFeePercentage","type":"uint16"}],"internalType":"struct OnchainBuy.settlementList","name":"paymentSettlement","type":"tuple"},{"internalType":"enum OnchainBuy.TransactionStatus","name":"transactionStatus","type":"uint8"},{"internalType":"enum OnchainBuy.PaymentStatus","name":"paymentStatus","type":"uint8"},{"internalType":"address","name":"tokenGatingContract","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"revokeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"approval","type":"bool"}],"name":"setAdminApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_platformAddress","type":"address"},{"internalType":"uint16","name":"_platformFeePercentage","type":"uint16"},{"internalType":"uint64","name":"_max1155Quantity","type":"uint64"},{"internalType":"address","name":"_royaltyContract","type":"address"},{"internalType":"address","name":"_pricefeed","type":"address"}],"name":"setContractData","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":[{"internalType":"string","name":"","type":"string"}],"name":"tokensUsed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"paymentCurrency","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60806040523480156200001157600080fd5b5060405162005dcb38038062005dcb8339810160408190526200003491620001f8565b6001600081815581546001600160a01b031916339081179092556040518291907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506001600160a01b038616620000d65760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420506c6174666f726d2041646472657373000000000000000060448201526064015b60405180910390fd5b6127108561ffff16106200013b5760405162461bcd60e51b815260206004820152602560248201527f706c6174666f726d4665652073686f756c64206265206c657373207468616e20604482015264031303030360dc1b6064820152608401620000cd565b60048054600580546001600160a01b039687166001600160a01b0319918216179091556006805495871695909116949094179093559015156a01000000000000000000000260ff60501b196001600160401b0390951662010000026001600160501b0319949097166b01000000000000000000000002939093167fff0000000000000000000000000000000000000000ff000000000000000000009092169190911761ffff909416939093179390931716919091179055620002ba565b60008060008060008060c087890312156200021257600080fd5b86516200021f81620002a1565b602088015190965061ffff811681146200023857600080fd5b60408801519095506001600160401b03811681146200025657600080fd5b60608801519094506200026981620002a1565b60808801519093506200027c81620002a1565b60a088015190925080151581146200029357600080fd5b809150509295509295509295565b6001600160a01b0381168114620002b757600080fd5b50565b615b0180620002ca6000396000f3fe6080604052600436106101175760003560e01c8063773fe9861161009a5780638ff79f90116100615780638ff79f901461042b578063a68b91ab1461044b578063d78ccb8b146104b1578063df354bdd146104ec578063f2fde38b1461051a57005b8063773fe9861461026c57806377dec6c31461029a578063858a6dc81461039d5780638da5cb5b146103e35780638f09d4931461040b57005b806331ae450b116100de57806331ae450b146101d557806339254111146101f757806351cff8d9146102175780636d73e66914610237578063715018a61461025757005b806301ffc9a71461012057806324cfb1a11461015557806324d7806c146101755780632977f78a146101955780632d345670146101b557005b3661011e57005b005b34801561012c57600080fd5b5061014061013b36600461486b565b61053a565b60405190151581526020015b60405180910390f35b61016861016336600461496f565b610571565b60405161014c919061501c565b34801561018157600080fd5b5061014061019036600461465b565b610e3c565b3480156101a157600080fd5b5061011e6101b036600461493b565b610e75565b3480156101c157600080fd5b5061011e6101d036600461465b565b611040565b3480156101e157600080fd5b506101ea6110c0565b60405161014c9190614ef3565b34801561020357600080fd5b5061011e610212366004614831565b61116e565b34801561022357600080fd5b5061011e61023236600461465b565b6111d6565b34801561024357600080fd5b5061011e61025236600461465b565b6113ab565b34801561026357600080fd5b5061011e611425565b34801561027857600080fd5b5061028c610287366004614706565b611499565b60405161014c929190614fc6565b3480156102a657600080fd5b506103886102b536600461493b565b8051808201602090810180516007808352938301948301949094209390528254600184015460028501546040805160c08101825260058801546001600160a01b0390811682526006890154811696820196909652958701548516908601526008860154808516606087015261ffff600160a01b820481166080880152600160b01b9091041660a08601526009909501546001600160401b0380841696600160401b8504821696600160801b90950490911694928316939092909160ff808216926101008304909116916201000090041689565b60405161014c99989796959493929190615333565b3480156103a957600080fd5b506103d56103b836600461493b565b805160208183018101805160088252928201919093012091525481565b60405190815260200161014c565b3480156103ef57600080fd5b506001546040516001600160a01b03909116815260200161014c565b34801561041757600080fd5b5061011e610426366004614a93565b611530565b34801561043757600080fd5b5061011e610446366004614695565b611d95565b34801561045757600080fd5b5060045460055460065460408051600160581b85046001600160a01b03908116825261ffff861660208301529384169181019190915291166060820152620100009091046001600160401b0316608082015260a00161014c565b3480156104bd57600080fd5b506101406104cc366004614895565b8051602081830181018051600a8252928201919093012091525460ff1681565b3480156104f857600080fd5b5061050c6105073660046148fa565b611e6f565b60405161014c92919061502f565b34801561052657600080fd5b5061011e61053536600461465b565b611f5f565b60006001600160e01b03198216632a9f3abf60e11b148061056b57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6060600260005414156105cb5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b6002600090815584516040516007916105e391614ed7565b908152604080516020928190038301812060c08201835260058101546001600160a01b03908116835260068201548116948301949094526007808201548516838501526008909101549384166060830152600160a01b840461ffff9081166080840152600160b01b90940490931660a0820152875191519093506000929161066a91614ed7565b9081526040805191829003602090810183206101608401835280546001600160401b038082168652600160401b8204811686850152600160801b909104168484015260018101546001600160a01b0316606085015260028101546080850152600381018054845181850281018501909552808552919360a086019390929083018282801561071757602002820191906000526020600020905b815481526020019060010190808311610703575b505050505081526020016004820180548060200260200160405190810160405280929190818152602001828054801561077957602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161075b575b50505091835250506040805160c08101825260058401546001600160a01b0390811682526006850154811660208381019190915260078601548216838501526008860154918216606084015261ffff600160a01b830481166080850152600160b01b90920490911660a0830152830152600983015491019060ff16600181111561080557610805615802565b600181111561081657610816615802565b81526020016009820160019054906101000a900460ff16600181111561083e5761083e615802565b600181111561084f5761084f615802565b81526009918201546201000090046001600160a01b0316602090910152875160405192935090916108809190614ed7565b9081526040519081900360200190205460ff166108d25760405162461bcd60e51b815260206004820152601060248201526f756e737570706f727465642073616c6560801b60448201526064016105c2565b6108db33610e3c565b806108f2575060a08601516001600160a01b031633145b6109755760405162461bcd60e51b815260206004820152604860248201527f4f6e6c7920746865206275796572206f722061646d696e206f72206f776e657260448201527f206f66207468697320636f6e74726163742063616e2063616c6c207468697320606482015267333ab731ba34b7b760c11b608482015260a4016105c2565b6101408101516001600160a01b031615610ab25761014081015161010087015161012088015160a0890151604051632c10f0e160e11b81526001600160a01b039384166004820152602481019290925282166044820152911690635821e1c290606401602060405180830381600087803b1580156109f257600080fd5b505af1158015610a06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2a919061484e565b610ab25760405162461bcd60e51b815260206004820152604d60248201527f706c656173652070726f7665646520746865207265717569726564206761746560448201527f6420636f6c6c656374696f6e20616e6420746f6b656e2064657461696c73207460648201526c1bc8189d5e481d1a19481b999d609a1b608482015260a4016105c2565b600080610ac26020870187614b04565b61ffff161180610adb5750600454600160501b900460ff165b15610d07576000610aef6020870187614b04565b61ffff161115610b2a57612710610b096020870187614b04565b61ffff1610610b2a5760405162461bcd60e51b81526004016105c290615126565b610b3d61019060a087016080880161465b565b610b9b5760405162461bcd60e51b815260206004820152602960248201527f6f6e6c79206f776e6572206f722061646d696e2063616e207369676e20666f7260448201526808191a5cd8dbdd5b9d60ba1b60648201526084016105c2565b600a610baa6060870187615441565b604051610bb8929190614ec7565b9081526040519081900360200190205460ff1615610c185760405162461bcd60e51b815260206004820152601960248201527f7369676e617475726520616c7265616479206170706c6965640000000000000060448201526064016105c2565b60a0870151610c6d90610c2e6020880188614b04565b610c3e6040890160208a01614b3a565b610c4e60a08a0160808b0161465b565b610c5b60408b018b615441565b610c6860608d018d615441565b61204a565b610cb95760405162461bcd60e51b815260206004820152601a60248201527f696e76616c696420646973636f756e74207369676e617475726500000000000060448201526064016105c2565b6001600a610cca6060880188615441565b604051610cd8929190614ec7565b90815260405160209181900382019020805460ff191692151592909217909155610d0490860186614b04565b90505b600080610d5389600001518a604001518b606001516001600160401b03168c608001516001600160401b03168d60c001518d8f60e00151610d489190615571565b8f60a001518a612191565b91509150610d9689600001518a60200151838c60a001518d604001518e606001516001600160401b03168f608001516001600160401b03168b6101000151612c91565b95508715610db657610db68960a0015186602001518b60c001518b613773565b610dde89600001518a60e001518b60a001518c60c001518d60400151868a6101000151613877565b806001600160a01b03167f7d230fa887dd4401f152bfcb09c80ceb2c6125f608ef6890e964c9656ba5ac6e8a888b868e60e00151604051610e239594939291906151bd565b60405180910390a2505050505060016000559392505050565b6000816001600160a01b0316610e5a6001546001600160a01b031690565b6001600160a01b0316148061056b575061056b600283613a8b565b33610e886001546001600160a01b031690565b6001600160a01b03161480610ea35750610ea3600233613a8b565b610ebf5760405162461bcd60e51b81526004016105c290615179565b600981604051610ecf9190614ed7565b9081526040519081900360200190205460ff16610f545760405162461bcd60e51b815260206004820152603760248201527f7468652073616c65496420796f75206861766520656e7465726564206973206960448201527f6e76616c69642e20506c656173652076616c696461746500000000000000000060648201526084016105c2565b600781604051610f649190614ed7565b90815260405190819003602001902080546001600160c01b03191681556001810180546001600160a01b0319169055600060028201819055610fa960038301826144c5565b610fb76004830160006144c5565b506005810180546001600160a01b03199081169091556006820180548216905560078201805490911690556008810180546001600160c01b031916905560090180546001600160b01b03191690556040517f09fced985ff97f7dac8f320b7d834e3862ae0274970ffe3dc0d84de5a453899590611035908390615069565b60405180910390a150565b6001546001600160a01b0316331461106a5760405162461bcd60e51b81526004016105c29061507c565b611075600282613a8b565b156110bd5760405133906001600160a01b038316907f7c0c3c84c67c85fcac635147348bfe374c24a1a93d0366d1cfe9d8853cbf89d590600090a36110bb600282613ab0565b505b50565b60606110cc6002613ac5565b6001600160401b038111156110e3576110e3615844565b60405190808252806020026020018201604052801561110c578160200160208202803683370190505b50905060005b61111c6002613ac5565b81101561116a5761112e600282613acf565b8282815181106111405761114061582e565b6001600160a01b039092166020928302919091019091015280611162816157d1565b915050611112565b5090565b336111816001546001600160a01b031690565b6001600160a01b0316148061119c575061119c600233613a8b565b6111b85760405162461bcd60e51b81526004016105c290615179565b60048054911515600160501b0260ff60501b19909216919091179055565b336111e96001546001600160a01b031690565b6001600160a01b031614806112045750611204600233613a8b565b6112205760405162461bcd60e51b81526004016105c290615179565b6000336001600160a01b03831661130657604080516000815260208101918290526001600160a01b03831691479161125791614ed7565b60006040518083038185875af1925050503d8060008114611294576040519150601f19603f3d011682016040523d82523d6000602084013e611299565b606091505b505080925050816113015760405162461bcd60e51b815260206004820152602c60248201527f776974686472617720746f2077697468647261772066756e64732e20506c656160448201526b39b2903a393c9030b3b0b4b760a11b60648201526084016105c2565b505050565b6001600160a01b03831615611301576040516370a0823160e01b81523060048201526000906001600160a01b038516906370a082319060240160206040518083038186803b15801561135757600080fd5b505afa15801561136b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138f9190614b21565b90506113a56001600160a01b0385168383613adb565b50505050565b6001546001600160a01b031633146113d55760405162461bcd60e51b81526004016105c29061507c565b6113e0600282613a8b565b6110bd5760405133906001600160a01b038316907f7e1a1a08d52e4ba0e21554733d66165fd5151f99460116223d9e3a608eec5cb190600090a36110bb600282613b3e565b6001546001600160a01b0316331461144f5760405162461bcd60e51b81526004016105c29061507c565b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b600654604051636e44a72f60e01b81526001600160a01b038481166004830152602482018490526060928392911690636e44a72f9060440160006040518083038186803b1580156114e957600080fd5b505afa1580156114fd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115259190810190614732565b909590945092505050565b336115436001546001600160a01b031690565b6001600160a01b0316148061155e575061155e600233613a8b565b61157a5760405162461bcd60e51b81526004016105c290615179565b600061158e6101a085016101808601614b04565b61ffff16156115d6576115a961018085016101608601614b04565b6115bb6101a086016101808701614b04565b6115c5919061554b565b6115cf908261554b565b9050611606565b6115e861018085016101608601614b04565b6004546115f9919061ffff1661554b565b611603908261554b565b90505b6127108161ffff161061162b5760405162461bcd60e51b81526004016105c290615126565b600061163a6020860186614b60565b6001600160401b03161180156116685750600061165d6040860160208701614b60565b6001600160401b0316115b156117365761167a6020850185614b60565b6001600160401b03166116936040860160208701614b60565b6001600160401b031610156117365760405162461bcd60e51b815260206004820152605f60248201527f54686973206973206e6f7420612076616c6964204e4654207374617274206f7260448201527f20656e6420746f6b656e2049442e20506c65617365207665726966792074686160648201527f74207468652072616e67652070726f766964656420697320636f727265637400608482015260a4016105c2565b61174360a08501856153f8565b905061175260c08601866153f8565b9050146117c75760405162461bcd60e51b815260206004820152603860248201527f73686f756c642070726f7669646520657175616c206c656e67746820696e207060448201527f7269636520616e64207061796d656e742061646472657373000000000000000060648201526084016105c2565b60006117db6101c086016101a087016148dd565b60018111156117ec576117ec615802565b1415611911576118026060850160408601614b60565b6001600160401b03166118615760405162461bcd60e51b815260206004820152602160248201527f73686f756c642070726f76696465206d617843617020666f72206d696e74696e6044820152606760f81b60648201526084016105c2565b61186e6020850185614b60565b6001600160401b031615801561189a575061188f6040850160208601614b60565b6001600160401b0316155b61190c5760405162461bcd60e51b815260206004820152603d60248201527f546865204e46547374617274746f6b656e696420616e64204e4654656e64746f60448201527f6b656e69642073686f756c64206265203020666f72206d696e74696e6700000060648201526084016105c2565b611987565b6119216060850160408601614b60565b6001600160401b0316156119875760405162461bcd60e51b815260206004820152602760248201527f6d61784361702073686f756c64206265203020666f72207072656d696e74656460448201526620746f6b656e7360c81b60648201526084016105c2565b611997608085016060860161465b565b6040516301ffc9a760e01b81526001600160a01b0391909116906301ffc9a7906119cc906380ac58cd60e01b90600401615054565b60206040518083038186803b1580156119e457600080fd5b505afa1580156119f8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a1c919061484e565b80611ab75750611a32608085016060860161465b565b6040516301ffc9a760e01b81526001600160a01b0391909116906301ffc9a790611a6790636cdb3d1360e11b90600401615054565b60206040518083038186803b158015611a7f57600080fd5b505afa158015611a93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab7919061484e565b611b295760405162461bcd60e51b815260206004820152603e60248201527f73686f756c642070726f76696465206f6e6c7920737570706f7274656420636f60448201527f6e747261637420696e746572666163657320455243203732312f31313535000060648201526084016105c2565b6000611b3c610100860160e0870161465b565b6001600160a01b03161415611bae5760405162461bcd60e51b815260206004820152603260248201527f73686f756c642070726f766964652076616c69642077616c6c65742061646472604482015271195cdcc8199bdc881cd95d1d1b195b595b9d60721b60648201526084016105c2565b6000611bc26101208601610100870161465b565b6001600160a01b03161415611c385760405162461bcd60e51b815260206004820152603660248201527f73686f756c642070726f766964652076616c69642077616c6c65742061646472604482015275195cdcc8199bdc881d185e081cd95d1d1b195b595b9d60521b60648201526084016105c2565b60098383604051611c4a929190614ec7565b9081526040519081900360200190205460ff16611cff578360078484604051611c74929190614ec7565b908152604051908190036020019020611c8d82826158bd565b905050600160098484604051611ca4929190614ec7565b908152604051908190036020018120805492151560ff19909316929092179091557f10ad2ba139c14ce12c8f9de79787831cd54ad8c67c6d8106f4af2295cfcf555d90611cf29086906152b3565b60405180910390a16113a5565b60098383604051611d11929190614ec7565b9081526040519081900360200190205460ff16156113a5578360078484604051611d3c929190614ec7565b908152604051908190036020019020611d5582826158bd565b9050507f10ad2ba139c14ce12c8f9de79787831cd54ad8c67c6d8106f4af2295cfcf555d84604051611d8791906152f3565b60405180910390a150505050565b33611da86001546001600160a01b031690565b6001600160a01b03161480611dc35750611dc3600233613a8b565b611ddf5760405162461bcd60e51b81526004016105c290615179565b600480546001600160401b03909416620100000269ffffffffffffffffffff196001600160a01b03978816600160581b02167fff0000000000000000000000000000000000000000ff000000000000000000009095169490941761ffff9095169490941792909217909255600680549284166001600160a01b031993841617905560058054919093169116179055565b60608060078484604051611e84929190614ec7565b9081526040805191829003602090810183206003018054808302850183019093528284529190830182828015611ed957602002820191906000526020600020905b815481526020019060010190808311611ec5575b5050505050915060078484604051611ef2929190614ec7565b9081526040805191829003602090810183206004018054808302850183019093528284529190830182828015611f5157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611f33575b505050505090509250929050565b6001546001600160a01b03163314611f895760405162461bcd60e51b81526004016105c29061507c565b6001600160a01b038116611fee5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016105c2565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000428763ffffffff1610156120b05760405162461bcd60e51b815260206004820152602560248201527f646973636f756e74207369676e617475726520697320616c72656164792065786044820152641c1a5c995960da1b60648201526084016105c2565b856001600160a01b031661217884848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604051612172925061211291508e908e908e908d908d904690602001614e5a565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b90613b53565b6001600160a01b03161490505b98975050505050505050565b600080600060078b6040516121a69190614ed7565b9081526040805191829003602090810183206101608401835280546001600160401b038082168652600160401b8204811686850152600160801b909104168484015260018101546001600160a01b0316606085015260028101546080850152600381018054845181850281018501909552808552919360a086019390929083018282801561225357602002820191906000526020600020905b81548152602001906001019080831161223f575b50505050508152602001600482018054806020026020016040519081016040528092919081815260200182805480156122b557602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612297575b50505091835250506040805160c08101825260058401546001600160a01b0390811682526006850154811660208381019190915260078601548216838501526008860154918216606084015261ffff600160a01b830481166080850152600160b01b90920490911660a0830152830152600983015491019060ff16600181111561234157612341615802565b600181111561235257612352615802565b81526020016009820160019054906101000a900460ff16600181111561237a5761237a615802565b600181111561238b5761238b615802565b8152600991909101546201000090046001600160a01b031660209091015280519091506001600160401b03161580156123d15750600081602001516001600160401b0316115b156124085780602001516001600160401b03168a11156124035760405162461bcd60e51b81526004016105c2906150b1565b6124c9565b80516001600160401b03161580159061242c575060208101516001600160401b0316155b1561245b5780516001600160401b03168a10156124035760405162461bcd60e51b81526004016105c2906150b1565b80516001600160401b0316158015906124815750600081602001516001600160401b0316115b156124c95780516001600160401b03168a108015906124ad575080602001516001600160401b03168a11155b6124c95760405162461bcd60e51b81526004016105c2906150b1565b60608101519150600081610120015160018111156124e9576124e9615802565b1415612580576005546080820151604051630748060b60e31b815260048101919091526001600160a01b03898116602483015290911690633a4030589060440160206040518083038186803b15801561254157600080fd5b505afa158015612555573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125799190614b21565b925061261f565b6001816101200151600181111561259957612599615802565b141561261f5760005b8160c001515181101561261d57876001600160a01b03168260c0015182815181106125cf576125cf61582e565b60200260200101516001600160a01b0316141561260b578160a0015181815181106125fc576125fc61582e565b6020026020010151935061261d565b80612615816157d1565b9150506125a2565b505b826126855760405162461bcd60e51b815260206004820152603060248201527f506c656173652070726f766964652076616c696420737570706f72746564204560448201526f524332302f455448206164647265737360801b60648201526084016105c2565b61ffff8416156126b7576127106126a061ffff8616856155ab565b6126aa9190615589565b6126b490846155ca565b92505b600081610100015160018111156126d0576126d0615802565b1415612954576004546201000090046001600160401b03168811156127935760405162461bcd60e51b815260206004820152606760248201527f546865206d6178696d756d207175616e7469747920616c6c6f77656420746f2060448201527f7075726368617365206174206f6e652074696d652073686f756c64206e6f742060648201527f6265206d6f7265207468616e20646566696e656420696e206d6178313135355160848201526675616e7469747960c81b60a482015260c4016105c2565b6040516301ffc9a760e01b81526001600160a01b038316906301ffc9a7906127c6906380ac58cd60e01b90600401615054565b60206040518083038186803b1580156127de57600080fd5b505afa1580156127f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612816919061484e565b1561282c5761282589846155ab565b9250612980565b6040516301ffc9a760e01b81526001600160a01b038316906301ffc9a79061285f90636cdb3d1360e11b90600401615054565b60206040518083038186803b15801561287757600080fd5b505afa15801561288b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128af919061484e565b1561294f5760405163bd85b03960e01b8152600481018b90526001600160a01b0383169063bd85b0399060240160206040518083038186803b1580156128f457600080fd5b505afa158015612908573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061292c9190614b21565b612945578761293b8a856155ab565b61282591906155ab565b61282588846155ab565b612980565b6001816101000151600181111561296d5761296d615802565b14156129805761297d88846155ab565b92505b6001600160a01b038716612a4557853414801561299d5750828610155b612a405760405162461bcd60e51b815260206004820152606260248201527f496e73756666696369656e742066756e6473206f7220696e76616c696420616d60448201527f6f756e742e20596f75206e65656420746f207061737320612076616c6964206160648201527f6d6f756e7420746f20636f6d706c6574652074686973207472616e736163746960848201526137b760f11b60a482015260c4016105c2565b612c83565b6040516370a0823160e01b81526001600160a01b0386811660048301528791908916906370a082319060240160206040518083038186803b158015612a8957600080fd5b505afa158015612a9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ac19190614b21565b10158015612acf5750828610155b612b5d5760405162461bcd60e51b815260206004820152605360248201527f496e73756666696369656e742066756e64732e20596f752073686f756c64206860448201527f6176652073756666696369656e742062616c616e636520746f20636f6d706c656064820152723a32903a3434b9903a3930b739b0b1ba34b7b760691b608482015260a4016105c2565b604051636eb1769f60e11b81526001600160a01b03868116600483015230602483015287919089169063dd62ed3e9060440160206040518083038186803b158015612ba757600080fd5b505afa158015612bbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bdf9190614b21565b1015612c835760405162461bcd60e51b815260206004820152606160248201527f496e73756666696369656e7420617070726f76616c2066726f6d20616e20455260448201527f43323020546f6b656e2e20506c656173652070726f7669646520617070726f7660648201527f616c20746f207468697320636f6e747261637420616e642074727920616761696084820152603760f91b60a482015260c4016105c2565b509850989650505050505050565b6040516301ffc9a760e01b81526060906001600160a01b038816906301ffc9a790612cc7906380ac58cd60e01b90600401615054565b60206040518083038186803b158015612cdf57600080fd5b505afa158015612cf3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d17919061484e565b156130a6576001826001811115612d3057612d30615802565b1415612e96576040516331a9108f60e11b8152600481018690526001600160a01b03808a169190891690636352211e9060240160206040518083038186803b158015612d7b57600080fd5b505afa158015612d8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612db39190614678565b6001600160a01b031614612e275760405162461bcd60e51b815260206004820152603560248201527f496e76616c6964204e4654204f776e657220416464726573732e20506c656173604482015274329031b432b1b59030b732103a393c9030b3b0b4b760591b60648201526084016105c2565b604051632142170760e11b81526001600160a01b0389811660048301528781166024830152604482018790528816906342842e0e90606401600060405180830381600087803b158015612e7957600080fd5b505af1158015612e8d573d6000803e3d6000fd5b50505050612185565b6000826001811115612eaa57612eaa615802565b14156130a157600789604051612ec09190614ed7565b908152604051908190036020018120546001600160401b03600160801b90910416908590600890612ef2908d90614ed7565b908152602001604051809103902054612f0b9190615571565b1115612fcb5760405162461bcd60e51b815260206004820152607760248201527f546865206d6178696d756d207175616e7469747920616c6c6f77656420746f2060448201527f70757263686173652045524337323120746f6b656e20686173206265656e207360648201527f6f6c64206f75742e20506c6561736520636f6e74616374207468652073616c6560848201527f206f776e657220666f72206d6f72652064657461696c7300000000000000000060a482015260c4016105c2565b60405163e00aab4b60e01b81526001600160a01b03878116600483015261ffff8616602483015288169063e00aab4b90604401600060405180830381600087803b15801561301857600080fd5b505af115801561302c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261305491908101906147fd565b90508360088a6040516130679190614ed7565b9081526020016040518091039020546130809190615571565b60088a6040516130909190614ed7565b908152604051908190036020019020555b612185565b6040516301ffc9a760e01b81526001600160a01b038816906301ffc9a7906130d990636cdb3d1360e11b90600401615054565b60206040518083038186803b1580156130f157600080fd5b505afa158015613105573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613129919061484e565b1561218557600182600181111561314257613142615802565b14156132ca57604051627eeac760e11b81526001600160a01b038981166004830152602482018790526000919089169062fdd58e9060440160206040518083038186803b15801561319257600080fd5b505afa1580156131a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131ca9190614b21565b90508084111580156131dc5750600084115b61323a5760405162461bcd60e51b815260206004820152602960248201527f496e73756666696369656e7420746f6b656e2062616c616e63652066726f6d206044820152683a34329037bbb732b960b91b60648201526084016105c2565b604051637921219560e11b81526001600160a01b038a811660048301528881166024830152604482018890526064820186905260a06084830152600260a483015261060f60f31b60c483015289169063f242432a9060e401600060405180830381600087803b1580156132ac57600080fd5b505af11580156132c0573d6000803e3d6000fd5b5050505050612185565b60008260018111156132de576132de615802565b141561218557604080516001808252818301909252600091602080830190803683370190505090506000856001600160401b0381111561332057613320615844565b604051908082528060200260200182016040528015613349578160200160208202803683370190505b509050606088836000815181106133625761336261582e565b60200260200101906001600160a01b031690816001600160a01b03168152505085826000815181106133965761339661582e565b602090810291909101015260405163bd85b03960e01b8152600481018990526001600160a01b038b169063bd85b0399060240160206040518083038186803b1580156133e157600080fd5b505afa1580156133f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134199190614b21565b61363e5760078c60405161342d9190614ed7565b908152604051908190036020018120546001600160401b03600160801b909104169060089061345d908f90614ed7565b9081526020016040518091039020541061352b5760405162461bcd60e51b815260206004820152607860248201527f546865206d6178696d756d207175616e7469747920616c6c6f77656420746f2060448201527f7075726368617365204552433131353520746f6b656e20686173206265656e2060648201527f736f6c64206f75742e20506c6561736520636f6e74616374207468652073616c60848201527f65206f776e657220666f72206d6f72652064657461696c73000000000000000060a482015260c4016105c2565b60005b8781101561356657868382815181106135495761354961582e565b60209081029190910101528061355e816157d1565b91505061352e565b50604051634637423960e11b81526001600160a01b038b1690638c6e84729061359790869086908690600401614f06565b600060405180830381600087803b1580156135b157600080fd5b505af11580156135c5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526135ed91908101906147fd565b93508660088d6040516136009190614ed7565b9081526020016040518091039020546136199190615571565b60088d6040516136299190614ed7565b90815260405190819003602001902055613764565b60405163bd85b03960e01b8152600481018990526000906001600160a01b038c169063bd85b0399060240160206040518083038186803b15801561368157600080fd5b505afa158015613695573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136b99190614b21565b1115613764576040805160018082528183019092526000916020808301908036833701905050905088816000815181106136f5576136f561582e565b60209081029190910101526040516339b2213760e21b81526001600160a01b038c169063e6c884dc9061373090879085908890600401614f8d565b600060405180830381600087803b15801561374a57600080fd5b505af115801561375e573d6000803e3d6000fd5b50505050505b50505098975050505050505050565b60006001600160a01b03831661385b57604080516000815260208101918290526001600160a01b0386169184916137a991614ed7565b60006040518083038185875af1925050503d80600081146137e6576040519150601f19603f3d011682016040523d82523d6000602084013e6137eb565b606091505b505080915050806138565760405162461bcd60e51b815260206004820152602f60248201527f756e61626c6520746f206465626974206e61746976652062616c616e6365207060448201526e3632b0b9b2903a393c9030b3b0b4b760891b60648201526084016105c2565b613870565b6138706001600160a01b038416868685613b77565b5050505050565b60006007886040516138899190614ed7565b908152604080516020928190038301812060c08201835260058101546001600160a01b0390811683526006820154811694830194909452600781015484169282019290925260089091015491821660608201819052600160a01b830461ffff9081166080840152600160b01b90930490921660a082015291506000901580159061391b575060008260a0015161ffff16115b156139625761395d878360600151886127108660a0015161ffff168d61394191906155ab565b61394b9190615589565b6139559086615571565b945084613773565b6139bb565b600454600160581b90046001600160a01b031615801590613988575060045461ffff1615155b156139bb576004546139bb9088906001600160a01b03600160581b820416908990612710906139419061ffff168e6155ab565b60408201516001600160a01b0316158015906139df57506000826080015161ffff16115b15613a4157612710826080015161ffff16896139fb91906155ab565b613a059190615589565b613a0f9082615571565b9050613a4187836040015188612710866080015161ffff168d613a3291906155ab565b613a3c9190615589565b613773565b613a4b81896155ca565b6006549098506001600160a01b031615613a7057613a6d8786868b8a88613baf565b97505b613a80878360000151888b613773565b505050505050505050565b6001600160a01b038116600090815260018301602052604081205415155b9392505050565b6000613aa9836001600160a01b038416613be5565b600061056b825490565b6000613aa98383613cd8565b6040516001600160a01b03831660248201526044810182905261130190849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613d02565b6000613aa9836001600160a01b038416613dd4565b6000806000613b628585613e23565b91509150613b6f81613e93565b509392505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113a59085906323b872dd60e01b90608401613b07565b60006001826001811115613bc557613bc5615802565b1415613bdb57613bd8878688878761404e565b90505b9695505050505050565b60008181526001830160205260408120548015613cce576000613c096001836155ca565b8554909150600090613c1d906001906155ca565b9050818114613c82576000866000018281548110613c3d57613c3d61582e565b9060005260206000200154905080876000018481548110613c6057613c6061582e565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613c9357613c93615818565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061056b565b600091505061056b565b6000826000018281548110613cef57613cef61582e565b9060005260206000200154905092915050565b6000613d57826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166142319092919063ffffffff16565b8051909150156113015780806020019051810190613d75919061484e565b6113015760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016105c2565b6000818152600183016020526040812054613e1b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561056b565b50600061056b565b600080825160411415613e5a5760208301516040840151606085015160001a613e4e87828585614248565b94509450505050613e8c565b825160401415613e845760208301516040840151613e79868383614335565b935093505050613e8c565b506000905060025b9250929050565b6000816004811115613ea757613ea7615802565b1415613eb05750565b6001816004811115613ec457613ec4615802565b1415613f125760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016105c2565b6002816004811115613f2657613f26615802565b1415613f745760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016105c2565b6003816004811115613f8857613f88615802565b1415613fe15760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016105c2565b6004816004811115613ff557613ff5615802565b14156110bd5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b60648201526084016105c2565b600654604051636e44a72f60e01b81526001600160a01b038681166004830152602482018690526000928592849283928392911690636e44a72f9060440160006040518083038186803b1580156140a457600080fd5b505afa1580156140b8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526140e09190810190614732565b81519193509150806140f9578795505050505050614228565b60005b8181101561421f5760008482815181106141185761411861582e565b602002602001015190506127108a8584815181106141385761413861582e565b602002602001015161414a91906155ab565b6141549190615589565b9550858710156141b45760405162461bcd60e51b815260206004820152602560248201527f696e736f6c76656e743a20756e61626c6520746f20636f6d706c65746520726f60448201526479616c747960d81b60648201526084016105c2565b6141c08d828b89613773565b604080516001600160a01b038e81168252602082018e90528316818301526060810188905290517f866e6ef8682ddf5f1025e64dfdb45527077f7be70fa9ef680b7ffd8cf4ab9c509181900360800190a15094849003946001016140fc565b50939450505050505b95945050505050565b60606142408484600085614364565b949350505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561427f575060009050600361432c565b8460ff16601b1415801561429757508460ff16601c14155b156142a8575060009050600461432c565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156142fc573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166143255760006001925092505061432c565b9150600090505b94509492505050565b6000806001600160ff1b03831660ff84901c601b0161435687828885614248565b935093505050935093915050565b6060824710156143c55760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016105c2565b843b6144135760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105c2565b600080866001600160a01b0316858760405161442f9190614ed7565b60006040518083038185875af1925050503d806000811461446c576040519150601f19603f3d011682016040523d82523d6000602084013e614471565b606091505b509150915061448182828661448c565b979650505050505050565b6060831561449b575081613aa9565b8251156144ab5782518084602001fd5b8160405162461bcd60e51b81526004016105c29190615069565b50805460008255906000526020600020908101906110bd91905b8082111561116a57600081556001016144df565b60006001600160401b0383111561450c5761450c615844565b61451f601f8401601f19166020016154b0565b905082815283838301111561453357600080fd5b828260208301376000602084830101529392505050565b803561455581615a76565b919050565b600082601f83011261456b57600080fd5b8151602061458061457b836154e0565b6154b0565b80838252828201915082860187848660051b89010111156145a057600080fd5b60005b858110156145bf578151845292840192908401906001016145a3565b5090979650505050505050565b803561455581615a99565b60008083601f8401126145e957600080fd5b5081356001600160401b0381111561460057600080fd5b602083019150836020828501011115613e8c57600080fd5b600082601f83011261462957600080fd5b613aa9838335602085016144f3565b600060a0828403121561464a57600080fd5b50919050565b803561455581615ab6565b60006020828403121561466d57600080fd5b8135613aa981615a76565b60006020828403121561468a57600080fd5b8151613aa981615a76565b600080600080600060a086880312156146ad57600080fd5b85356146b881615a76565b945060208601356146c881615aa6565b935060408601356146d881615ab6565b925060608601356146e881615a76565b915060808601356146f881615a76565b809150509295509295909350565b6000806040838503121561471957600080fd5b823561472481615a76565b946020939093013593505050565b6000806040838503121561474557600080fd5b82516001600160401b038082111561475c57600080fd5b818501915085601f83011261477057600080fd5b8151602061478061457b836154e0565b8083825282820191508286018a848660051b89010111156147a057600080fd5b600096505b848710156147cc5780516147b881615a76565b8352600196909601959183019183016147a5565b50918801519196509093505050808211156147e657600080fd5b506147f38582860161455a565b9150509250929050565b60006020828403121561480f57600080fd5b81516001600160401b0381111561482557600080fd5b6142408482850161455a565b60006020828403121561484357600080fd5b8135613aa981615a8b565b60006020828403121561486057600080fd5b8151613aa981615a8b565b60006020828403121561487d57600080fd5b81356001600160e01b031981168114613aa957600080fd5b6000602082840312156148a757600080fd5b81356001600160401b038111156148bd57600080fd5b8201601f810184136148ce57600080fd5b614240848235602084016144f3565b6000602082840312156148ef57600080fd5b8135613aa981615a99565b6000806020838503121561490d57600080fd5b82356001600160401b0381111561492357600080fd5b61492f858286016145d7565b90969095509350505050565b60006020828403121561494d57600080fd5b81356001600160401b0381111561496357600080fd5b61424084828501614618565b60008060006060848603121561498457600080fd5b83356001600160401b038082111561499b57600080fd5b9085019061014082880312156149b057600080fd5b6149b8615487565b8235828111156149c757600080fd5b6149d389828601614618565b8252506149e26020840161454a565b6020820152604083013560408201526149fd60608401614650565b6060820152614a0e60808401614650565b6080820152614a1f60a0840161454a565b60a0820152614a3060c0840161454a565b60c082015260e083013560e0820152610100614a4d81850161454a565b9082015261012092830135928101929092529093506020850135925060408501359080821115614a7c57600080fd5b50614a8986828701614638565b9150509250925092565b600080600060408486031215614aa857600080fd5b83356001600160401b0380821115614abf57600080fd5b908501906102008288031215614ad457600080fd5b90935060208501359080821115614aea57600080fd5b50614af7868287016145d7565b9497909650939450505050565b600060208284031215614b1657600080fd5b8135613aa981615aa6565b600060208284031215614b3357600080fd5b5051919050565b600060208284031215614b4c57600080fd5b813563ffffffff81168114613aa957600080fd5b600060208284031215614b7257600080fd5b8135613aa981615ab6565b8183526000602080850194508260005b85811015614bbb578135614ba081615a76565b6001600160a01b031687529582019590820190600101614b8d565b509495945050505050565b600081518084526020808501945080840160005b83811015614bbb5781516001600160a01b031687529582019590820190600101614bda565b81835260006001600160fb1b03831115614c1857600080fd5b8260051b8083602087013760009401602001938452509192915050565b600081518084526020808501945080840160005b83811015614bbb57815187529582019590820190600101614c49565b614c6e81615a58565b9052565b60008151808452614c8a8160208601602086016156e0565b601f01601f19169290920160200192915050565b6000610200614cbd84614cb085614650565b6001600160401b03169052565b614cc960208401614650565b6001600160401b03166020850152614ce360408401614650565b6001600160401b03166040850152614cfd6060840161454a565b6001600160a01b0316606085015260808381013590850152614d2260a0840184615503565b8260a0870152614d358387018284614bff565b92505050614d4660c0840184615503565b85830360c0870152614d59838284614b7d565b92505050614d6d60e0850160e08501614dc9565b6101a0614d7b8185016145cc565b614d8782870182614c65565b50506101c0614d978185016145cc565b614da382870182614c65565b50506101e0614db381850161454a565b6001600160a01b03169401939093525090919050565b8035614dd481615a76565b6001600160a01b039081168352602082013590614df082615a76565b9081166020840152604082013590614e0782615a76565b9081166040840152606082013590614e1e82615a76565b1660608301526080810135614e3281615aa6565b61ffff908116608084015260a082013590614e4c82615aa6565b80821660a085015250505050565b606087901b6bffffffffffffffffffffffff1916815260f086901b6001600160f01b031916601482015260e085901b6001600160e01b03191660168201528284601a830137694f4e434841494e42555960b01b9201601a8101929092526024820152604401949350505050565b8183823760009101908152919050565b60008251614ee98184602087016156e0565b9190910192915050565b602081526000613aa96020830184614bc6565b606081526000614f196060830186614bc6565b602083820381850152614f2c8287614c35565b915083820360408501528185518084528284019150828160051b85010183880160005b83811015614f7d57601f19878403018552614f6b838351614c72565b94860194925090850190600101614f4f565b50909a9950505050505050505050565b606081526000614fa06060830186614bc6565b8281036020840152614fb28186614c35565b90508281036040840152613bdb8185614c35565b604080825283519082018190526000906020906060840190828701845b828110156150085781516001600160a01b031684529284019290840190600101614fe3565b50505083810382850152613bdb8186614c35565b602081526000613aa96020830184614c35565b6040815260006150426040830185614c35565b82810360208401526142288185614bc6565b6001600160e01b031991909116815260200190565b602081526000613aa96020830184614c72565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252604f908201527f54686973206973206e6f7420612076616c696420746f6b656e49642e20506c6560408201527f6173652076657269667920746861742074686520746f6b656e49642070726f7660608201526e1a591959081a5cc818dbdc9c9958dd608a1b608082015260a00190565b60208082526033908201527f54686520746f74616c2066656520626173697320706f696e742073686f756c646040820152720206265206c657373207468616e20313030303606c1b606082015260800190565b60208082526024908201527f41646d696e436f6e74726f6c3a204d757374206265206f776e6572206f7220616040820152633236b4b760e11b606082015260800190565b60a08152600086516101408060a08501526151dc6101e0850183614c72565b915060208901516151f860c08601826001600160a01b03169052565b50604089015160e0850152606089015161010061521f818701836001600160401b03169052565b60808b0151915061012061523d818801846001600160401b03169052565b60a08c01516001600160a01b039081169488019490945260c08c0151841661016088015260e08c0151610180880152908b01519092166101a0860152508801516101c084015282810360208401526152958188614c35565b60408401969096525050606081019290925260809091015292915050565b6040815260006152c66040830184614c9e565b8281036020840152600b81526a1cd85b1950dc99585d195960aa1b60208201526040810191505092915050565b6040815260006153066040830184614c9e565b8281036020840152600b81526a1cd85b19555c19185d195960aa1b60208201526040810191505092915050565b60006101c0820190506001600160401b03808c168352808b166020840152808a1660408401525060018060a01b0380891660608401528760808401528087511660a08401528060208801511660c08401528060408801511660e08401528060608801511661010084015250608086015161ffff8082166101208501528060a08901511661014085015250506153cc610160830186614c65565b6153da610180830185614c65565b6001600160a01b0383166101a08301529a9950505050505050505050565b6000808335601e1984360301811261540f57600080fd5b8301803591506001600160401b0382111561542957600080fd5b6020019150600581901b3603821315613e8c57600080fd5b6000808335601e1984360301811261545857600080fd5b8301803591506001600160401b0382111561547257600080fd5b602001915036819003821315613e8c57600080fd5b60405161014081016001600160401b03811182821017156154aa576154aa615844565b60405290565b604051601f8201601f191681016001600160401b03811182821017156154d8576154d8615844565b604052919050565b60006001600160401b038211156154f9576154f9615844565b5060051b60200190565b6000808335601e1984360301811261551a57600080fd5b83016020810192503590506001600160401b0381111561553957600080fd5b8060051b3603831315613e8c57600080fd5b600061ffff808316818516808303821115615568576155686157ec565b01949350505050565b60008219821115615584576155846157ec565b500190565b6000826155a657634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156155c5576155c56157ec565b500290565b6000828210156155dc576155dc6157ec565b500390565b81831015611301576000818152602081208481019084015b8082101561560f578282556001820191506155f9565b505050505050565b600160401b83111561562b5761562b615844565b805483825561563b8482846155e1565b50818160005260208060002060005b8681101561568857833561565d81615a76565b82546001600160a01b0319166001600160a01b0391909116178255928201926001918201910161564a565b50505050505050565b600160401b8311156156a5576156a5615844565b80548382556156b58482846155e1565b50818160005260208060002060005b86811015615688578335825592820192600191820191016156c4565b60005b838110156156fb5781810151838201526020016156e3565b838111156113a55750506000910152565b813561571781615a76565b6157218183615881565b50602082013561573081615a76565b61573d8160018401615881565b50604082013561574c81615a76565b6157598160028401615881565b5060038101606083013561576c81615a76565b6157768183615881565b50608083013561578581615aa6565b815461ffff60a01b60a092831b1661ffff60a01b19821681178455918501356157ad81615aa6565b63ffffffff60a01b199190911690911760b09190911b61ffff60b01b161790555050565b60006000198214156157e5576157e56157ec565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6000813561056b81615a76565b6000813561056b81615a99565b6000813561056b81615ab6565b80546001600160a01b0319166001600160a01b0392909216919091179055565b6158aa82615a58565b60ff1981541660ff831681178255505050565b6158e76158c983615874565b825467ffffffffffffffff19166001600160401b0391909116178255565b6159286158f660208401615874565b82546fffffffffffffffff0000000000000000191660409190911b6fffffffffffffffff000000000000000016178255565b61596361593760408401615874565b82805467ffffffffffffffff60801b191660809290921b67ffffffffffffffff60801b16919091179055565b61597b6159726060840161585a565b60018301615881565b6080820135600282015561599260a08301836153f8565b6159a0818360038601615691565b50506159af60c08301836153f8565b6159bd818360048601615617565b50506159cf60e083016005830161570c565b600981016159e96159e36101a08501615867565b826158a1565b6159ff6159f96101c08501615867565b82615a37565b611301615a0f6101e0850161585a565b82805462010000600160b01b03191660109290921b62010000600160b01b0316919091179055565b615a4082615a58565b805461ff008360081b1661ff00198216178255505050565b600281106110bd57634e487b7160e01b600052602160045260246000fd5b6001600160a01b03811681146110bd57600080fd5b80151581146110bd57600080fd5b600281106110bd57600080fd5b61ffff811681146110bd57600080fd5b6001600160401b03811681146110bd57600080fdfea26469706673582212204641c60b73675afdd9a9a7568b10ac3b8b6ce18be959c6ae386dd49d988b9c8a64736f6c634300080700330000000000000000000000009fd1620fb2e589d1b08812b5e9cee4f0a31a5b5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c830e706eabbd9a4f2f7ed309e5b519a3073d5f200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
Deployed Bytecode
0x6080604052600436106101175760003560e01c8063773fe9861161009a5780638ff79f90116100615780638ff79f901461042b578063a68b91ab1461044b578063d78ccb8b146104b1578063df354bdd146104ec578063f2fde38b1461051a57005b8063773fe9861461026c57806377dec6c31461029a578063858a6dc81461039d5780638da5cb5b146103e35780638f09d4931461040b57005b806331ae450b116100de57806331ae450b146101d557806339254111146101f757806351cff8d9146102175780636d73e66914610237578063715018a61461025757005b806301ffc9a71461012057806324cfb1a11461015557806324d7806c146101755780632977f78a146101955780632d345670146101b557005b3661011e57005b005b34801561012c57600080fd5b5061014061013b36600461486b565b61053a565b60405190151581526020015b60405180910390f35b61016861016336600461496f565b610571565b60405161014c919061501c565b34801561018157600080fd5b5061014061019036600461465b565b610e3c565b3480156101a157600080fd5b5061011e6101b036600461493b565b610e75565b3480156101c157600080fd5b5061011e6101d036600461465b565b611040565b3480156101e157600080fd5b506101ea6110c0565b60405161014c9190614ef3565b34801561020357600080fd5b5061011e610212366004614831565b61116e565b34801561022357600080fd5b5061011e61023236600461465b565b6111d6565b34801561024357600080fd5b5061011e61025236600461465b565b6113ab565b34801561026357600080fd5b5061011e611425565b34801561027857600080fd5b5061028c610287366004614706565b611499565b60405161014c929190614fc6565b3480156102a657600080fd5b506103886102b536600461493b565b8051808201602090810180516007808352938301948301949094209390528254600184015460028501546040805160c08101825260058801546001600160a01b0390811682526006890154811696820196909652958701548516908601526008860154808516606087015261ffff600160a01b820481166080880152600160b01b9091041660a08601526009909501546001600160401b0380841696600160401b8504821696600160801b90950490911694928316939092909160ff808216926101008304909116916201000090041689565b60405161014c99989796959493929190615333565b3480156103a957600080fd5b506103d56103b836600461493b565b805160208183018101805160088252928201919093012091525481565b60405190815260200161014c565b3480156103ef57600080fd5b506001546040516001600160a01b03909116815260200161014c565b34801561041757600080fd5b5061011e610426366004614a93565b611530565b34801561043757600080fd5b5061011e610446366004614695565b611d95565b34801561045757600080fd5b5060045460055460065460408051600160581b85046001600160a01b03908116825261ffff861660208301529384169181019190915291166060820152620100009091046001600160401b0316608082015260a00161014c565b3480156104bd57600080fd5b506101406104cc366004614895565b8051602081830181018051600a8252928201919093012091525460ff1681565b3480156104f857600080fd5b5061050c6105073660046148fa565b611e6f565b60405161014c92919061502f565b34801561052657600080fd5b5061011e61053536600461465b565b611f5f565b60006001600160e01b03198216632a9f3abf60e11b148061056b57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6060600260005414156105cb5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b6002600090815584516040516007916105e391614ed7565b908152604080516020928190038301812060c08201835260058101546001600160a01b03908116835260068201548116948301949094526007808201548516838501526008909101549384166060830152600160a01b840461ffff9081166080840152600160b01b90940490931660a0820152875191519093506000929161066a91614ed7565b9081526040805191829003602090810183206101608401835280546001600160401b038082168652600160401b8204811686850152600160801b909104168484015260018101546001600160a01b0316606085015260028101546080850152600381018054845181850281018501909552808552919360a086019390929083018282801561071757602002820191906000526020600020905b815481526020019060010190808311610703575b505050505081526020016004820180548060200260200160405190810160405280929190818152602001828054801561077957602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161075b575b50505091835250506040805160c08101825260058401546001600160a01b0390811682526006850154811660208381019190915260078601548216838501526008860154918216606084015261ffff600160a01b830481166080850152600160b01b90920490911660a0830152830152600983015491019060ff16600181111561080557610805615802565b600181111561081657610816615802565b81526020016009820160019054906101000a900460ff16600181111561083e5761083e615802565b600181111561084f5761084f615802565b81526009918201546201000090046001600160a01b0316602090910152875160405192935090916108809190614ed7565b9081526040519081900360200190205460ff166108d25760405162461bcd60e51b815260206004820152601060248201526f756e737570706f727465642073616c6560801b60448201526064016105c2565b6108db33610e3c565b806108f2575060a08601516001600160a01b031633145b6109755760405162461bcd60e51b815260206004820152604860248201527f4f6e6c7920746865206275796572206f722061646d696e206f72206f776e657260448201527f206f66207468697320636f6e74726163742063616e2063616c6c207468697320606482015267333ab731ba34b7b760c11b608482015260a4016105c2565b6101408101516001600160a01b031615610ab25761014081015161010087015161012088015160a0890151604051632c10f0e160e11b81526001600160a01b039384166004820152602481019290925282166044820152911690635821e1c290606401602060405180830381600087803b1580156109f257600080fd5b505af1158015610a06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2a919061484e565b610ab25760405162461bcd60e51b815260206004820152604d60248201527f706c656173652070726f7665646520746865207265717569726564206761746560448201527f6420636f6c6c656374696f6e20616e6420746f6b656e2064657461696c73207460648201526c1bc8189d5e481d1a19481b999d609a1b608482015260a4016105c2565b600080610ac26020870187614b04565b61ffff161180610adb5750600454600160501b900460ff165b15610d07576000610aef6020870187614b04565b61ffff161115610b2a57612710610b096020870187614b04565b61ffff1610610b2a5760405162461bcd60e51b81526004016105c290615126565b610b3d61019060a087016080880161465b565b610b9b5760405162461bcd60e51b815260206004820152602960248201527f6f6e6c79206f776e6572206f722061646d696e2063616e207369676e20666f7260448201526808191a5cd8dbdd5b9d60ba1b60648201526084016105c2565b600a610baa6060870187615441565b604051610bb8929190614ec7565b9081526040519081900360200190205460ff1615610c185760405162461bcd60e51b815260206004820152601960248201527f7369676e617475726520616c7265616479206170706c6965640000000000000060448201526064016105c2565b60a0870151610c6d90610c2e6020880188614b04565b610c3e6040890160208a01614b3a565b610c4e60a08a0160808b0161465b565b610c5b60408b018b615441565b610c6860608d018d615441565b61204a565b610cb95760405162461bcd60e51b815260206004820152601a60248201527f696e76616c696420646973636f756e74207369676e617475726500000000000060448201526064016105c2565b6001600a610cca6060880188615441565b604051610cd8929190614ec7565b90815260405160209181900382019020805460ff191692151592909217909155610d0490860186614b04565b90505b600080610d5389600001518a604001518b606001516001600160401b03168c608001516001600160401b03168d60c001518d8f60e00151610d489190615571565b8f60a001518a612191565b91509150610d9689600001518a60200151838c60a001518d604001518e606001516001600160401b03168f608001516001600160401b03168b6101000151612c91565b95508715610db657610db68960a0015186602001518b60c001518b613773565b610dde89600001518a60e001518b60a001518c60c001518d60400151868a6101000151613877565b806001600160a01b03167f7d230fa887dd4401f152bfcb09c80ceb2c6125f608ef6890e964c9656ba5ac6e8a888b868e60e00151604051610e239594939291906151bd565b60405180910390a2505050505060016000559392505050565b6000816001600160a01b0316610e5a6001546001600160a01b031690565b6001600160a01b0316148061056b575061056b600283613a8b565b33610e886001546001600160a01b031690565b6001600160a01b03161480610ea35750610ea3600233613a8b565b610ebf5760405162461bcd60e51b81526004016105c290615179565b600981604051610ecf9190614ed7565b9081526040519081900360200190205460ff16610f545760405162461bcd60e51b815260206004820152603760248201527f7468652073616c65496420796f75206861766520656e7465726564206973206960448201527f6e76616c69642e20506c656173652076616c696461746500000000000000000060648201526084016105c2565b600781604051610f649190614ed7565b90815260405190819003602001902080546001600160c01b03191681556001810180546001600160a01b0319169055600060028201819055610fa960038301826144c5565b610fb76004830160006144c5565b506005810180546001600160a01b03199081169091556006820180548216905560078201805490911690556008810180546001600160c01b031916905560090180546001600160b01b03191690556040517f09fced985ff97f7dac8f320b7d834e3862ae0274970ffe3dc0d84de5a453899590611035908390615069565b60405180910390a150565b6001546001600160a01b0316331461106a5760405162461bcd60e51b81526004016105c29061507c565b611075600282613a8b565b156110bd5760405133906001600160a01b038316907f7c0c3c84c67c85fcac635147348bfe374c24a1a93d0366d1cfe9d8853cbf89d590600090a36110bb600282613ab0565b505b50565b60606110cc6002613ac5565b6001600160401b038111156110e3576110e3615844565b60405190808252806020026020018201604052801561110c578160200160208202803683370190505b50905060005b61111c6002613ac5565b81101561116a5761112e600282613acf565b8282815181106111405761114061582e565b6001600160a01b039092166020928302919091019091015280611162816157d1565b915050611112565b5090565b336111816001546001600160a01b031690565b6001600160a01b0316148061119c575061119c600233613a8b565b6111b85760405162461bcd60e51b81526004016105c290615179565b60048054911515600160501b0260ff60501b19909216919091179055565b336111e96001546001600160a01b031690565b6001600160a01b031614806112045750611204600233613a8b565b6112205760405162461bcd60e51b81526004016105c290615179565b6000336001600160a01b03831661130657604080516000815260208101918290526001600160a01b03831691479161125791614ed7565b60006040518083038185875af1925050503d8060008114611294576040519150601f19603f3d011682016040523d82523d6000602084013e611299565b606091505b505080925050816113015760405162461bcd60e51b815260206004820152602c60248201527f776974686472617720746f2077697468647261772066756e64732e20506c656160448201526b39b2903a393c9030b3b0b4b760a11b60648201526084016105c2565b505050565b6001600160a01b03831615611301576040516370a0823160e01b81523060048201526000906001600160a01b038516906370a082319060240160206040518083038186803b15801561135757600080fd5b505afa15801561136b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138f9190614b21565b90506113a56001600160a01b0385168383613adb565b50505050565b6001546001600160a01b031633146113d55760405162461bcd60e51b81526004016105c29061507c565b6113e0600282613a8b565b6110bd5760405133906001600160a01b038316907f7e1a1a08d52e4ba0e21554733d66165fd5151f99460116223d9e3a608eec5cb190600090a36110bb600282613b3e565b6001546001600160a01b0316331461144f5760405162461bcd60e51b81526004016105c29061507c565b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b600654604051636e44a72f60e01b81526001600160a01b038481166004830152602482018490526060928392911690636e44a72f9060440160006040518083038186803b1580156114e957600080fd5b505afa1580156114fd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115259190810190614732565b909590945092505050565b336115436001546001600160a01b031690565b6001600160a01b0316148061155e575061155e600233613a8b565b61157a5760405162461bcd60e51b81526004016105c290615179565b600061158e6101a085016101808601614b04565b61ffff16156115d6576115a961018085016101608601614b04565b6115bb6101a086016101808701614b04565b6115c5919061554b565b6115cf908261554b565b9050611606565b6115e861018085016101608601614b04565b6004546115f9919061ffff1661554b565b611603908261554b565b90505b6127108161ffff161061162b5760405162461bcd60e51b81526004016105c290615126565b600061163a6020860186614b60565b6001600160401b03161180156116685750600061165d6040860160208701614b60565b6001600160401b0316115b156117365761167a6020850185614b60565b6001600160401b03166116936040860160208701614b60565b6001600160401b031610156117365760405162461bcd60e51b815260206004820152605f60248201527f54686973206973206e6f7420612076616c6964204e4654207374617274206f7260448201527f20656e6420746f6b656e2049442e20506c65617365207665726966792074686160648201527f74207468652072616e67652070726f766964656420697320636f727265637400608482015260a4016105c2565b61174360a08501856153f8565b905061175260c08601866153f8565b9050146117c75760405162461bcd60e51b815260206004820152603860248201527f73686f756c642070726f7669646520657175616c206c656e67746820696e207060448201527f7269636520616e64207061796d656e742061646472657373000000000000000060648201526084016105c2565b60006117db6101c086016101a087016148dd565b60018111156117ec576117ec615802565b1415611911576118026060850160408601614b60565b6001600160401b03166118615760405162461bcd60e51b815260206004820152602160248201527f73686f756c642070726f76696465206d617843617020666f72206d696e74696e6044820152606760f81b60648201526084016105c2565b61186e6020850185614b60565b6001600160401b031615801561189a575061188f6040850160208601614b60565b6001600160401b0316155b61190c5760405162461bcd60e51b815260206004820152603d60248201527f546865204e46547374617274746f6b656e696420616e64204e4654656e64746f60448201527f6b656e69642073686f756c64206265203020666f72206d696e74696e6700000060648201526084016105c2565b611987565b6119216060850160408601614b60565b6001600160401b0316156119875760405162461bcd60e51b815260206004820152602760248201527f6d61784361702073686f756c64206265203020666f72207072656d696e74656460448201526620746f6b656e7360c81b60648201526084016105c2565b611997608085016060860161465b565b6040516301ffc9a760e01b81526001600160a01b0391909116906301ffc9a7906119cc906380ac58cd60e01b90600401615054565b60206040518083038186803b1580156119e457600080fd5b505afa1580156119f8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a1c919061484e565b80611ab75750611a32608085016060860161465b565b6040516301ffc9a760e01b81526001600160a01b0391909116906301ffc9a790611a6790636cdb3d1360e11b90600401615054565b60206040518083038186803b158015611a7f57600080fd5b505afa158015611a93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab7919061484e565b611b295760405162461bcd60e51b815260206004820152603e60248201527f73686f756c642070726f76696465206f6e6c7920737570706f7274656420636f60448201527f6e747261637420696e746572666163657320455243203732312f31313535000060648201526084016105c2565b6000611b3c610100860160e0870161465b565b6001600160a01b03161415611bae5760405162461bcd60e51b815260206004820152603260248201527f73686f756c642070726f766964652076616c69642077616c6c65742061646472604482015271195cdcc8199bdc881cd95d1d1b195b595b9d60721b60648201526084016105c2565b6000611bc26101208601610100870161465b565b6001600160a01b03161415611c385760405162461bcd60e51b815260206004820152603660248201527f73686f756c642070726f766964652076616c69642077616c6c65742061646472604482015275195cdcc8199bdc881d185e081cd95d1d1b195b595b9d60521b60648201526084016105c2565b60098383604051611c4a929190614ec7565b9081526040519081900360200190205460ff16611cff578360078484604051611c74929190614ec7565b908152604051908190036020019020611c8d82826158bd565b905050600160098484604051611ca4929190614ec7565b908152604051908190036020018120805492151560ff19909316929092179091557f10ad2ba139c14ce12c8f9de79787831cd54ad8c67c6d8106f4af2295cfcf555d90611cf29086906152b3565b60405180910390a16113a5565b60098383604051611d11929190614ec7565b9081526040519081900360200190205460ff16156113a5578360078484604051611d3c929190614ec7565b908152604051908190036020019020611d5582826158bd565b9050507f10ad2ba139c14ce12c8f9de79787831cd54ad8c67c6d8106f4af2295cfcf555d84604051611d8791906152f3565b60405180910390a150505050565b33611da86001546001600160a01b031690565b6001600160a01b03161480611dc35750611dc3600233613a8b565b611ddf5760405162461bcd60e51b81526004016105c290615179565b600480546001600160401b03909416620100000269ffffffffffffffffffff196001600160a01b03978816600160581b02167fff0000000000000000000000000000000000000000ff000000000000000000009095169490941761ffff9095169490941792909217909255600680549284166001600160a01b031993841617905560058054919093169116179055565b60608060078484604051611e84929190614ec7565b9081526040805191829003602090810183206003018054808302850183019093528284529190830182828015611ed957602002820191906000526020600020905b815481526020019060010190808311611ec5575b5050505050915060078484604051611ef2929190614ec7565b9081526040805191829003602090810183206004018054808302850183019093528284529190830182828015611f5157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611f33575b505050505090509250929050565b6001546001600160a01b03163314611f895760405162461bcd60e51b81526004016105c29061507c565b6001600160a01b038116611fee5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016105c2565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000428763ffffffff1610156120b05760405162461bcd60e51b815260206004820152602560248201527f646973636f756e74207369676e617475726520697320616c72656164792065786044820152641c1a5c995960da1b60648201526084016105c2565b856001600160a01b031661217884848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604051612172925061211291508e908e908e908d908d904690602001614e5a565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b90613b53565b6001600160a01b03161490505b98975050505050505050565b600080600060078b6040516121a69190614ed7565b9081526040805191829003602090810183206101608401835280546001600160401b038082168652600160401b8204811686850152600160801b909104168484015260018101546001600160a01b0316606085015260028101546080850152600381018054845181850281018501909552808552919360a086019390929083018282801561225357602002820191906000526020600020905b81548152602001906001019080831161223f575b50505050508152602001600482018054806020026020016040519081016040528092919081815260200182805480156122b557602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612297575b50505091835250506040805160c08101825260058401546001600160a01b0390811682526006850154811660208381019190915260078601548216838501526008860154918216606084015261ffff600160a01b830481166080850152600160b01b90920490911660a0830152830152600983015491019060ff16600181111561234157612341615802565b600181111561235257612352615802565b81526020016009820160019054906101000a900460ff16600181111561237a5761237a615802565b600181111561238b5761238b615802565b8152600991909101546201000090046001600160a01b031660209091015280519091506001600160401b03161580156123d15750600081602001516001600160401b0316115b156124085780602001516001600160401b03168a11156124035760405162461bcd60e51b81526004016105c2906150b1565b6124c9565b80516001600160401b03161580159061242c575060208101516001600160401b0316155b1561245b5780516001600160401b03168a10156124035760405162461bcd60e51b81526004016105c2906150b1565b80516001600160401b0316158015906124815750600081602001516001600160401b0316115b156124c95780516001600160401b03168a108015906124ad575080602001516001600160401b03168a11155b6124c95760405162461bcd60e51b81526004016105c2906150b1565b60608101519150600081610120015160018111156124e9576124e9615802565b1415612580576005546080820151604051630748060b60e31b815260048101919091526001600160a01b03898116602483015290911690633a4030589060440160206040518083038186803b15801561254157600080fd5b505afa158015612555573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125799190614b21565b925061261f565b6001816101200151600181111561259957612599615802565b141561261f5760005b8160c001515181101561261d57876001600160a01b03168260c0015182815181106125cf576125cf61582e565b60200260200101516001600160a01b0316141561260b578160a0015181815181106125fc576125fc61582e565b6020026020010151935061261d565b80612615816157d1565b9150506125a2565b505b826126855760405162461bcd60e51b815260206004820152603060248201527f506c656173652070726f766964652076616c696420737570706f72746564204560448201526f524332302f455448206164647265737360801b60648201526084016105c2565b61ffff8416156126b7576127106126a061ffff8616856155ab565b6126aa9190615589565b6126b490846155ca565b92505b600081610100015160018111156126d0576126d0615802565b1415612954576004546201000090046001600160401b03168811156127935760405162461bcd60e51b815260206004820152606760248201527f546865206d6178696d756d207175616e7469747920616c6c6f77656420746f2060448201527f7075726368617365206174206f6e652074696d652073686f756c64206e6f742060648201527f6265206d6f7265207468616e20646566696e656420696e206d6178313135355160848201526675616e7469747960c81b60a482015260c4016105c2565b6040516301ffc9a760e01b81526001600160a01b038316906301ffc9a7906127c6906380ac58cd60e01b90600401615054565b60206040518083038186803b1580156127de57600080fd5b505afa1580156127f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612816919061484e565b1561282c5761282589846155ab565b9250612980565b6040516301ffc9a760e01b81526001600160a01b038316906301ffc9a79061285f90636cdb3d1360e11b90600401615054565b60206040518083038186803b15801561287757600080fd5b505afa15801561288b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128af919061484e565b1561294f5760405163bd85b03960e01b8152600481018b90526001600160a01b0383169063bd85b0399060240160206040518083038186803b1580156128f457600080fd5b505afa158015612908573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061292c9190614b21565b612945578761293b8a856155ab565b61282591906155ab565b61282588846155ab565b612980565b6001816101000151600181111561296d5761296d615802565b14156129805761297d88846155ab565b92505b6001600160a01b038716612a4557853414801561299d5750828610155b612a405760405162461bcd60e51b815260206004820152606260248201527f496e73756666696369656e742066756e6473206f7220696e76616c696420616d60448201527f6f756e742e20596f75206e65656420746f207061737320612076616c6964206160648201527f6d6f756e7420746f20636f6d706c6574652074686973207472616e736163746960848201526137b760f11b60a482015260c4016105c2565b612c83565b6040516370a0823160e01b81526001600160a01b0386811660048301528791908916906370a082319060240160206040518083038186803b158015612a8957600080fd5b505afa158015612a9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ac19190614b21565b10158015612acf5750828610155b612b5d5760405162461bcd60e51b815260206004820152605360248201527f496e73756666696369656e742066756e64732e20596f752073686f756c64206860448201527f6176652073756666696369656e742062616c616e636520746f20636f6d706c656064820152723a32903a3434b9903a3930b739b0b1ba34b7b760691b608482015260a4016105c2565b604051636eb1769f60e11b81526001600160a01b03868116600483015230602483015287919089169063dd62ed3e9060440160206040518083038186803b158015612ba757600080fd5b505afa158015612bbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bdf9190614b21565b1015612c835760405162461bcd60e51b815260206004820152606160248201527f496e73756666696369656e7420617070726f76616c2066726f6d20616e20455260448201527f43323020546f6b656e2e20506c656173652070726f7669646520617070726f7660648201527f616c20746f207468697320636f6e747261637420616e642074727920616761696084820152603760f91b60a482015260c4016105c2565b509850989650505050505050565b6040516301ffc9a760e01b81526060906001600160a01b038816906301ffc9a790612cc7906380ac58cd60e01b90600401615054565b60206040518083038186803b158015612cdf57600080fd5b505afa158015612cf3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d17919061484e565b156130a6576001826001811115612d3057612d30615802565b1415612e96576040516331a9108f60e11b8152600481018690526001600160a01b03808a169190891690636352211e9060240160206040518083038186803b158015612d7b57600080fd5b505afa158015612d8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612db39190614678565b6001600160a01b031614612e275760405162461bcd60e51b815260206004820152603560248201527f496e76616c6964204e4654204f776e657220416464726573732e20506c656173604482015274329031b432b1b59030b732103a393c9030b3b0b4b760591b60648201526084016105c2565b604051632142170760e11b81526001600160a01b0389811660048301528781166024830152604482018790528816906342842e0e90606401600060405180830381600087803b158015612e7957600080fd5b505af1158015612e8d573d6000803e3d6000fd5b50505050612185565b6000826001811115612eaa57612eaa615802565b14156130a157600789604051612ec09190614ed7565b908152604051908190036020018120546001600160401b03600160801b90910416908590600890612ef2908d90614ed7565b908152602001604051809103902054612f0b9190615571565b1115612fcb5760405162461bcd60e51b815260206004820152607760248201527f546865206d6178696d756d207175616e7469747920616c6c6f77656420746f2060448201527f70757263686173652045524337323120746f6b656e20686173206265656e207360648201527f6f6c64206f75742e20506c6561736520636f6e74616374207468652073616c6560848201527f206f776e657220666f72206d6f72652064657461696c7300000000000000000060a482015260c4016105c2565b60405163e00aab4b60e01b81526001600160a01b03878116600483015261ffff8616602483015288169063e00aab4b90604401600060405180830381600087803b15801561301857600080fd5b505af115801561302c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261305491908101906147fd565b90508360088a6040516130679190614ed7565b9081526020016040518091039020546130809190615571565b60088a6040516130909190614ed7565b908152604051908190036020019020555b612185565b6040516301ffc9a760e01b81526001600160a01b038816906301ffc9a7906130d990636cdb3d1360e11b90600401615054565b60206040518083038186803b1580156130f157600080fd5b505afa158015613105573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613129919061484e565b1561218557600182600181111561314257613142615802565b14156132ca57604051627eeac760e11b81526001600160a01b038981166004830152602482018790526000919089169062fdd58e9060440160206040518083038186803b15801561319257600080fd5b505afa1580156131a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131ca9190614b21565b90508084111580156131dc5750600084115b61323a5760405162461bcd60e51b815260206004820152602960248201527f496e73756666696369656e7420746f6b656e2062616c616e63652066726f6d206044820152683a34329037bbb732b960b91b60648201526084016105c2565b604051637921219560e11b81526001600160a01b038a811660048301528881166024830152604482018890526064820186905260a06084830152600260a483015261060f60f31b60c483015289169063f242432a9060e401600060405180830381600087803b1580156132ac57600080fd5b505af11580156132c0573d6000803e3d6000fd5b5050505050612185565b60008260018111156132de576132de615802565b141561218557604080516001808252818301909252600091602080830190803683370190505090506000856001600160401b0381111561332057613320615844565b604051908082528060200260200182016040528015613349578160200160208202803683370190505b509050606088836000815181106133625761336261582e565b60200260200101906001600160a01b031690816001600160a01b03168152505085826000815181106133965761339661582e565b602090810291909101015260405163bd85b03960e01b8152600481018990526001600160a01b038b169063bd85b0399060240160206040518083038186803b1580156133e157600080fd5b505afa1580156133f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134199190614b21565b61363e5760078c60405161342d9190614ed7565b908152604051908190036020018120546001600160401b03600160801b909104169060089061345d908f90614ed7565b9081526020016040518091039020541061352b5760405162461bcd60e51b815260206004820152607860248201527f546865206d6178696d756d207175616e7469747920616c6c6f77656420746f2060448201527f7075726368617365204552433131353520746f6b656e20686173206265656e2060648201527f736f6c64206f75742e20506c6561736520636f6e74616374207468652073616c60848201527f65206f776e657220666f72206d6f72652064657461696c73000000000000000060a482015260c4016105c2565b60005b8781101561356657868382815181106135495761354961582e565b60209081029190910101528061355e816157d1565b91505061352e565b50604051634637423960e11b81526001600160a01b038b1690638c6e84729061359790869086908690600401614f06565b600060405180830381600087803b1580156135b157600080fd5b505af11580156135c5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526135ed91908101906147fd565b93508660088d6040516136009190614ed7565b9081526020016040518091039020546136199190615571565b60088d6040516136299190614ed7565b90815260405190819003602001902055613764565b60405163bd85b03960e01b8152600481018990526000906001600160a01b038c169063bd85b0399060240160206040518083038186803b15801561368157600080fd5b505afa158015613695573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136b99190614b21565b1115613764576040805160018082528183019092526000916020808301908036833701905050905088816000815181106136f5576136f561582e565b60209081029190910101526040516339b2213760e21b81526001600160a01b038c169063e6c884dc9061373090879085908890600401614f8d565b600060405180830381600087803b15801561374a57600080fd5b505af115801561375e573d6000803e3d6000fd5b50505050505b50505098975050505050505050565b60006001600160a01b03831661385b57604080516000815260208101918290526001600160a01b0386169184916137a991614ed7565b60006040518083038185875af1925050503d80600081146137e6576040519150601f19603f3d011682016040523d82523d6000602084013e6137eb565b606091505b505080915050806138565760405162461bcd60e51b815260206004820152602f60248201527f756e61626c6520746f206465626974206e61746976652062616c616e6365207060448201526e3632b0b9b2903a393c9030b3b0b4b760891b60648201526084016105c2565b613870565b6138706001600160a01b038416868685613b77565b5050505050565b60006007886040516138899190614ed7565b908152604080516020928190038301812060c08201835260058101546001600160a01b0390811683526006820154811694830194909452600781015484169282019290925260089091015491821660608201819052600160a01b830461ffff9081166080840152600160b01b90930490921660a082015291506000901580159061391b575060008260a0015161ffff16115b156139625761395d878360600151886127108660a0015161ffff168d61394191906155ab565b61394b9190615589565b6139559086615571565b945084613773565b6139bb565b600454600160581b90046001600160a01b031615801590613988575060045461ffff1615155b156139bb576004546139bb9088906001600160a01b03600160581b820416908990612710906139419061ffff168e6155ab565b60408201516001600160a01b0316158015906139df57506000826080015161ffff16115b15613a4157612710826080015161ffff16896139fb91906155ab565b613a059190615589565b613a0f9082615571565b9050613a4187836040015188612710866080015161ffff168d613a3291906155ab565b613a3c9190615589565b613773565b613a4b81896155ca565b6006549098506001600160a01b031615613a7057613a6d8786868b8a88613baf565b97505b613a80878360000151888b613773565b505050505050505050565b6001600160a01b038116600090815260018301602052604081205415155b9392505050565b6000613aa9836001600160a01b038416613be5565b600061056b825490565b6000613aa98383613cd8565b6040516001600160a01b03831660248201526044810182905261130190849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613d02565b6000613aa9836001600160a01b038416613dd4565b6000806000613b628585613e23565b91509150613b6f81613e93565b509392505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113a59085906323b872dd60e01b90608401613b07565b60006001826001811115613bc557613bc5615802565b1415613bdb57613bd8878688878761404e565b90505b9695505050505050565b60008181526001830160205260408120548015613cce576000613c096001836155ca565b8554909150600090613c1d906001906155ca565b9050818114613c82576000866000018281548110613c3d57613c3d61582e565b9060005260206000200154905080876000018481548110613c6057613c6061582e565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613c9357613c93615818565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061056b565b600091505061056b565b6000826000018281548110613cef57613cef61582e565b9060005260206000200154905092915050565b6000613d57826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166142319092919063ffffffff16565b8051909150156113015780806020019051810190613d75919061484e565b6113015760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016105c2565b6000818152600183016020526040812054613e1b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561056b565b50600061056b565b600080825160411415613e5a5760208301516040840151606085015160001a613e4e87828585614248565b94509450505050613e8c565b825160401415613e845760208301516040840151613e79868383614335565b935093505050613e8c565b506000905060025b9250929050565b6000816004811115613ea757613ea7615802565b1415613eb05750565b6001816004811115613ec457613ec4615802565b1415613f125760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016105c2565b6002816004811115613f2657613f26615802565b1415613f745760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016105c2565b6003816004811115613f8857613f88615802565b1415613fe15760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016105c2565b6004816004811115613ff557613ff5615802565b14156110bd5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b60648201526084016105c2565b600654604051636e44a72f60e01b81526001600160a01b038681166004830152602482018690526000928592849283928392911690636e44a72f9060440160006040518083038186803b1580156140a457600080fd5b505afa1580156140b8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526140e09190810190614732565b81519193509150806140f9578795505050505050614228565b60005b8181101561421f5760008482815181106141185761411861582e565b602002602001015190506127108a8584815181106141385761413861582e565b602002602001015161414a91906155ab565b6141549190615589565b9550858710156141b45760405162461bcd60e51b815260206004820152602560248201527f696e736f6c76656e743a20756e61626c6520746f20636f6d706c65746520726f60448201526479616c747960d81b60648201526084016105c2565b6141c08d828b89613773565b604080516001600160a01b038e81168252602082018e90528316818301526060810188905290517f866e6ef8682ddf5f1025e64dfdb45527077f7be70fa9ef680b7ffd8cf4ab9c509181900360800190a15094849003946001016140fc565b50939450505050505b95945050505050565b60606142408484600085614364565b949350505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561427f575060009050600361432c565b8460ff16601b1415801561429757508460ff16601c14155b156142a8575060009050600461432c565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156142fc573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166143255760006001925092505061432c565b9150600090505b94509492505050565b6000806001600160ff1b03831660ff84901c601b0161435687828885614248565b935093505050935093915050565b6060824710156143c55760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016105c2565b843b6144135760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105c2565b600080866001600160a01b0316858760405161442f9190614ed7565b60006040518083038185875af1925050503d806000811461446c576040519150601f19603f3d011682016040523d82523d6000602084013e614471565b606091505b509150915061448182828661448c565b979650505050505050565b6060831561449b575081613aa9565b8251156144ab5782518084602001fd5b8160405162461bcd60e51b81526004016105c29190615069565b50805460008255906000526020600020908101906110bd91905b8082111561116a57600081556001016144df565b60006001600160401b0383111561450c5761450c615844565b61451f601f8401601f19166020016154b0565b905082815283838301111561453357600080fd5b828260208301376000602084830101529392505050565b803561455581615a76565b919050565b600082601f83011261456b57600080fd5b8151602061458061457b836154e0565b6154b0565b80838252828201915082860187848660051b89010111156145a057600080fd5b60005b858110156145bf578151845292840192908401906001016145a3565b5090979650505050505050565b803561455581615a99565b60008083601f8401126145e957600080fd5b5081356001600160401b0381111561460057600080fd5b602083019150836020828501011115613e8c57600080fd5b600082601f83011261462957600080fd5b613aa9838335602085016144f3565b600060a0828403121561464a57600080fd5b50919050565b803561455581615ab6565b60006020828403121561466d57600080fd5b8135613aa981615a76565b60006020828403121561468a57600080fd5b8151613aa981615a76565b600080600080600060a086880312156146ad57600080fd5b85356146b881615a76565b945060208601356146c881615aa6565b935060408601356146d881615ab6565b925060608601356146e881615a76565b915060808601356146f881615a76565b809150509295509295909350565b6000806040838503121561471957600080fd5b823561472481615a76565b946020939093013593505050565b6000806040838503121561474557600080fd5b82516001600160401b038082111561475c57600080fd5b818501915085601f83011261477057600080fd5b8151602061478061457b836154e0565b8083825282820191508286018a848660051b89010111156147a057600080fd5b600096505b848710156147cc5780516147b881615a76565b8352600196909601959183019183016147a5565b50918801519196509093505050808211156147e657600080fd5b506147f38582860161455a565b9150509250929050565b60006020828403121561480f57600080fd5b81516001600160401b0381111561482557600080fd5b6142408482850161455a565b60006020828403121561484357600080fd5b8135613aa981615a8b565b60006020828403121561486057600080fd5b8151613aa981615a8b565b60006020828403121561487d57600080fd5b81356001600160e01b031981168114613aa957600080fd5b6000602082840312156148a757600080fd5b81356001600160401b038111156148bd57600080fd5b8201601f810184136148ce57600080fd5b614240848235602084016144f3565b6000602082840312156148ef57600080fd5b8135613aa981615a99565b6000806020838503121561490d57600080fd5b82356001600160401b0381111561492357600080fd5b61492f858286016145d7565b90969095509350505050565b60006020828403121561494d57600080fd5b81356001600160401b0381111561496357600080fd5b61424084828501614618565b60008060006060848603121561498457600080fd5b83356001600160401b038082111561499b57600080fd5b9085019061014082880312156149b057600080fd5b6149b8615487565b8235828111156149c757600080fd5b6149d389828601614618565b8252506149e26020840161454a565b6020820152604083013560408201526149fd60608401614650565b6060820152614a0e60808401614650565b6080820152614a1f60a0840161454a565b60a0820152614a3060c0840161454a565b60c082015260e083013560e0820152610100614a4d81850161454a565b9082015261012092830135928101929092529093506020850135925060408501359080821115614a7c57600080fd5b50614a8986828701614638565b9150509250925092565b600080600060408486031215614aa857600080fd5b83356001600160401b0380821115614abf57600080fd5b908501906102008288031215614ad457600080fd5b90935060208501359080821115614aea57600080fd5b50614af7868287016145d7565b9497909650939450505050565b600060208284031215614b1657600080fd5b8135613aa981615aa6565b600060208284031215614b3357600080fd5b5051919050565b600060208284031215614b4c57600080fd5b813563ffffffff81168114613aa957600080fd5b600060208284031215614b7257600080fd5b8135613aa981615ab6565b8183526000602080850194508260005b85811015614bbb578135614ba081615a76565b6001600160a01b031687529582019590820190600101614b8d565b509495945050505050565b600081518084526020808501945080840160005b83811015614bbb5781516001600160a01b031687529582019590820190600101614bda565b81835260006001600160fb1b03831115614c1857600080fd5b8260051b8083602087013760009401602001938452509192915050565b600081518084526020808501945080840160005b83811015614bbb57815187529582019590820190600101614c49565b614c6e81615a58565b9052565b60008151808452614c8a8160208601602086016156e0565b601f01601f19169290920160200192915050565b6000610200614cbd84614cb085614650565b6001600160401b03169052565b614cc960208401614650565b6001600160401b03166020850152614ce360408401614650565b6001600160401b03166040850152614cfd6060840161454a565b6001600160a01b0316606085015260808381013590850152614d2260a0840184615503565b8260a0870152614d358387018284614bff565b92505050614d4660c0840184615503565b85830360c0870152614d59838284614b7d565b92505050614d6d60e0850160e08501614dc9565b6101a0614d7b8185016145cc565b614d8782870182614c65565b50506101c0614d978185016145cc565b614da382870182614c65565b50506101e0614db381850161454a565b6001600160a01b03169401939093525090919050565b8035614dd481615a76565b6001600160a01b039081168352602082013590614df082615a76565b9081166020840152604082013590614e0782615a76565b9081166040840152606082013590614e1e82615a76565b1660608301526080810135614e3281615aa6565b61ffff908116608084015260a082013590614e4c82615aa6565b80821660a085015250505050565b606087901b6bffffffffffffffffffffffff1916815260f086901b6001600160f01b031916601482015260e085901b6001600160e01b03191660168201528284601a830137694f4e434841494e42555960b01b9201601a8101929092526024820152604401949350505050565b8183823760009101908152919050565b60008251614ee98184602087016156e0565b9190910192915050565b602081526000613aa96020830184614bc6565b606081526000614f196060830186614bc6565b602083820381850152614f2c8287614c35565b915083820360408501528185518084528284019150828160051b85010183880160005b83811015614f7d57601f19878403018552614f6b838351614c72565b94860194925090850190600101614f4f565b50909a9950505050505050505050565b606081526000614fa06060830186614bc6565b8281036020840152614fb28186614c35565b90508281036040840152613bdb8185614c35565b604080825283519082018190526000906020906060840190828701845b828110156150085781516001600160a01b031684529284019290840190600101614fe3565b50505083810382850152613bdb8186614c35565b602081526000613aa96020830184614c35565b6040815260006150426040830185614c35565b82810360208401526142288185614bc6565b6001600160e01b031991909116815260200190565b602081526000613aa96020830184614c72565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252604f908201527f54686973206973206e6f7420612076616c696420746f6b656e49642e20506c6560408201527f6173652076657269667920746861742074686520746f6b656e49642070726f7660608201526e1a591959081a5cc818dbdc9c9958dd608a1b608082015260a00190565b60208082526033908201527f54686520746f74616c2066656520626173697320706f696e742073686f756c646040820152720206265206c657373207468616e20313030303606c1b606082015260800190565b60208082526024908201527f41646d696e436f6e74726f6c3a204d757374206265206f776e6572206f7220616040820152633236b4b760e11b606082015260800190565b60a08152600086516101408060a08501526151dc6101e0850183614c72565b915060208901516151f860c08601826001600160a01b03169052565b50604089015160e0850152606089015161010061521f818701836001600160401b03169052565b60808b0151915061012061523d818801846001600160401b03169052565b60a08c01516001600160a01b039081169488019490945260c08c0151841661016088015260e08c0151610180880152908b01519092166101a0860152508801516101c084015282810360208401526152958188614c35565b60408401969096525050606081019290925260809091015292915050565b6040815260006152c66040830184614c9e565b8281036020840152600b81526a1cd85b1950dc99585d195960aa1b60208201526040810191505092915050565b6040815260006153066040830184614c9e565b8281036020840152600b81526a1cd85b19555c19185d195960aa1b60208201526040810191505092915050565b60006101c0820190506001600160401b03808c168352808b166020840152808a1660408401525060018060a01b0380891660608401528760808401528087511660a08401528060208801511660c08401528060408801511660e08401528060608801511661010084015250608086015161ffff8082166101208501528060a08901511661014085015250506153cc610160830186614c65565b6153da610180830185614c65565b6001600160a01b0383166101a08301529a9950505050505050505050565b6000808335601e1984360301811261540f57600080fd5b8301803591506001600160401b0382111561542957600080fd5b6020019150600581901b3603821315613e8c57600080fd5b6000808335601e1984360301811261545857600080fd5b8301803591506001600160401b0382111561547257600080fd5b602001915036819003821315613e8c57600080fd5b60405161014081016001600160401b03811182821017156154aa576154aa615844565b60405290565b604051601f8201601f191681016001600160401b03811182821017156154d8576154d8615844565b604052919050565b60006001600160401b038211156154f9576154f9615844565b5060051b60200190565b6000808335601e1984360301811261551a57600080fd5b83016020810192503590506001600160401b0381111561553957600080fd5b8060051b3603831315613e8c57600080fd5b600061ffff808316818516808303821115615568576155686157ec565b01949350505050565b60008219821115615584576155846157ec565b500190565b6000826155a657634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156155c5576155c56157ec565b500290565b6000828210156155dc576155dc6157ec565b500390565b81831015611301576000818152602081208481019084015b8082101561560f578282556001820191506155f9565b505050505050565b600160401b83111561562b5761562b615844565b805483825561563b8482846155e1565b50818160005260208060002060005b8681101561568857833561565d81615a76565b82546001600160a01b0319166001600160a01b0391909116178255928201926001918201910161564a565b50505050505050565b600160401b8311156156a5576156a5615844565b80548382556156b58482846155e1565b50818160005260208060002060005b86811015615688578335825592820192600191820191016156c4565b60005b838110156156fb5781810151838201526020016156e3565b838111156113a55750506000910152565b813561571781615a76565b6157218183615881565b50602082013561573081615a76565b61573d8160018401615881565b50604082013561574c81615a76565b6157598160028401615881565b5060038101606083013561576c81615a76565b6157768183615881565b50608083013561578581615aa6565b815461ffff60a01b60a092831b1661ffff60a01b19821681178455918501356157ad81615aa6565b63ffffffff60a01b199190911690911760b09190911b61ffff60b01b161790555050565b60006000198214156157e5576157e56157ec565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6000813561056b81615a76565b6000813561056b81615a99565b6000813561056b81615ab6565b80546001600160a01b0319166001600160a01b0392909216919091179055565b6158aa82615a58565b60ff1981541660ff831681178255505050565b6158e76158c983615874565b825467ffffffffffffffff19166001600160401b0391909116178255565b6159286158f660208401615874565b82546fffffffffffffffff0000000000000000191660409190911b6fffffffffffffffff000000000000000016178255565b61596361593760408401615874565b82805467ffffffffffffffff60801b191660809290921b67ffffffffffffffff60801b16919091179055565b61597b6159726060840161585a565b60018301615881565b6080820135600282015561599260a08301836153f8565b6159a0818360038601615691565b50506159af60c08301836153f8565b6159bd818360048601615617565b50506159cf60e083016005830161570c565b600981016159e96159e36101a08501615867565b826158a1565b6159ff6159f96101c08501615867565b82615a37565b611301615a0f6101e0850161585a565b82805462010000600160b01b03191660109290921b62010000600160b01b0316919091179055565b615a4082615a58565b805461ff008360081b1661ff00198216178255505050565b600281106110bd57634e487b7160e01b600052602160045260246000fd5b6001600160a01b03811681146110bd57600080fd5b80151581146110bd57600080fd5b600281106110bd57600080fd5b61ffff811681146110bd57600080fd5b6001600160401b03811681146110bd57600080fdfea26469706673582212204641c60b73675afdd9a9a7568b10ac3b8b6ce18be959c6ae386dd49d988b9c8a64736f6c63430008070033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000009fd1620fb2e589d1b08812b5e9cee4f0a31a5b5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c830e706eabbd9a4f2f7ed309e5b519a3073d5f200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
-----Decoded View---------------
Arg [0] : _platformAddress (address): 0x9FD1620fb2e589D1b08812B5E9CEE4F0a31a5b50
Arg [1] : _platformFeePercentage (uint16): 0
Arg [2] : _max1155Quantity (uint64): 0
Arg [3] : _priceFeedAddress (address): 0xc830E706eABBd9A4F2F7Ed309E5B519a3073d5f2
Arg [4] : _royaltycontract (address): 0x0000000000000000000000000000000000000000
Arg [5] : _adminApprovalRequired (bool): True
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000009fd1620fb2e589d1b08812b5e9cee4f0a31a5b50
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [3] : 000000000000000000000000c830e706eabbd9a4f2f7ed309e5b519a3073d5f2
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000001
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
CRONOS | 100.00% | $0.192714 | 0.2 | $0.038543 |
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.