Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 373 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Mint Allow List | 15491546 | 723 days ago | IN | 0.00003 ETH | 0.00071857 | ||||
Mint Public | 15488828 | 723 days ago | IN | 0.00001 ETH | 0.00039256 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00106395 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00106429 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00324261 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00324261 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00324261 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00324261 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00324261 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00324261 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00324261 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00324261 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00324261 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00324261 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00324261 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00324261 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00324261 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00324261 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00324261 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00399226 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00399226 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00399226 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00399226 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00399226 | ||||
Mint Public | 15487528 | 724 days ago | IN | 0.00001 ETH | 0.00399226 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
15487528 | 724 days ago | 0.000009 ETH | ||||
15487528 | 724 days ago | 0.000001 ETH | ||||
15487528 | 724 days ago | 0.000009 ETH | ||||
15487528 | 724 days ago | 0.000001 ETH | ||||
15487528 | 724 days ago | 0.000009 ETH | ||||
15487528 | 724 days ago | 0.000001 ETH | ||||
15487528 | 724 days ago | 0.000009 ETH | ||||
15487528 | 724 days ago | 0.000001 ETH | ||||
15487528 | 724 days ago | 0.000009 ETH | ||||
15487528 | 724 days ago | 0.000001 ETH | ||||
15487528 | 724 days ago | 0.000009 ETH | ||||
15487528 | 724 days ago | 0.000001 ETH | ||||
15487528 | 724 days ago | 0.000009 ETH | ||||
15487528 | 724 days ago | 0.000001 ETH | ||||
15487528 | 724 days ago | 0.000009 ETH | ||||
15487528 | 724 days ago | 0.000001 ETH | ||||
15487528 | 724 days ago | 0.000009 ETH | ||||
15487528 | 724 days ago | 0.000001 ETH | ||||
15487528 | 724 days ago | 0.000009 ETH | ||||
15487528 | 724 days ago | 0.000001 ETH | ||||
15487528 | 724 days ago | 0.000009 ETH | ||||
15487528 | 724 days ago | 0.000001 ETH | ||||
15487528 | 724 days ago | 0.000009 ETH | ||||
15487528 | 724 days ago | 0.000001 ETH | ||||
15487528 | 724 days ago | 0.000009 ETH |
Loading...
Loading
Contract Name:
SeaDrop
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.11; import { ISeaDrop } from "./interfaces/ISeaDrop.sol"; import { AllowListData, MintParams, PublicDrop, TokenGatedDropStage, TokenGatedMintParams } from "./lib/SeaDropStructs.sol"; import { IERC721SeaDrop } from "./interfaces/IERC721SeaDrop.sol"; import { ERC20, SafeTransferLib } from "solmate/utils/SafeTransferLib.sol"; import { MerkleProofLib } from "solady/utils/MerkleProofLib.sol"; import { IERC721 } from "openzeppelin-contracts/contracts/token/ERC721/IERC721.sol"; import { IERC165 } from "openzeppelin-contracts/contracts/utils/introspection/IERC165.sol"; import { ECDSA } from "openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol"; /** * @title SeaDrop * @author jameswenzel, ryanio, stephankmin * @notice SeaDrop is a contract to help facilitate ERC721 token drops * with functionality for public, allow list, server-side signed, * and token-gated drops. */ contract SeaDrop is ISeaDrop { using ECDSA for bytes32; // Track the public drops. mapping(address => PublicDrop) private _publicDrops; // Track the drop URIs. mapping(address => string) private _dropURIs; // Track the creator payout addresses. mapping(address => address) private _creatorPayoutAddresses; // Track the allow list merkle roots. mapping(address => bytes32) private _allowListMerkleRoots; // Track the allowed fee recipients. mapping(address => mapping(address => bool)) private _allowedFeeRecipients; // Track the allowed signers for server side drops. mapping(address => mapping(address => bool)) private _signers; // Track the signers for each server side drop. mapping(address => address[]) private _enumeratedSigners; // Track token gated drop stages. mapping(address => mapping(address => TokenGatedDropStage)) private _tokenGatedDrops; // Track the tokens for token gated drops. mapping(address => address[]) private _enumeratedTokenGatedTokens; // Track redeemed token IDs for token gated drop stages. mapping(address => mapping(address => mapping(uint256 => bool))) private _tokenGatedRedeemed; // EIP-712: Typed structured data hashing and signing bytes32 public immutable DOMAIN_SEPARATOR; bytes32 public immutable MINT_DATA_TYPEHASH; /** * @notice Ensure only tokens implementing IERC721SeaDrop can * call the update methods. */ modifier onlyIERC721SeaDrop() virtual { if ( !IERC165(msg.sender).supportsInterface( type(IERC721SeaDrop).interfaceId ) ) { revert OnlyIERC721SeaDrop(msg.sender); } _; } /** * @notice Constructor for the contract deployment. */ constructor() { DOMAIN_SEPARATOR = keccak256( abi.encode( keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ), keccak256(bytes("SeaDrop")), keccak256(bytes("1")), block.chainid, address(this) ) ); MINT_DATA_TYPEHASH = keccak256( "MintParams(address minter, uint256 mintPrice, uint256 maxTotalMintableByWallet, uint256 startTime, uint256 endTime, uint256 dropStageIndex, uint256 feeBps, bool restrictFeeRecipients)" ); } /** * @notice Mint a public drop. * * @param nftContract The nft contract to mint. * @param feeRecipient The fee recipient. * @param minter The mint recipient. * @param quantity The number of tokens to mint. */ function mintPublic( address nftContract, address feeRecipient, address minter, uint256 quantity ) external payable override { // Get the public drop data. PublicDrop memory publicDrop = _publicDrops[nftContract]; // Ensure that the drop has started. if (block.timestamp < publicDrop.startTime) { revert NotActive( block.timestamp, publicDrop.startTime, type(uint64).max ); } // Validate payment is correct for number minted. _checkCorrectPayment(quantity, publicDrop.mintPrice); // Check that the minter is allowed to mint the desired quantity. _checkMintQuantity( nftContract, minter, quantity, publicDrop.maxMintsPerWallet, 0 ); // Check that the fee recipient is allowed if restricted. _checkFeeRecipientIsAllowed( nftContract, feeRecipient, publicDrop.restrictFeeRecipients ); // Split the payout, mint the token, emit an event. _payAndMint( nftContract, minter, quantity, publicDrop.mintPrice, 0, publicDrop.feeBps, feeRecipient ); } /** * @notice Mint from an allow list. * * @param nftContract The nft contract to mint. * @param feeRecipient The fee recipient. * @param minter The mint recipient. * @param quantity The number of tokens to mint. * @param mintParams The mint parameters. * @param proof The proof for the leaf of the allow list. */ function mintAllowList( address nftContract, address feeRecipient, address minter, uint256 quantity, MintParams calldata mintParams, bytes32[] calldata proof ) external payable override { // Check that the drop stage is active. _checkActive(mintParams.startTime, mintParams.endTime); // Validate payment is correct for number minted. _checkCorrectPayment(quantity, mintParams.mintPrice); // Check that the minter is allowed to mint the desired quantity. _checkMintQuantity( nftContract, minter, quantity, mintParams.maxTotalMintableByWallet, mintParams.maxTokenSupplyForStage ); // Check that the fee recipient is allowed if restricted. _checkFeeRecipientIsAllowed( nftContract, feeRecipient, mintParams.restrictFeeRecipients ); // Verify the proof. if ( !MerkleProofLib.verify( proof, _allowListMerkleRoots[nftContract], keccak256(abi.encode(minter, mintParams)) ) ) { revert InvalidProof(); } // Split the payout, mint the token, emit an event. _payAndMint( nftContract, minter, quantity, mintParams.mintPrice, mintParams.dropStageIndex, mintParams.feeBps, feeRecipient ); } /** * @notice Mint with a server side signature. * * @param nftContract The nft contract to mint. * @param feeRecipient The fee recipient. * @param minter The mint recipient. * @param quantity The number of tokens to mint. * @param mintParams The mint parameters. * @param signature The server side signature, must be an allowed * signer. */ function mintSigned( address nftContract, address feeRecipient, address minter, uint256 quantity, MintParams calldata mintParams, bytes calldata signature ) external payable override { // Check that the drop stage is active. _checkActive(mintParams.startTime, mintParams.endTime); // Validate payment is correct for number minted. _checkCorrectPayment(quantity, mintParams.mintPrice); // Check that the minter is allowed to mint the desired quantity. _checkMintQuantity( nftContract, minter, quantity, mintParams.maxTotalMintableByWallet, mintParams.maxTokenSupplyForStage ); // Check that the fee recipient is allowed if restricted. _checkFeeRecipientIsAllowed( nftContract, feeRecipient, mintParams.restrictFeeRecipients ); // Verify EIP-712 signature by recreating the data structure // that we signed on the client side, and then using that to recover // the address that signed the signature for this data. bytes32 digest = keccak256( abi.encodePacked( bytes2(0x1901), DOMAIN_SEPARATOR, keccak256(abi.encode(MINT_DATA_TYPEHASH, minter, mintParams)) ) ); // Use the recover method to see what address was used to create // the signature on this data. // Note that if the digest doesn't exactly match what was signed we'll // get a random recovered address. address recoveredAddress = digest.recover(signature); if (!_signers[nftContract][recoveredAddress]) { revert InvalidSignature(recoveredAddress); } // Split the payout, mint the token, emit an event. _payAndMint( nftContract, minter, quantity, mintParams.mintPrice, mintParams.dropStageIndex, mintParams.feeBps, feeRecipient ); } /** * @notice Mint as an allowed token holder. * This will mark the token id as reedemed and will revert if the * same token id is attempted to be redeemed twice. * * @param nftContract The nft contract to mint. * @param feeRecipient The fee recipient. * @param minter The mint recipient. * @param tokenGatedMintParams The token gated mint params. */ function mintAllowedTokenHolder( address nftContract, address feeRecipient, address minter, TokenGatedMintParams[] calldata tokenGatedMintParams ) external payable override { // Track the total mint cost to compare against value sent with tx. uint256 totalCost; // Iterate through each allowedNftToken. for (uint256 i = 0; i < tokenGatedMintParams.length; ) { // Set the mintParams to a variable. TokenGatedMintParams calldata mintParams = tokenGatedMintParams[i]; // Set the dropStage to a variable. TokenGatedDropStage storage dropStage = _tokenGatedDrops[ nftContract ][mintParams.allowedNftToken]; // Validate that the dropStage is active. _checkActive(dropStage.startTime, dropStage.endTime); // Check that the fee recipient is allowed if restricted. _checkFeeRecipientIsAllowed( nftContract, feeRecipient, dropStage.restrictFeeRecipients ); // Put the mint quantity on the stack for more efficient access. uint256 mintQuantity = mintParams.allowedNftTokenIds.length; // Add to total cost. totalCost += mintQuantity * dropStage.mintPrice; // Check that the minter is allowed to mint the desired quantity. _checkMintQuantity( nftContract, minter, mintQuantity, dropStage.maxTotalMintableByWallet, dropStage.maxTokenSupplyForStage ); // Iterate through each allowedNftTokenId // to ensure it is not already reedemed. for (uint256 j = 0; j < mintQuantity; ) { // Put the tokenId on the stack. uint256 tokenId = mintParams.allowedNftTokenIds[j]; // Check that the sender is the owner of the allowedNftTokenId. if ( IERC721(mintParams.allowedNftToken).ownerOf(tokenId) != minter ) { revert TokenGatedNotTokenOwner( nftContract, mintParams.allowedNftToken, tokenId ); } // Check that the token id has not already been redeemed. bool redeemed = _tokenGatedRedeemed[nftContract][ mintParams.allowedNftToken ][tokenId]; if (redeemed == true) { revert TokenGatedTokenIdAlreadyRedeemed( nftContract, mintParams.allowedNftToken, tokenId ); } // Mark the token id as reedemed. redeemed = true; unchecked { ++j; } } // Split the payout, mint the token, emit an event. _payAndMint( nftContract, minter, mintQuantity, dropStage.mintPrice, dropStage.dropStageIndex, dropStage.feeBps, feeRecipient ); unchecked { ++i; } } // Validate correct payment. if (msg.value != totalCost) { revert IncorrectPayment(msg.value, totalCost); } } /** * @notice Check that the drop stage is active. * * @param startTime The drop stage start time. * @param endTime The drop stage end time. */ function _checkActive(uint256 startTime, uint256 endTime) internal view { if (block.timestamp < startTime || block.timestamp > endTime) { // Revert if the drop stage is not active. revert NotActive(block.timestamp, startTime, endTime); } } /** * @notice Check that the fee recipient is allowed. * * @param nftContract The nft contract. * @param feeRecipient The fee recipient. * @param restrictFeeRecipients If the fee recipients are restricted. */ function _checkFeeRecipientIsAllowed( address nftContract, address feeRecipient, bool restrictFeeRecipients ) internal view { // Ensure the fee recipient is not the zero address. if (feeRecipient == address(0)) { revert FeeRecipientCannotBeZeroAddress(); } // Revert if the fee recipient is restricted and not allowed. if ( restrictFeeRecipients == true && _allowedFeeRecipients[nftContract][feeRecipient] == false ) { revert FeeRecipientNotAllowed(); } } /** * @notice Check that the wallet is allowed to mint the desired quantity. * * @param nftContract The nft contract. * @param minter The mint recipient. * @param quantity The number of tokens to mint. * @param maxMintsPerWallet The allowed max mints per wallet. * @param nftContract The nft contract. */ function _checkMintQuantity( address nftContract, address minter, uint256 quantity, uint256 maxMintsPerWallet, uint256 maxTokenSupplyForStage ) internal view { // Get the mint stats. ( uint256 minterNumMinted, uint256 currentTotalSupply, uint256 maxSupply ) = IERC721SeaDrop(nftContract).getMintStats(minter); // Ensure mint quantity doesn't exceed maxMintsPerWallet. if (quantity + minterNumMinted > maxMintsPerWallet) { revert MintQuantityExceedsMaxMintedPerWallet( quantity + minterNumMinted, maxMintsPerWallet ); } // Ensure mint quantity doesn't exceed maxSupply. if (quantity + currentTotalSupply > maxSupply) { revert MintQuantityExceedsMaxSupply( quantity + currentTotalSupply, maxSupply ); } // Ensure mint quantity doesn't exceed maxTokenSupplyForStage // when provided. if (maxTokenSupplyForStage != 0) { if (quantity + currentTotalSupply > maxTokenSupplyForStage) { revert MintQuantityExceedsMaxTokenSupplyForStage( quantity + currentTotalSupply, maxTokenSupplyForStage ); } } } /** * @notice Revert if the payment is not the quantity times the mint price. * * @param quantity The number of tokens to mint. * @param mintPrice The mint price per token. */ function _checkCorrectPayment(uint256 quantity, uint256 mintPrice) internal view { // Revert if the tx's value doesn't match the total cost. if (msg.value != quantity * mintPrice) { revert IncorrectPayment(msg.value, quantity * mintPrice); } } /** * @notice Split the payment payout for the creator and fee recipient. * * @param nftContract The nft contract. * @param feeRecipient The fee recipient. * @param feeBps The fee basis points. */ function _splitPayout( address nftContract, address feeRecipient, uint256 feeBps ) internal { // Get the creator payout address. address creatorPayoutAddress = _creatorPayoutAddresses[nftContract]; // Ensure the creator payout address is not the zero address. if (creatorPayoutAddress == address(0)) { revert CreatorPayoutAddressCannotBeZeroAddress(); } // Get the fee amount. uint256 feeAmount = (msg.value * feeBps) / 10_000; // Get the creator payout amount. uint256 payoutAmount = msg.value - feeAmount; // Transfer to the fee recipient. SafeTransferLib.safeTransferETH(feeRecipient, feeAmount); // Transfer to the creator. SafeTransferLib.safeTransferETH(creatorPayoutAddress, payoutAmount); } /** * @notice Splits the payment, mints a number of tokens, * and emits an event. * * @param nftContract The nft contract. * @param minter The mint recipient. * @param quantity The number of tokens to mint. * @param mintPrice The mint price per token. * @param dropStageIndex The drop stage index. * @param feeBps The fee basis points. * @param feeRecipient The fee recipient. */ function _payAndMint( address nftContract, address minter, uint256 quantity, uint256 mintPrice, uint256 dropStageIndex, uint256 feeBps, address feeRecipient ) internal { // Split the payment between the creator and fee recipient. _splitPayout(nftContract, feeRecipient, feeBps); // Mint the token(s). IERC721SeaDrop(nftContract).mintSeaDrop(minter, quantity); // Emit an event for the mint. emit SeaDropMint( nftContract, minter, feeRecipient, msg.sender, quantity, mintPrice, feeBps, dropStageIndex ); } /** * @notice Returns the drop URI for the nft contract. * * @param nftContract The nft contract. */ function getDropURI(address nftContract) external view returns (string memory) { return _dropURIs[nftContract]; } /** * @notice Returns the public drop data for the nft contract. * * @param nftContract The nft contract. */ function getPublicDrop(address nftContract) external view returns (PublicDrop memory) { return _publicDrops[nftContract]; } /** * @notice Returns the creator payout address for the nft contract. * * @param nftContract The nft contract. */ function getCreatorPayoutAddress(address nftContract) external view returns (address) { return _creatorPayoutAddresses[nftContract]; } /** * @notice Returns the allow list merkle root for the nft contract. * * @param nftContract The nft contract. */ function getAllowListMerkleRoot(address nftContract) external view returns (bytes32) { return _allowListMerkleRoots[nftContract]; } /** * @notice Returns if the specified fee recipient is allowed * for the nft contract. * * @param nftContract The nft contract. */ function getFeeRecipientIsAllowed(address nftContract, address feeRecipient) external view returns (bool) { return _allowedFeeRecipients[nftContract][feeRecipient]; } /** * @notice Returns the server side signers for the nft contract. * * @param nftContract The nft contract. */ function getSigners(address nftContract) external view returns (address[] memory) { return _enumeratedSigners[nftContract]; } /** * @notice Returns the allowed token gated drop tokens for the nft contract. * * @param nftContract The nft contract. */ function getTokenGatedAllowedTokens(address nftContract) external view returns (address[] memory) { return _enumeratedTokenGatedTokens[nftContract]; } /** * @notice Returns the token gated drop data for the nft contract * and token gated nft. * * @param nftContract The nft contract. * @param allowedNftToken The token gated nft token. */ function getTokenGatedDrop(address nftContract, address allowedNftToken) external view returns (TokenGatedDropStage memory) { return _tokenGatedDrops[nftContract][allowedNftToken]; } /** * @notice Updates the drop URI and emits an event. * * @param newDropURI The new drop URI. */ function updateDropURI(string calldata newDropURI) external onlyIERC721SeaDrop { // Set the new drop URI. _dropURIs[msg.sender] = newDropURI; // Emit an event with the update. emit DropURIUpdated(msg.sender, newDropURI); } /** * @notice Updates the public drop for the nft contract and emits an event. * * @param publicDrop The public drop data. */ function updatePublicDrop(PublicDrop calldata publicDrop) external override onlyIERC721SeaDrop { // Set the public drop data. _publicDrops[msg.sender] = publicDrop; // Emit an event with the update. emit PublicDropUpdated(msg.sender, publicDrop); } /** * @notice Updates the allow list merkle root for the nft contract * and emits an event. * * @param allowListData The allow list data. */ function updateAllowList(AllowListData calldata allowListData) external override onlyIERC721SeaDrop { // Track the previous root. bytes32 prevRoot = _allowListMerkleRoots[msg.sender]; // Update the merkle root. _allowListMerkleRoots[msg.sender] = allowListData.merkleRoot; // Emit an event with the update. emit AllowListUpdated( msg.sender, prevRoot, allowListData.merkleRoot, allowListData.publicKeyURIs, allowListData.allowListURI ); } /** * @notice Updates the token gated drop stage for the nft contract * and emits an event. * * @param nftContract The nft contract. * @param allowedNftToken The token gated nft token. * @param dropStage The token gated drop stage data. */ function updateTokenGatedDrop( address nftContract, address allowedNftToken, TokenGatedDropStage calldata dropStage ) external override onlyIERC721SeaDrop { // Set the drop stage. _tokenGatedDrops[nftContract][allowedNftToken] = dropStage; // If the maxTotalMintableByWallet is greater than zero // then we are setting an active drop stage. if (dropStage.maxTotalMintableByWallet > 0) { // Add allowedNftToken to enumerated list if not present. bool allowedNftTokenExistsInEnumeration = false; // Iterate through enumerated token gated tokens for nft contract. for ( uint256 i = 0; i < _enumeratedTokenGatedTokens[nftContract].length; ) { if ( _enumeratedTokenGatedTokens[nftContract][i] == allowedNftToken ) { // Set the bool to true if found. allowedNftTokenExistsInEnumeration = true; } unchecked { ++i; } } // Add allowedNftToken to enumerated list if not present. if (allowedNftTokenExistsInEnumeration == false) { _enumeratedTokenGatedTokens[nftContract].push(allowedNftToken); } } // Emit an event with the update. emit TokenGatedDropStageUpdated( nftContract, allowedNftToken, dropStage ); } /** * @notice Updates the creator payout address and emits an event. * * @param _payoutAddress The creator payout address. */ function updateCreatorPayoutAddress(address _payoutAddress) external onlyIERC721SeaDrop { // Set the creator payout address. _creatorPayoutAddresses[msg.sender] = _payoutAddress; // Emit an event with the update. emit CreatorPayoutAddressUpdated(msg.sender, _payoutAddress); } /** * @notice Updates the allowed fee recipient and emits an event. * * @param feeRecipient The fee recipient. * @param allowed If the fee recipient is allowed. */ function updateAllowedFeeRecipient(address feeRecipient, bool allowed) external onlyIERC721SeaDrop { // Set the allowed fee recipient. _allowedFeeRecipients[msg.sender][feeRecipient] = allowed; // Emit an event with the update. emit AllowedFeeRecipientUpdated(msg.sender, feeRecipient, allowed); } /** * @notice Updates the allowed server side signers and emits an event. * * @param newSigners The new list of signers. */ function updateSigners(address[] calldata newSigners) external onlyIERC721SeaDrop { // Track the enumerated storage. address[] storage enumeratedStorage = _enumeratedSigners[msg.sender]; // Track the old signers. address[] memory oldSigners = enumeratedStorage; // Delete old enumeration. delete _enumeratedSigners[msg.sender]; // Add new enumeration. for (uint256 i = 0; i < newSigners.length; ) { enumeratedStorage.push(newSigners[i]); unchecked { ++i; } } // Create a mapping of the signers. mapping(address => bool) storage signersMap = _signers[msg.sender]; // Delete old signers. for (uint256 i = 0; i < oldSigners.length; ) { signersMap[oldSigners[i]] = false; unchecked { ++i; } } // Add new signers. for (uint256 i = 0; i < newSigners.length; ) { signersMap[newSigners[i]] = true; unchecked { ++i; } } // Emit an event with the update. emit SignersUpdated(msg.sender, oldSigners, newSigners); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.11; import { AllowListData, MintParams, PublicDrop, TokenGatedDropStage, TokenGatedMintParams } from "../lib/SeaDropStructs.sol"; import { SeaDropErrorsAndEvents } from "../lib/SeaDropErrorsAndEvents.sol"; interface ISeaDrop is SeaDropErrorsAndEvents { /** * @notice Mint a public drop. * * @param nftContract The nft contract to mint. * @param feeRecipient The fee recipient. * @param minter The mint recipient. * @param quantity The number of tokens to mint. */ function mintPublic( address nftContract, address feeRecipient, address minter, uint256 quantity ) external payable; /** * @notice Mint from an allow list. * * @param nftContract The nft contract to mint. * @param feeRecipient The fee recipient. * @param minter The mint recipient. * @param quantity The number of tokens to mint. * @param mintParams The mint parameters. * @param proof The proof for the leaf of the allow list. */ function mintAllowList( address nftContract, address feeRecipient, address minter, uint256 quantity, MintParams calldata mintParams, bytes32[] calldata proof ) external payable; /** * @notice Mint with a server side signature. * * @param nftContract The nft contract to mint. * @param feeRecipient The fee recipient. * @param minter The mint recipient. * @param quantity The number of tokens to mint. * @param mintParams The mint parameters. * @param signature The server side signature, must be an allowed signer. */ function mintSigned( address nftContract, address feeRecipient, address minter, uint256 quantity, MintParams calldata mintParams, bytes calldata signature ) external payable; /** * @notice Mint as an allowed token holder. * This will mark the token id as reedemed and will revert if the * same token id is attempted to be redeemed twice. * * @param nftContract The nft contract to mint. * @param feeRecipient The fee recipient. * @param minter The mint recipient. * @param tokenGatedMintParams The token gated mint params. */ function mintAllowedTokenHolder( address nftContract, address feeRecipient, address minter, TokenGatedMintParams[] calldata tokenGatedMintParams ) external payable; /** * @notice Returns the drop URI for the nft contract. * * @param nftContract The nft contract. */ function getDropURI(address nftContract) external view returns (string memory); /** * @notice Returns the public drop data for the nft contract. * * @param nftContract The nft contract. */ function getPublicDrop(address nftContract) external view returns (PublicDrop memory); /** * @notice Returns the creator payout address for the nft contract. * * @param nftContract The nft contract. */ function getCreatorPayoutAddress(address nftContract) external view returns (address); /** * @notice Returns the allow list merkle root for the nft contract. * * @param nftContract The nft contract. */ function getAllowListMerkleRoot(address nftContract) external view returns (bytes32); /** * @notice Returns if the specified fee recipient is allowed * for the nft contract. * * @param nftContract The nft contract. */ function getFeeRecipientIsAllowed(address nftContract, address feeRecipient) external view returns (bool); /** * @notice Returns the server side signers for the nft contract. * * @param nftContract The nft contract. */ function getSigners(address nftContract) external view returns (address[] memory); /** * @notice Returns the allowed token gated drop tokens for the nft contract. * * @param nftContract The nft contract. */ function getTokenGatedAllowedTokens(address nftContract) external view returns (address[] memory); /** * @notice Returns the token gated drop data for the nft contract * and token gated nft. * * @param nftContract The nft contract. * @param allowedNftToken The token gated nft token. */ function getTokenGatedDrop(address nftContract, address allowedNftToken) external view returns (TokenGatedDropStage memory); /** * The following methods assume msg.sender is an nft contract * and its ERC165 interface id matches IERC721SeaDrop. */ /** * @notice Updates the drop URI and emits an event. * * @param dropURI The new drop URI. */ function updateDropURI(string calldata dropURI) external; /** * @notice Updates the public drop data for the nft contract * and emits an event. * * @param publicDrop The public drop data. */ function updatePublicDrop(PublicDrop calldata publicDrop) external; /** * @notice Updates the allow list merkle root for the nft contract * and emits an event. * * @param allowListData The allow list data. */ function updateAllowList(AllowListData calldata allowListData) external; /** * @notice Updates the token gated drop stage for the nft contract * and emits an event. * * @param nftContract The nft contract. * @param allowedNftToken The token gated nft token. * @param dropStage The token gated drop stage data. */ function updateTokenGatedDrop( address nftContract, address allowedNftToken, TokenGatedDropStage calldata dropStage ) external; /** * @notice Updates the creator payout address and emits an event. * * @param payoutAddress The creator payout address. */ function updateCreatorPayoutAddress(address payoutAddress) external; /** * @notice Updates the allowed fee recipient and emits an event. * * @param feeRecipient The fee recipient. * @param allowed If the fee recipient is allowed. */ function updateAllowedFeeRecipient(address feeRecipient, bool allowed) external; /** * @notice Updates the allowed server side signers and emits an event. * * @param newSigners The new list of signers. */ function updateSigners(address[] calldata newSigners) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.11; /** * @notice A struct defining public drop data. * Designed to fit efficiently in one storage slot. * * @param mintPrice The mint price per token. * (Up to 1.2m of native token, e.g.: ETH, MATIC) * @param startTime The start time, ensure this is not zero. * @param maxMintsPerWallet Maximum total number of mints a user is * allowed. * @param feeBps Fee out of 10,000 basis points to be collected. * @param restrictFeeRecipients If false, allow any fee recipient; * if true, check fee recipient is allowed. */ struct PublicDrop { uint80 mintPrice; // 80/256 bits uint64 startTime; // 144/256 bits uint40 maxMintsPerWallet; // 184/256 bits uint16 feeBps; // 200/256 bits bool restrictFeeRecipients; // 208/256 bits } /** * @notice Stages from dropURI are strictly for front-end consumption, * and are trusted to match information in the * PublicDrop, AllowLists or TokenGatedDropStage * (we may want to surface discrepancies on the front-end) */ /** * @notice A struct defining token gated drop stage data. * Designed to fit efficiently in one storage slot. * * @param mintPrice The mint price per token. * (Up to 1.2m of native token, e.g.: ETH, MATIC) * @param maxTotalMintableByWallet The limit of items this wallet can mint. * @param startTime The start time, ensure this is not zero. * @param endTime The end time, ensure this is not zero. * @param dropStageIndex The drop stage index to emit with the event * for analytical purposes. This should be * non-zero since the public mint emits * with index zero. * @param maxTokenSupplyForStage The limit of token supply this stage can * mint within. * @param feeBps Fee out of 10,000 basis points to be * collected. * @param restrictFeeRecipients If false, allow any fee recipient; * if true, check fee recipient is allowed. */ struct TokenGatedDropStage { uint80 mintPrice; // 80/256 bits uint16 maxTotalMintableByWallet; uint48 startTime; uint48 endTime; uint8 dropStageIndex; // non-zero uint40 maxTokenSupplyForStage; uint16 feeBps; bool restrictFeeRecipients; } /** * @notice A struct defining mint params for an allow list. * An allow list leaf will be composed of `msg.sender` and * the following params. * * Note: Since feeBps is encoded in the leaf, backend should ensure * that feeBps is acceptable before generating a proof. * * @param mintPrice The mint price per token. * @param maxTotalMintableByWallet The limit of items this wallet can mint. * @param startTime The start time, ensure this is not zero. * @param endTime The end time, ensure this is not zero. * @param dropStageIndex The drop stage index to emit with the event * for analytical purposes. This should be * non-zero since the public mint emits with * index zero. * @param maxTokenSupplyForStage The limit of token supply this stage can * mint within. * @param feeBps Fee out of 10,000 basis points to be * collected. * @param restrictFeeRecipients If false, allow any fee recipient; * if true, check fee recipient is allowed. */ struct MintParams { uint256 mintPrice; uint256 maxTotalMintableByWallet; uint256 startTime; uint256 endTime; uint256 dropStageIndex; // non-zero uint256 maxTokenSupplyForStage; uint256 feeBps; bool restrictFeeRecipients; } /** * @notice A struct defining token gated mint params. * * @param allowedNftToken The allowed nft token contract address. * @param allowedNftTokenIds The token ids to redeem. */ struct TokenGatedMintParams { address allowedNftToken; uint256[] allowedNftTokenIds; } /** * @notice A struct defining allow list data (for minting an allow list). * * @param merkleRoot The merkle root for the allow list. * @param publicKeyURIs If the allowListURI is encrypted, a list of URIs * pointing to the public keys. Empty if unencrypted. * @param allowListURI The URI for the allow list. */ struct AllowListData { bytes32 merkleRoot; string[] publicKeyURIs; string allowListURI; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.11; import { IERC721ContractMetadata } from "../interfaces/IERC721ContractMetadata.sol"; import { AllowListData, PublicDrop, TokenGatedDropStage } from "../lib/SeaDropStructs.sol"; import { IERC165 } from "openzeppelin-contracts/contracts/utils/introspection/IERC165.sol"; interface IERC721SeaDrop is IERC721ContractMetadata, IERC165 { /** * @dev Revert with an error if a contract other than an allowed * SeaDrop address calls an update function. */ error OnlySeaDrop(); /** * @dev Emit an event when allowed SeaDrop contracts are updated. */ event AllowedSeaDropUpdated(address[] allowedSeaDrop); /** * @notice Update the allowed SeaDrop contracts. * * @param allowedSeaDrop The allowed SeaDrop addresses. */ function updateAllowedSeaDrop(address[] calldata allowedSeaDrop) external; /** * @notice Mint tokens, restricted to the SeaDrop contract. * * @param minter The address to mint to. * @param quantity The number of tokens to mint. */ function mintSeaDrop(address minter, uint256 quantity) external payable; /** * @notice Returns a set of mint stats for the address. * This assists SeaDrop in enforcing maxSupply, * maxMintsPerWallet, and maxTokenSupplyForStage checks. * * @param minter The minter address. */ function getMintStats(address minter) external view returns ( uint256 minterNumMinted, uint256 currentTotalSupply, uint256 maxSupply ); /** * @notice Update public drop data for this nft contract on SeaDrop. * Use `updatePublicDropFee` to update the fee recipient or feeBps. * * @param seaDropImpl The allowed SeaDrop contract. * @param publicDrop The public drop data. */ function updatePublicDrop( address seaDropImpl, PublicDrop calldata publicDrop ) external; /** * @notice Update allow list data for this nft contract on SeaDrop. * * @param seaDropImpl The allowed SeaDrop contract. * @param allowListData The allow list data. */ function updateAllowList( address seaDropImpl, AllowListData calldata allowListData ) external; /** * @notice Update token gated drop stage data for this nft contract * on SeaDrop. * * @param seaDropImpl The allowed SeaDrop contract. * @param allowedNftToken The allowed nft token. * @param dropStage The token gated drop stage data. */ function updateTokenGatedDrop( address seaDropImpl, address allowedNftToken, TokenGatedDropStage calldata dropStage ) external; /** * @notice Update the drop URI for this nft contract on SeaDrop. * * @param seaDropImpl The allowed SeaDrop contract. * @param dropURI The new drop URI. */ function updateDropURI(address seaDropImpl, string calldata dropURI) external; /** * @notice Update the creator payout address for this nft contract on SeaDrop. * Only the owner can set the creator payout address. * * @param seaDropImpl The allowed SeaDrop contract. * @param payoutAddress The new payout address. */ function updateCreatorPayoutAddress( address seaDropImpl, address payoutAddress ) external; /** * @notice Update the allowed fee recipient for this nft contract * on SeaDrop. * Only the administrator can set the allowed fee recipient. * * @param seaDropImpl The allowed SeaDrop contract. * @param feeRecipient The new fee recipient. */ function updateAllowedFeeRecipient( address seaDropImpl, address feeRecipient, bool allowed ) external; /** * @notice Update the server side signers for this nft contract * on SeaDrop. * Only the owner or administrator can update the signers. * * @param seaDropImpl The allowed SeaDrop contract. * @param newSigners The new signers. */ function updateSigners(address seaDropImpl, address[] calldata newSigners) external; }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument. mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) ) } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "APPROVE_FAILED"); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Gas optimized verification of proof of inclusion for a leaf in a Merkle tree. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleProofLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol) library MerkleProofLib { function verify( bytes32[] calldata proof, bytes32 root, bytes32 leaf ) internal pure returns (bool isValid) { assembly { if proof.length { // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(proof.offset, shl(5, proof.length)) // Initialize `offset` to the offset of `proof` in the calldata. let offset := proof.offset // Iterate over proof elements to compute root hash. // prettier-ignore for {} 1 {} { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(leaf, calldataload(offset))) // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), calldataload(offset)) // Reuse `leaf` to store the hash to reduce stack operations. leaf := keccak256(0x00, 0x40) offset := add(offset, 0x20) // prettier-ignore if iszero(lt(offset, end)) { break } } } isValid := eq(leaf, root) } } function verifyMultiProof( bytes32[] calldata proof, bytes32 root, bytes32[] calldata leafs, bool[] calldata flags ) internal pure returns (bool isValid) { // Rebuilds the root by consuming and producing values on a queue. // The queue starts with the `leafs` array, and goes into a `hashes` array. // After the process, the last element on the queue is verified // to be equal to the `root`. // // The `flags` array denotes whether the sibling // should be popped from the queue (`flag == true`), or // should be popped from the `proof` (`flag == false`). assembly { // If the number of flags is correct. // prettier-ignore for {} eq(add(leafs.length, proof.length), add(flags.length, 1)) {} { // Left shift by 5 is equivalent to multiplying by 0x20. // Compute the end calldata offset of `leafs`. let leafsEnd := add(leafs.offset, shl(5, leafs.length)) // These are the calldata offsets. let leafsOffset := leafs.offset let flagsOffset := flags.offset let proofOffset := proof.offset // We can use the free memory space for the queue. // We don't need to allocate, since the queue is temporary. let hashesFront := mload(0x40) let hashesBack := hashesFront // This is the end of the memory for the queue. let end := add(hashesBack, shl(5, flags.length)) // For the case where `proof.length + leafs.length == 1`. if iszero(flags.length) { // If `proof.length` is zero, `leafs.length` is 1. if iszero(proof.length) { isValid := eq(calldataload(leafsOffset), root) break } // If `leafs.length` is zero, `proof.length` is 1. if iszero(leafs.length) { isValid := eq(calldataload(proofOffset), root) break } } // prettier-ignore for {} 1 {} { let a := 0 // Pops a value from the queue into `a`. switch lt(leafsOffset, leafsEnd) case 0 { // Pop from `hashes` if there are no more leafs. a := mload(hashesFront) hashesFront := add(hashesFront, 0x20) } default { // Otherwise, pop from `leafs`. a := calldataload(leafsOffset) leafsOffset := add(leafsOffset, 0x20) } let b := 0 // If the flag is false, load the next proof, // else, pops from the queue. switch calldataload(flagsOffset) case 0 { // Loads the next proof. b := calldataload(proofOffset) proofOffset := add(proofOffset, 0x20) } default { // Pops a value from the queue into `a`. switch lt(leafsOffset, leafsEnd) case 0 { // Pop from `hashes` if there are no more leafs. b := mload(hashesFront) hashesFront := add(hashesFront, 0x20) } default { // Otherwise, pop from `leafs`. b := calldataload(leafsOffset) leafsOffset := add(leafsOffset, 0x20) } } // Advance to the next flag offset. flagsOffset := add(flagsOffset, 0x20) // Slot of `a` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(a, b)) // Hash the scratch space and push the result onto the queue. mstore(scratch, a) mstore(xor(scratch, 0x20), b) mstore(hashesBack, keccak256(0x00, 0x40)) hashesBack := add(hashesBack, 0x20) // prettier-ignore if iszero(lt(hashesBack, end)) { break } } // Checks if the last value in the queue is same as the root. isValid := eq(mload(sub(hashesBack, 0x20)), root) break } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: 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 Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.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. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else 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. /// @solidity memory-safe-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 = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } if (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.11; import { PublicDrop, TokenGatedDropStage } from "./SeaDropStructs.sol"; interface SeaDropErrorsAndEvents { /** * @dev Revert with an error if the drop stage is not active. */ error NotActive( uint256 currentTimestamp, uint256 startTimestamp, uint256 endTimestamp ); /** * @dev Revert with an error if the mint quantity exceeds the max allowed * per transaction. */ error MintQuantityExceedsMaxPerTransaction(uint256 quantity, uint256 allowed); /** * @dev Revert with an error if the mint quantity exceeds the max allowed * to be minted per wallet. */ error MintQuantityExceedsMaxMintedPerWallet(uint256 total, uint256 allowed); /** * @dev Revert with an error if the mint quantity exceeds the max token * supply. */ error MintQuantityExceedsMaxSupply(uint256 total, uint256 maxSupply); /** * @dev Revert with an error if the mint quantity exceeds the max token * supply for the stage. */ error MintQuantityExceedsMaxTokenSupplyForStage(uint256 total, uint256 maxTokenSupplyForStage); /** * @dev Revert if the fee recipient is the zero address. */ error FeeRecipientCannotBeZeroAddress(); /** * @dev Revert if the fee recipient is restricted and not allowe. */ error FeeRecipientNotAllowed(); /** * @dev Revert if the creator payout address is the zero address. */ error CreatorPayoutAddressCannotBeZeroAddress(); /** * @dev Revert with an error if the allow list is already redeemed. * TODO should you only be able to redeem from an allow list once? * would otherwise be capped by maxTotalMintableByWallet */ error AllowListRedeemed(address minter); /** * @dev Revert with an error if the received payment is incorrect. */ error IncorrectPayment(uint256 got, uint256 want); /** * @dev Revert with an error if the allow list proof is invalid. */ error InvalidProof(); /** * @dev Revert with an error if signer's signatuer is invalid. */ error InvalidSignature(address recoveredSigner); /** * @dev Revert with an error if the sender does not * match the IERC721SeaDrop interface. */ error OnlyIERC721SeaDrop(address sender); /** * @dev Revert with an error if the sender of a token gated supplied * drop stage redeem is not the owner of the token. */ error TokenGatedNotTokenOwner(address nftContract, address allowedNftContract, uint256 tokenId); /** * @dev Revert with an error if the token id has already been used to * redeem a token gated drop stage. */ error TokenGatedTokenIdAlreadyRedeemed(address nftContract, address allowedNftContract, uint256 tokenId); /** * @dev An event with details of a SeaDrop mint, for analytical purposes. * * @param nftContract The nft contract. * @param minter The mint recipient. * @param feeRecipient The fee recipient. * @param payer The address who payed for the tx. * @param quantityMinted The number of tokens minted. * @param unitMintPrice The amount paid for each token. * @param feeBps The fee out of 10_000 basis points collected. * @param dropStageIndex The drop stage index. Items minted * through mintPublic() have * dropStageIndex of 0. */ event SeaDropMint( address indexed nftContract, address indexed minter, address indexed feeRecipient, address payer, uint256 quantityMinted, uint256 unitMintPrice, uint256 feeBps, uint256 dropStageIndex ); /** * @dev An event with updated public drop data for an nft contract. */ event PublicDropUpdated(address indexed nftContract, PublicDrop publicDrop); /** * @dev An event with updated token gated drop stage data * for an nft contract. */ event TokenGatedDropStageUpdated( address indexed nftContract, address indexed allowedNftToken, TokenGatedDropStage dropStage ); /** * @dev An event with updated allow list data for an nft contract. * * @param nftContract The nft contract. * @param previousMerkleRoot The previous allow list merkle root. * @param newMerkleRoot The new allow list merkle root. * @param publicKeyURI If the allow list is encrypted, the public key * URIs that can decrypt the list. * Empty if unencrypted. * @param allowListURI The URI for the allow list. */ event AllowListUpdated( address indexed nftContract, bytes32 indexed previousMerkleRoot, bytes32 indexed newMerkleRoot, string[] publicKeyURI, string allowListURI ); /** * @dev An event with updated drop URI for an nft contract. */ event DropURIUpdated(address indexed nftContract, string newDropURI); /** * @dev An event with the updated creator payout address for an nft contract. */ event CreatorPayoutAddressUpdated( address indexed nftContract, address indexed newPayoutAddress ); /** * @dev An event with the updated allowed fee recipient for an nft contract. */ event AllowedFeeRecipientUpdated( address indexed nftContract, address indexed feeRecipient, bool indexed allowed ); /** * @dev An event with the updated server side signers for an nft contract. */ event SignersUpdated( address indexed nftContract, address[] oldSigners, address[] newSigners ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.11; interface IERC721ContractMetadata { /** * @dev Emit an event when the max token supply is updated. */ event MaxSupplyUpdated(uint256 newMaxSupply); /** * @dev Emit an event with the previous and new provenance hash after * being updated. */ event ProvenanceHashUpdated(bytes32 previousHash, bytes32 newHash); /** * @dev Emit an event when the URI for the collection-level metadata * is updated. */ event ContractURIUpdated(string newContractURI); /** * @dev Emit an event for partial reveals/updates. * Batch update implementation should be left to contract. * * @param startTokenId The start token id. * @param endTokenId The end token id. */ event TokenURIUpdated( uint256 indexed startTokenId, uint256 indexed endTokenId ); /** * @dev Emit an event for full token metadata reveals/updates. * * @param baseURI The base URI. */ event BaseURIUpdated(string baseURI); /** * @notice Returns the contract URI. */ function contractURI() external view returns (string memory); /** * @notice Sets the contract URI for contract metadata. * * @param newContractURI The new contract URI. */ function setContractURI(string calldata newContractURI) external; /** * @notice Returns the base URI for token metadata. */ function baseURI() external view returns (string memory); /** * @notice Sets the base URI for the token metadata and emits an event. * * @param tokenURI The new base URI to set. */ function setBaseURI(string calldata tokenURI) external; /** * @notice Returns the max token supply. */ function maxSupply() external view returns (uint256); /** * @notice Sets the max supply and emits an event. * * @param newMaxSupply The new max supply to set. */ function setMaxSupply(uint256 newMaxSupply) external; /** * @notice Returns the total token supply. */ function totalSupply() external view returns (uint256); /** * @notice Returns the provenance hash. * The provenance hash is used for random reveals, which * is a hash of the ordered metadata to show it is unmodified * after mint has started. */ function provenanceHash() external view returns (bytes32); /** * @notice Sets the provenance hash and emits an event. * The provenance hash is used for random reveals, which * is a hash of the ordered metadata to show it is unmodified * after mint has started. * This function will revert after the first item has been minted. * * @param newProvenanceHash The new provenance hash to set. */ function setProvenanceHash(bytes32 newProvenanceHash) external; /** * @dev Revert with an error when attempting to set the provenance * hash after the mint has started. */ error ProvenanceHashCannotBeSetAfterMintStarted(); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // 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); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
{ "remappings": [ "ERC721A/=lib/ERC721A/contracts/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "murky/=lib/murky/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "seadrop/=src/", "solady/=lib/solady/src/", "solmate/=lib/solmate/src/", "utility-contracts/=lib/utility-contracts/src/", "src/=src/", "test/=test/", "script/=script/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"minter","type":"address"}],"name":"AllowListRedeemed","type":"error"},{"inputs":[],"name":"CreatorPayoutAddressCannotBeZeroAddress","type":"error"},{"inputs":[],"name":"FeeRecipientCannotBeZeroAddress","type":"error"},{"inputs":[],"name":"FeeRecipientNotAllowed","type":"error"},{"inputs":[{"internalType":"uint256","name":"got","type":"uint256"},{"internalType":"uint256","name":"want","type":"uint256"}],"name":"IncorrectPayment","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[{"internalType":"address","name":"recoveredSigner","type":"address"}],"name":"InvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256","name":"allowed","type":"uint256"}],"name":"MintQuantityExceedsMaxMintedPerWallet","type":"error"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"uint256","name":"allowed","type":"uint256"}],"name":"MintQuantityExceedsMaxPerTransaction","type":"error"},{"inputs":[{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256","name":"maxSupply","type":"uint256"}],"name":"MintQuantityExceedsMaxSupply","type":"error"},{"inputs":[{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256","name":"maxTokenSupplyForStage","type":"uint256"}],"name":"MintQuantityExceedsMaxTokenSupplyForStage","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentTimestamp","type":"uint256"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"}],"name":"NotActive","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"OnlyIERC721SeaDrop","type":"error"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"address","name":"allowedNftContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TokenGatedNotTokenOwner","type":"error"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"address","name":"allowedNftContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TokenGatedTokenIdAlreadyRedeemed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":true,"internalType":"bytes32","name":"previousMerkleRoot","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newMerkleRoot","type":"bytes32"},{"indexed":false,"internalType":"string[]","name":"publicKeyURI","type":"string[]"},{"indexed":false,"internalType":"string","name":"allowListURI","type":"string"}],"name":"AllowListUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":true,"internalType":"address","name":"feeRecipient","type":"address"},{"indexed":true,"internalType":"bool","name":"allowed","type":"bool"}],"name":"AllowedFeeRecipientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":true,"internalType":"address","name":"newPayoutAddress","type":"address"}],"name":"CreatorPayoutAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":false,"internalType":"string","name":"newDropURI","type":"string"}],"name":"DropURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"components":[{"internalType":"uint80","name":"mintPrice","type":"uint80"},{"internalType":"uint64","name":"startTime","type":"uint64"},{"internalType":"uint40","name":"maxMintsPerWallet","type":"uint40"},{"internalType":"uint16","name":"feeBps","type":"uint16"},{"internalType":"bool","name":"restrictFeeRecipients","type":"bool"}],"indexed":false,"internalType":"struct PublicDrop","name":"publicDrop","type":"tuple"}],"name":"PublicDropUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":true,"internalType":"address","name":"feeRecipient","type":"address"},{"indexed":false,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"uint256","name":"quantityMinted","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unitMintPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeBps","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dropStageIndex","type":"uint256"}],"name":"SeaDropMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":false,"internalType":"address[]","name":"oldSigners","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"newSigners","type":"address[]"}],"name":"SignersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":true,"internalType":"address","name":"allowedNftToken","type":"address"},{"components":[{"internalType":"uint80","name":"mintPrice","type":"uint80"},{"internalType":"uint16","name":"maxTotalMintableByWallet","type":"uint16"},{"internalType":"uint48","name":"startTime","type":"uint48"},{"internalType":"uint48","name":"endTime","type":"uint48"},{"internalType":"uint8","name":"dropStageIndex","type":"uint8"},{"internalType":"uint40","name":"maxTokenSupplyForStage","type":"uint40"},{"internalType":"uint16","name":"feeBps","type":"uint16"},{"internalType":"bool","name":"restrictFeeRecipients","type":"bool"}],"indexed":false,"internalType":"struct TokenGatedDropStage","name":"dropStage","type":"tuple"}],"name":"TokenGatedDropStageUpdated","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINT_DATA_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"getAllowListMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"getCreatorPayoutAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"getDropURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"getFeeRecipientIsAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"getPublicDrop","outputs":[{"components":[{"internalType":"uint80","name":"mintPrice","type":"uint80"},{"internalType":"uint64","name":"startTime","type":"uint64"},{"internalType":"uint40","name":"maxMintsPerWallet","type":"uint40"},{"internalType":"uint16","name":"feeBps","type":"uint16"},{"internalType":"bool","name":"restrictFeeRecipients","type":"bool"}],"internalType":"struct PublicDrop","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"getSigners","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"getTokenGatedAllowedTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"address","name":"allowedNftToken","type":"address"}],"name":"getTokenGatedDrop","outputs":[{"components":[{"internalType":"uint80","name":"mintPrice","type":"uint80"},{"internalType":"uint16","name":"maxTotalMintableByWallet","type":"uint16"},{"internalType":"uint48","name":"startTime","type":"uint48"},{"internalType":"uint48","name":"endTime","type":"uint48"},{"internalType":"uint8","name":"dropStageIndex","type":"uint8"},{"internalType":"uint40","name":"maxTokenSupplyForStage","type":"uint40"},{"internalType":"uint16","name":"feeBps","type":"uint16"},{"internalType":"bool","name":"restrictFeeRecipients","type":"bool"}],"internalType":"struct TokenGatedDropStage","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"components":[{"internalType":"uint256","name":"mintPrice","type":"uint256"},{"internalType":"uint256","name":"maxTotalMintableByWallet","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"dropStageIndex","type":"uint256"},{"internalType":"uint256","name":"maxTokenSupplyForStage","type":"uint256"},{"internalType":"uint256","name":"feeBps","type":"uint256"},{"internalType":"bool","name":"restrictFeeRecipients","type":"bool"}],"internalType":"struct MintParams","name":"mintParams","type":"tuple"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"mintAllowList","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"address","name":"minter","type":"address"},{"components":[{"internalType":"address","name":"allowedNftToken","type":"address"},{"internalType":"uint256[]","name":"allowedNftTokenIds","type":"uint256[]"}],"internalType":"struct TokenGatedMintParams[]","name":"tokenGatedMintParams","type":"tuple[]"}],"name":"mintAllowedTokenHolder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"mintPublic","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"components":[{"internalType":"uint256","name":"mintPrice","type":"uint256"},{"internalType":"uint256","name":"maxTotalMintableByWallet","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"dropStageIndex","type":"uint256"},{"internalType":"uint256","name":"maxTokenSupplyForStage","type":"uint256"},{"internalType":"uint256","name":"feeBps","type":"uint256"},{"internalType":"bool","name":"restrictFeeRecipients","type":"bool"}],"internalType":"struct MintParams","name":"mintParams","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"mintSigned","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"string[]","name":"publicKeyURIs","type":"string[]"},{"internalType":"string","name":"allowListURI","type":"string"}],"internalType":"struct AllowListData","name":"allowListData","type":"tuple"}],"name":"updateAllowList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"updateAllowedFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_payoutAddress","type":"address"}],"name":"updateCreatorPayoutAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newDropURI","type":"string"}],"name":"updateDropURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint80","name":"mintPrice","type":"uint80"},{"internalType":"uint64","name":"startTime","type":"uint64"},{"internalType":"uint40","name":"maxMintsPerWallet","type":"uint40"},{"internalType":"uint16","name":"feeBps","type":"uint16"},{"internalType":"bool","name":"restrictFeeRecipients","type":"bool"}],"internalType":"struct PublicDrop","name":"publicDrop","type":"tuple"}],"name":"updatePublicDrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"newSigners","type":"address[]"}],"name":"updateSigners","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"address","name":"allowedNftToken","type":"address"},{"components":[{"internalType":"uint80","name":"mintPrice","type":"uint80"},{"internalType":"uint16","name":"maxTotalMintableByWallet","type":"uint16"},{"internalType":"uint48","name":"startTime","type":"uint48"},{"internalType":"uint48","name":"endTime","type":"uint48"},{"internalType":"uint8","name":"dropStageIndex","type":"uint8"},{"internalType":"uint40","name":"maxTokenSupplyForStage","type":"uint40"},{"internalType":"uint16","name":"feeBps","type":"uint16"},{"internalType":"bool","name":"restrictFeeRecipients","type":"bool"}],"internalType":"struct TokenGatedDropStage","name":"dropStage","type":"tuple"}],"name":"updateTokenGatedDrop","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60c060405234801561001057600080fd5b506040805180820182526007815266053656144726f760cc1b6020918201528151808301835260018152603160f81b9082015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f918101919091527f752a02269614d51d9b7bd0a2f05cf03e553ce6be8b487650a6a2a4990208d804918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160408051601f1981840301815291905280516020909101206080527f5d2d2748b9e0b62f8bb884fa4fa88030198735648d300a06521feab7a3d6552d60a05260805160a051612fd461013c600039600081816103a601526115fa01526000818161037201526115d90152612fd46000f3fe60806040526004361061012a5760003560e01c80636d999226116100ab5780639d1636f31161006f5780639d1636f3146104bf578063b957d0cb146104ec578063bbf1ab0c1461050c578063bc6a629c1461052c578063bf52a8a914610653578063ebb4a55f1461066657600080fd5b80636d9992261461042c57806379627a321461044c5780637e3ba6af1461045f5780638e7d1e431461047f57806396751ae91461049f57600080fd5b806332bf11f5116100f257806332bf11f51461031c5780633644e5151461036057806337ca8c03146103945780634300a4e6146103c85780635cb3c4d3146103db57600080fd5b80630b0e8a6e1461012f57806312738db814610261578063161ac21f146102835780632db526eb14610296578063322e75d1146102c3575b600080fd5b34801561013b57600080fd5b5061024b61014a366004612012565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810191909152506001600160a01b03808316600090815260076020908152604080832093851683529281529082902082516101008101845281546001600160501b038116825261ffff600160501b820481169483019490945265ffffffffffff600160601b8204811695830195909552600160901b8104909416606082015260ff600160c01b85048116608083015264ffffffffff600160c81b86041660a0830152600160f01b90940490921660c083015260010154909116151560e082015292915050565b604051610258919061204b565b60405180910390f35b34801561026d57600080fd5b5061028161027c3660046120ef565b610686565b005b610281610291366004612113565b61076c565b3480156102a257600080fd5b506102b66102b13660046120ef565b610893565b60405161025891906121a8565b3480156102cf57600080fd5b5061030c6102de366004612012565b6001600160a01b03918216600090815260046020908152604080832093909416825291909152205460ff1690565b6040519015158152602001610258565b34801561032857600080fd5b506103526103373660046120ef565b6001600160a01b031660009081526003602052604090205490565b604051908152602001610258565b34801561036c57600080fd5b506103527f000000000000000000000000000000000000000000000000000000000000000081565b3480156103a057600080fd5b506103527f000000000000000000000000000000000000000000000000000000000000000081565b6102816103d6366004612218565b610909565b3480156103e757600080fd5b506104146103f63660046120ef565b6001600160a01b039081166000908152600260205260409020541690565b6040516001600160a01b039091168152602001610258565b34801561043857600080fd5b506102816104473660046122b0565b6109ed565b61028161045a3660046122c2565b610ad1565b34801561046b57600080fd5b506102b661047a3660046120ef565b610e10565b34801561048b57600080fd5b5061028161049a36600461235b565b610e84565b3480156104ab57600080fd5b506102816104ba366004612389565b610f6e565b3480156104cb57600080fd5b506104df6104da3660046120ef565b611209565b60405161025891906123ca565b3480156104f857600080fd5b50610281610507366004612460565b6112ab565b34801561051857600080fd5b50610281610527366004612495565b611397565b34801561053857600080fd5b506105f26105473660046120ef565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506001600160a01b031660009081526020818152604091829020825160a08101845290546001600160501b0381168252600160501b81046001600160401b031692820192909252600160901b820464ffffffffff1692810192909252600160b81b810461ffff166060830152600160c81b900460ff161515608082015290565b6040516102589190600060a0820190506001600160501b0383511682526001600160401b03602084015116602083015264ffffffffff604084015116604083015261ffff606084015116606083015260808301511515608083015292915050565b6102816106613660046124de565b611587565b34801561067257600080fd5b50610281610681366004612563565b61173c565b6040516301ffc9a760e01b815233906301ffc9a7906106b09063290d607b60e21b9060040161259d565b602060405180830381865afa1580156106cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f191906125b2565b6107155760405163104fa0ef60e11b81523360048201526024015b60405180910390fd5b3360008181526002602052604080822080546001600160a01b0319166001600160a01b03861690811790915590519092917f0c69f21751e800ea5960436c9a94370c7adbf54c733a20a025293fbbe8f1625291a350565b6001600160a01b03841660009081526020818152604091829020825160a08101845290546001600160501b0381168252600160501b81046001600160401b0316928201839052600160901b810464ffffffffff1693820193909352600160b81b830461ffff166060820152600160c81b90920460ff16151560808301524210156108285760208101516040516309ed117960e11b81524260048201526001600160401b039182166024820152604481019190915260640161070c565b61083f8282600001516001600160501b031661183d565b610858858484846040015164ffffffffff16600061187e565b610867858583608001516119c4565b61088c85848484600001516001600160501b03166000866060015161ffff168a611a46565b5050505050565b6001600160a01b0381166000908152600860209081526040918290208054835181840281018401909452808452606093928301828280156108fd57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116108df575b50505050509050919050565b61091b83604001358460600135611b1e565b61092684843561183d565b61093b87868686602001358760a0013561187e565b6109568787610951610100870160e088016125cf565b6119c4565b6109af8282600360008b6001600160a01b03166001600160a01b03168152602001908152602001600020548887604051602001610994929190612647565b60405160208183030381529060405280519060200120611b59565b6109cc576040516309bde33960e01b815260040160405180910390fd5b6109e48786868635608088013560c08901358c611a46565b50505050505050565b6040516301ffc9a760e01b815233906301ffc9a790610a179063290d607b60e21b9060040161259d565b602060405180830381865afa158015610a34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a5891906125b2565b610a775760405163104fa0ef60e11b815233600482015260240161070c565b3360009081526020819052604090208190610a9282826126df565b505060405133907ffb8089f2dff2c2a47c0a399dd9bd178cd9885036fd9dcea23f8ad0dcb6ffbbf890610ac69084906127f6565b60405180910390a250565b6000805b82811015610dde5736848483818110610af057610af061287a565b9050602002810190610b029190612890565b6001600160a01b038916600090815260076020908152604082209293509091908290610b30908501856120ef565b6001600160a01b0316815260208101919091526040016000208054909150610b709065ffffffffffff600160601b8204811691600160901b900416611b1e565b6001810154610b85908a908a9060ff166119c4565b6000610b9460208401846128b0565b8354909250610bad91506001600160501b03168261290f565b610bb7908661292e565b8254909550610be5908b908a908490600160501b810461ffff1690600160c81b900464ffffffffff1661187e565b60005b81811015610d9c576000610bff60208601866128b0565b83818110610c0f57610c0f61287a565b905060200201359050896001600160a01b0316856000016020810190610c3591906120ef565b6001600160a01b0316636352211e836040518263ffffffff1660e01b8152600401610c6291815260200190565b602060405180830381865afa158015610c7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca39190612946565b6001600160a01b031614610cf2578b610cbf60208701876120ef565b60405163da8c7bc760e01b81526001600160a01b039283166004820152911660248201526044810182905260640161070c565b6001600160a01b038c1660009081526009602090815260408220908290610d1b908901896120ef565b6001600160a01b031681526020808201929092526040908101600090812085825290925290205460ff169050801515600103610d92578c610d5f60208801886120ef565b60405163a93f299b60e01b81526001600160a01b039283166004820152911660248201526044810183905260640161070c565b5050600101610be8565b508154610dd0908b908a9084906001600160501b03811690600160c01b810460ff1690600160f01b900461ffff168f611a46565b836001019350505050610ad5565b50803414610e0857604051630d35e92160e01b81523460048201526024810182905260440161070c565b505050505050565b6001600160a01b0381166000908152600660209081526040918290208054835181840281018401909452808452606093928301828280156108fd576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116108df5750505050509050919050565b6040516301ffc9a760e01b815233906301ffc9a790610eae9063290d607b60e21b9060040161259d565b602060405180830381865afa158015610ecb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eef91906125b2565b610f0e5760405163104fa0ef60e11b815233600482015260240161070c565b3360008181526004602090815260408083206001600160a01b0387168085529252808320805460ff19168615159081179091559051909391927f6486c31f9d664e241acf94ec2541d328f6b9e97257ae16a1d887f296f879719f91a45050565b6040516301ffc9a760e01b815233906301ffc9a790610f989063290d607b60e21b9060040161259d565b602060405180830381865afa158015610fb5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd991906125b2565b610ff85760405163104fa0ef60e11b815233600482015260240161070c565b336000908152600660209081526040808320805482518185028101850190935280835290939284919083018282801561105a57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161103c575b505033600090815260066020526040812094955061107d9493509150611fcb9050565b60005b838110156110e8578285858381811061109b5761109b61287a565b90506020020160208101906110b091906120ef565b815460018082018455600093845260209093200180546001600160a01b0319166001600160a01b039290921691909117905501611080565b50336000908152600560205260408120905b825181101561115457600082600085848151811061111a5761111a61287a565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff19169115159190911790556001016110fa565b5060005b848110156111bc5760018260008888858181106111775761117761287a565b905060200201602081019061118c91906120ef565b6001600160a01b031681526020810191909152604001600020805460ff1916911515919091179055600101611158565b50336001600160a01b03167ff91188cded8aeb0b400eb42edd175d6dc8d5e5a9f457adfc27e0be7bd612caab8387876040516111fa93929190612963565b60405180910390a25050505050565b6001600160a01b0381166000908152600160205260409020805460609190611230906129c6565b80601f016020809104026020016040519081016040528092919081815260200182805461125c906129c6565b80156108fd5780601f1061127e576101008083540402835291602001916108fd565b820191906000526020600020905b81548152906001019060200180831161128c5750939695505050505050565b6040516301ffc9a760e01b815233906301ffc9a7906112d59063290d607b60e21b9060040161259d565b602060405180830381865afa1580156112f2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061131691906125b2565b6113355760405163104fa0ef60e11b815233600482015260240161070c565b33600090815260016020526040902061134f828483612a56565b50336001600160a01b03167fa0295608d25b3033c2e2c41cbac8746c2d08767bcfde6d47fae1ed7ba1d32150838360405161138b929190612b3e565b60405180910390a25050565b6040516301ffc9a760e01b815233906301ffc9a7906113c19063290d607b60e21b9060040161259d565b602060405180830381865afa1580156113de573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061140291906125b2565b6114215760405163104fa0ef60e11b815233600482015260240161070c565b6001600160a01b03808416600090815260076020908152604080832093861683529290522081906114528282612b97565b50600090506114676040830160208401612d13565b61ffff161115611537576000805b6001600160a01b0385166000908152600860205260409020548110156114eb576001600160a01b038581166000908152600860205260409020805491861691839081106114c4576114c461287a565b6000918252602090912001546001600160a01b0316036114e357600191505b600101611475565b50801515600003611535576001600160a01b0384811660009081526008602090815260408220805460018101825590835291200180546001600160a01b0319169185169190911790555b505b816001600160a01b0316836001600160a01b03167f5ddb09355563c3e5d9f8472902701579edb3aca9bc1c2d53a316eafd91df9ebb8360405161157a9190612d46565b60405180910390a3505050565b61159983604001358460600135611b1e565b6115a484843561183d565b6115b987868686602001358760a0013561187e565b6115cf8787610951610100870160e088016125cf565b600061190160f01b7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000888760405160200161162d93929190612e06565b60408051601f198184030181529082905280516020918201206001600160f01b0319909416908201526022810191909152604281019190915260620160405160208183030381529060405280519060200120905060006116c584848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508693925050611b939050565b6001600160a01b03808b1660009081526005602090815260408083209385168352929052205490915060ff1661171957604051633615713d60e21b81526001600160a01b038216600482015260240161070c565b611731898888883560808a013560c08b01358e611a46565b505050505050505050565b6040516301ffc9a760e01b815233906301ffc9a7906117669063290d607b60e21b9060040161259d565b602060405180830381865afa158015611783573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a791906125b2565b6117c65760405163104fa0ef60e11b815233600482015260240161070c565b33600081815260036020908152604090912080548435918290559290918391907fefcd7e019bc8b47d27881fd59e2619280ca5894f285950f10ab049870652efa590611814908701876128b0565b6118216040890189612e2a565b6040516118319493929190612e70565b60405180910390a45050565b611847818361290f565b341461187a5734611858828461290f565b604051630d35e92160e01b81526004810192909252602482015260440161070c565b5050565b604051632103857560e21b81526001600160a01b038581166004830152600091829182919089169063840e15d490602401606060405180830381865afa1580156118cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f09190612f21565b9194509250905084611902848861292e565b111561193657611912838761292e565b60405163edc0127360e01b815260048101919091526024810186905260440161070c565b80611941838861292e565b111561197557611951828761292e565b60405163384b48c560e21b815260048101919091526024810182905260440161070c565b83156119ba5783611986838861292e565b11156119ba57611996828761292e565b604051635cc6d5f560e11b815260048101919091526024810185905260440161070c565b5050505050505050565b6001600160a01b0382166119eb57604051635136e8d560e01b815260040160405180910390fd5b6001811515148015611a2357506001600160a01b0380841660009081526004602090815260408083209386168352929052205460ff16155b15611a415760405163f477d26f60e01b815260040160405180910390fd5b505050565b611a51878284611bb7565b6040516364869dad60e01b81526001600160a01b038781166004830152602482018790528816906364869dad90604401600060405180830381600087803b158015611a9b57600080fd5b505af1158015611aaf573d6000803e3d6000fd5b5050604080513381526020810189905290810187905260608101859052608081018690526001600160a01b03808516935089811692508a16907fe90cf9cc0a552cf52ea6ff74ece0f1c8ae8cc9ad630d3181f55ac43ca076b7d69060a00160405180910390a450505050505050565b81421080611b2b57508042115b1561187a576040516309ed117960e11b8152426004820152602481018390526044810182905260640161070c565b60008315611b8b578360051b8501855b803580851160051b94855260209485185260406000209301818110611b695750505b501492915050565b6000806000611ba28585611c2d565b91509150611baf81611c9b565b509392505050565b6001600160a01b038084166000908152600260205260409020541680611bf057604051633f00976960e01b815260040160405180910390fd5b6000612710611bff843461290f565b611c099190612f4f565b90506000611c178234612f71565b9050611c238583611e54565b610e088382611e54565b6000808251604103611c635760208301516040840151606085015160001a611c5787828585611ea5565b94509450505050611c94565b8251604003611c8c5760208301516040840151611c81868383611f92565b935093505050611c94565b506000905060025b9250929050565b6000816004811115611caf57611caf612f88565b03611cb75750565b6001816004811115611ccb57611ccb612f88565b03611d185760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161070c565b6002816004811115611d2c57611d2c612f88565b03611d795760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161070c565b6003816004811115611d8d57611d8d612f88565b03611de55760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161070c565b6004816004811115611df957611df9612f88565b03611e515760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b606482015260840161070c565b50565b600080600080600085875af1905080611a415760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b604482015260640161070c565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611edc5750600090506003611f89565b8460ff16601b14158015611ef457508460ff16601c14155b15611f055750600090506004611f89565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611f59573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611f8257600060019250925050611f89565b9150600090505b94509492505050565b6000806001600160ff1b03831681611faf60ff86901c601b61292e565b9050611fbd87828885611ea5565b935093505050935093915050565b5080546000825590600052602060002090810190611e5191905b80821115611ff95760008155600101611fe5565b5090565b6001600160a01b0381168114611e5157600080fd5b6000806040838503121561202557600080fd5b823561203081611ffd565b9150602083013561204081611ffd565b809150509250929050565b6000610100820190506001600160501b03835116825261ffff6020840151166020830152604083015165ffffffffffff8082166040850152806060860151166060850152505060808301516120a5608084018260ff169052565b5060a08301516120be60a084018264ffffffffff169052565b5060c08301516120d460c084018261ffff169052565b5060e08301516120e860e084018215159052565b5092915050565b60006020828403121561210157600080fd5b813561210c81611ffd565b9392505050565b6000806000806080858703121561212957600080fd5b843561213481611ffd565b9350602085013561214481611ffd565b9250604085013561215481611ffd565b9396929550929360600135925050565b600081518084526020808501945080840160005b8381101561219d5781516001600160a01b031687529582019590820190600101612178565b509495945050505050565b60208152600061210c6020830184612164565b600061010082840312156121ce57600080fd5b50919050565b60008083601f8401126121e657600080fd5b5081356001600160401b038111156121fd57600080fd5b6020830191508360208260051b8501011115611c9457600080fd5b60008060008060008060006101a0888a03121561223457600080fd5b873561223f81611ffd565b9650602088013561224f81611ffd565b9550604088013561225f81611ffd565b9450606088013593506122758960808a016121bb565b92506101808801356001600160401b0381111561229157600080fd5b61229d8a828b016121d4565b989b979a50959850939692959293505050565b600060a082840312156121ce57600080fd5b6000806000806000608086880312156122da57600080fd5b85356122e581611ffd565b945060208601356122f581611ffd565b9350604086013561230581611ffd565b925060608601356001600160401b0381111561232057600080fd5b61232c888289016121d4565b969995985093965092949392505050565b8015158114611e5157600080fd5b80356123568161233d565b919050565b6000806040838503121561236e57600080fd5b823561237981611ffd565b915060208301356120408161233d565b6000806020838503121561239c57600080fd5b82356001600160401b038111156123b257600080fd5b6123be858286016121d4565b90969095509350505050565b600060208083528351808285015260005b818110156123f7578581018301518582016040015282016123db565b81811115612409576000604083870101525b50601f01601f1916929092016040019392505050565b60008083601f84011261243157600080fd5b5081356001600160401b0381111561244857600080fd5b602083019150836020828501011115611c9457600080fd5b6000806020838503121561247357600080fd5b82356001600160401b0381111561248957600080fd5b6123be8582860161241f565b600080600061014084860312156124ab57600080fd5b83356124b681611ffd565b925060208401356124c681611ffd565b91506124d585604086016121bb565b90509250925092565b60008060008060008060006101a0888a0312156124fa57600080fd5b873561250581611ffd565b9650602088013561251581611ffd565b9550604088013561252581611ffd565b94506060880135935061253b8960808a016121bb565b92506101808801356001600160401b0381111561255757600080fd5b61229d8a828b0161241f565b60006020828403121561257557600080fd5b81356001600160401b0381111561258b57600080fd5b82016060818503121561210c57600080fd5b6001600160e01b031991909116815260200190565b6000602082840312156125c457600080fd5b815161210c8161233d565b6000602082840312156125e157600080fd5b813561210c8161233d565b803582526020810135602083015260408101356040830152606081013560608301526080810135608083015260a081013560a083015260c081013560c083015260e081013561263a8161233d565b80151560e0840152505050565b6001600160a01b0383168152610120810161210c60208301846125ec565b6001600160501b0381168114611e5157600080fd5b6001600160401b0381168114611e5157600080fd5b64ffffffffff81168114611e5157600080fd5b600081356126af8161268f565b92915050565b61ffff81168114611e5157600080fd5b600081356126af816126b5565b600081356126af8161233d565b81356126ea81612665565b815469ffffffffffffffffffff19166001600160501b0382161782555060208201356127158161267a565b815467ffffffffffffffff60501b19811660509290921b67ffffffffffffffff60501b169182178355604084013561274c8161268f565b64ffffffffff60901b60909190911b166cffffffffffffffffffffffffff60501b1982168317811784556060850135612784816126b5565b6effffffffffffffffffffffffffffff60501b19929092169092179190911760b89190911b61ffff60b81b1617815561187a6127c2608084016126d2565b82805460ff60c81b191691151560c81b60ff60c81b16919091179055565b80356123568161268f565b8035612356816126b5565b60a08101823561280581612665565b6001600160501b03168252602083013561281e8161267a565b6001600160401b03166020830152604083013561283a8161268f565b64ffffffffff1660408301526060830135612854816126b5565b61ffff166060830152608083013561286b8161233d565b80151560808401525092915050565b634e487b7160e01b600052603260045260246000fd5b60008235603e198336030181126128a657600080fd5b9190910192915050565b6000808335601e198436030181126128c757600080fd5b8301803591506001600160401b038211156128e157600080fd5b6020019150600581901b3603821315611c9457600080fd5b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615612929576129296128f9565b500290565b60008219821115612941576129416128f9565b500190565b60006020828403121561295857600080fd5b815161210c81611ffd565b6040815260006129766040830186612164565b8281036020848101919091528482528591810160005b868110156129ba57833561299f81611ffd565b6001600160a01b03168252928201929082019060010161298c565b50979650505050505050565b600181811c908216806129da57607f821691505b6020821081036121ce57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b601f821115611a4157600081815260208120601f850160051c81016020861015612a375750805b601f850160051c820191505b81811015610e0857828155600101612a43565b6001600160401b03831115612a6d57612a6d6129fa565b612a8183612a7b83546129c6565b83612a10565b6000601f841160018114612ab55760008515612a9d5750838201355b600019600387901b1c1916600186901b17835561088c565b600083815260209020601f19861690835b82811015612ae65786850135825560209485019460019092019101612ac6565b5086821015612b035760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b602081526000612b52602083018486612b15565b949350505050565b65ffffffffffff81168114611e5157600080fd5b600081356126af81612b5a565b60ff81168114611e5157600080fd5b600081356126af81612b7b565b8135612ba281612665565b815469ffffffffffffffffffff19166001600160501b038216178255506020820135612bcd816126b5565b815461ffff60501b19811660509290921b61ffff60501b1691821783556040840135612bf881612b5a565b67ffffffffffffffff60501b1991909116909117606091821b65ffffffffffff60601b16178255612c5690612c2e908401612b6e565b82805465ffffffffffff60901b191660909290921b65ffffffffffff60901b16919091179055565b612c83612c6560808401612b8a565b82805460ff60c01b191660c09290921b60ff60c01b16919091179055565b612cb8612c9260a084016126a2565b82805464ffffffffff60c81b191660c89290921b64ffffffffff60c81b16919091179055565b612ceb612cc760c084016126c5565b8280546001600160f01b031660f09290921b6001600160f01b031916919091179055565b61187a612cfa60e084016126d2565b6001830160ff1981541660ff8315151681178255505050565b600060208284031215612d2557600080fd5b813561210c816126b5565b803561235681612b5a565b803561235681612b7b565b61010081018235612d5681612665565b6001600160501b031682526020830135612d6f816126b5565b61ffff1660208301526040830135612d8681612b5a565b65ffffffffffff166040830152612d9f60608401612d30565b65ffffffffffff166060830152612db860808401612d3b565b60ff166080830152612dcc60a084016127e0565b64ffffffffff1660a0830152612de460c084016127eb565b61ffff1660c0830152612df960e0840161234b565b80151560e08401526120e8565b8381526001600160a01b03831660208201526101408101612b5260408301846125ec565b6000808335601e19843603018112612e4157600080fd5b8301803591506001600160401b03821115612e5b57600080fd5b602001915036819003821315611c9457600080fd5b6040808252810184905260006060600586901b8301810190830187835b88811015612f0057858403605f190183528135368b9003601e19018112612eb357600080fd5b8a0160208181019135906001600160401b03821115612ed157600080fd5b813603831315612ee057600080fd5b612eeb878385612b15565b96509485019493909301925050600101612e8d565b5050508281036020840152612f16818587612b15565b979650505050505050565b600080600060608486031215612f3657600080fd5b8351925060208401519150604084015190509250925092565b600082612f6c57634e487b7160e01b600052601260045260246000fd5b500490565b600082821015612f8357612f836128f9565b500390565b634e487b7160e01b600052602160045260246000fdfea26469706673582212206e73effaf3764248c116ee3a72258ca43e9caeab94b45b782b420433b05beeb864736f6c634300080f0033
Deployed Bytecode
0x60806040526004361061012a5760003560e01c80636d999226116100ab5780639d1636f31161006f5780639d1636f3146104bf578063b957d0cb146104ec578063bbf1ab0c1461050c578063bc6a629c1461052c578063bf52a8a914610653578063ebb4a55f1461066657600080fd5b80636d9992261461042c57806379627a321461044c5780637e3ba6af1461045f5780638e7d1e431461047f57806396751ae91461049f57600080fd5b806332bf11f5116100f257806332bf11f51461031c5780633644e5151461036057806337ca8c03146103945780634300a4e6146103c85780635cb3c4d3146103db57600080fd5b80630b0e8a6e1461012f57806312738db814610261578063161ac21f146102835780632db526eb14610296578063322e75d1146102c3575b600080fd5b34801561013b57600080fd5b5061024b61014a366004612012565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810191909152506001600160a01b03808316600090815260076020908152604080832093851683529281529082902082516101008101845281546001600160501b038116825261ffff600160501b820481169483019490945265ffffffffffff600160601b8204811695830195909552600160901b8104909416606082015260ff600160c01b85048116608083015264ffffffffff600160c81b86041660a0830152600160f01b90940490921660c083015260010154909116151560e082015292915050565b604051610258919061204b565b60405180910390f35b34801561026d57600080fd5b5061028161027c3660046120ef565b610686565b005b610281610291366004612113565b61076c565b3480156102a257600080fd5b506102b66102b13660046120ef565b610893565b60405161025891906121a8565b3480156102cf57600080fd5b5061030c6102de366004612012565b6001600160a01b03918216600090815260046020908152604080832093909416825291909152205460ff1690565b6040519015158152602001610258565b34801561032857600080fd5b506103526103373660046120ef565b6001600160a01b031660009081526003602052604090205490565b604051908152602001610258565b34801561036c57600080fd5b506103527fc5a5659b242a6663b12840058c7853f303b645b3c900c86203f2e12030167f1781565b3480156103a057600080fd5b506103527f5d2d2748b9e0b62f8bb884fa4fa88030198735648d300a06521feab7a3d6552d81565b6102816103d6366004612218565b610909565b3480156103e757600080fd5b506104146103f63660046120ef565b6001600160a01b039081166000908152600260205260409020541690565b6040516001600160a01b039091168152602001610258565b34801561043857600080fd5b506102816104473660046122b0565b6109ed565b61028161045a3660046122c2565b610ad1565b34801561046b57600080fd5b506102b661047a3660046120ef565b610e10565b34801561048b57600080fd5b5061028161049a36600461235b565b610e84565b3480156104ab57600080fd5b506102816104ba366004612389565b610f6e565b3480156104cb57600080fd5b506104df6104da3660046120ef565b611209565b60405161025891906123ca565b3480156104f857600080fd5b50610281610507366004612460565b6112ab565b34801561051857600080fd5b50610281610527366004612495565b611397565b34801561053857600080fd5b506105f26105473660046120ef565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506001600160a01b031660009081526020818152604091829020825160a08101845290546001600160501b0381168252600160501b81046001600160401b031692820192909252600160901b820464ffffffffff1692810192909252600160b81b810461ffff166060830152600160c81b900460ff161515608082015290565b6040516102589190600060a0820190506001600160501b0383511682526001600160401b03602084015116602083015264ffffffffff604084015116604083015261ffff606084015116606083015260808301511515608083015292915050565b6102816106613660046124de565b611587565b34801561067257600080fd5b50610281610681366004612563565b61173c565b6040516301ffc9a760e01b815233906301ffc9a7906106b09063290d607b60e21b9060040161259d565b602060405180830381865afa1580156106cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f191906125b2565b6107155760405163104fa0ef60e11b81523360048201526024015b60405180910390fd5b3360008181526002602052604080822080546001600160a01b0319166001600160a01b03861690811790915590519092917f0c69f21751e800ea5960436c9a94370c7adbf54c733a20a025293fbbe8f1625291a350565b6001600160a01b03841660009081526020818152604091829020825160a08101845290546001600160501b0381168252600160501b81046001600160401b0316928201839052600160901b810464ffffffffff1693820193909352600160b81b830461ffff166060820152600160c81b90920460ff16151560808301524210156108285760208101516040516309ed117960e11b81524260048201526001600160401b039182166024820152604481019190915260640161070c565b61083f8282600001516001600160501b031661183d565b610858858484846040015164ffffffffff16600061187e565b610867858583608001516119c4565b61088c85848484600001516001600160501b03166000866060015161ffff168a611a46565b5050505050565b6001600160a01b0381166000908152600860209081526040918290208054835181840281018401909452808452606093928301828280156108fd57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116108df575b50505050509050919050565b61091b83604001358460600135611b1e565b61092684843561183d565b61093b87868686602001358760a0013561187e565b6109568787610951610100870160e088016125cf565b6119c4565b6109af8282600360008b6001600160a01b03166001600160a01b03168152602001908152602001600020548887604051602001610994929190612647565b60405160208183030381529060405280519060200120611b59565b6109cc576040516309bde33960e01b815260040160405180910390fd5b6109e48786868635608088013560c08901358c611a46565b50505050505050565b6040516301ffc9a760e01b815233906301ffc9a790610a179063290d607b60e21b9060040161259d565b602060405180830381865afa158015610a34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a5891906125b2565b610a775760405163104fa0ef60e11b815233600482015260240161070c565b3360009081526020819052604090208190610a9282826126df565b505060405133907ffb8089f2dff2c2a47c0a399dd9bd178cd9885036fd9dcea23f8ad0dcb6ffbbf890610ac69084906127f6565b60405180910390a250565b6000805b82811015610dde5736848483818110610af057610af061287a565b9050602002810190610b029190612890565b6001600160a01b038916600090815260076020908152604082209293509091908290610b30908501856120ef565b6001600160a01b0316815260208101919091526040016000208054909150610b709065ffffffffffff600160601b8204811691600160901b900416611b1e565b6001810154610b85908a908a9060ff166119c4565b6000610b9460208401846128b0565b8354909250610bad91506001600160501b03168261290f565b610bb7908661292e565b8254909550610be5908b908a908490600160501b810461ffff1690600160c81b900464ffffffffff1661187e565b60005b81811015610d9c576000610bff60208601866128b0565b83818110610c0f57610c0f61287a565b905060200201359050896001600160a01b0316856000016020810190610c3591906120ef565b6001600160a01b0316636352211e836040518263ffffffff1660e01b8152600401610c6291815260200190565b602060405180830381865afa158015610c7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca39190612946565b6001600160a01b031614610cf2578b610cbf60208701876120ef565b60405163da8c7bc760e01b81526001600160a01b039283166004820152911660248201526044810182905260640161070c565b6001600160a01b038c1660009081526009602090815260408220908290610d1b908901896120ef565b6001600160a01b031681526020808201929092526040908101600090812085825290925290205460ff169050801515600103610d92578c610d5f60208801886120ef565b60405163a93f299b60e01b81526001600160a01b039283166004820152911660248201526044810183905260640161070c565b5050600101610be8565b508154610dd0908b908a9084906001600160501b03811690600160c01b810460ff1690600160f01b900461ffff168f611a46565b836001019350505050610ad5565b50803414610e0857604051630d35e92160e01b81523460048201526024810182905260440161070c565b505050505050565b6001600160a01b0381166000908152600660209081526040918290208054835181840281018401909452808452606093928301828280156108fd576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116108df5750505050509050919050565b6040516301ffc9a760e01b815233906301ffc9a790610eae9063290d607b60e21b9060040161259d565b602060405180830381865afa158015610ecb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eef91906125b2565b610f0e5760405163104fa0ef60e11b815233600482015260240161070c565b3360008181526004602090815260408083206001600160a01b0387168085529252808320805460ff19168615159081179091559051909391927f6486c31f9d664e241acf94ec2541d328f6b9e97257ae16a1d887f296f879719f91a45050565b6040516301ffc9a760e01b815233906301ffc9a790610f989063290d607b60e21b9060040161259d565b602060405180830381865afa158015610fb5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd991906125b2565b610ff85760405163104fa0ef60e11b815233600482015260240161070c565b336000908152600660209081526040808320805482518185028101850190935280835290939284919083018282801561105a57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161103c575b505033600090815260066020526040812094955061107d9493509150611fcb9050565b60005b838110156110e8578285858381811061109b5761109b61287a565b90506020020160208101906110b091906120ef565b815460018082018455600093845260209093200180546001600160a01b0319166001600160a01b039290921691909117905501611080565b50336000908152600560205260408120905b825181101561115457600082600085848151811061111a5761111a61287a565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff19169115159190911790556001016110fa565b5060005b848110156111bc5760018260008888858181106111775761117761287a565b905060200201602081019061118c91906120ef565b6001600160a01b031681526020810191909152604001600020805460ff1916911515919091179055600101611158565b50336001600160a01b03167ff91188cded8aeb0b400eb42edd175d6dc8d5e5a9f457adfc27e0be7bd612caab8387876040516111fa93929190612963565b60405180910390a25050505050565b6001600160a01b0381166000908152600160205260409020805460609190611230906129c6565b80601f016020809104026020016040519081016040528092919081815260200182805461125c906129c6565b80156108fd5780601f1061127e576101008083540402835291602001916108fd565b820191906000526020600020905b81548152906001019060200180831161128c5750939695505050505050565b6040516301ffc9a760e01b815233906301ffc9a7906112d59063290d607b60e21b9060040161259d565b602060405180830381865afa1580156112f2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061131691906125b2565b6113355760405163104fa0ef60e11b815233600482015260240161070c565b33600090815260016020526040902061134f828483612a56565b50336001600160a01b03167fa0295608d25b3033c2e2c41cbac8746c2d08767bcfde6d47fae1ed7ba1d32150838360405161138b929190612b3e565b60405180910390a25050565b6040516301ffc9a760e01b815233906301ffc9a7906113c19063290d607b60e21b9060040161259d565b602060405180830381865afa1580156113de573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061140291906125b2565b6114215760405163104fa0ef60e11b815233600482015260240161070c565b6001600160a01b03808416600090815260076020908152604080832093861683529290522081906114528282612b97565b50600090506114676040830160208401612d13565b61ffff161115611537576000805b6001600160a01b0385166000908152600860205260409020548110156114eb576001600160a01b038581166000908152600860205260409020805491861691839081106114c4576114c461287a565b6000918252602090912001546001600160a01b0316036114e357600191505b600101611475565b50801515600003611535576001600160a01b0384811660009081526008602090815260408220805460018101825590835291200180546001600160a01b0319169185169190911790555b505b816001600160a01b0316836001600160a01b03167f5ddb09355563c3e5d9f8472902701579edb3aca9bc1c2d53a316eafd91df9ebb8360405161157a9190612d46565b60405180910390a3505050565b61159983604001358460600135611b1e565b6115a484843561183d565b6115b987868686602001358760a0013561187e565b6115cf8787610951610100870160e088016125cf565b600061190160f01b7fc5a5659b242a6663b12840058c7853f303b645b3c900c86203f2e12030167f177f5d2d2748b9e0b62f8bb884fa4fa88030198735648d300a06521feab7a3d6552d888760405160200161162d93929190612e06565b60408051601f198184030181529082905280516020918201206001600160f01b0319909416908201526022810191909152604281019190915260620160405160208183030381529060405280519060200120905060006116c584848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508693925050611b939050565b6001600160a01b03808b1660009081526005602090815260408083209385168352929052205490915060ff1661171957604051633615713d60e21b81526001600160a01b038216600482015260240161070c565b611731898888883560808a013560c08b01358e611a46565b505050505050505050565b6040516301ffc9a760e01b815233906301ffc9a7906117669063290d607b60e21b9060040161259d565b602060405180830381865afa158015611783573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a791906125b2565b6117c65760405163104fa0ef60e11b815233600482015260240161070c565b33600081815260036020908152604090912080548435918290559290918391907fefcd7e019bc8b47d27881fd59e2619280ca5894f285950f10ab049870652efa590611814908701876128b0565b6118216040890189612e2a565b6040516118319493929190612e70565b60405180910390a45050565b611847818361290f565b341461187a5734611858828461290f565b604051630d35e92160e01b81526004810192909252602482015260440161070c565b5050565b604051632103857560e21b81526001600160a01b038581166004830152600091829182919089169063840e15d490602401606060405180830381865afa1580156118cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f09190612f21565b9194509250905084611902848861292e565b111561193657611912838761292e565b60405163edc0127360e01b815260048101919091526024810186905260440161070c565b80611941838861292e565b111561197557611951828761292e565b60405163384b48c560e21b815260048101919091526024810182905260440161070c565b83156119ba5783611986838861292e565b11156119ba57611996828761292e565b604051635cc6d5f560e11b815260048101919091526024810185905260440161070c565b5050505050505050565b6001600160a01b0382166119eb57604051635136e8d560e01b815260040160405180910390fd5b6001811515148015611a2357506001600160a01b0380841660009081526004602090815260408083209386168352929052205460ff16155b15611a415760405163f477d26f60e01b815260040160405180910390fd5b505050565b611a51878284611bb7565b6040516364869dad60e01b81526001600160a01b038781166004830152602482018790528816906364869dad90604401600060405180830381600087803b158015611a9b57600080fd5b505af1158015611aaf573d6000803e3d6000fd5b5050604080513381526020810189905290810187905260608101859052608081018690526001600160a01b03808516935089811692508a16907fe90cf9cc0a552cf52ea6ff74ece0f1c8ae8cc9ad630d3181f55ac43ca076b7d69060a00160405180910390a450505050505050565b81421080611b2b57508042115b1561187a576040516309ed117960e11b8152426004820152602481018390526044810182905260640161070c565b60008315611b8b578360051b8501855b803580851160051b94855260209485185260406000209301818110611b695750505b501492915050565b6000806000611ba28585611c2d565b91509150611baf81611c9b565b509392505050565b6001600160a01b038084166000908152600260205260409020541680611bf057604051633f00976960e01b815260040160405180910390fd5b6000612710611bff843461290f565b611c099190612f4f565b90506000611c178234612f71565b9050611c238583611e54565b610e088382611e54565b6000808251604103611c635760208301516040840151606085015160001a611c5787828585611ea5565b94509450505050611c94565b8251604003611c8c5760208301516040840151611c81868383611f92565b935093505050611c94565b506000905060025b9250929050565b6000816004811115611caf57611caf612f88565b03611cb75750565b6001816004811115611ccb57611ccb612f88565b03611d185760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161070c565b6002816004811115611d2c57611d2c612f88565b03611d795760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161070c565b6003816004811115611d8d57611d8d612f88565b03611de55760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161070c565b6004816004811115611df957611df9612f88565b03611e515760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b606482015260840161070c565b50565b600080600080600085875af1905080611a415760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b604482015260640161070c565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611edc5750600090506003611f89565b8460ff16601b14158015611ef457508460ff16601c14155b15611f055750600090506004611f89565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611f59573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611f8257600060019250925050611f89565b9150600090505b94509492505050565b6000806001600160ff1b03831681611faf60ff86901c601b61292e565b9050611fbd87828885611ea5565b935093505050935093915050565b5080546000825590600052602060002090810190611e5191905b80821115611ff95760008155600101611fe5565b5090565b6001600160a01b0381168114611e5157600080fd5b6000806040838503121561202557600080fd5b823561203081611ffd565b9150602083013561204081611ffd565b809150509250929050565b6000610100820190506001600160501b03835116825261ffff6020840151166020830152604083015165ffffffffffff8082166040850152806060860151166060850152505060808301516120a5608084018260ff169052565b5060a08301516120be60a084018264ffffffffff169052565b5060c08301516120d460c084018261ffff169052565b5060e08301516120e860e084018215159052565b5092915050565b60006020828403121561210157600080fd5b813561210c81611ffd565b9392505050565b6000806000806080858703121561212957600080fd5b843561213481611ffd565b9350602085013561214481611ffd565b9250604085013561215481611ffd565b9396929550929360600135925050565b600081518084526020808501945080840160005b8381101561219d5781516001600160a01b031687529582019590820190600101612178565b509495945050505050565b60208152600061210c6020830184612164565b600061010082840312156121ce57600080fd5b50919050565b60008083601f8401126121e657600080fd5b5081356001600160401b038111156121fd57600080fd5b6020830191508360208260051b8501011115611c9457600080fd5b60008060008060008060006101a0888a03121561223457600080fd5b873561223f81611ffd565b9650602088013561224f81611ffd565b9550604088013561225f81611ffd565b9450606088013593506122758960808a016121bb565b92506101808801356001600160401b0381111561229157600080fd5b61229d8a828b016121d4565b989b979a50959850939692959293505050565b600060a082840312156121ce57600080fd5b6000806000806000608086880312156122da57600080fd5b85356122e581611ffd565b945060208601356122f581611ffd565b9350604086013561230581611ffd565b925060608601356001600160401b0381111561232057600080fd5b61232c888289016121d4565b969995985093965092949392505050565b8015158114611e5157600080fd5b80356123568161233d565b919050565b6000806040838503121561236e57600080fd5b823561237981611ffd565b915060208301356120408161233d565b6000806020838503121561239c57600080fd5b82356001600160401b038111156123b257600080fd5b6123be858286016121d4565b90969095509350505050565b600060208083528351808285015260005b818110156123f7578581018301518582016040015282016123db565b81811115612409576000604083870101525b50601f01601f1916929092016040019392505050565b60008083601f84011261243157600080fd5b5081356001600160401b0381111561244857600080fd5b602083019150836020828501011115611c9457600080fd5b6000806020838503121561247357600080fd5b82356001600160401b0381111561248957600080fd5b6123be8582860161241f565b600080600061014084860312156124ab57600080fd5b83356124b681611ffd565b925060208401356124c681611ffd565b91506124d585604086016121bb565b90509250925092565b60008060008060008060006101a0888a0312156124fa57600080fd5b873561250581611ffd565b9650602088013561251581611ffd565b9550604088013561252581611ffd565b94506060880135935061253b8960808a016121bb565b92506101808801356001600160401b0381111561255757600080fd5b61229d8a828b0161241f565b60006020828403121561257557600080fd5b81356001600160401b0381111561258b57600080fd5b82016060818503121561210c57600080fd5b6001600160e01b031991909116815260200190565b6000602082840312156125c457600080fd5b815161210c8161233d565b6000602082840312156125e157600080fd5b813561210c8161233d565b803582526020810135602083015260408101356040830152606081013560608301526080810135608083015260a081013560a083015260c081013560c083015260e081013561263a8161233d565b80151560e0840152505050565b6001600160a01b0383168152610120810161210c60208301846125ec565b6001600160501b0381168114611e5157600080fd5b6001600160401b0381168114611e5157600080fd5b64ffffffffff81168114611e5157600080fd5b600081356126af8161268f565b92915050565b61ffff81168114611e5157600080fd5b600081356126af816126b5565b600081356126af8161233d565b81356126ea81612665565b815469ffffffffffffffffffff19166001600160501b0382161782555060208201356127158161267a565b815467ffffffffffffffff60501b19811660509290921b67ffffffffffffffff60501b169182178355604084013561274c8161268f565b64ffffffffff60901b60909190911b166cffffffffffffffffffffffffff60501b1982168317811784556060850135612784816126b5565b6effffffffffffffffffffffffffffff60501b19929092169092179190911760b89190911b61ffff60b81b1617815561187a6127c2608084016126d2565b82805460ff60c81b191691151560c81b60ff60c81b16919091179055565b80356123568161268f565b8035612356816126b5565b60a08101823561280581612665565b6001600160501b03168252602083013561281e8161267a565b6001600160401b03166020830152604083013561283a8161268f565b64ffffffffff1660408301526060830135612854816126b5565b61ffff166060830152608083013561286b8161233d565b80151560808401525092915050565b634e487b7160e01b600052603260045260246000fd5b60008235603e198336030181126128a657600080fd5b9190910192915050565b6000808335601e198436030181126128c757600080fd5b8301803591506001600160401b038211156128e157600080fd5b6020019150600581901b3603821315611c9457600080fd5b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615612929576129296128f9565b500290565b60008219821115612941576129416128f9565b500190565b60006020828403121561295857600080fd5b815161210c81611ffd565b6040815260006129766040830186612164565b8281036020848101919091528482528591810160005b868110156129ba57833561299f81611ffd565b6001600160a01b03168252928201929082019060010161298c565b50979650505050505050565b600181811c908216806129da57607f821691505b6020821081036121ce57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b601f821115611a4157600081815260208120601f850160051c81016020861015612a375750805b601f850160051c820191505b81811015610e0857828155600101612a43565b6001600160401b03831115612a6d57612a6d6129fa565b612a8183612a7b83546129c6565b83612a10565b6000601f841160018114612ab55760008515612a9d5750838201355b600019600387901b1c1916600186901b17835561088c565b600083815260209020601f19861690835b82811015612ae65786850135825560209485019460019092019101612ac6565b5086821015612b035760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b602081526000612b52602083018486612b15565b949350505050565b65ffffffffffff81168114611e5157600080fd5b600081356126af81612b5a565b60ff81168114611e5157600080fd5b600081356126af81612b7b565b8135612ba281612665565b815469ffffffffffffffffffff19166001600160501b038216178255506020820135612bcd816126b5565b815461ffff60501b19811660509290921b61ffff60501b1691821783556040840135612bf881612b5a565b67ffffffffffffffff60501b1991909116909117606091821b65ffffffffffff60601b16178255612c5690612c2e908401612b6e565b82805465ffffffffffff60901b191660909290921b65ffffffffffff60901b16919091179055565b612c83612c6560808401612b8a565b82805460ff60c01b191660c09290921b60ff60c01b16919091179055565b612cb8612c9260a084016126a2565b82805464ffffffffff60c81b191660c89290921b64ffffffffff60c81b16919091179055565b612ceb612cc760c084016126c5565b8280546001600160f01b031660f09290921b6001600160f01b031916919091179055565b61187a612cfa60e084016126d2565b6001830160ff1981541660ff8315151681178255505050565b600060208284031215612d2557600080fd5b813561210c816126b5565b803561235681612b5a565b803561235681612b7b565b61010081018235612d5681612665565b6001600160501b031682526020830135612d6f816126b5565b61ffff1660208301526040830135612d8681612b5a565b65ffffffffffff166040830152612d9f60608401612d30565b65ffffffffffff166060830152612db860808401612d3b565b60ff166080830152612dcc60a084016127e0565b64ffffffffff1660a0830152612de460c084016127eb565b61ffff1660c0830152612df960e0840161234b565b80151560e08401526120e8565b8381526001600160a01b03831660208201526101408101612b5260408301846125ec565b6000808335601e19843603018112612e4157600080fd5b8301803591506001600160401b03821115612e5b57600080fd5b602001915036819003821315611c9457600080fd5b6040808252810184905260006060600586901b8301810190830187835b88811015612f0057858403605f190183528135368b9003601e19018112612eb357600080fd5b8a0160208181019135906001600160401b03821115612ed157600080fd5b813603831315612ee057600080fd5b612eeb878385612b15565b96509485019493909301925050600101612e8d565b5050508281036020840152612f16818587612b15565b979650505050505050565b600080600060608486031215612f3657600080fd5b8351925060208401519150604084015190509250925092565b600082612f6c57634e487b7160e01b600052601260045260246000fd5b500490565b600082821015612f8357612f836128f9565b500390565b634e487b7160e01b600052602160045260246000fdfea26469706673582212206e73effaf3764248c116ee3a72258ca43e9caeab94b45b782b420433b05beeb864736f6c634300080f0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.