Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Multichain Info
Latest 25 from a total of 118 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Buy | 18343549 | 314 days ago | IN | 0.0655 ETH | 0.00212973 | ||||
Buy | 18343435 | 314 days ago | IN | 0.0655 ETH | 0.0020461 | ||||
Buy | 18343202 | 314 days ago | IN | 0.0654 ETH | 0.00277929 | ||||
Buy | 18343119 | 314 days ago | IN | 0.0779 ETH | 0.00202333 | ||||
Buy | 18343102 | 314 days ago | IN | 0.0655 ETH | 0.00201235 | ||||
Buy | 18343045 | 314 days ago | IN | 0.0806 ETH | 0.00348392 | ||||
Buy | 18342753 | 314 days ago | IN | 0.0655 ETH | 0.00519395 | ||||
Buy | 18342372 | 314 days ago | IN | 0.0655 ETH | 0.00309112 | ||||
Buy | 18342328 | 314 days ago | IN | 0.0655 ETH | 0.00228241 | ||||
Buy | 18342270 | 314 days ago | IN | 0.0656 ETH | 0.00180441 | ||||
Buy | 18341866 | 314 days ago | IN | 0.0653 ETH | 0.00275541 | ||||
Buy | 18341656 | 314 days ago | IN | 0.0652 ETH | 0.00198691 | ||||
Buy | 18341516 | 314 days ago | IN | 0.0784 ETH | 0.00220216 | ||||
Buy | 18341354 | 314 days ago | IN | 0.0654 ETH | 0.0017772 | ||||
Buy | 18341343 | 314 days ago | IN | 0.0654 ETH | 0.00160566 | ||||
Buy | 18341200 | 314 days ago | IN | 0.0654 ETH | 0.00178825 | ||||
Buy | 18341185 | 314 days ago | IN | 0.0654 ETH | 0.00141618 | ||||
Buy | 18341128 | 314 days ago | IN | 0.0654 ETH | 0.00123594 | ||||
Buy | 18340547 | 314 days ago | IN | 0.0653 ETH | 0.00134334 | ||||
Buy | 18340522 | 314 days ago | IN | 0.0653 ETH | 0.00143694 | ||||
Buy | 18338027 | 315 days ago | IN | 0.0655 ETH | 0.00151606 | ||||
Buy | 18337979 | 315 days ago | IN | 0.0655 ETH | 0.00215126 | ||||
Buy | 18336824 | 315 days ago | IN | 0.0659 ETH | 0.00192554 | ||||
Buy | 18336401 | 315 days ago | IN | 0.0656 ETH | 0.001674 | ||||
Buy | 18336311 | 315 days ago | IN | 0.0656 ETH | 0.00188373 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
18343549 | 314 days ago | 0.06419 ETH | ||||
18343549 | 314 days ago | 0.00131 ETH | ||||
18343435 | 314 days ago | 0.06419 ETH | ||||
18343435 | 314 days ago | 0.00131 ETH | ||||
18343202 | 314 days ago | 0.064092 ETH | ||||
18343202 | 314 days ago | 0.001308 ETH | ||||
18343119 | 314 days ago | 0.064092 ETH | ||||
18343119 | 314 days ago | 0.001308 ETH | ||||
18343119 | 314 days ago | 0.0125 ETH | ||||
18343102 | 314 days ago | 0.06419 ETH | ||||
18343102 | 314 days ago | 0.00131 ETH | ||||
18343045 | 314 days ago | 0.06419 ETH | ||||
18343045 | 314 days ago | 0.00131 ETH | ||||
18343045 | 314 days ago | 0.0151 ETH | ||||
18342753 | 314 days ago | 0.06419 ETH | ||||
18342753 | 314 days ago | 0.00131 ETH | ||||
18342372 | 314 days ago | 0.06419 ETH | ||||
18342372 | 314 days ago | 0.00131 ETH | ||||
18342328 | 314 days ago | 0.06419 ETH | ||||
18342328 | 314 days ago | 0.00131 ETH | ||||
18342270 | 314 days ago | 0.064288 ETH | ||||
18342270 | 314 days ago | 0.001312 ETH | ||||
18341866 | 314 days ago | 0.063994 ETH | ||||
18341866 | 314 days ago | 0.001306 ETH | ||||
18341656 | 314 days ago | 0.063896 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 public 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 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 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 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 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":[],"name":"adminApprovalRequired","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"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
60806040523480156200001157600080fd5b5060405162005df738038062005df78339810160408190526200003491620001f8565b6001600081815581546001600160a01b031916339081179092556040518291907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506001600160a01b038616620000d65760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420506c6174666f726d2041646472657373000000000000000060448201526064015b60405180910390fd5b6127108561ffff16106200013b5760405162461bcd60e51b815260206004820152602560248201527f706c6174666f726d4665652073686f756c64206265206c657373207468616e20604482015264031303030360dc1b6064820152608401620000cd565b60048054600580546001600160a01b039687166001600160a01b0319918216179091556006805495871695909116949094179093559015156a01000000000000000000000260ff60501b196001600160401b0390951662010000026001600160501b0319949097166b01000000000000000000000002939093167fff0000000000000000000000000000000000000000ff000000000000000000009092169190911761ffff909416939093179390931716919091179055620002ba565b60008060008060008060c087890312156200021257600080fd5b86516200021f81620002a1565b602088015190965061ffff811681146200023857600080fd5b60408801519095506001600160401b03811681146200025657600080fd5b60608801519094506200026981620002a1565b60808801519093506200027c81620002a1565b60a088015190925080151581146200029357600080fd5b809150509295509295509295565b6001600160a01b0381168114620002b757600080fd5b50565b615b2d80620002ca6000396000f3fe6080604052600436106101225760003560e01c8063715018a6116100a55780638f09d4931161006c5780638f09d493146104375780638ff79f9014610457578063a68b91ab14610477578063d78ccb8b146104dd578063df354bdd14610518578063f2fde38b1461054657005b8063715018a614610283578063773fe9861461029857806377dec6c3146102c6578063858a6dc8146103c95780638da5cb5b1461040f57005b80632d345670116100e95780632d345670146101e157806331ae450b14610201578063392541111461022357806351cff8d9146102435780636d73e6691461026357005b806301ffc9a71461012b57806324cfb1a11461016057806324d7806c146101805780632977f78a146101a05780632ca35542146101c057005b3661012957005b005b34801561013757600080fd5b5061014b610146366004614897565b610566565b60405190151581526020015b60405180910390f35b61017361016e36600461499b565b61059d565b6040516101579190615048565b34801561018c57600080fd5b5061014b61019b366004614687565b610e68565b3480156101ac57600080fd5b506101296101bb366004614967565b610ea1565b3480156101cc57600080fd5b5060045461014b90600160501b900460ff1681565b3480156101ed57600080fd5b506101296101fc366004614687565b61106c565b34801561020d57600080fd5b506102166110ec565b6040516101579190614f1f565b34801561022f57600080fd5b5061012961023e36600461485d565b61119a565b34801561024f57600080fd5b5061012961025e366004614687565b611202565b34801561026f57600080fd5b5061012961027e366004614687565b6113d7565b34801561028f57600080fd5b50610129611451565b3480156102a457600080fd5b506102b86102b3366004614732565b6114c5565b604051610157929190614ff2565b3480156102d257600080fd5b506103b46102e1366004614967565b8051808201602090810180516007808352938301948301949094209390528254600184015460028501546040805160c08101825260058801546001600160a01b0390811682526006890154811696820196909652958701548516908601526008860154808516606087015261ffff600160a01b820481166080880152600160b01b9091041660a08601526009909501546001600160401b0380841696600160401b8504821696600160801b90950490911694928316939092909160ff808216926101008304909116916201000090041689565b6040516101579998979695949392919061535f565b3480156103d557600080fd5b506104016103e4366004614967565b805160208183018101805160088252928201919093012091525481565b604051908152602001610157565b34801561041b57600080fd5b506001546040516001600160a01b039091168152602001610157565b34801561044357600080fd5b50610129610452366004614abf565b61155c565b34801561046357600080fd5b506101296104723660046146c1565b611dc1565b34801561048357600080fd5b5060045460055460065460408051600160581b85046001600160a01b03908116825261ffff861660208301529384169181019190915291166060820152620100009091046001600160401b0316608082015260a001610157565b3480156104e957600080fd5b5061014b6104f83660046148c1565b8051602081830181018051600a8252928201919093012091525460ff1681565b34801561052457600080fd5b50610538610533366004614926565b611e9b565b60405161015792919061505b565b34801561055257600080fd5b50610129610561366004614687565b611f8b565b60006001600160e01b03198216632a9f3abf60e11b148061059757506301ffc9a760e01b6001600160e01b03198316145b92915050565b6060600260005414156105f75760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b60026000908155845160405160079161060f91614f03565b908152604080516020928190038301812060c08201835260058101546001600160a01b03908116835260068201548116948301949094526007808201548516838501526008909101549384166060830152600160a01b840461ffff9081166080840152600160b01b90940490931660a0820152875191519093506000929161069691614f03565b9081526040805191829003602090810183206101608401835280546001600160401b038082168652600160401b8204811686850152600160801b909104168484015260018101546001600160a01b0316606085015260028101546080850152600381018054845181850281018501909552808552919360a086019390929083018282801561074357602002820191906000526020600020905b81548152602001906001019080831161072f575b50505050508152602001600482018054806020026020016040519081016040528092919081815260200182805480156107a557602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610787575b50505091835250506040805160c08101825260058401546001600160a01b0390811682526006850154811660208381019190915260078601548216838501526008860154918216606084015261ffff600160a01b830481166080850152600160b01b90920490911660a0830152830152600983015491019060ff1660018111156108315761083161582e565b60018111156108425761084261582e565b81526020016009820160019054906101000a900460ff16600181111561086a5761086a61582e565b600181111561087b5761087b61582e565b81526009918201546201000090046001600160a01b0316602090910152875160405192935090916108ac9190614f03565b9081526040519081900360200190205460ff166108fe5760405162461bcd60e51b815260206004820152601060248201526f756e737570706f727465642073616c6560801b60448201526064016105ee565b61090733610e68565b8061091e575060a08601516001600160a01b031633145b6109a15760405162461bcd60e51b815260206004820152604860248201527f4f6e6c7920746865206275796572206f722061646d696e206f72206f776e657260448201527f206f66207468697320636f6e74726163742063616e2063616c6c207468697320606482015267333ab731ba34b7b760c11b608482015260a4016105ee565b6101408101516001600160a01b031615610ade5761014081015161010087015161012088015160a0890151604051632c10f0e160e11b81526001600160a01b039384166004820152602481019290925282166044820152911690635821e1c290606401602060405180830381600087803b158015610a1e57600080fd5b505af1158015610a32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a56919061487a565b610ade5760405162461bcd60e51b815260206004820152604d60248201527f706c656173652070726f7665646520746865207265717569726564206761746560448201527f6420636f6c6c656374696f6e20616e6420746f6b656e2064657461696c73207460648201526c1bc8189d5e481d1a19481b999d609a1b608482015260a4016105ee565b600080610aee6020870187614b30565b61ffff161180610b075750600454600160501b900460ff165b15610d33576000610b1b6020870187614b30565b61ffff161115610b5657612710610b356020870187614b30565b61ffff1610610b565760405162461bcd60e51b81526004016105ee90615152565b610b6961019b60a0870160808801614687565b610bc75760405162461bcd60e51b815260206004820152602960248201527f6f6e6c79206f776e6572206f722061646d696e2063616e207369676e20666f7260448201526808191a5cd8dbdd5b9d60ba1b60648201526084016105ee565b600a610bd6606087018761546d565b604051610be4929190614ef3565b9081526040519081900360200190205460ff1615610c445760405162461bcd60e51b815260206004820152601960248201527f7369676e617475726520616c7265616479206170706c6965640000000000000060448201526064016105ee565b60a0870151610c9990610c5a6020880188614b30565b610c6a6040890160208a01614b66565b610c7a60a08a0160808b01614687565b610c8760408b018b61546d565b610c9460608d018d61546d565b612076565b610ce55760405162461bcd60e51b815260206004820152601a60248201527f696e76616c696420646973636f756e74207369676e617475726500000000000060448201526064016105ee565b6001600a610cf6606088018861546d565b604051610d04929190614ef3565b90815260405160209181900382019020805460ff191692151592909217909155610d3090860186614b30565b90505b600080610d7f89600001518a604001518b606001516001600160401b03168c608001516001600160401b03168d60c001518d8f60e00151610d74919061559d565b8f60a001518a6121bd565b91509150610dc289600001518a60200151838c60a001518d604001518e606001516001600160401b03168f608001516001600160401b03168b6101000151612cbd565b95508715610de257610de28960a0015186602001518b60c001518b61379f565b610e0a89600001518a60e001518b60a001518c60c001518d60400151868a61010001516138a3565b806001600160a01b03167f7d230fa887dd4401f152bfcb09c80ceb2c6125f608ef6890e964c9656ba5ac6e8a888b868e60e00151604051610e4f9594939291906151e9565b60405180910390a2505050505060016000559392505050565b6000816001600160a01b0316610e866001546001600160a01b031690565b6001600160a01b031614806105975750610597600283613ab7565b33610eb46001546001600160a01b031690565b6001600160a01b03161480610ecf5750610ecf600233613ab7565b610eeb5760405162461bcd60e51b81526004016105ee906151a5565b600981604051610efb9190614f03565b9081526040519081900360200190205460ff16610f805760405162461bcd60e51b815260206004820152603760248201527f7468652073616c65496420796f75206861766520656e7465726564206973206960448201527f6e76616c69642e20506c656173652076616c696461746500000000000000000060648201526084016105ee565b600781604051610f909190614f03565b90815260405190819003602001902080546001600160c01b03191681556001810180546001600160a01b0319169055600060028201819055610fd560038301826144f1565b610fe36004830160006144f1565b506005810180546001600160a01b03199081169091556006820180548216905560078201805490911690556008810180546001600160c01b031916905560090180546001600160b01b03191690556040517f09fced985ff97f7dac8f320b7d834e3862ae0274970ffe3dc0d84de5a453899590611061908390615095565b60405180910390a150565b6001546001600160a01b031633146110965760405162461bcd60e51b81526004016105ee906150a8565b6110a1600282613ab7565b156110e95760405133906001600160a01b038316907f7c0c3c84c67c85fcac635147348bfe374c24a1a93d0366d1cfe9d8853cbf89d590600090a36110e7600282613adc565b505b50565b60606110f86002613af1565b6001600160401b0381111561110f5761110f615870565b604051908082528060200260200182016040528015611138578160200160208202803683370190505b50905060005b6111486002613af1565b8110156111965761115a600282613afb565b82828151811061116c5761116c61585a565b6001600160a01b03909216602092830291909101909101528061118e816157fd565b91505061113e565b5090565b336111ad6001546001600160a01b031690565b6001600160a01b031614806111c857506111c8600233613ab7565b6111e45760405162461bcd60e51b81526004016105ee906151a5565b60048054911515600160501b0260ff60501b19909216919091179055565b336112156001546001600160a01b031690565b6001600160a01b031614806112305750611230600233613ab7565b61124c5760405162461bcd60e51b81526004016105ee906151a5565b6000336001600160a01b03831661133257604080516000815260208101918290526001600160a01b03831691479161128391614f03565b60006040518083038185875af1925050503d80600081146112c0576040519150601f19603f3d011682016040523d82523d6000602084013e6112c5565b606091505b5050809250508161132d5760405162461bcd60e51b815260206004820152602c60248201527f776974686472617720746f2077697468647261772066756e64732e20506c656160448201526b39b2903a393c9030b3b0b4b760a11b60648201526084016105ee565b505050565b6001600160a01b0383161561132d576040516370a0823160e01b81523060048201526000906001600160a01b038516906370a082319060240160206040518083038186803b15801561138357600080fd5b505afa158015611397573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bb9190614b4d565b90506113d16001600160a01b0385168383613b07565b50505050565b6001546001600160a01b031633146114015760405162461bcd60e51b81526004016105ee906150a8565b61140c600282613ab7565b6110e95760405133906001600160a01b038316907f7e1a1a08d52e4ba0e21554733d66165fd5151f99460116223d9e3a608eec5cb190600090a36110e7600282613b6a565b6001546001600160a01b0316331461147b5760405162461bcd60e51b81526004016105ee906150a8565b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b600654604051636e44a72f60e01b81526001600160a01b038481166004830152602482018490526060928392911690636e44a72f9060440160006040518083038186803b15801561151557600080fd5b505afa158015611529573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611551919081019061475e565b909590945092505050565b3361156f6001546001600160a01b031690565b6001600160a01b0316148061158a575061158a600233613ab7565b6115a65760405162461bcd60e51b81526004016105ee906151a5565b60006115ba6101a085016101808601614b30565b61ffff1615611602576115d561018085016101608601614b30565b6115e76101a086016101808701614b30565b6115f19190615577565b6115fb9082615577565b9050611632565b61161461018085016101608601614b30565b600454611625919061ffff16615577565b61162f9082615577565b90505b6127108161ffff16106116575760405162461bcd60e51b81526004016105ee90615152565b60006116666020860186614b8c565b6001600160401b0316118015611694575060006116896040860160208701614b8c565b6001600160401b0316115b15611762576116a66020850185614b8c565b6001600160401b03166116bf6040860160208701614b8c565b6001600160401b031610156117625760405162461bcd60e51b815260206004820152605f60248201527f54686973206973206e6f7420612076616c6964204e4654207374617274206f7260448201527f20656e6420746f6b656e2049442e20506c65617365207665726966792074686160648201527f74207468652072616e67652070726f766964656420697320636f727265637400608482015260a4016105ee565b61176f60a0850185615424565b905061177e60c0860186615424565b9050146117f35760405162461bcd60e51b815260206004820152603860248201527f73686f756c642070726f7669646520657175616c206c656e67746820696e207060448201527f7269636520616e64207061796d656e742061646472657373000000000000000060648201526084016105ee565b60006118076101c086016101a08701614909565b60018111156118185761181861582e565b141561193d5761182e6060850160408601614b8c565b6001600160401b031661188d5760405162461bcd60e51b815260206004820152602160248201527f73686f756c642070726f76696465206d617843617020666f72206d696e74696e6044820152606760f81b60648201526084016105ee565b61189a6020850185614b8c565b6001600160401b03161580156118c657506118bb6040850160208601614b8c565b6001600160401b0316155b6119385760405162461bcd60e51b815260206004820152603d60248201527f546865204e46547374617274746f6b656e696420616e64204e4654656e64746f60448201527f6b656e69642073686f756c64206265203020666f72206d696e74696e6700000060648201526084016105ee565b6119b3565b61194d6060850160408601614b8c565b6001600160401b0316156119b35760405162461bcd60e51b815260206004820152602760248201527f6d61784361702073686f756c64206265203020666f72207072656d696e74656460448201526620746f6b656e7360c81b60648201526084016105ee565b6119c36080850160608601614687565b6040516301ffc9a760e01b81526001600160a01b0391909116906301ffc9a7906119f8906380ac58cd60e01b90600401615080565b60206040518083038186803b158015611a1057600080fd5b505afa158015611a24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a48919061487a565b80611ae35750611a5e6080850160608601614687565b6040516301ffc9a760e01b81526001600160a01b0391909116906301ffc9a790611a9390636cdb3d1360e11b90600401615080565b60206040518083038186803b158015611aab57600080fd5b505afa158015611abf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae3919061487a565b611b555760405162461bcd60e51b815260206004820152603e60248201527f73686f756c642070726f76696465206f6e6c7920737570706f7274656420636f60448201527f6e747261637420696e746572666163657320455243203732312f31313535000060648201526084016105ee565b6000611b68610100860160e08701614687565b6001600160a01b03161415611bda5760405162461bcd60e51b815260206004820152603260248201527f73686f756c642070726f766964652076616c69642077616c6c65742061646472604482015271195cdcc8199bdc881cd95d1d1b195b595b9d60721b60648201526084016105ee565b6000611bee61012086016101008701614687565b6001600160a01b03161415611c645760405162461bcd60e51b815260206004820152603660248201527f73686f756c642070726f766964652076616c69642077616c6c65742061646472604482015275195cdcc8199bdc881d185e081cd95d1d1b195b595b9d60521b60648201526084016105ee565b60098383604051611c76929190614ef3565b9081526040519081900360200190205460ff16611d2b578360078484604051611ca0929190614ef3565b908152604051908190036020019020611cb982826158e9565b905050600160098484604051611cd0929190614ef3565b908152604051908190036020018120805492151560ff19909316929092179091557f10ad2ba139c14ce12c8f9de79787831cd54ad8c67c6d8106f4af2295cfcf555d90611d1e9086906152df565b60405180910390a16113d1565b60098383604051611d3d929190614ef3565b9081526040519081900360200190205460ff16156113d1578360078484604051611d68929190614ef3565b908152604051908190036020019020611d8182826158e9565b9050507f10ad2ba139c14ce12c8f9de79787831cd54ad8c67c6d8106f4af2295cfcf555d84604051611db3919061531f565b60405180910390a150505050565b33611dd46001546001600160a01b031690565b6001600160a01b03161480611def5750611def600233613ab7565b611e0b5760405162461bcd60e51b81526004016105ee906151a5565b600480546001600160401b03909416620100000269ffffffffffffffffffff196001600160a01b03978816600160581b02167fff0000000000000000000000000000000000000000ff000000000000000000009095169490941761ffff9095169490941792909217909255600680549284166001600160a01b031993841617905560058054919093169116179055565b60608060078484604051611eb0929190614ef3565b9081526040805191829003602090810183206003018054808302850183019093528284529190830182828015611f0557602002820191906000526020600020905b815481526020019060010190808311611ef1575b5050505050915060078484604051611f1e929190614ef3565b9081526040805191829003602090810183206004018054808302850183019093528284529190830182828015611f7d57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611f5f575b505050505090509250929050565b6001546001600160a01b03163314611fb55760405162461bcd60e51b81526004016105ee906150a8565b6001600160a01b03811661201a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016105ee565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000428763ffffffff1610156120dc5760405162461bcd60e51b815260206004820152602560248201527f646973636f756e74207369676e617475726520697320616c72656164792065786044820152641c1a5c995960da1b60648201526084016105ee565b856001600160a01b03166121a484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060405161219e925061213e91508e908e908e908d908d904690602001614e86565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b90613b7f565b6001600160a01b03161490505b98975050505050505050565b600080600060078b6040516121d29190614f03565b9081526040805191829003602090810183206101608401835280546001600160401b038082168652600160401b8204811686850152600160801b909104168484015260018101546001600160a01b0316606085015260028101546080850152600381018054845181850281018501909552808552919360a086019390929083018282801561227f57602002820191906000526020600020905b81548152602001906001019080831161226b575b50505050508152602001600482018054806020026020016040519081016040528092919081815260200182805480156122e157602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116122c3575b50505091835250506040805160c08101825260058401546001600160a01b0390811682526006850154811660208381019190915260078601548216838501526008860154918216606084015261ffff600160a01b830481166080850152600160b01b90920490911660a0830152830152600983015491019060ff16600181111561236d5761236d61582e565b600181111561237e5761237e61582e565b81526020016009820160019054906101000a900460ff1660018111156123a6576123a661582e565b60018111156123b7576123b761582e565b8152600991909101546201000090046001600160a01b031660209091015280519091506001600160401b03161580156123fd5750600081602001516001600160401b0316115b156124345780602001516001600160401b03168a111561242f5760405162461bcd60e51b81526004016105ee906150dd565b6124f5565b80516001600160401b031615801590612458575060208101516001600160401b0316155b156124875780516001600160401b03168a101561242f5760405162461bcd60e51b81526004016105ee906150dd565b80516001600160401b0316158015906124ad5750600081602001516001600160401b0316115b156124f55780516001600160401b03168a108015906124d9575080602001516001600160401b03168a11155b6124f55760405162461bcd60e51b81526004016105ee906150dd565b60608101519150600081610120015160018111156125155761251561582e565b14156125ac576005546080820151604051630748060b60e31b815260048101919091526001600160a01b03898116602483015290911690633a4030589060440160206040518083038186803b15801561256d57600080fd5b505afa158015612581573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125a59190614b4d565b925061264b565b600181610120015160018111156125c5576125c561582e565b141561264b5760005b8160c001515181101561264957876001600160a01b03168260c0015182815181106125fb576125fb61585a565b60200260200101516001600160a01b03161415612637578160a0015181815181106126285761262861585a565b60200260200101519350612649565b80612641816157fd565b9150506125ce565b505b826126b15760405162461bcd60e51b815260206004820152603060248201527f506c656173652070726f766964652076616c696420737570706f72746564204560448201526f524332302f455448206164647265737360801b60648201526084016105ee565b61ffff8416156126e3576127106126cc61ffff8616856155d7565b6126d691906155b5565b6126e090846155f6565b92505b600081610100015160018111156126fc576126fc61582e565b1415612980576004546201000090046001600160401b03168811156127bf5760405162461bcd60e51b815260206004820152606760248201527f546865206d6178696d756d207175616e7469747920616c6c6f77656420746f2060448201527f7075726368617365206174206f6e652074696d652073686f756c64206e6f742060648201527f6265206d6f7265207468616e20646566696e656420696e206d6178313135355160848201526675616e7469747960c81b60a482015260c4016105ee565b6040516301ffc9a760e01b81526001600160a01b038316906301ffc9a7906127f2906380ac58cd60e01b90600401615080565b60206040518083038186803b15801561280a57600080fd5b505afa15801561281e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612842919061487a565b156128585761285189846155d7565b92506129ac565b6040516301ffc9a760e01b81526001600160a01b038316906301ffc9a79061288b90636cdb3d1360e11b90600401615080565b60206040518083038186803b1580156128a357600080fd5b505afa1580156128b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128db919061487a565b1561297b5760405163bd85b03960e01b8152600481018b90526001600160a01b0383169063bd85b0399060240160206040518083038186803b15801561292057600080fd5b505afa158015612934573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129589190614b4d565b61297157876129678a856155d7565b61285191906155d7565b61285188846155d7565b6129ac565b600181610100015160018111156129995761299961582e565b14156129ac576129a988846155d7565b92505b6001600160a01b038716612a715785341480156129c95750828610155b612a6c5760405162461bcd60e51b815260206004820152606260248201527f496e73756666696369656e742066756e6473206f7220696e76616c696420616d60448201527f6f756e742e20596f75206e65656420746f207061737320612076616c6964206160648201527f6d6f756e7420746f20636f6d706c6574652074686973207472616e736163746960848201526137b760f11b60a482015260c4016105ee565b612caf565b6040516370a0823160e01b81526001600160a01b0386811660048301528791908916906370a082319060240160206040518083038186803b158015612ab557600080fd5b505afa158015612ac9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aed9190614b4d565b10158015612afb5750828610155b612b895760405162461bcd60e51b815260206004820152605360248201527f496e73756666696369656e742066756e64732e20596f752073686f756c64206860448201527f6176652073756666696369656e742062616c616e636520746f20636f6d706c656064820152723a32903a3434b9903a3930b739b0b1ba34b7b760691b608482015260a4016105ee565b604051636eb1769f60e11b81526001600160a01b03868116600483015230602483015287919089169063dd62ed3e9060440160206040518083038186803b158015612bd357600080fd5b505afa158015612be7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0b9190614b4d565b1015612caf5760405162461bcd60e51b815260206004820152606160248201527f496e73756666696369656e7420617070726f76616c2066726f6d20616e20455260448201527f43323020546f6b656e2e20506c656173652070726f7669646520617070726f7660648201527f616c20746f207468697320636f6e747261637420616e642074727920616761696084820152603760f91b60a482015260c4016105ee565b509850989650505050505050565b6040516301ffc9a760e01b81526060906001600160a01b038816906301ffc9a790612cf3906380ac58cd60e01b90600401615080565b60206040518083038186803b158015612d0b57600080fd5b505afa158015612d1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d43919061487a565b156130d2576001826001811115612d5c57612d5c61582e565b1415612ec2576040516331a9108f60e11b8152600481018690526001600160a01b03808a169190891690636352211e9060240160206040518083038186803b158015612da757600080fd5b505afa158015612dbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddf91906146a4565b6001600160a01b031614612e535760405162461bcd60e51b815260206004820152603560248201527f496e76616c6964204e4654204f776e657220416464726573732e20506c656173604482015274329031b432b1b59030b732103a393c9030b3b0b4b760591b60648201526084016105ee565b604051632142170760e11b81526001600160a01b0389811660048301528781166024830152604482018790528816906342842e0e90606401600060405180830381600087803b158015612ea557600080fd5b505af1158015612eb9573d6000803e3d6000fd5b505050506121b1565b6000826001811115612ed657612ed661582e565b14156130cd57600789604051612eec9190614f03565b908152604051908190036020018120546001600160401b03600160801b90910416908590600890612f1e908d90614f03565b908152602001604051809103902054612f37919061559d565b1115612ff75760405162461bcd60e51b815260206004820152607760248201527f546865206d6178696d756d207175616e7469747920616c6c6f77656420746f2060448201527f70757263686173652045524337323120746f6b656e20686173206265656e207360648201527f6f6c64206f75742e20506c6561736520636f6e74616374207468652073616c6560848201527f206f776e657220666f72206d6f72652064657461696c7300000000000000000060a482015260c4016105ee565b60405163e00aab4b60e01b81526001600160a01b03878116600483015261ffff8616602483015288169063e00aab4b90604401600060405180830381600087803b15801561304457600080fd5b505af1158015613058573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130809190810190614829565b90508360088a6040516130939190614f03565b9081526020016040518091039020546130ac919061559d565b60088a6040516130bc9190614f03565b908152604051908190036020019020555b6121b1565b6040516301ffc9a760e01b81526001600160a01b038816906301ffc9a79061310590636cdb3d1360e11b90600401615080565b60206040518083038186803b15801561311d57600080fd5b505afa158015613131573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613155919061487a565b156121b157600182600181111561316e5761316e61582e565b14156132f657604051627eeac760e11b81526001600160a01b038981166004830152602482018790526000919089169062fdd58e9060440160206040518083038186803b1580156131be57600080fd5b505afa1580156131d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131f69190614b4d565b90508084111580156132085750600084115b6132665760405162461bcd60e51b815260206004820152602960248201527f496e73756666696369656e7420746f6b656e2062616c616e63652066726f6d206044820152683a34329037bbb732b960b91b60648201526084016105ee565b604051637921219560e11b81526001600160a01b038a811660048301528881166024830152604482018890526064820186905260a06084830152600260a483015261060f60f31b60c483015289169063f242432a9060e401600060405180830381600087803b1580156132d857600080fd5b505af11580156132ec573d6000803e3d6000fd5b50505050506121b1565b600082600181111561330a5761330a61582e565b14156121b157604080516001808252818301909252600091602080830190803683370190505090506000856001600160401b0381111561334c5761334c615870565b604051908082528060200260200182016040528015613375578160200160208202803683370190505b5090506060888360008151811061338e5761338e61585a565b60200260200101906001600160a01b031690816001600160a01b03168152505085826000815181106133c2576133c261585a565b602090810291909101015260405163bd85b03960e01b8152600481018990526001600160a01b038b169063bd85b0399060240160206040518083038186803b15801561340d57600080fd5b505afa158015613421573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134459190614b4d565b61366a5760078c6040516134599190614f03565b908152604051908190036020018120546001600160401b03600160801b9091041690600890613489908f90614f03565b908152602001604051809103902054106135575760405162461bcd60e51b815260206004820152607860248201527f546865206d6178696d756d207175616e7469747920616c6c6f77656420746f2060448201527f7075726368617365204552433131353520746f6b656e20686173206265656e2060648201527f736f6c64206f75742e20506c6561736520636f6e74616374207468652073616c60848201527f65206f776e657220666f72206d6f72652064657461696c73000000000000000060a482015260c4016105ee565b60005b8781101561359257868382815181106135755761357561585a565b60209081029190910101528061358a816157fd565b91505061355a565b50604051634637423960e11b81526001600160a01b038b1690638c6e8472906135c390869086908690600401614f32565b600060405180830381600087803b1580156135dd57600080fd5b505af11580156135f1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526136199190810190614829565b93508660088d60405161362c9190614f03565b908152602001604051809103902054613645919061559d565b60088d6040516136559190614f03565b90815260405190819003602001902055613790565b60405163bd85b03960e01b8152600481018990526000906001600160a01b038c169063bd85b0399060240160206040518083038186803b1580156136ad57600080fd5b505afa1580156136c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136e59190614b4d565b1115613790576040805160018082528183019092526000916020808301908036833701905050905088816000815181106137215761372161585a565b60209081029190910101526040516339b2213760e21b81526001600160a01b038c169063e6c884dc9061375c90879085908890600401614fb9565b600060405180830381600087803b15801561377657600080fd5b505af115801561378a573d6000803e3d6000fd5b50505050505b50505098975050505050505050565b60006001600160a01b03831661388757604080516000815260208101918290526001600160a01b0386169184916137d591614f03565b60006040518083038185875af1925050503d8060008114613812576040519150601f19603f3d011682016040523d82523d6000602084013e613817565b606091505b505080915050806138825760405162461bcd60e51b815260206004820152602f60248201527f756e61626c6520746f206465626974206e61746976652062616c616e6365207060448201526e3632b0b9b2903a393c9030b3b0b4b760891b60648201526084016105ee565b61389c565b61389c6001600160a01b038416868685613ba3565b5050505050565b60006007886040516138b59190614f03565b908152604080516020928190038301812060c08201835260058101546001600160a01b0390811683526006820154811694830194909452600781015484169282019290925260089091015491821660608201819052600160a01b830461ffff9081166080840152600160b01b90930490921660a0820152915060009015801590613947575060008260a0015161ffff16115b1561398e57613989878360600151886127108660a0015161ffff168d61396d91906155d7565b61397791906155b5565b613981908661559d565b94508461379f565b6139e7565b600454600160581b90046001600160a01b0316158015906139b4575060045461ffff1615155b156139e7576004546139e79088906001600160a01b03600160581b8204169089906127109061396d9061ffff168e6155d7565b60408201516001600160a01b031615801590613a0b57506000826080015161ffff16115b15613a6d57612710826080015161ffff1689613a2791906155d7565b613a3191906155b5565b613a3b908261559d565b9050613a6d87836040015188612710866080015161ffff168d613a5e91906155d7565b613a6891906155b5565b61379f565b613a7781896155f6565b6006549098506001600160a01b031615613a9c57613a998786868b8a88613bdb565b97505b613aac878360000151888b61379f565b505050505050505050565b6001600160a01b038116600090815260018301602052604081205415155b9392505050565b6000613ad5836001600160a01b038416613c11565b6000610597825490565b6000613ad58383613d04565b6040516001600160a01b03831660248201526044810182905261132d90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613d2e565b6000613ad5836001600160a01b038416613e00565b6000806000613b8e8585613e4f565b91509150613b9b81613ebf565b509392505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113d19085906323b872dd60e01b90608401613b33565b60006001826001811115613bf157613bf161582e565b1415613c0757613c04878688878761407a565b90505b9695505050505050565b60008181526001830160205260408120548015613cfa576000613c356001836155f6565b8554909150600090613c49906001906155f6565b9050818114613cae576000866000018281548110613c6957613c6961585a565b9060005260206000200154905080876000018481548110613c8c57613c8c61585a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613cbf57613cbf615844565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610597565b6000915050610597565b6000826000018281548110613d1b57613d1b61585a565b9060005260206000200154905092915050565b6000613d83826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661425d9092919063ffffffff16565b80519091501561132d5780806020019051810190613da1919061487a565b61132d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016105ee565b6000818152600183016020526040812054613e4757508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610597565b506000610597565b600080825160411415613e865760208301516040840151606085015160001a613e7a87828585614274565b94509450505050613eb8565b825160401415613eb05760208301516040840151613ea5868383614361565b935093505050613eb8565b506000905060025b9250929050565b6000816004811115613ed357613ed361582e565b1415613edc5750565b6001816004811115613ef057613ef061582e565b1415613f3e5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016105ee565b6002816004811115613f5257613f5261582e565b1415613fa05760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016105ee565b6003816004811115613fb457613fb461582e565b141561400d5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016105ee565b60048160048111156140215761402161582e565b14156110e95760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b60648201526084016105ee565b600654604051636e44a72f60e01b81526001600160a01b038681166004830152602482018690526000928592849283928392911690636e44a72f9060440160006040518083038186803b1580156140d057600080fd5b505afa1580156140e4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261410c919081019061475e565b8151919350915080614125578795505050505050614254565b60005b8181101561424b5760008482815181106141445761414461585a565b602002602001015190506127108a8584815181106141645761416461585a565b602002602001015161417691906155d7565b61418091906155b5565b9550858710156141e05760405162461bcd60e51b815260206004820152602560248201527f696e736f6c76656e743a20756e61626c6520746f20636f6d706c65746520726f60448201526479616c747960d81b60648201526084016105ee565b6141ec8d828b8961379f565b604080516001600160a01b038e81168252602082018e90528316818301526060810188905290517f866e6ef8682ddf5f1025e64dfdb45527077f7be70fa9ef680b7ffd8cf4ab9c509181900360800190a1509484900394600101614128565b50939450505050505b95945050505050565b606061426c8484600085614390565b949350505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156142ab5750600090506003614358565b8460ff16601b141580156142c357508460ff16601c14155b156142d45750600090506004614358565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614328573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661435157600060019250925050614358565b9150600090505b94509492505050565b6000806001600160ff1b03831660ff84901c601b0161438287828885614274565b935093505050935093915050565b6060824710156143f15760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016105ee565b843b61443f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105ee565b600080866001600160a01b0316858760405161445b9190614f03565b60006040518083038185875af1925050503d8060008114614498576040519150601f19603f3d011682016040523d82523d6000602084013e61449d565b606091505b50915091506144ad8282866144b8565b979650505050505050565b606083156144c7575081613ad5565b8251156144d75782518084602001fd5b8160405162461bcd60e51b81526004016105ee9190615095565b50805460008255906000526020600020908101906110e991905b80821115611196576000815560010161450b565b60006001600160401b0383111561453857614538615870565b61454b601f8401601f19166020016154dc565b905082815283838301111561455f57600080fd5b828260208301376000602084830101529392505050565b803561458181615aa2565b919050565b600082601f83011261459757600080fd5b815160206145ac6145a78361550c565b6154dc565b80838252828201915082860187848660051b89010111156145cc57600080fd5b60005b858110156145eb578151845292840192908401906001016145cf565b5090979650505050505050565b803561458181615ac5565b60008083601f84011261461557600080fd5b5081356001600160401b0381111561462c57600080fd5b602083019150836020828501011115613eb857600080fd5b600082601f83011261465557600080fd5b613ad58383356020850161451f565b600060a0828403121561467657600080fd5b50919050565b803561458181615ae2565b60006020828403121561469957600080fd5b8135613ad581615aa2565b6000602082840312156146b657600080fd5b8151613ad581615aa2565b600080600080600060a086880312156146d957600080fd5b85356146e481615aa2565b945060208601356146f481615ad2565b9350604086013561470481615ae2565b9250606086013561471481615aa2565b9150608086013561472481615aa2565b809150509295509295909350565b6000806040838503121561474557600080fd5b823561475081615aa2565b946020939093013593505050565b6000806040838503121561477157600080fd5b82516001600160401b038082111561478857600080fd5b818501915085601f83011261479c57600080fd5b815160206147ac6145a78361550c565b8083825282820191508286018a848660051b89010111156147cc57600080fd5b600096505b848710156147f85780516147e481615aa2565b8352600196909601959183019183016147d1565b509188015191965090935050508082111561481257600080fd5b5061481f85828601614586565b9150509250929050565b60006020828403121561483b57600080fd5b81516001600160401b0381111561485157600080fd5b61426c84828501614586565b60006020828403121561486f57600080fd5b8135613ad581615ab7565b60006020828403121561488c57600080fd5b8151613ad581615ab7565b6000602082840312156148a957600080fd5b81356001600160e01b031981168114613ad557600080fd5b6000602082840312156148d357600080fd5b81356001600160401b038111156148e957600080fd5b8201601f810184136148fa57600080fd5b61426c8482356020840161451f565b60006020828403121561491b57600080fd5b8135613ad581615ac5565b6000806020838503121561493957600080fd5b82356001600160401b0381111561494f57600080fd5b61495b85828601614603565b90969095509350505050565b60006020828403121561497957600080fd5b81356001600160401b0381111561498f57600080fd5b61426c84828501614644565b6000806000606084860312156149b057600080fd5b83356001600160401b03808211156149c757600080fd5b9085019061014082880312156149dc57600080fd5b6149e46154b3565b8235828111156149f357600080fd5b6149ff89828601614644565b825250614a0e60208401614576565b602082015260408301356040820152614a296060840161467c565b6060820152614a3a6080840161467c565b6080820152614a4b60a08401614576565b60a0820152614a5c60c08401614576565b60c082015260e083013560e0820152610100614a79818501614576565b9082015261012092830135928101929092529093506020850135925060408501359080821115614aa857600080fd5b50614ab586828701614664565b9150509250925092565b600080600060408486031215614ad457600080fd5b83356001600160401b0380821115614aeb57600080fd5b908501906102008288031215614b0057600080fd5b90935060208501359080821115614b1657600080fd5b50614b2386828701614603565b9497909650939450505050565b600060208284031215614b4257600080fd5b8135613ad581615ad2565b600060208284031215614b5f57600080fd5b5051919050565b600060208284031215614b7857600080fd5b813563ffffffff81168114613ad557600080fd5b600060208284031215614b9e57600080fd5b8135613ad581615ae2565b8183526000602080850194508260005b85811015614be7578135614bcc81615aa2565b6001600160a01b031687529582019590820190600101614bb9565b509495945050505050565b600081518084526020808501945080840160005b83811015614be75781516001600160a01b031687529582019590820190600101614c06565b81835260006001600160fb1b03831115614c4457600080fd5b8260051b8083602087013760009401602001938452509192915050565b600081518084526020808501945080840160005b83811015614be757815187529582019590820190600101614c75565b614c9a81615a84565b9052565b60008151808452614cb681602086016020860161570c565b601f01601f19169290920160200192915050565b6000610200614ce984614cdc8561467c565b6001600160401b03169052565b614cf56020840161467c565b6001600160401b03166020850152614d0f6040840161467c565b6001600160401b03166040850152614d2960608401614576565b6001600160a01b0316606085015260808381013590850152614d4e60a084018461552f565b8260a0870152614d618387018284614c2b565b92505050614d7260c084018461552f565b85830360c0870152614d85838284614ba9565b92505050614d9960e0850160e08501614df5565b6101a0614da78185016145f8565b614db382870182614c91565b50506101c0614dc38185016145f8565b614dcf82870182614c91565b50506101e0614ddf818501614576565b6001600160a01b03169401939093525090919050565b8035614e0081615aa2565b6001600160a01b039081168352602082013590614e1c82615aa2565b9081166020840152604082013590614e3382615aa2565b9081166040840152606082013590614e4a82615aa2565b1660608301526080810135614e5e81615ad2565b61ffff908116608084015260a082013590614e7882615ad2565b80821660a085015250505050565b606087901b6bffffffffffffffffffffffff1916815260f086901b6001600160f01b031916601482015260e085901b6001600160e01b03191660168201528284601a830137694f4e434841494e42555960b01b9201601a8101929092526024820152604401949350505050565b8183823760009101908152919050565b60008251614f1581846020870161570c565b9190910192915050565b602081526000613ad56020830184614bf2565b606081526000614f456060830186614bf2565b602083820381850152614f588287614c61565b915083820360408501528185518084528284019150828160051b85010183880160005b83811015614fa957601f19878403018552614f97838351614c9e565b94860194925090850190600101614f7b565b50909a9950505050505050505050565b606081526000614fcc6060830186614bf2565b8281036020840152614fde8186614c61565b90508281036040840152613c078185614c61565b604080825283519082018190526000906020906060840190828701845b828110156150345781516001600160a01b03168452928401929084019060010161500f565b50505083810382850152613c078186614c61565b602081526000613ad56020830184614c61565b60408152600061506e6040830185614c61565b82810360208401526142548185614bf2565b6001600160e01b031991909116815260200190565b602081526000613ad56020830184614c9e565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252604f908201527f54686973206973206e6f7420612076616c696420746f6b656e49642e20506c6560408201527f6173652076657269667920746861742074686520746f6b656e49642070726f7660608201526e1a591959081a5cc818dbdc9c9958dd608a1b608082015260a00190565b60208082526033908201527f54686520746f74616c2066656520626173697320706f696e742073686f756c646040820152720206265206c657373207468616e20313030303606c1b606082015260800190565b60208082526024908201527f41646d696e436f6e74726f6c3a204d757374206265206f776e6572206f7220616040820152633236b4b760e11b606082015260800190565b60a08152600086516101408060a08501526152086101e0850183614c9e565b9150602089015161522460c08601826001600160a01b03169052565b50604089015160e0850152606089015161010061524b818701836001600160401b03169052565b60808b01519150610120615269818801846001600160401b03169052565b60a08c01516001600160a01b039081169488019490945260c08c0151841661016088015260e08c0151610180880152908b01519092166101a0860152508801516101c084015282810360208401526152c18188614c61565b60408401969096525050606081019290925260809091015292915050565b6040815260006152f26040830184614cca565b8281036020840152600b81526a1cd85b1950dc99585d195960aa1b60208201526040810191505092915050565b6040815260006153326040830184614cca565b8281036020840152600b81526a1cd85b19555c19185d195960aa1b60208201526040810191505092915050565b60006101c0820190506001600160401b03808c168352808b166020840152808a1660408401525060018060a01b0380891660608401528760808401528087511660a08401528060208801511660c08401528060408801511660e08401528060608801511661010084015250608086015161ffff8082166101208501528060a08901511661014085015250506153f8610160830186614c91565b615406610180830185614c91565b6001600160a01b0383166101a08301529a9950505050505050505050565b6000808335601e1984360301811261543b57600080fd5b8301803591506001600160401b0382111561545557600080fd5b6020019150600581901b3603821315613eb857600080fd5b6000808335601e1984360301811261548457600080fd5b8301803591506001600160401b0382111561549e57600080fd5b602001915036819003821315613eb857600080fd5b60405161014081016001600160401b03811182821017156154d6576154d6615870565b60405290565b604051601f8201601f191681016001600160401b038111828210171561550457615504615870565b604052919050565b60006001600160401b0382111561552557615525615870565b5060051b60200190565b6000808335601e1984360301811261554657600080fd5b83016020810192503590506001600160401b0381111561556557600080fd5b8060051b3603831315613eb857600080fd5b600061ffff80831681851680830382111561559457615594615818565b01949350505050565b600082198211156155b0576155b0615818565b500190565b6000826155d257634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156155f1576155f1615818565b500290565b60008282101561560857615608615818565b500390565b8183101561132d576000818152602081208481019084015b8082101561563b57828255600182019150615625565b505050505050565b600160401b83111561565757615657615870565b805483825561566784828461560d565b50818160005260208060002060005b868110156156b457833561568981615aa2565b82546001600160a01b0319166001600160a01b03919091161782559282019260019182019101615676565b50505050505050565b600160401b8311156156d1576156d1615870565b80548382556156e184828461560d565b50818160005260208060002060005b868110156156b4578335825592820192600191820191016156f0565b60005b8381101561572757818101518382015260200161570f565b838111156113d15750506000910152565b813561574381615aa2565b61574d81836158ad565b50602082013561575c81615aa2565b61576981600184016158ad565b50604082013561577881615aa2565b61578581600284016158ad565b5060038101606083013561579881615aa2565b6157a281836158ad565b5060808301356157b181615ad2565b815461ffff60a01b60a092831b1661ffff60a01b19821681178455918501356157d981615ad2565b63ffffffff60a01b199190911690911760b09190911b61ffff60b01b161790555050565b600060001982141561581157615811615818565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6000813561059781615aa2565b6000813561059781615ac5565b6000813561059781615ae2565b80546001600160a01b0319166001600160a01b0392909216919091179055565b6158d682615a84565b60ff1981541660ff831681178255505050565b6159136158f5836158a0565b825467ffffffffffffffff19166001600160401b0391909116178255565b615954615922602084016158a0565b82546fffffffffffffffff0000000000000000191660409190911b6fffffffffffffffff000000000000000016178255565b61598f615963604084016158a0565b82805467ffffffffffffffff60801b191660809290921b67ffffffffffffffff60801b16919091179055565b6159a761599e60608401615886565b600183016158ad565b608082013560028201556159be60a0830183615424565b6159cc8183600386016156bd565b50506159db60c0830183615424565b6159e9818360048601615643565b50506159fb60e0830160058301615738565b60098101615a15615a0f6101a08501615893565b826158cd565b615a2b615a256101c08501615893565b82615a63565b61132d615a3b6101e08501615886565b82805462010000600160b01b03191660109290921b62010000600160b01b0316919091179055565b615a6c82615a84565b805461ff008360081b1661ff00198216178255505050565b600281106110e957634e487b7160e01b600052602160045260246000fd5b6001600160a01b03811681146110e957600080fd5b80151581146110e957600080fd5b600281106110e957600080fd5b61ffff811681146110e957600080fd5b6001600160401b03811681146110e957600080fdfea26469706673582212206711fa78f1aa3025eab19d77c1a4281493c43f3c7b76ac6e1916a498d87dd0df64736f6c63430008070033000000000000000000000000c0d66432e3fd40da54aadcff899add918625373100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c830e706eabbd9a4f2f7ed309e5b519a3073d5f200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106101225760003560e01c8063715018a6116100a55780638f09d4931161006c5780638f09d493146104375780638ff79f9014610457578063a68b91ab14610477578063d78ccb8b146104dd578063df354bdd14610518578063f2fde38b1461054657005b8063715018a614610283578063773fe9861461029857806377dec6c3146102c6578063858a6dc8146103c95780638da5cb5b1461040f57005b80632d345670116100e95780632d345670146101e157806331ae450b14610201578063392541111461022357806351cff8d9146102435780636d73e6691461026357005b806301ffc9a71461012b57806324cfb1a11461016057806324d7806c146101805780632977f78a146101a05780632ca35542146101c057005b3661012957005b005b34801561013757600080fd5b5061014b610146366004614897565b610566565b60405190151581526020015b60405180910390f35b61017361016e36600461499b565b61059d565b6040516101579190615048565b34801561018c57600080fd5b5061014b61019b366004614687565b610e68565b3480156101ac57600080fd5b506101296101bb366004614967565b610ea1565b3480156101cc57600080fd5b5060045461014b90600160501b900460ff1681565b3480156101ed57600080fd5b506101296101fc366004614687565b61106c565b34801561020d57600080fd5b506102166110ec565b6040516101579190614f1f565b34801561022f57600080fd5b5061012961023e36600461485d565b61119a565b34801561024f57600080fd5b5061012961025e366004614687565b611202565b34801561026f57600080fd5b5061012961027e366004614687565b6113d7565b34801561028f57600080fd5b50610129611451565b3480156102a457600080fd5b506102b86102b3366004614732565b6114c5565b604051610157929190614ff2565b3480156102d257600080fd5b506103b46102e1366004614967565b8051808201602090810180516007808352938301948301949094209390528254600184015460028501546040805160c08101825260058801546001600160a01b0390811682526006890154811696820196909652958701548516908601526008860154808516606087015261ffff600160a01b820481166080880152600160b01b9091041660a08601526009909501546001600160401b0380841696600160401b8504821696600160801b90950490911694928316939092909160ff808216926101008304909116916201000090041689565b6040516101579998979695949392919061535f565b3480156103d557600080fd5b506104016103e4366004614967565b805160208183018101805160088252928201919093012091525481565b604051908152602001610157565b34801561041b57600080fd5b506001546040516001600160a01b039091168152602001610157565b34801561044357600080fd5b50610129610452366004614abf565b61155c565b34801561046357600080fd5b506101296104723660046146c1565b611dc1565b34801561048357600080fd5b5060045460055460065460408051600160581b85046001600160a01b03908116825261ffff861660208301529384169181019190915291166060820152620100009091046001600160401b0316608082015260a001610157565b3480156104e957600080fd5b5061014b6104f83660046148c1565b8051602081830181018051600a8252928201919093012091525460ff1681565b34801561052457600080fd5b50610538610533366004614926565b611e9b565b60405161015792919061505b565b34801561055257600080fd5b50610129610561366004614687565b611f8b565b60006001600160e01b03198216632a9f3abf60e11b148061059757506301ffc9a760e01b6001600160e01b03198316145b92915050565b6060600260005414156105f75760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b60026000908155845160405160079161060f91614f03565b908152604080516020928190038301812060c08201835260058101546001600160a01b03908116835260068201548116948301949094526007808201548516838501526008909101549384166060830152600160a01b840461ffff9081166080840152600160b01b90940490931660a0820152875191519093506000929161069691614f03565b9081526040805191829003602090810183206101608401835280546001600160401b038082168652600160401b8204811686850152600160801b909104168484015260018101546001600160a01b0316606085015260028101546080850152600381018054845181850281018501909552808552919360a086019390929083018282801561074357602002820191906000526020600020905b81548152602001906001019080831161072f575b50505050508152602001600482018054806020026020016040519081016040528092919081815260200182805480156107a557602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610787575b50505091835250506040805160c08101825260058401546001600160a01b0390811682526006850154811660208381019190915260078601548216838501526008860154918216606084015261ffff600160a01b830481166080850152600160b01b90920490911660a0830152830152600983015491019060ff1660018111156108315761083161582e565b60018111156108425761084261582e565b81526020016009820160019054906101000a900460ff16600181111561086a5761086a61582e565b600181111561087b5761087b61582e565b81526009918201546201000090046001600160a01b0316602090910152875160405192935090916108ac9190614f03565b9081526040519081900360200190205460ff166108fe5760405162461bcd60e51b815260206004820152601060248201526f756e737570706f727465642073616c6560801b60448201526064016105ee565b61090733610e68565b8061091e575060a08601516001600160a01b031633145b6109a15760405162461bcd60e51b815260206004820152604860248201527f4f6e6c7920746865206275796572206f722061646d696e206f72206f776e657260448201527f206f66207468697320636f6e74726163742063616e2063616c6c207468697320606482015267333ab731ba34b7b760c11b608482015260a4016105ee565b6101408101516001600160a01b031615610ade5761014081015161010087015161012088015160a0890151604051632c10f0e160e11b81526001600160a01b039384166004820152602481019290925282166044820152911690635821e1c290606401602060405180830381600087803b158015610a1e57600080fd5b505af1158015610a32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a56919061487a565b610ade5760405162461bcd60e51b815260206004820152604d60248201527f706c656173652070726f7665646520746865207265717569726564206761746560448201527f6420636f6c6c656374696f6e20616e6420746f6b656e2064657461696c73207460648201526c1bc8189d5e481d1a19481b999d609a1b608482015260a4016105ee565b600080610aee6020870187614b30565b61ffff161180610b075750600454600160501b900460ff165b15610d33576000610b1b6020870187614b30565b61ffff161115610b5657612710610b356020870187614b30565b61ffff1610610b565760405162461bcd60e51b81526004016105ee90615152565b610b6961019b60a0870160808801614687565b610bc75760405162461bcd60e51b815260206004820152602960248201527f6f6e6c79206f776e6572206f722061646d696e2063616e207369676e20666f7260448201526808191a5cd8dbdd5b9d60ba1b60648201526084016105ee565b600a610bd6606087018761546d565b604051610be4929190614ef3565b9081526040519081900360200190205460ff1615610c445760405162461bcd60e51b815260206004820152601960248201527f7369676e617475726520616c7265616479206170706c6965640000000000000060448201526064016105ee565b60a0870151610c9990610c5a6020880188614b30565b610c6a6040890160208a01614b66565b610c7a60a08a0160808b01614687565b610c8760408b018b61546d565b610c9460608d018d61546d565b612076565b610ce55760405162461bcd60e51b815260206004820152601a60248201527f696e76616c696420646973636f756e74207369676e617475726500000000000060448201526064016105ee565b6001600a610cf6606088018861546d565b604051610d04929190614ef3565b90815260405160209181900382019020805460ff191692151592909217909155610d3090860186614b30565b90505b600080610d7f89600001518a604001518b606001516001600160401b03168c608001516001600160401b03168d60c001518d8f60e00151610d74919061559d565b8f60a001518a6121bd565b91509150610dc289600001518a60200151838c60a001518d604001518e606001516001600160401b03168f608001516001600160401b03168b6101000151612cbd565b95508715610de257610de28960a0015186602001518b60c001518b61379f565b610e0a89600001518a60e001518b60a001518c60c001518d60400151868a61010001516138a3565b806001600160a01b03167f7d230fa887dd4401f152bfcb09c80ceb2c6125f608ef6890e964c9656ba5ac6e8a888b868e60e00151604051610e4f9594939291906151e9565b60405180910390a2505050505060016000559392505050565b6000816001600160a01b0316610e866001546001600160a01b031690565b6001600160a01b031614806105975750610597600283613ab7565b33610eb46001546001600160a01b031690565b6001600160a01b03161480610ecf5750610ecf600233613ab7565b610eeb5760405162461bcd60e51b81526004016105ee906151a5565b600981604051610efb9190614f03565b9081526040519081900360200190205460ff16610f805760405162461bcd60e51b815260206004820152603760248201527f7468652073616c65496420796f75206861766520656e7465726564206973206960448201527f6e76616c69642e20506c656173652076616c696461746500000000000000000060648201526084016105ee565b600781604051610f909190614f03565b90815260405190819003602001902080546001600160c01b03191681556001810180546001600160a01b0319169055600060028201819055610fd560038301826144f1565b610fe36004830160006144f1565b506005810180546001600160a01b03199081169091556006820180548216905560078201805490911690556008810180546001600160c01b031916905560090180546001600160b01b03191690556040517f09fced985ff97f7dac8f320b7d834e3862ae0274970ffe3dc0d84de5a453899590611061908390615095565b60405180910390a150565b6001546001600160a01b031633146110965760405162461bcd60e51b81526004016105ee906150a8565b6110a1600282613ab7565b156110e95760405133906001600160a01b038316907f7c0c3c84c67c85fcac635147348bfe374c24a1a93d0366d1cfe9d8853cbf89d590600090a36110e7600282613adc565b505b50565b60606110f86002613af1565b6001600160401b0381111561110f5761110f615870565b604051908082528060200260200182016040528015611138578160200160208202803683370190505b50905060005b6111486002613af1565b8110156111965761115a600282613afb565b82828151811061116c5761116c61585a565b6001600160a01b03909216602092830291909101909101528061118e816157fd565b91505061113e565b5090565b336111ad6001546001600160a01b031690565b6001600160a01b031614806111c857506111c8600233613ab7565b6111e45760405162461bcd60e51b81526004016105ee906151a5565b60048054911515600160501b0260ff60501b19909216919091179055565b336112156001546001600160a01b031690565b6001600160a01b031614806112305750611230600233613ab7565b61124c5760405162461bcd60e51b81526004016105ee906151a5565b6000336001600160a01b03831661133257604080516000815260208101918290526001600160a01b03831691479161128391614f03565b60006040518083038185875af1925050503d80600081146112c0576040519150601f19603f3d011682016040523d82523d6000602084013e6112c5565b606091505b5050809250508161132d5760405162461bcd60e51b815260206004820152602c60248201527f776974686472617720746f2077697468647261772066756e64732e20506c656160448201526b39b2903a393c9030b3b0b4b760a11b60648201526084016105ee565b505050565b6001600160a01b0383161561132d576040516370a0823160e01b81523060048201526000906001600160a01b038516906370a082319060240160206040518083038186803b15801561138357600080fd5b505afa158015611397573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bb9190614b4d565b90506113d16001600160a01b0385168383613b07565b50505050565b6001546001600160a01b031633146114015760405162461bcd60e51b81526004016105ee906150a8565b61140c600282613ab7565b6110e95760405133906001600160a01b038316907f7e1a1a08d52e4ba0e21554733d66165fd5151f99460116223d9e3a608eec5cb190600090a36110e7600282613b6a565b6001546001600160a01b0316331461147b5760405162461bcd60e51b81526004016105ee906150a8565b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b600654604051636e44a72f60e01b81526001600160a01b038481166004830152602482018490526060928392911690636e44a72f9060440160006040518083038186803b15801561151557600080fd5b505afa158015611529573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611551919081019061475e565b909590945092505050565b3361156f6001546001600160a01b031690565b6001600160a01b0316148061158a575061158a600233613ab7565b6115a65760405162461bcd60e51b81526004016105ee906151a5565b60006115ba6101a085016101808601614b30565b61ffff1615611602576115d561018085016101608601614b30565b6115e76101a086016101808701614b30565b6115f19190615577565b6115fb9082615577565b9050611632565b61161461018085016101608601614b30565b600454611625919061ffff16615577565b61162f9082615577565b90505b6127108161ffff16106116575760405162461bcd60e51b81526004016105ee90615152565b60006116666020860186614b8c565b6001600160401b0316118015611694575060006116896040860160208701614b8c565b6001600160401b0316115b15611762576116a66020850185614b8c565b6001600160401b03166116bf6040860160208701614b8c565b6001600160401b031610156117625760405162461bcd60e51b815260206004820152605f60248201527f54686973206973206e6f7420612076616c6964204e4654207374617274206f7260448201527f20656e6420746f6b656e2049442e20506c65617365207665726966792074686160648201527f74207468652072616e67652070726f766964656420697320636f727265637400608482015260a4016105ee565b61176f60a0850185615424565b905061177e60c0860186615424565b9050146117f35760405162461bcd60e51b815260206004820152603860248201527f73686f756c642070726f7669646520657175616c206c656e67746820696e207060448201527f7269636520616e64207061796d656e742061646472657373000000000000000060648201526084016105ee565b60006118076101c086016101a08701614909565b60018111156118185761181861582e565b141561193d5761182e6060850160408601614b8c565b6001600160401b031661188d5760405162461bcd60e51b815260206004820152602160248201527f73686f756c642070726f76696465206d617843617020666f72206d696e74696e6044820152606760f81b60648201526084016105ee565b61189a6020850185614b8c565b6001600160401b03161580156118c657506118bb6040850160208601614b8c565b6001600160401b0316155b6119385760405162461bcd60e51b815260206004820152603d60248201527f546865204e46547374617274746f6b656e696420616e64204e4654656e64746f60448201527f6b656e69642073686f756c64206265203020666f72206d696e74696e6700000060648201526084016105ee565b6119b3565b61194d6060850160408601614b8c565b6001600160401b0316156119b35760405162461bcd60e51b815260206004820152602760248201527f6d61784361702073686f756c64206265203020666f72207072656d696e74656460448201526620746f6b656e7360c81b60648201526084016105ee565b6119c36080850160608601614687565b6040516301ffc9a760e01b81526001600160a01b0391909116906301ffc9a7906119f8906380ac58cd60e01b90600401615080565b60206040518083038186803b158015611a1057600080fd5b505afa158015611a24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a48919061487a565b80611ae35750611a5e6080850160608601614687565b6040516301ffc9a760e01b81526001600160a01b0391909116906301ffc9a790611a9390636cdb3d1360e11b90600401615080565b60206040518083038186803b158015611aab57600080fd5b505afa158015611abf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae3919061487a565b611b555760405162461bcd60e51b815260206004820152603e60248201527f73686f756c642070726f76696465206f6e6c7920737570706f7274656420636f60448201527f6e747261637420696e746572666163657320455243203732312f31313535000060648201526084016105ee565b6000611b68610100860160e08701614687565b6001600160a01b03161415611bda5760405162461bcd60e51b815260206004820152603260248201527f73686f756c642070726f766964652076616c69642077616c6c65742061646472604482015271195cdcc8199bdc881cd95d1d1b195b595b9d60721b60648201526084016105ee565b6000611bee61012086016101008701614687565b6001600160a01b03161415611c645760405162461bcd60e51b815260206004820152603660248201527f73686f756c642070726f766964652076616c69642077616c6c65742061646472604482015275195cdcc8199bdc881d185e081cd95d1d1b195b595b9d60521b60648201526084016105ee565b60098383604051611c76929190614ef3565b9081526040519081900360200190205460ff16611d2b578360078484604051611ca0929190614ef3565b908152604051908190036020019020611cb982826158e9565b905050600160098484604051611cd0929190614ef3565b908152604051908190036020018120805492151560ff19909316929092179091557f10ad2ba139c14ce12c8f9de79787831cd54ad8c67c6d8106f4af2295cfcf555d90611d1e9086906152df565b60405180910390a16113d1565b60098383604051611d3d929190614ef3565b9081526040519081900360200190205460ff16156113d1578360078484604051611d68929190614ef3565b908152604051908190036020019020611d8182826158e9565b9050507f10ad2ba139c14ce12c8f9de79787831cd54ad8c67c6d8106f4af2295cfcf555d84604051611db3919061531f565b60405180910390a150505050565b33611dd46001546001600160a01b031690565b6001600160a01b03161480611def5750611def600233613ab7565b611e0b5760405162461bcd60e51b81526004016105ee906151a5565b600480546001600160401b03909416620100000269ffffffffffffffffffff196001600160a01b03978816600160581b02167fff0000000000000000000000000000000000000000ff000000000000000000009095169490941761ffff9095169490941792909217909255600680549284166001600160a01b031993841617905560058054919093169116179055565b60608060078484604051611eb0929190614ef3565b9081526040805191829003602090810183206003018054808302850183019093528284529190830182828015611f0557602002820191906000526020600020905b815481526020019060010190808311611ef1575b5050505050915060078484604051611f1e929190614ef3565b9081526040805191829003602090810183206004018054808302850183019093528284529190830182828015611f7d57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611f5f575b505050505090509250929050565b6001546001600160a01b03163314611fb55760405162461bcd60e51b81526004016105ee906150a8565b6001600160a01b03811661201a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016105ee565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000428763ffffffff1610156120dc5760405162461bcd60e51b815260206004820152602560248201527f646973636f756e74207369676e617475726520697320616c72656164792065786044820152641c1a5c995960da1b60648201526084016105ee565b856001600160a01b03166121a484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060405161219e925061213e91508e908e908e908d908d904690602001614e86565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b90613b7f565b6001600160a01b03161490505b98975050505050505050565b600080600060078b6040516121d29190614f03565b9081526040805191829003602090810183206101608401835280546001600160401b038082168652600160401b8204811686850152600160801b909104168484015260018101546001600160a01b0316606085015260028101546080850152600381018054845181850281018501909552808552919360a086019390929083018282801561227f57602002820191906000526020600020905b81548152602001906001019080831161226b575b50505050508152602001600482018054806020026020016040519081016040528092919081815260200182805480156122e157602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116122c3575b50505091835250506040805160c08101825260058401546001600160a01b0390811682526006850154811660208381019190915260078601548216838501526008860154918216606084015261ffff600160a01b830481166080850152600160b01b90920490911660a0830152830152600983015491019060ff16600181111561236d5761236d61582e565b600181111561237e5761237e61582e565b81526020016009820160019054906101000a900460ff1660018111156123a6576123a661582e565b60018111156123b7576123b761582e565b8152600991909101546201000090046001600160a01b031660209091015280519091506001600160401b03161580156123fd5750600081602001516001600160401b0316115b156124345780602001516001600160401b03168a111561242f5760405162461bcd60e51b81526004016105ee906150dd565b6124f5565b80516001600160401b031615801590612458575060208101516001600160401b0316155b156124875780516001600160401b03168a101561242f5760405162461bcd60e51b81526004016105ee906150dd565b80516001600160401b0316158015906124ad5750600081602001516001600160401b0316115b156124f55780516001600160401b03168a108015906124d9575080602001516001600160401b03168a11155b6124f55760405162461bcd60e51b81526004016105ee906150dd565b60608101519150600081610120015160018111156125155761251561582e565b14156125ac576005546080820151604051630748060b60e31b815260048101919091526001600160a01b03898116602483015290911690633a4030589060440160206040518083038186803b15801561256d57600080fd5b505afa158015612581573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125a59190614b4d565b925061264b565b600181610120015160018111156125c5576125c561582e565b141561264b5760005b8160c001515181101561264957876001600160a01b03168260c0015182815181106125fb576125fb61585a565b60200260200101516001600160a01b03161415612637578160a0015181815181106126285761262861585a565b60200260200101519350612649565b80612641816157fd565b9150506125ce565b505b826126b15760405162461bcd60e51b815260206004820152603060248201527f506c656173652070726f766964652076616c696420737570706f72746564204560448201526f524332302f455448206164647265737360801b60648201526084016105ee565b61ffff8416156126e3576127106126cc61ffff8616856155d7565b6126d691906155b5565b6126e090846155f6565b92505b600081610100015160018111156126fc576126fc61582e565b1415612980576004546201000090046001600160401b03168811156127bf5760405162461bcd60e51b815260206004820152606760248201527f546865206d6178696d756d207175616e7469747920616c6c6f77656420746f2060448201527f7075726368617365206174206f6e652074696d652073686f756c64206e6f742060648201527f6265206d6f7265207468616e20646566696e656420696e206d6178313135355160848201526675616e7469747960c81b60a482015260c4016105ee565b6040516301ffc9a760e01b81526001600160a01b038316906301ffc9a7906127f2906380ac58cd60e01b90600401615080565b60206040518083038186803b15801561280a57600080fd5b505afa15801561281e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612842919061487a565b156128585761285189846155d7565b92506129ac565b6040516301ffc9a760e01b81526001600160a01b038316906301ffc9a79061288b90636cdb3d1360e11b90600401615080565b60206040518083038186803b1580156128a357600080fd5b505afa1580156128b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128db919061487a565b1561297b5760405163bd85b03960e01b8152600481018b90526001600160a01b0383169063bd85b0399060240160206040518083038186803b15801561292057600080fd5b505afa158015612934573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129589190614b4d565b61297157876129678a856155d7565b61285191906155d7565b61285188846155d7565b6129ac565b600181610100015160018111156129995761299961582e565b14156129ac576129a988846155d7565b92505b6001600160a01b038716612a715785341480156129c95750828610155b612a6c5760405162461bcd60e51b815260206004820152606260248201527f496e73756666696369656e742066756e6473206f7220696e76616c696420616d60448201527f6f756e742e20596f75206e65656420746f207061737320612076616c6964206160648201527f6d6f756e7420746f20636f6d706c6574652074686973207472616e736163746960848201526137b760f11b60a482015260c4016105ee565b612caf565b6040516370a0823160e01b81526001600160a01b0386811660048301528791908916906370a082319060240160206040518083038186803b158015612ab557600080fd5b505afa158015612ac9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aed9190614b4d565b10158015612afb5750828610155b612b895760405162461bcd60e51b815260206004820152605360248201527f496e73756666696369656e742066756e64732e20596f752073686f756c64206860448201527f6176652073756666696369656e742062616c616e636520746f20636f6d706c656064820152723a32903a3434b9903a3930b739b0b1ba34b7b760691b608482015260a4016105ee565b604051636eb1769f60e11b81526001600160a01b03868116600483015230602483015287919089169063dd62ed3e9060440160206040518083038186803b158015612bd357600080fd5b505afa158015612be7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0b9190614b4d565b1015612caf5760405162461bcd60e51b815260206004820152606160248201527f496e73756666696369656e7420617070726f76616c2066726f6d20616e20455260448201527f43323020546f6b656e2e20506c656173652070726f7669646520617070726f7660648201527f616c20746f207468697320636f6e747261637420616e642074727920616761696084820152603760f91b60a482015260c4016105ee565b509850989650505050505050565b6040516301ffc9a760e01b81526060906001600160a01b038816906301ffc9a790612cf3906380ac58cd60e01b90600401615080565b60206040518083038186803b158015612d0b57600080fd5b505afa158015612d1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d43919061487a565b156130d2576001826001811115612d5c57612d5c61582e565b1415612ec2576040516331a9108f60e11b8152600481018690526001600160a01b03808a169190891690636352211e9060240160206040518083038186803b158015612da757600080fd5b505afa158015612dbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddf91906146a4565b6001600160a01b031614612e535760405162461bcd60e51b815260206004820152603560248201527f496e76616c6964204e4654204f776e657220416464726573732e20506c656173604482015274329031b432b1b59030b732103a393c9030b3b0b4b760591b60648201526084016105ee565b604051632142170760e11b81526001600160a01b0389811660048301528781166024830152604482018790528816906342842e0e90606401600060405180830381600087803b158015612ea557600080fd5b505af1158015612eb9573d6000803e3d6000fd5b505050506121b1565b6000826001811115612ed657612ed661582e565b14156130cd57600789604051612eec9190614f03565b908152604051908190036020018120546001600160401b03600160801b90910416908590600890612f1e908d90614f03565b908152602001604051809103902054612f37919061559d565b1115612ff75760405162461bcd60e51b815260206004820152607760248201527f546865206d6178696d756d207175616e7469747920616c6c6f77656420746f2060448201527f70757263686173652045524337323120746f6b656e20686173206265656e207360648201527f6f6c64206f75742e20506c6561736520636f6e74616374207468652073616c6560848201527f206f776e657220666f72206d6f72652064657461696c7300000000000000000060a482015260c4016105ee565b60405163e00aab4b60e01b81526001600160a01b03878116600483015261ffff8616602483015288169063e00aab4b90604401600060405180830381600087803b15801561304457600080fd5b505af1158015613058573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130809190810190614829565b90508360088a6040516130939190614f03565b9081526020016040518091039020546130ac919061559d565b60088a6040516130bc9190614f03565b908152604051908190036020019020555b6121b1565b6040516301ffc9a760e01b81526001600160a01b038816906301ffc9a79061310590636cdb3d1360e11b90600401615080565b60206040518083038186803b15801561311d57600080fd5b505afa158015613131573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613155919061487a565b156121b157600182600181111561316e5761316e61582e565b14156132f657604051627eeac760e11b81526001600160a01b038981166004830152602482018790526000919089169062fdd58e9060440160206040518083038186803b1580156131be57600080fd5b505afa1580156131d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131f69190614b4d565b90508084111580156132085750600084115b6132665760405162461bcd60e51b815260206004820152602960248201527f496e73756666696369656e7420746f6b656e2062616c616e63652066726f6d206044820152683a34329037bbb732b960b91b60648201526084016105ee565b604051637921219560e11b81526001600160a01b038a811660048301528881166024830152604482018890526064820186905260a06084830152600260a483015261060f60f31b60c483015289169063f242432a9060e401600060405180830381600087803b1580156132d857600080fd5b505af11580156132ec573d6000803e3d6000fd5b50505050506121b1565b600082600181111561330a5761330a61582e565b14156121b157604080516001808252818301909252600091602080830190803683370190505090506000856001600160401b0381111561334c5761334c615870565b604051908082528060200260200182016040528015613375578160200160208202803683370190505b5090506060888360008151811061338e5761338e61585a565b60200260200101906001600160a01b031690816001600160a01b03168152505085826000815181106133c2576133c261585a565b602090810291909101015260405163bd85b03960e01b8152600481018990526001600160a01b038b169063bd85b0399060240160206040518083038186803b15801561340d57600080fd5b505afa158015613421573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134459190614b4d565b61366a5760078c6040516134599190614f03565b908152604051908190036020018120546001600160401b03600160801b9091041690600890613489908f90614f03565b908152602001604051809103902054106135575760405162461bcd60e51b815260206004820152607860248201527f546865206d6178696d756d207175616e7469747920616c6c6f77656420746f2060448201527f7075726368617365204552433131353520746f6b656e20686173206265656e2060648201527f736f6c64206f75742e20506c6561736520636f6e74616374207468652073616c60848201527f65206f776e657220666f72206d6f72652064657461696c73000000000000000060a482015260c4016105ee565b60005b8781101561359257868382815181106135755761357561585a565b60209081029190910101528061358a816157fd565b91505061355a565b50604051634637423960e11b81526001600160a01b038b1690638c6e8472906135c390869086908690600401614f32565b600060405180830381600087803b1580156135dd57600080fd5b505af11580156135f1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526136199190810190614829565b93508660088d60405161362c9190614f03565b908152602001604051809103902054613645919061559d565b60088d6040516136559190614f03565b90815260405190819003602001902055613790565b60405163bd85b03960e01b8152600481018990526000906001600160a01b038c169063bd85b0399060240160206040518083038186803b1580156136ad57600080fd5b505afa1580156136c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136e59190614b4d565b1115613790576040805160018082528183019092526000916020808301908036833701905050905088816000815181106137215761372161585a565b60209081029190910101526040516339b2213760e21b81526001600160a01b038c169063e6c884dc9061375c90879085908890600401614fb9565b600060405180830381600087803b15801561377657600080fd5b505af115801561378a573d6000803e3d6000fd5b50505050505b50505098975050505050505050565b60006001600160a01b03831661388757604080516000815260208101918290526001600160a01b0386169184916137d591614f03565b60006040518083038185875af1925050503d8060008114613812576040519150601f19603f3d011682016040523d82523d6000602084013e613817565b606091505b505080915050806138825760405162461bcd60e51b815260206004820152602f60248201527f756e61626c6520746f206465626974206e61746976652062616c616e6365207060448201526e3632b0b9b2903a393c9030b3b0b4b760891b60648201526084016105ee565b61389c565b61389c6001600160a01b038416868685613ba3565b5050505050565b60006007886040516138b59190614f03565b908152604080516020928190038301812060c08201835260058101546001600160a01b0390811683526006820154811694830194909452600781015484169282019290925260089091015491821660608201819052600160a01b830461ffff9081166080840152600160b01b90930490921660a0820152915060009015801590613947575060008260a0015161ffff16115b1561398e57613989878360600151886127108660a0015161ffff168d61396d91906155d7565b61397791906155b5565b613981908661559d565b94508461379f565b6139e7565b600454600160581b90046001600160a01b0316158015906139b4575060045461ffff1615155b156139e7576004546139e79088906001600160a01b03600160581b8204169089906127109061396d9061ffff168e6155d7565b60408201516001600160a01b031615801590613a0b57506000826080015161ffff16115b15613a6d57612710826080015161ffff1689613a2791906155d7565b613a3191906155b5565b613a3b908261559d565b9050613a6d87836040015188612710866080015161ffff168d613a5e91906155d7565b613a6891906155b5565b61379f565b613a7781896155f6565b6006549098506001600160a01b031615613a9c57613a998786868b8a88613bdb565b97505b613aac878360000151888b61379f565b505050505050505050565b6001600160a01b038116600090815260018301602052604081205415155b9392505050565b6000613ad5836001600160a01b038416613c11565b6000610597825490565b6000613ad58383613d04565b6040516001600160a01b03831660248201526044810182905261132d90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613d2e565b6000613ad5836001600160a01b038416613e00565b6000806000613b8e8585613e4f565b91509150613b9b81613ebf565b509392505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113d19085906323b872dd60e01b90608401613b33565b60006001826001811115613bf157613bf161582e565b1415613c0757613c04878688878761407a565b90505b9695505050505050565b60008181526001830160205260408120548015613cfa576000613c356001836155f6565b8554909150600090613c49906001906155f6565b9050818114613cae576000866000018281548110613c6957613c6961585a565b9060005260206000200154905080876000018481548110613c8c57613c8c61585a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613cbf57613cbf615844565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610597565b6000915050610597565b6000826000018281548110613d1b57613d1b61585a565b9060005260206000200154905092915050565b6000613d83826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661425d9092919063ffffffff16565b80519091501561132d5780806020019051810190613da1919061487a565b61132d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016105ee565b6000818152600183016020526040812054613e4757508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610597565b506000610597565b600080825160411415613e865760208301516040840151606085015160001a613e7a87828585614274565b94509450505050613eb8565b825160401415613eb05760208301516040840151613ea5868383614361565b935093505050613eb8565b506000905060025b9250929050565b6000816004811115613ed357613ed361582e565b1415613edc5750565b6001816004811115613ef057613ef061582e565b1415613f3e5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016105ee565b6002816004811115613f5257613f5261582e565b1415613fa05760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016105ee565b6003816004811115613fb457613fb461582e565b141561400d5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016105ee565b60048160048111156140215761402161582e565b14156110e95760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b60648201526084016105ee565b600654604051636e44a72f60e01b81526001600160a01b038681166004830152602482018690526000928592849283928392911690636e44a72f9060440160006040518083038186803b1580156140d057600080fd5b505afa1580156140e4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261410c919081019061475e565b8151919350915080614125578795505050505050614254565b60005b8181101561424b5760008482815181106141445761414461585a565b602002602001015190506127108a8584815181106141645761416461585a565b602002602001015161417691906155d7565b61418091906155b5565b9550858710156141e05760405162461bcd60e51b815260206004820152602560248201527f696e736f6c76656e743a20756e61626c6520746f20636f6d706c65746520726f60448201526479616c747960d81b60648201526084016105ee565b6141ec8d828b8961379f565b604080516001600160a01b038e81168252602082018e90528316818301526060810188905290517f866e6ef8682ddf5f1025e64dfdb45527077f7be70fa9ef680b7ffd8cf4ab9c509181900360800190a1509484900394600101614128565b50939450505050505b95945050505050565b606061426c8484600085614390565b949350505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156142ab5750600090506003614358565b8460ff16601b141580156142c357508460ff16601c14155b156142d45750600090506004614358565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614328573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661435157600060019250925050614358565b9150600090505b94509492505050565b6000806001600160ff1b03831660ff84901c601b0161438287828885614274565b935093505050935093915050565b6060824710156143f15760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016105ee565b843b61443f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105ee565b600080866001600160a01b0316858760405161445b9190614f03565b60006040518083038185875af1925050503d8060008114614498576040519150601f19603f3d011682016040523d82523d6000602084013e61449d565b606091505b50915091506144ad8282866144b8565b979650505050505050565b606083156144c7575081613ad5565b8251156144d75782518084602001fd5b8160405162461bcd60e51b81526004016105ee9190615095565b50805460008255906000526020600020908101906110e991905b80821115611196576000815560010161450b565b60006001600160401b0383111561453857614538615870565b61454b601f8401601f19166020016154dc565b905082815283838301111561455f57600080fd5b828260208301376000602084830101529392505050565b803561458181615aa2565b919050565b600082601f83011261459757600080fd5b815160206145ac6145a78361550c565b6154dc565b80838252828201915082860187848660051b89010111156145cc57600080fd5b60005b858110156145eb578151845292840192908401906001016145cf565b5090979650505050505050565b803561458181615ac5565b60008083601f84011261461557600080fd5b5081356001600160401b0381111561462c57600080fd5b602083019150836020828501011115613eb857600080fd5b600082601f83011261465557600080fd5b613ad58383356020850161451f565b600060a0828403121561467657600080fd5b50919050565b803561458181615ae2565b60006020828403121561469957600080fd5b8135613ad581615aa2565b6000602082840312156146b657600080fd5b8151613ad581615aa2565b600080600080600060a086880312156146d957600080fd5b85356146e481615aa2565b945060208601356146f481615ad2565b9350604086013561470481615ae2565b9250606086013561471481615aa2565b9150608086013561472481615aa2565b809150509295509295909350565b6000806040838503121561474557600080fd5b823561475081615aa2565b946020939093013593505050565b6000806040838503121561477157600080fd5b82516001600160401b038082111561478857600080fd5b818501915085601f83011261479c57600080fd5b815160206147ac6145a78361550c565b8083825282820191508286018a848660051b89010111156147cc57600080fd5b600096505b848710156147f85780516147e481615aa2565b8352600196909601959183019183016147d1565b509188015191965090935050508082111561481257600080fd5b5061481f85828601614586565b9150509250929050565b60006020828403121561483b57600080fd5b81516001600160401b0381111561485157600080fd5b61426c84828501614586565b60006020828403121561486f57600080fd5b8135613ad581615ab7565b60006020828403121561488c57600080fd5b8151613ad581615ab7565b6000602082840312156148a957600080fd5b81356001600160e01b031981168114613ad557600080fd5b6000602082840312156148d357600080fd5b81356001600160401b038111156148e957600080fd5b8201601f810184136148fa57600080fd5b61426c8482356020840161451f565b60006020828403121561491b57600080fd5b8135613ad581615ac5565b6000806020838503121561493957600080fd5b82356001600160401b0381111561494f57600080fd5b61495b85828601614603565b90969095509350505050565b60006020828403121561497957600080fd5b81356001600160401b0381111561498f57600080fd5b61426c84828501614644565b6000806000606084860312156149b057600080fd5b83356001600160401b03808211156149c757600080fd5b9085019061014082880312156149dc57600080fd5b6149e46154b3565b8235828111156149f357600080fd5b6149ff89828601614644565b825250614a0e60208401614576565b602082015260408301356040820152614a296060840161467c565b6060820152614a3a6080840161467c565b6080820152614a4b60a08401614576565b60a0820152614a5c60c08401614576565b60c082015260e083013560e0820152610100614a79818501614576565b9082015261012092830135928101929092529093506020850135925060408501359080821115614aa857600080fd5b50614ab586828701614664565b9150509250925092565b600080600060408486031215614ad457600080fd5b83356001600160401b0380821115614aeb57600080fd5b908501906102008288031215614b0057600080fd5b90935060208501359080821115614b1657600080fd5b50614b2386828701614603565b9497909650939450505050565b600060208284031215614b4257600080fd5b8135613ad581615ad2565b600060208284031215614b5f57600080fd5b5051919050565b600060208284031215614b7857600080fd5b813563ffffffff81168114613ad557600080fd5b600060208284031215614b9e57600080fd5b8135613ad581615ae2565b8183526000602080850194508260005b85811015614be7578135614bcc81615aa2565b6001600160a01b031687529582019590820190600101614bb9565b509495945050505050565b600081518084526020808501945080840160005b83811015614be75781516001600160a01b031687529582019590820190600101614c06565b81835260006001600160fb1b03831115614c4457600080fd5b8260051b8083602087013760009401602001938452509192915050565b600081518084526020808501945080840160005b83811015614be757815187529582019590820190600101614c75565b614c9a81615a84565b9052565b60008151808452614cb681602086016020860161570c565b601f01601f19169290920160200192915050565b6000610200614ce984614cdc8561467c565b6001600160401b03169052565b614cf56020840161467c565b6001600160401b03166020850152614d0f6040840161467c565b6001600160401b03166040850152614d2960608401614576565b6001600160a01b0316606085015260808381013590850152614d4e60a084018461552f565b8260a0870152614d618387018284614c2b565b92505050614d7260c084018461552f565b85830360c0870152614d85838284614ba9565b92505050614d9960e0850160e08501614df5565b6101a0614da78185016145f8565b614db382870182614c91565b50506101c0614dc38185016145f8565b614dcf82870182614c91565b50506101e0614ddf818501614576565b6001600160a01b03169401939093525090919050565b8035614e0081615aa2565b6001600160a01b039081168352602082013590614e1c82615aa2565b9081166020840152604082013590614e3382615aa2565b9081166040840152606082013590614e4a82615aa2565b1660608301526080810135614e5e81615ad2565b61ffff908116608084015260a082013590614e7882615ad2565b80821660a085015250505050565b606087901b6bffffffffffffffffffffffff1916815260f086901b6001600160f01b031916601482015260e085901b6001600160e01b03191660168201528284601a830137694f4e434841494e42555960b01b9201601a8101929092526024820152604401949350505050565b8183823760009101908152919050565b60008251614f1581846020870161570c565b9190910192915050565b602081526000613ad56020830184614bf2565b606081526000614f456060830186614bf2565b602083820381850152614f588287614c61565b915083820360408501528185518084528284019150828160051b85010183880160005b83811015614fa957601f19878403018552614f97838351614c9e565b94860194925090850190600101614f7b565b50909a9950505050505050505050565b606081526000614fcc6060830186614bf2565b8281036020840152614fde8186614c61565b90508281036040840152613c078185614c61565b604080825283519082018190526000906020906060840190828701845b828110156150345781516001600160a01b03168452928401929084019060010161500f565b50505083810382850152613c078186614c61565b602081526000613ad56020830184614c61565b60408152600061506e6040830185614c61565b82810360208401526142548185614bf2565b6001600160e01b031991909116815260200190565b602081526000613ad56020830184614c9e565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252604f908201527f54686973206973206e6f7420612076616c696420746f6b656e49642e20506c6560408201527f6173652076657269667920746861742074686520746f6b656e49642070726f7660608201526e1a591959081a5cc818dbdc9c9958dd608a1b608082015260a00190565b60208082526033908201527f54686520746f74616c2066656520626173697320706f696e742073686f756c646040820152720206265206c657373207468616e20313030303606c1b606082015260800190565b60208082526024908201527f41646d696e436f6e74726f6c3a204d757374206265206f776e6572206f7220616040820152633236b4b760e11b606082015260800190565b60a08152600086516101408060a08501526152086101e0850183614c9e565b9150602089015161522460c08601826001600160a01b03169052565b50604089015160e0850152606089015161010061524b818701836001600160401b03169052565b60808b01519150610120615269818801846001600160401b03169052565b60a08c01516001600160a01b039081169488019490945260c08c0151841661016088015260e08c0151610180880152908b01519092166101a0860152508801516101c084015282810360208401526152c18188614c61565b60408401969096525050606081019290925260809091015292915050565b6040815260006152f26040830184614cca565b8281036020840152600b81526a1cd85b1950dc99585d195960aa1b60208201526040810191505092915050565b6040815260006153326040830184614cca565b8281036020840152600b81526a1cd85b19555c19185d195960aa1b60208201526040810191505092915050565b60006101c0820190506001600160401b03808c168352808b166020840152808a1660408401525060018060a01b0380891660608401528760808401528087511660a08401528060208801511660c08401528060408801511660e08401528060608801511661010084015250608086015161ffff8082166101208501528060a08901511661014085015250506153f8610160830186614c91565b615406610180830185614c91565b6001600160a01b0383166101a08301529a9950505050505050505050565b6000808335601e1984360301811261543b57600080fd5b8301803591506001600160401b0382111561545557600080fd5b6020019150600581901b3603821315613eb857600080fd5b6000808335601e1984360301811261548457600080fd5b8301803591506001600160401b0382111561549e57600080fd5b602001915036819003821315613eb857600080fd5b60405161014081016001600160401b03811182821017156154d6576154d6615870565b60405290565b604051601f8201601f191681016001600160401b038111828210171561550457615504615870565b604052919050565b60006001600160401b0382111561552557615525615870565b5060051b60200190565b6000808335601e1984360301811261554657600080fd5b83016020810192503590506001600160401b0381111561556557600080fd5b8060051b3603831315613eb857600080fd5b600061ffff80831681851680830382111561559457615594615818565b01949350505050565b600082198211156155b0576155b0615818565b500190565b6000826155d257634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156155f1576155f1615818565b500290565b60008282101561560857615608615818565b500390565b8183101561132d576000818152602081208481019084015b8082101561563b57828255600182019150615625565b505050505050565b600160401b83111561565757615657615870565b805483825561566784828461560d565b50818160005260208060002060005b868110156156b457833561568981615aa2565b82546001600160a01b0319166001600160a01b03919091161782559282019260019182019101615676565b50505050505050565b600160401b8311156156d1576156d1615870565b80548382556156e184828461560d565b50818160005260208060002060005b868110156156b4578335825592820192600191820191016156f0565b60005b8381101561572757818101518382015260200161570f565b838111156113d15750506000910152565b813561574381615aa2565b61574d81836158ad565b50602082013561575c81615aa2565b61576981600184016158ad565b50604082013561577881615aa2565b61578581600284016158ad565b5060038101606083013561579881615aa2565b6157a281836158ad565b5060808301356157b181615ad2565b815461ffff60a01b60a092831b1661ffff60a01b19821681178455918501356157d981615ad2565b63ffffffff60a01b199190911690911760b09190911b61ffff60b01b161790555050565b600060001982141561581157615811615818565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6000813561059781615aa2565b6000813561059781615ac5565b6000813561059781615ae2565b80546001600160a01b0319166001600160a01b0392909216919091179055565b6158d682615a84565b60ff1981541660ff831681178255505050565b6159136158f5836158a0565b825467ffffffffffffffff19166001600160401b0391909116178255565b615954615922602084016158a0565b82546fffffffffffffffff0000000000000000191660409190911b6fffffffffffffffff000000000000000016178255565b61598f615963604084016158a0565b82805467ffffffffffffffff60801b191660809290921b67ffffffffffffffff60801b16919091179055565b6159a761599e60608401615886565b600183016158ad565b608082013560028201556159be60a0830183615424565b6159cc8183600386016156bd565b50506159db60c0830183615424565b6159e9818360048601615643565b50506159fb60e0830160058301615738565b60098101615a15615a0f6101a08501615893565b826158cd565b615a2b615a256101c08501615893565b82615a63565b61132d615a3b6101e08501615886565b82805462010000600160b01b03191660109290921b62010000600160b01b0316919091179055565b615a6c82615a84565b805461ff008360081b1661ff00198216178255505050565b600281106110e957634e487b7160e01b600052602160045260246000fd5b6001600160a01b03811681146110e957600080fd5b80151581146110e957600080fd5b600281106110e957600080fd5b61ffff811681146110e957600080fd5b6001600160401b03811681146110e957600080fdfea26469706673582212206711fa78f1aa3025eab19d77c1a4281493c43f3c7b76ac6e1916a498d87dd0df64736f6c63430008070033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c0d66432e3fd40da54aadcff899add918625373100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c830e706eabbd9a4f2f7ed309e5b519a3073d5f200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _platformAddress (address): 0xC0d66432E3Fd40DA54AAdcfF899ADD9186253731
Arg [1] : _platformFeePercentage (uint16): 0
Arg [2] : _max1155Quantity (uint64): 0
Arg [3] : _priceFeedAddress (address): 0xc830E706eABBd9A4F2F7Ed309E5B519a3073d5f2
Arg [4] : _royaltycontract (address): 0x0000000000000000000000000000000000000000
Arg [5] : _adminApprovalRequired (bool): False
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 000000000000000000000000c0d66432e3fd40da54aadcff899add9186253731
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [3] : 000000000000000000000000c830e706eabbd9a4f2f7ed309e5b519a3073d5f2
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.