Overview
APE Balance
APE Value
$0.00More Info
Private Name Tags
ContractCreator
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 1 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 "../utils/ERC721/IERC721.sol"; import "./interfaces/INativeMetaTransaction.sol"; import "../utils/EIP712Upgradeable.sol"; import "../metatx/ERC2771ContextUpgradeable.sol"; import "./interfaces/IAbridgedMintVector.sol"; import "./interfaces/IMintFeeOracle.sol"; import "./mechanics/interfaces/IMechanicMintManager.sol"; import "./mechanics/interfaces/IMechanic.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"; import { GelatoRelayContext } from "@gelatonetwork/relay-context/contracts/GelatoRelayContext.sol"; /** * @title MintManager * @author highlight.xyz * @notice 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, IAbridgedMintVector, IMechanicMintManager, GelatoRelayContext { using ECDSA for bytes32; using EnumerableSet for EnumerableSet.Bytes32Set; using EnumerableSet for EnumerableSet.AddressSet; /** * @notice Throw when sender is unauthorized to complete action */ error Unauthorized(); /** * @notice Throw when the executor being added or removed is invalid */ error InvalidExecutorChanged(); /** * @notice Throw when the action being applied to the vector has been frozen */ error VectorUpdateActionFrozen(); /** * @notice Throw when the totalClaimedViaVector passed in is invalid */ error InvalidTotalClaimed(); /** * @notice Throw when an invalid allowlist proof is used, or a regular mint is attempted on an allowlist vector */ error AllowlistInvalid(); /** * @notice Throw when a native gas token payment is attempted on a payment packet mint */ error CurrencyTypeInvalid(); /** * @notice Throw when the mint fee sent is too low */ error MintFeeTooLow(); /** * @notice Throw when an internal transfer of ether fails */ error EtherSendFailed(); /** * @notice Throw when a transaction signer is not the claimer passed in via a claim */ error SenderNotClaimer(); /** * @notice Throw when a claim is invalid */ error InvalidClaim(); /** * @notice Throw when an invalid amount is sent for a payment (native gas token or erc20) */ error InvalidPaymentAmount(); /** * @notice Throw when an on-chain mint vector's config parameter isn't met */ error OnchainVectorMintGuardFailed(); /** * @notice Throw when a mint is tried on a vector of the * wrong collection type (edition -> series, series -> edition) */ error VectorWrongCollectionType(); /** * @notice Throw when msgSender is not directly an EOA */ error SenderNotDirectEOA(); /** * @notice Throw when a mint recipient on a gated claim is different from the claimer, * and tx sender is not the claimer */ error UnsafeMintRecipient(); /** * @notice Throw when a mint is paused. */ error MintPaused(); /** * @notice Throw when an entity is already registered with a given ID */ error AlreadyRegisteredWithId(); /** * @notice Throw when a mechanic is invalid */ error InvalidMechanic(); /** * @notice Throw when a mechanic is paused */ error MechanicPaused(); /** * @notice Throw when the sender is not an authorized gasless relayer */ error UnauthorizedGaslessRelayer(); /** * @notice 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; } /** * @notice 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; } /** * @notice 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; } /** * @notice 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; } /** * @notice Claim that is signed off-chain with EIP-712, and unwrapped to facilitate fulfillment of mint on a Series * @dev Max number claimable per transaction is enforced off-chain * @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 maxPerTxn Max number of tokens that can be minted in a 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 claimExpiryTimestamp Time when claim expires * @param claimNonce Unique identifier of claim * @param offchainVectorId Unique identifier of vector offchain */ struct SeriesClaim { address currency; address contractAddress; address claimer; address payable paymentRecipient; uint256 pricePerToken; uint64 maxPerTxn; uint64 maxClaimableViaVector; uint64 maxClaimablePerUser; uint64 claimExpiryTimestamp; bytes32 claimNonce; bytes32 offchainVectorId; } /** * @notice 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 */ /** * @notice 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)" ); /** * @notice 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 */ /** * @notice Platform receiving portion of payment */ address payable private _platform; /** * @notice System-wide mint vectors */ mapping(uint256 => Vector) public vectors; /** * @notice System-wide mint vectors' mutabilities */ mapping(uint256 => VectorMutability) public vectorMutabilities; /** * @notice System-wide vector ids to (user to user claims count) */ mapping(uint256 => mapping(address => uint64)) public userClaims; /** * @notice 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; /** * @notice Tracks running state of offchain vectors */ mapping(bytes32 => OffchainVectorClaimState) public offchainVectorsClaimState; /** * @notice Maps vector ids to edition ids */ mapping(uint256 => uint256) public vectorToEditionId; /** * @notice Current vector id index */ uint256 private _vectorSupply; /** * @notice Platform transaction executors */ EnumerableSet.AddressSet internal _platformExecutors; /** * @notice Platform mint fee */ uint256 private _platformMintFee; /** * @notice System-wide mint vectors */ mapping(uint256 => AbridgedVectorData) private _abridgedVectors; /** * @notice Extra data about an abridged mint vector * Bits Layout: * - [0] `paused` * - [1..127] `unused` (for now) * - [128..255] `flexible data` */ mapping(uint256 => uint256) private _abridgedVectorMetadata; /** @notice The bit position of `flexibleData` in packed abridged vector metadata. */ uint256 private constant _BITPOS_AV_FLEXIBLE_DATA = 128; /** @notice The bitmask of `paused` in packed abridged vector metadata. */ uint256 private constant _BITMASK_AV_PAUSED = 1; /** * @notice Global mechanic vector metadatas */ mapping(bytes32 => MechanicVectorMetadata) public mechanicVectorMetadata; /** * @notice Mint fee oracle */ address private _mintFeeOracle; /** * @notice Gasless mechanic address */ address private _gaslessMechanicAddress; /** * @notice 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); /** * @notice Emitted when vector for edition based colletction is created on-chain * @param vectorId ID of vector * @param editionId Edition id of vector * @param contractAddress Collection contract address */ event EditionVectorCreated(uint256 indexed vectorId, uint48 indexed editionId, address indexed contractAddress); /** * @notice Emitted when vector for series based collection is created on-chain * @param vectorId ID of vector * @param contractAddress Collection contract address */ event SeriesVectorCreated(uint256 indexed vectorId, address indexed contractAddress); /** * @notice Emitted when vector is updated on-chain * @param vectorId ID of vector */ event VectorUpdated(uint256 indexed vectorId); /** * @notice Emitted when vector is deleted on-chain * @param vectorId ID of vector to delete */ event VectorDeleted(uint256 indexed vectorId); /** * @notice Emitted when vector metadata is set * @param vectorId ID of vector * @param paused True if vector was paused, false otherwise * @param flexibleData Flexible data set in a vector's metadata */ event VectorMetadataSet(uint256 indexed vectorId, bool indexed paused, uint128 indexed flexibleData); /** * @notice 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 ); /** * @notice 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 ); /** * @notice Emitted on a mint where discrete token ids are minted * @param vectorId Vector that payment was for * @param contractAddress Address of contract being minted on * @param onChainVector Denotes whether mint vector is on-chain * @param tokenIds Array of token ids to mint */ event ChooseTokenMint( bytes32 indexed vectorId, address indexed contractAddress, bool indexed onChainVector, uint256[] tokenIds ); /** * @notice Emitted on a mint where a number of tokens are minted monotonically * @param vectorId Vector that payment was for * @param contractAddress Address of contract being minted on * @param onChainVector Denotes whether mint vector is on-chain * @param numMinted Number of tokens minted */ event NumTokenMint( bytes32 indexed vectorId, address indexed contractAddress, bool indexed onChainVector, uint256 numMinted ); /** * @notice Emitted on a mint where a number of tokens are minted monotonically by the owner * @param contractAddress Address of contract being minted on * @param isEditionBased Denotes whether collection is edition-based * @param editionId Edition ID, if applicable * @param numMinted Number of tokens minted */ event CreatorReservesNumMint( address indexed contractAddress, bool indexed isEditionBased, uint256 indexed editionId, uint256 numMinted ); /** * @notice Emitted on a mint where a number of tokens are minted monotonically by the owner * @param contractAddress Address of contract being minted on * @param tokenIds IDs of tokens minted */ event CreatorReservesChooseMint(address indexed contractAddress, uint256[] tokenIds); /** * @notice Emitted when a mechanic vector is registered * @param mechanicVectorId Global mechanic vector ID * @param mechanic Mechanic's address * @param contractAddress Address of collection the mechanic is minting on * @param editionId ID of edition, if applicable * @param isEditionBased If true, edition based */ event MechanicVectorRegistered( bytes32 indexed mechanicVectorId, address indexed mechanic, address indexed contractAddress, uint256 editionId, bool isEditionBased ); /** * @notice Emitted when a mechanic vector's pause state is toggled * @param mechanicVectorId Global mechanic vector ID * @param paused If true, mechanic was paused. If false, mechanic was unpaused */ event MechanicVectorPauseSet(bytes32 indexed mechanicVectorId, bool indexed paused); /** * @notice Emitted when the platform mint fee is updated * @param newPlatformMintFee New platform mint fee */ event PlatformMintFeeUpdated(uint256 indexed newPlatformMintFee); /** * @notice Emit when creator is paid out * @param currency Currency creator reward is in * @param rewardRecipient Creator reward recipient * @param amount Amount of payout */ event CreatorRewardPayout( bytes32 indexed vectorId, address indexed currency, address indexed rewardRecipient, uint256 amount ); /** * @notice Restricts calls to platform */ modifier onlyPlatform() { if (_msgSender() != _platform) { _revert(Unauthorized.selector); } _; } /** * @notice Initializes MintManager * @param platform Platform address * @param _owner MintManager owner * @param trustedForwarder Trusted meta-tx executor * @param initialExecutor Initial platform executor * @param initialPlatformMintFee Initial platform mint fee */ function initialize( address payable platform, address _owner, address trustedForwarder, address initialExecutor, uint256 initialPlatformMintFee ) external initializer { _platform = platform; __EIP721Upgradeable_initialize("MintManager", "1.0.0"); __ERC2771ContextUpgradeable__init__(trustedForwarder); __Ownable_init(); _transferOwnership(_owner); _platformExecutors.add(initialExecutor); _platformMintFee = initialPlatformMintFee; } /** * @notice Add or deprecate platform executor * @param _executor Platform executor to add or deprecate */ function addOrDeprecatePlatformExecutor(address _executor) external onlyOwner { if (_executor == address(0)) { _revert(InvalidExecutorChanged.selector); } if (_platformExecutors.contains(_executor)) { // remove exeuctor _platformExecutors.remove(_executor); } else { // add executor _platformExecutors.add(_executor); } } /** * @notice See {IAbridgedMintVector-createAbridgedVector} */ function createAbridgedVector(AbridgedVectorData calldata _vector) external { address msgSender = _msgSender(); if ( address(_vector.contractAddress) == msgSender || Ownable(address(_vector.contractAddress)).owner() == msgSender ) { if (_vector.totalClaimedViaVector > 0) { _revert(InvalidTotalClaimed.selector); } _vectorSupply++; _abridgedVectors[_vectorSupply] = _vector; if (_vector.editionBasedCollection) { emit EditionVectorCreated(_vectorSupply, _vector.editionId, address(_vector.contractAddress)); } else { emit SeriesVectorCreated(_vectorSupply, address(_vector.contractAddress)); } } else { _revert(Unauthorized.selector); } } /* solhint-disable code-complexity */ /** * @notice See {IAbridgedMintVector-updateAbridgedVector} */ function updateAbridgedVector( uint256 vectorId, AbridgedVector calldata _newVector, UpdateAbridgedVectorConfig calldata updateConfig, bool pause, uint128 flexibleData ) external { address contractAddress = address(_abridgedVectors[vectorId].contractAddress); address msgSender = _msgSender(); // check owner() first, more likely if (Ownable(contractAddress).owner() == msgSender || msgSender == contractAddress) { if (updateConfig.updateStartTimestamp > 0) { _abridgedVectors[vectorId].startTimestamp = _newVector.startTimestamp; } if (updateConfig.updateEndTimestamp > 0) { _abridgedVectors[vectorId].endTimestamp = _newVector.endTimestamp; } if (updateConfig.updatePaymentRecipient > 0) { _abridgedVectors[vectorId].paymentRecipient = uint160(_newVector.paymentRecipient); } if (updateConfig.updateMaxTotalClaimableViaVector > 0) { _abridgedVectors[vectorId].maxTotalClaimableViaVector = _newVector.maxTotalClaimableViaVector; } if (updateConfig.updateTokenLimitPerTx > 0) { _abridgedVectors[vectorId].tokenLimitPerTx = _newVector.tokenLimitPerTx; } if (updateConfig.updateMaxUserClaimableViaVector > 0) { _abridgedVectors[vectorId].maxUserClaimableViaVector = _newVector.maxUserClaimableViaVector; } if (updateConfig.updatePricePerToken > 0) { _abridgedVectors[vectorId].pricePerToken = _newVector.pricePerToken; } if (updateConfig.updateCurrency > 0) { _abridgedVectors[vectorId].currency = uint160(_newVector.currency); } if (updateConfig.updateRequireDirectEOA > 0) { _abridgedVectors[vectorId].requireDirectEOA = _newVector.requireDirectEOA; } if (updateConfig.updateMetadata > 0) { _abridgedVectorMetadata[vectorId] = _composeAbridgedVectorMetadata(pause, flexibleData); emit VectorMetadataSet(vectorId, pause, flexibleData); } emit VectorUpdated(vectorId); } else { _revert(Unauthorized.selector); } } /* solhint-enable code-complexity */ /** * @notice See {IAbridgedMintVector-setAbridgedVectorMetadata} */ function setAbridgedVectorMetadata(uint256 vectorId, bool pause, uint128 flexibleData) external { address contractAddress = address(_abridgedVectors[vectorId].contractAddress); address msgSender = _msgSender(); // check .owner() first, more likely if (Ownable(contractAddress).owner() == msgSender || msgSender == contractAddress) { _abridgedVectorMetadata[vectorId] = _composeAbridgedVectorMetadata(pause, flexibleData); emit VectorMetadataSet(vectorId, pause, flexibleData); } else { _revert(Unauthorized.selector); } } /** * @notice See {IMechanicMintManager-registerMechanicVector} */ function registerMechanicVector( MechanicVectorMetadata memory _mechanicVectorMetadata, uint96 seed, bytes calldata vectorData ) external { address msgSender = _msgSender(); bytes32 mechanicVectorId = _produceMechanicVectorId(_mechanicVectorMetadata, seed); if ( msgSender == _mechanicVectorMetadata.contractAddress || Ownable(_mechanicVectorMetadata.contractAddress).owner() == msgSender ) { if (mechanicVectorMetadata[mechanicVectorId].contractAddress != address(0)) { _revert(AlreadyRegisteredWithId.selector); } if ( _mechanicVectorMetadata.contractAddress == address(0) || _mechanicVectorMetadata.mechanic == address(0) || (_mechanicVectorMetadata.isEditionBased && _mechanicVectorMetadata.isChoose) || mechanicVectorId == bytes32(0) ) { _revert(InvalidMechanic.selector); } _mechanicVectorMetadata.paused = false; mechanicVectorMetadata[mechanicVectorId] = _mechanicVectorMetadata; } else { _revert(Unauthorized.selector); } IMechanic(_mechanicVectorMetadata.mechanic).createVector(mechanicVectorId, vectorData); emit MechanicVectorRegistered( mechanicVectorId, _mechanicVectorMetadata.mechanic, _mechanicVectorMetadata.contractAddress, _mechanicVectorMetadata.editionId, _mechanicVectorMetadata.isEditionBased ); } /** * @notice See {IMechanicMintManager-setPauseOnMechanicMintVector} */ function setPauseOnMechanicMintVector(bytes32 mechanicVectorId, bool pause) external { address msgSender = _msgSender(); address contractAddress = mechanicVectorMetadata[mechanicVectorId].contractAddress; if (contractAddress == address(0)) { _revert(InvalidMechanic.selector); } if (Ownable(contractAddress).owner() == msgSender || msgSender == contractAddress) { mechanicVectorMetadata[mechanicVectorId].paused = pause; } else { _revert(Unauthorized.selector); } emit MechanicVectorPauseSet(mechanicVectorId, pause); } /* solhint-disable code-complexity */ /** * @notice See {IMechanicMintManager-mechanicMintNum} */ function mechanicMintNum( bytes32 mechanicVectorId, address recipient, uint32 numToMint, bytes memory data ) external payable { MechanicVectorMetadata memory _mechanicVectorMetadata = mechanicVectorMetadata[mechanicVectorId]; address msgSender = _msgSender(); if (_mechanicVectorMetadata.paused) { _revert(MechanicPaused.selector); } if (_mechanicVectorMetadata.isChoose) { _revert(InvalidMechanic.selector); } // constant gasless mechanic address if (_mechanicVectorMetadata.mechanic == _gaslessMechanicAddress) { if (!_isGelatoRelay(msgSender)) { _revert(UnauthorizedGaslessRelayer.selector); } IMechanic(_mechanicVectorMetadata.mechanic).processNumMint( mechanicVectorId, recipient, numToMint, msgSender, _mechanicVectorMetadata, abi.encode(_getFee(), _getFeeCollector(), data) ); } else { uint256 _platformFee = IMintFeeOracle(_mintFeeOracle).getMechanicMintFee( mechanicVectorId, numToMint, _mechanicVectorMetadata.mechanic, msgSender, _mechanicVectorMetadata.contractAddress ); if (msg.value < _platformFee) { _revert(MintFeeTooLow.selector); } IMechanic(_mechanicVectorMetadata.mechanic).processNumMint{ value: msg.value - _platformFee }( mechanicVectorId, recipient, numToMint, msgSender, _mechanicVectorMetadata, data ); } if (_mechanicVectorMetadata.isEditionBased) { if (numToMint == 1) { IERC721EditionMint(_mechanicVectorMetadata.contractAddress).mintOneToRecipient( _mechanicVectorMetadata.editionId, recipient ); } else { IERC721EditionMint(_mechanicVectorMetadata.contractAddress).mintAmountToRecipient( _mechanicVectorMetadata.editionId, recipient, uint256(numToMint) ); } } else { if (numToMint == 1) { IERC721GeneralMint(_mechanicVectorMetadata.contractAddress).mintOneToOneRecipient(recipient); } else { IERC721GeneralMint(_mechanicVectorMetadata.contractAddress).mintAmountToOneRecipient( recipient, uint256(numToMint) ); } } emit NumTokenMint(mechanicVectorId, _mechanicVectorMetadata.contractAddress, true, uint256(numToMint)); } /** * @notice See {IMechanicMintManager-mechanicMintChoose} */ function mechanicMintChoose( bytes32 mechanicVectorId, address recipient, uint256[] calldata tokenIds, bytes memory data ) external payable { MechanicVectorMetadata memory _mechanicVectorMetadata = mechanicVectorMetadata[mechanicVectorId]; address msgSender = _msgSender(); if (_mechanicVectorMetadata.paused) { _revert(MechanicPaused.selector); } if (!_mechanicVectorMetadata.isChoose) { _revert(InvalidMechanic.selector); } uint32 numToMint = uint32(tokenIds.length); // constant gasless mechanic address if (_mechanicVectorMetadata.mechanic == _gaslessMechanicAddress) { if (!_isGelatoRelay(msgSender)) { _revert(UnauthorizedGaslessRelayer.selector); } IMechanic(_mechanicVectorMetadata.mechanic).processChooseMint( mechanicVectorId, recipient, tokenIds, msgSender, _mechanicVectorMetadata, abi.encode(_getFee(), _getFeeCollector(), data) ); } else { uint256 _platformFee = IMintFeeOracle(_mintFeeOracle).getMechanicMintFee( mechanicVectorId, numToMint, _mechanicVectorMetadata.mechanic, msgSender, _mechanicVectorMetadata.contractAddress ); if (msg.value < _platformFee) { _revert(MintFeeTooLow.selector); } // send value without amount needed for mint fee IMechanic(_mechanicVectorMetadata.mechanic).processChooseMint{ value: msg.value - _platformFee }( mechanicVectorId, recipient, tokenIds, msgSender, _mechanicVectorMetadata, data ); } if (numToMint == 1) { IERC721GeneralMint(_mechanicVectorMetadata.contractAddress).mintSpecificTokenToOneRecipient( recipient, tokenIds[0] ); } else { IERC721GeneralMint(_mechanicVectorMetadata.contractAddress).mintSpecificTokensToOneRecipient( recipient, tokenIds ); } emit ChooseTokenMint(mechanicVectorId, _mechanicVectorMetadata.contractAddress, true, tokenIds); } /* solhint-disable code-complexity */ /** * @notice Let the owner of a collection mint creator reserves * @param collection Collection contract address * @param isEditionBased If true, collection is edition-based * @param editionId Edition ID of collection, if applicable * @param numToMint Number of tokens to mint on sequential mints * @param tokenIds To reserve mint collector's choice based mints * @param isCollectorsChoice If true, mint via collector's choice based paradigm * @param recipient Recipient of minted tokens */ function creatorReservesMint( address collection, bool isEditionBased, uint256 editionId, uint256 numToMint, uint256[] calldata tokenIds, bool isCollectorsChoice, address recipient ) external payable { address msgSender = _msgSender(); uint256 tokenIdsLength = tokenIds.length; if (tokenIdsLength > 0) { numToMint = tokenIdsLength; } if (Ownable(collection).owner() == msgSender || msgSender == collection) { if (isEditionBased) { if (numToMint == 1) { IERC721EditionMint(collection).mintOneToRecipient(editionId, recipient); } else { IERC721EditionMint(collection).mintAmountToRecipient(editionId, recipient, numToMint); } } else { if (numToMint == 1) { if (isCollectorsChoice) { IERC721GeneralMint(collection).mintSpecificTokenToOneRecipient(recipient, tokenIds[0]); } else { IERC721GeneralMint(collection).mintOneToOneRecipient(recipient); } } else { if (isCollectorsChoice) { IERC721GeneralMint(collection).mintSpecificTokensToOneRecipient(recipient, tokenIds); } else { IERC721GeneralMint(collection).mintAmountToOneRecipient(recipient, numToMint); } } } if (isCollectorsChoice) { emit CreatorReservesChooseMint(collection, tokenIds); } else { emit CreatorReservesNumMint(collection, isEditionBased, editionId, numToMint); } } else { _revert(Unauthorized.selector); } } /* solhint-enable code-complexity */ /** * @notice Mint on a Series with a valid claim where one can choose the tokens to mint * @param claim Series Claim * @param claimSignature Signed + encoded claim * @param mintRecipient Who to mint the NFT(s) to. * Can't mint to different recipient if tx isn't sent by claim.claimer. * @param tokenIds IDs of NFTs to mint */ function gatedSeriesMintChooseToken( SeriesClaim calldata claim, bytes calldata claimSignature, address mintRecipient, uint256[] calldata tokenIds ) external payable { address msgSender = _msgSender(); uint256 numTokensToMint = tokenIds.length; if (claim.claimer != msgSender && mintRecipient != claim.claimer) { _revert(UnsafeMintRecipient.selector); } _verifyAndUpdateSeriesClaim(claim, claimSignature, numTokensToMint); _processClassicVectorPayments( claim.offchainVectorId, numTokensToMint, msgSender, claim.currency, claim.pricePerToken, claim.paymentRecipient, claim.contractAddress ); emit ChooseTokenMint(claim.offchainVectorId, claim.contractAddress, false, tokenIds); // mint NFT(s) if (numTokensToMint == 1) { IERC721GeneralMint(claim.contractAddress).mintSpecificTokenToOneRecipient(mintRecipient, tokenIds[0]); } else { IERC721GeneralMint(claim.contractAddress).mintSpecificTokensToOneRecipient(mintRecipient, tokenIds); } } /** * @notice Mint on a collection with sequentially minted token IDs with a valid claim * @param claim Claim * @param claimSignature Signed + encoded claim * @param mintRecipient Who to mint the NFT(s) to. * Can't mint to different recipient if tx isn't sent by claim.claimer. */ function gatedNumMint( Claim calldata claim, bytes calldata claimSignature, address mintRecipient, bool isEditionBased ) external payable { address msgSender = _msgSender(); if (claim.claimer != msgSender && mintRecipient != claim.claimer) { _revert(UnsafeMintRecipient.selector); } _verifyAndUpdateClaim(claim, claimSignature); _processClassicVectorPayments( claim.offchainVectorId, claim.numTokensToMint, msgSender, claim.currency, claim.pricePerToken, claim.paymentRecipient, claim.contractAddress ); emit NumTokenMint(claim.offchainVectorId, claim.contractAddress, false, claim.numTokensToMint); if (isEditionBased) { if (claim.numTokensToMint == 1) { IERC721EditionMint(claim.contractAddress).mintOneToRecipient(claim.editionId, mintRecipient); } else { IERC721EditionMint(claim.contractAddress).mintAmountToRecipient( claim.editionId, mintRecipient, claim.numTokensToMint ); } } else { if (claim.numTokensToMint == 1) { IERC721GeneralMint(claim.contractAddress).mintOneToOneRecipient(mintRecipient); } else { IERC721GeneralMint(claim.contractAddress).mintAmountToOneRecipient( mintRecipient, claim.numTokensToMint ); } } } /** * @notice Mint via an abridged vector * @param vectorId ID of vector * @param numTokensToMint Number of tokens to mint * @param mintRecipient Who to mint the NFT(s) to */ function vectorMint721(uint256 vectorId, uint48 numTokensToMint, address mintRecipient) external payable { address msgSender = _msgSender(); AbridgedVectorData memory _vector = _abridgedVectors[vectorId]; uint48 newNumClaimedViaVector = _vector.totalClaimedViaVector + numTokensToMint; uint48 newNumClaimedForUser = uint48(userClaims[vectorId][mintRecipient]) + numTokensToMint; if (_vector.requireDirectEOA && msgSender != tx.origin) { _revert(SenderNotDirectEOA.selector); } _abridgedVectors[vectorId].totalClaimedViaVector = newNumClaimedViaVector; userClaims[vectorId][mintRecipient] = uint64(newNumClaimedForUser); if (_vector.editionBasedCollection) { _vectorMintEdition721( vectorId, _vector, numTokensToMint, mintRecipient, msgSender, newNumClaimedViaVector, newNumClaimedForUser ); } else { _vectorMintGeneral721( vectorId, _vector, numTokensToMint, mintRecipient, msgSender, newNumClaimedViaVector, newNumClaimedForUser ); } } /** * @notice Withdraw native gas token owed to platform */ function withdrawNativeGasToken(uint256 amountToWithdraw) external onlyPlatform { (bool sentToPlatform, bytes memory dataPlatform) = _platform.call{ value: amountToWithdraw }(""); if (!sentToPlatform) { _revert(EtherSendFailed.selector); } } /** * @notice Update platform payment address */ function updatePlatformAndMintFeeOracle( address payable newPlatform, address newOracle, address gaslessMechanic ) external onlyOwner { if (newPlatform == address(0)) { _revert(Unauthorized.selector); } if (_platform != newPlatform) { _platform = newPlatform; } if (_mintFeeOracle != newOracle) { _mintFeeOracle = newOracle; } if (_gaslessMechanicAddress != gaslessMechanic) { _gaslessMechanicAddress = gaslessMechanic; } } /** * @notice Returns if an address is a platform executor */ function isPlatformExecutor(address _executor) external view returns (bool) { return _platformExecutors.contains(_executor); } /** * @notice 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]; } /** * @notice Verify that claim and claim signature are valid for a mint * @param claim Claim * @param signature Signed + encoded claim * @param expectedMsgSender *DEPRECATED*, keep for interface adherence */ function verifyClaim( Claim calldata claim, bytes calldata signature, address expectedMsgSender ) external view returns (bool) { address signer = _claimSigner(claim, signature); return _platformExecutors.contains(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[claim.claimer] <= claim.maxClaimablePerUser); } /** * @notice 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); } /** * @notice See {IAbridgedMintVector-getAbridgedVector} */ function getAbridgedVector(uint256 vectorId) external view returns (AbridgedVector memory) { AbridgedVectorData memory data = _abridgedVectors[vectorId]; return AbridgedVector( address(data.contractAddress), data.startTimestamp, data.endTimestamp, address(data.paymentRecipient), data.maxTotalClaimableViaVector, data.totalClaimedViaVector, address(data.currency), data.tokenLimitPerTx, data.maxUserClaimableViaVector, data.pricePerToken, data.editionId, data.editionBasedCollection, data.requireDirectEOA, data.allowlistRoot ); } /** * @notice See {IAbridgedMintVector-getAbridgedVectorMetadata} */ function getAbridgedVectorMetadata(uint256 vectorId) external view returns (bool, uint128) { return _decomposeAbridgedVectorMetadata(_abridgedVectorMetadata[vectorId]); } /* solhint-disable no-empty-blocks */ /** * @notice Limit upgrades of contract to MintManager owner * @param // New implementation address */ function _authorizeUpgrade(address) internal override onlyOwner {} /* solhint-enable no-empty-blocks */ /** * @notice Used for meta-transactions */ function _msgSender() internal view override(ContextUpgradeable, ERC2771ContextUpgradeable) returns (address sender) { return msg.sender; // temporary } /** * @notice Used for meta-transactions */ function _msgData() internal view override(ContextUpgradeable, ERC2771ContextUpgradeable) returns (bytes calldata) { return msg.data; // temporary } /** * @notice Verify, and update the state of a gated mint claim * @param claim Claim * @param signature Signed + encoded claim */ function _verifyAndUpdateClaim(Claim calldata claim, bytes calldata signature) private { address signer = _claimSigner(claim, signature); // cannot cache here due to nested mapping uint256 expectedNumClaimedViaVector = offchainVectorsClaimState[claim.offchainVectorId].numClaimed + claim.numTokensToMint; uint256 expectedNumClaimedByUser = offchainVectorsClaimState[claim.offchainVectorId].numClaimedPerUser[ claim.claimer ] + claim.numTokensToMint; if ( !_platformExecutors.contains(signer) || _offchainVectorsToNoncesUsed[claim.offchainVectorId].contains(claim.claimNonce) || block.timestamp > claim.claimExpiryTimestamp || (expectedNumClaimedViaVector > claim.maxClaimableViaVector && claim.maxClaimableViaVector != 0) || (expectedNumClaimedByUser > claim.maxClaimablePerUser && claim.maxClaimablePerUser != 0) ) { _revert(InvalidClaim.selector); } _offchainVectorsToNoncesUsed[claim.offchainVectorId].add(claim.claimNonce); // mark claim nonce as used // update claim state offchainVectorsClaimState[claim.offchainVectorId].numClaimed = expectedNumClaimedViaVector; offchainVectorsClaimState[claim.offchainVectorId].numClaimedPerUser[claim.claimer] = expectedNumClaimedByUser; } /** * @notice Verify, and update the state of a gated series mint claim * @param claim Series Claim * @param signature Signed + encoded claim * @param numTokensToMint How many tokens to mint in this series claim */ function _verifyAndUpdateSeriesClaim( SeriesClaim calldata claim, bytes calldata signature, uint256 numTokensToMint ) private { address signer = _seriesClaimSigner(claim, signature); // cannot cache here due to nested mapping uint256 expectedNumClaimedViaVector = offchainVectorsClaimState[claim.offchainVectorId].numClaimed + numTokensToMint; uint256 expectedNumClaimedByUser = offchainVectorsClaimState[claim.offchainVectorId].numClaimedPerUser[ claim.claimer ] + numTokensToMint; if ( !_platformExecutors.contains(signer) || (numTokensToMint > claim.maxPerTxn && claim.maxPerTxn != 0) || _offchainVectorsToNoncesUsed[claim.offchainVectorId].contains(claim.claimNonce) || block.timestamp > claim.claimExpiryTimestamp || (expectedNumClaimedViaVector > claim.maxClaimableViaVector && claim.maxClaimableViaVector != 0) || (expectedNumClaimedByUser > claim.maxClaimablePerUser && claim.maxClaimablePerUser != 0) ) { _revert(InvalidClaim.selector); } _offchainVectorsToNoncesUsed[claim.offchainVectorId].add(claim.claimNonce); // mark claim nonce as used // update claim state offchainVectorsClaimState[claim.offchainVectorId].numClaimed = expectedNumClaimedViaVector; offchainVectorsClaimState[claim.offchainVectorId].numClaimedPerUser[claim.claimer] = expectedNumClaimedByUser; } /** * @notice 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 * @param msgSender Minter */ function _processVectorMint( uint256 _vectorId, AbridgedVectorData memory _vector, uint48 numTokensToMint, uint48 newNumClaimedViaVector, uint48 newNumClaimedForUser, address msgSender ) private { if ( (_vector.maxTotalClaimableViaVector < newNumClaimedViaVector && _vector.maxTotalClaimableViaVector != 0) || (_vector.maxUserClaimableViaVector < newNumClaimedForUser && _vector.maxUserClaimableViaVector != 0) || ((_vector.startTimestamp > block.timestamp && _vector.startTimestamp != 0) || (block.timestamp > _vector.endTimestamp && _vector.endTimestamp != 0)) || (numTokensToMint == 0) || (numTokensToMint > _vector.tokenLimitPerTx && _vector.tokenLimitPerTx != 0) ) { _revert(OnchainVectorMintGuardFailed.selector); } if (_isVectorPaused(_abridgedVectorMetadata[_vectorId])) { _revert(MintPaused.selector); } _processClassicVectorPayments( bytes32(_vectorId), uint256(numTokensToMint), msgSender, address(_vector.currency), _vector.pricePerToken, payable(address(_vector.paymentRecipient)), address(_vector.contractAddress) ); emit NumTokenMint(bytes32(_vectorId), address(_vector.contractAddress), true, numTokensToMint); } /** * @notice 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 msgSender Minter * @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, AbridgedVectorData memory _vector, uint48 numTokensToMint, address mintRecipient, address msgSender, uint48 newNumClaimedViaVector, uint48 newNumClaimedForUser ) private { _processVectorMint( _vectorId, _vector, numTokensToMint, newNumClaimedViaVector, newNumClaimedForUser, msgSender ); if (numTokensToMint == 1) { IERC721GeneralMint(address(_vector.contractAddress)).mintOneToOneRecipient(mintRecipient); } else { IERC721GeneralMint(address(_vector.contractAddress)).mintAmountToOneRecipient( mintRecipient, numTokensToMint ); } } /** * @notice Mint on vector pointing to ERC721Editions or ERC721SingleEdiion 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 msgSender Minter * @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, AbridgedVectorData memory _vector, uint48 numTokensToMint, address mintRecipient, address msgSender, uint48 newNumClaimedViaVector, uint48 newNumClaimedForUser ) private { _processVectorMint( _vectorId, _vector, numTokensToMint, newNumClaimedViaVector, newNumClaimedForUser, msgSender ); if (numTokensToMint == 1) { IERC721EditionMint(address(_vector.contractAddress)).mintOneToRecipient(_vector.editionId, mintRecipient); } else { IERC721EditionMint(address(_vector.contractAddress)).mintAmountToRecipient( _vector.editionId, mintRecipient, numTokensToMint ); } } /** * @notice Process payment in native gas token * @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 { (bool sentToRecipient, ) = recipient.call{ value: totalAmount }(""); if (!sentToRecipient) { _revert(EtherSendFailed.selector); } emit NativeGasTokenPayment(recipient, vectorId, totalAmount, 10000); } /** * @notice Process payment in ERC20 * @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 { IERC20(currency).transferFrom(payer, recipient, totalAmount); emit ERC20Payment(currency, recipient, vectorId, payer, totalAmount, 10000); } /** * @notice 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); } /** * @notice Recover series claim signature signer * @param claim Series Claim * @param signature Series Claim signature */ function _seriesClaimSigner(SeriesClaim calldata claim, bytes calldata signature) private view returns (address) { return _hashTypedDataV4(keccak256(_seriesClaimABIEncoded(claim))).recover(signature); } /* solhint-disable code-complexity */ /** * @notice Process payments (sale + mint fee) for classic vectors (direct + gated) * @param vectorId Vector ID * @param numToMint Number of tokens being minted * @param msgSender Minter * @param currency Sale currency * @param salePrice Sale price * @param salePaymentRecipient Sale payment recipient * @param collectionContract Collection NFT contract address */ function _processClassicVectorPayments( bytes32 vectorId, uint256 numToMint, address msgSender, address currency, uint256 salePrice, address payable salePaymentRecipient, address collectionContract ) private { (uint256 mintFeeCap, bool is1155) = IMintFeeOracle(_mintFeeOracle).getClassicVectorMintFeeCap( vectorId, numToMint, msgSender, currency, collectionContract ); uint256 mintFeeEtherValue = currency == address(0) ? mintFeeCap : 0; uint256 saleAmount = numToMint * salePrice; _processClassicVectorPaymentsInner(vectorId, saleAmount, mintFeeEtherValue, currency, salePaymentRecipient); _processClassicVectorMintFee( mintFeeCap, msgSender, currency, salePaymentRecipient, vectorId, mintFeeEtherValue, salePrice == 0, is1155 ); } /** * @notice Process payments (sale + mint fee) for classic vectors (direct + gated) * @param vectorId Vector ID * @param saleAmount Sale amount * @param mintFeeEtherValue Mint fee in ether (if existent) * @param currency Sale currency * @param salePaymentRecipient Sale payment recipient */ function _processClassicVectorPaymentsInner( bytes32 vectorId, uint256 saleAmount, uint256 mintFeeEtherValue, address currency, address payable salePaymentRecipient ) private returns (uint256, bool, uint256) { if (currency == address(0)) { if (mintFeeEtherValue + saleAmount != msg.value) { _revert(InvalidPaymentAmount.selector); } if (saleAmount > 0) { // pay in native gas token _processNativeGasTokenPayment(saleAmount, salePaymentRecipient, vectorId); } } else if (saleAmount > 0) { // pay in ERC20 // tx.origin instead of msgSender for referrals _processERC20Payment(saleAmount, salePaymentRecipient, tx.origin, currency, vectorId); } } /** * @notice Helper util to process the classic vector mint fee */ function _processClassicVectorMintFee( uint256 mintFeeCap, address msgSender, address currency, address salePaymentRecipient, bytes32 vectorId, uint256 mintFeeEtherValue, bool isSaleFree, bool is1155 ) private { if (mintFeeCap > 0) { if (currency != address(0)) { // send erc20 mint fee cap to the mint fee oracle // tx.origin instead of msgSender for referrals IERC20(currency).transferFrom(tx.origin, _mintFeeOracle, mintFeeCap); } uint256 creatorPayout = IMintFeeOracle(_mintFeeOracle).processClassicVectorMintFeeCap{ value: mintFeeEtherValue }(vectorId, isSaleFree, salePaymentRecipient, currency, mintFeeCap, msgSender, is1155); if (creatorPayout != 0) { emit CreatorRewardPayout(vectorId, currency, salePaymentRecipient, creatorPayout); } } } /* solhint-enable code-complexity */ /** * @notice Deterministically produce mechanic vector ID from mechanic vector inputs * @param metadata Mechanic vector metadata * @param seed Used to seed uniqueness */ function _produceMechanicVectorId( MechanicVectorMetadata memory metadata, uint96 seed ) private pure returns (bytes32 mechanicVectorId) { mechanicVectorId = keccak256( abi.encodePacked( metadata.contractAddress, metadata.editionId, metadata.mechanic, metadata.isEditionBased, seed ) ); } /* solhint-disable max-line-length */ /** * @notice 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)" ); } /** * @notice Get series claim typehash */ function _getSeriesClaimTypeHash() private pure returns (bytes32) { return keccak256( "SeriesClaim(address currency,address contractAddress,address claimer,address paymentRecipient,uint256 pricePerToken,uint64 maxPerTxn,uint64 maxClaimableViaVector,uint64 maxClaimablePerUser,uint64 claimExpiryTimestamp,bytes32 claimNonce,bytes32 offchainVectorId)" ); } /* solhint-enable max-line-length */ /** * @notice 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 ); } /** * @notice Return abi-encoded series claim part one * @param claim SeriesClaim */ function _seriesClaimABIEncoded(SeriesClaim calldata claim) private pure returns (bytes memory) { return abi.encode( _getSeriesClaimTypeHash(), claim.currency, claim.contractAddress, claim.claimer, claim.paymentRecipient, claim.pricePerToken, claim.maxPerTxn, claim.maxClaimableViaVector, claim.maxClaimablePerUser, claim.claimExpiryTimestamp, claim.claimNonce, claim.offchainVectorId ); } /** * @notice 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); } /** * @notice Compose abridged vector metadata into a `uint256` * @param paused If the abridged vector is paused * @param flexibleData Flexible data */ function _composeAbridgedVectorMetadata(bool paused, uint128 flexibleData) private pure returns (uint256) { uint256 metadata = 0; if (paused) { metadata = metadata | _BITMASK_AV_PAUSED; } metadata = metadata | (uint256(flexibleData) << 128); return metadata; } /** * @notice Decompose abridged vector metadata from a `uint256` into its constituent parts * @param packedMetadata Packed abridged vector metadata */ function _decomposeAbridgedVectorMetadata(uint256 packedMetadata) private pure returns (bool, uint128) { bool paused = packedMetadata & _BITMASK_AV_PAUSED != 0; uint128 flexibleData = uint128(packedMetadata >> _BITPOS_AV_FLEXIBLE_DATA); return (paused, flexibleData); } /** * @notice Grab paused status for an onchain abridged mint vector * @param packedMetadata Packed abridged vector metadata */ function _isVectorPaused(uint256 packedMetadata) private pure returns (bool) { return packedMetadata & _BITMASK_AV_PAUSED != 0; } /** * @dev For more efficient reverts. */ function _revert(bytes4 errorSelector) private pure { assembly { mstore(0x00, errorSelector) revert(0x00, 0x04) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.1; import {GELATO_RELAY, GELATO_RELAY_ZKSYNC} from "../constants/GelatoRelay.sol"; abstract contract GelatoRelayBase { modifier onlyGelatoRelay() { require(_isGelatoRelay(msg.sender), "onlyGelatoRelay"); _; } function _isGelatoRelay(address _forwarder) internal view returns (bool) { return block.chainid == 324 || block.chainid == 280 ? _forwarder == GELATO_RELAY_ZKSYNC : _forwarder == GELATO_RELAY; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.1; address constant GELATO_RELAY = 0xaBcC9b596420A9E9172FD5938620E265a0f9Df92; address constant GELATO_RELAY_ERC2771 = 0xb539068872230f20456CF38EC52EF2f91AF4AE49; address constant GELATO_RELAY_CONCURRENT_ERC2771 = 0x8598806401A63Ddf52473F1B3C55bC9E33e2d73b; address constant GELATO_RELAY_ZKSYNC = 0xB16a1DbE755f992636705fDbb3A8678a657EB3ea; address constant GELATO_RELAY_ERC2771_ZKSYNC = 0x22DCC39b2AC376862183dd35A1664798dafC7Da6; // solhint-disable-next-line max-line-length address constant GELATO_RELAY_CONCURRENT_ERC2771_ZKSYNC = 0xBa4082F4961c8Fb76231995C967CD9aa40f321b5;
// SPDX-License-Identifier: MIT pragma solidity ^0.8.1; address constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
// SPDX-License-Identifier: MIT pragma solidity ^0.8.1; import {GelatoRelayBase} from "./base/GelatoRelayBase.sol"; import {TokenUtils} from "./lib/TokenUtils.sol"; uint256 constant _FEE_COLLECTOR_START = 72; // offset: address + address + uint256 uint256 constant _FEE_TOKEN_START = 52; // offset: address + uint256 uint256 constant _FEE_START = 32; // offset: uint256 // WARNING: Do not use this free fn by itself, always inherit GelatoRelayContext // solhint-disable-next-line func-visibility, private-vars-leading-underscore function _getFeeCollectorRelayContext() pure returns (address feeCollector) { assembly { feeCollector := shr( 96, calldataload(sub(calldatasize(), _FEE_COLLECTOR_START)) ) } } // WARNING: Do not use this free fn by itself, always inherit GelatoRelayContext // solhint-disable-next-line func-visibility, private-vars-leading-underscore function _getFeeTokenRelayContext() pure returns (address feeToken) { assembly { feeToken := shr(96, calldataload(sub(calldatasize(), _FEE_TOKEN_START))) } } // WARNING: Do not use this free fn by itself, always inherit GelatoRelayContext // solhint-disable-next-line func-visibility, private-vars-leading-underscore function _getFeeRelayContext() pure returns (uint256 fee) { assembly { fee := calldataload(sub(calldatasize(), _FEE_START)) } } /** * @dev Context variant with feeCollector, feeToken and fee appended to msg.data * Expects calldata encoding: * abi.encodePacked( _data, * _feeCollector, * _feeToken, * _fee); * Therefore, we're expecting 20 + 20 + 32 = 72 bytes to be appended to normal msgData * 32bytes start offsets from calldatasize: * feeCollector: - 72 bytes * feeToken: - 52 bytes * fee: - 32 bytes */ /// @dev Do not use with GelatoRelayFeeCollector - pick only one abstract contract GelatoRelayContext is GelatoRelayBase { using TokenUtils for address; // DANGER! Only use with onlyGelatoRelay `_isGelatoRelay` before transferring function _transferRelayFee() internal { _getFeeToken().transfer(_getFeeCollector(), _getFee()); } // DANGER! Only use with onlyGelatoRelay `_isGelatoRelay` before transferring function _transferRelayFeeCapped(uint256 _maxFee) internal { uint256 fee = _getFee(); require( fee <= _maxFee, "GelatoRelayContext._transferRelayFeeCapped: maxFee" ); _getFeeToken().transfer(_getFeeCollector(), fee); } function _getMsgData() internal view returns (bytes calldata) { return _isGelatoRelay(msg.sender) ? msg.data[:msg.data.length - _FEE_COLLECTOR_START] : msg.data; } // Only use with GelatoRelayBase onlyGelatoRelay or `_isGelatoRelay` checks function _getFeeCollector() internal pure returns (address) { return _getFeeCollectorRelayContext(); } // Only use with previous onlyGelatoRelay or `_isGelatoRelay` checks function _getFeeToken() internal pure returns (address) { return _getFeeTokenRelayContext(); } // Only use with previous onlyGelatoRelay or `_isGelatoRelay` checks function _getFee() internal pure returns (uint256) { return _getFeeRelayContext(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.1; import {NATIVE_TOKEN} from "../constants/Tokens.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; library TokenUtils { using SafeERC20 for IERC20; using SafeERC20 for IERC20Permit; modifier onlyERC20(address _token) { require(_token != NATIVE_TOKEN, "TokenUtils.onlyERC20"); _; } function permit( address _token, address _owner, address _spender, uint256 _value, uint256 _deadline, uint8 _v, bytes32 _r, bytes32 _s ) internal onlyERC20(_token) { IERC20Permit(_token).safePermit( _owner, _spender, _value, _deadline, _v, _r, _s ); } function transfer( address _token, address _to, uint256 _amount ) internal { if (_amount == 0) return; _token == NATIVE_TOKEN ? Address.sendValue(payable(_to), _amount) : IERC20(_token).safeTransfer(_to, _amount); } function transferFrom( address _token, address _from, address _to, uint256 _amount ) internal onlyERC20(_token) { if (_amount == 0) return; IERC20(_token).safeTransferFrom(_from, _to, _amount); } function getBalance(address token, address user) internal view returns (uint256) { return token == NATIVE_TOKEN ? user.balance : IERC20(token).balanceOf(user); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.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. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { 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 (last updated v4.9.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] * ```solidity * 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. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ 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. * * 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. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * 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. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ 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. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.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 * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [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://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/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 functionCallWithValue(target, data, 0, "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"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or 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 { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// 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; }
// 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.9.0) (interfaces/IERC1967.sol) pragma solidity ^0.8.0; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. * * _Available since v4.8.3._ */ interface IERC1967 { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
// 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.9.0) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeacon.sol"; import "../../interfaces/IERC1967.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._ */ abstract contract ERC1967Upgrade is IERC1967 { // 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 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 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 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 (last updated v4.9.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 the implementation's compatibility when performing 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. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeTo(address newImplementation) public 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. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeToAndCall(address newImplementation, bytes memory data) public 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.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.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.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.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 * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [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://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/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 functionCallWithValue(target, data, 0, "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"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or 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 { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// 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.9.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 // Deprecated in v4.8 } 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"); } } /** * @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) { 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 { 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 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 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @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 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.2) (utils/cryptography/MerkleProof.sol) pragma solidity ^0.8.0; /** * @dev These functions deal with verification of Merkle Tree proofs. * * The tree and the proofs can be generated using our * https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. * You will find a quickstart guide in the readme. * * 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. * OpenZeppelin's JavaScript library generates merkle trees that are safe * against this attack out of the box. */ 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 simultaneously proven to be a part of a merkle tree defined by * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _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} * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _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 sibling nodes in `proof`. The reconstruction * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false * respectively. * * CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer). * * _Available since v4.7._ */ function processMultiProof( bytes32[] memory proof, bool[] memory proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuilds 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 proofLen = proof.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proofLen - 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 from 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) { require(proofPos == proofLen, "MerkleProof: invalid multiproof"); unchecked { return hashes[totalHashes - 1]; } } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Calldata version of {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function processMultiProofCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuilds 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 proofLen = proof.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proofLen - 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 from 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) { require(proofPos == proofLen, "MerkleProof: invalid multiproof"); unchecked { 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.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. 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: * ```solidity * 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`, `uint256`._ * _Available since v4.9 for `string`, `bytes`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes 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 } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _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) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { 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] = _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); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. 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. * * ```solidity * 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) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // 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 in 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: UNLICENSED pragma solidity 0.8.10; /** * @notice Mint interface on editions contracts * @author highlight.xyz */ interface IERC721EditionMint { /** * @notice 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); /** * @notice 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); /** * @notice 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); /** * @notice 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; /** * @notice General721 mint interface * @author highlight.xyz */ interface IERC721GeneralMint { /** * @notice Mint one token to one recipient * @param recipient Recipient of minted NFT */ function mintOneToOneRecipient(address recipient) external returns (uint256); /** * @notice 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; /** * @notice Mint one token to multiple recipients. Useful for use-cases like airdrops * @param recipients Recipients of minted NFTs */ function mintOneToMultipleRecipients(address[] calldata recipients) external; /** * @notice 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; /** * @notice Mint a chosen token id to a single recipient * @param recipient Recipient of chosen NFT * @param tokenId ID of NFT to mint */ function mintSpecificTokenToOneRecipient(address recipient, uint256 tokenId) external; /** * @notice Mint chosen token ids to a single recipient * @param recipient Recipient of chosen NFT * @param tokenIds IDs of NFTs to mint */ function mintSpecificTokensToOneRecipient(address recipient, uint256[] calldata tokenIds) external; }
// 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: UNLICENSED pragma solidity 0.8.10; /** * @title MintManager interface for onchain abridged mint vectors * @author highlight.xyz */ interface IAbridgedMintVector { /** * @notice On-chain mint vector (stored data) * @param contractAddress NFT smart contract address * @param startTimestamp When minting opens on vector * @param endTimestamp When minting ends on vector * @param paymentRecipient Payment recipient * @param maxTotalClaimableViaVector Max number of tokens that can be minted via vector * @param totalClaimedViaVector Total number of tokens minted via vector * @param currency Currency used for payment. Native gas token, if zero address * @param tokenLimitPerTx Max number of tokens that can be minted in one transaction * @param maxUserClaimableViaVector Max number of tokens that can be minted by user via vector * @param pricePerToken Price that has to be paid per minted token * @param editionId Edition ID, if vector is for edition based collection * @param editionBasedCollection If vector is for an edition based collection * @param requireDirectEOA Require minters to directly be EOAs * @param allowlistRoot Root of merkle tree with allowlist */ struct AbridgedVectorData { uint160 contractAddress; uint48 startTimestamp; uint48 endTimestamp; uint160 paymentRecipient; uint48 maxTotalClaimableViaVector; uint48 totalClaimedViaVector; uint160 currency; uint48 tokenLimitPerTx; uint48 maxUserClaimableViaVector; uint192 pricePerToken; uint48 editionId; bool editionBasedCollection; bool requireDirectEOA; bytes32 allowlistRoot; } /** * @notice On-chain mint vector (public) - See {AbridgedVectorData} */ struct AbridgedVector { address contractAddress; uint48 startTimestamp; uint48 endTimestamp; address paymentRecipient; uint48 maxTotalClaimableViaVector; uint48 totalClaimedViaVector; address currency; uint48 tokenLimitPerTx; uint48 maxUserClaimableViaVector; uint192 pricePerToken; uint48 editionId; bool editionBasedCollection; bool requireDirectEOA; bytes32 allowlistRoot; } /** * @notice Config defining what fields to update * @param updateStartTimestamp If 1, update startTimestamp * @param updateEndTimestamp If 1, update endTimestamp * @param updatePaymentRecipient If 1, update paymentRecipient * @param updateMaxTotalClaimableViaVector If 1, update maxTotalClaimableViaVector * @param updateTokenLimitPerTx If 1, update tokenLimitPerTx * @param updateMaxUserClaimableViaVector If 1, update maxUserClaimableViaVector * @param updatePricePerToken If 1, update pricePerToken * @param updateCurrency If 1, update currency * @param updateRequireDirectEOA If 1, update requireDirectEOA * @param updateMetadata If 1, update MintVector metadata */ struct UpdateAbridgedVectorConfig { uint16 updateStartTimestamp; uint16 updateEndTimestamp; uint16 updatePaymentRecipient; uint16 updateMaxTotalClaimableViaVector; uint16 updateTokenLimitPerTx; uint16 updateMaxUserClaimableViaVector; uint8 updatePricePerToken; uint8 updateCurrency; uint8 updateRequireDirectEOA; uint8 updateMetadata; } /** * @notice Creates on-chain vector * @param _vector Vector to create */ function createAbridgedVector(AbridgedVectorData memory _vector) external; /** * @notice Updates on-chain vector * @param vectorId ID of vector to update * @param _newVector New vector details * @param updateConfig Number encoding what fields to update * @param pause Pause / unpause vector * @param flexibleData Flexible data in vector metadata */ function updateAbridgedVector( uint256 vectorId, AbridgedVector calldata _newVector, UpdateAbridgedVectorConfig calldata updateConfig, bool pause, uint128 flexibleData ) external; /** * @notice Pauses or unpauses an on-chain mint vector * @param vectorId ID of abridged vector to pause * @param pause True to pause, False to unpause * @param flexibleData Flexible data that can be interpreted differently */ function setAbridgedVectorMetadata(uint256 vectorId, bool pause, uint128 flexibleData) external; /** * @notice Get on-chain abridged vector * @param vectorId ID of abridged vector to get */ function getAbridgedVector(uint256 vectorId) external view returns (AbridgedVector memory); /** * @notice Get on-chain abridged vector metadata * @param vectorId ID of abridged vector to get */ function getAbridgedVectorMetadata(uint256 vectorId) external view returns (bool, uint128); }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.10; /** * @title MintManager interface for a mint fee oracle * @author highlight.xyz */ interface IMintFeeOracle { /** * @notice Process the mint fee for a classic mv * @param vectorId Vector ID * @param payoutCreatorReward Payout creator reward * @param vectorPaymentRecipient Vector payment recipient * @param currency Mint fee currency currency * @param amount Sale amount * @param minter Minter address * @param is1155 If collection contract is an 1155 */ function processClassicVectorMintFeeCap( bytes32 vectorId, bool payoutCreatorReward, address vectorPaymentRecipient, address currency, uint256 amount, address minter, bool is1155 ) external payable returns (uint256); /** * @notice Get the mint fee cap for a classic mv * @param vectorId Vector ID (bytes32) * @param numToMint Number of tokens to mint in this transaction * @param minter Minter address * @param currency Sale currency * @param collectionContract Collection NFT contract */ function getClassicVectorMintFeeCap( bytes32 vectorId, uint256 numToMint, address minter, address currency, address collectionContract ) external view returns (uint256, bool); /** * @notice Get the mint fee for a mechanic mint mv * @param vectorId Vector ID * @param numToMint Number of tokens to mint in this transaction * @param mechanic Address of mechanic facilitating mint * @param minter Address minting * @param collectionContract Collection NFT contract */ function getMechanicMintFee( bytes32 vectorId, uint32 numToMint, address mechanic, address minter, address collectionContract ) external view returns (uint256); }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.10; /** * @title NativeMetaTransaction interface. Used by eg. wETH on Polygon * @author highlight.xyz */ interface INativeMetaTransaction { /** * @notice 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; } /** * @notice 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: UNLICENSED pragma solidity 0.8.10; import "./IMechanicData.sol"; /** * @notice Interface that mint mechanics are forced to adhere to, * provided they support both collector's choice and sequential minting */ interface IMechanic is IMechanicData { /** * @notice Create a mechanic vector on the mechanic * @param mechanicVectorId Global mechanic vector ID * @param vectorData Mechanic vector data */ function createVector(bytes32 mechanicVectorId, bytes calldata vectorData) external; /** * @notice Process a sequential mint * @param mechanicVectorId Global ID identifying mint vector, using this mechanic * @param recipient Mint recipient * @param numToMint Number of tokens to mint * @param minter Account that called mint on the MintManager * @param mechanicVectorMetadata Mechanic vector metadata * @param data Custom data that can be deserialized and processed according to implementation */ function processNumMint( bytes32 mechanicVectorId, address recipient, uint32 numToMint, address minter, MechanicVectorMetadata calldata mechanicVectorMetadata, bytes calldata data ) external payable; /** * @notice Process a collector's choice mint * @param mechanicVectorId Global ID identifying mint vector, using this mechanic * @param recipient Mint recipient * @param tokenIds IDs of tokens to mint * @param minter Account that called mint on the MintManager * @param mechanicVectorMetadata Mechanic vector metadata * @param data Custom data that can be deserialized and processed according to implementation */ function processChooseMint( bytes32 mechanicVectorId, address recipient, uint256[] calldata tokenIds, address minter, MechanicVectorMetadata calldata mechanicVectorMetadata, bytes calldata data ) external payable; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.10; /** * @notice Defines a mechanic's metadata on the MintManager */ interface IMechanicData { /** * @notice A mechanic's metadata * @param contractAddress Collection contract address * @param editionId Edition ID if the collection is edition based * @param mechanic Address of mint mechanic contract * @param isEditionBased True if collection is edition based * @param isChoose True if collection uses a collector's choice mint paradigm * @param paused True if mechanic vector is paused */ struct MechanicVectorMetadata { address contractAddress; uint96 editionId; address mechanic; bool isEditionBased; bool isChoose; bool paused; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.10; import "./IMechanicData.sol"; /** * @notice Capabilities on MintManager pertaining to mechanics */ interface IMechanicMintManager is IMechanicData { /** * @notice Register a new mechanic vector * @param _mechanicVectorMetadata Mechanic vector metadata * @param seed Used to seed uniqueness into mechanic vector ID generation * @param vectorData Vector data to store on mechanic (optional) */ function registerMechanicVector( MechanicVectorMetadata calldata _mechanicVectorMetadata, uint96 seed, bytes calldata vectorData ) external; /** * @notice Pause or unpause a mechanic vector * @param mechanicVectorId Global mechanic ID * @param pause If true, pause the mechanic mint vector. If false, unpause */ function setPauseOnMechanicMintVector(bytes32 mechanicVectorId, bool pause) external; /** * @notice Mint a number of tokens sequentially via a mechanic vector * @param mechanicVectorId Global mechanic ID * @param recipient Mint recipient * @param numToMint Number of tokens to mint * @param data Custom data to be processed by mechanic */ function mechanicMintNum( bytes32 mechanicVectorId, address recipient, uint32 numToMint, bytes calldata data ) external payable; /** * @notice Mint a specific set of token ids via a mechanic vector * @param mechanicVectorId Global mechanic ID * @param recipient Mint recipient * @param tokenIds IDs of tokens to mint * @param data Custom data to be processed by mechanic */ function mechanicMintChoose( bytes32 mechanicVectorId, address recipient, uint256[] calldata tokenIds, bytes calldata data ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; /** * @author OpenZeppelin, modified by highlight.xyz 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 v4.4.1 (utils/introspection/IERC165.sol) pragma solidity 0.8.10; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol) pragma solidity 0.8.10; import "../ERC165/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ /* solhint-disable */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (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); } }
{ "metadata": { "bytecodeHash": "none" }, "optimizer": { "enabled": true, "runs": 1 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"AllowlistInvalid","type":"error"},{"inputs":[],"name":"AlreadyRegisteredWithId","type":"error"},{"inputs":[],"name":"CurrencyTypeInvalid","type":"error"},{"inputs":[],"name":"EtherSendFailed","type":"error"},{"inputs":[],"name":"InvalidClaim","type":"error"},{"inputs":[],"name":"InvalidExecutorChanged","type":"error"},{"inputs":[],"name":"InvalidMechanic","type":"error"},{"inputs":[],"name":"InvalidPaymentAmount","type":"error"},{"inputs":[],"name":"InvalidTotalClaimed","type":"error"},{"inputs":[],"name":"MechanicPaused","type":"error"},{"inputs":[],"name":"MintFeeTooLow","type":"error"},{"inputs":[],"name":"MintPaused","type":"error"},{"inputs":[],"name":"OnchainVectorMintGuardFailed","type":"error"},{"inputs":[],"name":"SenderNotClaimer","type":"error"},{"inputs":[],"name":"SenderNotDirectEOA","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnauthorizedGaslessRelayer","type":"error"},{"inputs":[],"name":"UnsafeMintRecipient","type":"error"},{"inputs":[],"name":"VectorUpdateActionFrozen","type":"error"},{"inputs":[],"name":"VectorWrongCollectionType","type":"error"},{"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":"bytes32","name":"vectorId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"bool","name":"onChainVector","type":"bool"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"ChooseTokenMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"CreatorReservesChooseMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"bool","name":"isEditionBased","type":"bool"},{"indexed":true,"internalType":"uint256","name":"editionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"numMinted","type":"uint256"}],"name":"CreatorReservesNumMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"vectorId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"currency","type":"address"},{"indexed":true,"internalType":"address","name":"rewardRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CreatorRewardPayout","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":"uint256","name":"vectorId","type":"uint256"},{"indexed":true,"internalType":"uint48","name":"editionId","type":"uint48"},{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"}],"name":"EditionVectorCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"mechanicVectorId","type":"bytes32"},{"indexed":true,"internalType":"bool","name":"paused","type":"bool"}],"name":"MechanicVectorPauseSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"mechanicVectorId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"mechanic","type":"address"},{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"editionId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isEditionBased","type":"bool"}],"name":"MechanicVectorRegistered","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":true,"internalType":"bytes32","name":"vectorId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"bool","name":"onChainVector","type":"bool"},{"indexed":false,"internalType":"uint256","name":"numMinted","type":"uint256"}],"name":"NumTokenMint","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":"uint256","name":"newPlatformMintFee","type":"uint256"}],"name":"PlatformMintFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vectorId","type":"uint256"},{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"}],"name":"SeriesVectorCreated","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"}],"name":"VectorDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vectorId","type":"uint256"},{"indexed":true,"internalType":"bool","name":"paused","type":"bool"},{"indexed":true,"internalType":"uint128","name":"flexibleData","type":"uint128"}],"name":"VectorMetadataSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vectorId","type":"uint256"}],"name":"VectorUpdated","type":"event"},{"inputs":[{"internalType":"address","name":"_executor","type":"address"}],"name":"addOrDeprecatePlatformExecutor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint160","name":"contractAddress","type":"uint160"},{"internalType":"uint48","name":"startTimestamp","type":"uint48"},{"internalType":"uint48","name":"endTimestamp","type":"uint48"},{"internalType":"uint160","name":"paymentRecipient","type":"uint160"},{"internalType":"uint48","name":"maxTotalClaimableViaVector","type":"uint48"},{"internalType":"uint48","name":"totalClaimedViaVector","type":"uint48"},{"internalType":"uint160","name":"currency","type":"uint160"},{"internalType":"uint48","name":"tokenLimitPerTx","type":"uint48"},{"internalType":"uint48","name":"maxUserClaimableViaVector","type":"uint48"},{"internalType":"uint192","name":"pricePerToken","type":"uint192"},{"internalType":"uint48","name":"editionId","type":"uint48"},{"internalType":"bool","name":"editionBasedCollection","type":"bool"},{"internalType":"bool","name":"requireDirectEOA","type":"bool"},{"internalType":"bytes32","name":"allowlistRoot","type":"bytes32"}],"internalType":"struct IAbridgedMintVector.AbridgedVectorData","name":"_vector","type":"tuple"}],"name":"createAbridgedVector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"bool","name":"isEditionBased","type":"bool"},{"internalType":"uint256","name":"editionId","type":"uint256"},{"internalType":"uint256","name":"numToMint","type":"uint256"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"bool","name":"isCollectorsChoice","type":"bool"},{"internalType":"address","name":"recipient","type":"address"}],"name":"creatorReservesMint","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"},{"internalType":"bool","name":"isEditionBased","type":"bool"}],"name":"gatedNumMint","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":"maxPerTxn","type":"uint64"},{"internalType":"uint64","name":"maxClaimableViaVector","type":"uint64"},{"internalType":"uint64","name":"maxClaimablePerUser","type":"uint64"},{"internalType":"uint64","name":"claimExpiryTimestamp","type":"uint64"},{"internalType":"bytes32","name":"claimNonce","type":"bytes32"},{"internalType":"bytes32","name":"offchainVectorId","type":"bytes32"}],"internalType":"struct MintManager.SeriesClaim","name":"claim","type":"tuple"},{"internalType":"bytes","name":"claimSignature","type":"bytes"},{"internalType":"address","name":"mintRecipient","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"gatedSeriesMintChooseToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vectorId","type":"uint256"}],"name":"getAbridgedVector","outputs":[{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint48","name":"startTimestamp","type":"uint48"},{"internalType":"uint48","name":"endTimestamp","type":"uint48"},{"internalType":"address","name":"paymentRecipient","type":"address"},{"internalType":"uint48","name":"maxTotalClaimableViaVector","type":"uint48"},{"internalType":"uint48","name":"totalClaimedViaVector","type":"uint48"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"uint48","name":"tokenLimitPerTx","type":"uint48"},{"internalType":"uint48","name":"maxUserClaimableViaVector","type":"uint48"},{"internalType":"uint192","name":"pricePerToken","type":"uint192"},{"internalType":"uint48","name":"editionId","type":"uint48"},{"internalType":"bool","name":"editionBasedCollection","type":"bool"},{"internalType":"bool","name":"requireDirectEOA","type":"bool"},{"internalType":"bytes32","name":"allowlistRoot","type":"bytes32"}],"internalType":"struct IAbridgedMintVector.AbridgedVector","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"vectorId","type":"uint256"}],"name":"getAbridgedVectorMetadata","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint128","name":"","type":"uint128"}],"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"},{"internalType":"uint256","name":"initialPlatformMintFee","type":"uint256"}],"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":"_executor","type":"address"}],"name":"isPlatformExecutor","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":"mechanicVectorId","type":"bytes32"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"mechanicMintChoose","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"mechanicVectorId","type":"bytes32"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint32","name":"numToMint","type":"uint32"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"mechanicMintNum","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"mechanicVectorMetadata","outputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint96","name":"editionId","type":"uint96"},{"internalType":"address","name":"mechanic","type":"address"},{"internalType":"bool","name":"isEditionBased","type":"bool"},{"internalType":"bool","name":"isChoose","type":"bool"},{"internalType":"bool","name":"paused","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":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint96","name":"editionId","type":"uint96"},{"internalType":"address","name":"mechanic","type":"address"},{"internalType":"bool","name":"isEditionBased","type":"bool"},{"internalType":"bool","name":"isChoose","type":"bool"},{"internalType":"bool","name":"paused","type":"bool"}],"internalType":"struct IMechanicData.MechanicVectorMetadata","name":"_mechanicVectorMetadata","type":"tuple"},{"internalType":"uint96","name":"seed","type":"uint96"},{"internalType":"bytes","name":"vectorData","type":"bytes"}],"name":"registerMechanicVector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vectorId","type":"uint256"},{"internalType":"bool","name":"pause","type":"bool"},{"internalType":"uint128","name":"flexibleData","type":"uint128"}],"name":"setAbridgedVectorMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"mechanicVectorId","type":"bytes32"},{"internalType":"bool","name":"pause","type":"bool"}],"name":"setPauseOnMechanicMintVector","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"},{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"uint48","name":"startTimestamp","type":"uint48"},{"internalType":"uint48","name":"endTimestamp","type":"uint48"},{"internalType":"address","name":"paymentRecipient","type":"address"},{"internalType":"uint48","name":"maxTotalClaimableViaVector","type":"uint48"},{"internalType":"uint48","name":"totalClaimedViaVector","type":"uint48"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"uint48","name":"tokenLimitPerTx","type":"uint48"},{"internalType":"uint48","name":"maxUserClaimableViaVector","type":"uint48"},{"internalType":"uint192","name":"pricePerToken","type":"uint192"},{"internalType":"uint48","name":"editionId","type":"uint48"},{"internalType":"bool","name":"editionBasedCollection","type":"bool"},{"internalType":"bool","name":"requireDirectEOA","type":"bool"},{"internalType":"bytes32","name":"allowlistRoot","type":"bytes32"}],"internalType":"struct IAbridgedMintVector.AbridgedVector","name":"_newVector","type":"tuple"},{"components":[{"internalType":"uint16","name":"updateStartTimestamp","type":"uint16"},{"internalType":"uint16","name":"updateEndTimestamp","type":"uint16"},{"internalType":"uint16","name":"updatePaymentRecipient","type":"uint16"},{"internalType":"uint16","name":"updateMaxTotalClaimableViaVector","type":"uint16"},{"internalType":"uint16","name":"updateTokenLimitPerTx","type":"uint16"},{"internalType":"uint16","name":"updateMaxUserClaimableViaVector","type":"uint16"},{"internalType":"uint8","name":"updatePricePerToken","type":"uint8"},{"internalType":"uint8","name":"updateCurrency","type":"uint8"},{"internalType":"uint8","name":"updateRequireDirectEOA","type":"uint8"},{"internalType":"uint8","name":"updateMetadata","type":"uint8"}],"internalType":"struct IAbridgedMintVector.UpdateAbridgedVectorConfig","name":"updateConfig","type":"tuple"},{"internalType":"bool","name":"pause","type":"bool"},{"internalType":"uint128","name":"flexibleData","type":"uint128"}],"name":"updateAbridgedVector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newPlatform","type":"address"},{"internalType":"address","name":"newOracle","type":"address"},{"internalType":"address","name":"gaslessMechanic","type":"address"}],"name":"updatePlatformAndMintFeeOracle","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":"uint48","name":"numTokensToMint","type":"uint48"},{"internalType":"address","name":"mintRecipient","type":"address"}],"name":"vectorMint721","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":[{"internalType":"uint256","name":"amountToWithdraw","type":"uint256"}],"name":"withdrawNativeGasToken","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a06040523060805234801561001457600080fd5b50608051615f946200004d600039600081816119ee01528181611a3701528181611bf001528181611c300152611de10152615f946000f3fe6080604052600436106101895760003560e01c8063041050181461018e57806306056f831461024f5780630dbb18a1146102645780631d9165aa1461029f57806323bc2078146102b25780632cf9adc8146102c55780633659cfe6146102e55780633716e28414610305578063391a6d28146103355780634f1ef2861461035557806352169be81461036857806352d1902d14610388578063532742461461039d57806356292ab5146103e4578063572b6c0514610404578063619b8589146104335780636c1b7abd14610551578063715018a61461056457806377a856ea146105795780637ced595c146105995780637e5811fc146105ac5780638a320d64146105cc5780638da5cb5b146109bc5780639e2dc500146109de578063a0f7652314610a2c578063b052d17c14610a85578063b414ae2f14610aa5578063c462507e14610ad2578063e28be14414610b39578063e2f66b1e14610b59578063f2fde38b14610b79578063f4a4034514610b99578063f7013ef614610bb9578063fc2c997114610bd9575b600080fd5b34801561019a57600080fd5b506101ff6101a9366004614cd1565b60a960205260009081526040902080546001909101546001600160a01b03808316926001600160601b03600160a01b9182900416929182169160ff918104821691600160a81b8204811691600160b01b90041686565b604080516001600160a01b0397881681526001600160601b039096166020870152959093169484019490945215156060830152911515608082015290151560a082015260c0015b60405180910390f35b61026261025d366004614d5e565b610bec565b005b34801561027057600080fd5b5061029161027f366004614cd1565b60a16020526000908152604090205481565b604051908152602001610246565b6102626102ad366004614ec9565b610f56565b6102626102c0366004614f62565b61132d565b3480156102d157600080fd5b506102626102e0366004614fd9565b611533565b3480156102f157600080fd5b5061026261030036600461504c565b6119e3565b34801561031157600080fd5b50610325610320366004615070565b611ab5565b6040519015158152602001610246565b34801561034157600080fd5b50610262610350366004615092565b611ad6565b6102626103633660046150d0565b611be5565b34801561037457600080fd5b5061026261038336600461511f565b611c9f565b34801561039457600080fd5b50610291611dd4565b3480156103a957600080fd5b506102916103b836600461514f565b600082815260a1602090815260408083206001600160a01b038516845260010190915290205492915050565b3480156103f057600080fd5b506102626103ff366004615174565b611e82565b34801561041057600080fd5b5061032561041f36600461504c565b606a546001600160a01b0391821691161490565b34801561043f57600080fd5b506104d361044e366004614cd1565b609d602052600090815260409020805460018201546002830154600384015460048501546005860154600687015460078801546008909801546001600160a01b039788169896881697909516959394929391926001600160401b0380831693600160401b8404821693600160801b8104831693600160c01b9091049092169160ff168c565b604080516001600160a01b039d8e1681529b8d1660208d015299909b16988a01989098526060890196909652608088019490945260a08701929092526001600160401b0390811660c087015290811660e08601529081166101008501521661012083015261014082015260ff90911661016082015261018001610246565b61026261055f3660046151e5565b611f3f565b34801561057057600080fd5b5061026261214d565b34801561058557600080fd5b50610262610594366004615285565b612161565b6102626105a73660046152b5565b61233f565b3480156105b857600080fd5b506102626105c7366004614cd1565b612671565b3480156105d857600080fd5b506109af6105e7366004614cd1565b604080516101c081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a0810191909152600060a76000848152602001908152602001600020604051806101c00160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160018201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016002820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016002820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160028201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016003820160009054906101000a90046001600160c01b03166001600160c01b03166001600160c01b031681526020016003820160189054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160038201601e9054906101000a900460ff1615151515815260200160038201601f9054906101000a900460ff161515151581526020016004820154815250509050604051806101c0016040528082600001516001600160a01b03168152602001826020015165ffffffffffff168152602001826040015165ffffffffffff16815260200182606001516001600160a01b03168152602001826080015165ffffffffffff1681526020018260a0015165ffffffffffff1681526020018260c001516001600160a01b031681526020018260e0015165ffffffffffff16815260200182610100015165ffffffffffff1681526020018261012001516001600160c01b0316815260200182610140015165ffffffffffff1681526020018261016001511515815260200182610180015115158152602001826101a00151815250915050919050565b6040516102469190615340565b3480156109c857600080fd5b506109d161270b565b6040516102469190615443565b3480156109ea57600080fd5b50610a1f6109f936600461514f565b609f6020908152600092835260408084209091529082529020546001600160401b031681565b6040516102469190615457565b348015610a3857600080fd5b50610a66610a47366004614cd1565b600090815260a860205260409020546001811615159160809190911c90565b6040805192151583526001600160801b03909116602083015201610246565b348015610a9157600080fd5b50610262610aa036600461504c565b61271a565b348015610ab157600080fd5b50610291610ac0366004614cd1565b60a26020526000908152604090205481565b348015610ade57600080fd5b50610b15610aed366004614cd1565b609e6020526000908152604090205460ff808216916101008104821691620100009091041683565b6040805160ff94851681529284166020840152921691810191909152606001610246565b348015610b4557600080fd5b50610262610b54366004615482565b612766565b348015610b6557600080fd5b50610325610b7436600461504c565b612a8b565b348015610b8557600080fd5b50610262610b9436600461504c565b612a98565b348015610ba557600080fd5b50610325610bb436600461555c565b612b0e565b348015610bc557600080fd5b50610262610bd43660046155c5565b612c49565b610262610be7366004615629565b612dea565b33838015610bf8578096505b816001600160a01b03168a6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c64919061569d565b6001600160a01b03161480610c8a5750896001600160a01b0316826001600160a01b0316145b15610f3b578815610d51578660011415610d155760405163b859c93560e01b81526001600160a01b038b169063b859c93590610ccc908b9087906004016156ba565b6020604051808303816000875af1158015610ceb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d0f91906156d1565b50610ea1565b604051631b30808d60e01b8152600481018990526001600160a01b038481166024830152604482018990528b1690631b30808d90606401610ccc565b8660011415610e0a578315610dde57896001600160a01b0316630d640e818488886000818110610d8357610d836156ea565b905060200201356040518363ffffffff1660e01b8152600401610da7929190615700565b600060405180830381600087803b158015610dc157600080fd5b505af1158015610dd5573d6000803e3d6000fd5b50505050610ea1565b60405163184a94d560e01b81526001600160a01b038b169063184a94d590610ccc908690600401615443565b8315610e4057604051636371fbe760e01b81526001600160a01b038b1690636371fbe790610da79086908a908a9060040161574f565b604051630b7d2a8960e31b81526001600160a01b038b1690635be9544890610e6e9086908b90600401615700565b600060405180830381600087803b158015610e8857600080fd5b505af1158015610e9c573d6000803e3d6000fd5b505050505b8315610eef57896001600160a01b03167f4e84cd8521d66b0c0a2d95e21910942e1616948e140df953825b0cb02c32a5e98787604051610ee292919061577d565b60405180910390a2610f4a565b878915158b6001600160a01b03167f4c0491da007181c9465d71c51f64ba4f8eb23133900a4bb2dae027b0c2252c3f8a604051610f2e91815260200190565b60405180910390a4610f4a565b610f4a6282b42960e81b613259565b50505050505050505050565b600085815260a96020908152604091829020825160c08101845281546001600160a01b0380821683526001600160601b03600160a01b9283900416948301949094526001909201549283169381019390935260ff908204811615156060840152600160a81b8204811615156080840152600160b01b9091041615801560a08301523390610fed57610fed6337e9321960e21b613259565b816080015161100657611006633bed786f60e21b613259565b60ab54604083015185916001600160a01b03918216911614156110e45761102c82613263565b6110405761104063ac3274ef60e01b613259565b82604001516001600160a01b031663c4804ce28989898987896110616132c5565b6110696132d3565b8d60405160200161107c939291906157e9565b6040516020818303038152906040526040518863ffffffff1660e01b81526004016110ad9796959493929190615867565b600060405180830381600087803b1580156110c757600080fd5b505af11580156110db573d6000803e3d6000fd5b505050506111f7565b60aa5460408085015185519151634b48652b60e11b81526000936001600160a01b031692639690ca5692611122928e928892918a91906004016158cc565b602060405180830381865afa15801561113f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116391906156d1565b90508034101561117d5761117d63207226af60e01b613259565b60408401516001600160a01b031663c4804ce261119a8334615916565b8b8b8b8b898b8d6040518963ffffffff1660e01b81526004016111c39796959493929190615867565b6000604051808303818588803b1580156111dc57600080fd5b505af11580156111f0573d6000803e3d6000fd5b5050505050505b8063ffffffff16600114156112835782516001600160a01b0316630d640e81888888600081611228576112286156ea565b905060200201356040518363ffffffff1660e01b815260040161124c929190615700565b600060405180830381600087803b15801561126657600080fd5b505af115801561127a573d6000803e3d6000fd5b505050506112e9565b8251604051636371fbe760e01b81526001600160a01b0390911690636371fbe7906112b6908a908a908a9060040161574f565b600060405180830381600087803b1580156112d057600080fd5b505af11580156112e4573d6000803e3d6000fd5b505050505b6001151583600001516001600160a01b031689600080516020615ec1833981519152898960405161131b92919061577d565b60405180910390a45050505050505050565b600033600085815260a76020908152604080832081516101c08101835281546001600160a01b03808216835265ffffffffffff600160a01b808404821697850197909752600160d01b928390048116958401959095526001840154808216606085015286810486166080850152829004851660a08401819052600285015491821660c0850152958104851660e084015204831661010082015260038201546001600160c01b038116610120830152600160c01b810490931661014082015260ff600160f01b840481161515610160830152600160f81b9093049092161515610180830152600401546101a082015292935061142990869061592d565b6000878152609f602090815260408083206001600160a01b0389168452909152812054919250906114649087906001600160401b031661592d565b9050826101800151801561148157506001600160a01b0384163214155b1561149657611496630977d34b60e01b613259565b600087815260a760209081526040808320600101805465ffffffffffff808816600160d01b026001600160d01b0390921691909117909155609f83528184206001600160a01b038a16855290925290912080546001600160401b0319169183169190911790556101608301511561151b57611516878488888887876132df565b61152a565b61152a87848888888787613414565b50505050505050565b600085815260a760205260408120546001600160a01b031690339050806001600160a01b0316826001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611597573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115bb919061569d565b6001600160a01b031614806115e15750816001600160a01b0316816001600160a01b0316145b156119d45760006115f56020870187615957565b61ffff1611156116455761160f604087016020880161597b565b600088815260a760205260409020805465ffffffffffff92909216600160a01b0265ffffffffffff60a01b199092169190911790555b60006116576040870160208801615957565b61ffff1611156116a457611671606087016040880161597b565b600088815260a760205260409020805465ffffffffffff92909216600160d01b026001600160d01b039092169190911790555b60006116b66060870160408801615957565b61ffff161115611700576116d0608087016060880161504c565b600088815260a76020526040902060010180546001600160a01b0319166001600160a01b03929092169190911790555b60006117126080870160608801615957565b61ffff1611156117655761172c60a087016080880161597b565b600088815260a760205260409020600101805465ffffffffffff92909216600160a01b0265ffffffffffff60a01b199092169190911790555b600061177760a0870160808801615957565b61ffff1611156117cb57611792610100870160e0880161597b565b600088815260a760205260409020600201805465ffffffffffff92909216600160a01b0265ffffffffffff60a01b199092169190911790555b60006117dd60c0870160a08801615957565b61ffff16111561182f576117f96101208701610100880161597b565b600088815260a760205260409020600201805465ffffffffffff92909216600160d01b026001600160d01b039092169190911790555b600061184160e0870160c08801615998565b60ff16111561188c5761185c610140870161012088016159d0565b600088815260a76020526040902060030180546001600160c01b0319166001600160c01b03929092169190911790555b600061189f610100870160e08801615998565b60ff1611156118e8576118b860e0870160c0880161504c565b600088815260a76020526040902060020180546001600160a01b0319166001600160a01b03929092169190911790555b60006118fc61012087016101008801615998565b60ff161115611945576119176101a0870161018088016159ed565b600088815260a7602052604090206003018054911515600160f81b026001600160f81b039092169190911790555b600061195961014087016101208801615998565b60ff1611156119a45761196c84846134d7565b600088815260a860205260408082209290925590516001600160801b03851691861515918a91600080516020615f6883398151915291a45b60405187907fe772ce44f6b7edf20d62f174efc62c5a18484d62a710bd48d57af1afd140811c90600090a261152a565b61152a6282b42960e81b613259565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161415611a355760405162461bcd60e51b8152600401611a2c90615a0a565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611a676134fc565b6001600160a01b031614611a8d5760405162461bcd60e51b8152600401611a2c90615a44565b611a9681613518565b60408051600080825260208201909252611ab291839190613520565b50565b600082815260a060205260408120611acd908361368b565b90505b92915050565b600083815260a760205260408120546001600160a01b031690339050806001600160a01b0316826001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b5e919061569d565b6001600160a01b03161480611b845750816001600160a01b0316816001600160a01b0316145b15611bcf57611b9384846134d7565b600086815260a860205260408082209290925590516001600160801b03851691861515918891600080516020615f6883398151915291a4611bde565b611bde6282b42960e81b613259565b5050505050565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161415611c2e5760405162461bcd60e51b8152600401611a2c90615a0a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611c606134fc565b6001600160a01b031614611c865760405162461bcd60e51b8152600401611a2c90615a44565b611c8f82613518565b611c9b82826001613520565b5050565b600082815260a9602052604090205433906001600160a01b031680611cce57611cce633bed786f60e21b613259565b816001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3a919061569d565b6001600160a01b03161480611d605750806001600160a01b0316826001600160a01b0316145b15611d9057600084815260a960205260409020600101805460ff60b01b1916600160b01b85151502179055611d9f565b611d9f6282b42960e81b613259565b6040518315159085907fa5a0d9b368dd777972caaaa919c8ca3243792928d90f1b032a1bab6b243a73ab90600090a350505050565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611e6f5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b6064820152608401611a2c565b50600080516020615f0183398151915290565b611e8a613697565b6001600160a01b038316611ea757611ea76282b42960e81b613259565b609c546001600160a01b03848116911614611ed857609c80546001600160a01b0319166001600160a01b0385161790555b60aa546001600160a01b03838116911614611f095760aa80546001600160a01b0319166001600160a01b0384161790555b60ab546001600160a01b03828116911614611f3a5760ab80546001600160a01b0319166001600160a01b0383161790555b505050565b338181611f5260608a0160408b0161504c565b6001600160a01b031614158015611f8a5750611f746060890160408a0161504c565b6001600160a01b0316856001600160a01b031614155b15611f9f57611f9f6343d0477760e01b613259565b611fab888888846136f6565b611ff36101408901358284611fc360208d018d61504c565b8c608001358d6060016020810190611fdb919061504c565b8e6020016020810190611fee919061504c565b61393c565b600061200560408a0160208b0161504c565b6001600160a01b0316896101400135600080516020615ec1833981519152878760405161203392919061577d565b60405180910390a480600114156120d1576120546040890160208a0161504c565b6001600160a01b0316630d640e818686866000818110612076576120766156ea565b905060200201356040518363ffffffff1660e01b815260040161209a929190615700565b600060405180830381600087803b1580156120b457600080fd5b505af11580156120c8573d6000803e3d6000fd5b50505050612143565b6120e16040890160208a0161504c565b6001600160a01b0316636371fbe78686866040518463ffffffff1660e01b81526004016121109392919061574f565b600060405180830381600087803b15801561212a57600080fd5b505af115801561213e573d6000803e3d6000fd5b505050505b5050505050505050565b612155613697565b61215f6000613a1d565b565b3380612170602084018461504c565b6001600160a01b0316148061220357506001600160a01b038116612197602084018461504c565b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f8919061569d565b6001600160a01b0316145b1561233057600061221a60c0840160a0850161597b565b65ffffffffffff1611156122385761223863875fc25f60e01b613259565b60a3805490600061224883615a7e565b909155505060a354600090815260a760205260409020829061226a8282615acd565b5061227f9050610180830161016084016159ed565b156122e757612291602083018361504c565b6001600160a01b03166122ac6101608401610140850161597b565b65ffffffffffff1660a3547fa712e8b25b3d4d043988e80f0a4087773b1c7e29e4115a4256e86aebe91c9be960405160405180910390a45050565b6122f4602083018361504c565b6001600160a01b031660a3547f7258df9bfe0a9fb9cf1285396575e6472f56ca38b4851afcb725c82726fd67ff60405160405180910390a35050565b611c9b6282b42960e81b613259565b3380612351606088016040890161504c565b6001600160a01b0316141580156123895750612373606087016040880161504c565b6001600160a01b0316836001600160a01b031614155b1561239e5761239e6343d0477760e01b613259565b6123a9868686613a6f565b6123fd6101608701356123c260c0890160a08a01615ca0565b6001600160401b0316836123d960208b018b61504c565b60808b018035906123ed9060608e0161504c565b611fee60408e0160208f0161504c565b600061240f604088016020890161504c565b6001600160a01b0316610160880135600080516020615f4883398151915261243d60c08b0160a08c01615ca0565b60405161244a9190615457565b60405180910390a4811561257b5761246860c0870160a08801615ca0565b6001600160401b03166001141561250457612489604087016020880161504c565b6001600160a01b031663b859c935876101000135856040518363ffffffff1660e01b81526004016124bb9291906156ba565b6020604051808303816000875af11580156124da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124fe91906156d1565b50612669565b612514604087016020880161504c565b6001600160a01b0316631b30808d6101008801358561253960c08b0160a08c01615ca0565b6040516001600160e01b031960e086901b16815260048101939093526001600160a01b0390911660248301526001600160401b031660448201526064016124bb565b61258b60c0870160a08801615ca0565b6001600160401b0316600114156125d7576125ac604087016020880161504c565b6001600160a01b031663184a94d5846040518263ffffffff1660e01b81526004016124bb9190615443565b6125e7604087016020880161504c565b6001600160a01b0316635be954488461260660c08a0160a08b01615ca0565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526001600160401b03166024820152604401600060405180830381600087803b15801561265557600080fd5b505af1158015610f4a573d6000803e3d6000fd5b505050505050565b609c546001600160a01b0316336001600160a01b03161461269b5761269b6282b42960e81b613259565b609c5460405160009182916001600160a01b039091169084908381818185875af1925050503d80600081146126ec576040519150601f19603f3d011682016040523d82523d6000602084013e6126f1565b606091505b509150915081611f3a57611f3a637cd69c3960e11b613259565b6038546001600160a01b031690565b612722613697565b6001600160a01b038116612740576127406340f3a16b60e01b613259565b61274b60a482613c39565b1561275b57611c9b60a482613c4e565b611c9b60a482613c63565b83516020808601516040808801516060808a015183516001600160601b031997831b8816818801526001600160a01b031960a096871b811660348301529390921b9096168184015294151560f81b60548601529187901b90911660558401528051808403604101815260619093019052815191012084513391906001600160a01b031682148061286c5750816001600160a01b031686600001516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561283d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612861919061569d565b6001600160a01b0316145b1561299a57600081815260a960205260409020546001600160a01b03161561289e5761289e63250675bd60e21b613259565b85516001600160a01b031615806128c0575060408601516001600160a01b0316155b806128d85750856060015180156128d8575085608001515b806128e1575080155b156128f6576128f6633bed786f60e21b613259565b600060a0870181815282825260a960209081526040928390208951918a01516001600160a01b03928316600160a01b6001600160601b039092168202178255938a01516001909101805460608c015160808d01519551939094166001600160a81b0319909116179215159094029190911761ffff60a81b1916600160a81b9215159290920260ff60b01b191691909117600160b01b911515919091021790556129a9565b6129a96282b42960e81b613259565b85604001516001600160a01b0316631a8d37928286866040518463ffffffff1660e01b81526004016129dd93929190615cc9565b600060405180830381600087803b1580156129f757600080fd5b505af1158015612a0b573d6000803e3d6000fd5b5050505085600001516001600160a01b031686604001516001600160a01b0316827f6ec667d7188a57a345b217226db199b2b1e98d2ccdb2eaa555af7ad19324303789602001518a60600151604051612a7b9291906001600160601b039290921682521515602082015260400190565b60405180910390a4505050505050565b6000611ad060a483613c39565b612aa0613697565b6001600160a01b038116612b055760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401611a2c565b611ab281613a1d565b600080612b1c868686613c78565b9050612b2960a482613c39565b8015612b555750610160860135600090815260a060205260409020612b539061014088013561368b565b155b8015612b6657508561012001354211155b8015612bb9575060c08601351580612bb95750610160860135600090815260a1602052604090205460c0870180359190612ba39060a08a01615ca0565b6001600160401b0316612bb69190615cff565b11155b8015612c3d575060e08601351580612c3d5750610160860135600090815260a1602052604080822060e089013592600190910191612bfd9060608b01908b0161504c565b6001600160a01b03168152602081019190915260400160002054612c2760c0890160a08a01615ca0565b6001600160401b0316612c3a9190615cff565b11155b9150505b949350505050565b600054610100900460ff1615808015612c695750600054600160ff909116105b80612c8a5750612c7830613d02565b158015612c8a575060005460ff166001145b612ced5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401611a2c565b6000805460ff191660011790558015612d10576000805461ff0019166101001790555b609c80546001600160a01b0319166001600160a01b038816179055604080518082018252600b81526a26b4b73a26b0b730b3b2b960a91b602080830191909152825180840190935260058352640312e302e360dc1b90830152612d7291613d11565b612d7b84613d92565b612d83613ddb565b612d8c85613a1d565b612d9760a484613c63565b5060a68290558015612669576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b600084815260a96020908152604091829020825160c08101845281546001600160a01b0380821683526001600160601b03600160a01b9283900416948301949094526001909201549283169381019390935260ff908204811615156060840152600160a81b8204811615156080840152600160b01b9091041615801560a08301523390612e8157612e816337e9321960e21b613259565b816080015115612e9b57612e9b633bed786f60e21b613259565b60ab5460408301516001600160a01b0390811691161415612f7557612ebf81613263565b612ed357612ed363ac3274ef60e01b613259565b81604001516001600160a01b0316639cc163e58787878587612ef36132c5565b612efb6132d3565b8b604051602001612f0e939291906157e9565b6040516020818303038152906040526040518763ffffffff1660e01b8152600401612f3e96959493929190615d17565b600060405180830381600087803b158015612f5857600080fd5b505af1158015612f6c573d6000803e3d6000fd5b50505050613086565b60aa5460408084015184519151634b48652b60e11b81526000936001600160a01b031692639690ca5692612fb3928c928b92918991906004016158cc565b602060405180830381865afa158015612fd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ff491906156d1565b90508034101561300e5761300e63207226af60e01b613259565b60408301516001600160a01b0316639cc163e561302b8334615916565b89898987898b6040518863ffffffff1660e01b815260040161305296959493929190615d17565b6000604051808303818588803b15801561306b57600080fd5b505af115801561307f573d6000803e3d6000fd5b5050505050505b81606001511561317c578363ffffffff166001141561312a578151602083015160405163b859c93560e01b81526001600160601b0390911660048201526001600160a01b0387811660248301529091169063b859c935906044015b6020604051808303816000875af1158015613100573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061312491906156d1565b50613224565b81516020830151604051631b30808d60e01b81526001600160601b0390911660048201526001600160a01b03878116602483015263ffffffff8716604483015290911690631b30808d906064016130e1565b8363ffffffff16600114156131ba57815160405163184a94d560e01b81526001600160a01b039091169063184a94d5906130e1908890600401615443565b8151604051630b7d2a8960e31b81526001600160a01b0390911690635be95448906131f190889063ffffffff891690600401615700565b600060405180830381600087803b15801561320b57600080fd5b505af115801561321f573d6000803e3d6000fd5b505050505b815160405163ffffffff861681526001916001600160a01b0316908890600080516020615f4883398151915290602001612a7b565b8060005260046000fd5b6000466101441480613276575046610118145b61329f576001600160a01b03821673abcc9b596420a9e9172fd5938620e265a0f9df9214611ad0565b6001600160a01b03821673b16a1dbe755f992636705fdbb3a8678a657eb3ea1492915050565b601f1936013590565b905090565b60471936013560601c90565b6132ed878787858588613e0a565b8465ffffffffffff166001141561338957855161014087015160405163b859c93560e01b815265ffffffffffff90911660048201526001600160a01b0386811660248301529091169063b859c935906044015b6020604051808303816000875af115801561335f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061338391906156d1565b5061152a565b8551610140870151604051631b30808d60e01b815265ffffffffffff91821660048201526001600160a01b0387811660248301529188166044820152911690631b30808d906064016020604051808303816000875af11580156133f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061214391906156d1565b613422878787858588613e0a565b8465ffffffffffff166001141561346257855160405163184a94d560e01b81526001600160a01b039091169063184a94d590613340908790600401615443565b8551604051630b7d2a8960e31b81526001600160a01b03868116600483015265ffffffffffff8816602483015290911690635be9544890604401600060405180830381600087803b1580156134b657600080fd5b505af11580156134ca573d6000803e3d6000fd5b5050505050505050505050565b60008083156134e4576001175b6001600160801b0319608084901b1617905092915050565b600080516020615f01833981519152546001600160a01b031690565b611ab2613697565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561355357611f3a83613fb2565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156135ad575060408051601f3d908101601f191682019092526135aa918101906156d1565b60015b6136105760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401611a2c565b600080516020615f01833981519152811461367f5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401611a2c565b50611f3a83838361404c565b6000611acd8383614077565b336136a061270b565b6001600160a01b03161461215f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611a2c565b600061370385858561408f565b610140860135600090815260a1602052604081205491925090613727908490615cff565b905060008360a160008961014001358152602001908152602001600020600101600089604001602081019061375c919061504c565b6001600160a01b03166001600160a01b03168152602001908152602001600020546137879190615cff565b905061379460a484613c39565b15806137d957506137ab60c0880160a08901615ca0565b6001600160401b0316841180156137d957506137cd60c0880160a08901615ca0565b6001600160401b031615155b806138025750610140870135600090815260a0602052604090206138029061012089013561368b565b80613826575061381a61012088016101008901615ca0565b6001600160401b031642115b8061386a575061383c60e0880160c08901615ca0565b6001600160401b03168211801561386a575061385e60e0880160c08901615ca0565b6001600160401b031615155b806138b05750613881610100880160e08901615ca0565b6001600160401b0316811180156138b057506138a4610100880160e08901615ca0565b6001600160401b031615155b156138c5576138c5633b4f091f60e21b613259565b610140870135600090815260a0602052604090206138e8906101208901356140e5565b50610140870135600090815260a1602052604080822084815583926001909101916139199060608c01908c0161504c565b6001600160a01b0316815260208101919091526040016000205550505050505050565b60aa546040516376c1989360e01b815260048101899052602481018890526001600160a01b0387811660448301528681166064830152838116608483015260009283929116906376c198939060a4016040805180830381865afa1580156139a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139cb9190615d6f565b909250905060006001600160a01b038716156139e85760006139ea565b825b905060006139f8878b615d94565b9050613a078b82848b8a6140f1565b5050506134ca848a8a898f878d6000148a614157565b603880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000613a7c848484613c78565b90506000613a9060c0860160a08701615ca0565b610160860135600090815260a16020526040902054613ab8916001600160401b031690615cff565b90506000613acc60c0870160a08801615ca0565b6001600160401b031660a1600088610160013581526020019081526020016000206001016000886040016020810190613b05919061504c565b6001600160a01b03166001600160a01b0316815260200190815260200160002054613b309190615cff565b9050613b3d60a484613c39565b1580613b675750610160860135600090815260a060205260409020613b679061014088013561368b565b80613b76575085610120013542115b80613b9257508560c0013582118015613b92575060c086013515155b80613bae57508560e0013581118015613bae575060e086013515155b15613bc357613bc3633b4f091f60e21b613259565b610160860135600090815260a060205260409020613be6906101408801356140e5565b50610160860135600090815260a160205260408082208481558392600190910191613c179060608b01908b0161504c565b6001600160a01b03168152602081019190915260400160002055505050505050565b6000611acd836001600160a01b038416614077565b6000611acd836001600160a01b0384166142e8565b6000611acd836001600160a01b0384166143db565b6000612c4183838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613cfc9250613cc29150889050614425565b613cd0886101600135614540565b604051602001613ce1929190615db3565b60405160208183030381529060405280519060200120614555565b9061459c565b6001600160a01b03163b151590565b600054610100900460ff16613d385760405162461bcd60e51b8152600401611a2c90615dd9565b815160208084019190912082519183019190912060038290556004819055466002557f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f613d868184846145c0565b60015560055550505050565b600054610100900460ff16613db95760405162461bcd60e51b8152600401611a2c90615dd9565b606a80546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff16613e025760405162461bcd60e51b8152600401611a2c90615dd9565b61215f614609565b8265ffffffffffff16856080015165ffffffffffff16108015613e385750608085015165ffffffffffff1615155b80613e6e57508165ffffffffffff1685610100015165ffffffffffff16108015613e6e575061010085015165ffffffffffff1615155b80613ec6575042856020015165ffffffffffff16118015613e9a5750602085015165ffffffffffff1615155b80613ec65750846040015165ffffffffffff1642118015613ec65750604085015165ffffffffffff1615155b80613ed7575065ffffffffffff8416155b80613f0b57508460e0015165ffffffffffff168465ffffffffffff16118015613f0b575060e085015165ffffffffffff1615155b15613f2057613f2063072b86df60e21b613259565b600086815260a8602052604090205460011615613f4757613f47636be9245d60e11b613259565b613f7b8660001b8565ffffffffffff16838860c001518961012001516001600160c01b03168a606001518b6000015161393c565b845160405165ffffffffffff861681526001916001600160a01b0316908890600080516020615f4883398151915290602001612a7b565b613fbb81613d02565b61401d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401611a2c565b600080516020615f0183398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b61405583614639565b6000825111806140625750805b15611f3a576140718383614679565b50505050565b60009081526001919091016020526040902054151590565b6000612c4183838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613cfc92506140d9915088905061469e565b80519060200120614555565b6000611acd83836143db565b600080806001600160a01b038516614139573461410e8888615cff565b1461412357614123637e2897ef60e11b613259565b86156141345761413487858a6147cb565b61414c565b861561414c5761414c878532888c614883565b955095509592505050565b8715612143576001600160a01b038616156141e55760aa546040516323b872dd60e01b81526001600160a01b03808916926323b872dd926141a092329216908d90600401615e24565b6020604051808303816000875af11580156141bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141e39190615e48565b505b60aa54604051636f18e93f60e01b81526004810186905283151560248201526001600160a01b0387811660448301528881166064830152608482018b905289811660a483015283151560c48301526000921690636f18e93f90869060e40160206040518083038185885af1158015614261573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061428691906156d1565b905080156142dd57856001600160a01b0316876001600160a01b0316867f27dcd1d67ca97c55aa198d8494458949bbbddae9336ef0969fc655edb5d2180a846040516142d491815260200190565b60405180910390a45b505050505050505050565b600081815260018301602052604081205480156143d157600061430c600183615916565b855490915060009061432090600190615916565b9050818114614385576000866000018281548110614340576143406156ea565b9060005260206000200154905080876000018481548110614363576143636156ea565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061439657614396615e65565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611ad0565b6000915050611ad0565b60006143e78383614077565b61441d57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611ad0565b506000611ad0565b60607f75d70c323d802883252e6285d4bb7cc6fcb7faca7fe3ab1d9e9f260aaa4c3424614455602084018461504c565b614465604085016020860161504c565b614475606086016040870161504c565b614485608087016060880161504c565b608087013561449a60c0890160a08a01615ca0565b6040805160208101989098526001600160a01b03968716908801529385166060870152918416608086015290921660a084015260c0808401929092526001600160401b031660e080840191909152908401356101008084019190915290840135610120808401919091529084013561014080840191909152908401356101608301528301356101808201526101a0015b6040516020818303038152906040529050919050565b60608160405160200161452a91815260200190565b600061455f614953565b60405161190160f01b6020820152602281019190915260428101839052606201604051602081830303815290604052805190602001209050919050565b60008060006145ab8585614977565b915091506145b8816149bd565b509392505050565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b600054610100900460ff166146305760405162461bcd60e51b8152600401611a2c90615dd9565b61215f33613a1d565b61464281613fb2565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060611acd8383604051806060016040528060278152602001615f2160279139614b06565b60607faf2a8dc7de0e027b17ddbe873c600be814993ef395f58475bc9ef0408f7ccf166146ce602084018461504c565b6146de604085016020860161504c565b6146ee606086016040870161504c565b6146fe608087016060880161504c565b608087013561471360c0890160a08a01615ca0565b61472360e08a0160c08b01615ca0565b6147346101008b0160e08c01615ca0565b6147466101208c016101008d01615ca0565b60408051602081019b909b526001600160a01b03998a16908b015296881660608a015294871660808901529290951660a087015260c08601526001600160401b0393841660e08601528316610100850152821661012080850191909152911661014080840191909152908401356101608301528301356101808201526101a00161452a565b6000826001600160a01b03168460405160006040518083038185875af1925050503d8060008114614818576040519150601f19603f3d011682016040523d82523d6000602084013e61481d565b606091505b505090508061483657614836637cd69c3960e11b613259565b60408051858152612710602082015283916001600160a01b038616917f9363885e28e7ba67b096932f9f00dff44742731d6cb4fa26ccd4424e78e41e13910160405180910390a350505050565b6040516323b872dd60e01b81526001600160a01b038316906323b872dd906148b390869088908a90600401615e24565b6020604051808303816000875af11580156148d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148f69190615e48565b50604080516001600160a01b03858116825260208201889052612710828401529151839287811692908616917fc899cbcc4511003ff90131e8b89605738e9a7f4925273377ae479a673cf5038c9181900360600190a45050505050565b6000600254461415614966575060015490565b6132ce6005546003546004546145c0565b6000808251604114156149ae5760208301516040840151606085015160001a6149a287828585614b7e565b945094505050506149b6565b506000905060025b9250929050565b60008160048111156149d1576149d1615e7b565b14156149da5750565b60018160048111156149ee576149ee615e7b565b1415614a375760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b6044820152606401611a2c565b6002816004811115614a4b57614a4b615e7b565b1415614a995760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401611a2c565b6003816004811115614aad57614aad615e7b565b1415611ab25760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401611a2c565b6060600080856001600160a01b031685604051614b239190615e91565b600060405180830381855af49150503d8060008114614b5e576040519150601f19603f3d011682016040523d82523d6000602084013e614b63565b606091505b5091509150614b7486838387614c38565b9695505050505050565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b03831115614bab5750600090506003614c2f565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614bff573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614c2857600060019250925050614c2f565b9150600090505b94509492505050565b60608315614ca2578251614c9b57614c4f85613d02565b614c9b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611a2c565b5081612c41565b612c418383815115614cb75781518083602001fd5b8060405162461bcd60e51b8152600401611a2c9190615ead565b600060208284031215614ce357600080fd5b5035919050565b6001600160a01b03169052565b6001600160a01b0381168114611ab257600080fd5b8015158114611ab257600080fd5b60008083601f840112614d2c57600080fd5b5081356001600160401b03811115614d4357600080fd5b6020830191508360208260051b85010111156149b657600080fd5b60008060008060008060008060e0898b031215614d7a57600080fd5b8835614d8581614cf7565b97506020890135614d9581614d0c565b9650604089013595506060890135945060808901356001600160401b03811115614dbe57600080fd5b614dca8b828c01614d1a565b90955093505060a0890135614dde81614d0c565b915060c0890135614dee81614cf7565b809150509295985092959890939650565b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b0381118282101715614e3757614e37614dff565b60405290565b600082601f830112614e4e57600080fd5b81356001600160401b0380821115614e6857614e68614dff565b604051601f8301601f19908116603f01168101908282118183101715614e9057614e90614dff565b81604052838152866020858801011115614ea957600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060808688031215614ee157600080fd5b853594506020860135614ef381614cf7565b935060408601356001600160401b0380821115614f0f57600080fd5b614f1b89838a01614d1a565b90955093506060880135915080821115614f3457600080fd5b50614f4188828901614e3d565b9150509295509295909350565b65ffffffffffff81168114611ab257600080fd5b600080600060608486031215614f7757600080fd5b833592506020840135614f8981614f4e565b91506040840135614f9981614cf7565b809150509250925092565b60006101c08284031215614fb757600080fd5b50919050565b80356001600160801b0381168114614fd457600080fd5b919050565b6000806000806000858703610360811215614ff357600080fd5b863595506150048860208901614fa4565b94506101406101df198201121561501a57600080fd5b506101e08601925061032086013561503181614d0c565b91506150406103408701614fbd565b90509295509295909350565b60006020828403121561505e57600080fd5b813561506981614cf7565b9392505050565b6000806040838503121561508357600080fd5b50508035926020909101359150565b6000806000606084860312156150a757600080fd5b8335925060208401356150b981614d0c565b91506150c760408501614fbd565b90509250925092565b600080604083850312156150e357600080fd5b82356150ee81614cf7565b915060208301356001600160401b0381111561510957600080fd5b61511585828601614e3d565b9150509250929050565b6000806040838503121561513257600080fd5b82359150602083013561514481614d0c565b809150509250929050565b6000806040838503121561516257600080fd5b82359150602083013561514481614cf7565b60008060006060848603121561518957600080fd5b833561519481614cf7565b92506020840135614f8981614cf7565b60008083601f8401126151b657600080fd5b5081356001600160401b038111156151cd57600080fd5b6020830191508360208285010111156149b657600080fd5b6000806000806000808688036101c081121561520057600080fd5b6101608082121561521057600080fd5b88975087013590506001600160401b038082111561522d57600080fd5b6152398a838b016151a4565b9097509550610180890135915061524f82614cf7565b9093506101a0880135908082111561526657600080fd5b5061527389828a01614d1a565b979a9699509497509295939492505050565b60006101c0828403121561529857600080fd5b611acd8383614fa4565b60006101808284031215614fb757600080fd5b60008060008060006101e086880312156152ce57600080fd5b6152d887876152a2565b94506101808601356001600160401b038111156152f457600080fd5b615300888289016151a4565b9095509350506101a086013561531581614cf7565b91506101c086013561532681614d0c565b809150509295509295909350565b65ffffffffffff169052565b60006101c082019050615354828451614cea565b60208301516153666020840182615334565b5060408301516153796040840182615334565b50606083015161538c6060840182614cea565b50608083015161539f6080840182615334565b5060a08301516153b260a0840182615334565b5060c08301516153c560c0840182614cea565b5060e08301516153d860e0840182615334565b50610100808401516153ec82850182615334565b5050610120838101516001600160c01b0316908301526101408084015161541582850182615334565b505061016083810151151590830152610180808401511515908301526101a092830151929091019190915290565b6001600160a01b0391909116815260200190565b6001600160401b0391909116815260200190565b80356001600160601b0381168114614fd457600080fd5b60008060008084860361010081121561549a57600080fd5b60c08112156154a857600080fd5b506154b1614e15565b85356154bc81614cf7565b81526154ca6020870161546b565b602082015260408601356154dd81614cf7565b604082015260608601356154f081614d0c565b6060820152608086013561550381614d0c565b608082015260a086013561551681614d0c565b60a0820152935061552960c0860161546b565b925060e08501356001600160401b0381111561554457600080fd5b615550878288016151a4565b95989497509550505050565b6000806000806101c0858703121561557357600080fd5b61557d86866152a2565b93506101808501356001600160401b0381111561559957600080fd5b6155a5878288016151a4565b9094509250506101a08501356155ba81614cf7565b939692955090935050565b600080600080600060a086880312156155dd57600080fd5b85356155e881614cf7565b945060208601356155f881614cf7565b9350604086013561560881614cf7565b9250606086013561561881614cf7565b949793965091946080013592915050565b6000806000806080858703121561563f57600080fd5b84359350602085013561565181614cf7565b9250604085013563ffffffff8116811461566a57600080fd5b915060608501356001600160401b0381111561568557600080fd5b61569187828801614e3d565b91505092959194509250565b6000602082840312156156af57600080fd5b815161506981614cf7565b9182526001600160a01b0316602082015260400190565b6000602082840312156156e357600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b03929092168252602082015260400190565b81835260006001600160fb1b0383111561573257600080fd5b8260051b8083602087013760009401602001938452509192915050565b6001600160a01b03841681526040602082018190526000906157749083018486615719565b95945050505050565b602081526000612c41602083018486615719565b60005b838110156157ac578181015183820152602001615794565b838111156140715750506000910152565b600081518084526157d5816020860160208601615791565b601f01601f19169290920160200192915050565b8381526001600160a01b0383166020820152606060408201819052600090615774908301846157bd565b80516001600160a01b0390811683526020808301516001600160601b0316908401526040808301519091169083015260608082015115159083015260808082015115159083015260a0908101511515910152565b8781526001600160a01b03878116602083015261016060408301819052600091615894848301898b615719565b908716606085015290506158ab6080840186615813565b8281036101408401526158be81856157bd565b9a9950505050505050505050565b94855263ffffffff9390931660208501526001600160a01b0391821660408501528116606084015216608082015260a00190565b634e487b7160e01b600052601160045260246000fd5b60008282101561592857615928615900565b500390565b600065ffffffffffff80831681851680830382111561594e5761594e615900565b01949350505050565b60006020828403121561596957600080fd5b813561ffff8116811461506957600080fd5b60006020828403121561598d57600080fd5b813561506981614f4e565b6000602082840312156159aa57600080fd5b813560ff8116811461506957600080fd5b6001600160c01b0381168114611ab257600080fd5b6000602082840312156159e257600080fd5b8135615069816159bb565b6000602082840312156159ff57600080fd5b813561506981614d0c565b6020808252602c90820152600080516020615ee183398151915260408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c90820152600080516020615ee183398151915260408201526b6163746976652070726f787960a01b606082015260800190565b6000600019821415615a9257615a92615900565b5060010190565b60008135611ad081614cf7565b60008135611ad081614f4e565b60008135611ad0816159bb565b60008135611ad081614d0c565b615af6615ad983615a99565b82546001600160a01b0319166001600160a01b0391909116178255565b615b2d615b0560208401615aa6565b82805465ffffffffffff60a01b191660a09290921b65ffffffffffff60a01b16919091179055565b615b60615b3c60408401615aa6565b8280546001600160d01b031660d09290921b6001600160d01b031916919091179055565b60018101615b73615ad960608501615a99565b615b82615b0560808501615aa6565b615b91615b3c60a08501615aa6565b5060028101615ba5615ad960c08501615a99565b615bb4615b0560e08501615aa6565b615bc4615b3c6101008501615aa6565b5060038101615bf6615bd96101208501615ab3565b82546001600160c01b0319166001600160c01b0391909116178255565b615c2e615c066101408501615aa6565b82805465ffffffffffff60c01b191660c09290921b65ffffffffffff60c01b16919091179055565b615c5c615c3e6101608501615ac0565b82805460ff60f01b191691151560f01b60ff60f01b16919091179055565b615c90615c6c6101808501615ac0565b8280546001600160f81b031691151560f81b6001600160f81b031916919091179055565b506101a082013560048201555050565b600060208284031215615cb257600080fd5b81356001600160401b038116811461506957600080fd5b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b60008219821115615d1257615d12615900565b500190565b8681526001600160a01b03868116602083015263ffffffff86166040830152841660608201526000610160615d4f6080840186615813565b80610140840152615d62818401856157bd565b9998505050505050505050565b60008060408385031215615d8257600080fd5b82519150602083015161514481614d0c565b6000816000190483118215151615615dae57615dae615900565b500290565b60008351615dc5818460208801615791565b83519083019061594e818360208801615791565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600060208284031215615e5a57600080fd5b815161506981614d0c565b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b60008251615ea3818460208701615791565b9190910192915050565b602081526000611acd60208301846157bd56fee0bf8a4af82e2af496af5f4957e2767f8b52e51a77caedd2f30a1843872d1b7c46756e6374696f6e206d7573742062652063616c6c6564207468726f75676820360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564981414aed4973b05aa301314dc13a5a4077f24490497b98bc270852581c1c578aaca5cb46300e4b20595b143bc883119e775ef88ff77f45fa989ca323576f06ba164736f6c634300080a000a
Deployed Bytecode
0x6080604052600436106101895760003560e01c8063041050181461018e57806306056f831461024f5780630dbb18a1146102645780631d9165aa1461029f57806323bc2078146102b25780632cf9adc8146102c55780633659cfe6146102e55780633716e28414610305578063391a6d28146103355780634f1ef2861461035557806352169be81461036857806352d1902d14610388578063532742461461039d57806356292ab5146103e4578063572b6c0514610404578063619b8589146104335780636c1b7abd14610551578063715018a61461056457806377a856ea146105795780637ced595c146105995780637e5811fc146105ac5780638a320d64146105cc5780638da5cb5b146109bc5780639e2dc500146109de578063a0f7652314610a2c578063b052d17c14610a85578063b414ae2f14610aa5578063c462507e14610ad2578063e28be14414610b39578063e2f66b1e14610b59578063f2fde38b14610b79578063f4a4034514610b99578063f7013ef614610bb9578063fc2c997114610bd9575b600080fd5b34801561019a57600080fd5b506101ff6101a9366004614cd1565b60a960205260009081526040902080546001909101546001600160a01b03808316926001600160601b03600160a01b9182900416929182169160ff918104821691600160a81b8204811691600160b01b90041686565b604080516001600160a01b0397881681526001600160601b039096166020870152959093169484019490945215156060830152911515608082015290151560a082015260c0015b60405180910390f35b61026261025d366004614d5e565b610bec565b005b34801561027057600080fd5b5061029161027f366004614cd1565b60a16020526000908152604090205481565b604051908152602001610246565b6102626102ad366004614ec9565b610f56565b6102626102c0366004614f62565b61132d565b3480156102d157600080fd5b506102626102e0366004614fd9565b611533565b3480156102f157600080fd5b5061026261030036600461504c565b6119e3565b34801561031157600080fd5b50610325610320366004615070565b611ab5565b6040519015158152602001610246565b34801561034157600080fd5b50610262610350366004615092565b611ad6565b6102626103633660046150d0565b611be5565b34801561037457600080fd5b5061026261038336600461511f565b611c9f565b34801561039457600080fd5b50610291611dd4565b3480156103a957600080fd5b506102916103b836600461514f565b600082815260a1602090815260408083206001600160a01b038516845260010190915290205492915050565b3480156103f057600080fd5b506102626103ff366004615174565b611e82565b34801561041057600080fd5b5061032561041f36600461504c565b606a546001600160a01b0391821691161490565b34801561043f57600080fd5b506104d361044e366004614cd1565b609d602052600090815260409020805460018201546002830154600384015460048501546005860154600687015460078801546008909801546001600160a01b039788169896881697909516959394929391926001600160401b0380831693600160401b8404821693600160801b8104831693600160c01b9091049092169160ff168c565b604080516001600160a01b039d8e1681529b8d1660208d015299909b16988a01989098526060890196909652608088019490945260a08701929092526001600160401b0390811660c087015290811660e08601529081166101008501521661012083015261014082015260ff90911661016082015261018001610246565b61026261055f3660046151e5565b611f3f565b34801561057057600080fd5b5061026261214d565b34801561058557600080fd5b50610262610594366004615285565b612161565b6102626105a73660046152b5565b61233f565b3480156105b857600080fd5b506102626105c7366004614cd1565b612671565b3480156105d857600080fd5b506109af6105e7366004614cd1565b604080516101c081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a0810191909152600060a76000848152602001908152602001600020604051806101c00160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016000820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160008201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160018201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016002820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016002820160149054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160028201601a9054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff1681526020016003820160009054906101000a90046001600160c01b03166001600160c01b03166001600160c01b031681526020016003820160189054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815260200160038201601e9054906101000a900460ff1615151515815260200160038201601f9054906101000a900460ff161515151581526020016004820154815250509050604051806101c0016040528082600001516001600160a01b03168152602001826020015165ffffffffffff168152602001826040015165ffffffffffff16815260200182606001516001600160a01b03168152602001826080015165ffffffffffff1681526020018260a0015165ffffffffffff1681526020018260c001516001600160a01b031681526020018260e0015165ffffffffffff16815260200182610100015165ffffffffffff1681526020018261012001516001600160c01b0316815260200182610140015165ffffffffffff1681526020018261016001511515815260200182610180015115158152602001826101a00151815250915050919050565b6040516102469190615340565b3480156109c857600080fd5b506109d161270b565b6040516102469190615443565b3480156109ea57600080fd5b50610a1f6109f936600461514f565b609f6020908152600092835260408084209091529082529020546001600160401b031681565b6040516102469190615457565b348015610a3857600080fd5b50610a66610a47366004614cd1565b600090815260a860205260409020546001811615159160809190911c90565b6040805192151583526001600160801b03909116602083015201610246565b348015610a9157600080fd5b50610262610aa036600461504c565b61271a565b348015610ab157600080fd5b50610291610ac0366004614cd1565b60a26020526000908152604090205481565b348015610ade57600080fd5b50610b15610aed366004614cd1565b609e6020526000908152604090205460ff808216916101008104821691620100009091041683565b6040805160ff94851681529284166020840152921691810191909152606001610246565b348015610b4557600080fd5b50610262610b54366004615482565b612766565b348015610b6557600080fd5b50610325610b7436600461504c565b612a8b565b348015610b8557600080fd5b50610262610b9436600461504c565b612a98565b348015610ba557600080fd5b50610325610bb436600461555c565b612b0e565b348015610bc557600080fd5b50610262610bd43660046155c5565b612c49565b610262610be7366004615629565b612dea565b33838015610bf8578096505b816001600160a01b03168a6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c64919061569d565b6001600160a01b03161480610c8a5750896001600160a01b0316826001600160a01b0316145b15610f3b578815610d51578660011415610d155760405163b859c93560e01b81526001600160a01b038b169063b859c93590610ccc908b9087906004016156ba565b6020604051808303816000875af1158015610ceb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d0f91906156d1565b50610ea1565b604051631b30808d60e01b8152600481018990526001600160a01b038481166024830152604482018990528b1690631b30808d90606401610ccc565b8660011415610e0a578315610dde57896001600160a01b0316630d640e818488886000818110610d8357610d836156ea565b905060200201356040518363ffffffff1660e01b8152600401610da7929190615700565b600060405180830381600087803b158015610dc157600080fd5b505af1158015610dd5573d6000803e3d6000fd5b50505050610ea1565b60405163184a94d560e01b81526001600160a01b038b169063184a94d590610ccc908690600401615443565b8315610e4057604051636371fbe760e01b81526001600160a01b038b1690636371fbe790610da79086908a908a9060040161574f565b604051630b7d2a8960e31b81526001600160a01b038b1690635be9544890610e6e9086908b90600401615700565b600060405180830381600087803b158015610e8857600080fd5b505af1158015610e9c573d6000803e3d6000fd5b505050505b8315610eef57896001600160a01b03167f4e84cd8521d66b0c0a2d95e21910942e1616948e140df953825b0cb02c32a5e98787604051610ee292919061577d565b60405180910390a2610f4a565b878915158b6001600160a01b03167f4c0491da007181c9465d71c51f64ba4f8eb23133900a4bb2dae027b0c2252c3f8a604051610f2e91815260200190565b60405180910390a4610f4a565b610f4a6282b42960e81b613259565b50505050505050505050565b600085815260a96020908152604091829020825160c08101845281546001600160a01b0380821683526001600160601b03600160a01b9283900416948301949094526001909201549283169381019390935260ff908204811615156060840152600160a81b8204811615156080840152600160b01b9091041615801560a08301523390610fed57610fed6337e9321960e21b613259565b816080015161100657611006633bed786f60e21b613259565b60ab54604083015185916001600160a01b03918216911614156110e45761102c82613263565b6110405761104063ac3274ef60e01b613259565b82604001516001600160a01b031663c4804ce28989898987896110616132c5565b6110696132d3565b8d60405160200161107c939291906157e9565b6040516020818303038152906040526040518863ffffffff1660e01b81526004016110ad9796959493929190615867565b600060405180830381600087803b1580156110c757600080fd5b505af11580156110db573d6000803e3d6000fd5b505050506111f7565b60aa5460408085015185519151634b48652b60e11b81526000936001600160a01b031692639690ca5692611122928e928892918a91906004016158cc565b602060405180830381865afa15801561113f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116391906156d1565b90508034101561117d5761117d63207226af60e01b613259565b60408401516001600160a01b031663c4804ce261119a8334615916565b8b8b8b8b898b8d6040518963ffffffff1660e01b81526004016111c39796959493929190615867565b6000604051808303818588803b1580156111dc57600080fd5b505af11580156111f0573d6000803e3d6000fd5b5050505050505b8063ffffffff16600114156112835782516001600160a01b0316630d640e81888888600081611228576112286156ea565b905060200201356040518363ffffffff1660e01b815260040161124c929190615700565b600060405180830381600087803b15801561126657600080fd5b505af115801561127a573d6000803e3d6000fd5b505050506112e9565b8251604051636371fbe760e01b81526001600160a01b0390911690636371fbe7906112b6908a908a908a9060040161574f565b600060405180830381600087803b1580156112d057600080fd5b505af11580156112e4573d6000803e3d6000fd5b505050505b6001151583600001516001600160a01b031689600080516020615ec1833981519152898960405161131b92919061577d565b60405180910390a45050505050505050565b600033600085815260a76020908152604080832081516101c08101835281546001600160a01b03808216835265ffffffffffff600160a01b808404821697850197909752600160d01b928390048116958401959095526001840154808216606085015286810486166080850152829004851660a08401819052600285015491821660c0850152958104851660e084015204831661010082015260038201546001600160c01b038116610120830152600160c01b810490931661014082015260ff600160f01b840481161515610160830152600160f81b9093049092161515610180830152600401546101a082015292935061142990869061592d565b6000878152609f602090815260408083206001600160a01b0389168452909152812054919250906114649087906001600160401b031661592d565b9050826101800151801561148157506001600160a01b0384163214155b1561149657611496630977d34b60e01b613259565b600087815260a760209081526040808320600101805465ffffffffffff808816600160d01b026001600160d01b0390921691909117909155609f83528184206001600160a01b038a16855290925290912080546001600160401b0319169183169190911790556101608301511561151b57611516878488888887876132df565b61152a565b61152a87848888888787613414565b50505050505050565b600085815260a760205260408120546001600160a01b031690339050806001600160a01b0316826001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611597573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115bb919061569d565b6001600160a01b031614806115e15750816001600160a01b0316816001600160a01b0316145b156119d45760006115f56020870187615957565b61ffff1611156116455761160f604087016020880161597b565b600088815260a760205260409020805465ffffffffffff92909216600160a01b0265ffffffffffff60a01b199092169190911790555b60006116576040870160208801615957565b61ffff1611156116a457611671606087016040880161597b565b600088815260a760205260409020805465ffffffffffff92909216600160d01b026001600160d01b039092169190911790555b60006116b66060870160408801615957565b61ffff161115611700576116d0608087016060880161504c565b600088815260a76020526040902060010180546001600160a01b0319166001600160a01b03929092169190911790555b60006117126080870160608801615957565b61ffff1611156117655761172c60a087016080880161597b565b600088815260a760205260409020600101805465ffffffffffff92909216600160a01b0265ffffffffffff60a01b199092169190911790555b600061177760a0870160808801615957565b61ffff1611156117cb57611792610100870160e0880161597b565b600088815260a760205260409020600201805465ffffffffffff92909216600160a01b0265ffffffffffff60a01b199092169190911790555b60006117dd60c0870160a08801615957565b61ffff16111561182f576117f96101208701610100880161597b565b600088815260a760205260409020600201805465ffffffffffff92909216600160d01b026001600160d01b039092169190911790555b600061184160e0870160c08801615998565b60ff16111561188c5761185c610140870161012088016159d0565b600088815260a76020526040902060030180546001600160c01b0319166001600160c01b03929092169190911790555b600061189f610100870160e08801615998565b60ff1611156118e8576118b860e0870160c0880161504c565b600088815260a76020526040902060020180546001600160a01b0319166001600160a01b03929092169190911790555b60006118fc61012087016101008801615998565b60ff161115611945576119176101a0870161018088016159ed565b600088815260a7602052604090206003018054911515600160f81b026001600160f81b039092169190911790555b600061195961014087016101208801615998565b60ff1611156119a45761196c84846134d7565b600088815260a860205260408082209290925590516001600160801b03851691861515918a91600080516020615f6883398151915291a45b60405187907fe772ce44f6b7edf20d62f174efc62c5a18484d62a710bd48d57af1afd140811c90600090a261152a565b61152a6282b42960e81b613259565b306001600160a01b037f0000000000000000000000009acdfe8020c3c191f7aa158e1c155f12e55c9717161415611a355760405162461bcd60e51b8152600401611a2c90615a0a565b60405180910390fd5b7f0000000000000000000000009acdfe8020c3c191f7aa158e1c155f12e55c97176001600160a01b0316611a676134fc565b6001600160a01b031614611a8d5760405162461bcd60e51b8152600401611a2c90615a44565b611a9681613518565b60408051600080825260208201909252611ab291839190613520565b50565b600082815260a060205260408120611acd908361368b565b90505b92915050565b600083815260a760205260408120546001600160a01b031690339050806001600160a01b0316826001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b5e919061569d565b6001600160a01b03161480611b845750816001600160a01b0316816001600160a01b0316145b15611bcf57611b9384846134d7565b600086815260a860205260408082209290925590516001600160801b03851691861515918891600080516020615f6883398151915291a4611bde565b611bde6282b42960e81b613259565b5050505050565b306001600160a01b037f0000000000000000000000009acdfe8020c3c191f7aa158e1c155f12e55c9717161415611c2e5760405162461bcd60e51b8152600401611a2c90615a0a565b7f0000000000000000000000009acdfe8020c3c191f7aa158e1c155f12e55c97176001600160a01b0316611c606134fc565b6001600160a01b031614611c865760405162461bcd60e51b8152600401611a2c90615a44565b611c8f82613518565b611c9b82826001613520565b5050565b600082815260a9602052604090205433906001600160a01b031680611cce57611cce633bed786f60e21b613259565b816001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3a919061569d565b6001600160a01b03161480611d605750806001600160a01b0316826001600160a01b0316145b15611d9057600084815260a960205260409020600101805460ff60b01b1916600160b01b85151502179055611d9f565b611d9f6282b42960e81b613259565b6040518315159085907fa5a0d9b368dd777972caaaa919c8ca3243792928d90f1b032a1bab6b243a73ab90600090a350505050565b6000306001600160a01b037f0000000000000000000000009acdfe8020c3c191f7aa158e1c155f12e55c97171614611e6f5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b6064820152608401611a2c565b50600080516020615f0183398151915290565b611e8a613697565b6001600160a01b038316611ea757611ea76282b42960e81b613259565b609c546001600160a01b03848116911614611ed857609c80546001600160a01b0319166001600160a01b0385161790555b60aa546001600160a01b03838116911614611f095760aa80546001600160a01b0319166001600160a01b0384161790555b60ab546001600160a01b03828116911614611f3a5760ab80546001600160a01b0319166001600160a01b0383161790555b505050565b338181611f5260608a0160408b0161504c565b6001600160a01b031614158015611f8a5750611f746060890160408a0161504c565b6001600160a01b0316856001600160a01b031614155b15611f9f57611f9f6343d0477760e01b613259565b611fab888888846136f6565b611ff36101408901358284611fc360208d018d61504c565b8c608001358d6060016020810190611fdb919061504c565b8e6020016020810190611fee919061504c565b61393c565b600061200560408a0160208b0161504c565b6001600160a01b0316896101400135600080516020615ec1833981519152878760405161203392919061577d565b60405180910390a480600114156120d1576120546040890160208a0161504c565b6001600160a01b0316630d640e818686866000818110612076576120766156ea565b905060200201356040518363ffffffff1660e01b815260040161209a929190615700565b600060405180830381600087803b1580156120b457600080fd5b505af11580156120c8573d6000803e3d6000fd5b50505050612143565b6120e16040890160208a0161504c565b6001600160a01b0316636371fbe78686866040518463ffffffff1660e01b81526004016121109392919061574f565b600060405180830381600087803b15801561212a57600080fd5b505af115801561213e573d6000803e3d6000fd5b505050505b5050505050505050565b612155613697565b61215f6000613a1d565b565b3380612170602084018461504c565b6001600160a01b0316148061220357506001600160a01b038116612197602084018461504c565b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f8919061569d565b6001600160a01b0316145b1561233057600061221a60c0840160a0850161597b565b65ffffffffffff1611156122385761223863875fc25f60e01b613259565b60a3805490600061224883615a7e565b909155505060a354600090815260a760205260409020829061226a8282615acd565b5061227f9050610180830161016084016159ed565b156122e757612291602083018361504c565b6001600160a01b03166122ac6101608401610140850161597b565b65ffffffffffff1660a3547fa712e8b25b3d4d043988e80f0a4087773b1c7e29e4115a4256e86aebe91c9be960405160405180910390a45050565b6122f4602083018361504c565b6001600160a01b031660a3547f7258df9bfe0a9fb9cf1285396575e6472f56ca38b4851afcb725c82726fd67ff60405160405180910390a35050565b611c9b6282b42960e81b613259565b3380612351606088016040890161504c565b6001600160a01b0316141580156123895750612373606087016040880161504c565b6001600160a01b0316836001600160a01b031614155b1561239e5761239e6343d0477760e01b613259565b6123a9868686613a6f565b6123fd6101608701356123c260c0890160a08a01615ca0565b6001600160401b0316836123d960208b018b61504c565b60808b018035906123ed9060608e0161504c565b611fee60408e0160208f0161504c565b600061240f604088016020890161504c565b6001600160a01b0316610160880135600080516020615f4883398151915261243d60c08b0160a08c01615ca0565b60405161244a9190615457565b60405180910390a4811561257b5761246860c0870160a08801615ca0565b6001600160401b03166001141561250457612489604087016020880161504c565b6001600160a01b031663b859c935876101000135856040518363ffffffff1660e01b81526004016124bb9291906156ba565b6020604051808303816000875af11580156124da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124fe91906156d1565b50612669565b612514604087016020880161504c565b6001600160a01b0316631b30808d6101008801358561253960c08b0160a08c01615ca0565b6040516001600160e01b031960e086901b16815260048101939093526001600160a01b0390911660248301526001600160401b031660448201526064016124bb565b61258b60c0870160a08801615ca0565b6001600160401b0316600114156125d7576125ac604087016020880161504c565b6001600160a01b031663184a94d5846040518263ffffffff1660e01b81526004016124bb9190615443565b6125e7604087016020880161504c565b6001600160a01b0316635be954488461260660c08a0160a08b01615ca0565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526001600160401b03166024820152604401600060405180830381600087803b15801561265557600080fd5b505af1158015610f4a573d6000803e3d6000fd5b505050505050565b609c546001600160a01b0316336001600160a01b03161461269b5761269b6282b42960e81b613259565b609c5460405160009182916001600160a01b039091169084908381818185875af1925050503d80600081146126ec576040519150601f19603f3d011682016040523d82523d6000602084013e6126f1565b606091505b509150915081611f3a57611f3a637cd69c3960e11b613259565b6038546001600160a01b031690565b612722613697565b6001600160a01b038116612740576127406340f3a16b60e01b613259565b61274b60a482613c39565b1561275b57611c9b60a482613c4e565b611c9b60a482613c63565b83516020808601516040808801516060808a015183516001600160601b031997831b8816818801526001600160a01b031960a096871b811660348301529390921b9096168184015294151560f81b60548601529187901b90911660558401528051808403604101815260619093019052815191012084513391906001600160a01b031682148061286c5750816001600160a01b031686600001516001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561283d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612861919061569d565b6001600160a01b0316145b1561299a57600081815260a960205260409020546001600160a01b03161561289e5761289e63250675bd60e21b613259565b85516001600160a01b031615806128c0575060408601516001600160a01b0316155b806128d85750856060015180156128d8575085608001515b806128e1575080155b156128f6576128f6633bed786f60e21b613259565b600060a0870181815282825260a960209081526040928390208951918a01516001600160a01b03928316600160a01b6001600160601b039092168202178255938a01516001909101805460608c015160808d01519551939094166001600160a81b0319909116179215159094029190911761ffff60a81b1916600160a81b9215159290920260ff60b01b191691909117600160b01b911515919091021790556129a9565b6129a96282b42960e81b613259565b85604001516001600160a01b0316631a8d37928286866040518463ffffffff1660e01b81526004016129dd93929190615cc9565b600060405180830381600087803b1580156129f757600080fd5b505af1158015612a0b573d6000803e3d6000fd5b5050505085600001516001600160a01b031686604001516001600160a01b0316827f6ec667d7188a57a345b217226db199b2b1e98d2ccdb2eaa555af7ad19324303789602001518a60600151604051612a7b9291906001600160601b039290921682521515602082015260400190565b60405180910390a4505050505050565b6000611ad060a483613c39565b612aa0613697565b6001600160a01b038116612b055760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401611a2c565b611ab281613a1d565b600080612b1c868686613c78565b9050612b2960a482613c39565b8015612b555750610160860135600090815260a060205260409020612b539061014088013561368b565b155b8015612b6657508561012001354211155b8015612bb9575060c08601351580612bb95750610160860135600090815260a1602052604090205460c0870180359190612ba39060a08a01615ca0565b6001600160401b0316612bb69190615cff565b11155b8015612c3d575060e08601351580612c3d5750610160860135600090815260a1602052604080822060e089013592600190910191612bfd9060608b01908b0161504c565b6001600160a01b03168152602081019190915260400160002054612c2760c0890160a08a01615ca0565b6001600160401b0316612c3a9190615cff565b11155b9150505b949350505050565b600054610100900460ff1615808015612c695750600054600160ff909116105b80612c8a5750612c7830613d02565b158015612c8a575060005460ff166001145b612ced5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401611a2c565b6000805460ff191660011790558015612d10576000805461ff0019166101001790555b609c80546001600160a01b0319166001600160a01b038816179055604080518082018252600b81526a26b4b73a26b0b730b3b2b960a91b602080830191909152825180840190935260058352640312e302e360dc1b90830152612d7291613d11565b612d7b84613d92565b612d83613ddb565b612d8c85613a1d565b612d9760a484613c63565b5060a68290558015612669576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b600084815260a96020908152604091829020825160c08101845281546001600160a01b0380821683526001600160601b03600160a01b9283900416948301949094526001909201549283169381019390935260ff908204811615156060840152600160a81b8204811615156080840152600160b01b9091041615801560a08301523390612e8157612e816337e9321960e21b613259565b816080015115612e9b57612e9b633bed786f60e21b613259565b60ab5460408301516001600160a01b0390811691161415612f7557612ebf81613263565b612ed357612ed363ac3274ef60e01b613259565b81604001516001600160a01b0316639cc163e58787878587612ef36132c5565b612efb6132d3565b8b604051602001612f0e939291906157e9565b6040516020818303038152906040526040518763ffffffff1660e01b8152600401612f3e96959493929190615d17565b600060405180830381600087803b158015612f5857600080fd5b505af1158015612f6c573d6000803e3d6000fd5b50505050613086565b60aa5460408084015184519151634b48652b60e11b81526000936001600160a01b031692639690ca5692612fb3928c928b92918991906004016158cc565b602060405180830381865afa158015612fd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ff491906156d1565b90508034101561300e5761300e63207226af60e01b613259565b60408301516001600160a01b0316639cc163e561302b8334615916565b89898987898b6040518863ffffffff1660e01b815260040161305296959493929190615d17565b6000604051808303818588803b15801561306b57600080fd5b505af115801561307f573d6000803e3d6000fd5b5050505050505b81606001511561317c578363ffffffff166001141561312a578151602083015160405163b859c93560e01b81526001600160601b0390911660048201526001600160a01b0387811660248301529091169063b859c935906044015b6020604051808303816000875af1158015613100573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061312491906156d1565b50613224565b81516020830151604051631b30808d60e01b81526001600160601b0390911660048201526001600160a01b03878116602483015263ffffffff8716604483015290911690631b30808d906064016130e1565b8363ffffffff16600114156131ba57815160405163184a94d560e01b81526001600160a01b039091169063184a94d5906130e1908890600401615443565b8151604051630b7d2a8960e31b81526001600160a01b0390911690635be95448906131f190889063ffffffff891690600401615700565b600060405180830381600087803b15801561320b57600080fd5b505af115801561321f573d6000803e3d6000fd5b505050505b815160405163ffffffff861681526001916001600160a01b0316908890600080516020615f4883398151915290602001612a7b565b8060005260046000fd5b6000466101441480613276575046610118145b61329f576001600160a01b03821673abcc9b596420a9e9172fd5938620e265a0f9df9214611ad0565b6001600160a01b03821673b16a1dbe755f992636705fdbb3a8678a657eb3ea1492915050565b601f1936013590565b905090565b60471936013560601c90565b6132ed878787858588613e0a565b8465ffffffffffff166001141561338957855161014087015160405163b859c93560e01b815265ffffffffffff90911660048201526001600160a01b0386811660248301529091169063b859c935906044015b6020604051808303816000875af115801561335f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061338391906156d1565b5061152a565b8551610140870151604051631b30808d60e01b815265ffffffffffff91821660048201526001600160a01b0387811660248301529188166044820152911690631b30808d906064016020604051808303816000875af11580156133f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061214391906156d1565b613422878787858588613e0a565b8465ffffffffffff166001141561346257855160405163184a94d560e01b81526001600160a01b039091169063184a94d590613340908790600401615443565b8551604051630b7d2a8960e31b81526001600160a01b03868116600483015265ffffffffffff8816602483015290911690635be9544890604401600060405180830381600087803b1580156134b657600080fd5b505af11580156134ca573d6000803e3d6000fd5b5050505050505050505050565b60008083156134e4576001175b6001600160801b0319608084901b1617905092915050565b600080516020615f01833981519152546001600160a01b031690565b611ab2613697565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561355357611f3a83613fb2565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156135ad575060408051601f3d908101601f191682019092526135aa918101906156d1565b60015b6136105760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401611a2c565b600080516020615f01833981519152811461367f5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401611a2c565b50611f3a83838361404c565b6000611acd8383614077565b336136a061270b565b6001600160a01b03161461215f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611a2c565b600061370385858561408f565b610140860135600090815260a1602052604081205491925090613727908490615cff565b905060008360a160008961014001358152602001908152602001600020600101600089604001602081019061375c919061504c565b6001600160a01b03166001600160a01b03168152602001908152602001600020546137879190615cff565b905061379460a484613c39565b15806137d957506137ab60c0880160a08901615ca0565b6001600160401b0316841180156137d957506137cd60c0880160a08901615ca0565b6001600160401b031615155b806138025750610140870135600090815260a0602052604090206138029061012089013561368b565b80613826575061381a61012088016101008901615ca0565b6001600160401b031642115b8061386a575061383c60e0880160c08901615ca0565b6001600160401b03168211801561386a575061385e60e0880160c08901615ca0565b6001600160401b031615155b806138b05750613881610100880160e08901615ca0565b6001600160401b0316811180156138b057506138a4610100880160e08901615ca0565b6001600160401b031615155b156138c5576138c5633b4f091f60e21b613259565b610140870135600090815260a0602052604090206138e8906101208901356140e5565b50610140870135600090815260a1602052604080822084815583926001909101916139199060608c01908c0161504c565b6001600160a01b0316815260208101919091526040016000205550505050505050565b60aa546040516376c1989360e01b815260048101899052602481018890526001600160a01b0387811660448301528681166064830152838116608483015260009283929116906376c198939060a4016040805180830381865afa1580156139a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139cb9190615d6f565b909250905060006001600160a01b038716156139e85760006139ea565b825b905060006139f8878b615d94565b9050613a078b82848b8a6140f1565b5050506134ca848a8a898f878d6000148a614157565b603880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000613a7c848484613c78565b90506000613a9060c0860160a08701615ca0565b610160860135600090815260a16020526040902054613ab8916001600160401b031690615cff565b90506000613acc60c0870160a08801615ca0565b6001600160401b031660a1600088610160013581526020019081526020016000206001016000886040016020810190613b05919061504c565b6001600160a01b03166001600160a01b0316815260200190815260200160002054613b309190615cff565b9050613b3d60a484613c39565b1580613b675750610160860135600090815260a060205260409020613b679061014088013561368b565b80613b76575085610120013542115b80613b9257508560c0013582118015613b92575060c086013515155b80613bae57508560e0013581118015613bae575060e086013515155b15613bc357613bc3633b4f091f60e21b613259565b610160860135600090815260a060205260409020613be6906101408801356140e5565b50610160860135600090815260a160205260408082208481558392600190910191613c179060608b01908b0161504c565b6001600160a01b03168152602081019190915260400160002055505050505050565b6000611acd836001600160a01b038416614077565b6000611acd836001600160a01b0384166142e8565b6000611acd836001600160a01b0384166143db565b6000612c4183838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613cfc9250613cc29150889050614425565b613cd0886101600135614540565b604051602001613ce1929190615db3565b60405160208183030381529060405280519060200120614555565b9061459c565b6001600160a01b03163b151590565b600054610100900460ff16613d385760405162461bcd60e51b8152600401611a2c90615dd9565b815160208084019190912082519183019190912060038290556004819055466002557f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f613d868184846145c0565b60015560055550505050565b600054610100900460ff16613db95760405162461bcd60e51b8152600401611a2c90615dd9565b606a80546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff16613e025760405162461bcd60e51b8152600401611a2c90615dd9565b61215f614609565b8265ffffffffffff16856080015165ffffffffffff16108015613e385750608085015165ffffffffffff1615155b80613e6e57508165ffffffffffff1685610100015165ffffffffffff16108015613e6e575061010085015165ffffffffffff1615155b80613ec6575042856020015165ffffffffffff16118015613e9a5750602085015165ffffffffffff1615155b80613ec65750846040015165ffffffffffff1642118015613ec65750604085015165ffffffffffff1615155b80613ed7575065ffffffffffff8416155b80613f0b57508460e0015165ffffffffffff168465ffffffffffff16118015613f0b575060e085015165ffffffffffff1615155b15613f2057613f2063072b86df60e21b613259565b600086815260a8602052604090205460011615613f4757613f47636be9245d60e11b613259565b613f7b8660001b8565ffffffffffff16838860c001518961012001516001600160c01b03168a606001518b6000015161393c565b845160405165ffffffffffff861681526001916001600160a01b0316908890600080516020615f4883398151915290602001612a7b565b613fbb81613d02565b61401d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401611a2c565b600080516020615f0183398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b61405583614639565b6000825111806140625750805b15611f3a576140718383614679565b50505050565b60009081526001919091016020526040902054151590565b6000612c4183838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613cfc92506140d9915088905061469e565b80519060200120614555565b6000611acd83836143db565b600080806001600160a01b038516614139573461410e8888615cff565b1461412357614123637e2897ef60e11b613259565b86156141345761413487858a6147cb565b61414c565b861561414c5761414c878532888c614883565b955095509592505050565b8715612143576001600160a01b038616156141e55760aa546040516323b872dd60e01b81526001600160a01b03808916926323b872dd926141a092329216908d90600401615e24565b6020604051808303816000875af11580156141bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141e39190615e48565b505b60aa54604051636f18e93f60e01b81526004810186905283151560248201526001600160a01b0387811660448301528881166064830152608482018b905289811660a483015283151560c48301526000921690636f18e93f90869060e40160206040518083038185885af1158015614261573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061428691906156d1565b905080156142dd57856001600160a01b0316876001600160a01b0316867f27dcd1d67ca97c55aa198d8494458949bbbddae9336ef0969fc655edb5d2180a846040516142d491815260200190565b60405180910390a45b505050505050505050565b600081815260018301602052604081205480156143d157600061430c600183615916565b855490915060009061432090600190615916565b9050818114614385576000866000018281548110614340576143406156ea565b9060005260206000200154905080876000018481548110614363576143636156ea565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061439657614396615e65565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611ad0565b6000915050611ad0565b60006143e78383614077565b61441d57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611ad0565b506000611ad0565b60607f75d70c323d802883252e6285d4bb7cc6fcb7faca7fe3ab1d9e9f260aaa4c3424614455602084018461504c565b614465604085016020860161504c565b614475606086016040870161504c565b614485608087016060880161504c565b608087013561449a60c0890160a08a01615ca0565b6040805160208101989098526001600160a01b03968716908801529385166060870152918416608086015290921660a084015260c0808401929092526001600160401b031660e080840191909152908401356101008084019190915290840135610120808401919091529084013561014080840191909152908401356101608301528301356101808201526101a0015b6040516020818303038152906040529050919050565b60608160405160200161452a91815260200190565b600061455f614953565b60405161190160f01b6020820152602281019190915260428101839052606201604051602081830303815290604052805190602001209050919050565b60008060006145ab8585614977565b915091506145b8816149bd565b509392505050565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b600054610100900460ff166146305760405162461bcd60e51b8152600401611a2c90615dd9565b61215f33613a1d565b61464281613fb2565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060611acd8383604051806060016040528060278152602001615f2160279139614b06565b60607faf2a8dc7de0e027b17ddbe873c600be814993ef395f58475bc9ef0408f7ccf166146ce602084018461504c565b6146de604085016020860161504c565b6146ee606086016040870161504c565b6146fe608087016060880161504c565b608087013561471360c0890160a08a01615ca0565b61472360e08a0160c08b01615ca0565b6147346101008b0160e08c01615ca0565b6147466101208c016101008d01615ca0565b60408051602081019b909b526001600160a01b03998a16908b015296881660608a015294871660808901529290951660a087015260c08601526001600160401b0393841660e08601528316610100850152821661012080850191909152911661014080840191909152908401356101608301528301356101808201526101a00161452a565b6000826001600160a01b03168460405160006040518083038185875af1925050503d8060008114614818576040519150601f19603f3d011682016040523d82523d6000602084013e61481d565b606091505b505090508061483657614836637cd69c3960e11b613259565b60408051858152612710602082015283916001600160a01b038616917f9363885e28e7ba67b096932f9f00dff44742731d6cb4fa26ccd4424e78e41e13910160405180910390a350505050565b6040516323b872dd60e01b81526001600160a01b038316906323b872dd906148b390869088908a90600401615e24565b6020604051808303816000875af11580156148d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148f69190615e48565b50604080516001600160a01b03858116825260208201889052612710828401529151839287811692908616917fc899cbcc4511003ff90131e8b89605738e9a7f4925273377ae479a673cf5038c9181900360600190a45050505050565b6000600254461415614966575060015490565b6132ce6005546003546004546145c0565b6000808251604114156149ae5760208301516040840151606085015160001a6149a287828585614b7e565b945094505050506149b6565b506000905060025b9250929050565b60008160048111156149d1576149d1615e7b565b14156149da5750565b60018160048111156149ee576149ee615e7b565b1415614a375760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b6044820152606401611a2c565b6002816004811115614a4b57614a4b615e7b565b1415614a995760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401611a2c565b6003816004811115614aad57614aad615e7b565b1415611ab25760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401611a2c565b6060600080856001600160a01b031685604051614b239190615e91565b600060405180830381855af49150503d8060008114614b5e576040519150601f19603f3d011682016040523d82523d6000602084013e614b63565b606091505b5091509150614b7486838387614c38565b9695505050505050565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b03831115614bab5750600090506003614c2f565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614bff573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614c2857600060019250925050614c2f565b9150600090505b94509492505050565b60608315614ca2578251614c9b57614c4f85613d02565b614c9b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611a2c565b5081612c41565b612c418383815115614cb75781518083602001fd5b8060405162461bcd60e51b8152600401611a2c9190615ead565b600060208284031215614ce357600080fd5b5035919050565b6001600160a01b03169052565b6001600160a01b0381168114611ab257600080fd5b8015158114611ab257600080fd5b60008083601f840112614d2c57600080fd5b5081356001600160401b03811115614d4357600080fd5b6020830191508360208260051b85010111156149b657600080fd5b60008060008060008060008060e0898b031215614d7a57600080fd5b8835614d8581614cf7565b97506020890135614d9581614d0c565b9650604089013595506060890135945060808901356001600160401b03811115614dbe57600080fd5b614dca8b828c01614d1a565b90955093505060a0890135614dde81614d0c565b915060c0890135614dee81614cf7565b809150509295985092959890939650565b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b0381118282101715614e3757614e37614dff565b60405290565b600082601f830112614e4e57600080fd5b81356001600160401b0380821115614e6857614e68614dff565b604051601f8301601f19908116603f01168101908282118183101715614e9057614e90614dff565b81604052838152866020858801011115614ea957600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060808688031215614ee157600080fd5b853594506020860135614ef381614cf7565b935060408601356001600160401b0380821115614f0f57600080fd5b614f1b89838a01614d1a565b90955093506060880135915080821115614f3457600080fd5b50614f4188828901614e3d565b9150509295509295909350565b65ffffffffffff81168114611ab257600080fd5b600080600060608486031215614f7757600080fd5b833592506020840135614f8981614f4e565b91506040840135614f9981614cf7565b809150509250925092565b60006101c08284031215614fb757600080fd5b50919050565b80356001600160801b0381168114614fd457600080fd5b919050565b6000806000806000858703610360811215614ff357600080fd5b863595506150048860208901614fa4565b94506101406101df198201121561501a57600080fd5b506101e08601925061032086013561503181614d0c565b91506150406103408701614fbd565b90509295509295909350565b60006020828403121561505e57600080fd5b813561506981614cf7565b9392505050565b6000806040838503121561508357600080fd5b50508035926020909101359150565b6000806000606084860312156150a757600080fd5b8335925060208401356150b981614d0c565b91506150c760408501614fbd565b90509250925092565b600080604083850312156150e357600080fd5b82356150ee81614cf7565b915060208301356001600160401b0381111561510957600080fd5b61511585828601614e3d565b9150509250929050565b6000806040838503121561513257600080fd5b82359150602083013561514481614d0c565b809150509250929050565b6000806040838503121561516257600080fd5b82359150602083013561514481614cf7565b60008060006060848603121561518957600080fd5b833561519481614cf7565b92506020840135614f8981614cf7565b60008083601f8401126151b657600080fd5b5081356001600160401b038111156151cd57600080fd5b6020830191508360208285010111156149b657600080fd5b6000806000806000808688036101c081121561520057600080fd5b6101608082121561521057600080fd5b88975087013590506001600160401b038082111561522d57600080fd5b6152398a838b016151a4565b9097509550610180890135915061524f82614cf7565b9093506101a0880135908082111561526657600080fd5b5061527389828a01614d1a565b979a9699509497509295939492505050565b60006101c0828403121561529857600080fd5b611acd8383614fa4565b60006101808284031215614fb757600080fd5b60008060008060006101e086880312156152ce57600080fd5b6152d887876152a2565b94506101808601356001600160401b038111156152f457600080fd5b615300888289016151a4565b9095509350506101a086013561531581614cf7565b91506101c086013561532681614d0c565b809150509295509295909350565b65ffffffffffff169052565b60006101c082019050615354828451614cea565b60208301516153666020840182615334565b5060408301516153796040840182615334565b50606083015161538c6060840182614cea565b50608083015161539f6080840182615334565b5060a08301516153b260a0840182615334565b5060c08301516153c560c0840182614cea565b5060e08301516153d860e0840182615334565b50610100808401516153ec82850182615334565b5050610120838101516001600160c01b0316908301526101408084015161541582850182615334565b505061016083810151151590830152610180808401511515908301526101a092830151929091019190915290565b6001600160a01b0391909116815260200190565b6001600160401b0391909116815260200190565b80356001600160601b0381168114614fd457600080fd5b60008060008084860361010081121561549a57600080fd5b60c08112156154a857600080fd5b506154b1614e15565b85356154bc81614cf7565b81526154ca6020870161546b565b602082015260408601356154dd81614cf7565b604082015260608601356154f081614d0c565b6060820152608086013561550381614d0c565b608082015260a086013561551681614d0c565b60a0820152935061552960c0860161546b565b925060e08501356001600160401b0381111561554457600080fd5b615550878288016151a4565b95989497509550505050565b6000806000806101c0858703121561557357600080fd5b61557d86866152a2565b93506101808501356001600160401b0381111561559957600080fd5b6155a5878288016151a4565b9094509250506101a08501356155ba81614cf7565b939692955090935050565b600080600080600060a086880312156155dd57600080fd5b85356155e881614cf7565b945060208601356155f881614cf7565b9350604086013561560881614cf7565b9250606086013561561881614cf7565b949793965091946080013592915050565b6000806000806080858703121561563f57600080fd5b84359350602085013561565181614cf7565b9250604085013563ffffffff8116811461566a57600080fd5b915060608501356001600160401b0381111561568557600080fd5b61569187828801614e3d565b91505092959194509250565b6000602082840312156156af57600080fd5b815161506981614cf7565b9182526001600160a01b0316602082015260400190565b6000602082840312156156e357600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b03929092168252602082015260400190565b81835260006001600160fb1b0383111561573257600080fd5b8260051b8083602087013760009401602001938452509192915050565b6001600160a01b03841681526040602082018190526000906157749083018486615719565b95945050505050565b602081526000612c41602083018486615719565b60005b838110156157ac578181015183820152602001615794565b838111156140715750506000910152565b600081518084526157d5816020860160208601615791565b601f01601f19169290920160200192915050565b8381526001600160a01b0383166020820152606060408201819052600090615774908301846157bd565b80516001600160a01b0390811683526020808301516001600160601b0316908401526040808301519091169083015260608082015115159083015260808082015115159083015260a0908101511515910152565b8781526001600160a01b03878116602083015261016060408301819052600091615894848301898b615719565b908716606085015290506158ab6080840186615813565b8281036101408401526158be81856157bd565b9a9950505050505050505050565b94855263ffffffff9390931660208501526001600160a01b0391821660408501528116606084015216608082015260a00190565b634e487b7160e01b600052601160045260246000fd5b60008282101561592857615928615900565b500390565b600065ffffffffffff80831681851680830382111561594e5761594e615900565b01949350505050565b60006020828403121561596957600080fd5b813561ffff8116811461506957600080fd5b60006020828403121561598d57600080fd5b813561506981614f4e565b6000602082840312156159aa57600080fd5b813560ff8116811461506957600080fd5b6001600160c01b0381168114611ab257600080fd5b6000602082840312156159e257600080fd5b8135615069816159bb565b6000602082840312156159ff57600080fd5b813561506981614d0c565b6020808252602c90820152600080516020615ee183398151915260408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c90820152600080516020615ee183398151915260408201526b6163746976652070726f787960a01b606082015260800190565b6000600019821415615a9257615a92615900565b5060010190565b60008135611ad081614cf7565b60008135611ad081614f4e565b60008135611ad0816159bb565b60008135611ad081614d0c565b615af6615ad983615a99565b82546001600160a01b0319166001600160a01b0391909116178255565b615b2d615b0560208401615aa6565b82805465ffffffffffff60a01b191660a09290921b65ffffffffffff60a01b16919091179055565b615b60615b3c60408401615aa6565b8280546001600160d01b031660d09290921b6001600160d01b031916919091179055565b60018101615b73615ad960608501615a99565b615b82615b0560808501615aa6565b615b91615b3c60a08501615aa6565b5060028101615ba5615ad960c08501615a99565b615bb4615b0560e08501615aa6565b615bc4615b3c6101008501615aa6565b5060038101615bf6615bd96101208501615ab3565b82546001600160c01b0319166001600160c01b0391909116178255565b615c2e615c066101408501615aa6565b82805465ffffffffffff60c01b191660c09290921b65ffffffffffff60c01b16919091179055565b615c5c615c3e6101608501615ac0565b82805460ff60f01b191691151560f01b60ff60f01b16919091179055565b615c90615c6c6101808501615ac0565b8280546001600160f81b031691151560f81b6001600160f81b031916919091179055565b506101a082013560048201555050565b600060208284031215615cb257600080fd5b81356001600160401b038116811461506957600080fd5b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b60008219821115615d1257615d12615900565b500190565b8681526001600160a01b03868116602083015263ffffffff86166040830152841660608201526000610160615d4f6080840186615813565b80610140840152615d62818401856157bd565b9998505050505050505050565b60008060408385031215615d8257600080fd5b82519150602083015161514481614d0c565b6000816000190483118215151615615dae57615dae615900565b500290565b60008351615dc5818460208801615791565b83519083019061594e818360208801615791565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600060208284031215615e5a57600080fd5b815161506981614d0c565b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b60008251615ea3818460208701615791565b9190910192915050565b602081526000611acd60208301846157bd56fee0bf8a4af82e2af496af5f4957e2767f8b52e51a77caedd2f30a1843872d1b7c46756e6374696f6e206d7573742062652063616c6c6564207468726f75676820360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564981414aed4973b05aa301314dc13a5a4077f24490497b98bc270852581c1c578aaca5cb46300e4b20595b143bc883119e775ef88ff77f45fa989ca323576f06ba164736f6c634300080a000a
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
BASE | 100.00% | $2,603.43 | 0.1112 | $289.47 |
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.