// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.20;
/*
Stages of the auction
None - initial stage, before bidding is allowed
Active - bids are allowed, the auction is active
Closed - bids are closed, the price needs to be set
Claims - bidders can claim their winnings and receive any refunds
Reveals - claims and refunds are still active, additionally
owners of pods are now able to reveal their pod
*/
enum AuctionStage {
None,
Active,
Closed,
Claims,
Reveals
}
// SPDX-License-Identifier: UNLICENCED
pragma solidity 0.8.20;
import "./AuctionEnums.sol";
// uint120 is 15 bytes, therefore the whole struct is 31 bytes
// this improves gas perfomance of claim and bid by quite a large margin
struct Bidder {
// the sum of the user's bids
uint120 totalBid;
// total funds refunded to the user
uint120 refundedFunds;
// whether or not the user has claimed already
bool claimed; // 1 byte
}
// @dev the uint limits are intentional
struct Auction {
// the auction id
uint8 id; // 1 byte
// the auction stage
AuctionStage stage; // 1 byte
// the maximum number of pods that can be won by a single wallet
uint8 maxWinPerWallet; // 1 byte
//
// the maximum number of pods that can be minted in this auction
uint16 supply; // 2 bytes
//
// the number of minted NFTs for this auction
uint16 remainingSupply; // 2 bytes
//
// minimum bid
uint64 minimumBid; // 8 bytes
// the price as computed by the binary search algorithm
// it get set after the bidding is closed
uint64 price; // 8 bytes
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
address constant CANONICAL_OPERATOR_FILTER_REGISTRY_ADDRESS = 0x000000000000AAeB6D7670E522A718067333cd4E;
address constant CANONICAL_CORI_SUBSCRIPTION = 0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6;
// 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
pragma solidity ^0.8.13;
import {OperatorFilterer} from "./OperatorFilterer.sol";
import {CANONICAL_CORI_SUBSCRIPTION} from "./lib/Constants.sol";
/**
* @title DefaultOperatorFilterer
* @notice Inherits from OperatorFilterer and automatically subscribes to the default OpenSea subscription.
* @dev Please note that if your token contract does not provide an owner with EIP-173, it must provide
* administration methods on the contract itself to interact with the registry otherwise the subscription
* will be locked to the options set during construction.
*/
abstract contract DefaultOperatorFilterer is OperatorFilterer {
/// @dev The constructor that is called when the contract is being deployed.
constructor() OperatorFilterer(CANONICAL_CORI_SUBSCRIPTION, true) {}
}
// #region Layout of Contract:
// version
// imports
// errors
// interfaces, libraries, contracts
// Type declarations
// State variables
// Events
// Modifiers
// Functions
// Layout of Functions:
// constructor
// receive function (if exists)
// fallback function (if exists)
// external
// public
// internal
// private
// view & pure functions
// #endregion
// SPDX-License-Identifier: UNLICENCED
pragma solidity 0.8.20;
import "delegate.cash/IDelegationRegistry.sol";
// #region errors
error WalletNotDelegated(address hotWallet, address vault);
// #endregion
contract DelegateUtils {
// the delegation registry contract
IDelegationRegistry public immutable delegationRegistry;
constructor(address _registryAddress) {
// initialize the delegation registry
delegationRegistry = IDelegationRegistry(_registryAddress);
}
modifier isDelegated(address vault) {
_checkDelegation(vault, address(this));
_;
}
function _checkDelegation(address vault, address _contract) internal view {
// check that the caller delegated to the vault
if (!delegationRegistry.checkDelegateForContract(msg.sender, vault, _contract)) {
revert WalletNotDelegated(msg.sender, vault);
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/common/ERC2981.sol)
pragma solidity ^0.8.0;
import "../../interfaces/IERC2981.sol";
import "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
*
* Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
* specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
*
* Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
* fee is specified in basis points by default.
*
* IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
* https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
* voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
*
* _Available since v4.5._
*/
abstract contract ERC2981 is IERC2981, ERC165 {
struct RoyaltyInfo {
address receiver;
uint96 royaltyFraction;
}
RoyaltyInfo private _defaultRoyaltyInfo;
mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc IERC2981
*/
function royaltyInfo(uint256 _tokenId, uint256 _salePrice) public view virtual override returns (address, uint256) {
RoyaltyInfo memory royalty = _tokenRoyaltyInfo[_tokenId];
if (royalty.receiver == address(0)) {
royalty = _defaultRoyaltyInfo;
}
uint256 royaltyAmount = (_salePrice * royalty.royaltyFraction) / _feeDenominator();
return (royalty.receiver, royaltyAmount);
}
/**
* @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
* fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
* override.
*/
function _feeDenominator() internal pure virtual returns (uint96) {
return 10000;
}
/**
* @dev Sets the royalty information that all ids in this contract will default to.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: invalid receiver");
_defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Removes default royalty information.
*/
function _deleteDefaultRoyalty() internal virtual {
delete _defaultRoyaltyInfo;
}
/**
* @dev Sets the royalty information for a specific token id, overriding the global default.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setTokenRoyalty(
uint256 tokenId,
address receiver,
uint96 feeNumerator
) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: Invalid parameters");
_tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Resets royalty information for the token id back to the global default.
*/
function _resetTokenRoyalty(uint256 tokenId) internal virtual {
delete _tokenRoyaltyInfo[tokenId];
}
}
// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import './IERC721A.sol';
/**
* @dev Interface of ERC721 token receiver.
*/
interface ERC721A__IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
/**
* @title ERC721A
*
* @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
* Non-Fungible Token Standard, including the Metadata extension.
* Optimized for lower gas during batch mints.
*
* Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
* starting from `_startTokenId()`.
*
* Assumptions:
*
* - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
* - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
*/
contract ERC721A is IERC721A {
// Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).
struct TokenApprovalRef {
address value;
}
// =============================================================
// CONSTANTS
// =============================================================
// Mask of an entry in packed address data.
uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;
// The bit position of `numberMinted` in packed address data.
uint256 private constant _BITPOS_NUMBER_MINTED = 64;
// The bit position of `numberBurned` in packed address data.
uint256 private constant _BITPOS_NUMBER_BURNED = 128;
// The bit position of `aux` in packed address data.
uint256 private constant _BITPOS_AUX = 192;
// Mask of all 256 bits in packed address data except the 64 bits for `aux`.
uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;
// The bit position of `startTimestamp` in packed ownership.
uint256 private constant _BITPOS_START_TIMESTAMP = 160;
// The bit mask of the `burned` bit in packed ownership.
uint256 private constant _BITMASK_BURNED = 1 << 224;
// The bit position of the `nextInitialized` bit in packed ownership.
uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;
// The bit mask of the `nextInitialized` bit in packed ownership.
uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;
// The bit position of `extraData` in packed ownership.
uint256 private constant _BITPOS_EXTRA_DATA = 232;
// Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.
uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;
// The mask of the lower 160 bits for addresses.
uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
// The maximum `quantity` that can be minted with {_mintERC2309}.
// This limit is to prevent overflows on the address data entries.
// For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
// is required to cause an overflow, which is unrealistic.
uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;
// The `Transfer` event signature is given by:
// `keccak256(bytes("Transfer(address,address,uint256)"))`.
bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
// =============================================================
// STORAGE
// =============================================================
// The next token ID to be minted.
uint256 private _currentIndex;
// The number of tokens burned.
uint256 private _burnCounter;
// Token name
string private _name;
// Token symbol
string private _symbol;
// Mapping from token ID to ownership details
// An empty struct value does not necessarily mean the token is unowned.
// See {_packedOwnershipOf} implementation for details.
//
// Bits Layout:
// - [0..159] `addr`
// - [160..223] `startTimestamp`
// - [224] `burned`
// - [225] `nextInitialized`
// - [232..255] `extraData`
mapping(uint256 => uint256) private _packedOwnerships;
// Mapping owner address to address data.
//
// Bits Layout:
// - [0..63] `balance`
// - [64..127] `numberMinted`
// - [128..191] `numberBurned`
// - [192..255] `aux`
mapping(address => uint256) private _packedAddressData;
// Mapping from token ID to approved address.
mapping(uint256 => TokenApprovalRef) private _tokenApprovals;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
// =============================================================
// CONSTRUCTOR
// =============================================================
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
_currentIndex = _startTokenId();
}
// =============================================================
// TOKEN COUNTING OPERATIONS
// =============================================================
/**
* @dev Returns the starting token ID.
* To change the starting token ID, please override this function.
*/
function _startTokenId() internal view virtual returns (uint256) {
return 0;
}
/**
* @dev Returns the next token ID to be minted.
*/
function _nextTokenId() internal view virtual returns (uint256) {
return _currentIndex;
}
/**
* @dev Returns the total number of tokens in existence.
* Burned tokens will reduce the count.
* To get the total number of tokens minted, please see {_totalMinted}.
*/
function totalSupply() public view virtual override returns (uint256) {
// Counter underflow is impossible as _burnCounter cannot be incremented
// more than `_currentIndex - _startTokenId()` times.
unchecked {
return _currentIndex - _burnCounter - _startTokenId();
}
}
/**
* @dev Returns the total amount of tokens minted in the contract.
*/
function _totalMinted() internal view virtual returns (uint256) {
// Counter underflow is impossible as `_currentIndex` does not decrement,
// and it is initialized to `_startTokenId()`.
unchecked {
return _currentIndex - _startTokenId();
}
}
/**
* @dev Returns the total number of tokens burned.
*/
function _totalBurned() internal view virtual returns (uint256) {
return _burnCounter;
}
// =============================================================
// ADDRESS DATA OPERATIONS
// =============================================================
/**
* @dev Returns the number of tokens in `owner`'s account.
*/
function balanceOf(address owner) public view virtual override returns (uint256) {
if (owner == address(0)) revert BalanceQueryForZeroAddress();
return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the number of tokens minted by `owner`.
*/
function _numberMinted(address owner) internal view returns (uint256) {
return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the number of tokens burned by or on behalf of `owner`.
*/
function _numberBurned(address owner) internal view returns (uint256) {
return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
*/
function _getAux(address owner) internal view returns (uint64) {
return uint64(_packedAddressData[owner] >> _BITPOS_AUX);
}
/**
* Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
* If there are multiple variables, please pack them into a uint64.
*/
function _setAux(address owner, uint64 aux) internal virtual {
uint256 packed = _packedAddressData[owner];
uint256 auxCasted;
// Cast `aux` with assembly to avoid redundant masking.
assembly {
auxCasted := aux
}
packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
_packedAddressData[owner] = packed;
}
// =============================================================
// IERC165
// =============================================================
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30000 gas.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
// The interface IDs are constants representing the first 4 bytes
// of the XOR of all function selectors in the interface.
// See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
// (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
return
interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
}
// =============================================================
// IERC721Metadata
// =============================================================
/**
* @dev Returns the token collection name.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the token collection symbol.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
string memory baseURI = _baseURI();
return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, it can be overridden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return '';
}
// =============================================================
// OWNERSHIPS OPERATIONS
// =============================================================
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
return address(uint160(_packedOwnershipOf(tokenId)));
}
/**
* @dev Gas spent here starts off proportional to the maximum mint batch size.
* It gradually moves to O(1) as tokens get transferred around over time.
*/
function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
return _unpackedOwnership(_packedOwnershipOf(tokenId));
}
/**
* @dev Returns the unpacked `TokenOwnership` struct at `index`.
*/
function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
return _unpackedOwnership(_packedOwnerships[index]);
}
/**
* @dev Initializes the ownership slot minted at `index` for efficiency purposes.
*/
function _initializeOwnershipAt(uint256 index) internal virtual {
if (_packedOwnerships[index] == 0) {
_packedOwnerships[index] = _packedOwnershipOf(index);
}
}
/**
* Returns the packed ownership data of `tokenId`.
*/
function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) {
uint256 curr = tokenId;
unchecked {
if (_startTokenId() <= curr)
if (curr < _currentIndex) {
uint256 packed = _packedOwnerships[curr];
// If not burned.
if (packed & _BITMASK_BURNED == 0) {
// Invariant:
// There will always be an initialized ownership slot
// (i.e. `ownership.addr != address(0) && ownership.burned == false`)
// before an unintialized ownership slot
// (i.e. `ownership.addr == address(0) && ownership.burned == false`)
// Hence, `curr` will not underflow.
//
// We can directly compare the packed value.
// If the address is zero, packed will be zero.
while (packed == 0) {
packed = _packedOwnerships[--curr];
}
return packed;
}
}
}
revert OwnerQueryForNonexistentToken();
}
/**
* @dev Returns the unpacked `TokenOwnership` struct from `packed`.
*/
function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {
ownership.addr = address(uint160(packed));
ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
ownership.burned = packed & _BITMASK_BURNED != 0;
ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
}
/**
* @dev Packs ownership data into a single uint256.
*/
function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
assembly {
// Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
owner := and(owner, _BITMASK_ADDRESS)
// `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.
result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
}
}
/**
* @dev Returns the `nextInitialized` flag set if `quantity` equals 1.
*/
function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {
// For branchless setting of the `nextInitialized` flag.
assembly {
// `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.
result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
}
}
// =============================================================
// APPROVAL OPERATIONS
// =============================================================
/**
* @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) public payable virtual override {
address owner = ownerOf(tokenId);
if (_msgSenderERC721A() != owner)
if (!isApprovedForAll(owner, _msgSenderERC721A())) {
revert ApprovalCallerNotOwnerNorApproved();
}
_tokenApprovals[tokenId].value = to;
emit Approval(owner, to, tokenId);
}
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) public view virtual override returns (address) {
if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();
return _tokenApprovals[tokenId].value;
}
/**
* @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) public virtual override {
_operatorApprovals[_msgSenderERC721A()][operator] = approved;
emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
}
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
*
* Tokens start existing when they are minted. See {_mint}.
*/
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return
_startTokenId() <= tokenId &&
tokenId < _currentIndex && // If within bounds,
_packedOwnerships[tokenId] & _BITMASK_BURNED == 0; // and not burned.
}
/**
* @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.
*/
function _isSenderApprovedOrOwner(
address approvedAddress,
address owner,
address msgSender
) private pure returns (bool result) {
assembly {
// Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
owner := and(owner, _BITMASK_ADDRESS)
// Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.
msgSender := and(msgSender, _BITMASK_ADDRESS)
// `msgSender == owner || msgSender == approvedAddress`.
result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
}
}
/**
* @dev Returns the storage slot and value for the approved address of `tokenId`.
*/
function _getApprovedSlotAndAddress(
uint256 tokenId
) private view returns (uint256 approvedAddressSlot, address approvedAddress) {
TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId];
// The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.
assembly {
approvedAddressSlot := tokenApproval.slot
approvedAddress := sload(approvedAddressSlot)
}
}
// =============================================================
// TRANSFER OPERATIONS
// =============================================================
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* 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) public payable virtual override {
uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner();
(uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
// The nested ifs save around 20+ gas over a compound boolean condition.
if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
if (to == address(0)) revert TransferToZeroAddress();
_beforeTokenTransfers(from, to, tokenId, 1);
// Clear approvals from the previous owner.
assembly {
if approvedAddress {
// This is equivalent to `delete _tokenApprovals[tokenId]`.
sstore(approvedAddressSlot, 0)
}
}
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
// Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
unchecked {
// We can directly increment and decrement the balances.
--_packedAddressData[from]; // Updates: `balance -= 1`.
++_packedAddressData[to]; // Updates: `balance += 1`.
// Updates:
// - `address` to the next owner.
// - `startTimestamp` to the timestamp of transfering.
// - `burned` to `false`.
// - `nextInitialized` to `true`.
_packedOwnerships[tokenId] = _packOwnershipData(
to,
_BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
);
// If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
uint256 nextTokenId = tokenId + 1;
// If the next slot's address is zero and not burned (i.e. packed value is zero).
if (_packedOwnerships[nextTokenId] == 0) {
// If the next slot is within bounds.
if (nextTokenId != _currentIndex) {
// Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
_packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
emit Transfer(from, to, tokenId);
_afterTokenTransfers(from, to, tokenId, 1);
}
/**
* @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) public payable virtual override {
safeTransferFrom(from, to, tokenId, '');
}
/**
* @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 memory _data
) public payable virtual override {
transferFrom(from, to, tokenId);
if (to.code.length != 0)
if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
revert TransferToNonERC721ReceiverImplementer();
}
}
/**
* @dev Hook that is called before a set of serially-ordered token IDs
* are about to be transferred. This includes minting.
* And also called before burning one token.
*
* `startTokenId` - the first token ID to be transferred.
* `quantity` - the amount to be transferred.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, `tokenId` will be burned by `from`.
* - `from` and `to` are never both zero.
*/
function _beforeTokenTransfers(address from, address to, uint256 startTokenId, uint256 quantity) internal virtual {}
/**
* @dev Hook that is called after a set of serially-ordered token IDs
* have been transferred. This includes minting.
* And also called after one token has been burned.
*
* `startTokenId` - the first token ID to be transferred.
* `quantity` - the amount to be transferred.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
* transferred to `to`.
* - When `from` is zero, `tokenId` has been minted for `to`.
* - When `to` is zero, `tokenId` has been burned by `from`.
* - `from` and `to` are never both zero.
*/
function _afterTokenTransfers(address from, address to, uint256 startTokenId, uint256 quantity) internal virtual {}
/**
* @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
*
* `from` - Previous owner of the given token ID.
* `to` - Target address that will receive the token.
* `tokenId` - Token ID to be transferred.
* `_data` - Optional data to send along with the call.
*
* Returns whether the call correctly returned the expected magic value.
*/
function _checkContractOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns (
bytes4 retval
) {
return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert TransferToNonERC721ReceiverImplementer();
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
// =============================================================
// MINT OPERATIONS
// =============================================================
/**
* @dev Mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `quantity` must be greater than 0.
*
* Emits a {Transfer} event for each mint.
*/
function _mint(address to, uint256 quantity) internal virtual {
uint256 startTokenId = _currentIndex;
if (quantity == 0) revert MintZeroQuantity();
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are incredibly unrealistic.
// `balance` and `numberMinted` have a maximum limit of 2**64.
// `tokenId` has a maximum limit of 2**256.
unchecked {
// Updates:
// - `balance += quantity`.
// - `numberMinted += quantity`.
//
// We can directly add to the `balance` and `numberMinted`.
_packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `quantity == 1`.
_packedOwnerships[startTokenId] = _packOwnershipData(
to,
_nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
);
uint256 toMasked;
uint256 end = startTokenId + quantity;
// Use assembly to loop and emit the `Transfer` event for gas savings.
// The duplicated `log4` removes an extra check and reduces stack juggling.
// The assembly, together with the surrounding Solidity code, have been
// delicately arranged to nudge the compiler into producing optimized opcodes.
assembly {
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
toMasked := and(to, _BITMASK_ADDRESS)
// Emit the `Transfer` event.
log4(
0, // Start of data (0, since no data).
0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.
0, // `address(0)`.
toMasked, // `to`.
startTokenId // `tokenId`.
)
// The `iszero(eq(,))` check ensures that large values of `quantity`
// that overflows uint256 will make the loop run out of gas.
// The compiler will optimize the `iszero` away for performance.
for {
let tokenId := add(startTokenId, 1)
} iszero(eq(tokenId, end)) {
tokenId := add(tokenId, 1)
} {
// Emit the `Transfer` event. Similar to above.
log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
}
}
if (toMasked == 0) revert MintToZeroAddress();
_currentIndex = end;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Mints `quantity` tokens and transfers them to `to`.
*
* This function is intended for efficient minting only during contract creation.
*
* It emits only one {ConsecutiveTransfer} as defined in
* [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
* instead of a sequence of {Transfer} event(s).
*
* Calling this function outside of contract creation WILL make your contract
* non-compliant with the ERC721 standard.
* For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
* {ConsecutiveTransfer} event is only permissible during contract creation.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `quantity` must be greater than 0.
*
* Emits a {ConsecutiveTransfer} event.
*/
function _mintERC2309(address to, uint256 quantity) internal virtual {
uint256 startTokenId = _currentIndex;
if (to == address(0)) revert MintToZeroAddress();
if (quantity == 0) revert MintZeroQuantity();
if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit();
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are unrealistic due to the above check for `quantity` to be below the limit.
unchecked {
// Updates:
// - `balance += quantity`.
// - `numberMinted += quantity`.
//
// We can directly add to the `balance` and `numberMinted`.
_packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `quantity == 1`.
_packedOwnerships[startTokenId] = _packOwnershipData(
to,
_nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
);
emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);
_currentIndex = startTokenId + quantity;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Safely mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
* - `quantity` must be greater than 0.
*
* See {_mint}.
*
* Emits a {Transfer} event for each mint.
*/
function _safeMint(address to, uint256 quantity, bytes memory _data) internal virtual {
_mint(to, quantity);
unchecked {
if (to.code.length != 0) {
uint256 end = _currentIndex;
uint256 index = end - quantity;
do {
if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
revert TransferToNonERC721ReceiverImplementer();
}
} while (index < end);
// Reentrancy protection.
if (_currentIndex != end) revert();
}
}
}
/**
* @dev Equivalent to `_safeMint(to, quantity, '')`.
*/
function _safeMint(address to, uint256 quantity) internal virtual {
_safeMint(to, quantity, '');
}
// =============================================================
// BURN OPERATIONS
// =============================================================
/**
* @dev Equivalent to `_burn(tokenId, false)`.
*/
function _burn(uint256 tokenId) internal virtual {
_burn(tokenId, false);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
address from = address(uint160(prevOwnershipPacked));
(uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
if (approvalCheck) {
// The nested ifs save around 20+ gas over a compound boolean condition.
if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
}
_beforeTokenTransfers(from, address(0), tokenId, 1);
// Clear approvals from the previous owner.
assembly {
if approvedAddress {
// This is equivalent to `delete _tokenApprovals[tokenId]`.
sstore(approvedAddressSlot, 0)
}
}
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
// Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
unchecked {
// Updates:
// - `balance -= 1`.
// - `numberBurned += 1`.
//
// We can directly decrement the balance, and increment the number burned.
// This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.
_packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;
// Updates:
// - `address` to the last owner.
// - `startTimestamp` to the timestamp of burning.
// - `burned` to `true`.
// - `nextInitialized` to `true`.
_packedOwnerships[tokenId] = _packOwnershipData(
from,
(_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
);
// If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
uint256 nextTokenId = tokenId + 1;
// If the next slot's address is zero and not burned (i.e. packed value is zero).
if (_packedOwnerships[nextTokenId] == 0) {
// If the next slot is within bounds.
if (nextTokenId != _currentIndex) {
// Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
_packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
emit Transfer(from, address(0), tokenId);
_afterTokenTransfers(from, address(0), tokenId, 1);
// Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.
unchecked {
_burnCounter++;
}
}
// =============================================================
// EXTRA DATA OPERATIONS
// =============================================================
/**
* @dev Directly sets the extra data for the ownership data `index`.
*/
function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
uint256 packed = _packedOwnerships[index];
if (packed == 0) revert OwnershipNotInitializedForExtraData();
uint256 extraDataCasted;
// Cast `extraData` with assembly to avoid redundant masking.
assembly {
extraDataCasted := extraData
}
packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
_packedOwnerships[index] = packed;
}
/**
* @dev Called during each token transfer to set the 24bit `extraData` field.
* Intended to be overridden by the cosumer contract.
*
* `previousExtraData` - the value of `extraData` before transfer.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, `tokenId` will be burned by `from`.
* - `from` and `to` are never both zero.
*/
function _extraData(address from, address to, uint24 previousExtraData) internal view virtual returns (uint24) {}
/**
* @dev Returns the next extra data for the packed ownership data.
* The returned result is shifted into position.
*/
function _nextExtraData(address from, address to, uint256 prevOwnershipPacked) private view returns (uint256) {
uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
}
// =============================================================
// OTHER OPERATIONS
// =============================================================
/**
* @dev Returns the message sender (defaults to `msg.sender`).
*
* If you are writing GSN compatible contracts, you need to override this function.
*/
function _msgSenderERC721A() internal view virtual returns (address) {
return msg.sender;
}
/**
* @dev Converts a uint256 to its ASCII string decimal representation.
*/
function _toString(uint256 value) internal pure virtual returns (string memory str) {
assembly {
// The maximum value of a uint256 contains 78 digits (1 byte per digit), but
// we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
// We will need 1 word for the trailing zeros padding, 1 word for the length,
// and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
let m := add(mload(0x40), 0xa0)
// Update the free memory pointer to allocate.
mstore(0x40, m)
// Assign the `str` to the end.
str := sub(m, 0x20)
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end of the memory to calculate the length later.
let end := str
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
// prettier-ignore
for { let temp := value } 1 {} {
str := sub(str, 1)
// Write the character to the pointer.
// The ASCII index of the '0' character is 48.
mstore8(str, add(48, mod(temp, 10)))
// Keep dividing `temp` until zero.
temp := div(temp, 10)
// prettier-ignore
if iszero(temp) { break }
}
let length := sub(end, str)
// Move the pointer 32 bytes leftwards to make room for the length.
str := sub(str, 0x20)
// Store the length.
mstore(str, length)
}
}
}
// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import './IERC721AQueryable.sol';
import '../ERC721A.sol';
/**
* @title ERC721AQueryable.
*
* @dev ERC721A subclass with convenience query functions.
*/
abstract contract ERC721AQueryable is ERC721A, IERC721AQueryable {
/**
* @dev Returns the `TokenOwnership` struct at `tokenId` without reverting.
*
* If the `tokenId` is out of bounds:
*
* - `addr = address(0)`
* - `startTimestamp = 0`
* - `burned = false`
* - `extraData = 0`
*
* If the `tokenId` is burned:
*
* - `addr = <Address of owner before token was burned>`
* - `startTimestamp = <Timestamp when token was burned>`
* - `burned = true`
* - `extraData = <Extra data when token was burned>`
*
* Otherwise:
*
* - `addr = <Address of owner>`
* - `startTimestamp = <Timestamp of start of ownership>`
* - `burned = false`
* - `extraData = <Extra data at start of ownership>`
*/
function explicitOwnershipOf(uint256 tokenId) public view virtual override returns (TokenOwnership memory) {
TokenOwnership memory ownership;
if (tokenId < _startTokenId() || tokenId >= _nextTokenId()) {
return ownership;
}
ownership = _ownershipAt(tokenId);
if (ownership.burned) {
return ownership;
}
return _ownershipOf(tokenId);
}
/**
* @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order.
* See {ERC721AQueryable-explicitOwnershipOf}
*/
function explicitOwnershipsOf(uint256[] calldata tokenIds)
external
view
virtual
override
returns (TokenOwnership[] memory)
{
unchecked {
uint256 tokenIdsLength = tokenIds.length;
TokenOwnership[] memory ownerships = new TokenOwnership[](tokenIdsLength);
for (uint256 i; i != tokenIdsLength; ++i) {
ownerships[i] = explicitOwnershipOf(tokenIds[i]);
}
return ownerships;
}
}
/**
* @dev Returns an array of token IDs owned by `owner`,
* in the range [`start`, `stop`)
* (i.e. `start <= tokenId < stop`).
*
* This function allows for tokens to be queried if the collection
* grows too big for a single call of {ERC721AQueryable-tokensOfOwner}.
*
* Requirements:
*
* - `start < stop`
*/
function tokensOfOwnerIn(
address owner,
uint256 start,
uint256 stop
) external view virtual override returns (uint256[] memory) {
unchecked {
if (start >= stop) revert InvalidQueryRange();
uint256 tokenIdsIdx;
uint256 stopLimit = _nextTokenId();
// Set `start = max(start, _startTokenId())`.
if (start < _startTokenId()) {
start = _startTokenId();
}
// Set `stop = min(stop, stopLimit)`.
if (stop > stopLimit) {
stop = stopLimit;
}
uint256 tokenIdsMaxLength = balanceOf(owner);
// Set `tokenIdsMaxLength = min(balanceOf(owner), stop - start)`,
// to cater for cases where `balanceOf(owner)` is too big.
if (start < stop) {
uint256 rangeLength = stop - start;
if (rangeLength < tokenIdsMaxLength) {
tokenIdsMaxLength = rangeLength;
}
} else {
tokenIdsMaxLength = 0;
}
uint256[] memory tokenIds = new uint256[](tokenIdsMaxLength);
if (tokenIdsMaxLength == 0) {
return tokenIds;
}
// We need to call `explicitOwnershipOf(start)`,
// because the slot at `start` may not be initialized.
TokenOwnership memory ownership = explicitOwnershipOf(start);
address currOwnershipAddr;
// If the starting slot exists (i.e. not burned), initialize `currOwnershipAddr`.
// `ownership.address` will not be zero, as `start` is clamped to the valid token ID range.
if (!ownership.burned) {
currOwnershipAddr = ownership.addr;
}
for (uint256 i = start; i != stop && tokenIdsIdx != tokenIdsMaxLength; ++i) {
ownership = _ownershipAt(i);
if (ownership.burned) {
continue;
}
if (ownership.addr != address(0)) {
currOwnershipAddr = ownership.addr;
}
if (currOwnershipAddr == owner) {
tokenIds[tokenIdsIdx++] = i;
}
}
// Downsize the array to fit.
assembly {
mstore(tokenIds, tokenIdsIdx)
}
return tokenIds;
}
}
/**
* @dev Returns an array of token IDs owned by `owner`.
*
* This function scans the ownership mapping and is O(`totalSupply`) in complexity.
* It is meant to be called off-chain.
*
* See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into
* multiple smaller scans if the collection is large enough to cause
* an out-of-gas error (10K collections should be fine).
*/
function tokensOfOwner(address owner) external view virtual override returns (uint256[] memory) {
unchecked {
uint256 tokenIdsIdx;
address currOwnershipAddr;
uint256 tokenIdsLength = balanceOf(owner);
uint256[] memory tokenIds = new uint256[](tokenIdsLength);
TokenOwnership memory ownership;
for (uint256 i = _startTokenId(); tokenIdsIdx != tokenIdsLength; ++i) {
ownership = _ownershipAt(i);
if (ownership.burned) {
continue;
}
if (ownership.addr != address(0)) {
currOwnershipAddr = ownership.addr;
}
if (currOwnershipAddr == owner) {
tokenIds[tokenIdsIdx++] = i;
}
}
return tokenIds;
}
}
}
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.17;
/**
* @title An immutable registry contract to be deployed as a standalone primitive
* @dev See EIP-5639, new project launches can read previous cold wallet -> hot wallet delegations
* from here and integrate those permissions into their flow
*/
interface IDelegationRegistry {
/// @notice Delegation type
enum DelegationType {
NONE,
ALL,
CONTRACT,
TOKEN
}
/// @notice Info about a single delegation, used for onchain enumeration
struct DelegationInfo {
DelegationType type_;
address vault;
address delegate;
address contract_;
uint256 tokenId;
}
/// @notice Info about a single contract-level delegation
struct ContractDelegation {
address contract_;
address delegate;
}
/// @notice Info about a single token-level delegation
struct TokenDelegation {
address contract_;
uint256 tokenId;
address delegate;
}
/// @notice Emitted when a user delegates their entire wallet
event DelegateForAll(address vault, address delegate, bool value);
/// @notice Emitted when a user delegates a specific contract
event DelegateForContract(address vault, address delegate, address contract_, bool value);
/// @notice Emitted when a user delegates a specific token
event DelegateForToken(address vault, address delegate, address contract_, uint256 tokenId, bool value);
/// @notice Emitted when a user revokes all delegations
event RevokeAllDelegates(address vault);
/// @notice Emitted when a user revoes all delegations for a given delegate
event RevokeDelegate(address vault, address delegate);
/**
* ----------- WRITE -----------
*/
/**
* @notice Allow the delegate to act on your behalf for all contracts
* @param delegate The hotwallet to act on your behalf
* @param value Whether to enable or disable delegation for this address, true for setting and false for revoking
*/
function delegateForAll(address delegate, bool value) external;
/**
* @notice Allow the delegate to act on your behalf for a specific contract
* @param delegate The hotwallet to act on your behalf
* @param contract_ The address for the contract you're delegating
* @param value Whether to enable or disable delegation for this address, true for setting and false for revoking
*/
function delegateForContract(address delegate, address contract_, bool value) external;
/**
* @notice Allow the delegate to act on your behalf for a specific token
* @param delegate The hotwallet to act on your behalf
* @param contract_ The address for the contract you're delegating
* @param tokenId The token id for the token you're delegating
* @param value Whether to enable or disable delegation for this address, true for setting and false for revoking
*/
function delegateForToken(address delegate, address contract_, uint256 tokenId, bool value) external;
/**
* @notice Revoke all delegates
*/
function revokeAllDelegates() external;
/**
* @notice Revoke a specific delegate for all their permissions
* @param delegate The hotwallet to revoke
*/
function revokeDelegate(address delegate) external;
/**
* @notice Remove yourself as a delegate for a specific vault
* @param vault The vault which delegated to the msg.sender, and should be removed
*/
function revokeSelf(address vault) external;
/**
* ----------- READ -----------
*/
/**
* @notice Returns all active delegations a given delegate is able to claim on behalf of
* @param delegate The delegate that you would like to retrieve delegations for
* @return info Array of DelegationInfo structs
*/
function getDelegationsByDelegate(address delegate) external view returns (DelegationInfo[] memory);
/**
* @notice Returns an array of wallet-level delegates for a given vault
* @param vault The cold wallet who issued the delegation
* @return addresses Array of wallet-level delegates for a given vault
*/
function getDelegatesForAll(address vault) external view returns (address[] memory);
/**
* @notice Returns an array of contract-level delegates for a given vault and contract
* @param vault The cold wallet who issued the delegation
* @param contract_ The address for the contract you're delegating
* @return addresses Array of contract-level delegates for a given vault and contract
*/
function getDelegatesForContract(address vault, address contract_) external view returns (address[] memory);
/**
* @notice Returns an array of contract-level delegates for a given vault's token
* @param vault The cold wallet who issued the delegation
* @param contract_ The address for the contract holding the token
* @param tokenId The token id for the token you're delegating
* @return addresses Array of contract-level delegates for a given vault's token
*/
function getDelegatesForToken(address vault, address contract_, uint256 tokenId)
external
view
returns (address[] memory);
/**
* @notice Returns all contract-level delegations for a given vault
* @param vault The cold wallet who issued the delegations
* @return delegations Array of ContractDelegation structs
*/
function getContractLevelDelegations(address vault)
external
view
returns (ContractDelegation[] memory delegations);
/**
* @notice Returns all token-level delegations for a given vault
* @param vault The cold wallet who issued the delegations
* @return delegations Array of TokenDelegation structs
*/
function getTokenLevelDelegations(address vault) external view returns (TokenDelegation[] memory delegations);
/**
* @notice Returns true if the address is delegated to act on the entire vault
* @param delegate The hotwallet to act on your behalf
* @param vault The cold wallet who issued the delegation
*/
function checkDelegateForAll(address delegate, address vault) external view returns (bool);
/**
* @notice Returns true if the address is delegated to act on your behalf for a token contract or an entire vault
* @param delegate The hotwallet to act on your behalf
* @param contract_ The address for the contract you're delegating
* @param vault The cold wallet who issued the delegation
*/
function checkDelegateForContract(address delegate, address vault, address contract_)
external
view
returns (bool);
/**
* @notice Returns true if the address is delegated to act on your behalf for a specific token, the token's contract or an entire vault
* @param delegate The hotwallet to act on your behalf
* @param contract_ The address for the contract you're delegating
* @param tokenId The token id for the token you're delegating
* @param vault The cold wallet who issued the delegation
*/
function checkDelegateForToken(address delegate, address vault, address contract_, uint256 tokenId)
external
view
returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol)
pragma solidity ^0.8.0;
import "../utils/introspection/IERC165.sol";
/**
* @dev Interface for the NFT Royalty Standard.
*
* A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
* support for royalty payments across all NFT marketplaces and ecosystem participants.
*
* _Available since v4.5._
*/
interface IERC2981 is IERC165 {
/**
* @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
* exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
*/
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external
view
returns (address receiver, uint256 royaltyAmount);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* 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
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs
pragma solidity ^0.8.4;
/**
* @dev Interface of ERC721A.
*/
interface IERC721A {
/**
* The caller must own the token or be an approved operator.
*/
error ApprovalCallerNotOwnerNorApproved();
/**
* The token does not exist.
*/
error ApprovalQueryForNonexistentToken();
/**
* Cannot query the balance for the zero address.
*/
error BalanceQueryForZeroAddress();
/**
* Cannot mint to the zero address.
*/
error MintToZeroAddress();
/**
* The quantity of tokens minted must be more than zero.
*/
error MintZeroQuantity();
/**
* The token does not exist.
*/
error OwnerQueryForNonexistentToken();
/**
* The caller must own the token or be an approved operator.
*/
error TransferCallerNotOwnerNorApproved();
/**
* The token must be owned by `from`.
*/
error TransferFromIncorrectOwner();
/**
* Cannot safely transfer to a contract that does not implement the
* ERC721Receiver interface.
*/
error TransferToNonERC721ReceiverImplementer();
/**
* Cannot transfer to the zero address.
*/
error TransferToZeroAddress();
/**
* The token does not exist.
*/
error URIQueryForNonexistentToken();
/**
* The `quantity` minted with ERC2309 exceeds the safety limit.
*/
error MintERC2309QuantityExceedsLimit();
/**
* The `extraData` cannot be set on an unintialized ownership slot.
*/
error OwnershipNotInitializedForExtraData();
// =============================================================
// STRUCTS
// =============================================================
struct TokenOwnership {
// The address of the owner.
address addr;
// Stores the start time of ownership with minimal overhead for tokenomics.
uint64 startTimestamp;
// Whether the token has been burned.
bool burned;
// Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
uint24 extraData;
}
// =============================================================
// TOKEN COUNTERS
// =============================================================
/**
* @dev Returns the total number of tokens in existence.
* Burned tokens will reduce the count.
* To get the total number of tokens minted, please see {_totalMinted}.
*/
function totalSupply() external view returns (uint256);
// =============================================================
// IERC165
// =============================================================
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
// =============================================================
// IERC721
// =============================================================
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables
* (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in `owner`'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`,
* checking first that contract recipients are aware of the ERC721 protocol
* to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move
* this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external payable;
/**
* @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external payable;
/**
* @dev Transfers `tokenId` 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 payable;
/**
* @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 payable;
/**
* @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);
// =============================================================
// IERC721Metadata
// =============================================================
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
// =============================================================
// IERC2309
// =============================================================
/**
* @dev Emitted when tokens in `fromTokenId` to `toTokenId`
* (inclusive) is transferred from `from` to `to`, as defined in the
* [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
*
* See {_mintERC2309} for more details.
*/
event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
}
// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import '../IERC721A.sol';
/**
* @dev Interface of ERC721AQueryable.
*/
interface IERC721AQueryable is IERC721A {
/**
* Invalid query range (`start` >= `stop`).
*/
error InvalidQueryRange();
/**
* @dev Returns the `TokenOwnership` struct at `tokenId` without reverting.
*
* If the `tokenId` is out of bounds:
*
* - `addr = address(0)`
* - `startTimestamp = 0`
* - `burned = false`
* - `extraData = 0`
*
* If the `tokenId` is burned:
*
* - `addr = <Address of owner before token was burned>`
* - `startTimestamp = <Timestamp when token was burned>`
* - `burned = true`
* - `extraData = <Extra data when token was burned>`
*
* Otherwise:
*
* - `addr = <Address of owner>`
* - `startTimestamp = <Timestamp of start of ownership>`
* - `burned = false`
* - `extraData = <Extra data at start of ownership>`
*/
function explicitOwnershipOf(uint256 tokenId) external view returns (TokenOwnership memory);
/**
* @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order.
* See {ERC721AQueryable-explicitOwnershipOf}
*/
function explicitOwnershipsOf(uint256[] memory tokenIds) external view returns (TokenOwnership[] memory);
/**
* @dev Returns an array of token IDs owned by `owner`,
* in the range [`start`, `stop`)
* (i.e. `start <= tokenId < stop`).
*
* This function allows for tokens to be queried if the collection
* grows too big for a single call of {ERC721AQueryable-tokensOfOwner}.
*
* Requirements:
*
* - `start < stop`
*/
function tokensOfOwnerIn(
address owner,
uint256 start,
uint256 stop
) external view returns (uint256[] memory);
/**
* @dev Returns an array of token IDs owned by `owner`.
*
* This function scans the ownership mapping and is O(`totalSupply`) in complexity.
* It is meant to be called off-chain.
*
* See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into
* multiple smaller scans if the collection is large enough to cause
* an out-of-gas error (10K collections should be fine).
*/
function tokensOfOwner(address owner) external view returns (uint256[] memory);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
interface IOperatorFilterRegistry {
/**
* @notice Returns true if operator is not filtered for a given token, either by address or codeHash. Also returns
* true if supplied registrant address is not registered.
*/
function isOperatorAllowed(address registrant, address operator) external view returns (bool);
/**
* @notice Registers an address with the registry. May be called by address itself or by EIP-173 owner.
*/
function register(address registrant) external;
/**
* @notice Registers an address with the registry and "subscribes" to another address's filtered operators and codeHashes.
*/
function registerAndSubscribe(address registrant, address subscription) external;
/**
* @notice Registers an address with the registry and copies the filtered operators and codeHashes from another
* address without subscribing.
*/
function registerAndCopyEntries(address registrant, address registrantToCopy) external;
/**
* @notice Unregisters an address with the registry and removes its subscription. May be called by address itself or by EIP-173 owner.
* Note that this does not remove any filtered addresses or codeHashes.
* Also note that any subscriptions to this registrant will still be active and follow the existing filtered addresses and codehashes.
*/
function unregister(address addr) external;
/**
* @notice Update an operator address for a registered address - when filtered is true, the operator is filtered.
*/
function updateOperator(address registrant, address operator, bool filtered) external;
/**
* @notice Update multiple operators for a registered address - when filtered is true, the operators will be filtered. Reverts on duplicates.
*/
function updateOperators(address registrant, address[] calldata operators, bool filtered) external;
/**
* @notice Update a codeHash for a registered address - when filtered is true, the codeHash is filtered.
*/
function updateCodeHash(address registrant, bytes32 codehash, bool filtered) external;
/**
* @notice Update multiple codeHashes for a registered address - when filtered is true, the codeHashes will be filtered. Reverts on duplicates.
*/
function updateCodeHashes(address registrant, bytes32[] calldata codeHashes, bool filtered) external;
/**
* @notice Subscribe an address to another registrant's filtered operators and codeHashes. Will remove previous
* subscription if present.
* Note that accounts with subscriptions may go on to subscribe to other accounts - in this case,
* subscriptions will not be forwarded. Instead the former subscription's existing entries will still be
* used.
*/
function subscribe(address registrant, address registrantToSubscribe) external;
/**
* @notice Unsubscribe an address from its current subscribed registrant, and optionally copy its filtered operators and codeHashes.
*/
function unsubscribe(address registrant, bool copyExistingEntries) external;
/**
* @notice Get the subscription address of a given registrant, if any.
*/
function subscriptionOf(address addr) external returns (address registrant);
/**
* @notice Get the set of addresses subscribed to a given registrant.
* Note that order is not guaranteed as updates are made.
*/
function subscribers(address registrant) external returns (address[] memory);
/**
* @notice Get the subscriber at a given index in the set of addresses subscribed to a given registrant.
* Note that order is not guaranteed as updates are made.
*/
function subscriberAt(address registrant, uint256 index) external returns (address);
/**
* @notice Copy filtered operators and codeHashes from a different registrantToCopy to addr.
*/
function copyEntriesOf(address registrant, address registrantToCopy) external;
/**
* @notice Returns true if operator is filtered by a given address or its subscription.
*/
function isOperatorFiltered(address registrant, address operator) external returns (bool);
/**
* @notice Returns true if the hash of an address's code is filtered by a given address or its subscription.
*/
function isCodeHashOfFiltered(address registrant, address operatorWithCode) external returns (bool);
/**
* @notice Returns true if a codeHash is filtered by a given address or its subscription.
*/
function isCodeHashFiltered(address registrant, bytes32 codeHash) external returns (bool);
/**
* @notice Returns a list of filtered operators for a given address or its subscription.
*/
function filteredOperators(address addr) external returns (address[] memory);
/**
* @notice Returns the set of filtered codeHashes for a given address or its subscription.
* Note that order is not guaranteed as updates are made.
*/
function filteredCodeHashes(address addr) external returns (bytes32[] memory);
/**
* @notice Returns the filtered operator at the given index of the set of filtered operators for a given address or
* its subscription.
* Note that order is not guaranteed as updates are made.
*/
function filteredOperatorAt(address registrant, uint256 index) external returns (address);
/**
* @notice Returns the filtered codeHash at the given index of the list of filtered codeHashes for a given address or
* its subscription.
* Note that order is not guaranteed as updates are made.
*/
function filteredCodeHashAt(address registrant, uint256 index) external returns (bytes32);
/**
* @notice Returns true if an address has registered
*/
function isRegistered(address addr) external returns (bool);
/**
* @dev Convenience method to compute the code hash of an arbitrary contract
*/
function codeHashOf(address addr) external returns (bytes32);
}
// SPDX-License-Identifier: UNLICENCED
pragma solidity 0.8.20;
import "./AuctionEnums.sol";
interface IXAuction {
/**
* EVENTS
*/
event Bid(
uint8 indexed auctionId,
address indexed bidder,
uint256 bidAmount,
uint256 bidderTotal
);
// when a bidder is refunded
event RefundSent(address indexed recipient, uint256 value);
event AuctionCreated(
uint8 indexed auctionId,
uint16 supply,
uint8 maxWinPerWallet,
uint64 minimumBid
);
event AuctionStarted(uint8 indexed auctionId);
event MinimumBidChanged(uint8 indexed auctionId, uint256 newMinBid);
event AuctionEnded(uint8 indexed auctionId);
event PriceSet(uint8 indexed auctionId, uint256 newPrice);
event ClaimsAndRefundsStarted(uint8 indexed auctionId);
// when a user claims their NFTs and/or refunds
event Claimed(address recipient, uint256 totalBid, uint256 podsWon, uint256 refund);
/**
* ERRORS
*/
error InvalidCreateAuctionParams();
error NullAddressParameter();
error AuctionMustNotBeStarted();
error InvalidStageForOperation(AuctionStage currentStage, AuctionStage requiredStage);
error AuctionMustBeActive();
error BidLowerThanMinimum(uint256 bid, uint256 minBid);
error StageMustBeBiddingClosed(AuctionStage currentStage);
error PriceMustBeSet();
error PriceIsLowerThanTheMinBid(uint256 priceInput, uint256 minBid);
error MultipleAuctionsViolation();
error ZeroBids(address user);
error NoActiveAuction();
error AuctionDoesNotExist(uint8 auctionId);
error MaxSupplyExceeded();
error RefundFailed(address recipient, uint256 amount);
error ContractCallersNotAllowed();
// function bid() external payable;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 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 10, 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 * 8) < value ? 1 : 0);
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {IOperatorFilterRegistry} from "./IOperatorFilterRegistry.sol";
import {CANONICAL_OPERATOR_FILTER_REGISTRY_ADDRESS} from "./lib/Constants.sol";
/**
* @title OperatorFilterer
* @notice Abstract contract whose constructor automatically registers and optionally subscribes to or copies another
* registrant's entries in the OperatorFilterRegistry.
* @dev This smart contract is meant to be inherited by token contracts so they can use the following:
* - `onlyAllowedOperator` modifier for `transferFrom` and `safeTransferFrom` methods.
* - `onlyAllowedOperatorApproval` modifier for `approve` and `setApprovalForAll` methods.
* Please note that if your token contract does not provide an owner with EIP-173, it must provide
* administration methods on the contract itself to interact with the registry otherwise the subscription
* will be locked to the options set during construction.
*/
abstract contract OperatorFilterer {
/// @dev Emitted when an operator is not allowed.
error OperatorNotAllowed(address operator);
IOperatorFilterRegistry public constant OPERATOR_FILTER_REGISTRY =
IOperatorFilterRegistry(CANONICAL_OPERATOR_FILTER_REGISTRY_ADDRESS);
/// @dev The constructor that is called when the contract is being deployed.
constructor(address subscriptionOrRegistrantToCopy, bool subscribe) {
// If an inheriting token contract is deployed to a network without the registry deployed, the modifier
// will not revert, but the contract will need to be registered with the registry once it is deployed in
// order for the modifier to filter addresses.
if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) {
if (subscribe) {
OPERATOR_FILTER_REGISTRY.registerAndSubscribe(address(this), subscriptionOrRegistrantToCopy);
} else {
if (subscriptionOrRegistrantToCopy != address(0)) {
OPERATOR_FILTER_REGISTRY.registerAndCopyEntries(address(this), subscriptionOrRegistrantToCopy);
} else {
OPERATOR_FILTER_REGISTRY.register(address(this));
}
}
}
}
/**
* @dev A helper function to check if an operator is allowed.
*/
modifier onlyAllowedOperator(address from) virtual {
// Allow spending tokens from addresses with balance
// Note that this still allows listings and marketplaces with escrow to transfer tokens if transferred
// from an EOA.
if (from != msg.sender) {
_checkFilterOperator(msg.sender);
}
_;
}
/**
* @dev A helper function to check if an operator approval is allowed.
*/
modifier onlyAllowedOperatorApproval(address operator) virtual {
_checkFilterOperator(operator);
_;
}
/**
* @dev A helper function to check if an operator is allowed.
*/
function _checkFilterOperator(address operator) internal view virtual {
// Check registry code length to facilitate testing in environments without a deployed registry.
if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) {
// under normal circumstances, this function will revert rather than return false, but inheriting contracts
// may specify their own OperatorFilterRegistry implementations, which may behave differently
if (!OPERATOR_FILTER_REGISTRY.isOperatorAllowed(address(this), operator)) {
revert OperatorNotAllowed(operator);
}
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/** ****************************************************************************
* @notice Interface for contracts using VRF randomness
* *****************************************************************************
* @dev PURPOSE
*
* @dev Reggie the Random Oracle (not his real job) wants to provide randomness
* @dev to Vera the verifier in such a way that Vera can be sure he's not
* @dev making his output up to suit himself. Reggie provides Vera a public key
* @dev to which he knows the secret key. Each time Vera provides a seed to
* @dev Reggie, he gives back a value which is computed completely
* @dev deterministically from the seed and the secret key.
*
* @dev Reggie provides a proof by which Vera can verify that the output was
* @dev correctly computed once Reggie tells it to her, but without that proof,
* @dev the output is indistinguishable to her from a uniform random sample
* @dev from the output space.
*
* @dev The purpose of this contract is to make it easy for unrelated contracts
* @dev to talk to Vera the verifier about the work Reggie is doing, to provide
* @dev simple access to a verifiable source of randomness. It ensures 2 things:
* @dev 1. The fulfillment came from the VRFCoordinator
* @dev 2. The consumer contract implements fulfillRandomWords.
* *****************************************************************************
* @dev USAGE
*
* @dev Calling contracts must inherit from VRFConsumerBase, and can
* @dev initialize VRFConsumerBase's attributes in their constructor as
* @dev shown:
*
* @dev contract VRFConsumer {
* @dev constructor(<other arguments>, address _vrfCoordinator, address _link)
* @dev VRFConsumerBase(_vrfCoordinator) public {
* @dev <initialization with other arguments goes here>
* @dev }
* @dev }
*
* @dev The oracle will have given you an ID for the VRF keypair they have
* @dev committed to (let's call it keyHash). Create subscription, fund it
* @dev and your consumer contract as a consumer of it (see VRFCoordinatorInterface
* @dev subscription management functions).
* @dev Call requestRandomWords(keyHash, subId, minimumRequestConfirmations,
* @dev callbackGasLimit, numWords),
* @dev see (VRFCoordinatorInterface for a description of the arguments).
*
* @dev Once the VRFCoordinator has received and validated the oracle's response
* @dev to your request, it will call your contract's fulfillRandomWords method.
*
* @dev The randomness argument to fulfillRandomWords is a set of random words
* @dev generated from your requestId and the blockHash of the request.
*
* @dev If your contract could have concurrent requests open, you can use the
* @dev requestId returned from requestRandomWords to track which response is associated
* @dev with which randomness request.
* @dev See "SECURITY CONSIDERATIONS" for principles to keep in mind,
* @dev if your contract could have multiple requests in flight simultaneously.
*
* @dev Colliding `requestId`s are cryptographically impossible as long as seeds
* @dev differ.
*
* *****************************************************************************
* @dev SECURITY CONSIDERATIONS
*
* @dev A method with the ability to call your fulfillRandomness method directly
* @dev could spoof a VRF response with any random value, so it's critical that
* @dev it cannot be directly called by anything other than this base contract
* @dev (specifically, by the VRFConsumerBase.rawFulfillRandomness method).
*
* @dev For your users to trust that your contract's random behavior is free
* @dev from malicious interference, it's best if you can write it so that all
* @dev behaviors implied by a VRF response are executed *during* your
* @dev fulfillRandomness method. If your contract must store the response (or
* @dev anything derived from it) and use it later, you must ensure that any
* @dev user-significant behavior which depends on that stored value cannot be
* @dev manipulated by a subsequent VRF request.
*
* @dev Similarly, both miners and the VRF oracle itself have some influence
* @dev over the order in which VRF responses appear on the blockchain, so if
* @dev your contract could have multiple VRF requests in flight simultaneously,
* @dev you must ensure that the order in which the VRF responses arrive cannot
* @dev be used to manipulate your contract's user-significant behavior.
*
* @dev Since the block hash of the block which contains the requestRandomness
* @dev call is mixed into the input to the VRF *last*, a sufficiently powerful
* @dev miner could, in principle, fork the blockchain to evict the block
* @dev containing the request, forcing the request to be included in a
* @dev different block with a different hash, and therefore a different input
* @dev to the VRF. However, such an attack would incur a substantial economic
* @dev cost. This cost scales with the number of blocks the VRF oracle waits
* @dev until it calls responds to a request. It is for this reason that
* @dev that you can signal to an oracle you'd like them to wait longer before
* @dev responding to the request (however this is not enforced in the contract
* @dev and so remains effective only in the case of unmodified oracle software).
*/
abstract contract VRFConsumerBaseV2 {
error OnlyCoordinatorCanFulfill(address have, address want);
address private immutable vrfCoordinator;
/**
* @param _vrfCoordinator address of VRFCoordinator contract
*/
constructor(address _vrfCoordinator) {
vrfCoordinator = _vrfCoordinator;
}
/**
* @notice fulfillRandomness handles the VRF response. Your contract must
* @notice implement it. See "SECURITY CONSIDERATIONS" above for important
* @notice principles to keep in mind when implementing your fulfillRandomness
* @notice method.
*
* @dev VRFConsumerBaseV2 expects its subcontracts to have a method with this
* @dev signature, and will call it once it has verified the proof
* @dev associated with the randomness. (It is triggered via a call to
* @dev rawFulfillRandomness, below.)
*
* @param requestId The Id initially returned by requestRandomness
* @param randomWords the VRF output expanded to the requested number of words
*/
function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal virtual;
// rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF
// proof. rawFulfillRandomness then calls fulfillRandomness, after validating
// the origin of the call
function rawFulfillRandomWords(uint256 requestId, uint256[] memory randomWords) external {
if (msg.sender != vrfCoordinator) {
revert OnlyCoordinatorCanFulfill(msg.sender, vrfCoordinator);
}
fulfillRandomWords(requestId, randomWords);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface VRFCoordinatorV2Interface {
/**
* @notice Get configuration relevant for making requests
* @return minimumRequestConfirmations global min for request confirmations
* @return maxGasLimit global max for request gas limit
* @return s_provingKeyHashes list of registered key hashes
*/
function getRequestConfig()
external
view
returns (
uint16,
uint32,
bytes32[] memory
);
/**
* @notice Request a set of random words.
* @param keyHash - Corresponds to a particular oracle job which uses
* that key for generating the VRF proof. Different keyHash's have different gas price
* ceilings, so you can select a specific one to bound your maximum per request cost.
* @param subId - The ID of the VRF subscription. Must be funded
* with the minimum subscription balance required for the selected keyHash.
* @param minimumRequestConfirmations - How many blocks you'd like the
* oracle to wait before responding to the request. See SECURITY CONSIDERATIONS
* for why you may want to request more. The acceptable range is
* [minimumRequestBlockConfirmations, 200].
* @param callbackGasLimit - How much gas you'd like to receive in your
* fulfillRandomWords callback. Note that gasleft() inside fulfillRandomWords
* may be slightly less than this amount because of gas used calling the function
* (argument decoding etc.), so you may need to request slightly more than you expect
* to have inside fulfillRandomWords. The acceptable range is
* [0, maxGasLimit]
* @param numWords - The number of uint256 random values you'd like to receive
* in your fulfillRandomWords callback. Note these numbers are expanded in a
* secure way by the VRFCoordinator from a single random value supplied by the oracle.
* @return requestId - A unique identifier of the request. Can be used to match
* a request to a response in fulfillRandomWords.
*/
function requestRandomWords(
bytes32 keyHash,
uint64 subId,
uint16 minimumRequestConfirmations,
uint32 callbackGasLimit,
uint32 numWords
) external returns (uint256 requestId);
/**
* @notice Create a VRF subscription.
* @return subId - A unique subscription id.
* @dev You can manage the consumer set dynamically with addConsumer/removeConsumer.
* @dev Note to fund the subscription, use transferAndCall. For example
* @dev LINKTOKEN.transferAndCall(
* @dev address(COORDINATOR),
* @dev amount,
* @dev abi.encode(subId));
*/
function createSubscription() external returns (uint64 subId);
/**
* @notice Get a VRF subscription.
* @param subId - ID of the subscription
* @return balance - LINK balance of the subscription in juels.
* @return reqCount - number of requests for this subscription, determines fee tier.
* @return owner - owner of the subscription.
* @return consumers - list of consumer address which are able to use this subscription.
*/
function getSubscription(uint64 subId)
external
view
returns (
uint96 balance,
uint64 reqCount,
address owner,
address[] memory consumers
);
/**
* @notice Request subscription owner transfer.
* @param subId - ID of the subscription
* @param newOwner - proposed new owner of the subscription
*/
function requestSubscriptionOwnerTransfer(uint64 subId, address newOwner) external;
/**
* @notice Request subscription owner transfer.
* @param subId - ID of the subscription
* @dev will revert if original owner of subId has
* not requested that msg.sender become the new owner.
*/
function acceptSubscriptionOwnerTransfer(uint64 subId) external;
/**
* @notice Add a consumer to a VRF subscription.
* @param subId - ID of the subscription
* @param consumer - New consumer which can use the subscription
*/
function addConsumer(uint64 subId, address consumer) external;
/**
* @notice Remove a consumer from a VRF subscription.
* @param subId - ID of the subscription
* @param consumer - Consumer to remove from the subscription
*/
function removeConsumer(uint64 subId, address consumer) external;
/**
* @notice Cancel a subscription
* @param subId - ID of the subscription
* @param to - Where to send the remaining LINK to
*/
function cancelSubscription(uint64 subId, address to) external;
/*
* @notice Check to see if there exists a request commitment consumers
* for all consumers and keyhashes for a given sub.
* @param subId - ID of the subscription
* @return true if there exists at least one unfulfilled request for the subscription, false
* otherwise.
*/
function pendingRequestExists(uint64 subId) external view returns (bool);
}
// SPDX-License-Identifier: UNLICENCED
pragma solidity 0.8.20;
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
// Errors
error NoFundsToWithdraw();
error WithdrawFailed(address recipient, uint256 amount);
error WithdrawToNullAddress();
contract Withdrawer {
using SafeCast for uint256;
// Events
event FundsWithdrawn(address recipient, uint256 amount);
// the total funds that can be withdrawn by the owner
uint128 internal withdrawableFunds;
/**
* @notice Withdraw function for the owner
* @dev since only pod sales funds can be withdrawn at any time
* and users' funds need to be protected, this is marked as nonReentrant
*/
function _withdraw(address payable receiver) internal {
// allow the owner to withdraw the balance for any minted pods
// allow the owner to withdraw the balance
if (receiver == address(0)) {
revert WithdrawToNullAddress();
}
uint128 funds = withdrawableFunds;
if (funds == 0) {
revert NoFundsToWithdraw();
}
// reset the withdrawable funds
withdrawableFunds = 0;
// emit the withdraw event
emit FundsWithdrawn(receiver, funds);
// send the funds to the receiver
(bool success, ) = receiver.call{value: funds}("");
if (!success) {
revert WithdrawFailed(receiver, funds);
}
}
/**
@dev fallback function to receive ether
*/
receive() external payable {
// increase the withdrawable funds by the ETH received
// += is less gas efficient
withdrawableFunds = withdrawableFunds + SafeCast.toUint128(msg.value);
}
}
/**
playplanetx.com
Planet-X Ltd © 2023 | All rights reserved
*/
// #region Layout of Contract:
// version
// imports
// errors
// interfaces, libraries, contracts
// Type declarations
// State variables
// Events
// Modifiers
// Functions
// Layout of Functions:
// constructor
// receive function (if exists)
// fallback function (if exists)
// external
// public
// internal
// private
// view & pure functions
// #endregion
// SPDX-License-Identifier: UNLICENCED
pragma solidity 0.8.20;
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "./IXAuction.sol";
import "./AuctionStructs.sol";
import "../base/Withdrawer.sol";
import "../base/XNFTRoyaltyBase.sol";
error AlreadyClaimed(address claimaint);
abstract contract XAuctions is IXAuction, Withdrawer, XNFTRoyaltyBase {
using SafeCast for uint256;
using Math for uint256;
uint8 public activeAuctionId;
// the auctions data
mapping(uint16 auctionId => Auction) public auctions;
// users bids and refunds
// auctionId -> userAddress -> User
mapping(uint16 auctionId => mapping(address => Bidder)) public bidders;
function _startClaims(uint8 _auctionId) internal {
// read auction to memory
Auction memory auction = auctions[_auctionId];
// revert if the stage is not "bidding closed"
if (auction.stage != AuctionStage.Closed) {
revert StageMustBeBiddingClosed(auction.stage);
}
if (auction.price == 0) {
revert PriceMustBeSet();
}
// write back to storage
auctions[_auctionId].stage = AuctionStage.Claims;
emit ClaimsAndRefundsStarted(_auctionId);
}
function _setPrice(uint8 _auctionId, uint64 newPrice) internal {
// read auction to memory
Auction memory auction = auctions[_auctionId];
if (auction.stage != AuctionStage.Closed) {
revert StageMustBeBiddingClosed(auction.stage);
}
uint64 minBid = auction.minimumBid; // storage to memory
if (newPrice < minBid) {
revert PriceIsLowerThanTheMinBid(newPrice, minBid);
}
auctions[auction.id].price = newPrice;
emit PriceSet(_auctionId, newPrice);
}
function bid(uint8 auctionId) internal {
if (auctions[auctionId].stage != AuctionStage.Active) {
revert AuctionMustBeActive();
}
uint256 userBid = bidders[auctionId][msg.sender].totalBid;
// increment the bid of the user
userBid += msg.value;
// if their new total bid is less than the current minimum bid
// revert with an error
uint64 minBid = auctions[auctionId].minimumBid;
if (userBid < minBid) {
revert BidLowerThanMinimum(userBid, minBid);
}
// save the bid
bidders[auctionId][msg.sender].totalBid = SafeCast.toUint120(userBid);
emit Bid(auctionId, msg.sender, msg.value, userBid);
}
function _startAuction(uint8 id) internal {
if (auctions[id].stage != AuctionStage.None) {
revert AuctionMustNotBeStarted();
}
auctions[id].stage = AuctionStage.Active;
activeAuctionId = id;
emit AuctionStarted(id);
}
function _saveNewAuction(
uint8 _id,
uint16 _supply,
uint8 _maxWinPerWallet,
uint64 _minimumBid
) internal {
if (
_supply == 0 ||
_minimumBid == 0 ||
_maxWinPerWallet == 0 ||
_supply < _maxWinPerWallet
) {
revert InvalidCreateAuctionParams();
}
// create the auction
auctions[_id] = Auction({
id: _id,
maxWinPerWallet: _maxWinPerWallet,
supply: _supply,
remainingSupply: _supply,
minimumBid: _minimumBid,
price: 0,
stage: AuctionStage.None
});
emit AuctionCreated(_id, _supply, _maxWinPerWallet, _minimumBid);
}
/**
* @notice claim function to be used both by the user and by the support role
* @dev used by claim() and claimOnBehalfOf()
* @param claimant the address to claim tokens for.
*/
function _internalClaim(address claimant, uint8 _auctionId) internal {
// early revert if the auction is not in the right stage
Auction memory auction = auctions[_auctionId];
if (auction.stage < AuctionStage.Claims) {
revert InvalidStageForOperation(auction.stage, AuctionStage.Claims);
}
// read user in memory
Bidder memory user = bidders[_auctionId][claimant];
// revert if the user has already claimed
if (user.claimed) {
revert AlreadyClaimed(claimant);
}
// @dev state modification CEI pattern
bidders[_auctionId][claimant].claimed = true;
uint120 userTotalBid = user.totalBid;
if (userTotalBid == 0) {
revert ZeroBids(claimant);
}
// determine the split between tokens and refund
// limit to the maximum tokens a wallet can win in the auction
uint mintAmount = Math.min(
// @dev no precision loss in division below, we only need the whole part
Math.min(userTotalBid / auction.price, auction.maxWinPerWallet),
auction.remainingSupply
);
uint128 podsMintCost = uint128(mintAmount) * auction.price;
// if any pods are won
// the mintAmount is adjusted for supply above,
// hence it can be 0 again if no supply has been left
if (mintAmount > 0) {
unchecked {
// does not overflow, mintAmount is limited to the supply left
auctions[_auctionId].remainingSupply = uint16(
auction.remainingSupply - mintAmount
);
// increase the withdrawable amount
withdrawableFunds = withdrawableFunds + podsMintCost;
}
// mint the tokens
_mint(claimant, mintAmount);
}
// send the refund
uint128 refund = userTotalBid - podsMintCost;
if (refund > 0) {
// write the refund to state
bidders[_auctionId][claimant].refundedFunds =
user.refundedFunds +
SafeCast.toUint120(refund);
(bool success, ) = claimant.call{value: refund}("");
if (!success) {
revert RefundFailed(claimant, refund);
}
emit RefundSent(claimant, refund);
}
emit Claimed(claimant, userTotalBid, mintAmount, refund);
}
// function currentAuction() external view returns (Auction memory) {
// return auctions[activeAuction];
// }
}
// #region Layout of Contract:
// version
// imports
// errors
// interfaces, libraries, contracts
// Type declarations
// State variables
// Events
// Modifiers
// Functions
// Layout of Functions:
// constructor
// receive function (if exists)
// fallback function (if exists)
// external
// public
// internal
// private
// view & pure functions
// #endregion
// SPDX-License-Identifier: UNLICENCED
pragma solidity 0.8.20;
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
contract XCrates {
using SafeCast for uint256;
enum CrateState {
None,
Locked,
WinnerDrawn,
Unlocked
}
struct XCrate {
/* Slot 1 - 32 bytes */
address requiredOwnership; // 20 bytes
// the expiration time for the winner to open the crate
// typically it's CLAIM_DEADLINE (i.e. 48hrs) from the winner being drawn
uint64 expires; // 8 bytes
uint16 id; // 2 bytes
uint8 forRound; // 1 byte
CrateState state; // 1 byte
}
// the current crate id
uint16 public crateId;
mapping(uint16 crateId => uint16 tokenId) internal crateWinningToken;
// the released x crates
mapping(uint16 crateId => XCrate) public crates;
mapping(uint16 crateId => address winner) public crateWinners;
// #region events
event XCreateCreated(
uint16 indexed crateId,
uint8 indexed forRound,
address indexed requiredOwnership
);
// #endregion
// #region internal functions
function _setupCrate(uint8 forRound, address requiredOwnership) internal {
// throw if exceeding 2^16-1 crates
uint16 _crateId = SafeCast.toUint16(crateId + 1);
// increment the crate id
crateId = _crateId;
// create the new crate
crates[_crateId] = XCrate({
requiredOwnership: requiredOwnership,
id: _crateId,
forRound: forRound,
state: CrateState.Locked,
expires: 0
});
emit XCreateCreated(_crateId, forRound, requiredOwnership);
}
// #endregion
// #region external functions
// #endregion
}
// Layout of Contract:
// version
// imports
// errors
// interfaces, libraries, contracts
// Type declarations
// State variables
// Events
// Modifiers
// Functions
// Layout of Functions:
// constructor
// receive function (if exists)
// fallback function (if exists)
// external
// public
// internal
// private
// view & pure functions
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/access/Ownable.sol";
import {VRFCoordinatorV2Interface} from "@chainlink/interfaces/VRFCoordinatorV2Interface.sol";
import {VRFConsumerBaseV2} from "@chainlink/vrf/VRFConsumerBaseV2.sol";
// import {AutomationCompatibleInterface} from "@chainlink/interfaces/automation/AutomationCompatibleInterface.sol";
/* Enums */
enum RequestType {
None,
Raffle,
XCrate
}
/**@title A sample VRF Contract
* @notice This contract is for creating a sample raffle contract
* @dev This implements the Chainlink VRF Version 2
*/
abstract contract XKeyVRFInterface is VRFConsumerBaseV2 {
/* Errors */
error AlreadyRequested();
error InvalidVRFRequestType();
/* Events */
// event VRFRequest(uint256 indexed requestId, RequestType indexed _type);
/* State variables */
// Chainlink VRF Variables
VRFCoordinatorV2Interface private immutable vrfCoordinator;
uint64 private immutable vrfSubscriptionId;
address private immutable vrfV2CoordinatorAddress;
bytes32 private immutable gasLane;
/* VRF config constants */
uint32 private constant CALLBACK_GAS_LIMIT = 500000;
uint16 private constant REQUEST_CONFIRMATIONS = 3;
uint32 private constant NUM_WORDS = 1;
// current request for a winner for a round
uint8 public awaitingWinnerForRound;
// current request for a winner for a crate
uint16 public awaitingWinnerForCrate;
mapping(uint256 => RequestType) internal vrfRequests;
mapping(uint256 requestId => uint16 crateId) internal vrfIdToCrateId;
/* Functions */
constructor(
address _vrfCoordinator,
uint64 _vrfSubscriptionId,
bytes32 _gasLane
) VRFConsumerBaseV2(_vrfCoordinator) {
// initialize Chainlink VRF
vrfCoordinator = VRFCoordinatorV2Interface(_vrfCoordinator);
// initialize immutable variables
vrfV2CoordinatorAddress = _vrfCoordinator;
vrfSubscriptionId = _vrfSubscriptionId;
gasLane = _gasLane;
}
function sendVRFRequest() internal returns (uint256) {
uint256 requestId = vrfCoordinator.requestRandomWords(
gasLane,
vrfSubscriptionId,
REQUEST_CONFIRMATIONS,
CALLBACK_GAS_LIMIT,
NUM_WORDS
);
// @todo comment out for mainnet;
// only needed for VRFCoordinatorV2Mock in unit tests
// pendingRequestId = requestId;
return requestId;
}
function _placeRequestInternal(RequestType _type) internal returns (uint256) {
uint256 requestId = sendVRFRequest();
// set the request type
vrfRequests[requestId] = _type;
// emit VRFRequest(requestId, _type);
return requestId;
}
function requestWinningTokenForRound(uint8 round) internal {
if (awaitingWinnerForRound != 0) {
revert AlreadyRequested();
}
awaitingWinnerForRound = round;
_placeRequestInternal(RequestType.Raffle);
}
function requestWinnerForCrate(uint16 crateId) internal {
if (awaitingWinnerForCrate != 0) {
revert AlreadyRequested();
}
awaitingWinnerForCrate = crateId;
uint256 requestId = _placeRequestInternal(RequestType.XCrate);
// record the crateId for the requestId
vrfIdToCrateId[requestId] = crateId;
}
}
/*
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ @@@, @@@@@( @@@ @/ &# @ .@@@@@@ *@@@@@@@@@@* %@@@
@@ V. @@@@@ @@@ / @ @ %@@@ @@, @@
@@ @> @. @@@@@ @@ @ @@@@@@, @@@@@@@ @@@ /@* *@@
@@ ^. @@@@ (@ @ /@@@, @& #& %@@@@@@@@@@
@@ (@, @@@@ % (@ @ /@@@, @ @& .@@@@@@@@@@@
@@ ,@@@@@, @@@# @ @ @@@@@@, @@@@@@@* @ @@@ @@@
@@ ,@@@@@, # #% @ @ @ @@@, @@@@@@ /@@& @@
@@ ,@@@@@, # #@, @ @/ @ @@@, @@@@@@@ @@@@@@@( *@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Planet-X X-Keys
playplanetx.com
Planet-X Ltd © 2023 | All rights reserved
cfec19b223b57f38d96f52994b515d455b5dd1bb3741b8791ada32f862e95879
*/
// #region Layout of Contract:
// version
// imports
// errors
// interfaces, libraries, contracts
// Type declarations
// State variables
// Events
// Modifiers
// Functions
// Layout of Functions:
// constructor
// receive function (if exists)
// fallback function (if exists)
// external
// public
// internal
// private
// view & pure functions
// #endregion
// SPDX-License-Identifier: UNLICENCED
pragma solidity 0.8.20;
import "../base/Withdrawer.sol";
import "./XRaffleBase.sol";
import "../auctions/XAuctions.sol";
// #region errors
error NullAddressParameters();
error ForbiddenDuringRaffle();
// #endregion
/**
X-Keys raffle auctions contract.
@dev This contract is used to mint an X-Key NFTs in 3 different ways:
1. Raffle: users can mint an XKey for free by owning a specific NFT.
2. Auction: users can bid for a chance to buy an XKey in an auction round.
3. Limited airdrop, see RESERVED_SUPPLY
*/
contract XKeys is XRaffleBase, XAuctions, ReentrancyGuard {
enum RoundType {
None,
Raffle,
Auction
}
// the total number of X Key NFTs that have been allocated by rounds created so far
uint16 public totalSupplyAllocated;
// the total number of X Key NFTs that can be minted
uint16 private constant MAX_SUPPLY = 500;
// the number of reserved X Keys for team & marketing
uint8 private constant RESERVED_SUPPLY = 25;
// reserved tokens already minted
uint8 public mintedReserved;
// current round type
RoundType currentRound;
modifier requireRound(RoundType _round) {
_checkRoundType(_round);
_;
}
constructor(
address vrfCoordinator,
uint64 vrfSubscriptionId,
bytes32 vrfKeyHash,
address delegateRegistryAddress
)
payable
XRaffleBase(
"X-Key",
"X-KEY",
500, // 5% royalty
msg.sender, // royalty recipient
vrfCoordinator,
vrfSubscriptionId,
vrfKeyHash,
delegateRegistryAddress,
48 hours // reward claim deadline for raffle rounds
)
{}
// #region External functions
function mintReservedTokens(uint8 number, address to) external payable onlyOwner {
// don't allow airdrops during a raffle
if (currentRound == RoundType.Raffle) {
revert ForbiddenDuringRaffle();
}
uint8 _minted = mintedReserved;
if (_minted + number > RESERVED_SUPPLY) {
revert ExceedsMaxSupply();
}
mintedReserved = _minted + number;
_mint(to, number);
}
function closeRound() external payable onlyOwner {
_closeRound(true);
}
function releaseNewRaffleRound(
uint16 _supply,
address requiredOwnership
) external payable onlyOwner {
// no raffle can be created with less than 2 tokens
if (_supply < 2) {
revert SupplyTooSmall();
}
// the contract must be an ERC721 contract
if (!_isNFTContract(requiredOwnership)) {
revert NotAnNFTContract(requiredOwnership);
}
if (currentRound == RoundType.Raffle) {
revert RoundMustBeClosed();
}
// supply must not exceed max supply, taking into account the reserved supply
_addNewRoundWithSupply(_supply);
uint8 _roundId = roundId;
raffles[roundId] = Raffle({
id: _roundId,
requiredOwnership: requiredOwnership,
supply: _supply,
supplyLeft: _supply,
stage: RaffleStage.Open,
startTokenId: uint16(_totalMinted() + 1)
});
// set the current round to raffle
currentRound = RoundType.Raffle;
emit RoundCreated(_roundId, requiredOwnership, _supply);
}
function releaseNewAuctionRound(
uint16 _supply,
uint8 _maxWinPerWallet,
uint64 _minimumBid
) external payable onlyOwner requireRound(RoundType.None) {
// _checkCreateParams(_supply, _maxWinPerWallet, _minimumBid);
_addNewRoundWithSupply(_supply);
// set the current round to auction
currentRound = RoundType.Auction;
_saveNewAuction(roundId, _supply, _maxWinPerWallet, _minimumBid);
}
/**
* @notice Respond to a mint request
* @param _roundId The round id
* @param minter The minter address
* @param approved Whether the mint request is approved
* @dev To ensure 1 holder can only claim 1 XKey per round, we need to verify
* that the NFT which they hold, allowing them to mint, is not already used by another minter
* this is done externally by our backend, and the result is passed to this function
*/
function validateMintRequest(
uint8 _roundId,
address minter,
bool approved
) external payable onlyOwner requireRound(RoundType.Raffle) {
// mint if the request is approved
uint256 _supplyLeft = _validateMintRequest(_roundId, minter, approved);
if (_supplyLeft < 1) {
// if the pool is full, close the round
_closeRound(false);
}
}
function mintXKey() external nonReentrant requireRound(RoundType.Raffle) {
_mintInRaffle(roundId);
}
/**
* @notice Claim an XKey from a hot wallet
*/
function mintXKeyDelegated(
address vault,
address to
) external nonReentrant requireRound(RoundType.Raffle) {
if (vault == address(0) || to == address(0)) {
revert NullAddressParameters();
}
_mintInRaffleDelegated(vault, to, roundId);
}
/// @notice Claim the reward via a delegated wallet
/// @param _roundId The round id
/// @param vault The vault for which to check delegation for msg.sender
function claimRewardDelegated(
uint8 _roundId,
address vault
) external isDelegated(vault) {
_claimRewardInternal(_roundId, vault);
}
/// @notice Open a crate via a delegated wallet
/// @param _crateId The crate id
/// @param vault The vault which will
function openCrateDelegated(
uint16 _crateId,
address vault
) external isDelegated(vault) {
_openCrateInternal(_crateId, msg.sender);
}
// #region auction functions
function startAuction() external payable onlyOwner requireRound(RoundType.Auction) {
_startAuction(roundId);
}
function bid() external payable requireRound(RoundType.Auction) {
XAuctions.bid(roundId);
}
function setPriceForAuction(
uint8 _auctionId,
uint64 newPrice
) external payable onlyOwner {
_setPrice(_auctionId, newPrice);
}
function startClaimsForAuction(uint8 _auctionId) external payable onlyOwner {
_startClaims(_auctionId);
}
/**
* @notice Claim tokens and refund for a specific auction.
*/
function claimForAuction(uint8 forAuctionId) external nonReentrant {
// don't allow claims during an active raffle
if (currentRound == RoundType.Raffle) {
revert ForbiddenDuringRaffle();
}
_internalClaim(msg.sender, forAuctionId);
}
// function currentAuction()
// external
// view
// requireRound(RoundType.Auction)
// returns (Auction memory)
// {
// return auctions[roundId];
// }
// #endregion
/**
* @notice Withdraw function for the owner
* @dev since only NFT sales funds can be withdrawn at any time
* and users' funds need to be protected, this is marked as nonReentrant
*/
function withdraw(address payable receiver) external onlyOwner nonReentrant {
_withdraw(receiver);
}
// #endregion
// #region internal functions
function _addNewRoundWithSupply(uint16 _newSupply) internal {
// supply must not exceed max supply, taking into account the reserved supply
uint16 _totalSupply = totalSupplyAllocated;
if (_totalSupply + _newSupply > MAX_SUPPLY - RESERVED_SUPPLY) {
revert ExceedsMaxSupply();
}
unchecked {
// allocate the supply
totalSupplyAllocated = _totalSupply + _newSupply;
// increment the round id
++roundId;
}
}
// #endregion
// #region private functions
function _checkRoundType(RoundType _round) private view {
if (_round != currentRound) {
revert InvalidRound();
}
}
function _closeRound(bool checkSupply) private {
RoundType _round = currentRound;
if (_round == RoundType.None) {
revert InvalidRound();
}
currentRound = RoundType.None;
uint8 _roundId = roundId;
if (_round == RoundType.Raffle) {
if (raffles[_roundId].stage != RaffleStage.Open) {
revert InvalidRaffleStage();
}
// close the round
raffles[_roundId].stage = RaffleStage.Closed;
// if the full supply allocated for this round is not claimed
// release it back
if (checkSupply) {
uint16 _supplyLeft = raffles[_roundId].supplyLeft;
if (_supplyLeft > 0) {
unchecked {
totalSupplyAllocated = totalSupplyAllocated - _supplyLeft;
}
}
}
emit RoundClosed(roundId);
} else {
if (auctions[_roundId].stage != AuctionStage.Active) {
revert AuctionMustBeActive();
}
// end the auction
auctions[_roundId].stage = AuctionStage.Closed;
activeAuctionId = 0;
emit AuctionEnded(_roundId);
}
}
// #endregion
}
// SPDX-License-Identifier: UNLICENCED
pragma solidity 0.8.20;
import "@openzeppelin/contracts/token/common/ERC2981.sol";
import "operator-filter-registry/src/DefaultOperatorFilterer.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "erc721a/contracts/extensions/ERC721AQueryable.sol";
/**
This base contract provides a combination of common base inheritance for PlanetX NFTs.
It includes: Royalties (ERC2981), OperatorFiltering (OperatorFilterRegistry)
and overries for basic ERC721A functionality - start token id and base uri.
*/
contract XNFTRoyaltyBase is DefaultOperatorFilterer, ERC721AQueryable, ERC2981, Ownable {
// the base URI for the metadata
string public baseURI;
// the URI for the contract level metadata
// @dev see https://docs.opensea.io/docs/contract-level-metadata
string private contractMetadataURI;
event RoyaltyChanged(address indexed receiver, uint96 feeNumerator);
event BaseURISet(string baseURI);
error EmptyBaseURI();
constructor(
string memory name,
string memory symbol,
uint96 royalty,
address receiver
) ERC721A(name, symbol) {
// set the default royalty
_setDefaultRoyalty(receiver, royalty);
}
/**
* @dev override from ERC721A
*/
function _baseURI() internal view override returns (string memory) {
return baseURI;
}
/**
* @dev overriding from ERC721: start at the 1st token instead of 0
*/
function _startTokenId() internal pure override returns (uint256) {
return 1;
}
/**
* @dev sets the base uri for {_baseURI}
*/
function setBaseURI(string calldata newBaseURI) external onlyOwner {
if (bytes(newBaseURI).length == 0) {
revert EmptyBaseURI();
}
baseURI = newBaseURI;
emit BaseURISet(newBaseURI);
}
// contract level metadata
function contractURI() external view returns (string memory) {
return contractMetadataURI;
}
function setContractURI(string calldata newURI) external payable onlyOwner {
contractMetadataURI = newURI;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ERC2981, IERC721A, ERC721A) returns (bool) {
return ERC721A.supportsInterface(interfaceId);
}
////////////////
// ERC2981 royalty standard
////////////////
/**
* @dev See {ERC2981-_setDefaultRoyalty}.
*/
function setDefaultRoyalty(
address receiver,
uint96 feeNumerator
) external payable onlyOwner {
_setDefaultRoyalty(receiver, feeNumerator);
emit RoyaltyChanged(receiver, feeNumerator);
}
/**
* @dev See {ERC2981-_deleteDefaultRoyalty}.
*/
function deleteDefaultRoyalty() external payable onlyOwner {
_deleteDefaultRoyalty();
}
////////////////
// overrides for using OpenSea's OperatorFilter to filter out platforms which are know to not enforce
// creator earnings
////////////////
function setApprovalForAll(
address operator,
bool approved
) public override(ERC721A, IERC721A) onlyAllowedOperatorApproval(operator) {
super.setApprovalForAll(operator, approved);
}
function approve(
address operator,
uint256 tokenId
) public payable override(ERC721A, IERC721A) onlyAllowedOperatorApproval(operator) {
super.approve(operator, tokenId);
}
function transferFrom(
address from,
address to,
uint256 tokenId
) public payable override(ERC721A, IERC721A) onlyAllowedOperator(from) {
super.transferFrom(from, to, tokenId);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public payable override(ERC721A, IERC721A) onlyAllowedOperator(from) {
super.safeTransferFrom(from, to, tokenId);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory data
) public payable override(ERC721A, IERC721A) onlyAllowedOperator(from) {
super.safeTransferFrom(from, to, tokenId, data);
}
//////////
// end of OpenSea DefaultOperatorFilter overrides
}
// #region Layout of Contract:
// version
// imports
// errors
// interfaces, libraries, contracts
// Type declarations
// State variables
// Events
// Modifiers
// Functions
// Layout of Functions:
// constructor
// receive function (if exists)
// fallback function (if exists)
// external
// public
// internal
// private
// view & pure functions
// #endregion
// SPDX-License-Identifier: UNLICENCED
pragma solidity 0.8.20;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "../utils/DelegateUtils.sol";
import "./XKeyVRFInterface.sol";
import "../base/XNFTRoyaltyBase.sol";
import "./XCrates.sol";
// #region Errors
error AlreadyMinted();
error RoundMustBeClosed();
error NFTOwnershipMissing(address nftContract);
error InsufficientBalance();
error NotAnNFTContract(address nftContract);
error ExceedsMaxSupply();
error CannotResetReward();
error RewardExpired();
error RewardNotExpired();
error YouDidNotWin();
error InvalidRaffleStage();
error NoWinningToken();
error CrateMustBeLocked();
error CrateAlreadyOpened();
error SupplyTooSmall();
error RoundPoolTooSmall();
error InvalidRound();
error RoundTokenPoolEmpty();
error MintRequestStateMismatch();
error CannotRedrawUnwonCrate();
// #endregion
contract XRaffleBase is XCrates, XKeyVRFInterface, XNFTRoyaltyBase, DelegateUtils {
using SafeCast for uint256;
struct Raffle {
address requiredOwnership; // 20 bytes
uint16 id; // 2 bytes
uint16 supply; // 2 bytes
uint16 supplyLeft; // 2 bytes
uint16 startTokenId; // 2 bytes
RaffleStage stage; // 1 byte
}
enum MintStatus {
None,
Pending,
Fulfilled,
Rejected,
SupplyExceeded,
UsedAsVault,
UsedAsDelegate
}
enum RaffleStage {
None,
Open,
Closed,
WinnerDrawn,
RewardClaimed
}
// the number of seconds after which the reward can be claimed
uint64 private immutable CLAIM_DEADLINE;
// the timestamp beyond which the reward can not be claimed
uint64 public nextClaimDeadline;
// the current raffle round
uint8 public roundId;
mapping(uint8 roundId => address) public roundWinners;
mapping(uint8 roundId => uint16 tokenId) private _roundWinningToken;
mapping(uint8 roundId => Raffle) public raffles;
// the status of a minter address in each raffle round
mapping(uint8 roundId => mapping(address minter => MintStatus)) public raffleMinters;
// the pool of tokens for each round
mapping(uint8 roundId => uint16[] tokenId) public roundTokenPool;
// #region Events
event RoundCreated(
uint16 indexed roundId,
address indexed requiredOwnership,
uint16 supply
);
event RoundClosed(uint16 indexed roundId);
event WinnerDrawn(RequestType indexed _type, uint16 indexed id);
event RewardClaimed(
uint16 indexed roundId,
uint16 indexed tokenId,
address indexed winner
);
event MintRequested(uint16 indexed roundId, address indexed minter);
event MintDecision(uint16 indexed roundId, address indexed minter, bool isApproved);
event CrateUnlocked(uint16 indexed crateId, address indexed winner);
event WinningToken(uint256 tokenId);
// #endregion
// #region Modifiers
modifier notMintedInRound(uint8 _roundId, address minter) {
// must mint once per round
_checkNotMintedInRound(_roundId, minter);
_;
}
// #endregion
constructor(
string memory name,
string memory symbol,
uint96 royalty,
address receiver,
address vrfCoordinator,
uint64 vrfSubscriptionId,
bytes32 vrfKeyHash,
address delegateRegistryAddress,
uint64 claimDeadline
)
payable
XKeyVRFInterface(vrfCoordinator, vrfSubscriptionId, vrfKeyHash)
XNFTRoyaltyBase(name, symbol, royalty, receiver)
DelegateUtils(delegateRegistryAddress)
{
CLAIM_DEADLINE = claimDeadline;
}
// #region External functions
// function hasMintedInThisRound(address minter) external view returns (bool) {
// return _hasMintedInRound(minter, roundId);
// }
// function currentRaffle() external view returns (Raffle memory) {
// return raffles[roundId];
// }
function checkCanOpenCrate(
uint16 _crateId,
address minter
) external view returns (bool) {
uint16 tokenId = crateWinningToken[_crateId];
bool canOpen = _exists(tokenId) && ownerOf(crateWinningToken[_crateId]) == minter;
if (canOpen) {
address _mustOwn = crates[_crateId].requiredOwnership;
if (_mustOwn != address(0)) {
// check that the claimant owns the required token
if (IERC721(_mustOwn).balanceOf(minter) < 1) {
canOpen = false;
}
}
}
return canOpen;
}
// function balancesOf(
// address[] calldata addresses
// ) external view returns (uint256[] memory) {
// uint256[] memory balances = new uint256[](addresses.length);
// for (uint256 i = 0; i < addresses.length; i++) {
// balances[i] = balanceOf(addresses[i]);
// }
// return balances;
// }
function claimReward(uint8 _roundId) external {
_claimRewardInternal(_roundId, msg.sender);
}
function openCrate(uint16 _crateId) external {
_openCrateInternal(_crateId, msg.sender);
}
function drawWinner(RequestType _type, uint16 id) external payable onlyOwner {
_drawWinnerInternal(_type, id);
}
function resetWinnerWhenRewardExpires() external payable onlyOwner {
// the reward must have a winner selected
uint8 _roundId = roundId;
if (raffles[_roundId].stage != RaffleStage.WinnerDrawn) {
revert CannotResetReward();
}
// the time for claiming the reward must have passed
if (!isRewardExpired()) {
revert RewardNotExpired();
}
// reset the winner
_roundWinningToken[_roundId] = 0;
// draw a random winner
requestWinningTokenForRound(_roundId);
}
/**
* @notice Release a new X-Crate, which can be opened by holders of a specific NFT and/or an X-Key from a specific round
* @param forRound The round for which the crate is released (0 - for all rounds)
* @param requiredOwnership The address of the NFT contract which must be owned to open the crate (address(0) - removes the requirement)
*/
function releaseCrate(
uint8 forRound,
address requiredOwnership
) external payable onlyOwner {
if (requiredOwnership != address(0)) {
// the contract must be an ERC721 contract
if (!_isNFTContract(requiredOwnership)) {
revert NotAnNFTContract(requiredOwnership);
}
}
// if the crate is only for a specific round
if (forRound > 0) {
// no crates can be created for a round in the future
if (forRound > roundId) {
revert InvalidRound();
}
// revert if there are no tokens in the round pool
if (roundTokenPool[forRound].length == 0) {
revert RoundTokenPoolEmpty();
}
// prevent creating a crate for a round
// if so many keys have been burned, that less than 2 are left
if (!_checkEnoughTokensInRoundPool(forRound)) {
revert RoundPoolTooSmall();
}
} else {
// ensure that enough supply is left for a crate
if (totalSupply() < 2) {
revert SupplyTooSmall();
}
}
_setupCrate(forRound, requiredOwnership);
}
function tokenPoolOfRound(uint8 _roundId) external view returns (uint16[] memory) {
return roundTokenPool[_roundId];
}
function checkWin(uint8 _roundId, address minter) external view returns (bool) {
return _checkWinInternal(_roundId, minter);
}
// #endregion
// #region Public functions
function isRewardExpired() public view returns (bool) {
// when nextClaimDeadline is 0 initially or when reward is claimed
// the timestamp will always be greater than nextClaimDeadline
// therefore the reward is always expired except when after the draw
return block.timestamp > nextClaimDeadline;
}
// #endregion
// #region Internal functions
function _isNFTContract(address contractAddress) internal view returns (bool) {
// check if the contract supports the ERC721 interface
return IERC721(contractAddress).supportsInterface(0x80ac58cd);
}
function _checkNotMintedInRound(uint8 _roundId, address minter) internal view {
if (raffleMinters[_roundId][minter] != MintStatus.None) {
revert AlreadyMinted();
}
}
function _checkWinInternal(
uint8 _roundId,
address winner
) internal view returns (bool) {
uint16 tokenId = _roundWinningToken[_roundId];
return _exists(tokenId) && ownerOf(tokenId) == winner;
}
function _adjustWinnerForBurnedTokens(
uint256 tokenId,
uint256 rangeLimit
) internal view returns (uint256) {
// if the token selected has been burned,
// select the previous token and wrap around if necessary
while (!_exists(tokenId)) {
unchecked {
if (tokenId > 1) {
--tokenId;
} else {
// loop back to the end of the range
tokenId = rangeLimit;
}
}
}
return tokenId;
}
/**
* @dev iterate over the supply to find an unburned winning token based on the Chainlink VRF random number
* @param vrfWord the random number returned by Chainlink
*/
function _getWinningTokenFromSupply(uint256 vrfWord) internal view returns (uint256) {
// @dev randomWord % _totalMinted() will give a number between 0 and _totalMinted().
// However, startTokenId is 1 and the modulus will give (totalMinted - 1) as the maximum value selected,
// therefore adding 1 to the result will give a number between 1 and _totalMinted() inclusive
uint256 mintCount = _totalMinted();
uint256 winningToken = _adjustWinnerForBurnedTokens(
(vrfWord % mintCount) + 1,
mintCount
);
return winningToken;
}
function _mintInRaffle(
uint8 _roundId
) internal notMintedInRound(_roundId, msg.sender) {
// minting this token must not exceed the max supply for the round
if (raffles[_roundId].supplyLeft == 0) {
revert ExceedsMaxSupply();
}
// must own the required NFT
_checkOwnsNFT(raffles[_roundId].requiredOwnership, msg.sender);
// add the minter to the round minters
raffleMinters[_roundId][msg.sender] = MintStatus.Pending;
emit MintRequested(_roundId, msg.sender);
}
function _mintInRaffleDelegated(
address vault,
address to,
uint8 _roundId
) internal notMintedInRound(_roundId, vault) {
// add the receiver to the round minters
raffleMinters[_roundId][to] = MintStatus.Pending;
// mark the vault as used
if (vault != to) {
raffleMinters[_roundId][vault] = MintStatus.UsedAsVault;
}
if (msg.sender != to) {
raffleMinters[_roundId][msg.sender] = MintStatus.UsedAsDelegate;
}
// minting this token must not exceed the max supply for the round
// if (raffleTokenPool[_roundId].length + 1 > raffle.supply) {
if (raffles[_roundId].supplyLeft == 0) {
revert ExceedsMaxSupply();
}
// check the delegation registry to see if the msg.sender is delegated by the vault
address requiredOwnership = raffles[_roundId].requiredOwnership;
_checkDelegation(vault, requiredOwnership);
// must own the required NFT
_checkOwnsNFT(requiredOwnership, vault);
emit MintRequested(_roundId, to);
}
/**
* @dev This is the function that Chainlink VRF node calls
*/
function fulfillRandomWords(
uint256 requestId,
uint256[] memory randomWords
) internal override {
RequestType _type = vrfRequests[requestId];
if (_type == RequestType.Raffle) {
// handle winner being picked for a raffle
// select a winner from the existing tokens in supply
uint256 winningToken = _getWinningTokenFromSupply(randomWords[0]);
// set the winning token for the round
_recordRoundWinner(roundId, uint16(winningToken));
} else if (_type == RequestType.XCrate) {
// read crate in memory
// XCrate memory crate = crates[vrfIdToCrateId[requestId]];
uint16 _crateId = vrfIdToCrateId[requestId];
uint8 forRound = crates[_crateId].forRound;
uint256 winningToken;
// if the crate is only openable by keys in a given round
if (forRound > 0) {
// read the token pool size
uint16[] memory pool = roundTokenPool[forRound];
uint256 poolSize = pool.length;
uint256 indexOfWinToken = randomWords[0] % poolSize;
// in case of any burned tokens, search for the previous token
// and wrap around if necessary
while (!_exists(pool[indexOfWinToken])) {
unchecked {
if (indexOfWinToken > 0) {
--indexOfWinToken;
} else {
// loop back to the end of the array
indexOfWinToken = poolSize - 1;
}
}
}
// set the winning token
winningToken = pool[indexOfWinToken];
} else {
// pick a random token from the entire supply
winningToken = _getWinningTokenFromSupply(randomWords[0]);
}
// set the winning token for the crate
_recordCrateWinner(_crateId, uint16(winningToken));
} else {
revert InvalidVRFRequestType();
}
}
function _drawWinnerInternal(RequestType _type, uint16 id) internal {
if (_type == RequestType.Raffle) {
uint8 raffleId = SafeCast.toUint8(id);
if (raffles[raffleId].stage != RaffleStage.Closed) {
revert RoundMustBeClosed();
}
if (roundTokenPool[raffleId].length == 0) {
revert NoWinningToken();
}
// draw a random winner
requestWinningTokenForRound(raffleId);
} else if (_type == RequestType.XCrate) {
// @dev crates winners can be drawn, after which the winner has a certain amount of time
// to open the crate, otherwise the crate expires and a new winner can be drawn
// check for an expired crate
uint256 expires = crates[id].expires;
if (expires > 0 && expires > block.timestamp) {
// the crate has expired
// check that the crate is in a state where a new winner can be drawn
if (crates[id].state != CrateState.WinnerDrawn) {
revert CannotRedrawUnwonCrate();
}
// continue to draw a new winner
} else {
// crate has no expiration or has not expired
// check that the crate is locked
if (crates[id].state != CrateState.Locked) {
revert CrateMustBeLocked();
}
}
requestWinnerForCrate(id);
}
}
function _recordRoundWinner(uint8 _roundId, uint16 tokenId) internal {
awaitingWinnerForRound = 0;
// set the winning token
_roundWinningToken[_roundId] = tokenId;
// set the raffle stage
raffles[_roundId].stage = RaffleStage.WinnerDrawn;
// set the deadline for claiming the reward
nextClaimDeadline = SafeCast.toUint64(block.timestamp + CLAIM_DEADLINE);
emit WinningToken(tokenId);
// the omission of the winning token is intentional
emit WinnerDrawn(RequestType.Raffle, _roundId);
}
function _recordCrateWinner(uint16 _crateId, uint16 tokenId) internal {
// reset the crate state
awaitingWinnerForCrate = 0;
// store the winning token
crateWinningToken[_crateId] = tokenId;
// set the crate state
if (crates[_crateId].state != CrateState.WinnerDrawn) {
// set the crate state
crates[_crateId].state = CrateState.WinnerDrawn;
}
// set the deadline for claiming the reward
crates[_crateId].expires = SafeCast.toUint64(block.timestamp + CLAIM_DEADLINE);
emit WinningToken(tokenId);
// emit the event
emit WinnerDrawn(RequestType.XCrate, _crateId);
}
function _claimRewardInternal(uint8 _roundId, address claimant) internal {
uint16 winningToken = _roundWinningToken[_roundId];
if (winningToken == 0) {
revert NoWinningToken();
}
if (ownerOf(winningToken) != claimant) {
revert YouDidNotWin();
}
if (isRewardExpired()) {
revert RewardExpired();
}
// set reward as claimed and reset the deadline
raffles[_roundId].stage = RaffleStage.RewardClaimed;
nextClaimDeadline = 0;
// record the winner
roundWinners[_roundId] = claimant;
// burn the winning token
_burn(winningToken);
// // set the token as burned
// burnedTokens.set(winningToken);
emit RewardClaimed(_roundId, winningToken, claimant);
}
function _openCrateInternal(uint16 _crateId, address claimant) internal {
if (balanceOf(claimant) < 1) {
revert InsufficientBalance();
}
uint16 winningToken = crateWinningToken[_crateId];
if (winningToken == 0) {
revert NoWinningToken();
}
// @dev no need to check if the crate is locked, because the winning token
// would have been burned and an earlier check would have reverted
// CrateState state = crates[_crateId].state;
// if (state == CrateState.Unlocked) {
// revert CrateAlreadyOpened();
// }
if (ownerOf(winningToken) != claimant) {
revert YouDidNotWin();
}
// check that the opening hasn't expired
if (block.timestamp > crates[_crateId].expires) {
revert RewardExpired();
}
address _mustOwn = crates[_crateId].requiredOwnership;
if (_mustOwn != address(0)) {
// check that the claimant owns the required token
_checkOwnsNFT(_mustOwn, claimant);
}
// burn the winning token
_burn(winningToken);
// set crate as unlocked and record the winner
crates[_crateId].state = CrateState.Unlocked;
crateWinners[_crateId] = claimant;
emit CrateUnlocked(_crateId, claimant);
}
function _checkEnoughTokensInRoundPool(uint8 _roundId) internal view returns (bool) {
uint16[] memory pool = roundTokenPool[_roundId];
uint256 unburned;
uint256 poolIdx = pool.length - 1;
// does not overflow
unchecked {
do {
if (_exists(pool[poolIdx])) {
++unburned;
}
// at least 2 tokens must be unburned
if (unburned > 1) {
return true;
}
--poolIdx;
} while (poolIdx > 0);
}
return false;
}
function _checkOwnsNFT(address _erc721, address _owner) internal view {
if (IERC721(_erc721).balanceOf(_owner) < 1) {
revert NFTOwnershipMissing(_erc721);
}
}
function _validateMintRequest(
uint8 _roundId,
address minter,
bool approved
) internal returns (uint256) {
if (raffleMinters[_roundId][minter] != MintStatus.Pending) {
revert MintRequestStateMismatch();
}
// total supply for this round
uint16 _supplyLeft = raffles[_roundId].supplyLeft;
// update the mint status
raffleMinters[_roundId][minter] = _supplyLeft < 1
? MintStatus.SupplyExceeded
: approved
? MintStatus.Fulfilled
: MintStatus.Rejected;
bool _willMint = approved && _supplyLeft > 0;
if (_willMint) {
// update the supply left
unchecked {
// @dev does not wrap around, because _supplyLeft > 0 in the if statement above
--_supplyLeft;
raffles[_roundId].supplyLeft = _supplyLeft;
}
// mint an XKey to the minter
_mint(minter, 1);
// add the last minted token to the pool
roundTokenPool[_roundId].push(uint16(_totalMinted()));
}
emit MintDecision(_roundId, minter, _willMint);
return _supplyLeft;
}
// #endregion
// #region Private functions
// #endregion
}
{
"compilationTarget": {
"src/x-key/XKeys.sol": "XKeys"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@chainlink/=lib/chainlink/contracts/src/v0.8/",
":@openzeppelin/=lib/openzeppelin-contracts/",
":CramBit/=lib/foundry-random/lib/CramBit/",
":ERC721A/=lib/ERC721A/contracts/",
":chainlink/=lib/chainlink/",
":delegate-registry/=lib/delegate-registry/",
":delegate.cash/=lib/delegate-registry/src/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=lib/operator-filter-registry/lib/openzeppelin-contracts/lib/erc4626-tests/",
":erc721a/=lib/ERC721A/",
":forge-std/=lib/forge-std/src/",
":foundry-random/=lib/foundry-random/src/",
":openzeppelin-contracts-upgradeable/=lib/operator-filter-registry/lib/openzeppelin-contracts-upgradeable/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/",
":operator-filter-registry/=lib/operator-filter-registry/",
":prb-test/=lib/foundry-random/lib/prb-test/src/",
":solidity-bytes-utils/=lib/foundry-random/lib/solidity-bytes-utils/contracts/"
]
}
[{"inputs":[{"internalType":"address","name":"vrfCoordinator","type":"address"},{"internalType":"uint64","name":"vrfSubscriptionId","type":"uint64"},{"internalType":"bytes32","name":"vrfKeyHash","type":"bytes32"},{"internalType":"address","name":"delegateRegistryAddress","type":"address"}],"stateMutability":"payable","type":"constructor"},{"inputs":[{"internalType":"address","name":"claimaint","type":"address"}],"name":"AlreadyClaimed","type":"error"},{"inputs":[],"name":"AlreadyMinted","type":"error"},{"inputs":[],"name":"AlreadyRequested","type":"error"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[{"internalType":"uint8","name":"auctionId","type":"uint8"}],"name":"AuctionDoesNotExist","type":"error"},{"inputs":[],"name":"AuctionMustBeActive","type":"error"},{"inputs":[],"name":"AuctionMustNotBeStarted","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"bid","type":"uint256"},{"internalType":"uint256","name":"minBid","type":"uint256"}],"name":"BidLowerThanMinimum","type":"error"},{"inputs":[],"name":"CannotRedrawUnwonCrate","type":"error"},{"inputs":[],"name":"CannotResetReward","type":"error"},{"inputs":[],"name":"ContractCallersNotAllowed","type":"error"},{"inputs":[],"name":"CrateMustBeLocked","type":"error"},{"inputs":[],"name":"EmptyBaseURI","type":"error"},{"inputs":[],"name":"ExceedsMaxSupply","type":"error"},{"inputs":[],"name":"ForbiddenDuringRaffle","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidCreateAuctionParams","type":"error"},{"inputs":[],"name":"InvalidQueryRange","type":"error"},{"inputs":[],"name":"InvalidRaffleStage","type":"error"},{"inputs":[],"name":"InvalidRound","type":"error"},{"inputs":[{"internalType":"enum AuctionStage","name":"currentStage","type":"uint8"},{"internalType":"enum AuctionStage","name":"requiredStage","type":"uint8"}],"name":"InvalidStageForOperation","type":"error"},{"inputs":[],"name":"InvalidVRFRequestType","type":"error"},{"inputs":[],"name":"MaxSupplyExceeded","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintRequestStateMismatch","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"MultipleAuctionsViolation","type":"error"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"NFTOwnershipMissing","type":"error"},{"inputs":[],"name":"NoActiveAuction","type":"error"},{"inputs":[],"name":"NoFundsToWithdraw","type":"error"},{"inputs":[],"name":"NoWinningToken","type":"error"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"NotAnNFTContract","type":"error"},{"inputs":[],"name":"NullAddressParameter","type":"error"},{"inputs":[],"name":"NullAddressParameters","type":"error"},{"inputs":[{"internalType":"address","name":"have","type":"address"},{"internalType":"address","name":"want","type":"address"}],"name":"OnlyCoordinatorCanFulfill","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"OperatorNotAllowed","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[{"internalType":"uint256","name":"priceInput","type":"uint256"},{"internalType":"uint256","name":"minBid","type":"uint256"}],"name":"PriceIsLowerThanTheMinBid","type":"error"},{"inputs":[],"name":"PriceMustBeSet","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RefundFailed","type":"error"},{"inputs":[],"name":"RewardExpired","type":"error"},{"inputs":[],"name":"RewardNotExpired","type":"error"},{"inputs":[],"name":"RoundMustBeClosed","type":"error"},{"inputs":[],"name":"RoundPoolTooSmall","type":"error"},{"inputs":[],"name":"RoundTokenPoolEmpty","type":"error"},{"inputs":[{"internalType":"enum AuctionStage","name":"currentStage","type":"uint8"}],"name":"StageMustBeBiddingClosed","type":"error"},{"inputs":[],"name":"SupplyTooSmall","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"inputs":[{"internalType":"address","name":"hotWallet","type":"address"},{"internalType":"address","name":"vault","type":"address"}],"name":"WalletNotDelegated","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawFailed","type":"error"},{"inputs":[],"name":"WithdrawToNullAddress","type":"error"},{"inputs":[],"name":"YouDidNotWin","type":"error"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"ZeroBids","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"auctionId","type":"uint8"},{"indexed":false,"internalType":"uint16","name":"supply","type":"uint16"},{"indexed":false,"internalType":"uint8","name":"maxWinPerWallet","type":"uint8"},{"indexed":false,"internalType":"uint64","name":"minimumBid","type":"uint64"}],"name":"AuctionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"auctionId","type":"uint8"}],"name":"AuctionEnded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"auctionId","type":"uint8"}],"name":"AuctionStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"auctionId","type":"uint8"},{"indexed":true,"internalType":"address","name":"bidder","type":"address"},{"indexed":false,"internalType":"uint256","name":"bidAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bidderTotal","type":"uint256"}],"name":"Bid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalBid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"podsWon","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"refund","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"auctionId","type":"uint8"}],"name":"ClaimsAndRefundsStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"crateId","type":"uint16"},{"indexed":true,"internalType":"address","name":"winner","type":"address"}],"name":"CrateUnlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"auctionId","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"newMinBid","type":"uint256"}],"name":"MinimumBidChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"roundId","type":"uint16"},{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"MintDecision","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"roundId","type":"uint16"},{"indexed":true,"internalType":"address","name":"minter","type":"address"}],"name":"MintRequested","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":"uint8","name":"auctionId","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"newPrice","type":"uint256"}],"name":"PriceSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"RefundSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"roundId","type":"uint16"},{"indexed":true,"internalType":"uint16","name":"tokenId","type":"uint16"},{"indexed":true,"internalType":"address","name":"winner","type":"address"}],"name":"RewardClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"roundId","type":"uint16"}],"name":"RoundClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"roundId","type":"uint16"},{"indexed":true,"internalType":"address","name":"requiredOwnership","type":"address"},{"indexed":false,"internalType":"uint16","name":"supply","type":"uint16"}],"name":"RoundCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"RoyaltyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum RequestType","name":"_type","type":"uint8"},{"indexed":true,"internalType":"uint16","name":"id","type":"uint16"}],"name":"WinnerDrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"WinningToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"crateId","type":"uint16"},{"indexed":true,"internalType":"uint8","name":"forRound","type":"uint8"},{"indexed":true,"internalType":"address","name":"requiredOwnership","type":"address"}],"name":"XCreateCreated","type":"event"},{"inputs":[],"name":"OPERATOR_FILTER_REGISTRY","outputs":[{"internalType":"contract IOperatorFilterRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activeAuctionId","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"auctionId","type":"uint16"}],"name":"auctions","outputs":[{"internalType":"uint8","name":"id","type":"uint8"},{"internalType":"enum AuctionStage","name":"stage","type":"uint8"},{"internalType":"uint8","name":"maxWinPerWallet","type":"uint8"},{"internalType":"uint16","name":"supply","type":"uint16"},{"internalType":"uint16","name":"remainingSupply","type":"uint16"},{"internalType":"uint64","name":"minimumBid","type":"uint64"},{"internalType":"uint64","name":"price","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"awaitingWinnerForCrate","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"awaitingWinnerForRound","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bid","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"auctionId","type":"uint16"},{"internalType":"address","name":"","type":"address"}],"name":"bidders","outputs":[{"internalType":"uint120","name":"totalBid","type":"uint120"},{"internalType":"uint120","name":"refundedFunds","type":"uint120"},{"internalType":"bool","name":"claimed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_crateId","type":"uint16"},{"internalType":"address","name":"minter","type":"address"}],"name":"checkCanOpenCrate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"_roundId","type":"uint8"},{"internalType":"address","name":"minter","type":"address"}],"name":"checkWin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"forAuctionId","type":"uint8"}],"name":"claimForAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_roundId","type":"uint8"}],"name":"claimReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_roundId","type":"uint8"},{"internalType":"address","name":"vault","type":"address"}],"name":"claimRewardDelegated","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"closeRound","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"crateId","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"crateId","type":"uint16"}],"name":"crateWinners","outputs":[{"internalType":"address","name":"winner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"crateId","type":"uint16"}],"name":"crates","outputs":[{"internalType":"address","name":"requiredOwnership","type":"address"},{"internalType":"uint64","name":"expires","type":"uint64"},{"internalType":"uint16","name":"id","type":"uint16"},{"internalType":"uint8","name":"forRound","type":"uint8"},{"internalType":"enum XCrates.CrateState","name":"state","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delegationRegistry","outputs":[{"internalType":"contract IDelegationRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deleteDefaultRoyalty","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"enum RequestType","name":"_type","type":"uint8"},{"internalType":"uint16","name":"id","type":"uint16"}],"name":"drawWinner","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"explicitOwnershipOf","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint64","name":"startTimestamp","type":"uint64"},{"internalType":"bool","name":"burned","type":"bool"},{"internalType":"uint24","name":"extraData","type":"uint24"}],"internalType":"struct IERC721A.TokenOwnership","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"explicitOwnershipsOf","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint64","name":"startTimestamp","type":"uint64"},{"internalType":"bool","name":"burned","type":"bool"},{"internalType":"uint24","name":"extraData","type":"uint24"}],"internalType":"struct IERC721A.TokenOwnership[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isRewardExpired","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"number","type":"uint8"},{"internalType":"address","name":"to","type":"address"}],"name":"mintReservedTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mintXKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"mintXKeyDelegated","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintedReserved","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextClaimDeadline","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_crateId","type":"uint16"}],"name":"openCrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_crateId","type":"uint16"},{"internalType":"address","name":"vault","type":"address"}],"name":"openCrateDelegated","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"roundId","type":"uint8"},{"internalType":"address","name":"minter","type":"address"}],"name":"raffleMinters","outputs":[{"internalType":"enum XRaffleBase.MintStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"roundId","type":"uint8"}],"name":"raffles","outputs":[{"internalType":"address","name":"requiredOwnership","type":"address"},{"internalType":"uint16","name":"id","type":"uint16"},{"internalType":"uint16","name":"supply","type":"uint16"},{"internalType":"uint16","name":"supplyLeft","type":"uint16"},{"internalType":"uint16","name":"startTokenId","type":"uint16"},{"internalType":"enum XRaffleBase.RaffleStage","name":"stage","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256[]","name":"randomWords","type":"uint256[]"}],"name":"rawFulfillRandomWords","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"forRound","type":"uint8"},{"internalType":"address","name":"requiredOwnership","type":"address"}],"name":"releaseCrate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_supply","type":"uint16"},{"internalType":"uint8","name":"_maxWinPerWallet","type":"uint8"},{"internalType":"uint64","name":"_minimumBid","type":"uint64"}],"name":"releaseNewAuctionRound","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_supply","type":"uint16"},{"internalType":"address","name":"requiredOwnership","type":"address"}],"name":"releaseNewRaffleRound","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resetWinnerWhenRewardExpires","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"roundId","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"roundId","type":"uint8"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"roundTokenPool","outputs":[{"internalType":"uint16","name":"tokenId","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"roundId","type":"uint8"}],"name":"roundWinners","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newBaseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newURI","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"setDefaultRoyalty","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_auctionId","type":"uint8"},{"internalType":"uint64","name":"newPrice","type":"uint64"}],"name":"setPriceForAuction","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"startAuction","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_auctionId","type":"uint8"}],"name":"startClaimsForAuction","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"_roundId","type":"uint8"}],"name":"tokenPoolOfRound","outputs":[{"internalType":"uint16[]","name":"","type":"uint16[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"tokensOfOwner","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"stop","type":"uint256"}],"name":"tokensOfOwnerIn","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupplyAllocated","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_roundId","type":"uint8"},{"internalType":"address","name":"minter","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"validateMintRequest","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address payable","name":"receiver","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]