Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60a06040 | 15941837 | 658 days ago | IN | 0 ETH | 0.1337099 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
MintManager
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.10; import "../utils/Ownable.sol"; import "../erc721/interfaces/IERC721GeneralMint.sol"; import "../erc721/interfaces/IERC721EditionMint.sol"; import "./interfaces/INativeMetaTransaction.sol"; import "../utils/EIP712Upgradeable.sol"; import "../metatx/ERC2771ContextUpgradeable.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; /** * @title MintManager * @author [email protected], [email protected] * @dev Faciliates lion's share of minting in Highlight protocol V2 by managing mint "vectors" on-chain and off-chain */ contract MintManager is EIP712Upgradeable, UUPSUpgradeable, OwnableUpgradeable, ERC2771ContextUpgradeable { using ECDSA for bytes32; using EnumerableSet for EnumerableSet.Bytes32Set; using EnumerableSet for EnumerableSet.AddressSet; /** * @dev On-chain mint vector * @param contractAddress NFT smart contract address * @param currency Currency used for payment. Native gas token, if zero address * @param paymentRecipient Payment recipient * @param startTimestamp When minting opens on vector * @param endTimestamp When minting ends on vector * @param pricePerToken Price that has to be paid per minted token * @param tokenLimitPerTx Max number of tokens that can be minted in one transaction * @param maxTotalClaimableViaVector Max number of tokens that can be minted via vector * @param maxUserClaimableViaVector Max number of tokens that can be minted by user via vector * @param totalClaimedViaVector Total number of tokens minted via vector * @param allowlistRoot Root of merkle tree with allowlist * @param paused If vector is paused */ struct Vector { address contractAddress; address currency; address payable paymentRecipient; uint256 startTimestamp; uint256 endTimestamp; uint256 pricePerToken; uint64 tokenLimitPerTx; uint64 maxTotalClaimableViaVector; uint64 maxUserClaimableViaVector; uint64 totalClaimedViaVector; bytes32 allowlistRoot; uint8 paused; } /** * @dev On-chain mint vector mutability rules * @param updatesFrozen If true, vector cannot be updated * @param deleteFrozen If true, vector cannot be deleted * @param pausesFrozen If true, vector cannot be paused */ struct VectorMutability { uint8 updatesFrozen; uint8 deleteFrozen; uint8 pausesFrozen; } /** * @dev Packet enabling impersonation of purchaser for currencies supporting meta-transactions * @param functionSignature Function to call on contract, with arguments encoded * @param sigR Elliptic curve signature component * @param sigS Elliptic curve signature component * @param sigV Elliptic curve signature component */ struct PurchaserMetaTxPacket { bytes functionSignature; bytes32 sigR; bytes32 sigS; uint8 sigV; } /** * @dev Claim that is signed off-chain with EIP-712, and unwrapped to facilitate fulfillment of mint * @param currency Currency used for payment. Native gas token, if zero address * @param contractAddress NFT smart contract address * @param claimer Account able to use this claim * @param paymentRecipient Payment recipient * @param pricePerToken Price that has to be paid per minted token * @param numTokensToMint Number of NFTs to mint in this transaction * @param maxClaimableViaVector Max number of tokens that can be minted via vector * @param maxClaimablePerUser Max number of tokens that can be minted by user via vector * @param editionId ID of edition to mint on. Unused if claim is passed into ERC721General minting function * @param claimExpiryTimestamp Time when claim expires * @param claimNonce Unique identifier of claim * @param offchainVectorId Unique identifier of vector offchain */ struct Claim { address currency; address contractAddress; address claimer; address payable paymentRecipient; uint256 pricePerToken; uint64 numTokensToMint; uint256 maxClaimableViaVector; uint256 maxClaimablePerUser; uint256 editionId; uint256 claimExpiryTimestamp; bytes32 claimNonce; bytes32 offchainVectorId; } /** * @dev Claim that is signed off-chain with EIP-712, and unwrapped to facilitate fulfillment of mint. * Includes meta-tx packets to impersonate purchaser and make payments. * @param currency Currency used for payment. Native gas token, if zero address * @param contractAddress NFT smart contract address * @param claimer Account able to use this claim * @param paymentRecipient Payment recipient * @param pricePerToken Price that has to be paid per minted token * @param numTokensToMint Number of NFTs to mint in this transaction * @param purchaseToCreatorPacket Meta-tx packet that send portion of payment to creator * @param purchaseToPlatformPacket Meta-tx packet that send portion of payment to platform * @param maxClaimableViaVector Max number of tokens that can be minted via vector * @param maxClaimablePerUser Max number of tokens that can be minted by user via vector * @param editionId ID of edition to mint on. Unused if claim is passed into ERC721General minting function * @param claimExpiryTimestamp Time when claim expires * @param claimNonce Unique identifier of claim * @param offchainVectorId Unique identifier of vector offchain */ struct ClaimWithMetaTxPacket { address currency; address contractAddress; address claimer; uint256 pricePerToken; uint64 numTokensToMint; PurchaserMetaTxPacket purchaseToCreatorPacket; PurchaserMetaTxPacket purchaseToPlatformPacket; uint256 maxClaimableViaVector; uint256 maxClaimablePerUser; uint256 editionId; // unused if for general contract mints uint256 claimExpiryTimestamp; bytes32 claimNonce; bytes32 offchainVectorId; } /** * @dev Tracks current claim state of offchain vectors * @param numClaimed Total claimed on vector * @param numClaimedPerUser Tracks totals claimed per user on vector */ struct OffchainVectorClaimState { uint256 numClaimed; mapping(address => uint256) numClaimedPerUser; } /* solhint-disable max-line-length */ /** * @dev DEPRECATED - Claim typehash used via typed structured data hashing (EIP-712) */ bytes32 private constant _CLAIM_TYPEHASH = keccak256( "Claim(address currency,address contractAddress,address claimer,address paymentRecipient,uint256 pricePerToken,uint64 numTokensToMint,uint256 maxClaimableViaVector,uint256 maxClaimablePerUser,uint256 editionId,uint256 claimExpiryTimestamp,bytes32 claimNonce,bytes32 offchainVectorId)" ); /** * @dev DEPRECATED - Claim typehash used via typed structured data hashing (EIP-712) */ bytes32 private constant _CLAIM_WITH_META_TX_PACKET_TYPEHASH = keccak256( "ClaimWithMetaTxPacket(address currency,address contractAddress,address claimer,uint256 pricePerToken,uint64 numTokensToMint,PurchaserMetaTxPacket purchaseToCreatorPacket,PurchaserMetaTxPacket purchaseToCreatorPacket,uint256 maxClaimableViaVector,uint256 maxClaimablePerUser,uint256 editionId,uint256 claimExpiryTimestamp,bytes32 claimNonce,bytes32 offchainVectorId)" ); /* solhint-enable max-line-length */ /** * @dev Platform receiving portion of payment */ address payable private _platform; /** * @dev System-wide mint vectors */ mapping(uint256 => Vector) public vectors; /** * @dev System-wide mint vectors' mutabilities */ mapping(uint256 => VectorMutability) public vectorMutabilities; /** * @dev System-wide vector ids to (user to user claims count) */ mapping(uint256 => mapping(address => uint64)) public userClaims; /** * @dev Tracks what nonces used in signed mint keys have been used for vectors enforced offchain * Requires the platform to not re-use offchain vector IDs. */ mapping(bytes32 => EnumerableSet.Bytes32Set) private _offchainVectorsToNoncesUsed; /** * @dev Tracks running state of offchain vectors */ mapping(bytes32 => OffchainVectorClaimState) public offchainVectorsClaimState; /** * @dev Maps vector ids to edition ids */ mapping(uint256 => uint256) public vectorToEditionId; /** * @dev Current vector id index */ uint256 private _vectorSupply; /** * @dev Platform transaction executors */ EnumerableSet.AddressSet internal _platformExecutors; /** * @dev Emitted when platform executor is added or removed * @param executor Changed executor * @param added True if executor was added and false otherwise */ event PlatformExecutorChanged(address indexed executor, bool indexed added); /** * @dev Emitted when vector is created on-chain * @param vectorId ID of vector * @param editionId Edition id of vector, meaningful if vector is for Editions collection * @param vector Vector to create */ event VectorCreated(uint256 indexed vectorId, uint256 indexed editionId, Vector vector); /** * @dev Emitted when vector is updated on-chain * @param vectorId ID of vector * @param newVector New vector details */ event VectorUpdated(uint256 indexed vectorId, Vector newVector); /** * @dev Emitted when vector is deleted on-chain * @param vectorId ID of vector to delete */ event VectorDeleted(uint256 indexed vectorId); /** * @dev Emitted when vector is paused or unpaused on-chain * @param vectorId ID of vector * @param paused True if vector was paused, false otherwise */ event VectorPausedOrUnpaused(uint256 indexed vectorId, uint8 indexed paused); /** * @dev Emitted when vector mutability updated * @param vectorId ID of vector * @param _newVectorMutability New vector mutability */ event VectorMutabilityUpdated(uint256 indexed vectorId, VectorMutability _newVectorMutability); /** * @dev Emits when native gas token held by contract is withdrawn by platform * @param withdrawnValue Amount withdrawn */ event NativeGasTokenWithdrawn(uint256 withdrawnValue); /** * @dev Emitted when payment is made in native gas token * @param paymentRecipient Creator recipient of payment * @param vectorId Vector that payment was for * @param amountToCreator Amount sent to creator * @param percentageBPSOfTotal Percentage (in basis points) that was sent to creator, of total payment */ event NativeGasTokenPayment( address indexed paymentRecipient, bytes32 indexed vectorId, uint256 amountToCreator, uint32 percentageBPSOfTotal ); /** * @dev Emitted when payment is made in ERC20 * @param currency ERC20 currency * @param paymentRecipient Creator recipient of payment * @param vectorId Vector that payment was for * @param payer Payer * @param amountToCreator Amount sent to creator * @param percentageBPSOfTotal Percentage (in basis points) that was sent to creator, of total payment */ event ERC20Payment( address indexed currency, address indexed paymentRecipient, bytes32 indexed vectorId, address payer, uint256 amountToCreator, uint32 percentageBPSOfTotal ); /** * @dev Emitted when payment is made in ERC20 via meta-tx packet method * @param currency ERC20 currency * @param msgSender Payer * @param vectorId Vector that payment was for * @param purchaseToCreatorPacket Meta-tx packet facilitating payment to creator * @param purchaseToPlatformPacket Meta-tx packet facilitating payment to platform * @param amount Payment amount */ event ERC20PaymentMetaTxPackets( address indexed currency, address indexed msgSender, bytes32 indexed vectorId, PurchaserMetaTxPacket purchaseToCreatorPacket, PurchaserMetaTxPacket purchaseToPlatformPacket, uint256 amount ); /** * @dev Restricts calls to platform */ modifier onlyPlatform() { require(_msgSender() == _platform, "Not platform"); _; } /** * @dev Initializes MintManager * @param platform Platform address * @param _owner MintManager owner * @param trustedForwarder Trusted meta-tx executor * @param initialExecutor Initial platform executor */ function initialize( address payable platform, address _owner, address trustedForwarder, address initialExecutor ) external initializer { _platform = platform; __EIP721Upgradeable_initialize("MintManager", "1.0.0"); __ERC2771ContextUpgradeable__init__(trustedForwarder); __Ownable_init(); _transferOwnership(_owner); _platformExecutors.add(initialExecutor); } /** * @dev Add platform executor. Expected to be protected by a smart contract wallet. * @param _executor Platform executor to add */ function addPlatformExecutor(address _executor) external onlyOwner { require(_executor != address(0), "Cannot set to null address"); require(_platformExecutors.add(_executor), "Already added"); emit PlatformExecutorChanged(_executor, true); } /** * @dev Deprecate platform executor. Expected to be protected by a smart contract wallet. * @param _executor Platform executor to deprecate */ function deprecatePlatformExecutor(address _executor) external onlyOwner { require(_platformExecutors.remove(_executor), "Not deprecated"); emit PlatformExecutorChanged(_executor, false); } /** * @dev Creates on-chain vector * @param _vector Vector to create * @param _vectorMutability Vector mutability * @param editionId Edition id of vector, meaningful if vector is for Editions collection */ function createVector( Vector calldata _vector, VectorMutability calldata _vectorMutability, uint256 editionId ) external { require(Ownable(_vector.contractAddress).owner() == _msgSender(), "Not contract owner"); require(_vector.totalClaimedViaVector == 0, "totalClaimedViaVector not 0"); _vectorSupply++; vectors[_vectorSupply] = _vector; vectorMutabilities[_vectorSupply] = _vectorMutability; vectorToEditionId[_vectorSupply] = editionId; emit VectorCreated(_vectorSupply, editionId, _vector); } /** * @dev Updates on-chain vector * @param vectorId ID of vector to update * @param _newVector New vector details */ function updateVector(uint256 vectorId, Vector calldata _newVector) external { Vector memory _oldVector = vectors[vectorId]; require(vectorMutabilities[vectorId].updatesFrozen == 0, "Updates frozen"); require(_oldVector.totalClaimedViaVector == _newVector.totalClaimedViaVector, "Total claimed different"); require(Ownable(_oldVector.contractAddress).owner() == _msgSender(), "Not contract owner"); vectors[vectorId] = _newVector; emit VectorUpdated(vectorId, _newVector); } /** * @dev Deletes on-chain vector * @param vectorId ID of vector to delete */ function deleteVector(uint256 vectorId) external { Vector memory _oldVector = vectors[vectorId]; require(vectorMutabilities[vectorId].deleteFrozen == 0, "Delete frozen"); require(Ownable(_oldVector.contractAddress).owner() == _msgSender(), "Not contract owner"); delete vectors[vectorId]; delete vectorMutabilities[vectorId]; delete vectorToEditionId[_vectorSupply]; emit VectorDeleted(vectorId); } /** * @dev Pauses on-chain vector * @param vectorId ID of vector to pause */ function pauseVector(uint256 vectorId) external { Vector memory _oldVector = vectors[vectorId]; require(vectorMutabilities[vectorId].pausesFrozen == 0, "Pauses frozen"); require(Ownable(_oldVector.contractAddress).owner() == _msgSender(), "Not contract owner"); vectors[vectorId].paused = 1; emit VectorPausedOrUnpaused(vectorId, 1); } /** * @dev Unpauses on-chain vector * @param vectorId ID of vector to unpause */ function unpauseVector(uint256 vectorId) external { Vector memory _oldVector = vectors[vectorId]; require(Ownable(_oldVector.contractAddress).owner() == _msgSender(), "Not contract owner"); vectors[vectorId].paused = 0; emit VectorPausedOrUnpaused(vectorId, 0); } /** * @dev Updates on-chain vector mutability. Protected by vector mutability field updatesFrozen itself * @param vectorId ID of vector mutability to update * @param _newVectorMutability New vector mutability details */ function updateVectorMutability(uint256 vectorId, VectorMutability calldata _newVectorMutability) external { require(vectorMutabilities[vectorId].updatesFrozen == 0, "Updates frozen"); require(Ownable(vectors[vectorId].contractAddress).owner() == _msgSender(), "Not contract owner"); vectorMutabilities[vectorId] = _newVectorMutability; emit VectorMutabilityUpdated(vectorId, _newVectorMutability); } /** * @dev Mint on vector pointing to ERC721General collection * @param vectorId ID of vector * @param numTokensToMint Number of tokens to mint * @param mintRecipient Who to mint the NFT(s) to */ function vectorMintGeneral721( uint256 vectorId, uint64 numTokensToMint, address mintRecipient ) external payable { address msgSender = _msgSender(); require(msgSender == tx.origin, "Smart contracts not allowed"); Vector memory _vector = vectors[vectorId]; uint64 newNumClaimedViaVector = _vector.totalClaimedViaVector + numTokensToMint; uint64 newNumClaimedForUser = userClaims[vectorId][msgSender] + numTokensToMint; require(_vector.allowlistRoot == 0, "Use allowlist mint"); _vectorMintGeneral721( vectorId, _vector, numTokensToMint, mintRecipient, newNumClaimedViaVector, newNumClaimedForUser ); vectors[vectorId].totalClaimedViaVector = newNumClaimedViaVector; userClaims[vectorId][msgSender] = newNumClaimedForUser; } /** * @dev Mint on vector pointing to ERC721General collection, with allowlist * @param vectorId ID of vector * @param numTokensToMint Number of tokens to mint * @param mintRecipient Who to mint the NFT(s) to * @param proof Proof of minter's inclusion in allowlist */ function vectorMintGeneral721WithAllowlist( uint256 vectorId, uint64 numTokensToMint, address mintRecipient, bytes32[] calldata proof ) external payable { address msgSender = _msgSender(); require(msgSender == tx.origin, "Smart contracts not allowed"); Vector memory _vector = vectors[vectorId]; uint64 newNumClaimedViaVector = _vector.totalClaimedViaVector + numTokensToMint; uint64 newNumClaimedForUser = userClaims[vectorId][msgSender] + numTokensToMint; // merkle tree allowlist validation bytes32 leaf = keccak256(abi.encodePacked(msgSender)); require(MerkleProof.verify(proof, _vector.allowlistRoot, leaf), "Invalid proof"); _vectorMintGeneral721( vectorId, _vector, numTokensToMint, mintRecipient, newNumClaimedViaVector, newNumClaimedForUser ); vectors[vectorId].totalClaimedViaVector = newNumClaimedViaVector; userClaims[vectorId][msgSender] = newNumClaimedForUser; } /** * @dev Mint on am ERC721General collection with a valid claim * @param claim Claim * @param claimSignature Signed + encoded claim * @param mintRecipient Who to mint the NFT(s) to */ function gatedMintGeneral721( Claim calldata claim, bytes calldata claimSignature, address mintRecipient ) external payable { _processGatedMintClaim(claim, claimSignature); // mint NFT(s) if (claim.numTokensToMint == 1) { IERC721GeneralMint(claim.contractAddress).mintOneToOneRecipient(mintRecipient); } else { IERC721GeneralMint(claim.contractAddress).mintAmountToOneRecipient(mintRecipient, claim.numTokensToMint); } } /** * @dev Mint on am ERC721General collection with a valid claim, using meta-tx packets * @param claim Claim * @param claimSignature Signed + encoded claim * @param mintRecipient Who to mint the NFT(s) to */ function gatedMintPaymentPacketGeneral721( ClaimWithMetaTxPacket calldata claim, bytes calldata claimSignature, address mintRecipient ) external { address msgSender = _msgSender(); _verifyAndUpdateClaimWithMetaTxPacket(claim, claimSignature, msgSender); require(claim.currency != address(0), "Not ERC20 payment"); // make payments if (claim.pricePerToken > 0) { _processERC20PaymentWithMetaTxPackets( claim.currency, claim.purchaseToCreatorPacket, claim.purchaseToPlatformPacket, msgSender, claim.offchainVectorId, claim.pricePerToken * claim.numTokensToMint ); } // mint NFT(s) if (claim.numTokensToMint == 1) { IERC721GeneralMint(claim.contractAddress).mintOneToOneRecipient(mintRecipient); } else { IERC721GeneralMint(claim.contractAddress).mintAmountToOneRecipient(mintRecipient, claim.numTokensToMint); } } /** * @dev Mint on vector pointing to ERC721Editions or ERC721SingleEdiion collection * @param vectorId ID of vector * @param numTokensToMint Number of tokens to mint * @param mintRecipient Who to mint the NFT(s) to */ function vectorMintEdition721( uint256 vectorId, uint64 numTokensToMint, address mintRecipient ) external payable { address msgSender = _msgSender(); require(msgSender == tx.origin, "Smart contracts not allowed"); Vector memory _vector = vectors[vectorId]; uint64 newNumClaimedViaVector = _vector.totalClaimedViaVector + numTokensToMint; uint64 newNumClaimedForUser = userClaims[vectorId][msgSender] + numTokensToMint; require(_vector.allowlistRoot == 0, "Use allowlist mint"); _vectorMintEdition721( vectorId, _vector, vectorToEditionId[vectorId], numTokensToMint, mintRecipient, newNumClaimedViaVector, newNumClaimedForUser ); vectors[vectorId].totalClaimedViaVector = newNumClaimedViaVector; userClaims[vectorId][msgSender] = newNumClaimedForUser; } /** * @dev Mint on vector pointing to ERC721Editions or ERC721SingleEdiion collection, with allowlist * @param vectorId ID of vector * @param numTokensToMint Number of tokens to mint * @param mintRecipient Who to mint the NFT(s) to * @param proof Proof of minter's inclusion in allowlist */ function vectorMintEdition721WithAllowlist( uint256 vectorId, uint64 numTokensToMint, address mintRecipient, bytes32[] calldata proof ) external payable { address msgSender = _msgSender(); require(msgSender == tx.origin, "Smart contracts not allowed"); Vector memory _vector = vectors[vectorId]; uint64 newNumClaimedViaVector = _vector.totalClaimedViaVector + numTokensToMint; uint64 newNumClaimedForUser = userClaims[vectorId][msgSender] + numTokensToMint; // merkle tree allowlist validation bytes32 leaf = keccak256(abi.encodePacked(msgSender)); require(MerkleProof.verify(proof, _vector.allowlistRoot, leaf), "Invalid proof"); _vectorMintEdition721( vectorId, _vector, vectorToEditionId[vectorId], numTokensToMint, mintRecipient, newNumClaimedViaVector, newNumClaimedForUser ); vectors[vectorId].totalClaimedViaVector = newNumClaimedViaVector; userClaims[vectorId][msgSender] = newNumClaimedForUser; } /** * @dev Mint on an ERC721Editions or ERC721SingleEdiion collection with a valid claim * @param _claim Claim * @param _signature Signed + encoded claim * @param _recipient Who to mint the NFT(s) to */ function gatedMintEdition721( Claim calldata _claim, bytes calldata _signature, address _recipient ) external payable { _processGatedMintClaim(_claim, _signature); // mint NFT(s) if (_claim.numTokensToMint == 1) { IERC721EditionMint(_claim.contractAddress).mintOneToRecipient(_claim.editionId, _recipient); } else { IERC721EditionMint(_claim.contractAddress).mintAmountToRecipient( _claim.editionId, _recipient, _claim.numTokensToMint ); } } /** * @dev Mint on an ERC721Editions or ERC721SingleEdiion collection with a valid claim, using meta-tx packets * @param claim Claim * @param claimSignature Signed + encoded claim * @param mintRecipient Who to mint the NFT(s) to */ function gatedMintPaymentPacketEdition721( ClaimWithMetaTxPacket calldata claim, bytes calldata claimSignature, address mintRecipient ) external { address msgSender = _msgSender(); _verifyAndUpdateClaimWithMetaTxPacket(claim, claimSignature, msgSender); require(claim.currency != address(0), "Has to be ERC20 payment"); // make payments if (claim.pricePerToken > 0) { _processERC20PaymentWithMetaTxPackets( claim.currency, claim.purchaseToCreatorPacket, claim.purchaseToPlatformPacket, msgSender, claim.offchainVectorId, claim.pricePerToken * claim.numTokensToMint ); } // mint NFT(s) if (claim.numTokensToMint == 1) { IERC721EditionMint(claim.contractAddress).mintOneToRecipient(claim.editionId, mintRecipient); } else { IERC721EditionMint(claim.contractAddress).mintAmountToRecipient( claim.editionId, mintRecipient, claim.numTokensToMint ); } } /** * @dev Withdraw native gas token owed to platform */ function withdrawNativeGasToken() external onlyPlatform { uint256 withdrawnValue = address(this).balance; (bool sentToPlatform, bytes memory dataPlatform) = _platform.call{ value: withdrawnValue }(""); require(sentToPlatform, "Failed to send Ether to platform"); emit NativeGasTokenWithdrawn(withdrawnValue); } /** * @dev Returns platform executors */ function platformExecutors() external view returns (address[] memory) { return _platformExecutors.values(); } /** * @dev Returns claim ids used for an offchain vector * @param vectorId ID of offchain vector */ function getClaimNoncesUsedForOffchainVector(bytes32 vectorId) external view returns (bytes32[] memory) { return _offchainVectorsToNoncesUsed[vectorId].values(); } /** * @dev Returns number of NFTs minted by user on vector * @param vectorId ID of offchain vector * @param user Minting user */ function getNumClaimedPerUserOffchainVector(bytes32 vectorId, address user) external view returns (uint256) { return offchainVectorsClaimState[vectorId].numClaimedPerUser[user]; } /** * @dev Verify that claim and claim signature are valid for a mint * @param claim Claim * @param signature Signed + encoded claim * @param expectedMsgSender Expected claimer to verify claim for */ function verifyClaim( Claim calldata claim, bytes calldata signature, address expectedMsgSender ) external view returns (bool) { address signer = _claimSigner(claim, signature); require(expectedMsgSender == claim.claimer, "Sender not claimer"); return _isPlatformExecutor(signer) && !_offchainVectorsToNoncesUsed[claim.offchainVectorId].contains(claim.claimNonce) && block.timestamp <= claim.claimExpiryTimestamp && (claim.maxClaimableViaVector == 0 || claim.numTokensToMint + offchainVectorsClaimState[claim.offchainVectorId].numClaimed <= claim.maxClaimableViaVector) && (claim.maxClaimablePerUser == 0 || claim.numTokensToMint + offchainVectorsClaimState[claim.offchainVectorId].numClaimedPerUser[expectedMsgSender] <= claim.maxClaimablePerUser); } /** * @dev Verify that claim and claim signature are valid for a mint (claim version with meta-tx packets) * @param claim Claim * @param signature Signed + encoded claim * @param expectedMsgSender Expected claimer to verify claim for */ function verifyClaimWithMetaTxPacket( ClaimWithMetaTxPacket calldata claim, bytes calldata signature, address expectedMsgSender ) external view returns (bool) { address signer = _claimWithMetaTxPacketSigner(claim, signature); require(expectedMsgSender == claim.claimer, "Sender not claimer"); return _isPlatformExecutor(signer) && !_offchainVectorsToNoncesUsed[claim.offchainVectorId].contains(claim.claimNonce) && block.timestamp <= claim.claimExpiryTimestamp && (claim.maxClaimableViaVector == 0 || claim.numTokensToMint + offchainVectorsClaimState[claim.offchainVectorId].numClaimed <= claim.maxClaimableViaVector) && (claim.maxClaimablePerUser == 0 || claim.numTokensToMint + offchainVectorsClaimState[claim.offchainVectorId].numClaimedPerUser[expectedMsgSender] <= claim.maxClaimablePerUser); } /** * @dev Returns if nonce is used for the vector * @param vectorId ID of offchain vector * @param nonce Nonce being checked */ function isNonceUsed(bytes32 vectorId, bytes32 nonce) external view returns (bool) { return _offchainVectorsToNoncesUsed[vectorId].contains(nonce); } /* solhint-disable no-empty-blocks */ /** * @dev Limit upgrades of contract to MintManager owner * @param // New implementation address */ function _authorizeUpgrade(address) internal override onlyOwner {} /* solhint-enable no-empty-blocks */ /** * @dev Used for meta-transactions */ function _msgSender() internal view override(ContextUpgradeable, ERC2771ContextUpgradeable) returns (address sender) { return ERC2771ContextUpgradeable._msgSender(); } /** * @dev Used for meta-transactions */ function _msgData() internal view override(ContextUpgradeable, ERC2771ContextUpgradeable) returns (bytes calldata) { return ERC2771ContextUpgradeable._msgData(); } /** * @dev Process, verify, and update the state of a gated mint claim * @param claim Claim * @param claimSignature Signed + encoded claim */ function _processGatedMintClaim(Claim calldata claim, bytes calldata claimSignature) private { address msgSender = _msgSender(); _verifyAndUpdateClaim(claim, claimSignature, msgSender); // make payments if (claim.currency == address(0) && claim.pricePerToken > 0) { // pay in native gas token uint256 amount = claim.numTokensToMint * claim.pricePerToken; _processNativeGasTokenPayment(amount, claim.paymentRecipient, claim.offchainVectorId); } else if (claim.pricePerToken > 0) { // pay in ERC20 uint256 amount = claim.numTokensToMint * claim.pricePerToken; _processERC20Payment(amount, claim.paymentRecipient, msgSender, claim.currency, claim.offchainVectorId); } } /** * @dev Verify, and update the state of a gated mint claim * @param claim Claim * @param signature Signed + encoded claim * @param msgSender Expected claimer */ function _verifyAndUpdateClaim( Claim calldata claim, bytes calldata signature, address msgSender ) private { address signer = _claimSigner(claim, signature); require(msgSender == claim.claimer, "Sender not claimer"); // cannot cache here due to nested mapping uint256 expectedNumClaimedViaVector = offchainVectorsClaimState[claim.offchainVectorId].numClaimed + claim.numTokensToMint; uint256 expectedNumClaimedByUser = offchainVectorsClaimState[claim.offchainVectorId].numClaimedPerUser[ msgSender ] + claim.numTokensToMint; require( _isPlatformExecutor(signer) && !_offchainVectorsToNoncesUsed[claim.offchainVectorId].contains(claim.claimNonce) && block.timestamp <= claim.claimExpiryTimestamp && (expectedNumClaimedViaVector <= claim.maxClaimableViaVector || claim.maxClaimableViaVector == 0) && (expectedNumClaimedByUser <= claim.maxClaimablePerUser || claim.maxClaimablePerUser == 0), "Invalid claim" ); _offchainVectorsToNoncesUsed[claim.offchainVectorId].add(claim.claimNonce); // mark claim nonce as used // update claim state offchainVectorsClaimState[claim.offchainVectorId].numClaimed = expectedNumClaimedViaVector; offchainVectorsClaimState[claim.offchainVectorId].numClaimedPerUser[msgSender] = expectedNumClaimedByUser; } /** * @dev Verify, and update the state of a gated mint claim (version w/ meta-tx packets) * @param claim Claim * @param signature Signed + encoded claim * @param msgSender Expected claimer */ function _verifyAndUpdateClaimWithMetaTxPacket( ClaimWithMetaTxPacket calldata claim, bytes calldata signature, address msgSender ) private { address signer = _claimWithMetaTxPacketSigner(claim, signature); require(msgSender == claim.claimer, "Sender not claimer"); // cannot cache here due to nested mapping uint256 expectedNumClaimedViaVector = offchainVectorsClaimState[claim.offchainVectorId].numClaimed + claim.numTokensToMint; uint256 expectedNumClaimedByUser = offchainVectorsClaimState[claim.offchainVectorId].numClaimedPerUser[ msgSender ] + claim.numTokensToMint; require( _isPlatformExecutor(signer) && !_offchainVectorsToNoncesUsed[claim.offchainVectorId].contains(claim.claimNonce) && block.timestamp <= claim.claimExpiryTimestamp && (expectedNumClaimedViaVector <= claim.maxClaimableViaVector || claim.maxClaimableViaVector == 0) && (expectedNumClaimedByUser <= claim.maxClaimablePerUser || claim.maxClaimablePerUser == 0), "Invalid claim" ); _offchainVectorsToNoncesUsed[claim.offchainVectorId].add(claim.claimNonce); // mark claim nonce as used // update claim state offchainVectorsClaimState[claim.offchainVectorId].numClaimed = expectedNumClaimedViaVector; offchainVectorsClaimState[claim.offchainVectorId].numClaimedPerUser[msgSender] = expectedNumClaimedByUser; } /** * @dev Process a mint on an on-chain vector * @param _vectorId ID of vector being minted on * @param _vector Vector being minted on * @param numTokensToMint Number of NFTs to mint on vector * @param newNumClaimedViaVector New number of NFTs minted via vector after this ones * @param newNumClaimedForUser New number of NFTs minted by user via vector after this ones */ function _processVectorMint( uint256 _vectorId, Vector memory _vector, uint64 numTokensToMint, uint256 newNumClaimedViaVector, uint256 newNumClaimedForUser ) private { require( _vector.maxTotalClaimableViaVector >= newNumClaimedViaVector || _vector.maxTotalClaimableViaVector == 0, "> maxClaimableViaVector" ); require( _vector.maxUserClaimableViaVector >= newNumClaimedForUser || _vector.maxUserClaimableViaVector == 0, "> maxClaimablePerUser" ); require(_vector.paused == 0, "Vector paused"); require( (_vector.startTimestamp <= block.timestamp || _vector.startTimestamp == 0) && (block.timestamp <= _vector.endTimestamp || _vector.endTimestamp == 0), "Invalid mint time" ); require(numTokensToMint > 0, "Have to mint something"); require(numTokensToMint <= _vector.tokenLimitPerTx, "Too many per tx"); if (_vector.currency == address(0) && _vector.pricePerToken > 0) { // pay in native gas token uint256 amount = numTokensToMint * _vector.pricePerToken; _processNativeGasTokenPayment(amount, _vector.paymentRecipient, bytes32(_vectorId)); } else if (_vector.pricePerToken > 0) { // pay in ERC20 uint256 amount = numTokensToMint * _vector.pricePerToken; _processERC20Payment(amount, _vector.paymentRecipient, _msgSender(), _vector.currency, bytes32(_vectorId)); } } /** * @dev Mint on vector pointing to ERC721General collection * @param _vectorId ID of vector * @param _vector Vector being minted on * @param numTokensToMint Number of tokens to mint * @param mintRecipient Who to mint the NFT(s) to * @param newNumClaimedViaVector New number of NFTs minted via vector after this ones * @param newNumClaimedForUser New number of NFTs minted by user via vector after this ones */ function _vectorMintGeneral721( uint256 _vectorId, Vector memory _vector, uint64 numTokensToMint, address mintRecipient, uint256 newNumClaimedViaVector, uint256 newNumClaimedForUser ) private { _processVectorMint(_vectorId, _vector, numTokensToMint, newNumClaimedViaVector, newNumClaimedForUser); if (numTokensToMint == 1) { IERC721GeneralMint(_vector.contractAddress).mintOneToOneRecipient(mintRecipient); } else { IERC721GeneralMint(_vector.contractAddress).mintAmountToOneRecipient(mintRecipient, numTokensToMint); } } /** * @dev Mint on vector pointing to ERC721Editions or ERC721SingleEdiion collection * @param _vectorId ID of vector * @param _vector Vector being minted on * @param editionId ID of edition being minted on * @param numTokensToMint Number of tokens to mint * @param mintRecipient Who to mint the NFT(s) to * @param newNumClaimedViaVector New number of NFTs minted via vector after this ones * @param newNumClaimedForUser New number of NFTs minted by user via vector after this ones */ function _vectorMintEdition721( uint256 _vectorId, Vector memory _vector, uint256 editionId, uint64 numTokensToMint, address mintRecipient, uint256 newNumClaimedViaVector, uint256 newNumClaimedForUser ) private { _processVectorMint(_vectorId, _vector, numTokensToMint, newNumClaimedViaVector, newNumClaimedForUser); if (numTokensToMint == 1) { IERC721EditionMint(_vector.contractAddress).mintOneToRecipient(editionId, mintRecipient); } else { IERC721EditionMint(_vector.contractAddress).mintAmountToRecipient( editionId, mintRecipient, numTokensToMint ); } } /** * @dev Process payment in native gas token, sending to creator and platform * @param totalAmount Total amount being paid * @param recipient Creator recipient of payment * @param vectorId ID of vector (on-chain or off-chain) */ function _processNativeGasTokenPayment( uint256 totalAmount, address payable recipient, bytes32 vectorId ) private { require(totalAmount == msg.value, "Invalid amount"); uint256 amountToCreator = (totalAmount * 95) / 100; (bool sentToRecipient, bytes memory dataRecipient) = recipient.call{ value: amountToCreator }(""); require(sentToRecipient, "Failed to send Ether to recipient"); emit NativeGasTokenPayment(recipient, vectorId, amountToCreator, 9500); } /** * @dev Process payment in ERC20, sending to creator and platform * @param totalAmount Total amount being paid * @param recipient Creator recipient of payment * @param payer Payer * @param currency ERC20 currency * @param vectorId ID of vector (on-chain or off-chain) */ function _processERC20Payment( uint256 totalAmount, address recipient, address payer, address currency, bytes32 vectorId ) private { uint256 amountToCreator = (totalAmount * 95) / 100; IERC20(currency).transferFrom(payer, recipient, amountToCreator); IERC20(currency).transferFrom(payer, _platform, totalAmount - amountToCreator); emit ERC20Payment(currency, recipient, vectorId, payer, amountToCreator, 9500); } /** * @dev Process payment in ERC20 with meta-tx packets, sending to creator and platform * @param currency ERC20 currency * @param purchaseToCreatorPacket Meta-tx packet facilitating payment to creator recipient * @param purchaseToPlatformPacket Meta-tx packet facilitating payment to platform * @param msgSender Claimer * @param vectorId ID of vector (on-chain or off-chain) * @param amount Total amount paid */ function _processERC20PaymentWithMetaTxPackets( address currency, PurchaserMetaTxPacket calldata purchaseToCreatorPacket, PurchaserMetaTxPacket calldata purchaseToPlatformPacket, address msgSender, bytes32 vectorId, uint256 amount ) private { uint256 previousBalance = IERC20(currency).balanceOf(msgSender); INativeMetaTransaction(currency).executeMetaTransaction( msgSender, purchaseToCreatorPacket.functionSignature, purchaseToCreatorPacket.sigR, purchaseToCreatorPacket.sigS, purchaseToCreatorPacket.sigV ); INativeMetaTransaction(currency).executeMetaTransaction( msgSender, purchaseToPlatformPacket.functionSignature, purchaseToPlatformPacket.sigR, purchaseToPlatformPacket.sigS, purchaseToPlatformPacket.sigV ); require(IERC20(currency).balanceOf(msgSender) <= previousBalance - amount, "Invalid amount transacted"); emit ERC20PaymentMetaTxPackets( currency, msgSender, vectorId, purchaseToCreatorPacket, purchaseToPlatformPacket, amount ); } /** * @dev Recover claim signature signer * @param claim Claim * @param signature Claim signature */ function _claimSigner(Claim calldata claim, bytes calldata signature) private view returns (address) { return _hashTypedDataV4( keccak256(bytes.concat(_claimABIEncoded1(claim), _claimABIEncoded2(claim.offchainVectorId))) ).recover(signature); } /** * @dev Recover claimWithMetaTxPacket signature signer * @param claim Claim * @param signature Claim signature */ function _claimWithMetaTxPacketSigner(ClaimWithMetaTxPacket calldata claim, bytes calldata signature) private view returns (address) { return _hashTypedDataV4( keccak256( bytes.concat( _claimWithMetaTxABIEncoded1(claim), _claimWithMetaTxABIEncoded2(claim.claimNonce, claim.offchainVectorId) ) ) ).recover(signature); } /** * @dev Returns true if account passed in is a platform executor * @param _executor Account being checked */ function _isPlatformExecutor(address _executor) private view returns (bool) { return _platformExecutors.contains(_executor); } /* solhint-disable max-line-length */ /** * @dev Get claim typehash */ function _getClaimTypeHash() private pure returns (bytes32) { return keccak256( "Claim(address currency,address contractAddress,address claimer,address paymentRecipient,uint256 pricePerToken,uint64 numTokensToMint,uint256 maxClaimableViaVector,uint256 maxClaimablePerUser,uint256 editionId,uint256 claimExpiryTimestamp,bytes32 claimNonce,bytes32 offchainVectorId)" ); } /** * @dev Get claimWithMetaTxPacket typehash */ function _getClaimWithMetaTxPacketTypeHash() private pure returns (bytes32) { return keccak256( "ClaimWithMetaTxPacket(address currency,address contractAddress,address claimer,uint256 pricePerToken,uint64 numTokensToMint,PurchaserMetaTxPacket purchaseToCreatorPacket,PurchaserMetaTxPacket purchaseToPlatformPacket,uint256 maxClaimableViaVector,uint256 maxClaimablePerUser,uint256 editionId,uint256 claimExpiryTimestamp,bytes32 claimNonce,bytes32 offchainVectorId)" ); } /* solhint-enable max-line-length */ /** * @dev Return abi-encoded claim part one * @param claim Claim */ function _claimABIEncoded1(Claim calldata claim) private pure returns (bytes memory) { return abi.encode( _getClaimTypeHash(), claim.currency, claim.contractAddress, claim.claimer, claim.paymentRecipient, claim.pricePerToken, claim.numTokensToMint, claim.maxClaimableViaVector, claim.maxClaimablePerUser, claim.editionId, claim.claimExpiryTimestamp, claim.claimNonce ); } /** * @dev Return abi-encoded claim part two * @param offchainVectorId Offchain vector ID of claim */ function _claimABIEncoded2(bytes32 offchainVectorId) private pure returns (bytes memory) { return abi.encode(offchainVectorId); } /** * @dev Return abi-encoded claimWithMetaTxPacket part one * @param claim Claim */ function _claimWithMetaTxABIEncoded1(ClaimWithMetaTxPacket calldata claim) private pure returns (bytes memory) { return abi.encode( _getClaimWithMetaTxPacketTypeHash(), claim.currency, claim.contractAddress, claim.claimer, claim.pricePerToken, claim.numTokensToMint, claim.purchaseToCreatorPacket, claim.purchaseToPlatformPacket, claim.maxClaimableViaVector, claim.maxClaimablePerUser, claim.editionId, claim.claimExpiryTimestamp ); } /** * @dev Return abi-encoded claimWithMetaTxPacket part two * @param claimNonce Claim's unique identifier * @param offchainVectorId Offchain vector ID of claim */ function _claimWithMetaTxABIEncoded2(bytes32 claimNonce, bytes32 offchainVectorId) private pure returns (bytes memory) { return abi.encode(claimNonce, offchainVectorId); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity 0.8.10; import "@openzeppelin/contracts/utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ /* solhint-disable */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.10; /** * @dev General721 mint interface * @author [email protected] */ interface IERC721GeneralMint { /** * @dev Mint one token to one recipient * @param recipient Recipient of minted NFT */ function mintOneToOneRecipient(address recipient) external; /** * @dev Mint an amount of tokens to one recipient * @param recipient Recipient of minted NFTs * @param amount Amount of NFTs minted */ function mintAmountToOneRecipient(address recipient, uint256 amount) external; /** * @dev Mint one token to multiple recipients. Useful for use-cases like airdrops * @param recipients Recipients of minted NFTs */ function mintOneToMultipleRecipients(address[] calldata recipients) external; /** * @dev Mint the same amount of tokens to multiple recipients * @param recipients Recipients of minted NFTs * @param amount Amount of NFTs minted to each recipient */ function mintSameAmountToMultipleRecipients(address[] calldata recipients, uint256 amount) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.10; /** * @dev Mint interface on editions contracts * @author [email protected] */ interface IERC721EditionMint { /** * @dev Mints one NFT to one recipient * @param editionId Edition to mint the NFT on * @param recipient Recipient of minted NFT */ function mintOneToRecipient(uint256 editionId, address recipient) external returns (uint256); /** * @dev Mints an amount of NFTs to one recipient * @param editionId Edition to mint the NFTs on * @param recipient Recipient of minted NFTs * @param amount Amount of NFTs minted */ function mintAmountToRecipient( uint256 editionId, address recipient, uint256 amount ) external returns (uint256); /** * @dev Mints one NFT each to a number of recipients * @param editionId Edition to mint the NFTs on * @param recipients Recipients of minted NFTs */ function mintOneToRecipients(uint256 editionId, address[] memory recipients) external returns (uint256); /** * @dev Mints an amount of NFTs each to a number of recipients * @param editionId Edition to mint the NFTs on * @param recipients Recipients of minted NFTs * @param amount Amount of NFTs minted per recipient */ function mintAmountToRecipients( uint256 editionId, address[] memory recipients, uint256 amount ) external returns (uint256); }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.10; /** * @title NativeMetaTransaction interface. Used by eg. wETH on Polygon * @author [email protected] */ interface INativeMetaTransaction { /** * @dev Meta-transaction object * @param nonce Account nonce * @param from Account to be considered as sender * @param functionSignature Function to call on contract, with arguments encoded */ struct MetaTransaction { uint256 nonce; address from; bytes functionSignature; } /** * @dev Execute meta transaction on contract containing EIP-712 stuff natively * @param userAddress User to be considered as sender * @param functionSignature Function to call on contract, with arguments encoded * @param sigR Elliptic curve signature component * @param sigS Elliptic curve signature component * @param sigV Elliptic curve signature component */ function executeMetaTransaction( address userAddress, bytes memory functionSignature, bytes32 sigR, bytes32 sigS, uint8 sigV ) external payable returns (bytes memory); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; /** * @author OpenZeppelin, modified by [email protected] to make compliant to upgradeable contracts * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * _Available since v3.4._ */ /* solhint-disable */ abstract contract EIP712Upgradeable is Initializable { /* solhint-disable var-name-mixedcase */ // Cache the domain separator, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private _CACHED_DOMAIN_SEPARATOR; uint256 private _CACHED_CHAIN_ID; bytes32 private _HASHED_NAME; bytes32 private _HASHED_VERSION; bytes32 private _TYPE_HASH; /* solhint-enable var-name-mixedcase */ /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ function __EIP721Upgradeable_initialize(string memory name, string memory version) internal onlyInitializing { bytes32 hashedName = keccak256(bytes(name)); bytes32 hashedVersion = keccak256(bytes(version)); /* solhint-disable max-line-length */ bytes32 typeHash = keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ); /* solhint-enable max-line-length */ _HASHED_NAME = hashedName; _HASHED_VERSION = hashedVersion; _CACHED_CHAIN_ID = block.chainid; _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion); _TYPE_HASH = typeHash; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { if (block.chainid == _CACHED_CHAIN_ID) { return _CACHED_DOMAIN_SEPARATOR; } else { return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION); } } function _buildDomainSeparator( bytes32 typeHash, bytes32 name, bytes32 version ) private view returns (bytes32) { return keccak256(abi.encode(typeHash, name, version, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), structHash)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (metatx/ERC2771Context.sol) pragma solidity 0.8.10; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; /** * @dev Context variant with ERC2771 support. * Openzeppelin contract slightly modified by ishan@ highlight.xyz to be upgradeable. */ abstract contract ERC2771ContextUpgradeable is Initializable { address private _trustedForwarder; /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; function isTrustedForwarder(address forwarder) public view virtual returns (bool) { return forwarder == _trustedForwarder; } function __ERC2771ContextUpgradeable__init__(address trustedForwarder) internal onlyInitializing { _trustedForwarder = trustedForwarder; } function _msgSender() internal view virtual returns (address sender) { if (isTrustedForwarder(msg.sender)) { // The assembly code is more direct than the Solidity version using `abi.decode`. /* solhint-disable no-inline-assembly */ assembly { sender := shr(96, calldataload(sub(calldatasize(), 20))) } /* solhint-enable no-inline-assembly */ } else { return msg.sender; } } function _msgData() internal view virtual returns (bytes calldata) { if (isTrustedForwarder(msg.sender)) { return msg.data[:msg.data.length - 20]; } else { return msg.data; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol) pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { return _values(set._inner); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol) pragma solidity ^0.8.0; /** * @dev These functions deal with verification of Merkle Tree proofs. * * The proofs can be generated using the JavaScript library * https://github.com/miguelmota/merkletreejs[merkletreejs]. * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled. * * See `test/utils/cryptography/MerkleProof.test.js` for some examples. * * WARNING: You should avoid using leaf values that are 64 bytes long prior to * hashing, or use a hash function other than keccak256 for hashing leaves. * This is because the concatenation of a sorted pair of internal nodes in * the merkle tree could be reinterpreted as a leaf value. */ library MerkleProof { /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify( bytes32[] memory proof, bytes32 root, bytes32 leaf ) internal pure returns (bool) { return processProof(proof, leaf) == root; } /** * @dev Calldata version of {verify} * * _Available since v4.7._ */ function verifyCalldata( bytes32[] calldata proof, bytes32 root, bytes32 leaf ) internal pure returns (bool) { return processProofCalldata(proof, leaf) == root; } /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. When processing the proof, the pairs * of leafs & pre-images are assumed to be sorted. * * _Available since v4.4._ */ function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Calldata version of {processProof} * * _Available since v4.7._ */ function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. * * _Available since v4.7._ */ function multiProofVerify( bytes32[] memory proof, bool[] memory proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProof(proof, proofFlags, leaves) == root; } /** * @dev Calldata version of {multiProofVerify} * * _Available since v4.7._ */ function multiProofVerifyCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProofCalldata(proof, proofFlags, leaves) == root; } /** * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`, * consuming from one or the other at each step according to the instructions given by * `proofFlags`. * * _Available since v4.7._ */ function processMultiProof( bytes32[] memory proof, bool[] memory proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { return hashes[totalHashes - 1]; } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Calldata version of {processMultiProof} * * _Available since v4.7._ */ function processMultiProofCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { return hashes[totalHashes - 1]; } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { return a < b ? _efficientHash(a, b) : _efficientHash(b, a); } function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, a) mstore(0x20, b) value := keccak256(0x00, 0x40) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external 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 // OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.0; import "../../interfaces/draft-IERC1822.sol"; import "../ERC1967/ERC1967Upgrade.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. * * _Available since v4.1._ */ abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment address private immutable __self = address(this); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { require(address(this) != __self, "Function must be called through delegatecall"); require(_getImplementation() == __self, "Function must be called through active proxy"); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall"); _; } /** * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate that the this implementation remains valid after an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual override notDelegated returns (bytes32) { return _IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeTo(address newImplementation) external virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data, true); } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeTo} and {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal override onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original * initialization step. This is essential to configure modules that are added through upgrades and that require * initialization. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// 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); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeacon.sol"; import "../../interfaces/draft-IERC1822.sol"; import "../../utils/Address.sol"; import "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967Upgrade { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { Address.functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS( address newImplementation, bytes memory data, bool forceCall ) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Emitted when the beacon is upgraded. */ event BeaconUpgraded(address indexed beacon); /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol) pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
{ "metadata": { "bytecodeHash": "none" }, "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"currency","type":"address"},{"indexed":true,"internalType":"address","name":"paymentRecipient","type":"address"},{"indexed":true,"internalType":"bytes32","name":"vectorId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountToCreator","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"percentageBPSOfTotal","type":"uint32"}],"name":"ERC20Payment","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"currency","type":"address"},{"indexed":true,"internalType":"address","name":"msgSender","type":"address"},{"indexed":true,"internalType":"bytes32","name":"vectorId","type":"bytes32"},{"components":[{"internalType":"bytes","name":"functionSignature","type":"bytes"},{"internalType":"bytes32","name":"sigR","type":"bytes32"},{"internalType":"bytes32","name":"sigS","type":"bytes32"},{"internalType":"uint8","name":"sigV","type":"uint8"}],"indexed":false,"internalType":"struct MintManager.PurchaserMetaTxPacket","name":"purchaseToCreatorPacket","type":"tuple"},{"components":[{"internalType":"bytes","name":"functionSignature","type":"bytes"},{"internalType":"bytes32","name":"sigR","type":"bytes32"},{"internalType":"bytes32","name":"sigS","type":"bytes32"},{"internalType":"uint8","name":"sigV","type":"uint8"}],"indexed":false,"internalType":"struct MintManager.PurchaserMetaTxPacket","name":"purchaseToPlatformPacket","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20PaymentMetaTxPackets","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"paymentRecipient","type":"address"},{"indexed":true,"internalType":"bytes32","name":"vectorId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amountToCreator","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"percentageBPSOfTotal","type":"uint32"}],"name":"NativeGasTokenPayment","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"withdrawnValue","type":"uint256"}],"name":"NativeGasTokenWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"executor","type":"address"},{"indexed":true,"internalType":"bool","name":"added","type":"bool"}],"name":"PlatformExecutorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vectorId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"editionId","type":"uint256"},{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"address payable","name":"paymentRecipient","type":"address"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"internalType":"uint256","name":"pricePerToken","type":"uint256"},{"internalType":"uint64","name":"tokenLimitPerTx","type":"uint64"},{"internalType":"uint64","name":"maxTotalClaimableViaVector","type":"uint64"},{"internalType":"uint64","name":"maxUserClaimableViaVector","type":"uint64"},{"internalType":"uint64","name":"totalClaimedViaVector","type":"uint64"},{"internalType":"bytes32","name":"allowlistRoot","type":"bytes32"},{"internalType":"uint8","name":"paused","type":"uint8"}],"indexed":false,"internalType":"struct MintManager.Vector","name":"vector","type":"tuple"}],"name":"VectorCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vectorId","type":"uint256"}],"name":"VectorDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vectorId","type":"uint256"},{"components":[{"internalType":"uint8","name":"updatesFrozen","type":"uint8"},{"internalType":"uint8","name":"deleteFrozen","type":"uint8"},{"internalType":"uint8","name":"pausesFrozen","type":"uint8"}],"indexed":false,"internalType":"struct MintManager.VectorMutability","name":"_newVectorMutability","type":"tuple"}],"name":"VectorMutabilityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vectorId","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"paused","type":"uint8"}],"name":"VectorPausedOrUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vectorId","type":"uint256"},{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"address payable","name":"paymentRecipient","type":"address"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"internalType":"uint256","name":"pricePerToken","type":"uint256"},{"internalType":"uint64","name":"tokenLimitPerTx","type":"uint64"},{"internalType":"uint64","name":"maxTotalClaimableViaVector","type":"uint64"},{"internalType":"uint64","name":"maxUserClaimableViaVector","type":"uint64"},{"internalType":"uint64","name":"totalClaimedViaVector","type":"uint64"},{"internalType":"bytes32","name":"allowlistRoot","type":"bytes32"},{"internalType":"uint8","name":"paused","type":"uint8"}],"indexed":false,"internalType":"struct MintManager.Vector","name":"newVector","type":"tuple"}],"name":"VectorUpdated","type":"event"},{"inputs":[{"internalType":"address","name":"_executor","type":"address"}],"name":"addPlatformExecutor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"address payable","name":"paymentRecipient","type":"address"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"internalType":"uint256","name":"pricePerToken","type":"uint256"},{"internalType":"uint64","name":"tokenLimitPerTx","type":"uint64"},{"internalType":"uint64","name":"maxTotalClaimableViaVector","type":"uint64"},{"internalType":"uint64","name":"maxUserClaimableViaVector","type":"uint64"},{"internalType":"uint64","name":"totalClaimedViaVector","type":"uint64"},{"internalType":"bytes32","name":"allowlistRoot","type":"bytes32"},{"internalType":"uint8","name":"paused","type":"uint8"}],"internalType":"struct MintManager.Vector","name":"_vector","type":"tuple"},{"components":[{"internalType":"uint8","name":"updatesFrozen","type":"uint8"},{"internalType":"uint8","name":"deleteFrozen","type":"uint8"},{"internalType":"uint8","name":"pausesFrozen","type":"uint8"}],"internalType":"struct MintManager.VectorMutability","name":"_vectorMutability","type":"tuple"},{"internalType":"uint256","name":"editionId","type":"uint256"}],"name":"createVector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vectorId","type":"uint256"}],"name":"deleteVector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_executor","type":"address"}],"name":"deprecatePlatformExecutor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"currency","type":"address"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"claimer","type":"address"},{"internalType":"address payable","name":"paymentRecipient","type":"address"},{"internalType":"uint256","name":"pricePerToken","type":"uint256"},{"internalType":"uint64","name":"numTokensToMint","type":"uint64"},{"internalType":"uint256","name":"maxClaimableViaVector","type":"uint256"},{"internalType":"uint256","name":"maxClaimablePerUser","type":"uint256"},{"internalType":"uint256","name":"editionId","type":"uint256"},{"internalType":"uint256","name":"claimExpiryTimestamp","type":"uint256"},{"internalType":"bytes32","name":"claimNonce","type":"bytes32"},{"internalType":"bytes32","name":"offchainVectorId","type":"bytes32"}],"internalType":"struct MintManager.Claim","name":"_claim","type":"tuple"},{"internalType":"bytes","name":"_signature","type":"bytes"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"gatedMintEdition721","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"currency","type":"address"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"claimer","type":"address"},{"internalType":"address payable","name":"paymentRecipient","type":"address"},{"internalType":"uint256","name":"pricePerToken","type":"uint256"},{"internalType":"uint64","name":"numTokensToMint","type":"uint64"},{"internalType":"uint256","name":"maxClaimableViaVector","type":"uint256"},{"internalType":"uint256","name":"maxClaimablePerUser","type":"uint256"},{"internalType":"uint256","name":"editionId","type":"uint256"},{"internalType":"uint256","name":"claimExpiryTimestamp","type":"uint256"},{"internalType":"bytes32","name":"claimNonce","type":"bytes32"},{"internalType":"bytes32","name":"offchainVectorId","type":"bytes32"}],"internalType":"struct MintManager.Claim","name":"claim","type":"tuple"},{"internalType":"bytes","name":"claimSignature","type":"bytes"},{"internalType":"address","name":"mintRecipient","type":"address"}],"name":"gatedMintGeneral721","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"currency","type":"address"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"claimer","type":"address"},{"internalType":"uint256","name":"pricePerToken","type":"uint256"},{"internalType":"uint64","name":"numTokensToMint","type":"uint64"},{"components":[{"internalType":"bytes","name":"functionSignature","type":"bytes"},{"internalType":"bytes32","name":"sigR","type":"bytes32"},{"internalType":"bytes32","name":"sigS","type":"bytes32"},{"internalType":"uint8","name":"sigV","type":"uint8"}],"internalType":"struct MintManager.PurchaserMetaTxPacket","name":"purchaseToCreatorPacket","type":"tuple"},{"components":[{"internalType":"bytes","name":"functionSignature","type":"bytes"},{"internalType":"bytes32","name":"sigR","type":"bytes32"},{"internalType":"bytes32","name":"sigS","type":"bytes32"},{"internalType":"uint8","name":"sigV","type":"uint8"}],"internalType":"struct MintManager.PurchaserMetaTxPacket","name":"purchaseToPlatformPacket","type":"tuple"},{"internalType":"uint256","name":"maxClaimableViaVector","type":"uint256"},{"internalType":"uint256","name":"maxClaimablePerUser","type":"uint256"},{"internalType":"uint256","name":"editionId","type":"uint256"},{"internalType":"uint256","name":"claimExpiryTimestamp","type":"uint256"},{"internalType":"bytes32","name":"claimNonce","type":"bytes32"},{"internalType":"bytes32","name":"offchainVectorId","type":"bytes32"}],"internalType":"struct MintManager.ClaimWithMetaTxPacket","name":"claim","type":"tuple"},{"internalType":"bytes","name":"claimSignature","type":"bytes"},{"internalType":"address","name":"mintRecipient","type":"address"}],"name":"gatedMintPaymentPacketEdition721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"currency","type":"address"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"claimer","type":"address"},{"internalType":"uint256","name":"pricePerToken","type":"uint256"},{"internalType":"uint64","name":"numTokensToMint","type":"uint64"},{"components":[{"internalType":"bytes","name":"functionSignature","type":"bytes"},{"internalType":"bytes32","name":"sigR","type":"bytes32"},{"internalType":"bytes32","name":"sigS","type":"bytes32"},{"internalType":"uint8","name":"sigV","type":"uint8"}],"internalType":"struct MintManager.PurchaserMetaTxPacket","name":"purchaseToCreatorPacket","type":"tuple"},{"components":[{"internalType":"bytes","name":"functionSignature","type":"bytes"},{"internalType":"bytes32","name":"sigR","type":"bytes32"},{"internalType":"bytes32","name":"sigS","type":"bytes32"},{"internalType":"uint8","name":"sigV","type":"uint8"}],"internalType":"struct MintManager.PurchaserMetaTxPacket","name":"purchaseToPlatformPacket","type":"tuple"},{"internalType":"uint256","name":"maxClaimableViaVector","type":"uint256"},{"internalType":"uint256","name":"maxClaimablePerUser","type":"uint256"},{"internalType":"uint256","name":"editionId","type":"uint256"},{"internalType":"uint256","name":"claimExpiryTimestamp","type":"uint256"},{"internalType":"bytes32","name":"claimNonce","type":"bytes32"},{"internalType":"bytes32","name":"offchainVectorId","type":"bytes32"}],"internalType":"struct MintManager.ClaimWithMetaTxPacket","name":"claim","type":"tuple"},{"internalType":"bytes","name":"claimSignature","type":"bytes"},{"internalType":"address","name":"mintRecipient","type":"address"}],"name":"gatedMintPaymentPacketGeneral721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"vectorId","type":"bytes32"}],"name":"getClaimNoncesUsedForOffchainVector","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"vectorId","type":"bytes32"},{"internalType":"address","name":"user","type":"address"}],"name":"getNumClaimedPerUserOffchainVector","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"platform","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"trustedForwarder","type":"address"},{"internalType":"address","name":"initialExecutor","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"vectorId","type":"bytes32"},{"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"isNonceUsed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"offchainVectorsClaimState","outputs":[{"internalType":"uint256","name":"numClaimed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"vectorId","type":"uint256"}],"name":"pauseVector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"platformExecutors","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vectorId","type":"uint256"}],"name":"unpauseVector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vectorId","type":"uint256"},{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"address payable","name":"paymentRecipient","type":"address"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"internalType":"uint256","name":"pricePerToken","type":"uint256"},{"internalType":"uint64","name":"tokenLimitPerTx","type":"uint64"},{"internalType":"uint64","name":"maxTotalClaimableViaVector","type":"uint64"},{"internalType":"uint64","name":"maxUserClaimableViaVector","type":"uint64"},{"internalType":"uint64","name":"totalClaimedViaVector","type":"uint64"},{"internalType":"bytes32","name":"allowlistRoot","type":"bytes32"},{"internalType":"uint8","name":"paused","type":"uint8"}],"internalType":"struct MintManager.Vector","name":"_newVector","type":"tuple"}],"name":"updateVector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vectorId","type":"uint256"},{"components":[{"internalType":"uint8","name":"updatesFrozen","type":"uint8"},{"internalType":"uint8","name":"deleteFrozen","type":"uint8"},{"internalType":"uint8","name":"pausesFrozen","type":"uint8"}],"internalType":"struct MintManager.VectorMutability","name":"_newVectorMutability","type":"tuple"}],"name":"updateVectorMutability","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"userClaims","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"vectorId","type":"uint256"},{"internalType":"uint64","name":"numTokensToMint","type":"uint64"},{"internalType":"address","name":"mintRecipient","type":"address"}],"name":"vectorMintEdition721","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vectorId","type":"uint256"},{"internalType":"uint64","name":"numTokensToMint","type":"uint64"},{"internalType":"address","name":"mintRecipient","type":"address"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"vectorMintEdition721WithAllowlist","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vectorId","type":"uint256"},{"internalType":"uint64","name":"numTokensToMint","type":"uint64"},{"internalType":"address","name":"mintRecipient","type":"address"}],"name":"vectorMintGeneral721","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vectorId","type":"uint256"},{"internalType":"uint64","name":"numTokensToMint","type":"uint64"},{"internalType":"address","name":"mintRecipient","type":"address"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"vectorMintGeneral721WithAllowlist","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"vectorMutabilities","outputs":[{"internalType":"uint8","name":"updatesFrozen","type":"uint8"},{"internalType":"uint8","name":"deleteFrozen","type":"uint8"},{"internalType":"uint8","name":"pausesFrozen","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"vectorToEditionId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"vectors","outputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"address payable","name":"paymentRecipient","type":"address"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"internalType":"uint256","name":"pricePerToken","type":"uint256"},{"internalType":"uint64","name":"tokenLimitPerTx","type":"uint64"},{"internalType":"uint64","name":"maxTotalClaimableViaVector","type":"uint64"},{"internalType":"uint64","name":"maxUserClaimableViaVector","type":"uint64"},{"internalType":"uint64","name":"totalClaimedViaVector","type":"uint64"},{"internalType":"bytes32","name":"allowlistRoot","type":"bytes32"},{"internalType":"uint8","name":"paused","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"currency","type":"address"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"claimer","type":"address"},{"internalType":"address payable","name":"paymentRecipient","type":"address"},{"internalType":"uint256","name":"pricePerToken","type":"uint256"},{"internalType":"uint64","name":"numTokensToMint","type":"uint64"},{"internalType":"uint256","name":"maxClaimableViaVector","type":"uint256"},{"internalType":"uint256","name":"maxClaimablePerUser","type":"uint256"},{"internalType":"uint256","name":"editionId","type":"uint256"},{"internalType":"uint256","name":"claimExpiryTimestamp","type":"uint256"},{"internalType":"bytes32","name":"claimNonce","type":"bytes32"},{"internalType":"bytes32","name":"offchainVectorId","type":"bytes32"}],"internalType":"struct MintManager.Claim","name":"claim","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"expectedMsgSender","type":"address"}],"name":"verifyClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"currency","type":"address"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"claimer","type":"address"},{"internalType":"uint256","name":"pricePerToken","type":"uint256"},{"internalType":"uint64","name":"numTokensToMint","type":"uint64"},{"components":[{"internalType":"bytes","name":"functionSignature","type":"bytes"},{"internalType":"bytes32","name":"sigR","type":"bytes32"},{"internalType":"bytes32","name":"sigS","type":"bytes32"},{"internalType":"uint8","name":"sigV","type":"uint8"}],"internalType":"struct MintManager.PurchaserMetaTxPacket","name":"purchaseToCreatorPacket","type":"tuple"},{"components":[{"internalType":"bytes","name":"functionSignature","type":"bytes"},{"internalType":"bytes32","name":"sigR","type":"bytes32"},{"internalType":"bytes32","name":"sigS","type":"bytes32"},{"internalType":"uint8","name":"sigV","type":"uint8"}],"internalType":"struct MintManager.PurchaserMetaTxPacket","name":"purchaseToPlatformPacket","type":"tuple"},{"internalType":"uint256","name":"maxClaimableViaVector","type":"uint256"},{"internalType":"uint256","name":"maxClaimablePerUser","type":"uint256"},{"internalType":"uint256","name":"editionId","type":"uint256"},{"internalType":"uint256","name":"claimExpiryTimestamp","type":"uint256"},{"internalType":"bytes32","name":"claimNonce","type":"bytes32"},{"internalType":"bytes32","name":"offchainVectorId","type":"bytes32"}],"internalType":"struct MintManager.ClaimWithMetaTxPacket","name":"claim","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"expectedMsgSender","type":"address"}],"name":"verifyClaimWithMetaTxPacket","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawNativeGasToken","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a06040523060805234801561001457600080fd5b50608051615b886200004d6000396000818161123001528181611270015281816117cd0152818161180d0152611bee0152615b886000f3fe60806040526004361061020f5760003560e01c80636008d06811610118578063aa1b5b46116100a0578063dfcbaa571161006f578063dfcbaa5714610782578063f2fde38b146107a2578063f4a40345146107c2578063f73bc2da146107e2578063f8c8765e1461080257600080fd5b8063aa1b5b46146106ae578063ae709ae3146106c1578063b414ae2f146106ee578063c462507e1461071b57600080fd5b80638da5cb5b116100e75780638da5cb5b146105d85780639c5c0492146106005780639e2dc500146106225780639fc11e191461067b578063a30808ff1461069b57600080fd5b80636008d06814610465578063619b858914610485578063715018a6146105a3578063868befd8146105b857600080fd5b80634561cdb11161019b578063525a2e031161016a578063525a2e03146103a757806352d1902d146103ba57806353274246146103cf578063572b6c05146104165780635dcd547e1461044557600080fd5b80634561cdb11461033f57806346b060c31461035f5780634f1ef2861461037f578063513ea0901461039257600080fd5b80631eeb26d2116101e25780631eeb26d21461029c5780631f25b358146102bc5780633659cfe6146102dc5780633716e284146102fc57806341772bf01461032c57600080fd5b80630680475b146102145780630c56ce86146102295780630dbb18a1146102495780631c6c0ed514610289575b600080fd5b610227610222366004614c54565b610822565b005b34801561023557600080fd5b50610227610244366004614cbd565b61097b565b34801561025557600080fd5b50610276610264366004614ceb565b60a16020526000908152604090205481565b6040519081526020015b60405180910390f35b610227610297366004614d24565b610bf1565b3480156102a857600080fd5b506102276102b7366004614ceb565b610e79565b3480156102c857600080fd5b506102276102d7366004614dc5565b61101c565b3480156102e857600080fd5b506102276102f7366004614e3e565b611225565b34801561030857600080fd5b5061031c610317366004614e5b565b611305565b6040519015158152602001610280565b61022761033a366004614d24565b611326565b34801561034b57600080fd5b5061022761035a366004614dc5565b611553565b34801561036b57600080fd5b5061022761037a366004614e3e565b611739565b61022761038d366004614eea565b6117c2565b34801561039e57600080fd5b50610227611893565b6102276103b5366004614f7c565b6119cc565b3480156103c657600080fd5b50610276611be1565b3480156103db57600080fd5b506102766103ea366004614fbe565b600082815260a1602090815260408083206001600160a01b038516845260010190915290205492915050565b34801561042257600080fd5b5061031c610431366004614e3e565b606a546001600160a01b0391821691161490565b34801561045157600080fd5b5061031c610460366004614dc5565b611c94565b34801561047157600080fd5b50610227610480366004615000565b611df5565b34801561049157600080fd5b506105256104a0366004614ceb565b609d602052600090815260409020805460018201546002830154600384015460048501546005860154600687015460078801546008909801546001600160a01b039788169896881697909516959394929391926001600160401b0380831693600160401b8404821693600160801b8104831693600160c01b9091049092169160ff168c565b604080516001600160a01b039d8e1681529b8d1660208d015299909b16988a01989098526060890196909652608088019490945260a08701929092526001600160401b0390811660c087015290811660e08601529081166101008501521661012083015261014082015260ff90911661016082015261018001610280565b3480156105af57600080fd5b50610227611fb0565b3480156105c457600080fd5b506102276105d3366004614ceb565b611fc4565b3480156105e457600080fd5b506038546040516001600160a01b039091168152602001610280565b34801561060c57600080fd5b5061061561221c565b6040516102809190615041565b34801561062e57600080fd5b5061066361063d366004614fbe565b609f6020908152600092835260408084209091529082529020546001600160401b031681565b6040516001600160401b039091168152602001610280565b34801561068757600080fd5b50610227610696366004614ceb565b61222d565b6102276106a9366004614c54565b612420565b6102276106bc366004614f7c565b61255a565b3480156106cd57600080fd5b506106e16106dc366004614ceb565b612717565b604051610280919061508e565b3480156106fa57600080fd5b50610276610709366004614ceb565b60a26020526000908152604090205481565b34801561072757600080fd5b5061075e610736366004614ceb565b609e6020526000908152604090205460ff808216916101008104821691620100009091041683565b6040805160ff94851681529284166020840152921691810191909152606001610280565b34801561078e57600080fd5b5061022761079d3660046150c6565b612731565b3480156107ae57600080fd5b506102276107bd366004614e3e565b612884565b3480156107ce57600080fd5b5061031c6107dd366004614c54565b6128fa565b3480156107ee57600080fd5b506102276107fd366004614e3e565b612a38565b34801561080e57600080fd5b5061022761081d3660046150ea565b612b17565b61082d848484612cab565b61083d60c0850160a0860161513b565b6001600160401b0316600114156108dd5761085e6040850160208601614e3e565b60405163b859c93560e01b815261010086013560048201526001600160a01b038381166024830152919091169063b859c935906044016020604051808303816000875af11580156108b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d79190615158565b50610975565b6108ed6040850160208601614e3e565b6001600160a01b0316631b30808d6101008601358361091260c0890160a08a0161513b565b6040518463ffffffff1660e01b815260040161093093929190615171565b6020604051808303816000875af115801561094f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109739190615158565b505b50505050565b6000828152609d6020908152604080832081516101808101835281546001600160a01b0390811682526001830154811682860152600283015416818401526003820154606082015260048201546080820152600582015460a082015260068201546001600160401b0380821660c0840152600160401b8204811660e0840152600160801b82048116610100840152600160c01b90910416610120820152600782015461014082015260089091015460ff908116610160830152868552609e9093529220541615610a835760405162461bcd60e51b815260206004820152600e60248201526d2ab83230ba32b990333937bd32b760911b60448201526064015b60405180910390fd5b610a956101408301610120840161513b565b6001600160401b03168161012001516001600160401b031614610afa5760405162461bcd60e51b815260206004820152601760248201527f546f74616c20636c61696d656420646966666572656e740000000000000000006044820152606401610a7a565b610b02612d9f565b6001600160a01b031681600001516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b719190615199565b6001600160a01b031614610b975760405162461bcd60e51b8152600401610a7a906151b6565b6000838152609d602052604090208290610bb18282615238565b905050827fff5c4fac01cfe6733a03f74e6e27fad31408c685c89c37640e0b4705a2b485b283604051610be491906153b6565b60405180910390a2505050565b6000610bfb612d9f565b90506001600160a01b0381163214610c255760405162461bcd60e51b8152600401610a7a906154ba565b6000868152609d6020908152604080832081516101808101835281546001600160a01b03908116825260018301548116948201949094526002820154909316918301919091526003810154606083015260048101546080830152600581015460a083015260068101546001600160401b0380821660c0850152600160401b8204811660e0850152600160801b82048116610100850152600160c01b909104166101208301819052600782015461014084015260089091015460ff16610160830152909190610cf4908890615507565b6000898152609f602090815260408083206001600160a01b038816845290915281205491925090610d2f9089906001600160401b0316615507565b6040516bffffffffffffffffffffffff19606087901b166020820152909150600090603401604051602081830303815290604052805190602001209050610dae87878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050505061014086015183612da9565b610dea5760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b210383937b7b360991b6044820152606401610a7a565b610e0a8a858b8b876001600160401b0316876001600160401b0316612dc1565b506000988952609d60209081526040808b2060060180546001600160c01b0316600160c01b6001600160401b0396871602179055609f8252808b206001600160a01b03969096168b5294905292909720805467ffffffffffffffff191692909716919091179095555050505050565b6000818152609d602090815260409182902082516101808101845281546001600160a01b03908116825260018301548116938201939093526002820154909216928201929092526003820154606082015260048201546080820152600582015460a082015260068201546001600160401b0380821660c0840152600160401b8204811660e0840152600160801b82048116610100840152600160c01b90910416610120820152600782015461014082015260089091015460ff16610160820152610f41612d9f565b6001600160a01b031681600001516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb09190615199565b6001600160a01b031614610fd65760405162461bcd60e51b8152600401610a7a906151b6565b6000828152609d6020526040808220600801805460ff191690555183907fdb6fb1b5c66ce89d126ba29f8251b4726a01581a6f14626db9d3179c9b30625a908390a35050565b6000611026612d9f565b905061103485858584612eb8565b60006110436020870187614e3e565b6001600160a01b0316141561108e5760405162461bcd60e51b8152602060048201526011602482015270139bdd08115490cc8c081c185e5b595b9d607a1b6044820152606401610a7a565b6060850135156110f5576110f56110a86020870187614e3e565b6110b560a0880188615532565b6110c260c0890189615532565b846101808a01356110d960a08c0160808d0161513b565b6110f0906001600160401b031660608d0135615552565b6130b3565b61110560a086016080870161513b565b6001600160401b031660011415611188576111266040860160208701614e3e565b60405163184a94d560e01b81526001600160a01b038481166004830152919091169063184a94d590602401600060405180830381600087803b15801561116b57600080fd5b505af115801561117f573d6000803e3d6000fd5b50505050610973565b6111986040860160208701614e3e565b6001600160a01b0316635be95448836111b760a0890160808a0161513b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526001600160401b03166024820152604401600060405180830381600087803b15801561120657600080fd5b505af115801561121a573d6000803e3d6000fd5b505050505050505050565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016141561126e5760405162461bcd60e51b8152600401610a7a90615571565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166112b7600080516020615b35833981519152546001600160a01b031690565b6001600160a01b0316146112dd5760405162461bcd60e51b8152600401610a7a906155bd565b6112e681613378565b6040805160008082526020820190925261130291839190613380565b50565b600082815260a06020526040812061131d90836134f0565b90505b92915050565b6000611330612d9f565b90506001600160a01b038116321461135a5760405162461bcd60e51b8152600401610a7a906154ba565b6000868152609d6020908152604080832081516101808101835281546001600160a01b03908116825260018301548116948201949094526002820154909316918301919091526003810154606083015260048101546080830152600581015460a083015260068101546001600160401b0380821660c0850152600160401b8204811660e0850152600160801b82048116610100850152600160c01b909104166101208301819052600782015461014084015260089091015460ff16610160830152909190611429908890615507565b6000898152609f602090815260408083206001600160a01b0388168452909152812054919250906114649089906001600160401b0316615507565b6040516bffffffffffffffffffffffff19606087901b1660208201529091506000906034016040516020818303038152906040528051906020012090506114e387878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050505061014086015183612da9565b61151f5760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b210383937b7b360991b6044820152606401610a7a565b610e0a8a8560a260008e8152602001908152602001600020548c8c886001600160401b0316886001600160401b0316613508565b600061155d612d9f565b905061156b85858584612eb8565b600061157a6020870187614e3e565b6001600160a01b031614156115d15760405162461bcd60e51b815260206004820152601760248201527f48617320746f206265204552433230207061796d656e740000000000000000006044820152606401610a7a565b6060850135156115eb576115eb6110a86020870187614e3e565b6115fb60a086016080870161513b565b6001600160401b03166001141561169b5761161c6040860160208701614e3e565b60405163b859c93560e01b815261012087013560048201526001600160a01b038481166024830152919091169063b859c935906044016020604051808303816000875af1158015611671573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116959190615158565b50610973565b6116ab6040860160208701614e3e565b6001600160a01b0316631b30808d610120870135846116d060a08a0160808b0161513b565b6040518463ffffffff1660e01b81526004016116ee93929190615171565b6020604051808303816000875af115801561170d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117319190615158565b505050505050565b611741613622565b61174c60a48261369b565b6117895760405162461bcd60e51b815260206004820152600e60248201526d139bdd0819195c1c9958d85d195960921b6044820152606401610a7a565b6040516000906001600160a01b038316907f88d9d369733d630a0dbd71ed25dcafecbae7bc29d54a925afc1d003acf2af385908390a350565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016141561180b5760405162461bcd60e51b8152600401610a7a90615571565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611854600080516020615b35833981519152546001600160a01b031690565b6001600160a01b03161461187a5760405162461bcd60e51b8152600401610a7a906155bd565b61188382613378565b61188f82826001613380565b5050565b609c546001600160a01b03166118a7612d9f565b6001600160a01b0316146118ec5760405162461bcd60e51b815260206004820152600c60248201526b4e6f7420706c6174666f726d60a01b6044820152606401610a7a565b609c54604051479160009182916001600160a01b03169084908381818185875af1925050503d806000811461193d576040519150601f19603f3d011682016040523d82523d6000602084013e611942565b606091505b5091509150816119945760405162461bcd60e51b815260206004820181905260248201527f4661696c656420746f2073656e6420457468657220746f20706c6174666f726d6044820152606401610a7a565b6040518381527fa941df830f6691e4ce38ea54fa7a7279d68f0a7ac9a3197e37a09b40323ec9029060200160405180910390a1505050565b60006119d6612d9f565b90506001600160a01b0381163214611a005760405162461bcd60e51b8152600401610a7a906154ba565b6000848152609d6020908152604080832081516101808101835281546001600160a01b03908116825260018301548116948201949094526002820154909316918301919091526003810154606083015260048101546080830152600581015460a083015260068101546001600160401b0380821660c0850152600160401b8204811660e0850152600160801b82048116610100850152600160c01b909104166101208301819052600782015461014084015260089091015460ff16610160830152909190611acf908690615507565b6000878152609f602090815260408083206001600160a01b038816845290915281205491925090611b0a9087906001600160401b0316615507565b61014084015190915015611b555760405162461bcd60e51b8152602060048201526012602482015271155cd948185b1b1bdddb1a5cdd081b5a5b9d60721b6044820152606401610a7a565b611b7587848888866001600160401b0316866001600160401b0316612dc1565b6000968752609d6020908152604080892060060180546001600160c01b0316600160c01b6001600160401b0396871602179055609f82528089206001600160a01b0396909616895294905292909520805467ffffffffffffffff19169290951691909117909355505050565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611c815760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610a7a565b50600080516020615b3583398151915290565b600080611ca28686866136b0565b9050611cb46060870160408801614e3e565b6001600160a01b0316836001600160a01b031614611ce45760405162461bcd60e51b8152600401610a7a90615609565b611ced8161375f565b8015611d195750610180860135600090815260a060205260409020611d17906101608801356134f0565b155b8015611d2a57508561014001354211155b8015611d7e575060e08601351580611d7e5750610180860135600090815260a1602052604090205460e087013590611d6860a0890160808a0161513b565b6001600160401b0316611d7b9190615635565b11155b8015611deb57506101008601351580611deb5750610180860135600090815260a1602090815260408083206001600160a01b038716845260010190915290205461010087013590611dd560a0890160808a0161513b565b6001600160401b0316611de89190615635565b11155b9695505050505050565b611dfd612d9f565b6001600160a01b0316611e136020850185614e3e565b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e749190615199565b6001600160a01b031614611e9a5760405162461bcd60e51b8152600401610a7a906151b6565b611eac6101408401610120850161513b565b6001600160401b031615611f025760405162461bcd60e51b815260206004820152601b60248201527f746f74616c436c61696d6564566961566563746f72206e6f74203000000000006044820152606401610a7a565b60a38054906000611f128361564d565b909155505060a3546000908152609d602052604090208390611f348282615238565b505060a3546000908152609e602052604090208290611f538282615668565b9050508060a2600060a3548152602001908152602001600020819055508060a3547f709b0a0bd2676c5cd18c4d5f0248c63bfa89a0df21132fce955c665495de279e85604051611fa391906153b6565b60405180910390a3505050565b611fb8613622565b611fc2600061376c565b565b6000818152609d6020908152604080832081516101808101835281546001600160a01b0390811682526001830154811682860152600283015416818401526003820154606082015260048201546080820152600582015460a082015260068201546001600160401b0380821660c0840152600160401b8204811660e0840152600160801b8204811661010080850191909152600160c01b90920416610120830152600783015461014083015260089092015460ff908116610160830152868652609e90945291909320549092900416156120d05760405162461bcd60e51b815260206004820152600d60248201526c2232b632ba3290333937bd32b760991b6044820152606401610a7a565b6120d8612d9f565b6001600160a01b031681600001516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612123573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121479190615199565b6001600160a01b03161461216d5760405162461bcd60e51b8152600401610a7a906151b6565b6000828152609d6020908152604080832080546001600160a01b031990811682556001820180548216905560028201805490911690556003810184905560048101849055600581018490556006810184905560078101849055600801805460ff19169055609e8252808320805462ffffff1916905560a354835260a29091528082208290555183917fc838617e2997901e8e4856126ebd46593aef10fb97d78f88b4635c9420f6731691a25050565b606061222860a46137be565b905090565b6000818152609d6020908152604080832081516101808101835281546001600160a01b0390811682526001830154811682860152600283015416818401526003820154606082015260048201546080820152600582015460a082015260068201546001600160401b0380821660c0840152600160401b8204811660e0840152600160801b82048116610100840152600160c01b90910416610120820152600782015461014082015260089091015460ff908116610160830152858552609e90935292205462010000900416156123355760405162461bcd60e51b815260206004820152600d60248201526c2830bab9b2b990333937bd32b760991b6044820152606401610a7a565b61233d612d9f565b6001600160a01b031681600001516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612388573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ac9190615199565b6001600160a01b0316146123d25760405162461bcd60e51b8152600401610a7a906151b6565b6000828152609d6020526040808220600801805460ff191660019081179091559051909184917fdb6fb1b5c66ce89d126ba29f8251b4726a01581a6f14626db9d3179c9b30625a9190a35050565b61242b848484612cab565b61243b60c0850160a0860161513b565b6001600160401b0316600114156124be5761245c6040850160208601614e3e565b60405163184a94d560e01b81526001600160a01b038381166004830152919091169063184a94d590602401600060405180830381600087803b1580156124a157600080fd5b505af11580156124b5573d6000803e3d6000fd5b50505050610975565b6124ce6040850160208601614e3e565b6001600160a01b0316635be95448826124ed60c0880160a0890161513b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526001600160401b03166024820152604401600060405180830381600087803b15801561253c57600080fd5b505af1158015612550573d6000803e3d6000fd5b5050505050505050565b6000612564612d9f565b90506001600160a01b038116321461258e5760405162461bcd60e51b8152600401610a7a906154ba565b6000848152609d6020908152604080832081516101808101835281546001600160a01b03908116825260018301548116948201949094526002820154909316918301919091526003810154606083015260048101546080830152600581015460a083015260068101546001600160401b0380821660c0850152600160401b8204811660e0850152600160801b82048116610100850152600160c01b909104166101208301819052600782015461014084015260089091015460ff1661016083015290919061265d908690615507565b6000878152609f602090815260408083206001600160a01b0388168452909152812054919250906126989087906001600160401b0316615507565b610140840151909150156126e35760405162461bcd60e51b8152602060048201526012602482015271155cd948185b1b1bdddb1a5cdd081b5a5b9d60721b6044820152606401610a7a565b611b75878460a260008b8152602001908152602001600020548989876001600160401b0316876001600160401b0316613508565b600081815260a060205260409020606090611320906137cb565b6000828152609e602052604090205460ff16156127815760405162461bcd60e51b815260206004820152600e60248201526d2ab83230ba32b990333937bd32b760911b6044820152606401610a7a565b612789612d9f565b6000838152609d6020908152604091829020548251638da5cb5b60e01b815292516001600160a01b039485169490911692638da5cb5b9260048083019391928290030181865afa1580156127e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128059190615199565b6001600160a01b03161461282b5760405162461bcd60e51b8152600401610a7a906151b6565b6000828152609e6020526040902081906128458282615668565b905050817f1f1a2195fcebf6da692499cf6af5ea967e7b082d945d48a9880c2c77273a5c198260405161287891906156cf565b60405180910390a25050565b61288c613622565b6001600160a01b0381166128f15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a7a565b6113028161376c565b6000806129088686866137d6565b905061291a6060870160408801614e3e565b6001600160a01b0316836001600160a01b03161461294a5760405162461bcd60e51b8152600401610a7a90615609565b6129538161375f565b801561297f5750610160860135600090815260a06020526040902061297d906101408801356134f0565b155b801561299057508561012001354211155b80156129e3575060c086013515806129e35750610160860135600090815260a1602052604090205460c08701803591906129cd9060a08a0161513b565b6001600160401b03166129e09190615635565b11155b8015611deb575060e08601351580611deb5750610160860135600090815260a1602090815260408083206001600160a01b038716845260010190915290205460e087013590611dd560c0890160a08a0161513b565b612a40613622565b6001600160a01b038116612a965760405162461bcd60e51b815260206004820152601a60248201527f43616e6e6f742073657420746f206e756c6c20616464726573730000000000006044820152606401610a7a565b612aa160a48261382e565b612add5760405162461bcd60e51b815260206004820152600d60248201526c105b1c9958591e481859191959609a1b6044820152606401610a7a565b6040516001906001600160a01b038316907f88d9d369733d630a0dbd71ed25dcafecbae7bc29d54a925afc1d003acf2af38590600090a350565b600054610100900460ff1615808015612b375750600054600160ff909116105b80612b515750303b158015612b51575060005460ff166001145b612bb45760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a7a565b6000805460ff191660011790558015612bd7576000805461ff0019166101001790555b609c80546001600160a01b0319166001600160a01b038716179055604080518082018252600b81526a26b4b73a26b0b730b3b2b960a91b602080830191909152825180840190935260058352640312e302e360dc1b90830152612c3991613843565b612c42836138c4565b612c4a61390d565b612c538461376c565b612c5e60a48361382e565b508015610973576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050565b6000612cb5612d9f565b9050612cc38484848461393c565b6000612cd26020860186614e3e565b6001600160a01b0316148015612cec575060008460800135115b15612d3c5760006080850135612d0860c0870160a0880161513b565b6001600160401b0316612d1b9190615552565b90506108d781612d316080880160608901614e3e565b876101600135613b35565b6080840135156109755760006080850135612d5d60c0870160a0880161513b565b6001600160401b0316612d709190615552565b905061097381612d866080880160608901614e3e565b84612d9460208a018a614e3e565b896101600135613c8e565b6000612228613e1f565b600082612db68584613e47565b1490505b9392505050565b612dce8686868585613e94565b836001600160401b031660011415612e4357845160405163184a94d560e01b81526001600160a01b0385811660048301529091169063184a94d590602401600060405180830381600087803b158015612e2657600080fd5b505af1158015612e3a573d6000803e3d6000fd5b50505050611731565b8451604051630b7d2a8960e31b81526001600160a01b0385811660048301526001600160401b038716602483015290911690635be9544890604401600060405180830381600087803b158015612e9857600080fd5b505af1158015612eac573d6000803e3d6000fd5b50505050505050505050565b6000612ec58585856136b0565b9050612ed76060860160408701614e3e565b6001600160a01b0316826001600160a01b031614612f075760405162461bcd60e51b8152600401610a7a90615609565b6000612f1960a087016080880161513b565b610180870135600090815260a16020526040902054612f41916001600160401b031690615635565b90506000612f5560a088016080890161513b565b610180880135600090815260a1602090815260408083206001600160a01b0389168452600101909152902054612f94916001600160401b031690615635565b9050612f9f8361375f565b8015612fcb5750610180870135600090815260a060205260409020612fc9906101608901356134f0565b155b8015612fdc57508661014001354211155b8015612ff857508660e0013582111580612ff8575060e0870135155b80156130165750866101000135811115806130165750610100870135155b6130525760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420636c61696d60981b6044820152606401610a7a565b610180870135600090815260a0602052604090206130759061016089013561416b565b5061018090960135600090815260a1602090815260408083209384556001600160a01b03909516825260019092019091529190912093909355505050565b6040516370a0823160e01b81526001600160a01b038481166004830152600091908816906370a0823190602401602060405180830381865afa1580156130fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131219190615158565b90506001600160a01b038716630c53c51c8561313d8980615717565b60208b013560408c013561315760808e0160608f0161575d565b6040518763ffffffff1660e01b8152600401613178969594939291906157a3565b6000604051808303816000875af1158015613197573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526131bf9190810190615815565b506001600160a01b038716630c53c51c856131da8880615717565b60208a013560408b01356131f460808d0160608e0161575d565b6040518763ffffffff1660e01b8152600401613215969594939291906157a3565b6000604051808303816000875af1158015613234573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261325c9190810190615815565b50613267828261588b565b6040516370a0823160e01b81526001600160a01b0386811660048301528916906370a0823190602401602060405180830381865afa1580156132ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132d19190615158565b111561331f5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420616d6f756e74207472616e736163746564000000000000006044820152606401610a7a565b82846001600160a01b0316886001600160a01b03167fe415115991e960f57314b86d3f4e4db15b9ac36256043523adcb60f15c3ddefd8989876040516133679392919061592d565b60405180910390a450505050505050565b611302613622565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156133b8576133b383614177565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015613412575060408051601f3d908101601f1916820190925261340f91810190615158565b60015b6134755760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610a7a565b600080516020615b3583398151915281146134e45760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610a7a565b506133b3838383614213565b6000818152600183016020526040812054151561131d565b6135158787868585613e94565b836001600160401b0316600114156135a357855160405163b859c93560e01b8152600481018790526001600160a01b0385811660248301529091169063b859c935906044016020604051808303816000875af1158015613579573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061359d9190615158565b50613619565b8551604051631b30808d60e01b81526001600160a01b0390911690631b30808d906135d690889087908990600401615171565b6020604051808303816000875af11580156135f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125509190615158565b50505050505050565b61362a612d9f565b6001600160a01b03166136456038546001600160a01b031690565b6001600160a01b031614611fc25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a7a565b600061131d836001600160a01b038416614238565b600061375783838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061375192506136fa915088905061432b565b604080516101608a013560208201526101808a01358183015281518082038301815260609091019091525b604051602001613736929190615963565b604051602081830303815290604052805190602001206143f2565b90614439565b949350505050565b600061132060a483614455565b603880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60606000612dba83614477565b606061132082614477565b600061375783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613751925061382091508890506144d3565b6137258861016001356145dc565b600061131d836001600160a01b0384166145f1565b600054610100900460ff1661386a5760405162461bcd60e51b8152600401610a7a90615989565b815160208084019190912082519183019190912060038290556004819055466002557f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6138b8818484614640565b60015560055550505050565b600054610100900460ff166138eb5760405162461bcd60e51b8152600401610a7a90615989565b606a80546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166139345760405162461bcd60e51b8152600401610a7a90615989565b611fc2614689565b60006139498585856137d6565b905061395b6060860160408701614e3e565b6001600160a01b0316826001600160a01b03161461398b5760405162461bcd60e51b8152600401610a7a90615609565b600061399d60c0870160a0880161513b565b610160870135600090815260a160205260409020546139c5916001600160401b031690615635565b905060006139d960c0880160a0890161513b565b610160880135600090815260a1602090815260408083206001600160a01b0389168452600101909152902054613a18916001600160401b031690615635565b9050613a238361375f565b8015613a4f5750610160870135600090815260a060205260409020613a4d906101408901356134f0565b155b8015613a6057508661012001354211155b8015613a7c57508660c0013582111580613a7c575060c0870135155b8015613a9857508660e0013581111580613a98575060e0870135155b613ad45760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420636c61696d60981b6044820152606401610a7a565b610160870135600090815260a060205260409020613af79061014089013561416b565b5061016090960135600090815260a1602090815260408083209384556001600160a01b03909516825260019092019091529190912093909355505050565b348314613b755760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a5908185b5bdd5b9d60921b6044820152606401610a7a565b60006064613b8485605f615552565b613b8e91906159d4565b9050600080846001600160a01b03168360405160006040518083038185875af1925050503d8060008114613bde576040519150601f19603f3d011682016040523d82523d6000602084013e613be3565b606091505b509150915081613c3f5760405162461bcd60e51b815260206004820152602160248201527f4661696c656420746f2073656e6420457468657220746f20726563697069656e6044820152601d60fa1b6064820152608401610a7a565b6040805184815261251c602082015285916001600160a01b038816917f9363885e28e7ba67b096932f9f00dff44742731d6cb4fa26ccd4424e78e41e13910160405180910390a3505050505050565b60006064613c9d87605f615552565b613ca791906159d4565b6040516323b872dd60e01b81526001600160a01b038681166004830152878116602483015260448201839052919250908416906323b872dd906064016020604051808303816000875af1158015613d02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d2691906159f6565b50609c546001600160a01b03808516916323b872dd91879116613d49858b61588b565b6040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af1158015613d9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dc191906159f6565b50604080516001600160a01b0386811682526020820184905261251c828401529151849288811692908716917fc899cbcc4511003ff90131e8b89605738e9a7f4925273377ae479a673cf5038c9181900360600190a4505050505050565b606a546000906001600160a01b0316331415613e42575060131936013560601c90565b503390565b600081815b8451811015613e8c57613e7882868381518110613e6b57613e6b615a18565b60200260200101516146c0565b915080613e848161564d565b915050613e4c565b509392505050565b818460e001516001600160401b0316101580613ebb575060e08401516001600160401b0316155b613f075760405162461bcd60e51b815260206004820152601760248201527f3e206d6178436c61696d61626c65566961566563746f720000000000000000006044820152606401610a7a565b808461010001516001600160401b0316101580613f3057506101008401516001600160401b0316155b613f745760405162461bcd60e51b81526020600482015260156024820152741f1036b0bc21b630b4b6b0b13632a832b92ab9b2b960591b6044820152606401610a7a565b61016084015160ff1615613fba5760405162461bcd60e51b815260206004820152600d60248201526c159958dd1bdc881c185d5cd959609a1b6044820152606401610a7a565b428460600151111580613fcf57506060840151155b8015613feb5750836080015142111580613feb57506080840151155b61402b5760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964206d696e742074696d6560781b6044820152606401610a7a565b6000836001600160401b03161161407d5760405162461bcd60e51b81526020600482015260166024820152754861766520746f206d696e7420736f6d657468696e6760501b6044820152606401610a7a565b8360c001516001600160401b0316836001600160401b031611156140d55760405162461bcd60e51b815260206004820152600f60248201526e0a8dede40dac2dcf240e0cae440e8f608b1b6044820152606401610a7a565b60208401516001600160a01b03161580156140f4575060008460a00151115b156141285760008460a00151846001600160401b03166141149190615552565b90506116958186604001518860001b613b35565b60a0840151156109735760008460a00151846001600160401b031661414d9190615552565b9050611731818660400151614160612d9f565b60208901518a613c8e565b600061131d83836145f1565b6001600160a01b0381163b6141e45760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610a7a565b600080516020615b3583398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b61421c836146ef565b6000825111806142295750805b156133b357610975838361472f565b6000818152600183016020526040812054801561432157600061425c60018361588b565b85549091506000906142709060019061588b565b90508181146142d557600086600001828154811061429057614290615a18565b90600052602060002001549050808760000184815481106142b3576142b3615a18565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806142e6576142e6615a2e565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611320565b6000915050611320565b60607f541246c88c6b91b7db54bf00983fe8c2a8dcd22de280e494797362be997f8c8e61435b6020840184614e3e565b61436b6040850160208601614e3e565b61437b6060860160408701614e3e565b606086013561439060a088016080890161513b565b61439d60a0890189615532565b6143aa60c08a018a615532565b8960e001358a61010001358b61012001358c61014001356040516020016143dc9c9b9a99989796959493929190615a44565b6040516020818303038152906040529050919050565b60006143fc614754565b60405161190160f01b6020820152602281019190915260428101839052606201604051602081830303815290604052805190602001209050919050565b60008060006144488585614778565b91509150613e8c816147e8565b6001600160a01b0381166000908152600183016020526040812054151561131d565b6060816000018054806020026020016040519081016040528092919081815260200182805480156144c757602002820191906000526020600020905b8154815260200190600101908083116144b3575b50505050509050919050565b60607f75d70c323d802883252e6285d4bb7cc6fcb7faca7fe3ab1d9e9f260aaa4c34246145036020840184614e3e565b6145136040850160208601614e3e565b6145236060860160408701614e3e565b6145336080870160608801614e3e565b608087013561454860c0890160a08a0161513b565b6040805160208101989098526001600160a01b03968716908801529385166060870152918416608086015290921660a084015260c0808401929092526001600160401b031660e080840191909152908401356101008084019190915290840135610120808401919091529084013561014080840191909152908401356101608301528301356101808201526101a0016143dc565b6060816040516020016143dc91815260200190565b600081815260018301602052604081205461463857508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611320565b506000611320565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b600054610100900460ff166146b05760405162461bcd60e51b8152600401610a7a90615989565b611fc26146bb612d9f565b61376c565b60008183106146dc57600082815260208490526040902061131d565b600083815260208390526040902061131d565b6146f881614177565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061131d8383604051806060016040528060278152602001615b55602791396149a3565b6000600254461415614767575060015490565b612228600554600354600454614640565b6000808251604114156147af5760208301516040840151606085015160001a6147a387828585614a76565b945094505050506147e1565b8251604014156147d957602083015160408401516147ce868383614b63565b9350935050506147e1565b506000905060025b9250929050565b60008160048111156147fc576147fc615ad9565b14156148055750565b600181600481111561481957614819615ad9565b14156148675760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610a7a565b600281600481111561487b5761487b615ad9565b14156148c95760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610a7a565b60038160048111156148dd576148dd615ad9565b14156149365760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610a7a565b600481600481111561494a5761494a615ad9565b14156113025760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610a7a565b60606001600160a01b0384163b614a0b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610a7a565b600080856001600160a01b031685604051614a269190615aef565b600060405180830381855af49150503d8060008114614a61576040519150601f19603f3d011682016040523d82523d6000602084013e614a66565b606091505b5091509150611deb828286614b9c565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614aad5750600090506003614b5a565b8460ff16601b14158015614ac557508460ff16601c14155b15614ad65750600090506004614b5a565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614b2a573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614b5357600060019250925050614b5a565b9150600090505b94509492505050565b6000806001600160ff1b03831681614b8060ff86901c601b615635565b9050614b8e87828885614a76565b935093505050935093915050565b60608315614bab575081612dba565b825115614bbb5782518084602001fd5b8160405162461bcd60e51b8152600401610a7a9190615b01565b60006101808284031215614be857600080fd5b50919050565b60008083601f840112614c0057600080fd5b5081356001600160401b03811115614c1757600080fd5b6020830191508360208285010111156147e157600080fd5b6001600160a01b038116811461130257600080fd5b8035614c4f81614c2f565b919050565b6000806000806101c08587031215614c6b57600080fd5b614c758686614bd5565b93506101808501356001600160401b03811115614c9157600080fd5b614c9d87828801614bee565b9094509250506101a0850135614cb281614c2f565b939692955090935050565b6000806101a08385031215614cd157600080fd5b82359150614ce28460208501614bd5565b90509250929050565b600060208284031215614cfd57600080fd5b5035919050565b6001600160401b038116811461130257600080fd5b8035614c4f81614d04565b600080600080600060808688031215614d3c57600080fd5b853594506020860135614d4e81614d04565b93506040860135614d5e81614c2f565b925060608601356001600160401b0380821115614d7a57600080fd5b818801915088601f830112614d8e57600080fd5b813581811115614d9d57600080fd5b8960208260051b8501011115614db257600080fd5b9699959850939650602001949392505050565b60008060008060608587031215614ddb57600080fd5b84356001600160401b0380821115614df257600080fd5b908601906101a08289031215614e0757600080fd5b90945060208601359080821115614e1d57600080fd5b50614e2a87828801614bee565b9094509250506040850135614cb281614c2f565b600060208284031215614e5057600080fd5b8135612dba81614c2f565b60008060408385031215614e6e57600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715614ebb57614ebb614e7d565b604052919050565b60006001600160401b03821115614edc57614edc614e7d565b50601f01601f191660200190565b60008060408385031215614efd57600080fd5b8235614f0881614c2f565b915060208301356001600160401b03811115614f2357600080fd5b8301601f81018513614f3457600080fd5b8035614f47614f4282614ec3565b614e93565b818152866020838501011115614f5c57600080fd5b816020840160208301376000602083830101528093505050509250929050565b600080600060608486031215614f9157600080fd5b833592506020840135614fa381614d04565b91506040840135614fb381614c2f565b809150509250925092565b60008060408385031215614fd157600080fd5b823591506020830135614fe381614c2f565b809150509250929050565b600060608284031215614be857600080fd5b6000806000610200848603121561501657600080fd5b6150208585614bd5565b9250615030856101808601614fee565b91506101e084013590509250925092565b6020808252825182820181905260009190848201906040850190845b818110156150825783516001600160a01b03168352928401929184019160010161505d565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015615082578351835292840192918401916001016150aa565b600080608083850312156150d957600080fd5b82359150614ce28460208501614fee565b6000806000806080858703121561510057600080fd5b843561510b81614c2f565b9350602085013561511b81614c2f565b9250604085013561512b81614c2f565b91506060850135614cb281614c2f565b60006020828403121561514d57600080fd5b8135612dba81614d04565b60006020828403121561516a57600080fd5b5051919050565b9283526001600160a01b039190911660208301526001600160401b0316604082015260600190565b6000602082840312156151ab57600080fd5b8151612dba81614c2f565b6020808252601290820152712737ba1031b7b73a3930b1ba1037bbb732b960711b604082015260600190565b6000813561132081614c2f565b80546001600160a01b0319166001600160a01b0392909216919091179055565b6000813561132081614d04565b60ff8116811461130257600080fd5b600081356113208161521c565b61524a615244836151e2565b826151ef565b615262615259602084016151e2565b600183016151ef565b61527a615271604084016151e2565b600283016151ef565b606082013560038201556080820135600482015560a08201356005820155600681016152c96152ab60c0850161520f565b825467ffffffffffffffff19166001600160401b0391909116178255565b61530a6152d860e0850161520f565b82546fffffffffffffffff0000000000000000191660409190911b6fffffffffffffffff000000000000000016178255565b61534661531a610100850161520f565b82805467ffffffffffffffff60801b191660809290921b67ffffffffffffffff60801b16919091179055565b61537a615356610120850161520f565b8280546001600160c01b031660c09290921b6001600160c01b031916919091179055565b50610140820135600782015561188f615396610160840161522b565b6008830160ff821660ff198254161781555050565b8035614c4f8161521c565b61018081016153d5826153c885614c44565b6001600160a01b03169052565b6153e160208401614c44565b6001600160a01b031660208301526153fb60408401614c44565b6001600160a01b038116604084015250606083013560608301526080830135608083015260a083013560a083015261543560c08401614d19565b6001600160401b031660c083015261544f60e08401614d19565b6001600160401b031660e083015261010061546b848201614d19565b6001600160401b031690830152610120615486848201614d19565b6001600160401b03169083015261014083810135908301526101606154ac8185016153ab565b60ff16920191909152919050565b6020808252601b908201527f536d61727420636f6e747261637473206e6f7420616c6c6f7765640000000000604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60006001600160401b03808316818516808303821115615529576155296154f1565b01949350505050565b60008235607e1983360301811261554857600080fd5b9190910192915050565b600081600019048311821515161561556c5761556c6154f1565b500290565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b60208082526012908201527129b2b73232b9103737ba1031b630b4b6b2b960711b604082015260600190565b60008219821115615648576156486154f1565b500190565b6000600019821415615661576156616154f1565b5060010190565b81356156738161521c565b815460ff191660ff821617825550602082013561568f8161521c565b815461ff008260081b1691508161ff0019821617835560408401356156b38161521c565b62ff00008160101b168362ffff00198416171784555050505050565b6060810182356156de8161521c565b60ff16825260208301356156f18161521c565b60ff16602083015260408301356157078161521c565b60ff811660408401525092915050565b6000808335601e1984360301811261572e57600080fd5b8301803591506001600160401b0382111561574857600080fd5b6020019150368190038213156147e157600080fd5b60006020828403121561576f57600080fd5b8135612dba8161521c565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b038716815260a0602082018190526000906157c8908301878961577a565b604083019590955250606081019290925260ff166080909101529392505050565b60005b838110156158045781810151838201526020016157ec565b838111156109755750506000910152565b60006020828403121561582757600080fd5b81516001600160401b0381111561583d57600080fd5b8201601f8101841361584e57600080fd5b805161585c614f4282614ec3565b81815285602083850101111561587157600080fd5b6158828260208301602086016157e9565b95945050505050565b60008282101561589d5761589d6154f1565b500390565b60008135601e198336030181126158b857600080fd5b820180356001600160401b038111156158d057600080fd5b8036038413156158df57600080fd5b608085526158f460808601826020850161577a565b915050602083013560208501526040830135604085015260608301356159198161521c565b60ff81166060860152508091505092915050565b60608152600061594060608301866158a2565b828103602084015261595281866158a2565b915050826040830152949350505050565b600083516159758184602088016157e9565b8351908301906155298183602088016157e9565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6000826159f157634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215615a0857600080fd5b81518015158114612dba57600080fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b8c81526001600160a01b038c811660208301528b811660408301528a166060820152608081018990526001600160401b03881660a082015261018060c08201819052600090615a958382018a6158a2565b905082810360e0840152615aa981896158a2565b915050856101008301528461012083015283610140830152826101608301529d9c50505050505050505050505050565b634e487b7160e01b600052602160045260246000fd5b600082516155488184602087016157e9565b6020815260008251806020840152615b208160408501602087016157e9565b601f01601f1916919091016040019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a164736f6c634300080a000a
Deployed Bytecode
0x60806040526004361061020f5760003560e01c80636008d06811610118578063aa1b5b46116100a0578063dfcbaa571161006f578063dfcbaa5714610782578063f2fde38b146107a2578063f4a40345146107c2578063f73bc2da146107e2578063f8c8765e1461080257600080fd5b8063aa1b5b46146106ae578063ae709ae3146106c1578063b414ae2f146106ee578063c462507e1461071b57600080fd5b80638da5cb5b116100e75780638da5cb5b146105d85780639c5c0492146106005780639e2dc500146106225780639fc11e191461067b578063a30808ff1461069b57600080fd5b80636008d06814610465578063619b858914610485578063715018a6146105a3578063868befd8146105b857600080fd5b80634561cdb11161019b578063525a2e031161016a578063525a2e03146103a757806352d1902d146103ba57806353274246146103cf578063572b6c05146104165780635dcd547e1461044557600080fd5b80634561cdb11461033f57806346b060c31461035f5780634f1ef2861461037f578063513ea0901461039257600080fd5b80631eeb26d2116101e25780631eeb26d21461029c5780631f25b358146102bc5780633659cfe6146102dc5780633716e284146102fc57806341772bf01461032c57600080fd5b80630680475b146102145780630c56ce86146102295780630dbb18a1146102495780631c6c0ed514610289575b600080fd5b610227610222366004614c54565b610822565b005b34801561023557600080fd5b50610227610244366004614cbd565b61097b565b34801561025557600080fd5b50610276610264366004614ceb565b60a16020526000908152604090205481565b6040519081526020015b60405180910390f35b610227610297366004614d24565b610bf1565b3480156102a857600080fd5b506102276102b7366004614ceb565b610e79565b3480156102c857600080fd5b506102276102d7366004614dc5565b61101c565b3480156102e857600080fd5b506102276102f7366004614e3e565b611225565b34801561030857600080fd5b5061031c610317366004614e5b565b611305565b6040519015158152602001610280565b61022761033a366004614d24565b611326565b34801561034b57600080fd5b5061022761035a366004614dc5565b611553565b34801561036b57600080fd5b5061022761037a366004614e3e565b611739565b61022761038d366004614eea565b6117c2565b34801561039e57600080fd5b50610227611893565b6102276103b5366004614f7c565b6119cc565b3480156103c657600080fd5b50610276611be1565b3480156103db57600080fd5b506102766103ea366004614fbe565b600082815260a1602090815260408083206001600160a01b038516845260010190915290205492915050565b34801561042257600080fd5b5061031c610431366004614e3e565b606a546001600160a01b0391821691161490565b34801561045157600080fd5b5061031c610460366004614dc5565b611c94565b34801561047157600080fd5b50610227610480366004615000565b611df5565b34801561049157600080fd5b506105256104a0366004614ceb565b609d602052600090815260409020805460018201546002830154600384015460048501546005860154600687015460078801546008909801546001600160a01b039788169896881697909516959394929391926001600160401b0380831693600160401b8404821693600160801b8104831693600160c01b9091049092169160ff168c565b604080516001600160a01b039d8e1681529b8d1660208d015299909b16988a01989098526060890196909652608088019490945260a08701929092526001600160401b0390811660c087015290811660e08601529081166101008501521661012083015261014082015260ff90911661016082015261018001610280565b3480156105af57600080fd5b50610227611fb0565b3480156105c457600080fd5b506102276105d3366004614ceb565b611fc4565b3480156105e457600080fd5b506038546040516001600160a01b039091168152602001610280565b34801561060c57600080fd5b5061061561221c565b6040516102809190615041565b34801561062e57600080fd5b5061066361063d366004614fbe565b609f6020908152600092835260408084209091529082529020546001600160401b031681565b6040516001600160401b039091168152602001610280565b34801561068757600080fd5b50610227610696366004614ceb565b61222d565b6102276106a9366004614c54565b612420565b6102276106bc366004614f7c565b61255a565b3480156106cd57600080fd5b506106e16106dc366004614ceb565b612717565b604051610280919061508e565b3480156106fa57600080fd5b50610276610709366004614ceb565b60a26020526000908152604090205481565b34801561072757600080fd5b5061075e610736366004614ceb565b609e6020526000908152604090205460ff808216916101008104821691620100009091041683565b6040805160ff94851681529284166020840152921691810191909152606001610280565b34801561078e57600080fd5b5061022761079d3660046150c6565b612731565b3480156107ae57600080fd5b506102276107bd366004614e3e565b612884565b3480156107ce57600080fd5b5061031c6107dd366004614c54565b6128fa565b3480156107ee57600080fd5b506102276107fd366004614e3e565b612a38565b34801561080e57600080fd5b5061022761081d3660046150ea565b612b17565b61082d848484612cab565b61083d60c0850160a0860161513b565b6001600160401b0316600114156108dd5761085e6040850160208601614e3e565b60405163b859c93560e01b815261010086013560048201526001600160a01b038381166024830152919091169063b859c935906044016020604051808303816000875af11580156108b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d79190615158565b50610975565b6108ed6040850160208601614e3e565b6001600160a01b0316631b30808d6101008601358361091260c0890160a08a0161513b565b6040518463ffffffff1660e01b815260040161093093929190615171565b6020604051808303816000875af115801561094f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109739190615158565b505b50505050565b6000828152609d6020908152604080832081516101808101835281546001600160a01b0390811682526001830154811682860152600283015416818401526003820154606082015260048201546080820152600582015460a082015260068201546001600160401b0380821660c0840152600160401b8204811660e0840152600160801b82048116610100840152600160c01b90910416610120820152600782015461014082015260089091015460ff908116610160830152868552609e9093529220541615610a835760405162461bcd60e51b815260206004820152600e60248201526d2ab83230ba32b990333937bd32b760911b60448201526064015b60405180910390fd5b610a956101408301610120840161513b565b6001600160401b03168161012001516001600160401b031614610afa5760405162461bcd60e51b815260206004820152601760248201527f546f74616c20636c61696d656420646966666572656e740000000000000000006044820152606401610a7a565b610b02612d9f565b6001600160a01b031681600001516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b719190615199565b6001600160a01b031614610b975760405162461bcd60e51b8152600401610a7a906151b6565b6000838152609d602052604090208290610bb18282615238565b905050827fff5c4fac01cfe6733a03f74e6e27fad31408c685c89c37640e0b4705a2b485b283604051610be491906153b6565b60405180910390a2505050565b6000610bfb612d9f565b90506001600160a01b0381163214610c255760405162461bcd60e51b8152600401610a7a906154ba565b6000868152609d6020908152604080832081516101808101835281546001600160a01b03908116825260018301548116948201949094526002820154909316918301919091526003810154606083015260048101546080830152600581015460a083015260068101546001600160401b0380821660c0850152600160401b8204811660e0850152600160801b82048116610100850152600160c01b909104166101208301819052600782015461014084015260089091015460ff16610160830152909190610cf4908890615507565b6000898152609f602090815260408083206001600160a01b038816845290915281205491925090610d2f9089906001600160401b0316615507565b6040516bffffffffffffffffffffffff19606087901b166020820152909150600090603401604051602081830303815290604052805190602001209050610dae87878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050505061014086015183612da9565b610dea5760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b210383937b7b360991b6044820152606401610a7a565b610e0a8a858b8b876001600160401b0316876001600160401b0316612dc1565b506000988952609d60209081526040808b2060060180546001600160c01b0316600160c01b6001600160401b0396871602179055609f8252808b206001600160a01b03969096168b5294905292909720805467ffffffffffffffff191692909716919091179095555050505050565b6000818152609d602090815260409182902082516101808101845281546001600160a01b03908116825260018301548116938201939093526002820154909216928201929092526003820154606082015260048201546080820152600582015460a082015260068201546001600160401b0380821660c0840152600160401b8204811660e0840152600160801b82048116610100840152600160c01b90910416610120820152600782015461014082015260089091015460ff16610160820152610f41612d9f565b6001600160a01b031681600001516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb09190615199565b6001600160a01b031614610fd65760405162461bcd60e51b8152600401610a7a906151b6565b6000828152609d6020526040808220600801805460ff191690555183907fdb6fb1b5c66ce89d126ba29f8251b4726a01581a6f14626db9d3179c9b30625a908390a35050565b6000611026612d9f565b905061103485858584612eb8565b60006110436020870187614e3e565b6001600160a01b0316141561108e5760405162461bcd60e51b8152602060048201526011602482015270139bdd08115490cc8c081c185e5b595b9d607a1b6044820152606401610a7a565b6060850135156110f5576110f56110a86020870187614e3e565b6110b560a0880188615532565b6110c260c0890189615532565b846101808a01356110d960a08c0160808d0161513b565b6110f0906001600160401b031660608d0135615552565b6130b3565b61110560a086016080870161513b565b6001600160401b031660011415611188576111266040860160208701614e3e565b60405163184a94d560e01b81526001600160a01b038481166004830152919091169063184a94d590602401600060405180830381600087803b15801561116b57600080fd5b505af115801561117f573d6000803e3d6000fd5b50505050610973565b6111986040860160208701614e3e565b6001600160a01b0316635be95448836111b760a0890160808a0161513b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526001600160401b03166024820152604401600060405180830381600087803b15801561120657600080fd5b505af115801561121a573d6000803e3d6000fd5b505050505050505050565b306001600160a01b037f000000000000000000000000526fe4ed6f23f34a97015e41f469fd54f37036f516141561126e5760405162461bcd60e51b8152600401610a7a90615571565b7f000000000000000000000000526fe4ed6f23f34a97015e41f469fd54f37036f56001600160a01b03166112b7600080516020615b35833981519152546001600160a01b031690565b6001600160a01b0316146112dd5760405162461bcd60e51b8152600401610a7a906155bd565b6112e681613378565b6040805160008082526020820190925261130291839190613380565b50565b600082815260a06020526040812061131d90836134f0565b90505b92915050565b6000611330612d9f565b90506001600160a01b038116321461135a5760405162461bcd60e51b8152600401610a7a906154ba565b6000868152609d6020908152604080832081516101808101835281546001600160a01b03908116825260018301548116948201949094526002820154909316918301919091526003810154606083015260048101546080830152600581015460a083015260068101546001600160401b0380821660c0850152600160401b8204811660e0850152600160801b82048116610100850152600160c01b909104166101208301819052600782015461014084015260089091015460ff16610160830152909190611429908890615507565b6000898152609f602090815260408083206001600160a01b0388168452909152812054919250906114649089906001600160401b0316615507565b6040516bffffffffffffffffffffffff19606087901b1660208201529091506000906034016040516020818303038152906040528051906020012090506114e387878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050505061014086015183612da9565b61151f5760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b210383937b7b360991b6044820152606401610a7a565b610e0a8a8560a260008e8152602001908152602001600020548c8c886001600160401b0316886001600160401b0316613508565b600061155d612d9f565b905061156b85858584612eb8565b600061157a6020870187614e3e565b6001600160a01b031614156115d15760405162461bcd60e51b815260206004820152601760248201527f48617320746f206265204552433230207061796d656e740000000000000000006044820152606401610a7a565b6060850135156115eb576115eb6110a86020870187614e3e565b6115fb60a086016080870161513b565b6001600160401b03166001141561169b5761161c6040860160208701614e3e565b60405163b859c93560e01b815261012087013560048201526001600160a01b038481166024830152919091169063b859c935906044016020604051808303816000875af1158015611671573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116959190615158565b50610973565b6116ab6040860160208701614e3e565b6001600160a01b0316631b30808d610120870135846116d060a08a0160808b0161513b565b6040518463ffffffff1660e01b81526004016116ee93929190615171565b6020604051808303816000875af115801561170d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117319190615158565b505050505050565b611741613622565b61174c60a48261369b565b6117895760405162461bcd60e51b815260206004820152600e60248201526d139bdd0819195c1c9958d85d195960921b6044820152606401610a7a565b6040516000906001600160a01b038316907f88d9d369733d630a0dbd71ed25dcafecbae7bc29d54a925afc1d003acf2af385908390a350565b306001600160a01b037f000000000000000000000000526fe4ed6f23f34a97015e41f469fd54f37036f516141561180b5760405162461bcd60e51b8152600401610a7a90615571565b7f000000000000000000000000526fe4ed6f23f34a97015e41f469fd54f37036f56001600160a01b0316611854600080516020615b35833981519152546001600160a01b031690565b6001600160a01b03161461187a5760405162461bcd60e51b8152600401610a7a906155bd565b61188382613378565b61188f82826001613380565b5050565b609c546001600160a01b03166118a7612d9f565b6001600160a01b0316146118ec5760405162461bcd60e51b815260206004820152600c60248201526b4e6f7420706c6174666f726d60a01b6044820152606401610a7a565b609c54604051479160009182916001600160a01b03169084908381818185875af1925050503d806000811461193d576040519150601f19603f3d011682016040523d82523d6000602084013e611942565b606091505b5091509150816119945760405162461bcd60e51b815260206004820181905260248201527f4661696c656420746f2073656e6420457468657220746f20706c6174666f726d6044820152606401610a7a565b6040518381527fa941df830f6691e4ce38ea54fa7a7279d68f0a7ac9a3197e37a09b40323ec9029060200160405180910390a1505050565b60006119d6612d9f565b90506001600160a01b0381163214611a005760405162461bcd60e51b8152600401610a7a906154ba565b6000848152609d6020908152604080832081516101808101835281546001600160a01b03908116825260018301548116948201949094526002820154909316918301919091526003810154606083015260048101546080830152600581015460a083015260068101546001600160401b0380821660c0850152600160401b8204811660e0850152600160801b82048116610100850152600160c01b909104166101208301819052600782015461014084015260089091015460ff16610160830152909190611acf908690615507565b6000878152609f602090815260408083206001600160a01b038816845290915281205491925090611b0a9087906001600160401b0316615507565b61014084015190915015611b555760405162461bcd60e51b8152602060048201526012602482015271155cd948185b1b1bdddb1a5cdd081b5a5b9d60721b6044820152606401610a7a565b611b7587848888866001600160401b0316866001600160401b0316612dc1565b6000968752609d6020908152604080892060060180546001600160c01b0316600160c01b6001600160401b0396871602179055609f82528089206001600160a01b0396909616895294905292909520805467ffffffffffffffff19169290951691909117909355505050565b6000306001600160a01b037f000000000000000000000000526fe4ed6f23f34a97015e41f469fd54f37036f51614611c815760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610a7a565b50600080516020615b3583398151915290565b600080611ca28686866136b0565b9050611cb46060870160408801614e3e565b6001600160a01b0316836001600160a01b031614611ce45760405162461bcd60e51b8152600401610a7a90615609565b611ced8161375f565b8015611d195750610180860135600090815260a060205260409020611d17906101608801356134f0565b155b8015611d2a57508561014001354211155b8015611d7e575060e08601351580611d7e5750610180860135600090815260a1602052604090205460e087013590611d6860a0890160808a0161513b565b6001600160401b0316611d7b9190615635565b11155b8015611deb57506101008601351580611deb5750610180860135600090815260a1602090815260408083206001600160a01b038716845260010190915290205461010087013590611dd560a0890160808a0161513b565b6001600160401b0316611de89190615635565b11155b9695505050505050565b611dfd612d9f565b6001600160a01b0316611e136020850185614e3e565b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e749190615199565b6001600160a01b031614611e9a5760405162461bcd60e51b8152600401610a7a906151b6565b611eac6101408401610120850161513b565b6001600160401b031615611f025760405162461bcd60e51b815260206004820152601b60248201527f746f74616c436c61696d6564566961566563746f72206e6f74203000000000006044820152606401610a7a565b60a38054906000611f128361564d565b909155505060a3546000908152609d602052604090208390611f348282615238565b505060a3546000908152609e602052604090208290611f538282615668565b9050508060a2600060a3548152602001908152602001600020819055508060a3547f709b0a0bd2676c5cd18c4d5f0248c63bfa89a0df21132fce955c665495de279e85604051611fa391906153b6565b60405180910390a3505050565b611fb8613622565b611fc2600061376c565b565b6000818152609d6020908152604080832081516101808101835281546001600160a01b0390811682526001830154811682860152600283015416818401526003820154606082015260048201546080820152600582015460a082015260068201546001600160401b0380821660c0840152600160401b8204811660e0840152600160801b8204811661010080850191909152600160c01b90920416610120830152600783015461014083015260089092015460ff908116610160830152868652609e90945291909320549092900416156120d05760405162461bcd60e51b815260206004820152600d60248201526c2232b632ba3290333937bd32b760991b6044820152606401610a7a565b6120d8612d9f565b6001600160a01b031681600001516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612123573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121479190615199565b6001600160a01b03161461216d5760405162461bcd60e51b8152600401610a7a906151b6565b6000828152609d6020908152604080832080546001600160a01b031990811682556001820180548216905560028201805490911690556003810184905560048101849055600581018490556006810184905560078101849055600801805460ff19169055609e8252808320805462ffffff1916905560a354835260a29091528082208290555183917fc838617e2997901e8e4856126ebd46593aef10fb97d78f88b4635c9420f6731691a25050565b606061222860a46137be565b905090565b6000818152609d6020908152604080832081516101808101835281546001600160a01b0390811682526001830154811682860152600283015416818401526003820154606082015260048201546080820152600582015460a082015260068201546001600160401b0380821660c0840152600160401b8204811660e0840152600160801b82048116610100840152600160c01b90910416610120820152600782015461014082015260089091015460ff908116610160830152858552609e90935292205462010000900416156123355760405162461bcd60e51b815260206004820152600d60248201526c2830bab9b2b990333937bd32b760991b6044820152606401610a7a565b61233d612d9f565b6001600160a01b031681600001516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612388573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ac9190615199565b6001600160a01b0316146123d25760405162461bcd60e51b8152600401610a7a906151b6565b6000828152609d6020526040808220600801805460ff191660019081179091559051909184917fdb6fb1b5c66ce89d126ba29f8251b4726a01581a6f14626db9d3179c9b30625a9190a35050565b61242b848484612cab565b61243b60c0850160a0860161513b565b6001600160401b0316600114156124be5761245c6040850160208601614e3e565b60405163184a94d560e01b81526001600160a01b038381166004830152919091169063184a94d590602401600060405180830381600087803b1580156124a157600080fd5b505af11580156124b5573d6000803e3d6000fd5b50505050610975565b6124ce6040850160208601614e3e565b6001600160a01b0316635be95448826124ed60c0880160a0890161513b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526001600160401b03166024820152604401600060405180830381600087803b15801561253c57600080fd5b505af1158015612550573d6000803e3d6000fd5b5050505050505050565b6000612564612d9f565b90506001600160a01b038116321461258e5760405162461bcd60e51b8152600401610a7a906154ba565b6000848152609d6020908152604080832081516101808101835281546001600160a01b03908116825260018301548116948201949094526002820154909316918301919091526003810154606083015260048101546080830152600581015460a083015260068101546001600160401b0380821660c0850152600160401b8204811660e0850152600160801b82048116610100850152600160c01b909104166101208301819052600782015461014084015260089091015460ff1661016083015290919061265d908690615507565b6000878152609f602090815260408083206001600160a01b0388168452909152812054919250906126989087906001600160401b0316615507565b610140840151909150156126e35760405162461bcd60e51b8152602060048201526012602482015271155cd948185b1b1bdddb1a5cdd081b5a5b9d60721b6044820152606401610a7a565b611b75878460a260008b8152602001908152602001600020548989876001600160401b0316876001600160401b0316613508565b600081815260a060205260409020606090611320906137cb565b6000828152609e602052604090205460ff16156127815760405162461bcd60e51b815260206004820152600e60248201526d2ab83230ba32b990333937bd32b760911b6044820152606401610a7a565b612789612d9f565b6000838152609d6020908152604091829020548251638da5cb5b60e01b815292516001600160a01b039485169490911692638da5cb5b9260048083019391928290030181865afa1580156127e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128059190615199565b6001600160a01b03161461282b5760405162461bcd60e51b8152600401610a7a906151b6565b6000828152609e6020526040902081906128458282615668565b905050817f1f1a2195fcebf6da692499cf6af5ea967e7b082d945d48a9880c2c77273a5c198260405161287891906156cf565b60405180910390a25050565b61288c613622565b6001600160a01b0381166128f15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a7a565b6113028161376c565b6000806129088686866137d6565b905061291a6060870160408801614e3e565b6001600160a01b0316836001600160a01b03161461294a5760405162461bcd60e51b8152600401610a7a90615609565b6129538161375f565b801561297f5750610160860135600090815260a06020526040902061297d906101408801356134f0565b155b801561299057508561012001354211155b80156129e3575060c086013515806129e35750610160860135600090815260a1602052604090205460c08701803591906129cd9060a08a0161513b565b6001600160401b03166129e09190615635565b11155b8015611deb575060e08601351580611deb5750610160860135600090815260a1602090815260408083206001600160a01b038716845260010190915290205460e087013590611dd560c0890160a08a0161513b565b612a40613622565b6001600160a01b038116612a965760405162461bcd60e51b815260206004820152601a60248201527f43616e6e6f742073657420746f206e756c6c20616464726573730000000000006044820152606401610a7a565b612aa160a48261382e565b612add5760405162461bcd60e51b815260206004820152600d60248201526c105b1c9958591e481859191959609a1b6044820152606401610a7a565b6040516001906001600160a01b038316907f88d9d369733d630a0dbd71ed25dcafecbae7bc29d54a925afc1d003acf2af38590600090a350565b600054610100900460ff1615808015612b375750600054600160ff909116105b80612b515750303b158015612b51575060005460ff166001145b612bb45760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a7a565b6000805460ff191660011790558015612bd7576000805461ff0019166101001790555b609c80546001600160a01b0319166001600160a01b038716179055604080518082018252600b81526a26b4b73a26b0b730b3b2b960a91b602080830191909152825180840190935260058352640312e302e360dc1b90830152612c3991613843565b612c42836138c4565b612c4a61390d565b612c538461376c565b612c5e60a48361382e565b508015610973576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050565b6000612cb5612d9f565b9050612cc38484848461393c565b6000612cd26020860186614e3e565b6001600160a01b0316148015612cec575060008460800135115b15612d3c5760006080850135612d0860c0870160a0880161513b565b6001600160401b0316612d1b9190615552565b90506108d781612d316080880160608901614e3e565b876101600135613b35565b6080840135156109755760006080850135612d5d60c0870160a0880161513b565b6001600160401b0316612d709190615552565b905061097381612d866080880160608901614e3e565b84612d9460208a018a614e3e565b896101600135613c8e565b6000612228613e1f565b600082612db68584613e47565b1490505b9392505050565b612dce8686868585613e94565b836001600160401b031660011415612e4357845160405163184a94d560e01b81526001600160a01b0385811660048301529091169063184a94d590602401600060405180830381600087803b158015612e2657600080fd5b505af1158015612e3a573d6000803e3d6000fd5b50505050611731565b8451604051630b7d2a8960e31b81526001600160a01b0385811660048301526001600160401b038716602483015290911690635be9544890604401600060405180830381600087803b158015612e9857600080fd5b505af1158015612eac573d6000803e3d6000fd5b50505050505050505050565b6000612ec58585856136b0565b9050612ed76060860160408701614e3e565b6001600160a01b0316826001600160a01b031614612f075760405162461bcd60e51b8152600401610a7a90615609565b6000612f1960a087016080880161513b565b610180870135600090815260a16020526040902054612f41916001600160401b031690615635565b90506000612f5560a088016080890161513b565b610180880135600090815260a1602090815260408083206001600160a01b0389168452600101909152902054612f94916001600160401b031690615635565b9050612f9f8361375f565b8015612fcb5750610180870135600090815260a060205260409020612fc9906101608901356134f0565b155b8015612fdc57508661014001354211155b8015612ff857508660e0013582111580612ff8575060e0870135155b80156130165750866101000135811115806130165750610100870135155b6130525760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420636c61696d60981b6044820152606401610a7a565b610180870135600090815260a0602052604090206130759061016089013561416b565b5061018090960135600090815260a1602090815260408083209384556001600160a01b03909516825260019092019091529190912093909355505050565b6040516370a0823160e01b81526001600160a01b038481166004830152600091908816906370a0823190602401602060405180830381865afa1580156130fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131219190615158565b90506001600160a01b038716630c53c51c8561313d8980615717565b60208b013560408c013561315760808e0160608f0161575d565b6040518763ffffffff1660e01b8152600401613178969594939291906157a3565b6000604051808303816000875af1158015613197573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526131bf9190810190615815565b506001600160a01b038716630c53c51c856131da8880615717565b60208a013560408b01356131f460808d0160608e0161575d565b6040518763ffffffff1660e01b8152600401613215969594939291906157a3565b6000604051808303816000875af1158015613234573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261325c9190810190615815565b50613267828261588b565b6040516370a0823160e01b81526001600160a01b0386811660048301528916906370a0823190602401602060405180830381865afa1580156132ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132d19190615158565b111561331f5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420616d6f756e74207472616e736163746564000000000000006044820152606401610a7a565b82846001600160a01b0316886001600160a01b03167fe415115991e960f57314b86d3f4e4db15b9ac36256043523adcb60f15c3ddefd8989876040516133679392919061592d565b60405180910390a450505050505050565b611302613622565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156133b8576133b383614177565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015613412575060408051601f3d908101601f1916820190925261340f91810190615158565b60015b6134755760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610a7a565b600080516020615b3583398151915281146134e45760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610a7a565b506133b3838383614213565b6000818152600183016020526040812054151561131d565b6135158787868585613e94565b836001600160401b0316600114156135a357855160405163b859c93560e01b8152600481018790526001600160a01b0385811660248301529091169063b859c935906044016020604051808303816000875af1158015613579573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061359d9190615158565b50613619565b8551604051631b30808d60e01b81526001600160a01b0390911690631b30808d906135d690889087908990600401615171565b6020604051808303816000875af11580156135f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125509190615158565b50505050505050565b61362a612d9f565b6001600160a01b03166136456038546001600160a01b031690565b6001600160a01b031614611fc25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a7a565b600061131d836001600160a01b038416614238565b600061375783838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061375192506136fa915088905061432b565b604080516101608a013560208201526101808a01358183015281518082038301815260609091019091525b604051602001613736929190615963565b604051602081830303815290604052805190602001206143f2565b90614439565b949350505050565b600061132060a483614455565b603880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60606000612dba83614477565b606061132082614477565b600061375783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613751925061382091508890506144d3565b6137258861016001356145dc565b600061131d836001600160a01b0384166145f1565b600054610100900460ff1661386a5760405162461bcd60e51b8152600401610a7a90615989565b815160208084019190912082519183019190912060038290556004819055466002557f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6138b8818484614640565b60015560055550505050565b600054610100900460ff166138eb5760405162461bcd60e51b8152600401610a7a90615989565b606a80546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166139345760405162461bcd60e51b8152600401610a7a90615989565b611fc2614689565b60006139498585856137d6565b905061395b6060860160408701614e3e565b6001600160a01b0316826001600160a01b03161461398b5760405162461bcd60e51b8152600401610a7a90615609565b600061399d60c0870160a0880161513b565b610160870135600090815260a160205260409020546139c5916001600160401b031690615635565b905060006139d960c0880160a0890161513b565b610160880135600090815260a1602090815260408083206001600160a01b0389168452600101909152902054613a18916001600160401b031690615635565b9050613a238361375f565b8015613a4f5750610160870135600090815260a060205260409020613a4d906101408901356134f0565b155b8015613a6057508661012001354211155b8015613a7c57508660c0013582111580613a7c575060c0870135155b8015613a9857508660e0013581111580613a98575060e0870135155b613ad45760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420636c61696d60981b6044820152606401610a7a565b610160870135600090815260a060205260409020613af79061014089013561416b565b5061016090960135600090815260a1602090815260408083209384556001600160a01b03909516825260019092019091529190912093909355505050565b348314613b755760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a5908185b5bdd5b9d60921b6044820152606401610a7a565b60006064613b8485605f615552565b613b8e91906159d4565b9050600080846001600160a01b03168360405160006040518083038185875af1925050503d8060008114613bde576040519150601f19603f3d011682016040523d82523d6000602084013e613be3565b606091505b509150915081613c3f5760405162461bcd60e51b815260206004820152602160248201527f4661696c656420746f2073656e6420457468657220746f20726563697069656e6044820152601d60fa1b6064820152608401610a7a565b6040805184815261251c602082015285916001600160a01b038816917f9363885e28e7ba67b096932f9f00dff44742731d6cb4fa26ccd4424e78e41e13910160405180910390a3505050505050565b60006064613c9d87605f615552565b613ca791906159d4565b6040516323b872dd60e01b81526001600160a01b038681166004830152878116602483015260448201839052919250908416906323b872dd906064016020604051808303816000875af1158015613d02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d2691906159f6565b50609c546001600160a01b03808516916323b872dd91879116613d49858b61588b565b6040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af1158015613d9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dc191906159f6565b50604080516001600160a01b0386811682526020820184905261251c828401529151849288811692908716917fc899cbcc4511003ff90131e8b89605738e9a7f4925273377ae479a673cf5038c9181900360600190a4505050505050565b606a546000906001600160a01b0316331415613e42575060131936013560601c90565b503390565b600081815b8451811015613e8c57613e7882868381518110613e6b57613e6b615a18565b60200260200101516146c0565b915080613e848161564d565b915050613e4c565b509392505050565b818460e001516001600160401b0316101580613ebb575060e08401516001600160401b0316155b613f075760405162461bcd60e51b815260206004820152601760248201527f3e206d6178436c61696d61626c65566961566563746f720000000000000000006044820152606401610a7a565b808461010001516001600160401b0316101580613f3057506101008401516001600160401b0316155b613f745760405162461bcd60e51b81526020600482015260156024820152741f1036b0bc21b630b4b6b0b13632a832b92ab9b2b960591b6044820152606401610a7a565b61016084015160ff1615613fba5760405162461bcd60e51b815260206004820152600d60248201526c159958dd1bdc881c185d5cd959609a1b6044820152606401610a7a565b428460600151111580613fcf57506060840151155b8015613feb5750836080015142111580613feb57506080840151155b61402b5760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964206d696e742074696d6560781b6044820152606401610a7a565b6000836001600160401b03161161407d5760405162461bcd60e51b81526020600482015260166024820152754861766520746f206d696e7420736f6d657468696e6760501b6044820152606401610a7a565b8360c001516001600160401b0316836001600160401b031611156140d55760405162461bcd60e51b815260206004820152600f60248201526e0a8dede40dac2dcf240e0cae440e8f608b1b6044820152606401610a7a565b60208401516001600160a01b03161580156140f4575060008460a00151115b156141285760008460a00151846001600160401b03166141149190615552565b90506116958186604001518860001b613b35565b60a0840151156109735760008460a00151846001600160401b031661414d9190615552565b9050611731818660400151614160612d9f565b60208901518a613c8e565b600061131d83836145f1565b6001600160a01b0381163b6141e45760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610a7a565b600080516020615b3583398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b61421c836146ef565b6000825111806142295750805b156133b357610975838361472f565b6000818152600183016020526040812054801561432157600061425c60018361588b565b85549091506000906142709060019061588b565b90508181146142d557600086600001828154811061429057614290615a18565b90600052602060002001549050808760000184815481106142b3576142b3615a18565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806142e6576142e6615a2e565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611320565b6000915050611320565b60607f541246c88c6b91b7db54bf00983fe8c2a8dcd22de280e494797362be997f8c8e61435b6020840184614e3e565b61436b6040850160208601614e3e565b61437b6060860160408701614e3e565b606086013561439060a088016080890161513b565b61439d60a0890189615532565b6143aa60c08a018a615532565b8960e001358a61010001358b61012001358c61014001356040516020016143dc9c9b9a99989796959493929190615a44565b6040516020818303038152906040529050919050565b60006143fc614754565b60405161190160f01b6020820152602281019190915260428101839052606201604051602081830303815290604052805190602001209050919050565b60008060006144488585614778565b91509150613e8c816147e8565b6001600160a01b0381166000908152600183016020526040812054151561131d565b6060816000018054806020026020016040519081016040528092919081815260200182805480156144c757602002820191906000526020600020905b8154815260200190600101908083116144b3575b50505050509050919050565b60607f75d70c323d802883252e6285d4bb7cc6fcb7faca7fe3ab1d9e9f260aaa4c34246145036020840184614e3e565b6145136040850160208601614e3e565b6145236060860160408701614e3e565b6145336080870160608801614e3e565b608087013561454860c0890160a08a0161513b565b6040805160208101989098526001600160a01b03968716908801529385166060870152918416608086015290921660a084015260c0808401929092526001600160401b031660e080840191909152908401356101008084019190915290840135610120808401919091529084013561014080840191909152908401356101608301528301356101808201526101a0016143dc565b6060816040516020016143dc91815260200190565b600081815260018301602052604081205461463857508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611320565b506000611320565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b600054610100900460ff166146b05760405162461bcd60e51b8152600401610a7a90615989565b611fc26146bb612d9f565b61376c565b60008183106146dc57600082815260208490526040902061131d565b600083815260208390526040902061131d565b6146f881614177565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061131d8383604051806060016040528060278152602001615b55602791396149a3565b6000600254461415614767575060015490565b612228600554600354600454614640565b6000808251604114156147af5760208301516040840151606085015160001a6147a387828585614a76565b945094505050506147e1565b8251604014156147d957602083015160408401516147ce868383614b63565b9350935050506147e1565b506000905060025b9250929050565b60008160048111156147fc576147fc615ad9565b14156148055750565b600181600481111561481957614819615ad9565b14156148675760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610a7a565b600281600481111561487b5761487b615ad9565b14156148c95760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610a7a565b60038160048111156148dd576148dd615ad9565b14156149365760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610a7a565b600481600481111561494a5761494a615ad9565b14156113025760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610a7a565b60606001600160a01b0384163b614a0b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610a7a565b600080856001600160a01b031685604051614a269190615aef565b600060405180830381855af49150503d8060008114614a61576040519150601f19603f3d011682016040523d82523d6000602084013e614a66565b606091505b5091509150611deb828286614b9c565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614aad5750600090506003614b5a565b8460ff16601b14158015614ac557508460ff16601c14155b15614ad65750600090506004614b5a565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614b2a573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614b5357600060019250925050614b5a565b9150600090505b94509492505050565b6000806001600160ff1b03831681614b8060ff86901c601b615635565b9050614b8e87828885614a76565b935093505050935093915050565b60608315614bab575081612dba565b825115614bbb5782518084602001fd5b8160405162461bcd60e51b8152600401610a7a9190615b01565b60006101808284031215614be857600080fd5b50919050565b60008083601f840112614c0057600080fd5b5081356001600160401b03811115614c1757600080fd5b6020830191508360208285010111156147e157600080fd5b6001600160a01b038116811461130257600080fd5b8035614c4f81614c2f565b919050565b6000806000806101c08587031215614c6b57600080fd5b614c758686614bd5565b93506101808501356001600160401b03811115614c9157600080fd5b614c9d87828801614bee565b9094509250506101a0850135614cb281614c2f565b939692955090935050565b6000806101a08385031215614cd157600080fd5b82359150614ce28460208501614bd5565b90509250929050565b600060208284031215614cfd57600080fd5b5035919050565b6001600160401b038116811461130257600080fd5b8035614c4f81614d04565b600080600080600060808688031215614d3c57600080fd5b853594506020860135614d4e81614d04565b93506040860135614d5e81614c2f565b925060608601356001600160401b0380821115614d7a57600080fd5b818801915088601f830112614d8e57600080fd5b813581811115614d9d57600080fd5b8960208260051b8501011115614db257600080fd5b9699959850939650602001949392505050565b60008060008060608587031215614ddb57600080fd5b84356001600160401b0380821115614df257600080fd5b908601906101a08289031215614e0757600080fd5b90945060208601359080821115614e1d57600080fd5b50614e2a87828801614bee565b9094509250506040850135614cb281614c2f565b600060208284031215614e5057600080fd5b8135612dba81614c2f565b60008060408385031215614e6e57600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715614ebb57614ebb614e7d565b604052919050565b60006001600160401b03821115614edc57614edc614e7d565b50601f01601f191660200190565b60008060408385031215614efd57600080fd5b8235614f0881614c2f565b915060208301356001600160401b03811115614f2357600080fd5b8301601f81018513614f3457600080fd5b8035614f47614f4282614ec3565b614e93565b818152866020838501011115614f5c57600080fd5b816020840160208301376000602083830101528093505050509250929050565b600080600060608486031215614f9157600080fd5b833592506020840135614fa381614d04565b91506040840135614fb381614c2f565b809150509250925092565b60008060408385031215614fd157600080fd5b823591506020830135614fe381614c2f565b809150509250929050565b600060608284031215614be857600080fd5b6000806000610200848603121561501657600080fd5b6150208585614bd5565b9250615030856101808601614fee565b91506101e084013590509250925092565b6020808252825182820181905260009190848201906040850190845b818110156150825783516001600160a01b03168352928401929184019160010161505d565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015615082578351835292840192918401916001016150aa565b600080608083850312156150d957600080fd5b82359150614ce28460208501614fee565b6000806000806080858703121561510057600080fd5b843561510b81614c2f565b9350602085013561511b81614c2f565b9250604085013561512b81614c2f565b91506060850135614cb281614c2f565b60006020828403121561514d57600080fd5b8135612dba81614d04565b60006020828403121561516a57600080fd5b5051919050565b9283526001600160a01b039190911660208301526001600160401b0316604082015260600190565b6000602082840312156151ab57600080fd5b8151612dba81614c2f565b6020808252601290820152712737ba1031b7b73a3930b1ba1037bbb732b960711b604082015260600190565b6000813561132081614c2f565b80546001600160a01b0319166001600160a01b0392909216919091179055565b6000813561132081614d04565b60ff8116811461130257600080fd5b600081356113208161521c565b61524a615244836151e2565b826151ef565b615262615259602084016151e2565b600183016151ef565b61527a615271604084016151e2565b600283016151ef565b606082013560038201556080820135600482015560a08201356005820155600681016152c96152ab60c0850161520f565b825467ffffffffffffffff19166001600160401b0391909116178255565b61530a6152d860e0850161520f565b82546fffffffffffffffff0000000000000000191660409190911b6fffffffffffffffff000000000000000016178255565b61534661531a610100850161520f565b82805467ffffffffffffffff60801b191660809290921b67ffffffffffffffff60801b16919091179055565b61537a615356610120850161520f565b8280546001600160c01b031660c09290921b6001600160c01b031916919091179055565b50610140820135600782015561188f615396610160840161522b565b6008830160ff821660ff198254161781555050565b8035614c4f8161521c565b61018081016153d5826153c885614c44565b6001600160a01b03169052565b6153e160208401614c44565b6001600160a01b031660208301526153fb60408401614c44565b6001600160a01b038116604084015250606083013560608301526080830135608083015260a083013560a083015261543560c08401614d19565b6001600160401b031660c083015261544f60e08401614d19565b6001600160401b031660e083015261010061546b848201614d19565b6001600160401b031690830152610120615486848201614d19565b6001600160401b03169083015261014083810135908301526101606154ac8185016153ab565b60ff16920191909152919050565b6020808252601b908201527f536d61727420636f6e747261637473206e6f7420616c6c6f7765640000000000604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60006001600160401b03808316818516808303821115615529576155296154f1565b01949350505050565b60008235607e1983360301811261554857600080fd5b9190910192915050565b600081600019048311821515161561556c5761556c6154f1565b500290565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b60208082526012908201527129b2b73232b9103737ba1031b630b4b6b2b960711b604082015260600190565b60008219821115615648576156486154f1565b500190565b6000600019821415615661576156616154f1565b5060010190565b81356156738161521c565b815460ff191660ff821617825550602082013561568f8161521c565b815461ff008260081b1691508161ff0019821617835560408401356156b38161521c565b62ff00008160101b168362ffff00198416171784555050505050565b6060810182356156de8161521c565b60ff16825260208301356156f18161521c565b60ff16602083015260408301356157078161521c565b60ff811660408401525092915050565b6000808335601e1984360301811261572e57600080fd5b8301803591506001600160401b0382111561574857600080fd5b6020019150368190038213156147e157600080fd5b60006020828403121561576f57600080fd5b8135612dba8161521c565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b038716815260a0602082018190526000906157c8908301878961577a565b604083019590955250606081019290925260ff166080909101529392505050565b60005b838110156158045781810151838201526020016157ec565b838111156109755750506000910152565b60006020828403121561582757600080fd5b81516001600160401b0381111561583d57600080fd5b8201601f8101841361584e57600080fd5b805161585c614f4282614ec3565b81815285602083850101111561587157600080fd5b6158828260208301602086016157e9565b95945050505050565b60008282101561589d5761589d6154f1565b500390565b60008135601e198336030181126158b857600080fd5b820180356001600160401b038111156158d057600080fd5b8036038413156158df57600080fd5b608085526158f460808601826020850161577a565b915050602083013560208501526040830135604085015260608301356159198161521c565b60ff81166060860152508091505092915050565b60608152600061594060608301866158a2565b828103602084015261595281866158a2565b915050826040830152949350505050565b600083516159758184602088016157e9565b8351908301906155298183602088016157e9565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6000826159f157634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215615a0857600080fd5b81518015158114612dba57600080fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b8c81526001600160a01b038c811660208301528b811660408301528a166060820152608081018990526001600160401b03881660a082015261018060c08201819052600090615a958382018a6158a2565b905082810360e0840152615aa981896158a2565b915050856101008301528461012083015283610140830152826101608301529d9c50505050505050505050505050565b634e487b7160e01b600052602160045260246000fd5b600082516155488184602087016157e9565b6020815260008251806020840152615b208160408501602087016157e9565b601f01601f1916919091016040019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a164736f6c634300080a000a
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.