Source Code
Latest 25 from a total of 2,699 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Withdraw Artist ... | 22597147 | 8 days ago | IN | 0 ETH | 0.00040677 | ||||
Admin Artist Aut... | 22597142 | 8 days ago | IN | 0 ETH | 0.0044549 | ||||
Top Up Bid | 22597118 | 8 days ago | IN | 0.15 ETH | 0.00066318 | ||||
Top Up Bid | 22597095 | 8 days ago | IN | 0.0125 ETH | 0.00043451 | ||||
Create Bid | 22597094 | 8 days ago | IN | 1.2125 ETH | 0.00085401 | ||||
Top Up Bid | 22597091 | 8 days ago | IN | 0.0125 ETH | 0.00040343 | ||||
Top Up Bid | 22597088 | 8 days ago | IN | 0.3375 ETH | 0.00076026 | ||||
Top Up Bid | 22597081 | 8 days ago | IN | 0.325 ETH | 0.00045592 | ||||
Create Bid | 22597076 | 8 days ago | IN | 1.5 ETH | 0.00068207 | ||||
Create Bid | 22597071 | 8 days ago | IN | 1.1875 ETH | 0.00086424 | ||||
Top Up Bid | 22597071 | 8 days ago | IN | 0.2 ETH | 0.00061959 | ||||
Top Up Bid | 22597055 | 8 days ago | IN | 0.0375 ETH | 0.00051911 | ||||
Top Up Bid | 22597053 | 8 days ago | IN | 0.025 ETH | 0.00044278 | ||||
Top Up Bid | 22597051 | 8 days ago | IN | 0.0375 ETH | 0.0006383 | ||||
Create Bid | 22597047 | 8 days ago | IN | 1.5 ETH | 0.0008936 | ||||
Top Up Bid | 22597044 | 8 days ago | IN | 0.05 ETH | 0.00066946 | ||||
Top Up Bid | 22597036 | 8 days ago | IN | 0.0125 ETH | 0.00050523 | ||||
Create Bid | 22597030 | 8 days ago | IN | 1.15 ETH | 0.00096362 | ||||
Create Bid | 22597021 | 8 days ago | IN | 1.1375 ETH | 0.00072251 | ||||
Top Up Bid | 22597017 | 8 days ago | IN | 0.0375 ETH | 0.00049476 | ||||
Top Up Bid | 22597011 | 8 days ago | IN | 0.8625 ETH | 0.00075008 | ||||
Create Bid | 22597005 | 8 days ago | IN | 1.1375 ETH | 0.00079976 | ||||
Top Up Bid | 22597003 | 8 days ago | IN | 0.0375 ETH | 0.000701 | ||||
Create Bid | 22596997 | 8 days ago | IN | 1.125 ETH | 0.00093746 | ||||
Top Up Bid | 22596990 | 8 days ago | IN | 0.0875 ETH | 0.00052104 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
Transfer | 22597147 | 8 days ago | 11.75625 ETH | ||||
Transfer | 22597147 | 8 days ago | 1.30625 ETH | ||||
Transfer | 22597142 | 8 days ago | 0.025 ETH | ||||
Transfer | 22597142 | 8 days ago | 0.3125 ETH | ||||
Transfer | 22597142 | 8 days ago | 0.325 ETH | ||||
Transfer | 22597142 | 8 days ago | 0.325 ETH | ||||
Transfer | 22597142 | 8 days ago | 0.325 ETH | ||||
Transfer | 22597142 | 8 days ago | 0.8125 ETH | ||||
Transfer | 22597142 | 8 days ago | 5.1125 ETH | ||||
Transfer | 22597142 | 8 days ago | 5.1625 ETH | ||||
Transfer | 22597142 | 8 days ago | 6.0125 ETH | ||||
Transfer | 22597142 | 8 days ago | 6.1125 ETH | ||||
Transfer | 22597094 | 8 days ago | 1.175 ETH | ||||
Transfer | 22597076 | 8 days ago | 1.1625 ETH | ||||
Transfer | 22597071 | 8 days ago | 1.15 ETH | ||||
Transfer | 22597047 | 8 days ago | 1.125 ETH | ||||
Transfer | 22597030 | 8 days ago | 1.1 ETH | ||||
Transfer | 22597021 | 8 days ago | 1.1 ETH | ||||
Transfer | 22597005 | 8 days ago | 1.1 ETH | ||||
Transfer | 22596997 | 8 days ago | 1.0875 ETH | ||||
Transfer | 22596985 | 8 days ago | 0.8 ETH | ||||
Transfer | 22596969 | 8 days ago | 0.7 ETH | ||||
Transfer | 22596946 | 8 days ago | 0.66875 ETH | ||||
Transfer | 22596929 | 8 days ago | 0.66875 ETH | ||||
Transfer | 22596924 | 8 days ago | 0.65 ETH |
Loading...
Loading
Contract Name:
MinterRAMV0
Compiler Version
v0.8.22+commit.4fc1097e
Optimization Enabled:
Yes with 10 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. // @dev fixed to specific solidity version for clarity and for more clear // source code verification purposes. pragma solidity 0.8.22; import {ISharedMinterV0} from "../../interfaces/v0.8.x/ISharedMinterV0.sol"; import {ISharedMinterRAMV0} from "../../interfaces/v0.8.x/ISharedMinterRAMV0.sol"; import {IMinterFilterV1} from "../../interfaces/v0.8.x/IMinterFilterV1.sol"; import {ABHelpers} from "../../libs/v0.8.x/ABHelpers.sol"; import {AuthLib} from "../../libs/v0.8.x/AuthLib.sol"; import {RAMLib} from "../../libs/v0.8.x/minter-libs/RAMLib.sol"; import {SplitFundsLib} from "../../libs/v0.8.x/minter-libs/SplitFundsLib.sol"; import {MaxInvocationsLib} from "../../libs/v0.8.x/minter-libs/MaxInvocationsLib.sol"; import {ReentrancyGuard} from "@openzeppelin-4.7/contracts/security/ReentrancyGuard.sol"; import {SafeCast} from "@openzeppelin-4.7/contracts/utils/math/SafeCast.sol"; /** * @title Filtered Minter contract that allows tokens to be minted with ETH. * Pricing is achieved using a fully on-chain ranked auction mechanism. * This is designed to be used with GenArt721CoreContractV3 flagship or * engine contracts. * @author Art Blocks Inc. * @notice Bid Front-Running: * Collectors can front-run bids, potentially causing bid transactions to * revert. The minter attempts to handle this in a simple and transparent * manner, but some transactions reverting, especially during highly * competitive auctions, is unavoidable, and best remedied by resubmitting a * new bid transaction with a higher value. * @notice Privileged Roles and Ownership: * This contract is designed to be managed, with limited powers. * Privileged roles and abilities are controlled by the core contract's Admin * ACL contract a project's artist, and auction winners. The Admin ACL and * project's artist roles hold extensive power and can modify minter details. * Care must be taken to ensure that the admin ACL contract and artist * addresses are secure behind a multi-sig or other access control mechanism. * * Additional admin and artist privileged roles may be described on other * contracts that this minter integrates with. * @notice Fallback and Error States: * This minter implements protections for collectors and artists and admin with * the intention of preventing any single party from being able to deny * revenue or minting rights to another party, for any time longer than * 72 hours. All funds are held non-custodially by the smart contract until * all tokens are minted or bids are refunded, after which they may be * distributed to the artist and admin. All settlements are non-custodial and * may be claimed by the winning bidder at any time after an auction ends. * ---------------------------------------------------------------------------- * @notice Project-Minter STATE, FLAG, and ERROR Summary * Note: STATEs are mutually exclusive and are in-order, State C potentially skipped * ------------- * STATE A: Pre-Auction * abilities: * - (artist) configure project max invocations * - (artist) configure project auction * ------------- * STATE B: Live-Auction * abilities: * - (minter active) create bid * - (minter active) top-up bid * - (admin) emergency increase auction end time by up to 72 hr (in cases of frontend downtime, etc.) * - (artist)(not in extra time)(no previous admin extension) reduce auction length * ------------- * STATE C: Post-Auction, Admin-Artist Mint Period (if applicable) * abilities: * - (admin | artist) auto-mint tokens to winners * - (winner) collect settlement * - (ERROR E1)(admin) auto-refund winning bids that cannot receive tokens due to max invocations error * note: State C is skipped if auction was not a sellout * ------------- * STATE D: Post-Auction, Open Mint Period * abilities: * - (winner | admin | artist) directly mint tokens to winners, any order * - (winner) collect settlement * - (FLAG F1) purchase remaining tokens for auction min price (base price), like fixed price minter * - (ERROR E1)(winner | admin | artist) directly refund bids due to max invocations error state, any order * ------------- * STATE E: Post-Auction, all bids handled * note: "all bids handled" guarantees not in ERROR E1 * - (artist | admin) collect revenues * - (FLAG F1) purchase remaining tokens for auction min price (base price), like fixed price minter * ------------- * FLAGS * F1: tokens owed < invocations available * occurs when an auction ends before selling out, so tokens are available to be purchased * note: also occurs during Pre and Live auction, so FLAG F1 can occur with STATE A, B, but should not enable purchases * ------------- * ERRORS * E1: tokens owed > invocations available * occurs when tokens minted on different minter or core max invocations were reduced after auction bidding began. * indicates operational error occurred. * resolution: when winning bids have refunded to sufficiently reduce tokens owed == invocations available. * note: error state does not affect minimum winning bid price, and therefore does not affect settlement amount due to any * winning bids. * ---------------------------------------------------------------------------- * @notice Caution: While Engine projects must be registered on the Art Blocks * Core Registry to assign this minter, this minter does not enforce that a * project is registered when configured or queried. This is primarily for gas * optimization purposes. It is, therefore, possible that fake projects may be * configured on this minter, but bids will not be able to be placed due to * checks performed by this minter's Minter Filter. * * @dev Note that while this minter makes use of `block.timestamp` and it is * technically possible that this value is manipulated by block producers, such * manipulation will not have material impact on the ability for collectors to * place a bid before auction end time. Minimum limits are set on time * intervals such that this manipulation would not have a material impact on * the auction process. */ contract MinterRAMV0 is ReentrancyGuard, ISharedMinterV0, ISharedMinterRAMV0 { using SafeCast for uint256; /// @notice Minter filter address this minter interacts with address public immutable minterFilterAddress; /// @notice Minter filter this minter may interact with. IMinterFilterV1 private immutable _minterFilter; /// @notice minterType for this minter string public constant minterType = "MinterRAMV0"; /// @notice minter version for this minter string public constant minterVersion = "v0.0.0"; /// @notice Minimum auction duration uint256 public constant MIN_AUCTION_DURATION_SECONDS = 60 * 10; // 10 minutes /** @notice Gas limit for refunding ETH to bidders * configurable by admin, default to 30,000 * max uint24 ~= 16 million gas, more than enough for a refund * @dev SENDALL fallback is used to refund ETH if this limit is exceeded */ uint24 internal _minterRefundGasLimit = 30_000; /** * @notice Initializes contract to be a shared, filtered minter for * minter filter `minterFilter` * @param minterFilter Minter filter for which this will be a minter */ constructor(address minterFilter) ReentrancyGuard() { minterFilterAddress = minterFilter; _minterFilter = IMinterFilterV1(minterFilter); // emit events indicating default minter configuration values emit RAMLib.MinAuctionDurationSecondsUpdated({ minAuctionDurationSeconds: MIN_AUCTION_DURATION_SECONDS }); emit RAMLib.MinterRefundGasLimitUpdated({ refundGasLimit: _minterRefundGasLimit }); emit RAMLib.AuctionBufferTimeParamsUpdated({ auctionBufferSeconds: RAMLib.AUCTION_BUFFER_SECONDS, maxAuctionExtraSeconds: RAMLib.MAX_AUCTION_EXTRA_SECONDS }); emit RAMLib.NumSlotsUpdated({numSlots: RAMLib.NUM_SLOTS}); } /** * @notice Sets the gas limit during ETH refunds when a collector is * outbid. This value should be set to a value that is high enough to * ensure that refunds are successful for commonly used wallets, but low * enough to avoid excessive abuse of refund gas allowance during a new * bid. * @dev max gas limit is ~16M, which is considered well over a future-safe * upper bound. * @param minterRefundGasLimit Gas limit to set for refunds. Must be * between 7,000 and max uint24 (~16M). */ function updateRefundGasLimit(uint24 minterRefundGasLimit) external { // CHECKS AuthLib.onlyMinterFilterAdminACL({ minterFilterAddress: minterFilterAddress, sender: msg.sender, contract_: address(this), selector: this.updateRefundGasLimit.selector }); // @dev max gas limit implicitly checked by using uint24 input arg // @dev min gas limit is based on rounding up current cost to send ETH // to a Gnosis Safe wallet, which accesses cold address and emits event require(minterRefundGasLimit >= 7_000, "Only gte 7_000"); // EFFECTS _minterRefundGasLimit = minterRefundGasLimit; emit RAMLib.MinterRefundGasLimitUpdated(minterRefundGasLimit); } /** * @notice Contract-Admin only function to update the requirements on if a * post-auction admin-artist-only mint period is required or banned, for * and-on configured projects. * @param coreContract core contract to set the configuration for. * @param adminMintingConstraint enum indicating if the minter should * require an admin-artist-only mint period after the auction ends or not. */ function setContractConfig( address coreContract, RAMLib.AdminMintingConstraint adminMintingConstraint ) external { // CHECKS AuthLib.onlyCoreAdminACL({ coreContract: coreContract, sender: msg.sender, contract_: address(this), selector: this.setContractConfig.selector }); // EFFECTS RAMLib.setContractConfig({ coreContract: coreContract, adminMintingConstraint: adminMintingConstraint }); } /** * @notice Contract-Admin only function to add emergency auction hours to * auction of project `projectId` on core contract `coreContract`. * Protects against unexpected frontend downtime, etc. * Reverts if called by anyone other than a contract admin. * Reverts if project is not in a Live Auction. * Reverts if auction is already in extra time. * Reverts if adding more than the maximum number of emergency hours. * @param projectId Project ID to add emergency auction hours to. * @param coreContract Core contract address for the given project. * @param emergencyHoursToAdd Number of emergency hours to add to the * project's auction. */ function adminAddEmergencyAuctionHours( uint256 projectId, address coreContract, uint8 emergencyHoursToAdd ) external nonReentrant { // CHECKS AuthLib.onlyCoreAdminACL({ coreContract: coreContract, sender: msg.sender, contract_: address(this), selector: this.adminAddEmergencyAuctionHours.selector }); // EFFECTS RAMLib.adminAddEmergencyAuctionHours({ projectId: projectId, coreContract: coreContract, emergencyHoursToAdd: emergencyHoursToAdd }); } /** * @notice Manually sets the local maximum invocations of project `projectId` * with the provided `maxInvocations`, checking that `maxInvocations` is less * than or equal to the value of project `project_id`'s maximum invocations that is * set on the core contract. * @dev Note that a `maxInvocations` of 0 can only be set if the current `invocations` * value is also 0 and this would also set `maxHasBeenInvoked` to true, correctly short-circuiting * this minter's purchase function, avoiding extra gas costs from the core contract's maxInvocations check. * @param projectId Project ID to set the maximum invocations for. * @param coreContract Core contract address for the given project. * @param maxInvocations Maximum invocations to set for the project. */ function manuallyLimitProjectMaxInvocations( uint256 projectId, address coreContract, uint24 maxInvocations ) external { // CHECKS AuthLib.onlyArtist({ projectId: projectId, coreContract: coreContract, sender: msg.sender }); // only project minter state A (Pre-Auction) RAMLib.ProjectMinterStates currentState = RAMLib.getProjectMinterState({ projectId: projectId, coreContract: coreContract }); require( currentState == RAMLib.ProjectMinterStates.PreAuction, "Only pre-auction" ); // EFFECTS MaxInvocationsLib.manuallyLimitProjectMaxInvocations({ projectId: projectId, coreContract: coreContract, maxInvocations: maxInvocations }); // also update number of tokens in auction RAMLib.refreshNumTokensInAuction({ projectId: projectId, coreContract: coreContract }); } /** * @notice Sets auction details for project `projectId`. * @param projectId Project ID to set auction details for. * @param coreContract Core contract address for the given project. * @param auctionTimestampStart Timestamp at which to start the auction. * @param basePrice Resting price of the auction, in Wei. * @param allowExtraTime Boolean indicating if extra time is allowed for * the auction, when valid bids are placed near the end of the auction. * @param adminArtistOnlyMintPeriodIfSellout Boolean indicating if an * admin-artist-only mint period should be enforced if the auction sells * out. * @dev Note that a basePrice of `0` will cause the transaction to revert. */ function setAuctionDetails( uint256 projectId, address coreContract, uint40 auctionTimestampStart, uint40 auctionTimestampEnd, uint256 basePrice, bool allowExtraTime, bool adminArtistOnlyMintPeriodIfSellout ) external nonReentrant { AuthLib.onlyArtist({ projectId: projectId, coreContract: coreContract, sender: msg.sender }); // CHECKS // check min auction duration // @dev underflow checked automatically in solidity 0.8 require( auctionTimestampEnd - auctionTimestampStart >= MIN_AUCTION_DURATION_SECONDS, "Auction too short" ); // EFFECTS // @dev project minter state checked in setAuctionDetails RAMLib.setAuctionDetails({ projectId: projectId, coreContract: coreContract, auctionTimestampStart: auctionTimestampStart, auctionTimestampEnd: auctionTimestampEnd, basePrice: basePrice.toUint88(), allowExtraTime: allowExtraTime, adminArtistOnlyMintPeriodIfSellout: adminArtistOnlyMintPeriodIfSellout }); } /** * @notice Reduces the auction length for project `projectId` on core * contract `coreContract` to `auctionTimestampEnd`. * Only allowed to be called during a live auction, and protects against * the case of an accidental excessively long auction, which locks funds. * Reverts if called by anyone other than the project's artist. * Reverts if project is not in a Live Auction. * Reverts if auction is not being reduced in length. * Reverts if in extra time. * Reverts if `auctionTimestampEnd` results in auction that is not at least * `MIN_AUCTION_DURATION_SECONDS` in duration. * Reverts if admin previously applied a time extension. * @param projectId Project ID to reduce the auction length for. * @param coreContract Core contract address for the given project. * @param auctionTimestampEnd New timestamp at which to end the auction. */ function reduceAuctionLength( uint256 projectId, address coreContract, uint40 auctionTimestampEnd ) external nonReentrant { AuthLib.onlyArtist({ projectId: projectId, coreContract: coreContract, sender: msg.sender }); RAMLib.reduceAuctionLength({ projectId: projectId, coreContract: coreContract, auctionTimestampEnd: auctionTimestampEnd, minimumAuctionDurationSeconds: MIN_AUCTION_DURATION_SECONDS }); } /** * @notice Places a bid for project `projectId` on core contract * `coreContract`. * Reverts if minter is not the active minter for projectId on minter * filter. * Reverts if project is not in a Live Auction. * Reverts if msg.value is not equal to slot value. * In order to successfully place the bid, the token bid must be: * - greater than or equal to a project's minimum bid price if maximum * number of bids has not been reached * - sufficiently greater than the current minimum bid if maximum number * of bids has been reached * If the bid is unsuccessful, the transaction will revert. * If the bid is successful, but outbid by another bid before the auction * ends, the funds will be noncustodially returned to the bidder's address, * `msg.sender`. A fallback method of sending funds back to the bidder via * SELFDESTRUCT (SENDALL) prevents denial of service attacks, even if the * original bidder reverts or runs out of gas during receive or fallback. * ------------------------------------------------------------------------ * WARNING: bidders must be prepared to handle the case where their bid is * outbid and their funds are returned to the original `msg.sender` address * via SELFDESTRUCT (SENDALL). * ------------------------------------------------------------------------ * @param projectId projectId being bid on. * @param coreContract Core contract address for the given project. * @param slotIndex Slot index to create the bid for. * @dev nonReentrant modifier is used to prevent reentrancy attacks, e.g. * an an auto-bidder that would be able to automically outbid a user's * new bid via a reentrant call to createBid. */ function createBid( uint256 projectId, address coreContract, uint16 slotIndex ) external payable nonReentrant { // CHECKS // minter must be set for project on MinterFilter require( _minterFilter.getMinterForProject({ projectId: projectId, coreContract: coreContract }) == address(this), "Minter not active" ); // @dev bid value is checked against slot value in placeBid // @dev project state is checked in placeBid // EFFECTS RAMLib.placeBid({ projectId: projectId, coreContract: coreContract, slotIndex: slotIndex, bidder: msg.sender, bidValue: msg.value, minterRefundGasLimit: _minterRefundGasLimit }); } /** * @notice Top up bid for project `projectId` on core contract * `coreContract` for bid `bidId` to new slot index `newSlotIndex`. * Reverts if Bid ID has been kicked out of the auction or does not exist. * Reverts if msg.sender is not the bidder of the bid. * Reverts if minter is not the active minter for projectId on minter * filter. * Reverts if project is not in a Live Auction. * Reverts if msg.value is not equal to difference in bid values between * new and old slots. * Reverts if new slot index is not greater than or equal to the current * slot index. * @param projectId Project ID to top up bid for. * @param coreContract Core contract address for the given project. * @param bidId ID of bid to top up. * @param newSlotIndex New slot index to move bid to. */ function topUpBid( uint256 projectId, address coreContract, uint32 bidId, uint16 newSlotIndex ) external payable nonReentrant { // CHECKS // minter must be set for project on MinterFilter require( _minterFilter.getMinterForProject({ projectId: projectId, coreContract: coreContract }) == address(this), "Minter not active" ); // @dev additional bid value is checked against slot value in topUpBid // @dev project state is checked in topUpBid // EFFECTS RAMLib.topUpBid({ projectId: projectId, coreContract: coreContract, bidId: bidId, newSlotIndex: newSlotIndex, bidder: msg.sender, addedValue: msg.value }); } /** * @notice Purchases token for project `projectId` on core contract * `coreContract` for auction that has ended, but not yet been sold out. * @param projectId Project ID to purchase token for. * @param coreContract Core contract address for the given project. * @return tokenId Token ID of minted token */ function purchase( uint256 projectId, address coreContract ) external payable nonReentrant returns (uint256 tokenId) { // @dev checks performed in RAMLib purchaseTo function tokenId = RAMLib.purchaseTo({ to: msg.sender, projectId: projectId, coreContract: coreContract, minterFilter: _minterFilter }); } /** * @notice Purchases token for project `projectId` on core contract * `coreContract` for auction that has ended, but not yet been sold out, * and sets the token's owner to `to`. * @param to Address to be the new token's owner. * @param projectId Project ID to purchase token for. * @param coreContract Core contract address for the given project. * @return tokenId Token ID of minted token */ function purchaseTo( address to, uint256 projectId, address coreContract ) external payable nonReentrant returns (uint256 tokenId) { // @dev checks performed in RAMLib purchaseTo function tokenId = RAMLib.purchaseTo({ to: to, projectId: projectId, coreContract: coreContract, minterFilter: _minterFilter }); } /** * @notice Collects settlement for project `projectId` on core contract * `coreContract` for all bids in `bidIds`, * which must be aligned by index. * Reverts if msg.sender is not the bidder for all bids. * Reverts if project is not in a post-auction state. * Reverts if one or more bids has already been settled. * Reverts if invalid bid is found. * @param projectId Project ID of bid to collect settlement for * @param coreContract Core contract address for the given project. * @param bidIds IDs of bids to collect settlements for */ function collectSettlements( uint256 projectId, address coreContract, uint32[] calldata bidIds ) external nonReentrant { // CHECKS // @dev project state is checked in collectSettlements // @dev length of slotIndices and bidIndicesInSlot must be equal is // checked in collectSettlements // EFFECTS RAMLib.collectSettlements({ projectId: projectId, coreContract: coreContract, bidIds: bidIds, bidder: msg.sender, minterRefundGasLimit: _minterRefundGasLimit }); } /** * @notice Contract-Admin or Artist only function to mint tokens to winners * of project `projectId` on core contract `coreContract`. * Automatically mints tokens to most-winning bids, in order from highest * and earliest bid to lowest and latest bid. * Settles bids as tokens are minted, if not already settled. * Reverts if project is not in a post-auction state, admin-artist-only * mint period (i.e. State C), with tokens available. * Reverts if msg.sender is not a contract admin or artist. * Reverts if number of tokens to mint is greater than the number of * tokens available to be minted. * @param projectId Project ID to mint tokens on. * @param coreContract Core contract address for the given project. * @param numTokensToMint Number of tokens to mint in this transaction. */ function adminArtistAutoMintTokensToWinners( uint256 projectId, address coreContract, uint24 numTokensToMint ) external nonReentrant { // CHECKS AuthLib.onlyCoreAdminACLOrArtist({ projectId: projectId, coreContract: coreContract, sender: msg.sender, contract_: address(this), selector: this.adminArtistAutoMintTokensToWinners.selector }); // EFFECTS/INTERACTIONS RAMLib.adminArtistAutoMintTokensToWinners({ projectId: projectId, coreContract: coreContract, numTokensToMint: numTokensToMint, minterFilter: _minterFilter, minterRefundGasLimit: _minterRefundGasLimit }); } /** * @notice Directly mint tokens to winners of project `projectId` on core * contract `coreContract`. * Does not guarantee an optimal ordering or handling of E1 state like * `adminAutoRefundWinners` does while in State C. * Admin or Artist may mint to any winning bids. * Provides protection for Admin and Artist because they may mint tokens * to winners to prevent denial of revenue claiming. * Skips over bids that have already been minted or refunded (front-running * protection). * Reverts if project is not in a post-auction state, * post-admin-artist-only mint period (i.e. State D), with tokens available * Reverts if msg.sender is not a contract admin or artist. * @param projectId Project ID to mint tokens on. * @param coreContract Core contract address for the given project. * @param bidIds IDs of bids to mint tokens for */ function adminArtistDirectMintTokensToWinners( uint256 projectId, address coreContract, uint32[] calldata bidIds ) external nonReentrant { // CHECKS AuthLib.onlyCoreAdminACLOrArtist({ projectId: projectId, coreContract: coreContract, sender: msg.sender, contract_: address(this), selector: this.adminArtistDirectMintTokensToWinners.selector }); // EFFECTS/INTERACTIONS RAMLib.directMintTokensToWinners({ projectId: projectId, coreContract: coreContract, bidIds: bidIds, requireSenderIsBidder: false, // not required when called by admin or artist minterFilter: _minterFilter, minterRefundGasLimit: _minterRefundGasLimit }); } /** * @notice Directly mint tokens of winner of project `projectId` on core * contract `coreContract`. * Does not guarantee an optimal ordering or handling of E1 state like * `adminAutoRefundWinners` does while in State C. * Only winning collector may call and mint tokens to themselves. * Provides protection for collectors because they may mint their tokens * directly. * Skips over bids that have already been minted or refunded (front-running * protection) * Reverts if project is not in a post-auction state, * post-admin-artist-only mint period (i.e. State D), with tokens available * Reverts if msg.sender is not the winning bidder for all specified bids. * @param projectId Project ID to mint tokens on. * @param coreContract Core contract address for the given project. * @param bidIds IDs of bids to mint tokens for */ function winnerDirectMintTokens( uint256 projectId, address coreContract, uint32[] calldata bidIds ) external nonReentrant { // CHECKS // @dev all checks performed in library function // EFFECTS/INTERACTIONS RAMLib.directMintTokensToWinners({ projectId: projectId, coreContract: coreContract, bidIds: bidIds, requireSenderIsBidder: true, // only allow winning bidder to call minterFilter: _minterFilter, minterRefundGasLimit: _minterRefundGasLimit }); } /** * @notice Directly refund bids for project `projectId` on core * contract `coreContract` to resolve error state E1. * Does not guarantee an optimal ordering or handling of E1 state like * `adminAutoMintTokensToWinners` does while in State C. * Admin or Artist may refund to any bids. * Provides protection for Admin and Artist because they may refund to * resolve E1 state to prevent denial of revenue claiming. * Skips over bids that have already been minted or refunded (front-running * protection). * Reverts if project is not in a post-auction state, * post-admin-artist-only mint period (i.e. State D). * Reverts if project is not in error state E1. * Reverts if length of bids to refund exceeds the number of bids that need * to be refunded to resolve the error state E1. * Reverts if bid does not exist at bidId. * Reverts if msg.sender is not a contract admin or artist. * @param projectId Project ID to refund bid values on. * @param coreContract Core contract address for the given project. * @param bidIds IDs of bids to refund bid values for */ function adminArtistDirectRefundWinners( uint256 projectId, address coreContract, uint32[] calldata bidIds ) external nonReentrant { // CHECKS AuthLib.onlyCoreAdminACLOrArtist({ projectId: projectId, coreContract: coreContract, sender: msg.sender, contract_: address(this), selector: this.adminArtistDirectRefundWinners.selector }); // EFFECTS/INTERACTIONS RAMLib.directRefundBidsToResolveE1({ projectId: projectId, coreContract: coreContract, bidIds: bidIds, requireSenderIsBidder: false, // not required when called by admin or artist minterRefundGasLimit: _minterRefundGasLimit }); } /** * @notice Directly refund bids for project `projectId` on core * contract `coreContract` to resolve error state E1. * Does not guarantee an optimal ordering or handling of E1 state like * `adminAutoMintTokensToWinners` does while in State C. * Only winning collector may call and refund to themselves. * Provides protection for collectors because they may refund their tokens * directly if in E1 state and they are no longer able to mint their * token(s) (prevent holding of funds). * Skips over bids that have already been minted or refunded (front-running * protection). * Reverts if project is not in a post-auction state, * post-admin-artist-only mint period (i.e. State D). * Reverts if project is not in error state E1. * Reverts if length of bids to refund exceeds the number of bids that need * to be refunded to resolve the error state E1. * Reverts if msg.sender is not the winning bidder for all specified bids. * @param projectId Project ID to refund bid values on. * @param coreContract Core contract address for the given project. * @param bidIds IDs of bids to refund bid values for */ function winnerDirectRefund( uint256 projectId, address coreContract, uint32[] calldata bidIds ) external nonReentrant { // CHECKS // @dev all checks performed in library function // EFFECTS/INTERACTIONS RAMLib.directRefundBidsToResolveE1({ projectId: projectId, coreContract: coreContract, bidIds: bidIds, requireSenderIsBidder: true, // only allow winning bidder to call minterRefundGasLimit: _minterRefundGasLimit }); } /** * @notice Function to automatically refund the lowest winning bids for * project `projectId` on core contract `coreContract` to resolve error * state E1. * Reverts if not called by a contract admin. * Reverts if project is not in post-auction state C. * Reverts if project is not in error state E1. * Reverts if numBidsToRefund exceeds the number of bids that need to be * refunded to resolve the error state E1. * @dev Admin-only requirement is not for security, but is to enable Admin * to be aware that an error state has been encountered while in post- * auction state C. * @param projectId Project ID to refunds bids for. * @param coreContract Core contract address for the given project. * @param numBidsToRefund Number of bids to refund in this call. */ function adminAutoRefundWinners( uint256 projectId, address coreContract, uint24 numBidsToRefund ) external nonReentrant { // CHECKS AuthLib.onlyCoreAdminACL({ coreContract: coreContract, sender: msg.sender, contract_: address(this), selector: this.adminAutoRefundWinners.selector }); // EFFECTS/INTERACTIONS RAMLib.autoRefundBidsToResolveE1({ projectId: projectId, coreContract: coreContract, numBidsToRefund: numBidsToRefund, minterRefundGasLimit: _minterRefundGasLimit }); } /** * @notice This withdraws project revenues for project `projectId` on core * contract `coreContract` to the artist and admin, only after all bids * have been minted+settled or refunded. * Note that the conditions described are the equivalent of project minter * State E. * @param projectId Project ID to withdraw revenues for. * @param coreContract Core contract address for the given project. */ function withdrawArtistAndAdminRevenues( uint256 projectId, address coreContract ) external nonReentrant { // CHECKS AuthLib.onlyCoreAdminACLOrArtist({ projectId: projectId, coreContract: coreContract, sender: msg.sender, contract_: address(this), selector: this.withdrawArtistAndAdminRevenues.selector }); // EFFECTS/INTERACTIONS RAMLib.withdrawArtistAndAdminRevenues({ projectId: projectId, coreContract: coreContract }); } /** * @notice Returns if project minter is in ERROR state E1, and the number * of bids that need to be refunded to resolve the error. * E1: Tokens owed > invocations available * Occurs when: tokens are minted on different minter after auction begins, * or when core contract max invocations are reduced after auction begins. * Resolution: Admin must refund the lowest bids after auction ends. * @param projectId Project Id to query * @param coreContract Core contract address to query * @return isError True if in error state, false otherwise * @return numBidsToRefund Number of bids to refund to resolve error, 0 if * not in error state */ function getIsErrorE1( uint256 projectId, address coreContract ) external view returns (bool isError, uint256 numBidsToRefund) { (isError, numBidsToRefund, ) = RAMLib.isErrorE1FlagF1({ projectId: projectId, coreContract: coreContract }); } /** * @notice View function to return the current minter-level configuration * details. Some or all of these values may be defined as constants for * this minter. * @return minAuctionDurationSeconds Minimum auction duration in seconds * @return auctionBufferSeconds Auction buffer time in seconds * @return maxAuctionExtraSeconds Maximum extra time in seconds * @return maxAuctionAdminEmergencyExtensionHours Maximum emergency * extension hours for admin * @return adminArtistOnlyMintTimeSeconds Admin-artist-only mint time in * seconds * @return minterRefundGasLimit Gas limit for refunding ETH */ function minterConfigurationDetails() external view returns ( uint256 minAuctionDurationSeconds, uint256 auctionBufferSeconds, uint256 maxAuctionExtraSeconds, uint256 maxAuctionAdminEmergencyExtensionHours, uint256 adminArtistOnlyMintTimeSeconds, uint24 minterRefundGasLimit ) { minAuctionDurationSeconds = MIN_AUCTION_DURATION_SECONDS; auctionBufferSeconds = RAMLib.AUCTION_BUFFER_SECONDS; maxAuctionExtraSeconds = RAMLib.MAX_AUCTION_EXTRA_SECONDS; maxAuctionAdminEmergencyExtensionHours = RAMLib .MAX_AUCTION_ADMIN_EMERGENCY_EXTENSION_HOURS; adminArtistOnlyMintTimeSeconds = RAMLib .ADMIN_ARTIST_ONLY_MINT_TIME_SECONDS; minterRefundGasLimit = _minterRefundGasLimit; } /** * @notice Gets the admin minting constraint configuration details for a core contract as configured by a * contract admin, for this minter. * @param coreContract The address of the core contract. * @return RAMLib.AdminMintingConstraint enum value. */ function contractConfigurationDetails( address coreContract ) external view returns (RAMLib.AdminMintingConstraint) { return RAMLib.getRAMAdminMintingConstraintValue(coreContract); } /** * @notice Gets the maximum invocations project configuration. * @dev RAMLib shims in logic to properly return maxHasBeenInvoked based * on project state, bid state, and core contract state. * @param projectId The ID of the project whose data needs to be fetched. * @param coreContract The address of the core contract. * @return MaxInvocationsLib.MaxInvocationsProjectConfig instance with the * configuration data. */ function maxInvocationsProjectConfig( uint256 projectId, address coreContract ) external view returns (MaxInvocationsLib.MaxInvocationsProjectConfig memory) { // RAM minter does not update maxHasBeenInvoked, so we ask the RAMLib // for this state, and it shims in an appropriate maxHasBeenInvoked // value based on the state of the auction, unminted bids, core // contract invocations, and minter max invocations return RAMLib.getMaxInvocationsProjectConfig({ projectId: projectId, coreContract: coreContract }); } /** * @notice Returns the auction details for project `projectId` on core * contract `coreContract`. * @param projectId is an existing project ID. * @param coreContract is an existing core contract address. * @return auctionTimestampStart is the timestamp at which the auction * starts. * @return auctionTimestampEnd is the timestamp at which the auction ends. * @return basePrice is the resting price of the auction, in Wei. * @return numTokensInAuction is the number of tokens in the auction. * @return numBids is the number of bids in the auction. * @return numBidsMintedTokens is the number of bids that have been minted * into tokens. * @return numBidsErrorRefunded is the number of bids that have been * refunded due to an error state. * @return minBidSlotIndex is the index of the slot with the minimum bid * value. * @return allowExtraTime is a bool indicating if the auction is allowed to * have extra time. * @return adminArtistOnlyMintPeriodIfSellout is a bool indicating if an * admin-artist-only mint period is required if the auction sells out. * @return revenuesCollected is a bool indicating if the auction revenues * have been collected. * @return projectMinterState is the current state of the project minter. * @dev projectMinterState is a RAMLib.ProjectMinterStates enum value. */ function getAuctionDetails( uint256 projectId, address coreContract ) external view returns ( uint256 auctionTimestampStart, uint256 auctionTimestampEnd, uint256 basePrice, uint256 numTokensInAuction, uint256 numBids, uint256 numBidsMintedTokens, uint256 numBidsErrorRefunded, uint256 minBidSlotIndex, bool allowExtraTime, bool adminArtistOnlyMintPeriodIfSellout, bool revenuesCollected, RAMLib.ProjectMinterStates projectMinterState ) { return RAMLib.getAuctionDetails({ projectId: projectId, coreContract: coreContract }); } /** * @notice Returns if project has reached maximum number of invocations for * a given project and core contract, properly accounting for the auction * state, unminted bids, core contract invocations, and minter max * invocations when determining maxHasBeenInvoked * @param projectId is an existing project ID. * @param coreContract is an existing core contract address. */ function projectMaxHasBeenInvoked( uint256 projectId, address coreContract ) external view returns (bool) { return RAMLib.getMaxHasBeenInvoked({ projectId: projectId, coreContract: coreContract }); } /** * @notice projectId => project's maximum number of invocations. * Optionally synced with core contract value, for gas optimization. * Note that this returns a local cache of the core contract's * state, and may be out of sync with the core contract. This is * intentional, as it only enables gas optimization of mints after a * project's maximum invocations has been reached. * @dev A number greater than the core contract's project max invocations * will only result in a gas cost increase, since the core contract will * still enforce a maxInvocation check during minting. A number less than * the core contract's project max invocations is only possible when the * project's max invocations have not been synced on this minter, since the * V3 core contract only allows maximum invocations to be reduced, not * increased. When this happens, the minter will enable minting, allowing * the core contract to enforce the max invocations check. Based on this * rationale, we intentionally do not do input validation in this method as * to whether or not the input `projectId` is an existing project ID. * @param projectId is an existing project ID. * @param coreContract is an existing core contract address. */ function projectMaxInvocations( uint256 projectId, address coreContract ) external view returns (uint256) { return MaxInvocationsLib.getMaxInvocations({ projectId: projectId, coreContract: coreContract }); } /** * @notice Checks if the specified `coreContract` is a valid engine contract. * @dev This function retrieves the cached value of `isEngine` from * the `isEngineCache` mapping. If the cached value is already set, it * returns the cached value. Otherwise, it calls the `getV3CoreIsEngineView` * function from the `SplitFundsLib` library to check if `coreContract` * is a valid engine contract. * @dev This function will revert if the provided `coreContract` is not * a valid Engine or V3 Flagship contract. * @param coreContract The address of the contract to check. * @return True if `coreContract` is a valid engine contract. */ function isEngineView(address coreContract) external view returns (bool) { SplitFundsLib.IsEngineCache storage isEngineCache = SplitFundsLib .getIsEngineCacheConfig(coreContract); if (isEngineCache.isCached) { return isEngineCache.isEngine; } else { // @dev this calls the non-state-modifying variant of isEngine return SplitFundsLib.getV3CoreIsEngineView(coreContract); } } /** * @notice Gets minimum bid value to participate in an * auction for project `projectId` on core contract `coreContract`. * If an auction is not configured, `isConfigured` will be false, and a * dummy price of zero is assigned to `tokenPriceInWei`. * If an auction is configured but still in a pre-auction state, * `isConfigured` will be true, and `tokenPriceInWei` will be the minimum * initial bid price for the next token auction. * If there is an active auction, `isConfigured` will be true, and * `tokenPriceInWei` will be the current minimum bid's value + min bid * increment due to the minter's increment percentage, rounded up to next * slot's bid value. * If there is an auction that has ended (no longer accepting bids), but * the project is configured, `isConfigured` will be true, and * `tokenPriceInWei` will be either the sellout price or the reserve price * of the auction if it did not sell out during its auction. * Also returns currency symbol and address to be being used as payment, * which for this minter is ETH only. * @param projectId Project ID to get price information for. * @param coreContract Core contract to get price information for. * @return isConfigured true only if project auctions are configured. * @return tokenPriceInWei price in wei to become a bidder on a * token auction. * @return currencySymbol currency symbol for purchases of project on this * minter. This minter always returns "ETH" * @return currencyAddress currency address for purchases of project on * this minter. This minter always returns null address, reserved for ether */ function getPriceInfo( uint256 projectId, address coreContract ) external view returns ( bool isConfigured, uint256 tokenPriceInWei, string memory currencySymbol, address currencyAddress ) { (isConfigured, tokenPriceInWei) = RAMLib.getPriceInfo({ projectId: projectId, coreContract: coreContract }); // currency is always ETH currencySymbol = "ETH"; currencyAddress = address(0); } /** * @notice Gets minimum next bid value in Wei and slot index for project `projectId` * on core contract `coreContract`. * If in a pre-auction state, reverts if unconfigured, otherwise returns * the minimum initial bid price for the upcoming auction. * If in an active auction, returns the minimum next bid's value and slot * index. * If in a post-auction state, reverts if auction was a sellout, otherwise * returns the auction's reserve price and slot index 0 (because tokens may * still be purchasable at the reserve price). * @param projectId Project ID to get the minimum next bid value for * @param coreContract Core contract address for the given project * @return minNextBidValueInWei minimum next bid value in Wei * @return minNextBidSlotIndex slot index of the minimum next bid */ function getMinimumNextBid( uint256 projectId, address coreContract ) external view returns (uint256 minNextBidValueInWei, uint256 minNextBidSlotIndex) { (minNextBidValueInWei, minNextBidSlotIndex) = RAMLib.getMinimumNextBid({ projectId: projectId, coreContract: coreContract }); } /** * @notice Returns the value of the lowest bid in the project's auction, * in Wei. * Reverts if no bids exist in the auction. * @param projectId Project ID to get the lowest bid value for * @param coreContract Core contract address for the given project * @return minBidValue Value of the lowest bid in the auction, in Wei */ function getLowestBidValue( uint256 projectId, address coreContract ) external view returns (uint256) { (, uint16 minBidSlotIndex) = RAMLib.getLowestBid({ projectId: projectId, coreContract: coreContract }); // translate slot index to bid value uint88 projectBasePrice = RAMLib .getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }) .basePrice; return RAMLib.slotIndexToBidValue({ basePrice: projectBasePrice, slotIndex: minBidSlotIndex }); } /** * @notice Convenience view function that returns the bid value associated * with a given slot index for the specified project's auction, in Wei. * Reverts if the slot index is out of range (greater than 511). * @param projectId Project ID to get the bid value for * @param coreContract Core contract address for the given project * @param slotIndex Slot index to get the bid value for */ function slotIndexToBidValue( uint256 projectId, address coreContract, uint16 slotIndex ) external view returns (uint256) { uint88 projectBasePrice = RAMLib .getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }) .basePrice; // @dev does not check if project configured to reduce bytecode size return RAMLib.slotIndexToBidValue({ basePrice: projectBasePrice, slotIndex: slotIndex }); } /** * @notice Returns balance of project `projectId` on core contract * `coreContract` on this minter contract. * @dev project balance is a failsafe backstop used to ensure that funds * from one project may never affect funds from another project on this * shared minter contract. * @param projectId Project ID to get the balance for * @param coreContract Core contract address for the given project */ function getProjectBalance( uint256 projectId, address coreContract ) external view returns (uint256) { return RAMLib.getProjectBalance({ projectId: projectId, coreContract: coreContract }); } /** * @notice Exists for interface conformance only. * Use manuallyLimitProjectMaxInvocations to set the maximum invocations * for a project instead. */ function syncProjectMaxInvocationsToCore( uint256 /*projectId*/, address /*coreContract*/ ) public pure { revert("Action not supported"); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (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() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/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. It 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)`. // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`. // This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`. // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a // good first aproximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1; uint256 x = a; if (x >> 128 > 0) { x >>= 128; result <<= 64; } if (x >> 64 > 0) { x >>= 64; result <<= 32; } if (x >> 32 > 0) { x >>= 32; result <<= 16; } if (x >> 16 > 0) { x >>= 16; result <<= 8; } if (x >> 8 > 0) { x >>= 8; result <<= 4; } if (x >> 4 > 0) { x >>= 4; result <<= 2; } if (x >> 2 > 0) { result <<= 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) { uint256 result = sqrt(a); if (rounding == Rounding.Up && result * result < a) { result += 1; } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/math/SafeCast.sol) 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) { require(value >= type(int248).min && value <= type(int248).max, "SafeCast: value doesn't fit in 248 bits"); return int248(value); } /** * @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) { require(value >= type(int240).min && value <= type(int240).max, "SafeCast: value doesn't fit in 240 bits"); return int240(value); } /** * @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) { require(value >= type(int232).min && value <= type(int232).max, "SafeCast: value doesn't fit in 232 bits"); return int232(value); } /** * @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) { require(value >= type(int224).min && value <= type(int224).max, "SafeCast: value doesn't fit in 224 bits"); return int224(value); } /** * @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) { require(value >= type(int216).min && value <= type(int216).max, "SafeCast: value doesn't fit in 216 bits"); return int216(value); } /** * @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) { require(value >= type(int208).min && value <= type(int208).max, "SafeCast: value doesn't fit in 208 bits"); return int208(value); } /** * @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) { require(value >= type(int200).min && value <= type(int200).max, "SafeCast: value doesn't fit in 200 bits"); return int200(value); } /** * @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) { require(value >= type(int192).min && value <= type(int192).max, "SafeCast: value doesn't fit in 192 bits"); return int192(value); } /** * @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) { require(value >= type(int184).min && value <= type(int184).max, "SafeCast: value doesn't fit in 184 bits"); return int184(value); } /** * @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) { require(value >= type(int176).min && value <= type(int176).max, "SafeCast: value doesn't fit in 176 bits"); return int176(value); } /** * @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) { require(value >= type(int168).min && value <= type(int168).max, "SafeCast: value doesn't fit in 168 bits"); return int168(value); } /** * @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) { require(value >= type(int160).min && value <= type(int160).max, "SafeCast: value doesn't fit in 160 bits"); return int160(value); } /** * @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) { require(value >= type(int152).min && value <= type(int152).max, "SafeCast: value doesn't fit in 152 bits"); return int152(value); } /** * @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) { require(value >= type(int144).min && value <= type(int144).max, "SafeCast: value doesn't fit in 144 bits"); return int144(value); } /** * @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) { require(value >= type(int136).min && value <= type(int136).max, "SafeCast: value doesn't fit in 136 bits"); return int136(value); } /** * @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) { require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits"); return int128(value); } /** * @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) { require(value >= type(int120).min && value <= type(int120).max, "SafeCast: value doesn't fit in 120 bits"); return int120(value); } /** * @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) { require(value >= type(int112).min && value <= type(int112).max, "SafeCast: value doesn't fit in 112 bits"); return int112(value); } /** * @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) { require(value >= type(int104).min && value <= type(int104).max, "SafeCast: value doesn't fit in 104 bits"); return int104(value); } /** * @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) { require(value >= type(int96).min && value <= type(int96).max, "SafeCast: value doesn't fit in 96 bits"); return int96(value); } /** * @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) { require(value >= type(int88).min && value <= type(int88).max, "SafeCast: value doesn't fit in 88 bits"); return int88(value); } /** * @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) { require(value >= type(int80).min && value <= type(int80).max, "SafeCast: value doesn't fit in 80 bits"); return int80(value); } /** * @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) { require(value >= type(int72).min && value <= type(int72).max, "SafeCast: value doesn't fit in 72 bits"); return int72(value); } /** * @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) { require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits"); return int64(value); } /** * @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) { require(value >= type(int56).min && value <= type(int56).max, "SafeCast: value doesn't fit in 56 bits"); return int56(value); } /** * @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) { require(value >= type(int48).min && value <= type(int48).max, "SafeCast: value doesn't fit in 48 bits"); return int48(value); } /** * @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) { require(value >= type(int40).min && value <= type(int40).max, "SafeCast: value doesn't fit in 40 bits"); return int40(value); } /** * @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) { require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits"); return int32(value); } /** * @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) { require(value >= type(int24).min && value <= type(int24).max, "SafeCast: value doesn't fit in 24 bits"); return int24(value); } /** * @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) { require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits"); return int16(value); } /** * @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) { require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits"); return int8(value); } /** * @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 // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; import {IERC165} from "../../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 address zero. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @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 v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @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 towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (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 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 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. uint256 twos = denominator & (0 - denominator); 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 (unsignedRoundsUp(rounding) && 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 * towards zero. * * 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 + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * 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 + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * 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 + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.20; /** * @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. */ library SafeCast { /** * @dev Value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); /** * @dev An int value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedIntToUint(int256 value); /** * @dev Value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); /** * @dev An uint value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedUintToInt(uint256 value); /** * @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 */ function toUint248(uint256 value) internal pure returns (uint248) { if (value > type(uint248).max) { revert SafeCastOverflowedUintDowncast(248, value); } 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 */ function toUint240(uint256 value) internal pure returns (uint240) { if (value > type(uint240).max) { revert SafeCastOverflowedUintDowncast(240, value); } 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 */ function toUint232(uint256 value) internal pure returns (uint232) { if (value > type(uint232).max) { revert SafeCastOverflowedUintDowncast(232, value); } 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 */ function toUint224(uint256 value) internal pure returns (uint224) { if (value > type(uint224).max) { revert SafeCastOverflowedUintDowncast(224, value); } 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 */ function toUint216(uint256 value) internal pure returns (uint216) { if (value > type(uint216).max) { revert SafeCastOverflowedUintDowncast(216, value); } 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 */ function toUint208(uint256 value) internal pure returns (uint208) { if (value > type(uint208).max) { revert SafeCastOverflowedUintDowncast(208, value); } 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 */ function toUint200(uint256 value) internal pure returns (uint200) { if (value > type(uint200).max) { revert SafeCastOverflowedUintDowncast(200, value); } 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 */ function toUint192(uint256 value) internal pure returns (uint192) { if (value > type(uint192).max) { revert SafeCastOverflowedUintDowncast(192, value); } 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 */ function toUint184(uint256 value) internal pure returns (uint184) { if (value > type(uint184).max) { revert SafeCastOverflowedUintDowncast(184, value); } 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 */ function toUint176(uint256 value) internal pure returns (uint176) { if (value > type(uint176).max) { revert SafeCastOverflowedUintDowncast(176, value); } 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 */ function toUint168(uint256 value) internal pure returns (uint168) { if (value > type(uint168).max) { revert SafeCastOverflowedUintDowncast(168, value); } 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 */ function toUint160(uint256 value) internal pure returns (uint160) { if (value > type(uint160).max) { revert SafeCastOverflowedUintDowncast(160, value); } 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 */ function toUint152(uint256 value) internal pure returns (uint152) { if (value > type(uint152).max) { revert SafeCastOverflowedUintDowncast(152, value); } 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 */ function toUint144(uint256 value) internal pure returns (uint144) { if (value > type(uint144).max) { revert SafeCastOverflowedUintDowncast(144, value); } 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 */ function toUint136(uint256 value) internal pure returns (uint136) { if (value > type(uint136).max) { revert SafeCastOverflowedUintDowncast(136, value); } 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 */ function toUint128(uint256 value) internal pure returns (uint128) { if (value > type(uint128).max) { revert SafeCastOverflowedUintDowncast(128, value); } 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 */ function toUint120(uint256 value) internal pure returns (uint120) { if (value > type(uint120).max) { revert SafeCastOverflowedUintDowncast(120, value); } 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 */ function toUint112(uint256 value) internal pure returns (uint112) { if (value > type(uint112).max) { revert SafeCastOverflowedUintDowncast(112, value); } 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 */ function toUint104(uint256 value) internal pure returns (uint104) { if (value > type(uint104).max) { revert SafeCastOverflowedUintDowncast(104, value); } 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 */ function toUint96(uint256 value) internal pure returns (uint96) { if (value > type(uint96).max) { revert SafeCastOverflowedUintDowncast(96, value); } 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 */ function toUint88(uint256 value) internal pure returns (uint88) { if (value > type(uint88).max) { revert SafeCastOverflowedUintDowncast(88, value); } 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 */ function toUint80(uint256 value) internal pure returns (uint80) { if (value > type(uint80).max) { revert SafeCastOverflowedUintDowncast(80, value); } 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 */ function toUint72(uint256 value) internal pure returns (uint72) { if (value > type(uint72).max) { revert SafeCastOverflowedUintDowncast(72, value); } 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 */ function toUint64(uint256 value) internal pure returns (uint64) { if (value > type(uint64).max) { revert SafeCastOverflowedUintDowncast(64, value); } 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 */ function toUint56(uint256 value) internal pure returns (uint56) { if (value > type(uint56).max) { revert SafeCastOverflowedUintDowncast(56, value); } 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 */ function toUint48(uint256 value) internal pure returns (uint48) { if (value > type(uint48).max) { revert SafeCastOverflowedUintDowncast(48, value); } 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 */ function toUint40(uint256 value) internal pure returns (uint40) { if (value > type(uint40).max) { revert SafeCastOverflowedUintDowncast(40, value); } 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 */ function toUint32(uint256 value) internal pure returns (uint32) { if (value > type(uint32).max) { revert SafeCastOverflowedUintDowncast(32, value); } 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 */ function toUint24(uint256 value) internal pure returns (uint24) { if (value > type(uint24).max) { revert SafeCastOverflowedUintDowncast(24, value); } 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 */ function toUint16(uint256 value) internal pure returns (uint16) { if (value > type(uint16).max) { revert SafeCastOverflowedUintDowncast(16, value); } 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 */ function toUint8(uint256 value) internal pure returns (uint8) { if (value > type(uint8).max) { revert SafeCastOverflowedUintDowncast(8, value); } return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { if (value < 0) { revert SafeCastOverflowedIntToUint(value); } 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 */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(248, value); } } /** * @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 */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(240, value); } } /** * @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 */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(232, value); } } /** * @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 */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(224, value); } } /** * @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 */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(216, value); } } /** * @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 */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(208, value); } } /** * @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 */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(200, value); } } /** * @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 */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(192, value); } } /** * @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 */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(184, value); } } /** * @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 */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(176, value); } } /** * @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 */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(168, value); } } /** * @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 */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(160, value); } } /** * @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 */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(152, value); } } /** * @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 */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(144, value); } } /** * @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 */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(136, value); } } /** * @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 */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(128, value); } } /** * @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 */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(120, value); } } /** * @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 */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(112, value); } } /** * @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 */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(104, value); } } /** * @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 */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(96, value); } } /** * @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 */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(88, value); } } /** * @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 */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(80, value); } } /** * @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 */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(72, value); } } /** * @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 */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(64, value); } } /** * @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 */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(56, value); } } /** * @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 */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(48, value); } } /** * @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 */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(40, value); } } /** * @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 */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(32, value); } } /** * @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 */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(24, value); } } /** * @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 */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(16, value); } } /** * @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 */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(8, value); } } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive if (value > uint256(type(int256).max)) { revert SafeCastOverflowedUintToInt(value); } return int256(value); } }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; interface IAdminACLV0 { /** * @notice Token ID `_tokenId` minted to `_to`. * @param previousSuperAdmin The previous superAdmin address. * @param newSuperAdmin The new superAdmin address. * @param genArt721CoreAddressesToUpdate Array of genArt721Core * addresses to update to the new superAdmin, for indexing purposes only. */ event SuperAdminTransferred( address indexed previousSuperAdmin, address indexed newSuperAdmin, address[] genArt721CoreAddressesToUpdate ); /// Type of the Admin ACL contract, e.g. "AdminACLV0" function AdminACLType() external view returns (string memory); /// super admin address function superAdmin() external view returns (address); /** * @notice Calls transferOwnership on other contract from this contract. * This is useful for updating to a new AdminACL contract. * @dev this function should be gated to only superAdmin-like addresses. */ function transferOwnershipOn( address _contract, address _newAdminACL ) external; /** * @notice Calls renounceOwnership on other contract from this contract. * @dev this function should be gated to only superAdmin-like addresses. */ function renounceOwnershipOn(address _contract) external; /** * @notice Checks if sender `_sender` is allowed to call function with selector * `_selector` on contract `_contract`. */ function allowed( address _sender, address _contract, bytes4 _selector ) external returns (bool); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; import "./IEngineRegistryV0.sol"; interface ICoreRegistryV1 is IEngineRegistryV0 { function registerContracts( address[] calldata contractAddresses, bytes32[] calldata coreVersions, bytes32[] calldata coreTypes ) external; function unregisterContracts(address[] calldata contractAddresses) external; function getNumRegisteredContracts() external view returns (uint256); function getRegisteredContractAt( uint256 index ) external view returns (address); function isRegisteredContract( address contractAddress ) external view returns (bool isRegistered); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; interface IEngineRegistryV0 { /// ADDRESS /** * @notice contract has been registered as a contract that is powered by the Art Blocks Engine. */ event ContractRegistered( address indexed _contractAddress, bytes32 _coreVersion, bytes32 _coreType ); /// ADDRESS /** * @notice contract has been unregistered as a contract that is powered by the Art Blocks Engine. */ event ContractUnregistered(address indexed _contractAddress); /** * @notice Emits a `ContractRegistered` event with the provided information. * @dev this function should be gated to only deployer addresses. */ function registerContract( address _contractAddress, bytes32 _coreVersion, bytes32 _coreType ) external; /** * @notice Emits a `ContractUnregistered` event with the provided information, validating that the provided * address was indeed previously registered. * @dev this function should be gated to only deployer addresses. */ function unregisterContract(address _contractAddress) external; }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; interface IFilteredMinterV0 { /** * @notice Price per token in wei updated for project `_projectId` to * `_pricePerTokenInWei`. */ event PricePerTokenInWeiUpdated( uint256 indexed _projectId, uint256 indexed _pricePerTokenInWei ); /** * @notice Currency updated for project `_projectId` to symbol * `_currencySymbol` and address `_currencyAddress`. */ event ProjectCurrencyInfoUpdated( uint256 indexed _projectId, address indexed _currencyAddress, string _currencySymbol ); /// togglePurchaseToDisabled updated event PurchaseToDisabledUpdated( uint256 indexed _projectId, bool _purchaseToDisabled ); // getter function of public variable function minterType() external view returns (string memory); function genArt721CoreAddress() external returns (address); function minterFilterAddress() external returns (address); // Triggers a purchase of a token from the desired project, to the // TX-sending address. function purchase( uint256 _projectId ) external payable returns (uint256 tokenId); // Triggers a purchase of a token from the desired project, to the specified // receiving address. function purchaseTo( address _to, uint256 _projectId ) external payable returns (uint256 tokenId); // Toggles the ability for `purchaseTo` to be called directly with a // specified receiving address that differs from the TX-sending address. function togglePurchaseToDisabled(uint256 _projectId) external; // Called to make the minter contract aware of the max invocations for a // given project. function setProjectMaxInvocations(uint256 _projectId) external; // Gets if token price is configured, token price in wei, currency symbol, // and currency address, assuming this is project's minter. // Supersedes any defined core price. function getPriceInfo( uint256 _projectId ) external view returns ( bool isConfigured, uint256 tokenPriceInWei, string memory currencySymbol, address currencyAddress ); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. import "./IFilteredMinterV0.sol"; pragma solidity ^0.8.0; /** * @title This interface extends the IFilteredMinterV0 interface in order to * add support for generic project minter configuration updates. * @dev keys represent strings of finite length encoded in bytes32 to minimize * gas. * @author Art Blocks Inc. */ interface IFilteredMinterV1 is IFilteredMinterV0 { /// ANY /** * @notice Generic project minter configuration event. Removes key `_key` * for project `_projectId`. */ event ConfigKeyRemoved(uint256 indexed _projectId, bytes32 _key); /// BOOL /** * @notice Generic project minter configuration event. Sets value of key * `_key` to `_value` for project `_projectId`. */ event ConfigValueSet(uint256 indexed _projectId, bytes32 _key, bool _value); /// UINT256 /** * @notice Generic project minter configuration event. Sets value of key * `_key` to `_value` for project `_projectId`. */ event ConfigValueSet( uint256 indexed _projectId, bytes32 _key, uint256 _value ); /** * @notice Generic project minter configuration event. Adds value `_value` * to the set of uint256 at key `_key` for project `_projectId`. */ event ConfigValueAddedToSet( uint256 indexed _projectId, bytes32 _key, uint256 _value ); /** * @notice Generic project minter configuration event. Removes value * `_value` to the set of uint256 at key `_key` for project `_projectId`. */ event ConfigValueRemovedFromSet( uint256 indexed _projectId, bytes32 _key, uint256 _value ); /// ADDRESS /** * @notice Generic project minter configuration event. Sets value of key * `_key` to `_value` for project `_projectId`. */ event ConfigValueSet( uint256 indexed _projectId, bytes32 _key, address _value ); /** * @notice Generic project minter configuration event. Adds value `_value` * to the set of addresses at key `_key` for project `_projectId`. */ event ConfigValueAddedToSet( uint256 indexed _projectId, bytes32 _key, address _value ); /** * @notice Generic project minter configuration event. Removes value * `_value` to the set of addresses at key `_key` for project `_projectId`. */ event ConfigValueRemovedFromSet( uint256 indexed _projectId, bytes32 _key, address _value ); /// BYTES32 /** * @notice Generic project minter configuration event. Sets value of key * `_key` to `_value` for project `_projectId`. */ event ConfigValueSet( uint256 indexed _projectId, bytes32 _key, bytes32 _value ); /** * @notice Generic project minter configuration event. Adds value `_value` * to the set of bytes32 at key `_key` for project `_projectId`. */ event ConfigValueAddedToSet( uint256 indexed _projectId, bytes32 _key, bytes32 _value ); /** * @notice Generic project minter configuration event. Removes value * `_value` to the set of bytes32 at key `_key` for project `_projectId`. */ event ConfigValueRemovedFromSet( uint256 indexed _projectId, bytes32 _key, bytes32 _value ); /** * @dev Strings not supported. Recommend conversion of (short) strings to * bytes32 to remain gas-efficient. */ }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. import "./IFilteredMinterV1.sol"; pragma solidity ^0.8.0; /** * @title This interface extends the IFilteredMinterV1 interface in order to * add support for manually setting project max invocations. * @author Art Blocks Inc. */ interface IFilteredMinterV2 is IFilteredMinterV1 { /** * @notice Local max invocations for project `_projectId`, tied to core contract `_coreContractAddress`, * updated to `_maxInvocations`. */ event ProjectMaxInvocationsLimitUpdated( uint256 indexed _projectId, uint256 _maxInvocations ); // Sets the local max invocations for a given project, checking that the provided max invocations is // less than or equal to the global max invocations for the project set on the core contract. // This does not impact the max invocations value defined on the core contract. function manuallyLimitProjectMaxInvocations( uint256 _projectId, uint256 _maxInvocations ) external; }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; import "./IAdminACLV0.sol"; /** * @title This interface is intended to house interface items that are common * across all GenArt721CoreContractV3 flagship and derivative implementations. * This interface extends the IManifold royalty interface in order to * add support the Royalty Registry by default. * @author Art Blocks Inc. */ interface IGenArt721CoreContractV3_Base { // This interface emits generic events that contain fields that indicate // which parameter has been updated. This is sufficient for application // state management, while also simplifying the contract and indexing code. // This was done as an alternative to having custom events that emit what // field-values have changed for each event, given that changed values can // be introspected by indexers due to the design of this smart contract // exposing these state changes via publicly viewable fields. /** * @notice Event emitted when the Art Blocks Curation Registry contract is updated. * @dev only utilized by subset of V3 core contracts (Art Blocks Curated contracts) * @param artblocksCurationRegistryAddress Address of Art Blocks Curation Registry contract. */ event ArtBlocksCurationRegistryContractUpdated( address indexed artblocksCurationRegistryAddress ); /** * @notice Project's royalty splitter was updated to `_splitter`. * @dev New event in v3.2 * @param projectId The project ID. * @param royaltySplitter The new splitter address to receive royalties. */ event ProjectRoyaltySplitterUpdated( uint256 indexed projectId, address indexed royaltySplitter ); // The following fields are used to indicate which contract-level parameter // has been updated in the `PlatformUpdated` event: // @dev only append to the end of this enum in the case of future updates enum PlatformUpdatedFields { FIELD_NEXT_PROJECT_ID, // 0 FIELD_NEW_PROJECTS_FORBIDDEN, // 1 FIELD_DEFAULT_BASE_URI, // 2 FIELD_RANDOMIZER_ADDRESS, // 3 FIELD_NEXT_CORE_CONTRACT, // 4 FIELD_ARTBLOCKS_DEPENDENCY_REGISTRY_ADDRESS, // 5 FIELD_ARTBLOCKS_ON_CHAIN_GENERATOR_ADDRESS, // 6 FIELD_PROVIDER_SALES_ADDRESSES, // 7 FIELD_PROVIDER_PRIMARY_SALES_PERCENTAGES, // 8 FIELD_PROVIDER_SECONDARY_SALES_BPS, // 9 FIELD_SPLIT_PROVIDER, // 10 FIELD_BYTECODE_STORAGE_READER // 11 } // The following fields are used to indicate which project-level parameter // has been updated in the `ProjectUpdated` event: // @dev only append to the end of this enum in the case of future updates enum ProjectUpdatedFields { FIELD_PROJECT_COMPLETED, // 0 FIELD_PROJECT_ACTIVE, // 1 FIELD_PROJECT_ARTIST_ADDRESS, // 2 FIELD_PROJECT_PAUSED, // 3 FIELD_PROJECT_CREATED, // 4 FIELD_PROJECT_NAME, // 5 FIELD_PROJECT_ARTIST_NAME, // 6 FIELD_PROJECT_SECONDARY_MARKET_ROYALTY_PERCENTAGE, // 7 FIELD_PROJECT_DESCRIPTION, // 8 FIELD_PROJECT_WEBSITE, // 9 FIELD_PROJECT_LICENSE, // 10 FIELD_PROJECT_MAX_INVOCATIONS, // 11 FIELD_PROJECT_SCRIPT, // 12 FIELD_PROJECT_SCRIPT_TYPE, // 13 FIELD_PROJECT_ASPECT_RATIO, // 14 FIELD_PROJECT_BASE_URI, // 15 FIELD_PROJECT_PROVIDER_SECONDARY_FINANCIALS // 16 } /** * @notice Error codes for the GenArt721 contract. Used by the GenArt721Error * custom error. * @dev only append to the end of this enum in the case of future updates */ enum ErrorCodes { OnlyNonZeroAddress, // 0 OnlyNonEmptyString, // 1 OnlyNonEmptyBytes, // 2 TokenDoesNotExist, // 3 ProjectDoesNotExist, // 4 OnlyUnlockedProjects, // 5 OnlyAdminACL, // 6 OnlyArtist, // 7 OnlyArtistOrAdminACL, // 8 OnlyAdminACLOrRenouncedArtist, // 9 OnlyMinterContract, // 10 MaxInvocationsReached, // 11 ProjectMustExistAndBeActive, // 12 PurchasesPaused, // 13 OnlyRandomizer, // 14 TokenHashAlreadySet, // 15 NoZeroHashSeed, // 16 OverMaxSumOfPercentages, // 17 IndexOutOfBounds, // 18 OverMaxSumOfBPS, // 19 MaxOf100Percent, // 20 PrimaryPayeeIsZeroAddress, // 21 SecondaryPayeeIsZeroAddress, // 22 MustMatchArtistProposal, // 23 NewProjectsForbidden, // 24 NewProjectsAlreadyForbidden, // 25 OnlyArtistOrAdminIfLocked, // 26 OverMaxSecondaryRoyaltyPercentage, // 27 OnlyMaxInvocationsDecrease, // 28 OnlyGteInvocations, // 29 ScriptIdOutOfRange, // 30 NoScriptsToRemove, // 31 ScriptTypeAndVersionFormat, // 32 AspectRatioTooLong, // 33 AspectRatioNoNumbers, // 34 AspectRatioImproperFormat, // 35 OnlyNullPlatformProvider, // 36 ContractInitialized // 37 } /** * @notice Emits an error code `_errorCode` in the GenArt721Error event. * @dev Emitting error codes instead of error strings saves significant * contract bytecode size, allowing for more contract functionality within * the 24KB contract size limit. * @param _errorCode The error code to emit. See ErrorCodes enum. */ error GenArt721Error(ErrorCodes _errorCode); /** * @notice Token ID `_tokenId` minted to `_to`. */ event Mint(address indexed _to, uint256 indexed _tokenId); /** * @notice currentMinter updated to `_currentMinter`. * @dev Implemented starting with V3 core */ event MinterUpdated(address indexed _currentMinter); /** * @notice Platform updated on bytes32-encoded field `_field`. */ event PlatformUpdated(bytes32 indexed _field); /** * @notice Project ID `_projectId` updated on bytes32-encoded field * `_update`. */ event ProjectUpdated(uint256 indexed _projectId, bytes32 indexed _update); event ProposedArtistAddressesAndSplits( uint256 indexed _projectId, address _artistAddress, address _additionalPayeePrimarySales, uint256 _additionalPayeePrimarySalesPercentage, address _additionalPayeeSecondarySales, uint256 _additionalPayeeSecondarySalesPercentage ); event AcceptedArtistAddressesAndSplits(uint256 indexed _projectId); // version and type of the core contract // coreVersion is a string of the form "0.x.y" function coreVersion() external view returns (string memory); // coreType is a string of the form "GenArt721CoreV3" function coreType() external view returns (string memory); // owner (pre-V3 was named admin) of contract // this is expected to be an Admin ACL contract for V3 function owner() external view returns (address); // Admin ACL contract for V3, will be at the address owner() function adminACLContract() external returns (IAdminACLV0); // backwards-compatible (pre-V3) admin - equal to owner() function admin() external view returns (address); /** * Function determining if _sender is allowed to call function with * selector _selector on contract `_contract`. Intended to be used with * peripheral contracts such as minters, as well as internally by the * core contract itself. */ function adminACLAllowed( address _sender, address _contract, bytes4 _selector ) external returns (bool); /// getter function of public variable function startingProjectId() external view returns (uint256); // getter function of public variable function nextProjectId() external view returns (uint256); // getter function of public mapping function tokenIdToProjectId( uint256 tokenId ) external view returns (uint256 projectId); // @dev this is not available in V0 function isMintWhitelisted(address minter) external view returns (bool); function projectIdToArtistAddress( uint256 _projectId ) external view returns (address payable); function projectIdToSecondaryMarketRoyaltyPercentage( uint256 _projectId ) external view returns (uint256); function projectURIInfo( uint256 _projectId ) external view returns (string memory projectBaseURI); // @dev new function in V3 function projectStateData( uint256 _projectId ) external view returns ( uint256 invocations, uint256 maxInvocations, bool active, bool paused, uint256 completedTimestamp, bool locked ); function projectDetails( uint256 _projectId ) external view returns ( string memory projectName, string memory artist, string memory description, string memory website, string memory license ); function projectScriptDetails( uint256 _projectId ) external view returns ( string memory scriptTypeAndVersion, string memory aspectRatio, uint256 scriptCount ); function projectScriptByIndex( uint256 _projectId, uint256 _index ) external view returns (string memory); function tokenIdToHash(uint256 _tokenId) external view returns (bytes32); // function to set a token's hash (must be guarded) function setTokenHash_8PT(uint256 _tokenId, bytes32 _hash) external; // @dev gas-optimized signature in V3 for `mint` function mint_Ecf( address _to, uint256 _projectId, address _by ) external returns (uint256 tokenId); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; import "./IAdminACLV0.sol"; import "./IGenArt721CoreContractV3_Base.sol"; import "./ISplitProviderV0.sol"; /** * @notice Struct representing Engine contract configuration. * @param tokenName Name of token. * @param tokenSymbol Token symbol. * @param renderProviderAddress address to send render provider revenue to * @param randomizerContract Randomizer contract. * @param splitProviderAddress Address to use as royalty splitter provider for the contract. * @param minterFilterAddress Address of the Minter Filter to set as the Minter * on the contract. * @param startingProjectId The initial next project ID. * @param autoApproveArtistSplitProposals Whether or not to always * auto-approve proposed artist split updates. * @param nullPlatformProvider Enforce always setting zero platform provider fees and addresses. * @param allowArtistProjectActivation Allow artist to activate their own projects. * @dev _startingProjectId should be set to a value much, much less than * max(uint248), but an explicit input type of `uint248` is used as it is * safer to cast up to `uint256` than it is to cast down for the purposes * of setting `_nextProjectId`. */ struct EngineConfiguration { string tokenName; string tokenSymbol; address renderProviderAddress; address platformProviderAddress; address newSuperAdminAddress; address randomizerContract; address splitProviderAddress; address minterFilterAddress; uint248 startingProjectId; bool autoApproveArtistSplitProposals; bool nullPlatformProvider; bool allowArtistProjectActivation; } interface IGenArt721CoreContractV3_Engine is IGenArt721CoreContractV3_Base { // @dev new function in V3.2 /** * @notice Initializes the contract with the provided `engineConfiguration`. * This function should be called atomically, immediately after deployment. * Only callable once. Validation on `engineConfiguration` is performed by caller. * @param engineConfiguration EngineConfiguration to configure the contract with. * @param adminACLContract_ Address of admin access control contract, to be * set as contract owner. * @param defaultBaseURIHost Base URI prefix to initialize default base URI with. * @param bytecodeStorageReaderContract_ Address of the bytecode storage reader contract. */ function initialize( EngineConfiguration calldata engineConfiguration, address adminACLContract_, string memory defaultBaseURIHost, address bytecodeStorageReaderContract_ ) external; // @dev new function in V3 function getPrimaryRevenueSplits( uint256 _projectId, uint256 _price ) external view returns ( uint256 renderProviderRevenue_, address payable renderProviderAddress_, uint256 platformProviderRevenue_, address payable platformProviderAddress_, uint256 artistRevenue_, address payable artistAddress_, uint256 additionalPayeePrimaryRevenue_, address payable additionalPayeePrimaryAddress_ ); // @dev The render provider primary sales payment address function renderProviderPrimarySalesAddress() external view returns (address payable); // @dev The platform provider primary sales payment address function platformProviderPrimarySalesAddress() external view returns (address payable); // @dev Percentage of primary sales allocated to the render provider function renderProviderPrimarySalesPercentage() external view returns (uint256); // @dev Percentage of primary sales allocated to the platform provider function platformProviderPrimarySalesPercentage() external view returns (uint256); /** @notice The default render provider payment address for all secondary sales royalty * revenues, for all new projects. Individual project payment info is defined * in each project's ProjectFinance struct. * @return The default render provider payment address for secondary sales royalties. */ function defaultRenderProviderSecondarySalesAddress() external view returns (address payable); /** @notice The default platform provider payment address for all secondary sales royalty * revenues, for all new projects. Individual project payment info is defined * in each project's ProjectFinance struct. * @return The default platform provider payment address for secondary sales royalties. */ function defaultPlatformProviderSecondarySalesAddress() external view returns (address payable); /** @notice The default render provider payment basis points for all secondary sales royalty * revenues, for all new projects. Individual project payment info is defined * in each project's ProjectFinance struct. * @return The default render provider payment basis points for secondary sales royalties. */ function defaultRenderProviderSecondarySalesBPS() external view returns (uint256); /** @notice The default platform provider payment basis points for all secondary sales royalty * revenues, for all new projects. Individual project payment info is defined * in each project's ProjectFinance struct. * @return The default platform provider payment basis points for secondary sales royalties. */ function defaultPlatformProviderSecondarySalesBPS() external view returns (uint256); /** * @notice The address of the current split provider being used by the contract. * @return The address of the current split provider. */ function splitProvider() external view returns (ISplitProviderV0); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; import "./IAdminACLV0.sol"; import "./IGenArt721CoreContractV3_Base.sol"; /** * @title This interface extends IGenArt721CoreContractV3_Base with functions * that are part of the Art Blocks Flagship core contract. * @author Art Blocks Inc. */ // This interface extends IGenArt721CoreContractV3_Base with functions that are // in part of the Art Blocks Flagship core contract. interface IGenArt721CoreContractV3 is IGenArt721CoreContractV3_Base { // @dev new function in V3 function getPrimaryRevenueSplits( uint256 _projectId, uint256 _price ) external view returns ( uint256 artblocksRevenue_, address payable artblocksAddress_, uint256 artistRevenue_, address payable artistAddress_, uint256 additionalPayeePrimaryRevenue_, address payable additionalPayeePrimaryAddress_ ); // @dev Art Blocks primary sales payment address function artblocksPrimarySalesAddress() external view returns (address payable); /** * @notice Backwards-compatible (pre-V3) function returning Art Blocks * primary sales payment address (now called artblocksPrimarySalesAddress). */ function artblocksAddress() external view returns (address payable); // @dev Percentage of primary sales allocated to Art Blocks function artblocksPrimarySalesPercentage() external view returns (uint256); /** * @notice Backwards-compatible (pre-V3) function returning Art Blocks * primary sales percentage (now called artblocksPrimarySalesPercentage). */ function artblocksPercentage() external view returns (uint256); // @dev Art Blocks secondary sales royalties payment address function artblocksSecondarySalesAddress() external view returns (address payable); // @dev Basis points of secondary sales allocated to Art Blocks function artblocksSecondarySalesBPS() external view returns (uint256); /** * @notice Backwards-compatible (pre-V3) function that gets artist + * artist's additional payee royalty data for token ID `_tokenId`. * WARNING: Does not include Art Blocks portion of royalties. */ function getRoyaltyData( uint256 _tokenId ) external view returns ( address artistAddress, address additionalPayee, uint256 additionalPayeePercentage, uint256 royaltyFeeByID ); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. import "./IFilteredMinterV2.sol"; pragma solidity ^0.8.0; /** * @title This interface defines any events or functions required for a minter * to conform to the MinterBase contract. * @dev The MinterBase contract was not implemented from the beginning of the * MinterSuite contract suite, therefore early versions of some minters may not * conform to this interface. * @author Art Blocks Inc. */ interface IMinterBaseV0 { // Function that returns if a minter is configured to integrate with a V3 flagship or V3 engine contract. // Returns true only if the minter is configured to integrate with an engine contract. function isEngine() external returns (bool isEngine); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; import "./ICoreRegistryV1.sol"; import "./IAdminACLV0.sol"; /** * @title IMinterFilterV1 * @author Art Blocks Inc. * @notice Interface for a new minter filter contract. * This interface does not extend the previous version of the minter filter * interface, as the previous version is not compatible with the new * minter filter architecture. * @dev This interface is for a minter filter that supports multiple core * contracts, and allows for a minter to be set on a per-project basis. */ interface IMinterFilterV1 { /** * @notice Emitted when contract is deployed to notify indexing services * of the new contract deployment. */ event Deployed(); /** * @notice Globally approved minter `minter`. */ event MinterApprovedGlobally(address indexed minter, string minterType); /** * @notice Globally revoked minter `minter`. * @dev contract owner may still approve this minter on a per-contract * basis. */ event MinterRevokedGlobally(address indexed minter); /** * @notice Approved minter `minter` on core contract * `coreContract`. */ event MinterApprovedForContract( address indexed coreContract, address indexed minter, string minterType ); /** * @notice Revoked minter `minter` on core contract `coreContract`. * @dev minter filter owner may still globally approve this minter for all * contracts. */ event MinterRevokedForContract( address indexed coreContract, address indexed minter ); /** * @notice Minter at address `minter` set as minter for project * `projectId` on core contract `coreContract`. */ event ProjectMinterRegistered( uint256 indexed projectId, address indexed coreContract, address indexed minter, string minterType ); /** * @notice Minter removed for project `projectId` on core contract * `coreContract`. */ event ProjectMinterRemoved( uint256 indexed projectId, address indexed coreContract ); /** * @notice Admin ACL contract updated to `adminACLContract`. */ event AdminACLUpdated(address indexed adminACLContract); /** * @notice Core Registry contract updated to `coreRegistry`. */ event CoreRegistryUpdated(address indexed coreRegistry); // struct used to return minter info // @dev this is not used for storage of data struct MinterWithType { address minterAddress; string minterType; } function setMinterForProject( uint256 projectId, address coreContract, address minter ) external; function removeMinterForProject( uint256 projectId, address coreContract ) external; // @dev function name is optimized for gas function mint_joo( address to, uint256 projectId, address coreContract, address sender ) external returns (uint256); function updateCoreRegistry(address coreRegistry) external; /** * @notice Returns if `sender` is allowed to call function on `contract` * with `selector` selector, according to the MinterFilter's Admin ACL. */ function adminACLAllowed( address sender, address contract_, bytes4 selector ) external returns (bool); function minterFilterType() external pure returns (string memory); function getMinterForProject( uint256 projectId, address coreContract ) external view returns (address); function projectHasMinter( uint256 projectId, address coreContract ) external view returns (bool); /** * @notice View that returns if a core contract is registered with the * core registry, allowing this minter filter to service it. * @param coreContract core contract address to be checked */ function isRegisteredCoreContract( address coreContract ) external view returns (bool); /// Address of current core registry contract function coreRegistry() external view returns (ICoreRegistryV1); /// The current admin ACL contract function adminACLContract() external view returns (IAdminACLV0); /// The quantity of projects on a core contract that have assigned minters function getNumProjectsOnContractWithMinters( address coreContract ) external view returns (uint256); function getProjectAndMinterInfoOnContractAt( address coreContract, uint256 index ) external view returns ( uint256 projectId, address minterAddress, string memory minterType ); function getAllGloballyApprovedMinters() external view returns (MinterWithType[] memory mintersWithTypes); function getAllContractApprovedMinters( address coreContract ) external view returns (MinterWithType[] memory mintersWithTypes); /** * Owner of contract. * @dev This returns the address of the Admin ACL contract. */ function owner() external view returns (address); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. to support the 0xSplits V2 integration // Sourced from: // - https://github.com/0xSplits/splits-contracts-monorepo/blob/main/packages/splits-v2/src/libraries/SplitV2.sol // - https://github.com/0xSplits/splits-contracts-monorepo/blob/main/packages/splits-v2/src/splitters/SplitFactoryV2.sol pragma solidity ^0.8.0; interface ISplitFactoryV2 { /* -------------------------------------------------------------------------- */ /* STRUCTS */ /* -------------------------------------------------------------------------- */ /** * @notice Split struct * @dev This struct is used to store the split information. * @dev There are no hard caps on the number of recipients/totalAllocation/allocation unit. Thus the chain and its * gas limits will dictate these hard caps. Please double check if the split you are creating can be distributed on * the chain. * @param recipients The recipients of the split. * @param allocations The allocations of the split. * @param totalAllocation The total allocation of the split. * @param distributionIncentive The incentive for distribution. Limits max incentive to 6.5%. */ struct Split { address[] recipients; uint256[] allocations; uint256 totalAllocation; uint16 distributionIncentive; } /* -------------------------------------------------------------------------- */ /* FUNCTIONS */ /* -------------------------------------------------------------------------- */ /** * @notice Create a new split with params and owner. * @param _splitParams Params to create split with. * @param _owner Owner of created split. * @param _creator Creator of created split. * @param _salt Salt for create2. * @return split Address of the created split. */ function createSplitDeterministic( Split calldata _splitParams, address _owner, address _creator, bytes32 _salt ) external returns (address split); /** * @notice Predict the address of a new split and check if it is deployed. * @param _splitParams Params to create split with. * @param _owner Owner of created split. * @param _salt Salt for create2. */ function isDeployed( Split calldata _splitParams, address _owner, bytes32 _salt ) external view returns (address split, bool exists); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; /** * @title This interface adds support for ranked auction minting. * @author Art Blocks Inc. */ interface ISharedMinterRAMV0 { function createBid( uint256 projectId, address coreContract, uint16 slotIndex ) external payable; function topUpBid( uint256 projectId, address coreContract, uint32 bidId, uint16 newSlotIndex ) external payable; }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; /** * @title ISharedMinterRequired * @notice This interface contains the minimum required interface for a shared * minter contract. All custom, one-off minter contracts should implement this * interface. */ interface ISharedMinterRequired { /** * @notice Returns the minter's type, used by the minter filter for metadata * purposes. * @return The minter type. */ function minterType() external view returns (string memory); /** * @notice Returns the minter's associated shared minter filter address. * @dev used by subgraph indexing service for entity relation purposes. * @return The minter filter address. */ function minterFilterAddress() external returns (address); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; import {ISharedMinterRequired} from "./ISharedMinterRequired.sol"; /** * @title ISharedMinterV0 * @notice This interface extends the minimum required interface for a shared * minter contract to add additional functionality that is generally available * for all shared minter contracts on the shared minter filter. * @dev Custom, one-off minter contracts that are not globally approved may * choose to not implement this interface, but should still implement the * ISharedMinterRequired interface. */ interface ISharedMinterV0 is ISharedMinterRequired { // Sets the local max invocations for a given project, checking that the provided max invocations is // less than or equal to the global max invocations for the project set on the core contract. // This does not impact the max invocations value defined on the core contract. function manuallyLimitProjectMaxInvocations( uint256 projectId, address coreContract, uint24 maxInvocations ) external; // Called to make the minter contract aware of the max invocations for a // given project. function syncProjectMaxInvocationsToCore( uint256 projectId, address coreContract ) external; // Gets if token price is configured, token price in wei, currency symbol, // and currency address, assuming this is project's minter. // Supersedes any defined core price. function getPriceInfo( uint256 projectId, address coreContract ) external view returns ( bool isConfigured, uint256 tokenPriceInWei, string memory currencySymbol, address currencyAddress ); }
// SPDX-License-Identifier: LGPL-3.0-only // Creatd By: Art Blocks Inc. pragma solidity ^0.8.0; import {ISplitFactoryV2} from "./integration-refs/splits-0x-v2/ISplitFactoryV2.sol"; interface ISplitProviderV0 { /** * @notice SplitInputs struct defines the inputs for requested splitters. * It is defined in a way easily communicated from the Art Blocks GenArt721V3 contract, * to allow for easy integration and minimal additional bytecode in the GenArt721V3 contract. */ struct SplitInputs { address platformProviderSecondarySalesAddress; uint16 platformProviderSecondarySalesBPS; address renderProviderSecondarySalesAddress; uint16 renderProviderSecondarySalesBPS; uint8 artistTotalRoyaltyPercentage; address artist; address additionalPayee; uint8 additionalPayeePercentage; } /** * @notice Emitted when a new splitter contract is created. * @param splitter address of the splitter contract */ event SplitterCreated(address indexed splitter); /** * @notice Gets or creates an immutable splitter contract at a deterministic address. * Splits in the splitter contract are determined by the input split parameters, * so we can safely create the splitter contract at a deterministic address (or use * the existing splitter contract if it already exists at that address). * @dev Uses the 0xSplits v2 implementation to create a splitter contract * @param splitInputs The split input parameters. * @return splitter The newly created splitter contract address. */ function getOrCreateSplitter( SplitInputs calldata splitInputs ) external returns (address); /** * @notice Indicates the type of the contract, e.g. `SplitProviderV0`. * @return type_ The type of the contract. */ function type_() external pure returns (bytes32); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; /** * @title Art Blocks Helpers Library * @notice This library contains helper functions for common operations in the * Art Blocks ecosystem of smart contracts. * @author Art Blocks Inc. */ library ABHelpers { uint256 constant ONE_MILLION = 1_000_000; /** * @notice Function to convert token id to project id. * @param tokenId The id of the token. */ function tokenIdToProjectId( uint256 tokenId ) internal pure returns (uint256) { // int division properly rounds down // @dev no way to disable division by zero check in solidity v0.8.24, so not unchecked return tokenId / ONE_MILLION; } /** * @notice Function to convert token id to token number. * @param tokenId The id of the token. */ function tokenIdToTokenNumber( uint256 tokenId ) internal pure returns (uint256) { // mod returns remainder, which is the token number // @dev no way to disable mod zero check in solidity, so not unchecked return tokenId % ONE_MILLION; } /** * @notice Function to convert token id to token invocation. * @dev token invocation is the token number plus one, because token #0 is * invocation 1. * @param tokenId The id of the token. */ function tokenIdToTokenInvocation( uint256 tokenId ) internal pure returns (uint256) { unchecked { // mod returns remainder, which is the token number // @dev no way to disable mod zero check in solidity, unchecked to optimize gas for addition return (tokenId % ONE_MILLION) + 1; } } /** * @notice Function to convert project id and token number to token id. * @param projectId The id of the project. * @param tokenNumber The token number. */ function tokenIdFromProjectIdAndTokenNumber( uint256 projectId, uint256 tokenNumber ) internal pure returns (uint256) { // @dev intentionally not unchecked to ensure overflow detection, which // would likley only occur in a malicious call return (projectId * ONE_MILLION) + tokenNumber; } }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; import {IGenArt721CoreContractV3_Base} from "../../interfaces/v0.8.x/IGenArt721CoreContractV3_Base.sol"; import {IMinterFilterV1} from "../../interfaces/v0.8.x/IMinterFilterV1.sol"; /** * @title Art Blocks Authorization Minter Library * @notice This library contains helper functions that may be used contracts to * check authorization for performing operations in the Art Blocks V3 core * contract ecosystem. * @author Art Blocks Inc. */ library AuthLib { /** * @notice Function to restrict access to only AdminACL allowed calls, where * AdminACL is the admin of an IMinterFilterV1. * Reverts if not allowed. * @param minterFilterAddress address of the minter filter to be checked, * should implement IMinterFilterV1 * @param sender address of the caller * @param contract_ address of the contract being called * @param selector selector of the function being called */ function onlyMinterFilterAdminACL( address minterFilterAddress, address sender, address contract_, bytes4 selector ) internal { require( _minterFilterAdminACLAllowed({ minterFilterAddress: minterFilterAddress, sender: sender, contract_: contract_, selector: selector }), "Only MinterFilter AdminACL" ); } /** * @notice Function to restrict access to only AdminACL allowed calls, where * AdminACL is the admin of a core contract at `coreContract`. * Reverts if not allowed. * @param coreContract address of the core contract to be checked * @param sender address of the caller * @param contract_ address of the contract being called * @param selector selector of the function being called */ function onlyCoreAdminACL( address coreContract, address sender, address contract_, bytes4 selector ) internal { require( _coreAdminACLAllowed({ coreContract: coreContract, sender: sender, contract_: contract_, selector: selector }), "Only Core AdminACL allowed" ); } /** * @notice Throws if `sender` is any account other than the artist of the * specified project `projectId` on core contract `coreContract`. * @param projectId The ID of the project being checked. * @param coreContract The address of the GenArt721CoreContractV3_Base * contract. * @param sender Wallet to check. Typically, the address of the caller. * @dev `sender` must be the artist associated with `projectId` on `coreContract`. */ function onlyArtist( uint256 projectId, address coreContract, address sender ) internal view { require( _senderIsArtist({ projectId: projectId, coreContract: coreContract, sender: sender }), "Only Artist" ); } /** * @notice Function to restrict access to only the artist of a project, or AdminACL * allowed calls, where AdminACL is the admin of a core contract at * `coreContract`. * @param projectId id of the project * @param coreContract address of the core contract to be checked * @param sender address of the caller * @param contract_ address of the contract being called * @param selector selector of the function being called */ function onlyCoreAdminACLOrArtist( uint256 projectId, address coreContract, address sender, address contract_, bytes4 selector ) internal { require( _senderIsArtist({ projectId: projectId, coreContract: coreContract, sender: sender }) || _coreAdminACLAllowed({ coreContract: coreContract, sender: sender, contract_: contract_, selector: selector }), "Only Artist or Core Admin ACL" ); } // ------------------------------------------------------------------------ // Private functions used internally by this library // ------------------------------------------------------------------------ /** * @notice Private function that returns if minter filter contract's AdminACL * allows `sender` to call function with selector `selector` on contract * `contract`. * @param minterFilterAddress address of the minter filter to be checked. * Should implement IMinterFilterV1. * @param sender address of the caller * @param contract_ address of the contract being called * @param selector selector of the function being called */ function _minterFilterAdminACLAllowed( address minterFilterAddress, address sender, address contract_, bytes4 selector ) private returns (bool) { return IMinterFilterV1(minterFilterAddress).adminACLAllowed({ sender: sender, contract_: contract_, selector: selector }); } /** * @notice Private function that returns if core contract's AdminACL allows * `sender` to call function with selector `selector` on contract * `contract`. * @param coreContract address of the core contract to be checked * @param sender address of the caller * @param contract_ address of the contract being called * @param selector selector of the function being called */ function _coreAdminACLAllowed( address coreContract, address sender, address contract_, bytes4 selector ) private returns (bool) { return IGenArt721CoreContractV3_Base(coreContract).adminACLAllowed({ _sender: sender, _contract: contract_, _selector: selector }); } /** * @notice Private function that returns if `sender` is the artist of `projectId` * on `coreContract`. * @param projectId project ID to check * @param coreContract core contract to check * @param sender wallet to check */ function _senderIsArtist( uint256 projectId, address coreContract, address sender ) private view returns (bool senderIsArtist) { return sender == IGenArt721CoreContractV3_Base(coreContract) .projectIdToArtistAddress(projectId); } }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; /** * @dev Library for using uint256 as a mapping to 256 bool values via a bit map. * This is useful for storing a large number of bool values in a compact way. * @dev This implementation is similar to OpenZeppelin's BitMaps library, but a * single uint256 is used directly in memory instead of operating within a * a mapping within a storage struct. * This design limits the number of indices to 256, but is more gas efficient * for use cases that fit within that limit. This is especially true for * operations that require many reads/writes, since SLOAD/SSTORE can be managed * outside of the library. */ library BitMaps256 { /** * @notice Checks if the bit at a specific index in the bit map is set. * A bit is considered set if it is 1, and unset if it is 0. * @param bitMap BitMap to check. * @param index The index of the bit to check. * @return Indicating if the bit at the specified index is set, false otherwise. */ function get(uint256 bitMap, uint8 index) internal pure returns (bool) { uint256 mask = 1 << index; return bitMap & mask != 0; } /** * @notice Sets the bit at a specific index in the bit map to 1. * This function creates a new bit map where the bit at the specified index is set, * leaving other bits unchanged. * @param bitMap The original BitMap. * @param index The index of the bit to set. * @return newBitMap The new bit map after setting the bit at the specified index. */ function set( uint256 bitMap, uint8 index ) internal pure returns (uint256 newBitMap) { uint256 mask = 1 << index; return bitMap | mask; } /** * @notice Unsets the bit at a specific index in the bit map, setting it to 0. * This function creates a new bit map where the bit at the specified index is unset, * leaving other bits unchanged. * @param bitMap The original BitMap. * @param index The index of the bit to unset. * @return newBitMap The new bit map after unsetting the bit at the specified index. */ function unset( uint256 bitMap, uint8 index ) internal pure returns (uint256 newBitMap) { uint256 mask = 1 << index; return bitMap & ~mask; } /** * @notice Finds the index of the first bit that is set in the bit map * starting from a given index. * Returns (255, false) if no set bits were found. * @param bitMap BitMap to search * @param startIndex Index to start searching from, inclusive * @return minIndex Index of first set bit, or 255 if no bits were found * @return foundSetBit True if a set bit was found, false otherwise */ function minBitSet( uint256 bitMap, uint8 startIndex ) internal pure returns (uint256 minIndex, bool foundSetBit) { // check if there's any set bit at or above startIndex if ((bitMap >> startIndex) == 0) { return (255, false); } minIndex = startIndex; // @dev this is a linear search, optimized to start only if there's a set bit at or above startIndex // worst case 255 iterations in memory while (minIndex < 255 && !get(bitMap, uint8(minIndex))) { minIndex++; } foundSetBit = get(bitMap, uint8(minIndex)); } /** * @notice Finds the index of the highest bit that is set in the bit map * starting from a given index and counting down. * Returns (0, false) if no set bits were found. * @param bitMap BitMap to search * @param startIndex Index to start searching from, inclusive * @return maxIndex Index of last set bit, or 0 if no bits were found * @return foundSetBit True if a set bit was found, false otherwise */ function maxBitSet( uint256 bitMap, uint8 startIndex ) internal pure returns (uint256 maxIndex, bool foundSetBit) { if ((bitMap << (255 - startIndex)) == 0) { return (0, false); } maxIndex = startIndex; // @dev this is a linear search, worst case 255 iterations in memory while (maxIndex > 0 && !get(bitMap, uint8(maxIndex))) { maxIndex--; } foundSetBit = get(bitMap, uint8(maxIndex)); } }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; /** * @title Art Blocks Generic Events Library * @notice This library is designed to define a set of generic events that all * shared minter libraries may utilize to populate indexed extra minter details * @dev Strings not supported. Recommend conversion of (short) strings to * bytes32 to remain gas-efficient. * @author Art Blocks Inc. */ library GenericMinterEventsLib { /** * @notice Generic project minter configuration event. Removed key `key` * for project `projectId`. * @param projectId Project ID key was removed for * @param coreContract Core contract address that projectId is on * @param key Key removed */ event ConfigKeyRemoved( uint256 indexed projectId, address indexed coreContract, bytes32 key ); /// BOOL /** * @notice Generic project minter configuration event. Value of key * `key` was set to `value` for project `projectId`. * @param projectId Project ID key was set for * @param coreContract Core contract address that projectId is on * @param key Key set * @param value Value key was set to */ event ConfigValueSet( uint256 indexed projectId, address indexed coreContract, bytes32 key, bool value ); /// UINT256 /** * @notice Generic project minter configuration event. Value of key * `key` was set to `value` for project `projectId`. * @param projectId Project ID key was set for * @param coreContract Core contract address that projectId is on * @param key Key set * @param value Value key was set to */ event ConfigValueSet( uint256 indexed projectId, address indexed coreContract, bytes32 key, uint256 value ); /** * @notice Generic project minter configuration event. Added value `value` * to the set of uint256 at key `key` for project `projectId`. * @param projectId Project ID key was set for * @param coreContract Core contract address that projectId is on * @param key Key modified * @param value Value added to the key's set */ event ConfigValueAddedToSet( uint256 indexed projectId, address indexed coreContract, bytes32 key, uint256 value ); /** * @notice Generic project minter configuration event. Removed value * `value` to the set of uint256 at key `key` for project `projectId`. * @param projectId Project ID key was set for * @param coreContract Core contract address that projectId is on * @param key Key modified * @param value Value removed from the key's set */ event ConfigValueRemovedFromSet( uint256 indexed projectId, address indexed coreContract, bytes32 key, uint256 value ); /// ADDRESS /** * @notice Generic project minter configuration event. Value of key * `key` was set to `value` for project `projectId`. * @param projectId Project ID key was set for * @param coreContract Core contract address that projectId is on * @param key Key set * @param value Value key was set to */ event ConfigValueSet( uint256 indexed projectId, address indexed coreContract, bytes32 key, address value ); /** * @notice Generic project minter configuration event. Added value `value` * to the set of addresses at key `key` for project `projectId`. * @param projectId Project ID key was set for * @param coreContract Core contract address that projectId is on * @param key Key modified * @param value Value added to the key's set */ event ConfigValueAddedToSet( uint256 indexed projectId, address indexed coreContract, bytes32 key, address value ); /** * @notice Generic project minter configuration event. Removed value * `value` to the set of addresses at key `key` for project `projectId`. * @param projectId Project ID key was set for * @param coreContract Core contract address that projectId is on * @param key Key modified * @param value Value removed from the key's set */ event ConfigValueRemovedFromSet( uint256 indexed projectId, address indexed coreContract, bytes32 key, address value ); /// BYTES32 /** * @notice Generic project minter configuration event. Value of key * `key` was set to `value` for project `projectId`. * @param projectId Project ID key was set for * @param coreContract Core contract address that projectId is on * @param key Key set * @param value Value key was set to */ event ConfigValueSet( uint256 indexed projectId, address indexed coreContract, bytes32 key, bytes32 value ); /** * @notice Generic project minter configuration event. Added value `value` * to the set of bytes32 at key `key` for project `projectId`. * @param projectId Project ID key was set for * @param coreContract Core contract address that projectId is on * @param key Key modified * @param value Value added to the key's set */ event ConfigValueAddedToSet( uint256 indexed projectId, address indexed coreContract, bytes32 key, bytes32 value ); /** * @notice Generic project minter configuration event. Removed value * `value` to the set of bytes32 at key `key` for project `projectId`. * @param projectId Project ID key was set for * @param coreContract Core contract address that projectId is on * @param key Key modified * @param value Value removed from the key's set */ event ConfigValueRemovedFromSet( uint256 indexed projectId, address indexed coreContract, bytes32 key, bytes32 value ); }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; import {IGenArt721CoreContractV3_Base} from "../../../interfaces/v0.8.x/IGenArt721CoreContractV3_Base.sol"; import {ABHelpers} from "../ABHelpers.sol"; import {Math} from "@openzeppelin-4.7/contracts/utils/math/Math.sol"; import {SafeCast} from "@openzeppelin-4.7/contracts/utils/math/SafeCast.sol"; /** * @title Art Blocks Max Invocations Library * @notice This library manages the maximum invocation limits for Art Blocks * projects. It provides functionality for synchronizing, manually limiting, and * updating these limits, ensuring the integrity in relation to the core Art * Blocks contract, and managing updates upon token minting. * @dev Functions include `syncProjectMaxInvocationsToCore`, * `manuallyLimitProjectMaxInvocations`, and `purchaseEffectsInvocations`. * @author Art Blocks Inc. */ library MaxInvocationsLib { using SafeCast for uint256; /** * @notice Local max invocations for project `projectId`, tied to core contract `coreContractAddress`, * updated to `maxInvocations`. * @param projectId The id of the project. * @param coreContract The address of the core contract. * @param maxInvocations The new max invocations limit. */ event ProjectMaxInvocationsLimitUpdated( uint256 indexed projectId, address indexed coreContract, uint256 maxInvocations ); // position of Max Invocations Lib storage, using a diamond storage pattern // for this library bytes32 constant MAX_INVOCATIONS_LIB_STORAGE_POSITION = keccak256("maxinvocationslib.storage"); uint256 internal constant ONE_MILLION = 1_000_000; /** * @notice Data structure that holds max invocations project configuration. */ struct MaxInvocationsProjectConfig { bool maxHasBeenInvoked; uint24 maxInvocations; } // Diamond storage pattern is used in this library struct MaxInvocationsLibStorage { mapping(address coreContract => mapping(uint256 projectId => MaxInvocationsProjectConfig)) maxInvocationsProjectConfigs; } /** * @notice Syncs project's max invocations to core contract value. * @param projectId The id of the project. * @param coreContract The address of the core contract. */ function syncProjectMaxInvocationsToCore( uint256 projectId, address coreContract ) internal { ( uint256 coreInvocations, uint256 coreMaxInvocations ) = coreContractInvocationData({ projectId: projectId, coreContract: coreContract }); // update storage with results MaxInvocationsProjectConfig storage maxInvocationsProjectConfig = getMaxInvocationsProjectConfig({ projectId: projectId, coreContract: coreContract }); // @dev only bugged core would return > 1e6 invocations, but safe-cast // for additional overflow safety maxInvocationsProjectConfig.maxInvocations = coreMaxInvocations .toUint24(); // We need to ensure maxHasBeenInvoked is correctly set after manually syncing the // local maxInvocations value with the core contract's maxInvocations value. maxInvocationsProjectConfig.maxHasBeenInvoked = coreInvocations == coreMaxInvocations; emit ProjectMaxInvocationsLimitUpdated({ projectId: projectId, coreContract: coreContract, maxInvocations: coreMaxInvocations }); } /** * @notice Manually limits project's max invocations. * @param projectId The id of the project. * @param coreContract The address of the core contract. * @param maxInvocations The new max invocations limit. */ function manuallyLimitProjectMaxInvocations( uint256 projectId, address coreContract, uint24 maxInvocations ) internal { // CHECKS ( uint256 coreInvocations, uint256 coreMaxInvocations ) = coreContractInvocationData({ projectId: projectId, coreContract: coreContract }); require( maxInvocations <= coreMaxInvocations, "Invalid max invocations" ); require(maxInvocations >= coreInvocations, "Invalid max invocations"); // EFFECTS MaxInvocationsProjectConfig storage maxInvocationsProjectConfig = getMaxInvocationsProjectConfig({ projectId: projectId, coreContract: coreContract }); // update storage with results maxInvocationsProjectConfig.maxInvocations = uint24(maxInvocations); // We need to ensure maxHasBeenInvoked is correctly set after manually setting the // local maxInvocations value. maxInvocationsProjectConfig.maxHasBeenInvoked = coreInvocations == maxInvocations; emit ProjectMaxInvocationsLimitUpdated({ projectId: projectId, coreContract: coreContract, maxInvocations: maxInvocations }); } /** * @notice Validate effects on invocations after purchase. This ensures * that the token invocation is less than or equal to the local max * invocations, and also updates the local maxHasBeenInvoked value. * @dev This function checks that the token invocation is less than or * equal to the local max invocations, and also updates the local * maxHasBeenInvoked value. * @param tokenId The id of the token. * @param coreContract The address of the core contract. */ function validateMintEffectsInvocations( uint256 tokenId, address coreContract ) internal { uint256 projectId = ABHelpers.tokenIdToProjectId(tokenId); MaxInvocationsProjectConfig storage maxInvocationsProjectConfig = getMaxInvocationsProjectConfig({ projectId: projectId, coreContract: coreContract }); // invocation is token number plus one, and will never overflow due to // limit of 1e6 invocations per project. uint256 tokenInvocation = ABHelpers.tokenIdToTokenInvocation(tokenId); uint256 localMaxInvocations = maxInvocationsProjectConfig .maxInvocations; // handle the case where the token invocation == minter local max // invocations occurred on a different minter, and we have a stale // local maxHasBeenInvoked value returning a false negative. // @dev this is a CHECK after EFFECTS, so security was considered // in detail here. require( tokenInvocation <= localMaxInvocations, "Max invocations reached" ); // in typical case, update the local maxHasBeenInvoked value // to true if the token invocation == minter local max invocations // (enables gas efficient reverts after sellout) if (tokenInvocation == localMaxInvocations) { maxInvocationsProjectConfig.maxHasBeenInvoked = true; } } /** * @notice Checks that the max invocations have not been reached for a * given project. This only checks the minter's local max invocations, and * does not consider the core contract's max invocations. * The function reverts if the max invocations have been reached. * @param projectId The id of the project. * @param coreContract The address of the core contract. */ function preMintChecks( uint256 projectId, address coreContract ) internal view { // check that max invocations have not been reached MaxInvocationsProjectConfig storage maxInvocationsProjectConfig = getMaxInvocationsProjectConfig({ projectId: projectId, coreContract: coreContract }); require( !maxInvocationsProjectConfig.maxHasBeenInvoked, "Max invocations reached" ); } /** * @notice Helper function to check if max invocations has not been initialized. * Returns true if not initialized, false if initialized. * @param projectId The id of the project. * @param coreContract The address of the core contract. * @dev We know a project's max invocations have never been initialized if * both max invocations and maxHasBeenInvoked are still initial values. * This is because if maxInvocations were ever set to zero, * maxHasBeenInvoked would be set to true. */ function maxInvocationsIsUnconfigured( uint256 projectId, address coreContract ) internal view returns (bool) { MaxInvocationsProjectConfig storage maxInvocationsProjectConfig = getMaxInvocationsProjectConfig({ projectId: projectId, coreContract: coreContract }); return maxInvocationsProjectConfig.maxInvocations == 0 && !maxInvocationsProjectConfig.maxHasBeenInvoked; } /** * @notice Function returns if invocations remain available for a given project. * This function calls the core contract to get the most up-to-date * invocation data (which may be useful to avoid reverts during mint). * This function considers core contract max invocations, and minter local * max invocations, and returns a response based on the most limiting * max invocations value. * @param projectId The id of the project. * @param coreContract The address of the core contract. */ function invocationsRemainOnCore( uint256 projectId, address coreContract ) internal view returns (bool) { return getInvocationsAvailable({ projectId: projectId, coreContract: coreContract }) != 0; } /** * @notice Pulls core contract invocation data for a given project. * @dev This function calls the core contract to get the invocation data * @param projectId The id of the project. * @param coreContract The address of the core contract. * @return coreInvocations The number of invocations for the project. * @return coreMaxInvocations The max invocations for the project, as * defined on the core contract. */ function coreContractInvocationData( uint256 projectId, address coreContract ) internal view returns (uint256 coreInvocations, uint256 coreMaxInvocations) { ( coreInvocations, coreMaxInvocations, , , , ) = IGenArt721CoreContractV3_Base(coreContract).projectStateData( projectId ); } /** * @notice Function returns the max invocations for a given project. * @param projectId The id of the project. * @param coreContract The address of the core contract. * to be queried. */ function getMaxInvocations( uint256 projectId, address coreContract ) internal view returns (uint256) { MaxInvocationsProjectConfig storage maxInvocationsProjectConfig = getMaxInvocationsProjectConfig({ projectId: projectId, coreContract: coreContract }); return maxInvocationsProjectConfig.maxInvocations; } /** * @notice Function returns if max has been invoked for a given project. * @param projectId The id of the project. * @param coreContract The address of the core contract. * to be queried. */ function getMaxHasBeenInvoked( uint256 projectId, address coreContract ) internal view returns (bool) { MaxInvocationsProjectConfig storage maxInvocationsProjectConfig = getMaxInvocationsProjectConfig({ projectId: projectId, coreContract: coreContract }); return maxInvocationsProjectConfig.maxHasBeenInvoked; } /** * @notice Function returns if a project has reached its max invocations. * Function is labelled as "safe" because it checks the core contract's * invocations and max invocations. If the local max invocations is greater * than the core contract's max invocations, it will defer to the core * contract's max invocations (since those are the limiting factor). * @param projectId The id of the project. * @param coreContract The address of the core contract. */ function projectMaxHasBeenInvokedSafe( uint256 projectId, address coreContract ) internal view returns (bool) { return getInvocationsAvailable({ projectId: projectId, coreContract: coreContract }) == 0; } /** * @notice Function returns the number of invocations available for a given * project. Function checks the core contract's invocations and minter's max * invocations, ensuring that the most limiting value is used, even if the * local minter max invocations is stale. * @param projectId The id of the project. * @param coreContract The address of the core contract. * @return Number of invocations available for the project. */ function getInvocationsAvailable( uint256 projectId, address coreContract ) internal view returns (uint256) { // get max invocations from core contract ( uint256 coreInvocations, uint256 coreMaxInvocations ) = coreContractInvocationData({ projectId: projectId, coreContract: coreContract }); MaxInvocationsProjectConfig storage maxInvocationsProjectConfig = getMaxInvocationsProjectConfig({ projectId: projectId, coreContract: coreContract }); uint256 limitingMaxInvocations = Math.min( coreMaxInvocations, maxInvocationsProjectConfig.maxInvocations // local max invocations ); // if core invocations are greater than the limiting max invocations, // return 0 since no invocations remain if (coreInvocations >= limitingMaxInvocations) { return 0; } // otherwise, return the number of invocations remaining // @dev will not undeflow due to previous check return limitingMaxInvocations - coreInvocations; } /** * @notice Refreshes max invocations to account for core contract max * invocations state, without imposing any additional restrictions on the * minter's max invocations state. * If minter max invocations have never been populated, this function will * populate them to equal the core contract's max invocations state (which * is the least restrictive state). * If minter max invocations have been populated, this function will ensure * the minter's max invocations are not greater than the core contract's * max invocations (which would be stale and illogical), and update the * minter's max invocations and maxHasBeenInvoked state to be consistent * with the core contract's max invocations. * If the minter max invocations have been populated and are not greater * than the core contract's max invocations, this function will do nothing, * since that is a valid state in which the minter has been configured to * be more restrictive than the core contract. * @dev assumes core contract's max invocations may only be reduced, which * is the case for all V3 core contracts * @param projectId The id of the project. * @param coreContract The address of the core contract. */ function refreshMaxInvocations( uint256 projectId, address coreContract ) internal { MaxInvocationsProjectConfig storage maxInvocationsProjectConfig = getMaxInvocationsProjectConfig({ projectId: projectId, coreContract: coreContract }); if (maxInvocationsIsUnconfigured(projectId, coreContract)) { // populate the minter max invocation state to equal the values on // the core contract (least restrictive state) syncProjectMaxInvocationsToCore({ projectId: projectId, coreContract: coreContract }); } else { // if local max invocations were already populated, validate the local state ( uint256 coreInvocations, uint256 coreMaxInvocations ) = coreContractInvocationData({ projectId: projectId, coreContract: coreContract }); uint256 localMaxInvocations = maxInvocationsProjectConfig .maxInvocations; if (localMaxInvocations > coreMaxInvocations) { // if local max invocations are greater than core max invocations, make // them equal since that is the least restrictive logical state // @dev this is only possible if the core contract's max invocations // have been reduced since the minter's max invocations were last // updated // set local max invocations to core contract's max invocations maxInvocationsProjectConfig.maxInvocations = uint24( coreMaxInvocations ); // update the minter's `maxHasBeenInvoked` state maxInvocationsProjectConfig .maxHasBeenInvoked = (coreMaxInvocations == coreInvocations); emit ProjectMaxInvocationsLimitUpdated({ projectId: projectId, coreContract: coreContract, maxInvocations: coreMaxInvocations }); } else if (coreInvocations >= localMaxInvocations) { // core invocations are greater than this minter's max // invocations, indicating that minting must have occurred on // another minter. update the minter's `maxHasBeenInvoked` to // true to prevent any false negatives on // `getMaxHasBeenInvoked' maxInvocationsProjectConfig.maxHasBeenInvoked = true; // @dev do not emit event, because we did not change the value // of minter-local max invocations } } } /** * @notice Loads the MaxInvocationsProjectConfig for a given project and core * contract. * @param projectId Project Id to get config for * @param coreContract Core contract address to get config for */ function getMaxInvocationsProjectConfig( uint256 projectId, address coreContract ) internal view returns (MaxInvocationsProjectConfig storage) { return s().maxInvocationsProjectConfigs[coreContract][projectId]; } /** * @notice Return the storage struct for reading and writing. This library * uses a diamond storage pattern when managing storage. * @return storageStruct The MaxInvocationsLibStorage struct. */ function s() internal pure returns (MaxInvocationsLibStorage storage storageStruct) { bytes32 position = MAX_INVOCATIONS_LIB_STORAGE_POSITION; assembly ("memory-safe") { storageStruct.slot := position } } }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; import {IMinterFilterV1} from "../../../interfaces/v0.8.x/IMinterFilterV1.sol"; import {BitMaps256} from "../BitMap.sol"; import {PackedBools} from "../PackedBools.sol"; import {ABHelpers} from "../ABHelpers.sol"; import {SplitFundsLib} from "./SplitFundsLib.sol"; import {MaxInvocationsLib} from "./MaxInvocationsLib.sol"; import {GenericMinterEventsLib} from "./GenericMinterEventsLib.sol"; import {IERC721} from "@openzeppelin-5.0/contracts/token/ERC721/IERC721.sol"; import {SafeCast} from "@openzeppelin-5.0/contracts/utils/math/SafeCast.sol"; import {Math} from "@openzeppelin-5.0/contracts/utils/math/Math.sol"; /** * @title Art Blocks Ranked Auction Minter (RAM) Library * @notice This library is designed for the Art Blocks platform. It includes * Structs and functions that help with ranked auction minters. * @author Art Blocks Inc. */ library RAMLib { using SafeCast for uint256; using BitMaps256 for uint256; using PackedBools for uint256; /** * @notice Minimum auction length, in seconds, was updated to be the * provided value. * @param minAuctionDurationSeconds Minimum auction length, in seconds */ event MinAuctionDurationSecondsUpdated(uint256 minAuctionDurationSeconds); /** * @notice Admin-controlled refund gas limit updated * @param refundGasLimit Gas limit to use when refunding the previous * highest bidder, prior to using fallback force-send to refund */ event MinterRefundGasLimitUpdated(uint24 refundGasLimit); /** * @notice Number of slots used by this RAM minter * @param numSlots Number of slots used by this RAM minter */ event NumSlotsUpdated(uint256 numSlots); /** * @notice RAM auction buffer time parameters updated * @param auctionBufferSeconds time period at end of auction when new bids * can affect auction end time, updated to be this many seconds after the * bid is placed. * @param maxAuctionExtraSeconds maximum amount of time that can be added * to the auction end time due to new bids. */ event AuctionBufferTimeParamsUpdated( uint256 auctionBufferSeconds, uint256 maxAuctionExtraSeconds ); /** * @notice Admin minting constraint configuration updated * @param coreContract Core contract address to update * @param adminMintingConstraint enum representing admin minting constraint imposed on this contract */ event ContractConfigUpdated( address indexed coreContract, AdminMintingConstraint adminMintingConstraint ); /** * @notice Auction parameters updated * @param projectId Project Id to update * @param coreContract Core contract address to update * @param timestampStart Auction start timestamp * @param timestampEnd Auction end timestamp * @param basePrice Auction base price * @param allowExtraTime Auction allows extra time * @param adminArtistOnlyMintPeriodIfSellout Auction admin-artist-only mint period if * sellout * @param numTokensInAuction Number of tokens in auction */ event AuctionConfigUpdated( uint256 indexed projectId, address indexed coreContract, uint256 timestampStart, uint256 timestampEnd, uint256 basePrice, bool allowExtraTime, bool adminArtistOnlyMintPeriodIfSellout, uint256 numTokensInAuction ); /** * @notice Number of tokens in auction updated * @dev okay to not index this event if prior to AuctionConfigUpdated, as * the state value will be emitted in another future event * @dev generic event not used due to additional indexing logic desired * @param projectId Project Id to update * @param coreContract Core contract address to update * @param numTokensInAuction Number of tokens in auction */ event NumTokensInAuctionUpdated( uint256 indexed projectId, address indexed coreContract, uint256 numTokensInAuction ); /** * @notice Auction timestamp end updated. Occurs when auction is extended * due to new bids near the end of an auction, when the auction is * configured to allow extra time. * Also may occur when an admin extends the auction within the emergency * extension time limit. * @dev generic event not used due to additional indexing logic desired * when event is encountered (want to understand what caused time * extension) * @param projectId Project Id to update * @param coreContract Core contract address to update * @param timestampEnd Auction end timestamp */ event AuctionTimestampEndUpdated( uint256 indexed projectId, address indexed coreContract, uint256 timestampEnd ); /** * @notice Bid created in auction * @param projectId Project Id to update * @param coreContract Core contract address to update * @param slotIndex Slot index of bid that was created * @param bidId Bid Id that was created * @param bidder Address of bidder */ event BidCreated( uint256 indexed projectId, address indexed coreContract, uint256 slotIndex, uint256 bidId, address bidder ); /** * @notice Bid removed from auction because it was outbid. * @param projectId Project Id to update * @param coreContract Core contract address to update * @param bidId Bid Id that was removed */ event BidRemoved( uint256 indexed projectId, address indexed coreContract, uint256 bidId ); /** * @notice Bid topped up in auction * @param projectId Project Id to update * @param coreContract Core contract address to update * @param bidId Bid Id that was topped up * @param newSlotIndex New slot index of bid that was topped up */ event BidToppedUp( uint256 indexed projectId, address indexed coreContract, uint256 bidId, uint256 newSlotIndex ); /** * @notice Bid was settled, and any payment above the lowest winning bid, * or base price if not a sellout, was refunded to the bidder. * @param projectId Project Id to update * @param coreContract Core contract address to update * @param bidId ID of bid that was settled */ event BidSettled( uint256 indexed projectId, address indexed coreContract, uint256 bidId ); /** * @notice A token was minted to the bidder for bid `bidId`. The tokenId is * the token that was minted. * @param projectId Project Id to update * @param coreContract Core contract address to update * @param bidId ID of bid that was settled * @param tokenId Token Id that was minted * */ event BidMinted( uint256 indexed projectId, address indexed coreContract, uint256 bidId, uint256 tokenId ); /** * @notice Bid was refunded, and the entire bid value was sent to the * bidder. * This only occurs if the minter encountered an unexpected error state * due to operational issues, and the minter was unable to mint a token to * the bidder. * @param projectId Project Id to update * @param coreContract Core contract address to update * @param bidId ID of bid that was settled */ event BidRefunded( uint256 indexed projectId, address indexed coreContract, uint256 bidId ); /** * @notice Token was directly purchased after an auction ended, and the * token was minted to the buyer. * @param projectId Project Id to update * @param coreContract Core contract address to update * @param tokenId Token Id that was minted * @param to Address that the token was minted to */ event TokenPurchased( uint256 indexed projectId, address indexed coreContract, uint256 tokenId, address to ); // position of RAM Lib storage, using a diamond storage pattern // for this library bytes32 constant RAM_LIB_STORAGE_POSITION = keccak256("ramlib.storage"); // generic event key constants bytes32 internal constant CONFIG_AUCTION_REVENUES_COLLECTED = "auctionRevenuesCollected"; bytes32 internal constant CONFIG_TIMESTAMP_END = "timestampEnd"; uint256 constant NUM_SLOTS = 512; // pricing assumes maxPrice = minPrice * 2^8, pseudo-exponential curve uint256 constant SLOTS_PER_PRICE_DOUBLE = NUM_SLOTS / 8; // 64 slots per double // auction extension time constants uint256 constant AUCTION_BUFFER_SECONDS = 5 minutes; uint256 constant MAX_AUCTION_EXTRA_SECONDS = 1 hours; // @dev store value in hours to improve storage packing uint256 constant MAX_AUCTION_ADMIN_EMERGENCY_EXTENSION_HOURS = 72; // 72 hours uint256 constant ADMIN_ARTIST_ONLY_MINT_TIME_SECONDS = 72 hours; // packed bools constants for Bid struct uint8 constant INDEX_IS_SETTLED = 0; uint8 constant INDEX_IS_MINTED = 1; uint8 constant INDEX_IS_REFUNDED = 2; enum ProjectMinterStates { PreAuction, // Pre-Auction, State A LiveAuction, // Live-Auction, State B PostAuctionSellOutAdminArtistMint, // Post-Auction, sell out, not all bids handled, admin-artist-only mint period, State C PostAuctionOpenMint, // Post-Auction, not all bids handled, post-admin-artist-only mint period, State D PostAuctionAllBidsHandled // Post-Auction, all bids handled, State E } // project-specific parameters struct RAMProjectConfig { // mapping of all bids by Bid ID mapping(uint256 bidId => Bid) bids; // doubly linked list of bids for each slot mapping(uint256 slot => uint256 headBidId) headBidIdBySlot; mapping(uint256 slot => uint256 tailBidId) tailBidIdBySlot; // --- slot metadata for efficiency --- // two bitmaps with index set only if one or more active bids exist for // the corresponding slot. The first bitmap (A) is for slots 0-255, the // second bitmap (B) is for slots 256-511. uint256 slotsBitmapA; uint256 slotsBitmapB; // minimum bitmap index with an active bid // @dev set to 512 if no active bids // @dev max uint16 >> max possible value of 512 uint16 minBidSlotIndex; // maximum bitmap index with an active bid // @dev set to 0 if no active bids uint16 maxBidSlotIndex; // --- bid auto-minting tracking --- uint32 latestMintedBidId; // --- error state bid auto-refund tracking --- uint32 latestRefundedBidId; // --- next bid ID --- // nonce for generating new bid IDs on this project // @dev allows for gt 4 billion bids, and max possible bids for a // 1M token project is 1M * 512 slots = 512M bids < 4B max uint32 uint32 nextBidId; // --- auction parameters --- // number of tokens and related values // @dev max uint24 is 16,777,215 > 1_000_000 max project size uint24 numTokensInAuction; uint24 numBids; uint24 numBidsMintedTokens; uint24 numBidsErrorRefunded; // timing // @dev max uint40 ~= 1.1e12 sec ~= 34 thousand years uint40 timestampStart; // @dev timestampOriginalEnd & timestampEnd are the same if not in extra time uint40 timestampOriginalEnd; uint40 timestampEnd; // @dev max uint8 ~= 256 hours, which is gt max auction extension time of 72 hours uint8 adminEmergencyExtensionHoursApplied; bool allowExtraTime; bool adminArtistOnlyMintPeriodIfSellout; // pricing // @dev max uint88 ~= 3e26 Wei = ~300 million ETH, which is well above // the expected prices of any NFT mint in the foreseeable future. uint88 basePrice; // -- redundant backstops -- // Track per-project fund balance, in wei. This is used as a redundant // backstop to prevent one project from draining the minter's balance // of ETH from other projects, which is a worthwhile failsafe on this // shared minter. // @dev max uint120 > max basPrice * 256 * 1_000_000 // @dev while uint88 is gt max ETH supply, use uin120 to prevent reliance on // max token supply uint120 projectBalance; // --- revenue collection state --- bool revenuesCollected; } struct Bid { uint32 prevBidId; uint32 nextBidId; uint16 slotIndex; address bidder; // three bool values packed into a single uint8 // index 0 - isSettled (INDEX_IS_SETTLED) // index 1 - isMinted (INDEX_IS_MINTED) // index 2 - isRefunded (INDEX_IS_REFUNDED) uint8 packedBools; } // contract-specific parameters enum AdminMintingConstraint { None, AdminArtistOnlyMintPeriod, NoAdminArtistOnlyMintPeriod } // Diamond storage pattern is used in this library struct RAMLibStorage { mapping(address coreContract => mapping(uint256 projectId => RAMProjectConfig)) RAMProjectConfigs; mapping(address => AdminMintingConstraint) RAMAdminMintingConstraint; } /** * @notice Update a contract's requirements on if a post-auction * admin-artist-only mint period is required or not, for and-on * configured projects. * @param coreContract The address of the core contract being configured * @param adminMintingConstraint The AdminMintingConstraint setting for the contract */ function setContractConfig( address coreContract, AdminMintingConstraint adminMintingConstraint ) internal { // set the contract admin minting constraint with the new constraint enum value s().RAMAdminMintingConstraint[coreContract] = adminMintingConstraint; // emit event emit ContractConfigUpdated({ coreContract: coreContract, adminMintingConstraint: adminMintingConstraint }); } /** * @notice Function to add emergency auction hours to auction of * project `projectId` on core contract `coreContract`. * Protects against unexpected frontend downtime, etc. * Reverts if called by anyone other than a contract admin. * Reverts if project is not in a Live Auction. * Reverts if auction is already in extra time. * Reverts if adding more than the maximum number of emergency hours. * @param projectId Project ID to add emergency auction hours to. * @param coreContract Core contract address for the given project. * @param emergencyHoursToAdd Number of emergency hours to add to the * project's auction. */ function adminAddEmergencyAuctionHours( uint256 projectId, address coreContract, uint8 emergencyHoursToAdd ) internal { // load project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // CHECKS // require auction in state B (Live Auction) require( getProjectMinterState(projectId, coreContract) == ProjectMinterStates.LiveAuction, "Only live auction" ); // require auction has not reached extra time require( RAMProjectConfig_.timestampOriginalEnd == RAMProjectConfig_.timestampEnd, "Not allowed in extra time" ); // require auction is not being extended beyond limit uint8 newAdminEmergencyExtensionHours = RAMProjectConfig_ .adminEmergencyExtensionHoursApplied + emergencyHoursToAdd; require( newAdminEmergencyExtensionHours <= MAX_AUCTION_ADMIN_EMERGENCY_EXTENSION_HOURS, "Only emergency hours lt max" ); // calculate auction end time // @dev overflow automatically checked in solidity 0.8 uint40 newTimestampEnd = RAMProjectConfig_.timestampEnd + emergencyHoursToAdd * 1 hours; // EFFECTS // update emergency hours applied // @dev overflow automatically checked in solidity 0.8 RAMProjectConfig_ .adminEmergencyExtensionHoursApplied = newAdminEmergencyExtensionHours; // update auction end time // @dev update both original end timestamp and current end timestamp // because this is not extra time, but rather an emergency extension RAMProjectConfig_.timestampEnd = newTimestampEnd; RAMProjectConfig_.timestampOriginalEnd = newTimestampEnd; // emit event emit AuctionTimestampEndUpdated({ projectId: projectId, coreContract: coreContract, timestampEnd: newTimestampEnd }); } /** * @notice Function to set auction details on project `projectId` on core contract `coreContract`. * Reverts if not currently in ProjectMinterState A. * Reverts if base price does not meet the minimum. * Reverts if not for future auction. * Reverts if end time not greater than start time. * Reverts if adminArtistOnlyMintPeriodIfSellout disagrees with the admin configured constraint. * @param projectId Project ID to add emergency auction hours to. * @param coreContract Core contract address for the given project. * @param auctionTimestampStart New timestamp at which to start the auction. * @param auctionTimestampEnd New timestamp at which to end the auction. * @param basePrice Base price (or reserve price) of the auction, in Wei * @param allowExtraTime Auction allows extra time * @param adminArtistOnlyMintPeriodIfSellout Auction admin-artist-only mint period if * sellout */ function setAuctionDetails( uint256 projectId, address coreContract, uint40 auctionTimestampStart, uint40 auctionTimestampEnd, uint88 basePrice, bool allowExtraTime, bool adminArtistOnlyMintPeriodIfSellout ) internal { // load project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // CHECKS // require ProjectMinterState Pre-auction (State A) require( getProjectMinterState({ projectId: projectId, coreContract: coreContract }) == ProjectMinterStates.PreAuction, "Only pre-auction" ); // require base price >= 0.05 ETH require(basePrice >= 0.05 ether, "Only base price gte 0.05 ETH"); // only future start time require( auctionTimestampStart > block.timestamp, "Only future auctions" ); // enforce contract-level constraints set by contract admin AdminMintingConstraint RAMAdminMintingConstraint_ = getRAMAdminMintingConstraintValue({ coreContract: coreContract }); if ( RAMAdminMintingConstraint_ == AdminMintingConstraint.AdminArtistOnlyMintPeriod ) { require( adminArtistOnlyMintPeriodIfSellout, "Only admin-artist mint period" ); } else if ( RAMAdminMintingConstraint_ == AdminMintingConstraint.NoAdminArtistOnlyMintPeriod ) { require( !adminArtistOnlyMintPeriodIfSellout, "Only no admin-artist mint period" ); } // refresh max invocations to eliminate any stale state MaxInvocationsLib.refreshMaxInvocations({ projectId: projectId, coreContract: coreContract }); // set auction details RAMProjectConfig_.timestampStart = auctionTimestampStart; RAMProjectConfig_.timestampEnd = auctionTimestampEnd; RAMProjectConfig_.timestampOriginalEnd = auctionTimestampEnd; RAMProjectConfig_.basePrice = basePrice; RAMProjectConfig_.allowExtraTime = allowExtraTime; RAMProjectConfig_ .adminArtistOnlyMintPeriodIfSellout = adminArtistOnlyMintPeriodIfSellout; // refresh numTokensInAuction uint256 numTokensInAuction = refreshNumTokensInAuction({ projectId: projectId, coreContract: coreContract }); // initialize min slot metadata to NUM_SLOTS (an invalid index) to represent NULL value RAMProjectConfig_.minBidSlotIndex = uint16(NUM_SLOTS); // emit state change event emit AuctionConfigUpdated({ projectId: projectId, coreContract: coreContract, timestampStart: auctionTimestampStart, timestampEnd: auctionTimestampEnd, basePrice: basePrice, allowExtraTime: allowExtraTime, adminArtistOnlyMintPeriodIfSellout: adminArtistOnlyMintPeriodIfSellout, numTokensInAuction: numTokensInAuction }); } /** * @notice Reduces the auction length for project `projectId` on core * contract `coreContract` to `auctionTimestampEnd`. * Only allowed to be called during a live auction, and protects against * the case of an accidental excessively long auction, which locks funds. * Reverts if called by anyone other than the project's artist. * Reverts if project is not in a Live Auction. * Reverts if auction is not being reduced in length. * Reverts if in extra time. * Reverts if `auctionTimestampEnd` results in auction that is not at least * `minimumAuctionDurationSeconds` in duration. * Reverts if admin previously applied a time extension. * @param projectId Project ID to reduce the auction length for. * @param coreContract Core contract address for the given project. * @param auctionTimestampEnd New timestamp at which to end the auction. * @param minimumAuctionDurationSeconds Minimum auction duration, in seconds */ function reduceAuctionLength( uint256 projectId, address coreContract, uint40 auctionTimestampEnd, uint256 minimumAuctionDurationSeconds ) internal { // load project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // CHECKS // require auction state B, live auction require( getProjectMinterState(projectId, coreContract) == ProjectMinterStates.LiveAuction, "Only live auction" ); // require no previous admin extension time require( RAMProjectConfig_.adminEmergencyExtensionHoursApplied == 0, "No previous admin extension" ); // require not in extra time require( RAMProjectConfig_.timestampOriginalEnd == RAMProjectConfig_.timestampEnd, "Not allowed in extra time" ); // require reduction in auction length require( auctionTimestampEnd < RAMProjectConfig_.timestampEnd, "Only reduce auction length" ); // require meet minimum auction length requirement require( auctionTimestampEnd > RAMProjectConfig_.timestampStart + minimumAuctionDurationSeconds, "Auction too short" ); // require new end time in future require(auctionTimestampEnd > block.timestamp, "Only future end time"); // set auction details RAMProjectConfig_.timestampEnd = auctionTimestampEnd; // also update original end for accurate extra time calculation RAMProjectConfig_.timestampOriginalEnd = auctionTimestampEnd; // emit state change event emit AuctionTimestampEndUpdated({ projectId: projectId, coreContract: coreContract, timestampEnd: auctionTimestampEnd }); } /** * @notice Update the number of tokens in the auction, based on the state * of the core contract and the minter-local max invocations. * @param projectId Project ID to update * @param coreContract Core contract address to update */ function refreshNumTokensInAuction( uint256 projectId, address coreContract ) internal returns (uint256 numTokensInAuction) { // load project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // @dev safe to cast - max uint24 is 16_777_215 > 1_000_000 max project size numTokensInAuction = MaxInvocationsLib.getInvocationsAvailable({ projectId: projectId, coreContract: coreContract }); RAMProjectConfig_.numTokensInAuction = uint24(numTokensInAuction); // emit event for state change emit NumTokensInAuctionUpdated({ projectId: projectId, coreContract: coreContract, numTokensInAuction: numTokensInAuction }); } /** * @notice Collects settlement for project `projectId` on core contract * `coreContract` for all bids in `bidIds`. * Reverts if project is not in a post-auction state. * Reverts if bidder is not the bidder for all bids. * Reverts if one or more bids has already been settled. * Reverts if invalid bid is found. * @param projectId Project ID of bid to collect settlement for * @param coreContract Core contract address for the given project. * @param bidIds IDs of bids to collect settlements for * @param bidder Bidder address of bid to collect settlements for * @param minterRefundGasLimit Gas limit to use when refunding the bidder. */ function collectSettlements( uint256 projectId, address coreContract, uint32[] calldata bidIds, address bidder, uint256 minterRefundGasLimit ) internal { // load project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // CHECKS // @dev block scope to avoid stack too deep error { // require project minter state C or D (Post-Auction, Open Mint or Admin-Artist Mint Period) ProjectMinterStates projectMinterState = getProjectMinterState({ projectId: projectId, coreContract: coreContract }); require( projectMinterState == ProjectMinterStates.PostAuctionSellOutAdminArtistMint || projectMinterState == ProjectMinterStates.PostAuctionOpenMint, "Only state C or D" ); } // get project price uint256 projectPrice = _getProjectPrice({ RAMProjectConfig_: RAMProjectConfig_ }); // settle each input bid // @dev already verified that input lengths match uint256 inputBidsLength = bidIds.length; // @dev overflow check optimization as of 0.8.22 for (uint256 i = 0; i < inputBidsLength; ++i) { // settle the bid _settleBidWithChecks({ RAMProjectConfig_: RAMProjectConfig_, projectId: projectId, coreContract: coreContract, projectPrice: projectPrice, bidId: bidIds[i], bidder: bidder, minterRefundGasLimit: minterRefundGasLimit }); } } /** * @notice Directly mint tokens to winners of project `projectId` on core * contract `coreContract`. * Does not guarantee an optimal ordering or handling of E1 state like * `adminArtistAutoMintTokensToWinners` does while in State C. * Skips over bids that have already been minted or refunded (front-running * protection) * Reverts if project is not in a post-auction state, * post-admin-artist-only mint period (i.e. State D), with tokens available * Reverts if bid does not exist at bidId. * Reverts if msg.sender is not the bidder for all bids if * requireSenderIsBidder is true. * @param projectId Project ID to mint tokens on. * @param coreContract Core contract address for the given project. * @param bidIds IDs of bids to mint tokens for * @param requireSenderIsBidder bool representing if the sender must be the * bidder for all bids * @param minterFilter Minter filter to use when minting tokens * @param minterRefundGasLimit Gas limit to use when refunding the bidder. */ function directMintTokensToWinners( uint256 projectId, address coreContract, uint32[] calldata bidIds, bool requireSenderIsBidder, IMinterFilterV1 minterFilter, uint256 minterRefundGasLimit ) internal { // load project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // get project price uint256 projectPrice = _getProjectPrice({ RAMProjectConfig_: RAMProjectConfig_ }); // CHECKS // @dev memoize length for gas efficiency uint256 bidIdsLength = bidIds.length; // @dev block scope to limit stack depth { // require project minter state D (Post-Auction, // post-admin-artist-only, not all bids handled) ProjectMinterStates projectMinterState = getProjectMinterState({ projectId: projectId, coreContract: coreContract }); require( projectMinterState == ProjectMinterStates.PostAuctionOpenMint, "Only post-auction open mint" ); // require numTokensToMint does not exceed number of tokens // owed. // @dev must check this here to avoid minting more tokens than max // invocations, which could potentially not revert if minter // max invocations was limiting (+other unexpected conditions) require( bidIdsLength <= _getNumTokensOwed({RAMProjectConfig_: RAMProjectConfig_}), "tokens to mint gt tokens owed" ); } // main loop to mint tokens for (uint256 i; i < bidIdsLength; ++i) { // @dev current slot index and bid index in slot not memoized due // to stack depth limitations // get bid uint256 currentBidId = bidIds[i]; Bid storage bid = RAMProjectConfig_.bids[currentBidId]; address bidderAddress = bid.bidder; // CHECKS // require bid exists require(bidderAddress != address(0), "invalid Bid ID"); // if bid is already minted or refunded, skip to next bid // @dev do not revert, since this could be due to front-running if ( _getBidPackedBool(bid, INDEX_IS_MINTED) || _getBidPackedBool(bid, INDEX_IS_REFUNDED) ) { continue; } // require sender is bidder if requireSenderIsBidder is true if (requireSenderIsBidder) { require(msg.sender == bidderAddress, "Only sender is bidder"); } // EFFECTS // @dev num bids minted tokens not memoized due to stack depth // limitations RAMProjectConfig_.numBidsMintedTokens++; // Mint bid and settle if not already settled _mintAndSettle({ projectId: projectId, coreContract: coreContract, projectPrice: projectPrice, slotIndex: bid.slotIndex, bidId: currentBidId, minterFilter: minterFilter, minterRefundGasLimit: minterRefundGasLimit }); } } /** * @notice Function that enables a contract admin or artist (checked by * external function) to mint tokens to winners of project `projectId` on * core contract `coreContract`. * Automatically mints tokens to most-winning bids, in order from highest * and earliest bid to lowest and latest bid. * Settles bids as tokens are minted, if not already settled. * Reverts if project is not in a post-auction state, admin-artist-only mint * period (i.e. State C), with tokens available. * to be minted. * Reverts if number of tokens to mint is greater than the number of * tokens available to be minted. * @param projectId Project ID to mint tokens on. * @param coreContract Core contract address for the given project. * @param numTokensToMint Number of tokens to mint in this transaction. * @param minterFilter Minter filter contract address * @param minterRefundGasLimit Gas limit to use when settling bid if not already settled */ function adminArtistAutoMintTokensToWinners( uint256 projectId, address coreContract, uint24 numTokensToMint, IMinterFilterV1 minterFilter, uint256 minterRefundGasLimit ) internal { // load project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // get project price uint256 projectPrice = _getProjectPrice({ RAMProjectConfig_: RAMProjectConfig_ }); // CHECKS // @dev block scope to limit stack depth { // require project minter state C (Post-Auction, sell out, admin-artist-only, // not all bids handled) ProjectMinterStates projectMinterState = getProjectMinterState({ projectId: projectId, coreContract: coreContract }); require( projectMinterState == ProjectMinterStates.PostAuctionSellOutAdminArtistMint, "Only state C" ); // require numTokensToMint does not exceed number of tokens // owed // @dev must check this here to avoid minting more tokens than max // invocations, which could potentially not revert if minter // max invocations was limiting (+other unexpected conditions) require( numTokensToMint <= _getNumTokensOwed({RAMProjectConfig_: RAMProjectConfig_}), "tokens to mint gt tokens owed" ); } // EFFECTS // load values to memory for gas efficiency uint256 currentLatestMintedBidId = RAMProjectConfig_.latestMintedBidId; // @dev will be zero if no bids minted yet uint256 currentLatestMintedBidSlotIndex = RAMProjectConfig_ .bids[currentLatestMintedBidId] .slotIndex; uint256 numNewTokensMinted; // = 0 // main loop to mint tokens while (numNewTokensMinted < numTokensToMint) { // EFFECTS // STEP 1: scroll to next bid to be minted a token // set latest minted bid indices to the bid to be minted a token if (currentLatestMintedBidId == 0) { // first mint, so need to initialize cursor values // set bid to highest bid in the project, head of max bid slot currentLatestMintedBidSlotIndex = RAMProjectConfig_ .maxBidSlotIndex; currentLatestMintedBidId = RAMProjectConfig_.headBidIdBySlot[ currentLatestMintedBidSlotIndex ]; } else { // scroll to next bid in current slot // @dev scrolling to null is okay and handled below currentLatestMintedBidId = RAMProjectConfig_ .bids[currentLatestMintedBidId] .nextBidId; // if scrolled off end of list, then find next slot with bids if (currentLatestMintedBidId == 0) { // past tail of current slot's linked list, so need to find next // bid slot with bids currentLatestMintedBidSlotIndex = _getMaxSlotWithBid({ RAMProjectConfig_: RAMProjectConfig_, startSlotIndex: uint16( currentLatestMintedBidSlotIndex - 1 ) }); // @dev no coverage on else branch because it is unreachable as used require( currentLatestMintedBidSlotIndex < NUM_SLOTS, "slot with bid not found" ); // current bid is now the head of the linked list currentLatestMintedBidId = RAMProjectConfig_ .headBidIdBySlot[currentLatestMintedBidSlotIndex]; } } // @dev minter is in State C, so bid must not have been minted or // refunded due to scrolling logic of admin mint and refund // functions available for use while in State C. The bid may have // been previously settled, however. // Mint bid and settle if not already settled // @dev scrolling logic in State C ensures bid **exists** is not yet minted _mintAndSettle({ projectId: projectId, coreContract: coreContract, projectPrice: projectPrice, slotIndex: currentLatestMintedBidSlotIndex, bidId: currentLatestMintedBidId, minterFilter: minterFilter, minterRefundGasLimit: minterRefundGasLimit }); // increment num new tokens minted unchecked { ++numNewTokensMinted; } } // finally, update auction metadata storage state from memoized values // @dev safe to cast numNewTokensMinted to uint24 RAMProjectConfig_.numBidsMintedTokens += uint24(numNewTokensMinted); // @dev safe to cast to uint32 because directly derived from bid ID RAMProjectConfig_.latestMintedBidId = uint32(currentLatestMintedBidId); } /** * @notice Directly refund bids for project `projectId` on core contract * `coreContract` to resolve error state E1. * Does not guarantee an optimal ordering or handling of E1 state like * `autoRefundBidsToResolveE1` does while in State C. * Skips over bids that have already been minted or refunded (front-running * protection) * Reverts if project is not in post-auction state, * post-admin-artist-only mint period (i.e. State D). * Reverts if project is not in error state E1. * Reverts if length of bids to refund exceeds the number of bids that need * to be refunded to resolve the error state E1. * Reverts if bid does not exist at bidId. * Reverts if msg.sender is not the bidder for all bids if * requireSenderIsBidder is true. * @param projectId Project ID to refunds bids for. * @param coreContract Core contract address for the given project. * @param bidIds IDs of bids to refund bid values for * @param requireSenderIsBidder Require sender is bidder for all bids * @param minterRefundGasLimit Gas limit to use when refunding the bidder. */ function directRefundBidsToResolveE1( uint256 projectId, address coreContract, uint32[] calldata bidIds, bool requireSenderIsBidder, uint256 minterRefundGasLimit ) internal { // CHECKS // @dev memoize length for gas efficiency uint256 bidIdsLength = bidIds.length; // @dev block scope to limit stack depth { // require project minter state D (Post-Auction, post-admin-artist-only, // not all bids handled) ProjectMinterStates projectMinterState = getProjectMinterState({ projectId: projectId, coreContract: coreContract }); require( projectMinterState == ProjectMinterStates.PostAuctionOpenMint, "Only post-auction open mint" ); // require is in state E1 (bool isErrorE1_, uint256 numBidsToResolveE1, ) = isErrorE1FlagF1({ projectId: projectId, coreContract: coreContract }); require(isErrorE1_, "Only in state E1"); // require numBidsToRefund does not exceed max number of bids // to resolve E1 error state require( bidIdsLength <= numBidsToResolveE1, "bids to refund gt available qty" ); } // load project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // get project price uint256 projectPrice = _getProjectPrice({ RAMProjectConfig_: RAMProjectConfig_ }); // @dev memoize for gas efficiency uint24 numRefundsIssued = 0; // main loop to refund tokens for (uint256 i; i < bidIdsLength; ++i) { // @dev current slot index and bid index in slot not memoized due // to stack depth limitations // get bid uint256 currentBidId = bidIds[i]; Bid storage bid = RAMProjectConfig_.bids[currentBidId]; // CHECKS // require bidder is non-zero address (i.e. bid exists) address bidderAddress = bid.bidder; require(bidderAddress != address(0), "invalid Bid ID"); // if bid is already minted or refunded, skip to next bid // @dev do not revert, since this could be due to front-running if ( _getBidPackedBool(bid, INDEX_IS_MINTED) || _getBidPackedBool(bid, INDEX_IS_REFUNDED) ) { continue; } // require sender is bidder if requireSenderIsBidder is true if (requireSenderIsBidder) { require(msg.sender == bidderAddress, "Only sender is bidder"); } // EFFECTS // Settle and Refund the Bid _settleAndRefundBid({ projectId: projectId, coreContract: coreContract, projectPrice: projectPrice, slotIndex: bid.slotIndex, bidId: currentBidId, minterRefundGasLimit: minterRefundGasLimit }); numRefundsIssued++; } // update number of bids refunded RAMProjectConfig_.numBidsErrorRefunded += numRefundsIssued; } /** * @notice Function to automatically refund the lowest winning bids for * project `projectId` on core contract `coreContract` to resolve error * state E1. * Reverts if project is not in post-auction state C. * Reverts if project is not in error state E1. * Reverts if numBidsToRefund exceeds the number of bids that need to be * refunded to resolve the error state E1. * @dev Recommend admin-only not for security, but rather to enable Admin * to be aware that an error state has been encountered while in post- * auction state C. * @param projectId Project ID to refunds bids for. * @param coreContract Core contract address for the given project. * @param numBidsToRefund Number of bids to refund in this call. * @param minterRefundGasLimit Gas limit to use when refunding the bidder. */ function autoRefundBidsToResolveE1( uint256 projectId, address coreContract, uint24 numBidsToRefund, uint256 minterRefundGasLimit ) internal { // CHECKS // @dev block scope to limit stack depth { // require project minter state C (Post-Auction, admin-artist-only, // not all bids handled) ProjectMinterStates projectMinterState = getProjectMinterState({ projectId: projectId, coreContract: coreContract }); require( projectMinterState == ProjectMinterStates.PostAuctionSellOutAdminArtistMint, "Only state C" ); // require is in state E1 (bool isErrorE1_, uint256 numBidsToResolveE1, ) = isErrorE1FlagF1({ projectId: projectId, coreContract: coreContract }); require(isErrorE1_, "Only in state E1"); // require numBidsToRefund does not exceed max number of bids // to resolve E1 error state require( numBidsToRefund <= numBidsToResolveE1, "bids to refund gt available qty" ); } // load project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // get project price uint256 projectPrice = _getProjectPrice({ RAMProjectConfig_: RAMProjectConfig_ }); // EFFECTS // load values to memory for gas efficiency uint256 currentLatestRefundedBidId = RAMProjectConfig_ .latestRefundedBidId; uint256 currentLatestRefundedBidSlotIndex = RAMProjectConfig_ .bids[currentLatestRefundedBidId] .slotIndex; // settlement values uint256 numRefundsIssued; // = 0 // main loop to refund bids while (numRefundsIssued < numBidsToRefund) { // EFFECTS // STEP 1: Get next bid to be refunded // set latest refunded bid indices to the bid to be refunded if (currentLatestRefundedBidId == 0) { // first refund, so need to initialize cursor values // set bid to lowest bid in the project, tail of min bid slot currentLatestRefundedBidSlotIndex = RAMProjectConfig_ .minBidSlotIndex; currentLatestRefundedBidId = RAMProjectConfig_.tailBidIdBySlot[ currentLatestRefundedBidSlotIndex ]; } else { // scroll to previous bid in current slot // @dev scrolling to null is okay and handled below currentLatestRefundedBidId = RAMProjectConfig_ .bids[currentLatestRefundedBidId] .prevBidId; } // if scrolled off end of list, then find next slot with bids if (currentLatestRefundedBidId == 0) { // past head of current slot's linked list, so need to find next // bid slot with bids // @dev not possible to not find next slot during auto-refund, // so no need to handle case where slot not found currentLatestRefundedBidSlotIndex = _getMinSlotWithBid({ RAMProjectConfig_: RAMProjectConfig_, startSlotIndex: uint16( currentLatestRefundedBidSlotIndex + 1 ) }); // current bid is now the tail of the linked list currentLatestRefundedBidId = RAMProjectConfig_.tailBidIdBySlot[ currentLatestRefundedBidSlotIndex ]; } // @dev minter is in State C, so bid must not have been minted or // refunded due to scrolling logic of admin mint and refund // functions available for use while in State C. The bid may have // been previously settled, however. // Settle & Refund the Bid _settleAndRefundBid({ projectId: projectId, coreContract: coreContract, projectPrice: projectPrice, slotIndex: uint16(currentLatestRefundedBidSlotIndex), bidId: currentLatestRefundedBidId, minterRefundGasLimit: minterRefundGasLimit }); // increment loop counter and current num bids refunded unchecked { ++numRefundsIssued; } } // finally, update auction metadata storage state from memoized values // @dev safe to cast currentNumBidsErrorRefunded to uint24 RAMProjectConfig_.numBidsErrorRefunded += uint24(numRefundsIssued); // @dev safe to cast to uint32 because directly derived from bid ID RAMProjectConfig_.latestRefundedBidId = uint32( currentLatestRefundedBidId ); } /** * @notice This withdraws project revenues for project `projectId` on core * contract `coreContract` to the artist and admin, only after all bids * have been minted+settled or refunded. * Note that the conditions described are the equivalent of project minter * State E. * @param projectId Project ID to withdraw revenues for. * @param coreContract Core contract address for the given project. */ function withdrawArtistAndAdminRevenues( uint256 projectId, address coreContract ) internal { // load project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // CHECKS // require project minter state E (Post-Auction, all bids handled) ProjectMinterStates projectMinterState = getProjectMinterState({ projectId: projectId, coreContract: coreContract }); require( projectMinterState == ProjectMinterStates.PostAuctionAllBidsHandled, "Only state E" ); // require revenues not already withdrawn require( !(RAMProjectConfig_.revenuesCollected), "Revenues already withdrawn" ); // EFFECTS // update state to indicate revenues withdrawn RAMProjectConfig_.revenuesCollected = true; // get project price uint256 projectPrice = _getProjectPrice({ RAMProjectConfig_: RAMProjectConfig_ }); // get netRevenues // @dev refunded bids do not count towards amount due because they // did not generate revenue uint256 netRevenues = projectPrice * RAMProjectConfig_.numBidsMintedTokens; // update project balance // @dev reverts on underflow RAMProjectConfig_.projectBalance -= uint120(netRevenues); // INTERACTIONS SplitFundsLib.splitRevenuesETHNoRefund({ projectId: projectId, valueInWei: netRevenues, coreContract: coreContract }); emit GenericMinterEventsLib.ConfigValueSet({ projectId: projectId, coreContract: coreContract, key: CONFIG_AUCTION_REVENUES_COLLECTED, value: true }); } /** * @notice Function to mint tokens if an auction is over, but did not sell * out and tokens are still available to be minted. * @dev must be called within non-reentrant context * @param to Address to be the new token's owner. * @param projectId Project ID to mint a token on. * @param coreContract Core contract address for the given project. * @param minterFilter Minter filter to use when minting token. * @return tokenId Token ID of minted token */ function purchaseTo( address to, uint256 projectId, address coreContract, IMinterFilterV1 minterFilter ) internal returns (uint256 tokenId) { // load project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // CHECKS // @dev block scope to limit stack depth { // require project minter state D, or E (Post-Auction) ProjectMinterStates projectMinterState = getProjectMinterState({ projectId: projectId, coreContract: coreContract }); require( projectMinterState == ProjectMinterStates.PostAuctionOpenMint || projectMinterState == ProjectMinterStates.PostAuctionAllBidsHandled, "Only state D or E" ); // require Flag F1, i.e. at least one excess token available to be // minted // @dev this ensures minter and core contract max-invocations // constraints are not violated, as well as confirms that one // additional mint will not send the minter into an E1 state (, , uint256 numExcessInvocationsAvailable) = isErrorE1FlagF1({ projectId: projectId, coreContract: coreContract }); require( numExcessInvocationsAvailable > 0, "Reached max invocations" ); } // require sufficient payment // since excess invocations are available, know not a sellout, so // project price is base price uint256 pricePerTokenInWei = RAMProjectConfig_.basePrice; require( msg.value == pricePerTokenInWei, "Only send auction reserve price" ); // EFFECTS // mint token tokenId = minterFilter.mint_joo({ to: to, projectId: projectId, coreContract: coreContract, sender: msg.sender }); // @dev this minter specifically does not update max invocations has // been reached, since it must consider unminted bids when determining // if max invocations has been reached // INTERACTIONS // split revenue from sale // @dev no refund because previously verified msg.value == pricePerTokenInWei // @dev no effect on project balance, splitting same amount received SplitFundsLib.splitRevenuesETHNoRefund({ projectId: projectId, valueInWei: pricePerTokenInWei, coreContract: coreContract }); // emit event for state change emit TokenPurchased({ projectId: projectId, coreContract: coreContract, tokenId: tokenId, to: to }); } /** * @notice Place a new bid for a project. * Assumes check that minter is set for project on minter filter has * already been performed. * Reverts if project is not in state B (Live Auction). * Reverts if bid value is not equal to the slot value. * @param projectId Project Id to place bid for * @param coreContract Core contract address to place bid for * @param slotIndex Slot index to place bid at * @param bidder Bidder address * @param bidValue Bid value, in Wei (verified to align with slotIndex) * @param minterRefundGasLimit Gas limit to use when refunding the previous * highest bidder, prior to using fallback force-send to refund */ function placeBid( uint256 projectId, address coreContract, uint16 slotIndex, address bidder, uint256 bidValue, uint256 minterRefundGasLimit ) internal { // load project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // CHECKS // require project minter state B (Live Auction) require( getProjectMinterState(projectId, coreContract) == ProjectMinterStates.LiveAuction, "Only live auction" ); // require slot index not out of range // @dev slot index out of range is checked in slotIndexToBidValue // require bid value must equal slot value uint256 newBidRequiredValue = slotIndexToBidValue({ basePrice: RAMProjectConfig_.basePrice, slotIndex: slotIndex }); require( bidValue == newBidRequiredValue, "msg.value must equal slot value" ); // EFFECTS // add bid value to project balance RAMProjectConfig_.projectBalance += uint120(bidValue); // if first bid, refresh max invocations in case artist has reduced // the core contract's max invocations after the auction was configured // @dev this helps prevent E1 error state if (RAMProjectConfig_.numBids == 0) { // refresh max invocations MaxInvocationsLib.refreshMaxInvocations({ projectId: projectId, coreContract: coreContract }); // also refresh numTokensInAuction for RAM project config refreshNumTokensInAuction({ projectId: projectId, coreContract: coreContract }); } // require at least one token allowed in auction // @dev this case would revert in _removeMinBid, but prefer clean error // message here uint256 numTokensInAuction = RAMProjectConfig_.numTokensInAuction; require(numTokensInAuction > 0, "No tokens in auction"); // determine if have reached max bids bool reachedMaxBids = RAMProjectConfig_.numBids >= numTokensInAuction; if (reachedMaxBids) { // remove + refund the minimum Bid uint256 removedBidValue = _removeMinBid({ RAMProjectConfig_: RAMProjectConfig_, projectId: projectId, coreContract: coreContract, minterRefundGasLimit: minterRefundGasLimit }); // require new bid is sufficiently greater than removed minimum bid require( _isSufficientOutbid({ oldBidValue: removedBidValue, newBidValue: bidValue }), "Insufficient bid value" ); // apply auction extension time if needed bool timeExtensionNeeded = RAMProjectConfig_.allowExtraTime && block.timestamp > RAMProjectConfig_.timestampEnd - AUCTION_BUFFER_SECONDS; if (timeExtensionNeeded) { // extend auction end time to no longer than // MAX_AUCTION_EXTRA_SECONDS after original end time RAMProjectConfig_.timestampEnd = uint40( Math.min( RAMProjectConfig_.timestampOriginalEnd + MAX_AUCTION_EXTRA_SECONDS, block.timestamp + AUCTION_BUFFER_SECONDS ) ); emit AuctionTimestampEndUpdated({ projectId: projectId, coreContract: coreContract, timestampEnd: RAMProjectConfig_.timestampEnd }); } } // insert the new Bid _insertBid({ RAMProjectConfig_: RAMProjectConfig_, projectId: projectId, coreContract: coreContract, slotIndex: slotIndex, bidder: bidder, bidId: 0 // zero triggers new bid ID to be assigned }); } /** * @notice Top up bid for project `projectId` on core contract * `coreContract` for bid `bidId` to new slot index `newSlotIndex`. * Reverts if Bid ID has been kicked out of the auction or does not exist. * Reverts if bidder is not the bidder of the bid. * Reverts if project is not in a Live Auction. * Reverts if addedValue is not equal to difference in bid values between * new and old slots. * Reverts if new slot index is not greater than or equal to the current * slot index. * @param projectId Project ID to top up bid for. * @param coreContract Core contract address for the given project. * @param bidId ID of bid to top up. * @param newSlotIndex New slot index to move bid to. * @param bidder Bidder address * @param addedValue Value to add to the bid, in Wei */ function topUpBid( uint256 projectId, address coreContract, uint32 bidId, uint16 newSlotIndex, address bidder, uint256 addedValue ) internal { // load project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); Bid storage bid = RAMProjectConfig_.bids[bidId]; // memoize for gas efficiency uint16 oldSlotIndex = bid.slotIndex; // CHECKS { // require project minter state B (Live Auction) require( getProjectMinterState(projectId, coreContract) == ProjectMinterStates.LiveAuction, "Only live auction" ); // require new slot index not out of range // @dev slot index out of range is checked in slotIndexToBidValue // @dev give clean error message if bid is null or deleted require(bid.bidder != address(0), "Bid dne - were you outbid?"); // require bidder owns referenced bid require(bid.bidder == bidder, "Only bidder of existing bid"); // require correct added bid value uint256 oldBidValue = slotIndexToBidValue({ basePrice: RAMProjectConfig_.basePrice, slotIndex: oldSlotIndex }); uint256 newBidValue = slotIndexToBidValue({ basePrice: RAMProjectConfig_.basePrice, slotIndex: newSlotIndex }); // implicitly checks that newSlotIndex > oldSlotIndex, since // addedValue must be positive require( oldBidValue + addedValue == newBidValue, "incorrect added value" ); } // EFFECTS // add the added value to project balance RAMProjectConfig_.projectBalance += uint120(addedValue); // eject bid from the linked list at oldSlotIndex _ejectBidFromSlot({ RAMProjectConfig_: RAMProjectConfig_, slotIndex: oldSlotIndex, bidId: bidId }); // insert the existing bid into newSlotIndex's linked list _insertBid({ RAMProjectConfig_: RAMProjectConfig_, projectId: projectId, coreContract: coreContract, slotIndex: newSlotIndex, bidder: bidder, bidId: bidId }); // emit top-up event emit BidToppedUp({ projectId: projectId, coreContract: coreContract, bidId: bidId, newSlotIndex: newSlotIndex }); } /** * @notice Returns a storage pointer to the Bid struct and slot index of the lowest bid in the * project's auction, in Wei. * Reverts if no bids exist in the auction. * @param projectId Project ID to get the lowest bid value for * @param coreContract Core contract address for the given project * @return minBid Storage pointer to Bid struct of the lowest bid in * the auction * @return minSlotIndex Slot index of the lowest bid in the auction */ function getLowestBid( uint256 projectId, address coreContract ) internal view returns (Bid storage minBid, uint16 minSlotIndex) { RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // revert if no bids in auction require(RAMProjectConfig_.numBids > 0, "No bids in auction"); // get min slot with a bid minSlotIndex = RAMProjectConfig_.minBidSlotIndex; // get the tail bid ID for the min slot uint256 tailBidId = RAMProjectConfig_.tailBidIdBySlot[minSlotIndex]; minBid = RAMProjectConfig_.bids[tailBidId]; } /** * @notice Returns the auction details for project `projectId` on core * contract `coreContract`. * @param projectId is an existing project ID. * @param coreContract is an existing core contract address. * @return auctionTimestampStart is the timestamp at which the auction * starts. * @return auctionTimestampEnd is the timestamp at which the auction ends. * @return basePrice is the resting price of the auction, in Wei. * @return numTokensInAuction is the number of tokens in the auction. * @return numBids is the number of bids in the auction. * @return numBidsMintedTokens is the number of bids that have been minted * into tokens. * @return numBidsErrorRefunded is the number of bids that have been * refunded due to an error state. * @return minBidSlotIndex is the index of the slot with the minimum bid * value. * @return allowExtraTime is a bool indicating if the auction is allowed to * have extra time. * @return adminArtistOnlyMintPeriodIfSellout is a bool indicating if an * admin-artist-only mint period is required if the auction sells out. * @return revenuesCollected is a bool indicating if the auction revenues * have been collected. * @return projectMinterState is the current state of the project minter. * @dev projectMinterState is a RAMLib.ProjectMinterStates enum value. */ function getAuctionDetails( uint256 projectId, address coreContract ) internal view returns ( uint256 auctionTimestampStart, uint256 auctionTimestampEnd, uint256 basePrice, uint256 numTokensInAuction, uint256 numBids, uint256 numBidsMintedTokens, uint256 numBidsErrorRefunded, uint256 minBidSlotIndex, bool allowExtraTime, bool adminArtistOnlyMintPeriodIfSellout, bool revenuesCollected, RAMLib.ProjectMinterStates projectMinterState ) { // asign project minter state projectMinterState = getProjectMinterState({ projectId: projectId, coreContract: coreContract }); // get project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // get auction details auctionTimestampStart = RAMProjectConfig_.timestampStart; auctionTimestampEnd = RAMProjectConfig_.timestampEnd; basePrice = RAMProjectConfig_.basePrice; numTokensInAuction = RAMProjectConfig_.numTokensInAuction; numBids = RAMProjectConfig_.numBids; numBidsMintedTokens = RAMProjectConfig_.numBidsMintedTokens; numBidsErrorRefunded = RAMProjectConfig_.numBidsErrorRefunded; minBidSlotIndex = RAMProjectConfig_.minBidSlotIndex; allowExtraTime = RAMProjectConfig_.allowExtraTime; adminArtistOnlyMintPeriodIfSellout = RAMProjectConfig_ .adminArtistOnlyMintPeriodIfSellout; revenuesCollected = RAMProjectConfig_.revenuesCollected; } /** * @notice Returns the price information for a given project. * If an auction is not configured, `isConfigured` will be false, and a * dummy price of zero is assigned to `tokenPriceInWei`. * If an auction is configured but still in a pre-auction state, * `isConfigured` will be true, and `tokenPriceInWei` will be the minimum * initial bid price for the next token auction. * If there is an active auction, `isConfigured` will be true, and * `tokenPriceInWei` will be the current minimum bid's value + min bid * increment due to the minter's increment percentage, rounded up to next * slot's bid value. * If there is an auction that has ended (no longer accepting bids), but * the project is configured, `isConfigured` will be true, and * `tokenPriceInWei` will be either the sellout price or the reserve price * of the auction if it did not sell out during its auction. * @param projectId Project ID to get price information for * @param coreContract Core contract address for the given project * @return isConfigured True if the project is configured, false otherwise * @return tokenPriceInWei Price of a token in Wei, if configured */ function getPriceInfo( uint256 projectId, address coreContract ) internal view returns (bool isConfigured, uint256 tokenPriceInWei) { // get minter state RAMLib.ProjectMinterStates projectMinterState = getProjectMinterState({ projectId: projectId, coreContract: coreContract }); // load project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // handle pre-auction State A if (projectMinterState == RAMLib.ProjectMinterStates.PreAuction) { isConfigured = RAMProjectConfig_.timestampStart > 0; // if not configured, leave tokenPriceInWei as 0 if (isConfigured) { tokenPriceInWei = RAMProjectConfig_.basePrice; } } else { // values that apply to all live-auction and post-auction states isConfigured = true; bool isSellout = RAMProjectConfig_.numBids >= RAMProjectConfig_.numTokensInAuction; // handle live-auction State B if (projectMinterState == RAMLib.ProjectMinterStates.LiveAuction) { if (isSellout) { // find next valid bid value // @dev okay if we extend past the maximum slot index value // for this view function (, tokenPriceInWei) = _findNextValidBidSlotIndexAndValue({ projectId: projectId, coreContract: coreContract, startSlotIndex: RAMProjectConfig_.minBidSlotIndex }); } else { // not sellout, so min bid is base price tokenPriceInWei = RAMProjectConfig_.basePrice; } } else { // handle post-auction States C, D, E if (isSellout) { // if sellout, return min bid price tokenPriceInWei = slotIndexToBidValue({ basePrice: RAMProjectConfig_.basePrice, slotIndex: RAMProjectConfig_.minBidSlotIndex }); } else { // not sellout, so return base price tokenPriceInWei = RAMProjectConfig_.basePrice; } } } } /** * @notice Gets minimum next bid value in Wei and slot index for project `projectId` * on core contract `coreContract`. * If in a pre-auction state, reverts if unconfigured, otherwise returns * the minimum initial bid price for the upcoming auction. * If in an active auction, returns the minimum next bid's value and slot * index. * If in a post-auction state, reverts if auction was a sellout, otherwise * returns the auction's reserve price and slot index 0 (because tokens may * still be purchasable at the reserve price). * @param projectId Project ID to get the minimum next bid value for * @param coreContract Core contract address for the given project * @return minNextBidValueInWei minimum next bid value in Wei * @return minNextBidSlotIndex slot index of the minimum next bid */ function getMinimumNextBid( uint256 projectId, address coreContract ) internal view returns (uint256 minNextBidValueInWei, uint256 minNextBidSlotIndex) { // get minter state RAMLib.ProjectMinterStates projectMinterState = getProjectMinterState({ projectId: projectId, coreContract: coreContract }); // load project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // handle pre-auction State A if (projectMinterState == RAMLib.ProjectMinterStates.PreAuction) { bool isConfigured = RAMProjectConfig_.timestampStart > 0; if (!isConfigured) { // if not configured, revert revert("auction not configured"); } // if configured, min next bid is base price at slot 0 minNextBidValueInWei = RAMProjectConfig_.basePrice; minNextBidSlotIndex = 0; } else { // values that apply to all live-auction and post-auction states bool isSellout = RAMProjectConfig_.numBids >= RAMProjectConfig_.numTokensInAuction; // handle live-auction State B if (projectMinterState == RAMLib.ProjectMinterStates.LiveAuction) { if (isSellout) { // find next valid bid slot index and value // @dev okay if we extend past the maximum slot index and value // for this view function ( minNextBidSlotIndex, minNextBidValueInWei ) = _findNextValidBidSlotIndexAndValue({ projectId: projectId, coreContract: coreContract, startSlotIndex: RAMProjectConfig_.minBidSlotIndex }); } else { // not sellout, so min bid is base price minNextBidValueInWei = RAMProjectConfig_.basePrice; minNextBidSlotIndex = 0; } } else { // handle post-auction States C, D, E if (isSellout) { // if sellout, revert revert("auction ended, sellout"); } else { // not sellout, so return base price minNextBidValueInWei = RAMProjectConfig_.basePrice; minNextBidSlotIndex = 0; } } } } /** * @notice Gets the project minter state of project `projectId` on core * contract `coreContract`. * @param projectId Project ID to get the minimum next bid value for * @param coreContract Core contract address for the given project * @return ProjectMinterStates enum representing the minter state. */ function getProjectMinterState( uint256 projectId, address coreContract ) internal view returns (ProjectMinterStates) { RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // State A: Pre-Auction // @dev load to memory for gas efficiency uint256 timestampStart = RAMProjectConfig_.timestampStart; // helper value(s) for readability bool auctionIsConfigured = timestampStart > 0; bool isPreAuction = block.timestamp < timestampStart; // confirm that auction is either not configured or is pre-auction if ((!auctionIsConfigured) || isPreAuction) { return ProjectMinterStates.PreAuction; } // State B: Live-Auction // @dev auction is configured due to previous State A return // helper value(s) for readability // @dev load to memory for gas efficiency uint256 timestampEnd = RAMProjectConfig_.timestampEnd; bool isPostAuction = block.timestamp > timestampEnd; // pre-auction is checked above if (!isPostAuction) { return ProjectMinterStates.LiveAuction; } // States C, D, E: Post-Auction // @dev auction is configured and post auction due to previous States A, B returns // all winners sent tokens means all bids have either been minted tokens or refunded if error state occurred bool allBidsHandled = RAMProjectConfig_.numBidsMintedTokens + RAMProjectConfig_.numBidsErrorRefunded == RAMProjectConfig_.numBids; if (allBidsHandled) { // State E: Post-Auction, all bids handled return ProjectMinterStates.PostAuctionAllBidsHandled; } // @dev all bids are not handled due to previous State E return bool adminOnlyMintPeriod = RAMProjectConfig_ // @dev if project is configured to have an admin-artist-only mint period .adminArtistOnlyMintPeriodIfSellout && // @dev sellout if numBids >= numTokensInAuction RAMProjectConfig_.numBids >= RAMProjectConfig_.numTokensInAuction && // @dev still in admin-artist-only mint period if current time < end time + admin-artist-only mint period block.timestamp < timestampEnd + ADMIN_ARTIST_ONLY_MINT_TIME_SECONDS; if (adminOnlyMintPeriod) { // State C: Post-Auction, sell out, not all bids handled, admin-artist-only mint period return ProjectMinterStates.PostAuctionSellOutAdminArtistMint; } // State D: Post-Auction, not all bids handled, post-admin-artist-only mint period // @dev states are mutually exclusive, so must be in final remaining state return ProjectMinterStates.PostAuctionOpenMint; } /** * @notice Returns if project minter is in ERROR state E1, and the number * of bids that need to be refunded to resolve the error. Also returns the * number of excess invocations available, if any, indicating Flag F1. * E1: Tokens owed > invocations available * Occurs when: tokens are minted on different minter after auction begins, * or when core contract max invocations are reduced after auction begins. * Resolution: Admin must refund the lowest bids after auction ends. * @param projectId Project Id to query * @param coreContract Core contract address to query * @return isError True if in error state, false otherwise * @return numBidsToRefund Number of bids to refund to resolve error, 0 if * not in error state * @return numExcessInvocationsAvailable Number of excess invocations * available. Value above 0 indicates Flag F1. */ function isErrorE1FlagF1( uint256 projectId, address coreContract ) internal view returns ( bool isError, uint256 numBidsToRefund, uint256 numExcessInvocationsAvailable ) { // get project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // E1: Tokens owed > invocations available uint256 tokensOwed = _getNumTokensOwed({ RAMProjectConfig_: RAMProjectConfig_ }); uint256 invocationsAvailable = MaxInvocationsLib .getInvocationsAvailable({ projectId: projectId, coreContract: coreContract }); // populate return values isError = tokensOwed > invocationsAvailable; numBidsToRefund = isError ? tokensOwed - invocationsAvailable : 0; // no excess invocations available if in error state, otherwise is the // difference between invocations available and tokens owed numExcessInvocationsAvailable = isError ? 0 : invocationsAvailable - tokensOwed; } /** * @notice Returns the MaxInvocationsProjectConfig for a given project and * core contract, properly accounting for the auction state, unminted bids, * core contract invocations, and minter max invocations when determining * maxHasBeenInvoked * @param projectId Project Id to get config for * @param coreContract Core contract address to get config for * @return maxInvocationsProjectConfig max invocations project configuration */ function getMaxInvocationsProjectConfig( uint256 projectId, address coreContract ) internal view returns ( MaxInvocationsLib.MaxInvocationsProjectConfig memory maxInvocationsProjectConfig ) { // get max invocations project config from MaxInvocationsLib maxInvocationsProjectConfig.maxInvocations = uint24( MaxInvocationsLib.getMaxInvocations({ projectId: projectId, coreContract: coreContract }) ); maxInvocationsProjectConfig.maxHasBeenInvoked = getMaxHasBeenInvoked({ projectId: projectId, coreContract: coreContract }); } /** * @notice Returns if project has reached maximum number of invocations for * a given project and core contract, properly accounting for the auction * state, unminted bids, core contract invocations, and minter max * invocations when determining maxHasBeenInvoked * @param projectId Project Id to get config for * @param coreContract Core contract address to get config for * @return maxHasBeenInvoked bool indicating if max invocations have been invoked */ function getMaxHasBeenInvoked( uint256 projectId, address coreContract ) internal view returns (bool maxHasBeenInvoked) { // calculate if max has been invoked based on auction state ProjectMinterStates projectMinterState = getProjectMinterState({ projectId: projectId, coreContract: coreContract }); if (projectMinterState == ProjectMinterStates.PreAuction) { // pre-auction, true if numTokensInAuction == 0 RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); if (RAMProjectConfig_.timestampStart > 0) { // if auction configured, look at num tokens in auction maxHasBeenInvoked = RAMProjectConfig_.numTokensInAuction == 0; } else { // if auction not configured, defer to max invocation lib maxHasBeenInvoked = MaxInvocationsLib.getMaxHasBeenInvoked({ projectId: projectId, coreContract: coreContract }); } } else if (projectMinterState == ProjectMinterStates.LiveAuction) { // live auction, set to true if num bids >= num tokens in auction RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); maxHasBeenInvoked = RAMProjectConfig_.numBids >= RAMProjectConfig_.numTokensInAuction; } else { // post auction, set to true if remaining excess invocations is zero (, , uint256 numExcessInvocationsAvailable) = isErrorE1FlagF1({ projectId: projectId, coreContract: coreContract }); maxHasBeenInvoked = numExcessInvocationsAvailable == 0; } } /** * Returns balance of project `projectId` on core contract `coreContract` * on this minter contract. * @param projectId Project ID to get the balance for * @param coreContract Core contract address for the given project */ function getProjectBalance( uint256 projectId, address coreContract ) internal view returns (uint256) { RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); return RAMProjectConfig_.projectBalance; } /** * Loads the RAMProjectConfig for a given project and core * contract. * @param projectId Project Id to get config for * @param coreContract Core contract address to get config for */ function getRAMProjectConfig( uint256 projectId, address coreContract ) internal view returns (RAMProjectConfig storage) { return s().RAMProjectConfigs[coreContract][projectId]; } /** * Loads the RAMAdminMintingConstraint for a given core contract. * @param coreContract Core contract address to get config for */ function getRAMAdminMintingConstraintValue( address coreContract ) internal view returns (AdminMintingConstraint) { return s().RAMAdminMintingConstraint[coreContract]; } /** * @notice private helper function to mint a token. * @dev assumes all checks have been performed * @param projectId project ID to mint token for * @param coreContract core contract address for the given project * @param bidId bid ID of bid to mint token for * @param bidder bidder address of bid to mint token for * @param minterFilter minter filter contract address */ function _mintTokenForBid( uint256 projectId, address coreContract, uint32 bidId, address bidder, IMinterFilterV1 minterFilter ) private { // mint token uint256 tokenId = minterFilter.mint_joo({ to: bidder, projectId: projectId, coreContract: coreContract, sender: msg.sender }); // emit event for state change emit BidMinted({ projectId: projectId, coreContract: coreContract, bidId: bidId, tokenId: tokenId }); } /** * @notice private helper function to mint and settle bid if not already settled. * Assumes check that bidder for bid `bidId` is not null * @param projectId Project ID to mint token on. * @param coreContract Core contract address for the given project. * @param projectPrice Price of a token for the given project. * @param slotIndex Slot index of bid. * @param bidId ID of bid to settle. * @param minterFilter Minter filter contract address * @param minterRefundGasLimit Gas limit to use when settling bid, prior to using fallback force-send to refund */ function _mintAndSettle( uint256 projectId, address coreContract, uint256 projectPrice, uint256 slotIndex, uint256 bidId, IMinterFilterV1 minterFilter, uint256 minterRefundGasLimit ) private { // load project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); Bid storage bid = RAMProjectConfig_.bids[bidId]; // Mark bid as minted _setBidPackedBool({bid: bid, index: INDEX_IS_MINTED, value: true}); // Mint token for bid _mintTokenForBid({ projectId: projectId, coreContract: coreContract, bidId: uint32(bidId), bidder: bid.bidder, minterFilter: minterFilter }); // Settle if not already settled // @dev collector could have previously settled bid, so need to // settle only if not already settled if (!(_getBidPackedBool(bid, INDEX_IS_SETTLED))) { _settleBid({ RAMProjectConfig_: RAMProjectConfig_, projectId: projectId, coreContract: coreContract, projectPrice: projectPrice, slotIndex: slotIndex, bidId: uint32(bidId), minterRefundGasLimit: minterRefundGasLimit }); } } /** * @notice Helper function to handle settling a bid. * Reverts if bidder is not the bid's bidder. * Reverts if bid has already been settled. * @param RAMProjectConfig_ RAMProjectConfig to update * @param projectId Project ID of bid to settle * @param coreContract Core contract address for the given project. * @param projectPrice Price of token on the project * @param bidId ID of bid to settle * @param bidder Bidder address of bid to settle * @param minterRefundGasLimit Gas limit to use when refunding the bidder. */ function _settleBidWithChecks( RAMProjectConfig storage RAMProjectConfig_, uint256 projectId, address coreContract, uint256 projectPrice, uint32 bidId, address bidder, uint256 minterRefundGasLimit ) private { // CHECKS Bid storage bid = RAMProjectConfig_.bids[bidId]; // require bidder is the bid's bidder require(bid.bidder == bidder, "Only bidder"); // require bid is not yet settled require( !(_getBidPackedBool(bid, INDEX_IS_SETTLED)), "Only un-settled bid" ); _settleBid({ RAMProjectConfig_: RAMProjectConfig_, projectId: projectId, coreContract: coreContract, slotIndex: bid.slotIndex, bidId: bidId, projectPrice: projectPrice, minterRefundGasLimit: minterRefundGasLimit }); } /** * @notice private helper function to handle settling a bid. * @dev assumes bid has not been previously settled, and that all other * checks have been performed. * @param RAMProjectConfig_ RAMProjectConfig to update * @param projectId Project ID of bid to settle * @param coreContract Core contract address for the given project. * @param slotIndex Slot index of bid to settle * @param bidId ID of bid to settle * @param projectPrice Price of token on the project * @param minterRefundGasLimit Gas limit to use when refunding the previous * highest bidder, prior to using fallback force-send to refund */ function _settleBid( RAMProjectConfig storage RAMProjectConfig_, uint256 projectId, address coreContract, uint256 slotIndex, uint32 bidId, uint256 projectPrice, uint256 minterRefundGasLimit ) private { // @dev bid not passed as parameter to avoid stack too deep error in // functions that utilize this helper function Bid storage bid = RAMProjectConfig_.bids[bidId]; // EFFECTS // update state _setBidPackedBool({bid: bid, index: INDEX_IS_SETTLED, value: true}); // amount due = bid amount - project price uint256 amountDue = slotIndexToBidValue({ basePrice: RAMProjectConfig_.basePrice, // @dev safe to cast to uint16 slotIndex: uint16(slotIndex) }) - projectPrice; if (amountDue > 0) { // force-send settlement to bidder // @dev reverts on underflow RAMProjectConfig_.projectBalance -= uint120(amountDue); SplitFundsLib.forceSafeTransferETH({ to: bid.bidder, amount: amountDue, minterRefundGasLimit: minterRefundGasLimit }); } // emit event for state change emit BidSettled({ projectId: projectId, coreContract: coreContract, bidId: bidId }); } /** * @notice private helper function to settle and refund bids to resolve E1 error state. * Assumes check that bidder for bid `bidId` is not null * @param projectId Project ID to refund bid for. * @param coreContract Core contract address for the given project. * @param projectPrice Price of a token for the given project. * @param slotIndex Slot index of bid. * @param bidId ID of bid to settle. * @param minterRefundGasLimit Gas limit to use when refunding bidder */ function _settleAndRefundBid( uint256 projectId, address coreContract, uint256 projectPrice, uint256 slotIndex, uint256 bidId, uint256 minterRefundGasLimit ) private { // load project config RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); // load bid Bid storage bid = RAMProjectConfig_.bids[bidId]; // @dev bidderAddress previously checked not null address bidderAddress = bid.bidder; // Settle and refund the Bid // Minimum value to send is the project price uint256 valueToSend = projectPrice; bool didSettleBid = false; // if not isSettled, then settle the bid if (!_getBidPackedBool(bid, INDEX_IS_SETTLED)) { // mark bid as settled _setBidPackedBool({bid: bid, index: INDEX_IS_SETTLED, value: true}); didSettleBid = true; // send entire bid value if not previously settled valueToSend = slotIndexToBidValue({ basePrice: RAMProjectConfig_.basePrice, slotIndex: uint16(slotIndex) }); } // mark bid as refunded _setBidPackedBool({bid: bid, index: INDEX_IS_REFUNDED, value: true}); // INTERACTIONS // force-send refund to bidder // @dev reverts on underflow RAMProjectConfig_.projectBalance -= uint120(valueToSend); SplitFundsLib.forceSafeTransferETH({ to: bidderAddress, amount: valueToSend, minterRefundGasLimit: minterRefundGasLimit }); // emit event for state changes if (didSettleBid) { emit BidSettled({ projectId: projectId, coreContract: coreContract, bidId: bidId }); } emit BidRefunded({ projectId: projectId, coreContract: coreContract, bidId: bidId }); } /** * @notice Helper function to get the price of a token on a project. * @dev Assumes project is configured, has a base price, and generally * makes sense to get a price for. * @param RAMProjectConfig_ RAMProjectConfig to query */ function _getProjectPrice( RAMProjectConfig storage RAMProjectConfig_ ) private view returns (uint256 projectPrice) { bool wasSellout = RAMProjectConfig_.numBids >= RAMProjectConfig_.numTokensInAuction; // price is lowest bid if sellout, otherwise base price projectPrice = wasSellout ? slotIndexToBidValue({ basePrice: RAMProjectConfig_.basePrice, slotIndex: RAMProjectConfig_.minBidSlotIndex }) : RAMProjectConfig_.basePrice; } /** * @notice Helper function to get the number of tokens owed for a given * project. * @param RAMProjectConfig_ RAMProjectConfig to query * @return tokensOwed The number of bids in a project minus the sum of tokens already * minted and bids that have been refunded due to an error state. */ function _getNumTokensOwed( RAMProjectConfig storage RAMProjectConfig_ ) private view returns (uint256 tokensOwed) { tokensOwed = RAMProjectConfig_.numBids - (RAMProjectConfig_.numBidsMintedTokens + RAMProjectConfig_.numBidsErrorRefunded); } /** * @notice Inserts a bid into the project's RAMProjectConfig. * Assumes the bid is valid and may be inserted into the bucket-sort data * structure. * Creates a new bid if bidId is zero, otherwise moves an existing bid, * which is assumed to exist and be valid. * Emits BidCreated event if a new bid is created. * @dev assumes slot index is valid and < NUM_SLOTS * @param RAMProjectConfig_ RAM project config to insert bid into * @param projectId Project ID to insert bid for * @param coreContract Core contract address to insert bid for * @param slotIndex Slot index to insert bid at * @param bidder Bidder address * @param bidId Bid ID to insert, or zero if a new bid should be created */ function _insertBid( RAMProjectConfig storage RAMProjectConfig_, uint256 projectId, address coreContract, uint16 slotIndex, address bidder, uint32 bidId ) private { // add the new Bid to tail of the slot's doubly linked list bool createNewBid = bidId == 0; if (createNewBid) { // prefix ++ to skip initial bid ID of zero (indicates null value) bidId = ++RAMProjectConfig_.nextBidId; } uint256 prevTailBidId = RAMProjectConfig_.tailBidIdBySlot[slotIndex]; RAMProjectConfig_.bids[bidId] = Bid({ prevBidId: uint32(prevTailBidId), nextBidId: 0, // null value at end of tail slotIndex: slotIndex, bidder: bidder, packedBools: 0 // all packed bools false }); // update tail pointer to new bid RAMProjectConfig_.tailBidIdBySlot[slotIndex] = bidId; // update head pointer or next pointer of previous bid if (prevTailBidId == 0) { // first bid in slot, update head pointer RAMProjectConfig_.headBidIdBySlot[slotIndex] = bidId; } else { // update previous bid's next pointer RAMProjectConfig_.bids[prevTailBidId].nextBidId = bidId; } // update number of active bids RAMProjectConfig_.numBids++; // update metadata if first bid for this slot // @dev assumes minting has not yet started if (prevTailBidId == 0) { // set the slot in the bitmap _setBitmapSlot({ RAMProjectConfig_: RAMProjectConfig_, slotIndex: slotIndex }); // update bitmap metadata - reduce min bid index if necessary if (slotIndex < RAMProjectConfig_.minBidSlotIndex) { RAMProjectConfig_.minBidSlotIndex = slotIndex; } // update bitmap metadata - increase max bid index if necessary if (slotIndex > RAMProjectConfig_.maxBidSlotIndex) { RAMProjectConfig_.maxBidSlotIndex = slotIndex; } } if (createNewBid) { // emit state change event emit BidCreated({ projectId: projectId, coreContract: coreContract, slotIndex: slotIndex, bidId: bidId, bidder: bidder }); } } /** * @notice Remove minimum bid from the project's RAMProjectConfig. * Reverts if no bids exist in slot RAMProjectConfig_.minBidSlotIndex. * @param RAMProjectConfig_ RAM project config to remove bid from * @param projectId Project ID to remove bid from * @param coreContract Core contract address for the given project * @param minterRefundGasLimit Gas limit to use when refunding the previous * highest bidder, prior to using fallback force-send to refund * @return removedBidAmount The value of the removed bid, in Wei */ function _removeMinBid( RAMProjectConfig storage RAMProjectConfig_, uint256 projectId, address coreContract, uint256 minterRefundGasLimit ) private returns (uint256 removedBidAmount) { // get the minimum bid slot and bid id uint16 removedSlotIndex = RAMProjectConfig_.minBidSlotIndex; uint256 removedBidId = RAMProjectConfig_.tailBidIdBySlot[ removedSlotIndex ]; // @dev no coverage on else branch because it is unreachable as used require(removedBidId > 0, "No bids"); // record the previous min bidder Bid storage removedBid = RAMProjectConfig_.bids[removedBidId]; address removedBidder = removedBid.bidder; // update the tail pointer of the slot's doubly linked list uint32 newTailBidId = removedBid.prevBidId; RAMProjectConfig_.tailBidIdBySlot[removedSlotIndex] = newTailBidId; RAMProjectConfig_.numBids--; // update metadata if no more active bids for this slot if (newTailBidId == 0) { // update the head pointer of the slot's doubly linked list RAMProjectConfig_.headBidIdBySlot[removedSlotIndex] = 0; // unset the slot in the bitmap // update minBidIndex, efficiently starting at minBidSlotIndex + 1 _unsetBitmapSlot({ RAMProjectConfig_: RAMProjectConfig_, slotIndex: removedSlotIndex }); // @dev reverts if removedSlotIndex was the maximum slot 511, // preventing bids from being removed entirely from the last slot, // which is acceptable and non-impacting for this minter // @dev sets minBidSlotIndex to 512 if no more active bids, which // is desired behavior for this minter RAMProjectConfig_.minBidSlotIndex = _getMinSlotWithBid({ RAMProjectConfig_: RAMProjectConfig_, startSlotIndex: removedSlotIndex + 1 }); } else { // if the removed bid was not the head, then unset the nextBidId pointer of the bid Bid storage newTailBid = RAMProjectConfig_.bids[newTailBidId]; newTailBid.nextBidId = 0; } // refund the removed bidder removedBidAmount = slotIndexToBidValue({ basePrice: RAMProjectConfig_.basePrice, slotIndex: removedSlotIndex }); // @dev reverts on underflow RAMProjectConfig_.projectBalance -= uint120(removedBidAmount); // delete the removed bid to prevent future claiming // @dev performed last to avoid pointing to deleted bid struct delete RAMProjectConfig_.bids[removedBidId]; SplitFundsLib.forceSafeTransferETH({ to: removedBidder, amount: removedBidAmount, minterRefundGasLimit: minterRefundGasLimit }); // emit state change event emit BidRemoved({ projectId: projectId, coreContract: coreContract, bidId: removedBidId }); } /** * @notice Ejects a bid from the project's RAMProjectConfig. * Assumes the bid is valid (i.e. bid ID is a valid, active bid). * Does not refund the bidder, does not emit events, does not delete Bid. * @param RAMProjectConfig_ RAM project config to eject bid from * @param slotIndex Slot index to eject bid from * @param bidId ID of bid to eject */ function _ejectBidFromSlot( RAMProjectConfig storage RAMProjectConfig_, uint16 slotIndex, uint256 bidId ) private { // get the bid to remove Bid storage removedBid = RAMProjectConfig_.bids[bidId]; uint32 prevBidId = removedBid.prevBidId; uint32 nextBidId = removedBid.nextBidId; // update previous bid's next pointer if (prevBidId == 0) { // removed bid was the head bid RAMProjectConfig_.headBidIdBySlot[slotIndex] = nextBidId; } else { // removed bid was not the head bid RAMProjectConfig_.bids[prevBidId].nextBidId = nextBidId; } // update next bid's previous pointer if (nextBidId == 0) { // removed bid was the tail bid RAMProjectConfig_.tailBidIdBySlot[slotIndex] = prevBidId; } else { // removed bid was not the tail bid RAMProjectConfig_.bids[nextBidId].prevBidId = prevBidId; } // decrement the number of active bids RAMProjectConfig_.numBids--; // update metadata if no more active bids for this slot if (prevBidId == 0 && nextBidId == 0) { // unset the slot in the bitmap // update minBidIndex, efficiently starting at minBidSlotIndex + 1 _unsetBitmapSlot({ RAMProjectConfig_: RAMProjectConfig_, slotIndex: slotIndex }); // @dev reverts if removedSlotIndex was the maximum slot 511, // preventing bids from being removed entirely from the last slot, // which is acceptable and non-impacting for this minter // @dev sets minBidSlotIndex to 512 if no more active bids, which // is desired behavior for this minter if (RAMProjectConfig_.minBidSlotIndex == slotIndex) { RAMProjectConfig_.minBidSlotIndex = _getMinSlotWithBid({ RAMProjectConfig_: RAMProjectConfig_, startSlotIndex: slotIndex + 1 }); } } // @dev do not refund, do not emit event, do not delete bid } /** * @notice Helper function to handle setting slot in 512-bit bitmap * Reverts if slotIndex > 511 * @param slotIndex Index of slot to set (between 0 and 511) * @param RAMProjectConfig_ RAMProjectConfig to update */ function _setBitmapSlot( RAMProjectConfig storage RAMProjectConfig_, uint256 slotIndex ) private { // revert if slotIndex >= NUM_SLOTS, since this is an invalid input // @dev no coverage as slot index out of range checked in placeBid and implicitly in topUpBid require(slotIndex < NUM_SLOTS, "Only slot index lt NUM_SLOTS"); // set the slot in the bitmap if (slotIndex < 256) { // @dev <256 conditional ensures no overflow when casting to uint8 RAMProjectConfig_.slotsBitmapA = RAMProjectConfig_.slotsBitmapA.set( uint8(slotIndex) ); } else { // @dev <512 results in no overflow when casting to uint8 RAMProjectConfig_.slotsBitmapB = RAMProjectConfig_.slotsBitmapB.set( // @dev casting to uint8 intentional overflow instead of // subtracting 256 from slotIndex uint8(slotIndex) ); } } /** * @notice Helper function to handle unsetting slot in 512-bit bitmap * Reverts if slotIndex > 511 * @param slotIndex Index of slot to set (between 0 and 511) * @param RAMProjectConfig_ RAMProjectConfig to update */ function _unsetBitmapSlot( RAMProjectConfig storage RAMProjectConfig_, uint256 slotIndex ) private { // revert if slotIndex >= NUM_SLOTS, since this is an invalid input // @dev no coverage as slot index out of range checked in placeBid and implicitly in topUpBid require(slotIndex < NUM_SLOTS, "Only slot index lt NUM_SLOTS"); // unset the slot in the bitmap if (slotIndex < 256) { // @dev <256 conditional ensures no overflow when casting to uint8 RAMProjectConfig_.slotsBitmapA = RAMProjectConfig_ .slotsBitmapA .unset(uint8(slotIndex)); } else { // @dev <512 results in no overflow when casting to uint8 RAMProjectConfig_.slotsBitmapB = RAMProjectConfig_ .slotsBitmapB .unset( // @dev casting to uint8 intentional overflow instead of // subtracting 256 from slotIndex uint8(slotIndex) ); } } /** * @notice Helper function to set a packed boolean in a Bid struct. * @param bid Bid to update * @param index Index of packed boolean to update * @param value Value to set packed boolean to */ function _setBidPackedBool( Bid storage bid, uint8 index, bool value ) private { // @dev no coverage on else branch because it is unreachable as used if (value) { bid.packedBools = uint8( uint256(bid.packedBools).setBoolTrue(index) ); } else { bid.packedBools = uint8( uint256(bid.packedBools).setBoolFalse(index) ); } } /** * @notice Helper function to get a packed boolean from a Bid struct. * @param bid Bid to query * @param index Index of packed boolean to query * @return Value of packed boolean */ function _getBidPackedBool( Bid storage bid, uint8 index ) private view returns (bool) { return uint256(bid.packedBools).getBool(index); } /** * @notice Helper function to get minimum slot index with an active bid, * starting at a given slot index and searching upwards. * Returns 512, (invalid slot index) if no slots with bids were found. * Reverts if startSlotIndex > 511, since this library only supports 512 * slots. * @param RAMProjectConfig_ RAM project config to query * @param startSlotIndex Slot index to start search at * @return minSlotWithBid Minimum slot index with an active bid, or 512 (invalid index) if * no slots with bids were found. */ function _getMinSlotWithBid( RAMProjectConfig storage RAMProjectConfig_, uint16 startSlotIndex ) private view returns (uint16 minSlotWithBid) { bool foundSlotWithBid; // revert if startSlotIndex > 511, since this is an invalid input // @dev no coverage on if branch because unreachable as used if (startSlotIndex > 511) { revert("Only start slot index lt 512"); } // temporary uint256 in working memory uint256 minSlotWithBid_; // start at startSlotIndex if (startSlotIndex > 255) { // @dev <512 check results in no overflow when casting to uint8 (minSlotWithBid_, foundSlotWithBid) = RAMProjectConfig_ .slotsBitmapB .minBitSet( // @dev casting to uint8 intentional overflow instead of // subtracting 256 from slotIndex uint8(startSlotIndex) ); // add 256 to account for slotsBitmapB offset minSlotWithBid_ += 256; } else { // @dev <256 conditional ensures no overflow when casting to uint8 (minSlotWithBid_, foundSlotWithBid) = RAMProjectConfig_ .slotsBitmapA .minBitSet(uint8(startSlotIndex)); // if no bids in first bitmap, check second bitmap // @dev behavior of library's minBitSet is to return 256 if no bits // were set if (!foundSlotWithBid) { // @dev <512 check results in no overflow when casting to uint8 (minSlotWithBid_, foundSlotWithBid) = RAMProjectConfig_ .slotsBitmapB .minBitSet( // start at beginning of second bitmap uint8(0) ); // add 256 to account for slotsBitmapB offset minSlotWithBid_ += 256; } } // populate return value if (!foundSlotWithBid) { return uint16(NUM_SLOTS); } else { minSlotWithBid = uint16(minSlotWithBid_); return minSlotWithBid; } } /** * @notice Helper function to get maximum slot index with an active bid, * starting at a given slot index and searching downwards. * Returns 512, (invalid slot index) if no slots with bids were found. * Reverts if startSlotIndex > 511, since this library only supports 512 * slots. * @param RAMProjectConfig_ RAM project config to query * @param startSlotIndex Slot index to start search at * @return maxSlotWithBid Maximum slot index with an active bid, and 512 (invalid index) if * no slots with bids were found. */ function _getMaxSlotWithBid( RAMProjectConfig storage RAMProjectConfig_, uint16 startSlotIndex ) private view returns (uint16 maxSlotWithBid) { bool foundSlotWithBid; // revert if startSlotIndex > 511, since this is an invalid input // @dev no coverage on if branch because unreachable as used if (startSlotIndex > 511) { revert("Only start slot index lt 512"); } // temporary uint256 in working memory uint256 maxSlotWithBid_; // start at startSlotIndex if (startSlotIndex < 256) { // @dev <256 conditional ensures no overflow when casting to uint8 (maxSlotWithBid_, foundSlotWithBid) = RAMProjectConfig_ .slotsBitmapA .maxBitSet(uint8(startSlotIndex)); } else { // need to potentially check both bitmaps (maxSlotWithBid_, foundSlotWithBid) = RAMProjectConfig_ .slotsBitmapB .maxBitSet( // @dev casting to uint8 intentional overflow instead of // subtracting 256 from slotIndex uint8(startSlotIndex) ); // add 256 to account for slotsBitmapB offset maxSlotWithBid_ += 256; if (!foundSlotWithBid) { // no bids in first bitmap B, so check second bitmap A (maxSlotWithBid_, foundSlotWithBid) = RAMProjectConfig_ .slotsBitmapA .maxBitSet( // start at the end of the first bitmap uint8(255) ); } } // populate return value // @dev no coverage on if branch because it is unreachable as used if (!foundSlotWithBid) { return uint16(NUM_SLOTS); } else { maxSlotWithBid = uint16(maxSlotWithBid_); return maxSlotWithBid; } } /** * @notice Returns the next valid bid slot index and value for a given project. * @dev this may return slot index and value higher than the maximum slot index and value * allowed by the minter, in which case a bid cannot actually be placed * to outbid a bid at `startSlotIndex`. * @param projectId Project ID to find next valid bid slot index for * @param coreContract Core contract address for the given project * @param startSlotIndex Slot index to start search from * @return nextValidBidSlotIndex Next valid bid slot index * @return nextValidBidValue Next valid bid value at nextValidBidSlotIndex slot index, in Wei */ function _findNextValidBidSlotIndexAndValue( uint256 projectId, address coreContract, uint16 startSlotIndex ) private view returns (uint16 nextValidBidSlotIndex, uint256 nextValidBidValue) { RAMProjectConfig storage RAMProjectConfig_ = getRAMProjectConfig({ projectId: projectId, coreContract: coreContract }); uint88 basePrice = RAMProjectConfig_.basePrice; uint256 startBidValue = slotIndexToBidValue({ basePrice: basePrice, slotIndex: startSlotIndex }); // start search at next slot, incremented in while loop uint16 currentSlotIndex = startSlotIndex; while (true) { // increment slot index and re-calc current slot bid value unchecked { currentSlotIndex++; } nextValidBidValue = slotIndexToBidValue({ basePrice: basePrice, slotIndex: currentSlotIndex }); // break if current slot's bid value is sufficiently greater than // the starting slot's bid value if ( _isSufficientOutbid({ oldBidValue: startBidValue, newBidValue: nextValidBidValue }) ) { break; } // otherwise continue to next iteration } // return the found valid slot index nextValidBidSlotIndex = currentSlotIndex; } /** * @notice Returns a bool indicating if a new bid value is sufficiently * greater than an old bid value, to replace the old bid value. * @param oldBidValue Old bid value to compare * @param newBidValue New bid value to compare * @return isSufficientOutbid True if new bid is sufficiently greater than * old bid, false otherwise */ function _isSufficientOutbid( uint256 oldBidValue, uint256 newBidValue ) private pure returns (bool) { if (oldBidValue > 0.5 ether) { // require new bid is at least 2.5% greater than removed minimum bid return newBidValue > (oldBidValue * 10250) / 10000; } // require new bid is at least 5% greater than removed minimum bid return newBidValue > (oldBidValue * 10500) / 10000; } /** * @notice Returns the value of a bid in a given slot, in Wei. * @dev returns 0 if base price is zero * @param basePrice Base price (or reserve price) of the auction, in Wei * @param slotIndex Slot index to query * @return slotBidValue Value of a bid in the slot, in Wei */ function slotIndexToBidValue( uint88 basePrice, uint16 slotIndex ) internal pure returns (uint256 slotBidValue) { // @dev for overflow safety, always revert if slotIndex >= NUM_SLOTS require(slotIndex < NUM_SLOTS, "Only slot index lt NUM_SLOTS"); // use pseud-exponential pricing curve // multiply by two (via bit-shifting) for the number of entire // slots-per-price-double associated with the slot index // @dev overflow not possible due to typing, constants, and check above // (max(uint88) << (512 / 64)) < max(uint256) slotBidValue = uint256(basePrice) << (slotIndex / SLOTS_PER_PRICE_DOUBLE); // perform a linear interpolation between partial half-life points, to // approximate the current place on a perfect exponential curve. // @dev overflow automatically checked in solidity 0.8, not expected slotBidValue += (slotBidValue * (slotIndex % SLOTS_PER_PRICE_DOUBLE)) / SLOTS_PER_PRICE_DOUBLE; } /** * @notice Return the storage struct for reading and writing. This library * uses a diamond storage pattern when managing storage. * @return storageStruct The RAMLibStorage struct. */ function s() private pure returns (RAMLibStorage storage storageStruct) { bytes32 position = RAM_LIB_STORAGE_POSITION; assembly ("memory-safe") { storageStruct.slot := position } } }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; import {IMinterBaseV0} from "../../../interfaces/v0.8.x/IMinterBaseV0.sol"; import {IGenArt721CoreContractV3_Base} from "../../../interfaces/v0.8.x/IGenArt721CoreContractV3_Base.sol"; import {IGenArt721CoreContractV3} from "../../../interfaces/v0.8.x/IGenArt721CoreContractV3.sol"; import {IGenArt721CoreContractV3_Engine} from "../../../interfaces/v0.8.x/IGenArt721CoreContractV3_Engine.sol"; import {IERC20} from "@openzeppelin-4.7/contracts/token/ERC20/IERC20.sol"; /** * @title Art Blocks Split Funds Library * @notice This library is designed for the Art Blocks platform. It splits * Ether (ETH) and ERC20 token funds among stakeholders, such as sender * (if refund is applicable), providers, artists, and artists' additional * payees. * @author Art Blocks Inc. */ library SplitFundsLib { /** * @notice Currency updated for project `projectId` to symbol * `currencySymbol` and address `currencyAddress`. * @param projectId Project ID currency was updated for * @param coreContract Core contract address currency was updated for * @param currencyAddress Currency address * @param currencySymbol Currency symbol */ event ProjectCurrencyInfoUpdated( uint256 indexed projectId, address indexed coreContract, address indexed currencyAddress, string currencySymbol ); // position of Split Funds Lib storage, using a diamond storage pattern // for this library bytes32 constant SPLIT_FUNDS_LIB_STORAGE_POSITION = keccak256("splitfundslib.storage"); // contract-level variables struct IsEngineCache { bool isEngine; bool isCached; } // project-level variables struct SplitFundsProjectConfig { address currencyAddress; // address(0) if ETH string currencySymbol; // Assumed to be ETH if null } // Diamond storage pattern is used in this library struct SplitFundsLibStorage { mapping(address coreContract => mapping(uint256 projectId => SplitFundsProjectConfig)) splitFundsProjectConfigs; mapping(address coreContract => IsEngineCache) isEngineCacheConfigs; } /** * @notice splits ETH funds between sender (if refund), providers, * artist, and artist's additional payee for a token purchased on * project `projectId`. * WARNING: This function uses msg.value and msg.sender to determine * refund amounts, and therefore may not be applicable to all use cases * (e.g. do not use with Dutch Auctions with on-chain settlement). * @dev This function relies on msg.sender and msg.value, so it must be * called directly from the contract that is receiving the payment. * @dev possible DoS during splits is acknowledged, and mitigated by * business practices, including end-to-end testing on mainnet, and * admin-accepted artist payment addresses. * @param projectId Project ID for which funds shall be split. * @param pricePerTokenInWei Current price of token, in Wei. * @param coreContract Address of the GenArt721CoreContract associated * with the project. */ function splitFundsETHRefundSender( uint256 projectId, uint256 pricePerTokenInWei, address coreContract ) internal { if (msg.value > 0) { // send refund to sender uint256 refund = msg.value - pricePerTokenInWei; if (refund > 0) { (bool success_, ) = msg.sender.call{value: refund}(""); require(success_, "Refund failed"); } // split revenues splitRevenuesETHNoRefund({ projectId: projectId, valueInWei: pricePerTokenInWei, coreContract: coreContract }); } } /** * @notice pays ETH funds to sender (if refund), with all of token price * being sent to the render provider for a token purchased on project * `projectId`. * WARNING: This function uses msg.value and msg.sender to determine * refund amounts, and therefore may not be applicable to all use cases * (e.g. do not use with Dutch Auctions with on-chain settlement). * @dev This function relies on msg.sender and msg.value, so it must be * called directly from the contract that is receiving the payment. * @dev possible DoS during splits is acknowledged, and mitigated by * business practices, including end-to-end testing on mainnet, and * admin-accepted artist payment addresses. * @param projectId Project ID for which funds shall be split. * @param pricePerTokenInWei Current price of token, in Wei. * @param coreContract Address of the GenArt721CoreContract associated * with the project. */ function sendAllToRenderProviderETHRefundSender( uint256 projectId, uint256 pricePerTokenInWei, address coreContract ) internal { if (msg.value > 0) { // send refund to sender uint256 refund = msg.value - pricePerTokenInWei; if (refund > 0) { (bool success_, ) = msg.sender.call{value: refund}(""); require(success_, "Refund failed"); } // send remaining to render provider sendAllToRenderProviderETHNoRefund({ projectId: projectId, valueInWei: pricePerTokenInWei, coreContract: coreContract }); } } /** * @notice Splits ETH revenues between providers, artist, and artist's * additional payee for revenue generated by project `projectId`. * This function does NOT refund msg.sender, and does NOT use msg.value * when determining the value to be split. * @dev possible DoS during splits is acknowledged, and mitigated by * business practices, including end-to-end testing on mainnet, and * admin-accepted artist payment addresses. * @param projectId Project ID for which funds shall be split. * @param valueInWei Value to be split, in Wei. * @param coreContract Address of the GenArt721CoreContract * associated with the project. */ function splitRevenuesETHNoRefund( uint256 projectId, uint256 valueInWei, address coreContract ) internal { if (valueInWei == 0) { return; // return early } // split funds between platforms, artist, and artist's // additional payee bool isEngine_ = isEngine(coreContract); uint256 renderProviderRevenue; address payable renderProviderAddress; uint256 platformProviderRevenue; address payable platformProviderAddress; uint256 artistRevenue; address payable artistAddress; uint256 additionalPayeePrimaryRevenue; address payable additionalPayeePrimaryAddress; if (isEngine_) { // get engine splits ( renderProviderRevenue, renderProviderAddress, platformProviderRevenue, platformProviderAddress, artistRevenue, artistAddress, additionalPayeePrimaryRevenue, additionalPayeePrimaryAddress ) = IGenArt721CoreContractV3_Engine(coreContract) .getPrimaryRevenueSplits({ _projectId: projectId, _price: valueInWei }); } else { // get flagship splits // @dev note that platformProviderAddress and // platformProviderRevenue remain 0 for flagship ( renderProviderRevenue, // artblocks revenue renderProviderAddress, // artblocks address artistRevenue, artistAddress, additionalPayeePrimaryRevenue, additionalPayeePrimaryAddress ) = IGenArt721CoreContractV3(coreContract).getPrimaryRevenueSplits({ _projectId: projectId, _price: valueInWei }); } // require total revenue split is 100% // @dev note that platformProviderRevenue remains 0 for flagship require( renderProviderRevenue + platformProviderRevenue + artistRevenue + additionalPayeePrimaryRevenue == valueInWei, "Invalid revenue split totals" ); // distribute revenues // @dev note that platformProviderAddress and platformProviderRevenue // remain 0 for flagship _sendPaymentsETH({ platformProviderRevenue: platformProviderRevenue, platformProviderAddress: platformProviderAddress, renderProviderRevenue: renderProviderRevenue, renderProviderAddress: renderProviderAddress, artistRevenue: artistRevenue, artistAddress: artistAddress, additionalPayeePrimaryRevenue: additionalPayeePrimaryRevenue, additionalPayeePrimaryAddress: additionalPayeePrimaryAddress }); } /** * @notice Sends all revenue generated by project `projectId` to render * provider. * This function does NOT refund msg.sender, and does NOT use msg.value * when determining the value to be split. * @dev possible DoS during splits is acknowledged, and mitigated by * business practices, including end-to-end testing on mainnet, and * admin-accepted payment addresses. * @param projectId Project ID for which funds shall be sent. * @param valueInWei Value to be sent, in Wei. * @param coreContract Address of the GenArt721CoreContract * associated with the project. */ function sendAllToRenderProviderETHNoRefund( uint256 projectId, uint256 valueInWei, address coreContract ) internal { if (valueInWei == 0) { return; // return early } // split funds between platforms, artist, and artist's // additional payee bool isEngine_ = isEngine(coreContract); address payable renderProviderAddress; if (isEngine_) { // get engine splits ( , renderProviderAddress, , , , , , ) = IGenArt721CoreContractV3_Engine(coreContract) .getPrimaryRevenueSplits({ _projectId: projectId, _price: valueInWei }); } else { // get flagship splits // @dev note that platformProviderAddress and // platformProviderRevenue remain 0 for flagship ( , // artblocks revenue renderProviderAddress, // artblocks address , , , ) = IGenArt721CoreContractV3(coreContract).getPrimaryRevenueSplits({ _projectId: projectId, _price: valueInWei }); } require( renderProviderAddress != address(0), "Render Provider address not set" ); // distribute revenue // Render Provider / Art Blocks payment // @dev previous conditional ensures valueInWei is non-zero (bool success, ) = renderProviderAddress.call{value: valueInWei}(""); require(success, "Render Provider payment failed"); } /** * @notice Splits ERC20 funds between providers, artist, and artist's * additional payee, for a token purchased on project `projectId`. * The function performs checks to ensure that the ERC20 token is * approved for transfer, and that a non-zero ERC20 token address is * configured. * @dev This function relies on msg.sender, so it must be * called directly from the contract that is receiving the payment. * @dev possible DoS during splits is acknowledged, and mitigated by * business practices, including end-to-end testing on mainnet, and * admin-accepted artist payment addresses. * @param projectId Project ID for which funds shall be split. * @param pricePerToken Current price of token, in base units. For example, * if the ERC20 token has 6 decimals, an input value of `1_000_000` would * represent a price of `1.000000` tokens. * @param coreContract Core contract address. */ function splitFundsERC20( uint256 projectId, uint256 pricePerToken, address coreContract ) internal { if (pricePerToken == 0) { return; // nothing to split, return early } IERC20 projectCurrency; // block scope to avoid stack too deep error { SplitFundsProjectConfig storage splitFundsProjectConfig = getSplitFundsProjectConfig({ projectId: projectId, coreContract: coreContract }); address currencyAddress = splitFundsProjectConfig.currencyAddress; require( currencyAddress != address(0), "ERC20: payment not configured" ); // ERC20 token is used for payment validateERC20Approvals({ msgSender: msg.sender, currencyAddress: currencyAddress, pricePerToken: pricePerToken }); projectCurrency = IERC20(currencyAddress); } // split remaining funds between foundation, artist, and artist's additional payee bool isEngine_ = isEngine(coreContract); uint256 renderProviderRevenue; address payable renderProviderAddress; uint256 platformProviderRevenue; address payable platformProviderAddress; uint256 artistRevenue; address payable artistAddress; uint256 additionalPayeePrimaryRevenue; address payable additionalPayeePrimaryAddress; if (isEngine_) { // get engine splits ( renderProviderRevenue, renderProviderAddress, platformProviderRevenue, platformProviderAddress, artistRevenue, artistAddress, additionalPayeePrimaryRevenue, additionalPayeePrimaryAddress ) = IGenArt721CoreContractV3_Engine(coreContract) .getPrimaryRevenueSplits({ _projectId: projectId, _price: pricePerToken }); } else { // get flagship splits // @dev note that platformProviderAddress and // platformProviderRevenue remain 0 for flagship ( renderProviderRevenue, // artblocks revenue renderProviderAddress, // artblocks address artistRevenue, artistAddress, additionalPayeePrimaryRevenue, additionalPayeePrimaryAddress ) = IGenArt721CoreContractV3(coreContract).getPrimaryRevenueSplits({ _projectId: projectId, _price: pricePerToken }); } // require total revenue split is 100% // @dev note that platformProviderRevenue remains 0 for flagship require( renderProviderRevenue + platformProviderRevenue + artistRevenue + additionalPayeePrimaryRevenue == pricePerToken, "Invalid revenue split totals" ); // distribute revenues // @dev note that platformProviderAddress and platformProviderRevenue // remain 0 for flagship _sendPaymentsERC20({ projectCurrency: projectCurrency, platformProviderRevenue: platformProviderRevenue, platformProviderAddress: platformProviderAddress, renderProviderRevenue: renderProviderRevenue, renderProviderAddress: renderProviderAddress, artistRevenue: artistRevenue, artistAddress: artistAddress, additionalPayeePrimaryRevenue: additionalPayeePrimaryRevenue, additionalPayeePrimaryAddress: additionalPayeePrimaryAddress }); } /** * @notice Updates payment currency of the referenced * SplitFundsProjectConfig to be `currencySymbol` at address * `currencyAddress`. * Only supports setting currency info of ERC20 tokens. * Returns bool that is true if the price should be reset after this * update. Price is recommended to be reset if the currency address was * previously configured, but is now being updated to a different currency * address. This is to protect accidental price reductions when changing * currency if an artist is changing currencies in an unpaused state. * @dev artist-defined currency symbol is used instead of any on-chain * currency symbol. * @param projectId Project ID to update. * @param coreContract Core contract address. * @param currencySymbol Currency symbol. * @param currencyAddress Currency address. * @return recommendPriceReset True if the price should be reset after this * update. */ function updateProjectCurrencyInfoERC20( uint256 projectId, address coreContract, string memory currencySymbol, address currencyAddress ) internal returns (bool recommendPriceReset) { // CHECKS require(currencyAddress != address(0), "null address, only ERC20"); require(bytes(currencySymbol).length > 0, "only non-null symbol"); // EFFECTS SplitFundsProjectConfig storage splitFundsProjectConfig = getSplitFundsProjectConfig({ projectId: projectId, coreContract: coreContract }); // recommend price reset if currency address was previously configured recommendPriceReset = (splitFundsProjectConfig.currencyAddress != address(0)); splitFundsProjectConfig.currencySymbol = currencySymbol; splitFundsProjectConfig.currencyAddress = currencyAddress; emit ProjectCurrencyInfoUpdated({ projectId: projectId, coreContract: coreContract, currencyAddress: currencyAddress, currencySymbol: currencySymbol }); } /** * @notice Force sends `amount` (in wei) ETH to `to`, with a gas stipend * equal to `minterRefundGasLimit`. * If sending via the normal procedure fails, force sends the ETH by * creating a temporary contract which uses `SELFDESTRUCT` to force send * the ETH. * Reverts if the current contract has insufficient balance. * @param to The address to send ETH to. * @param amount The amount of ETH to send. * @param minterRefundGasLimit The gas limit to use when sending ETH, prior * to fallback. * @dev This function is adapted from the `forceSafeTransferETH` function * in the `https://github.com/Vectorized/solady` repository, with * modifications to not check if the current contract has sufficient * balance. Therefore, the contract should be checked for sufficient * balance before calling this function in the minter itself, if * applicable. */ function forceSafeTransferETH( address to, uint256 amount, uint256 minterRefundGasLimit ) internal { // Manually inlined because the compiler doesn't inline functions with // branches. /// @solidity memory-safe-assembly assembly { // @dev intentionally do not check if this contract has sufficient // balance, because that is not intended to be a valid state. // Transfer the ETH and check if it succeeded or not. if iszero(call(minterRefundGasLimit, to, amount, 0, 0, 0, 0)) { // if the transfer failed, we create a temporary contract with // initialization code that uses `SELFDESTRUCT` to force send // the ETH. // note: Compatible with `SENDALL`: // https://eips.ethereum.org/EIPS/eip-4758 //---------------------------------------------------------------------------------------------------------------// // Opcode | Opcode + Arguments | Description | Stack View // //---------------------------------------------------------------------------------------------------------------// // Contract creation code that uses `SELFDESTRUCT` to force send ETH to a specified address. // // Creation code summary: 0x73<20-byte toAddress>0xff // //---------------------------------------------------------------------------------------------------------------// // 0x73 | 0x73_toAddress | PUSH20 toAddress | toAddress // // 0xFF | 0xFF | SELFDESTRUCT | // //---------------------------------------------------------------------------------------------------------------// // Store the address in scratch space, starting at 0x00, which begins the 20-byte address at 32-20=12 in memory // @dev use scratch space because we have enough space for simple creation code (less than 0x40 bytes) mstore(0x00, to) // store opcode PUSH20 immediately before the address, starting at 0x0b (11) in memory mstore8(0x0b, 0x73) // store opcode SELFDESTRUCT immediately after the address, starting at 0x20 (32) in memory mstore8(0x20, 0xff) // this will always succeed because the contract creation code is // valid, and the address is valid because it is a 20-byte value if iszero(create(amount, 0x0b, 0x16)) { // @dev For better gas estimation. if iszero(gt(gas(), 1000000)) { revert(0, 0) } } } } } /** * @notice Returns whether or not the provided address `coreContract` * is an Art Blocks Engine core contract. Caches the result for future access. * @param coreContract Address of the core contract to check. */ function isEngine(address coreContract) internal returns (bool) { IsEngineCache storage isEngineCache = getIsEngineCacheConfig( coreContract ); // check cache, return early if cached if (isEngineCache.isCached) { return isEngineCache.isEngine; } // populate cache and return result bool isEngine_ = getV3CoreIsEngineView(coreContract); isEngineCache.isCached = true; isEngineCache.isEngine = isEngine_; return isEngine_; } /** * @notice Returns whether a V3 core contract is an Art Blocks Engine * contract or not. Return value of false indicates that the core is a * flagship contract. This function does not update the cache state for the * given V3 core contract. * @dev this function reverts if a core contract does not return the * expected number of return values from getPrimaryRevenueSplits() for * either a flagship or engine core contract. * @dev this function uses the length of the return data (in bytes) to * determine whether the core is an engine or not. * @param coreContract The address of the deployed core contract. */ function getV3CoreIsEngineView( address coreContract ) internal view returns (bool) { // call getPrimaryRevenueSplits() on core contract bytes memory payload = abi.encodeWithSignature( "getPrimaryRevenueSplits(uint256,uint256)", 0, 0 ); (bool success, bytes memory returnData) = coreContract.staticcall( payload ); require(success, "getPrimaryRevenueSplits() call failed"); // determine whether core is engine or not, based on return data length uint256 returnDataLength = returnData.length; if (returnDataLength == 6 * 32) { // 6 32-byte words returned if flagship (not engine) // @dev 6 32-byte words are expected because the non-engine core // contracts return a payout address and uint256 payment value for // the artist, and artist's additional payee, and Art Blocks. // also note that per Solidity ABI encoding, the address return // values are padded to 32 bytes. return false; } else if (returnDataLength == 8 * 32) { // 8 32-byte words returned if engine // @dev 8 32-byte words are expected because the engine core // contracts return a payout address and uint256 payment value for // the artist, artist's additional payee, render provider // typically Art Blocks, and platform provider (partner). // also note that per Solidity ABI encoding, the address return // values are padded to 32 bytes. return true; } // unexpected return value length revert("Unexpected revenue split bytes"); } /** * @notice Gets the currency address and symbol for the referenced * SplitFundsProjectConfig. * Only supports ERC20 tokens - returns currencySymbol of `UNCONFIG` if * `currencyAddress` is zero. * @param projectId Project ID to get config for * @param coreContract Core contract address to get config for * @return currencyAddress currency address for the referenced SplitFundsProjectConfig. * @return currencySymbol currency symbol for the referenced SplitFundsProjectConfig. */ function getCurrencyInfoERC20( uint256 projectId, address coreContract ) internal view returns (address currencyAddress, string memory currencySymbol) { SplitFundsProjectConfig storage splitFundsProjectConfig = getSplitFundsProjectConfig({ projectId: projectId, coreContract: coreContract }); currencyAddress = splitFundsProjectConfig.currencyAddress; // default to "UNCONFIG" if project currency address is initial value currencySymbol = currencyAddress == address(0) ? "UNCONFIG" : splitFundsProjectConfig.currencySymbol; } /** * @notice Gets the balance of `currencyAddress` ERC20 tokens for `walletAddress`. * @param currencyAddress ERC20 token address. * @param walletAddress wallet address. * @return balance Balance of ERC-20 */ function getERC20Balance( address currencyAddress, address walletAddress ) internal view returns (uint256) { return IERC20(currencyAddress).balanceOf(walletAddress); } /** * @notice Gets the allowance of `spenderAddress` to spend `walletAddress`'s * `currencyAddress` ERC20 tokens. * @param currencyAddress ERC20 token address. * @param walletAddress wallet address. * @param spenderAddress spender address. * @return allowance Allowance of ERC-20 */ function getERC20Allowance( address currencyAddress, address walletAddress, address spenderAddress ) internal view returns (uint256 allowance) { allowance = IERC20(currencyAddress).allowance({ owner: walletAddress, spender: spenderAddress }); return allowance; } /** * @notice Function validates that `msgSender` has approved the contract to spend at least * `pricePerToken` of `currencyAddress` ERC20 tokens, and that * `msgSender` has a balance of at least `pricePerToken` of * `currencyAddress` ERC20 tokens. * Reverts if insufficient allowance or balance. * @param msgSender Address of the message sender to validate. * @param currencyAddress Address of the ERC20 token to validate. * @param pricePerToken Price of token, in base units. For example, * if the ERC20 token has 6 decimals, an input value of `1_000_000` would * represent a price of `1.000000` tokens. */ function validateERC20Approvals( address msgSender, address currencyAddress, uint256 pricePerToken ) private view { require( IERC20(currencyAddress).allowance({ owner: msgSender, spender: address(this) }) >= pricePerToken, "Insufficient ERC20 allowance" ); require( IERC20(currencyAddress).balanceOf(msgSender) >= pricePerToken, "Insufficient ERC20 balance" ); } /** * @notice Sends ETH revenues between providers, artist, and artist's * additional payee. Reverts if any payment fails. * @dev This function pays priviliged addresses. DoS is acknowledged, and * mitigated by business practices, including end-to-end testing on * mainnet, and admin-accepted artist payment addresses. * @param platformProviderRevenue Platform Provider revenue. * @param platformProviderAddress Platform Provider address. * @param renderProviderRevenue Render Provider revenue. * @param renderProviderAddress Render Provider address. * @param artistRevenue Artist revenue. * @param artistAddress Artist address. * @param additionalPayeePrimaryRevenue Additional Payee revenue. * @param additionalPayeePrimaryAddress Additional Payee address. */ function _sendPaymentsETH( uint256 platformProviderRevenue, address payable platformProviderAddress, uint256 renderProviderRevenue, address payable renderProviderAddress, uint256 artistRevenue, address payable artistAddress, uint256 additionalPayeePrimaryRevenue, address payable additionalPayeePrimaryAddress ) private { // Platform Provider payment (only possible if engine) if (platformProviderRevenue > 0) { (bool success, ) = platformProviderAddress.call{ value: platformProviderRevenue }(""); require(success, "Platform Provider payment failed"); } // Render Provider / Art Blocks payment if (renderProviderRevenue > 0) { (bool success, ) = renderProviderAddress.call{ value: renderProviderRevenue }(""); require(success, "Render Provider payment failed"); } // artist payment if (artistRevenue > 0) { (bool success, ) = artistAddress.call{value: artistRevenue}(""); require(success, "Artist payment failed"); } // additional payee payment if (additionalPayeePrimaryRevenue > 0) { (bool success, ) = additionalPayeePrimaryAddress.call{ value: additionalPayeePrimaryRevenue }(""); require(success, "Additional Payee payment failed"); } } /** * @notice Sends ERC20 revenues between providers, artist, and artist's * additional payee. Reverts if any payment fails. All revenue values * should use base units. For example, if the ERC20 token has 6 decimals, * an input value of `1_000_000` would represent an amount of `1.000000` * tokens. * @dev This function relies on msg.sender, so it must be called from * the contract that is receiving the payment. * @param projectCurrency IERC20 payment token. * @param platformProviderRevenue Platform Provider revenue. * @param platformProviderAddress Platform Provider address. * @param renderProviderRevenue Render Provider revenue. * @param renderProviderAddress Render Provider address. * @param artistRevenue Artist revenue. * @param artistAddress Artist address. * @param additionalPayeePrimaryRevenue Additional Payee revenue. * @param additionalPayeePrimaryAddress Additional Payee address. */ function _sendPaymentsERC20( IERC20 projectCurrency, uint256 platformProviderRevenue, address payable platformProviderAddress, uint256 renderProviderRevenue, address payable renderProviderAddress, uint256 artistRevenue, address payable artistAddress, uint256 additionalPayeePrimaryRevenue, address payable additionalPayeePrimaryAddress ) private { // Platform Provider payment (only possible if engine) if (platformProviderRevenue > 0) { require( projectCurrency.transferFrom({ from: msg.sender, to: platformProviderAddress, amount: platformProviderRevenue }), "Platform Provider payment failed" ); } // Art Blocks payment if (renderProviderRevenue > 0) { require( projectCurrency.transferFrom({ from: msg.sender, to: renderProviderAddress, amount: renderProviderRevenue }), "Render Provider payment failed" ); } // artist payment if (artistRevenue > 0) { require( projectCurrency.transferFrom({ from: msg.sender, to: artistAddress, amount: artistRevenue }), "Artist payment failed" ); } // additional payee payment if (additionalPayeePrimaryRevenue > 0) { // @dev some ERC20 may not revert on transfer failure, so we // check the return value require( projectCurrency.transferFrom({ from: msg.sender, to: additionalPayeePrimaryAddress, amount: additionalPayeePrimaryRevenue }), "Additional Payee payment failed" ); } } /** * @notice Loads the SplitFundsProjectConfig for a given project and core * contract. * @param projectId Project Id to get config for * @param coreContract Core contract address to get config for */ function getSplitFundsProjectConfig( uint256 projectId, address coreContract ) internal view returns (SplitFundsProjectConfig storage) { return s().splitFundsProjectConfigs[coreContract][projectId]; } /** * @notice Loads the IsEngineCache for a given core contract. * @param coreContract Core contract address to get config for */ function getIsEngineCacheConfig( address coreContract ) internal view returns (IsEngineCache storage) { return s().isEngineCacheConfigs[coreContract]; } /** * @notice Return the storage struct for reading and writing. This library * uses a diamond storage pattern when managing storage. * @return storageStruct The SetPriceLibStorage struct. */ function s() internal pure returns (SplitFundsLibStorage storage storageStruct) { bytes32 position = SPLIT_FUNDS_LIB_STORAGE_POSITION; assembly ("memory-safe") { storageStruct.slot := position } } }
// SPDX-License-Identifier: LGPL-3.0-only // Created By: Art Blocks Inc. pragma solidity ^0.8.0; /** * @dev Library for packing multiple boolean values into a single uint256. * This is useful for storing a large number of bool values in a more compact * way than solidify's native bool type, which uses 8 bytes per bool. * * The implementation is similar to a BitMap, but function names are more * descriptive for packing and unpacking multiple bools. * * Note that the library may still be used in cases where less than 256 bools * are needed to be packed. For example, if <= 8 bools are needed, casting may * be used outside of the library for compatibility with any size uint. */ library PackedBools { function getBool( uint256 packedBool, uint8 index ) internal pure returns (bool) { uint256 mask = 1 << index; return packedBool & mask != 0; } function setBoolTrue( uint256 bitMap, uint8 index ) internal pure returns (uint256 newBitMap) { uint256 mask = 1 << index; return bitMap | mask; } function setBoolFalse( uint256 bitMap, uint8 index ) internal pure returns (uint256 newBitMap) { uint256 mask = 1 << index; return bitMap & ~mask; } }
{ "optimizer": { "enabled": true, "runs": 10 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"minterFilter","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"auctionBufferSeconds","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxAuctionExtraSeconds","type":"uint256"}],"name":"AuctionBufferTimeParamsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"address","name":"coreContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestampStart","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestampEnd","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"basePrice","type":"uint256"},{"indexed":false,"internalType":"bool","name":"allowExtraTime","type":"bool"},{"indexed":false,"internalType":"bool","name":"adminArtistOnlyMintPeriodIfSellout","type":"bool"},{"indexed":false,"internalType":"uint256","name":"numTokensInAuction","type":"uint256"}],"name":"AuctionConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"address","name":"coreContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestampEnd","type":"uint256"}],"name":"AuctionTimestampEndUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"address","name":"coreContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"slotIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bidId","type":"uint256"},{"indexed":false,"internalType":"address","name":"bidder","type":"address"}],"name":"BidCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"address","name":"coreContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"bidId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"BidMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"address","name":"coreContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"bidId","type":"uint256"}],"name":"BidRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"address","name":"coreContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"bidId","type":"uint256"}],"name":"BidRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"address","name":"coreContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"bidId","type":"uint256"}],"name":"BidSettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"address","name":"coreContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"bidId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSlotIndex","type":"uint256"}],"name":"BidToppedUp","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"address","name":"coreContract","type":"address"},{"indexed":false,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"value","type":"bool"}],"name":"ConfigValueSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"coreContract","type":"address"},{"indexed":false,"internalType":"enum RAMLib.AdminMintingConstraint","name":"adminMintingConstraint","type":"uint8"}],"name":"ContractConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minAuctionDurationSeconds","type":"uint256"}],"name":"MinAuctionDurationSecondsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint24","name":"refundGasLimit","type":"uint24"}],"name":"MinterRefundGasLimitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"numSlots","type":"uint256"}],"name":"NumSlotsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"address","name":"coreContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"numTokensInAuction","type":"uint256"}],"name":"NumTokensInAuctionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"address","name":"coreContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"maxInvocations","type":"uint256"}],"name":"ProjectMaxInvocationsLimitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"address","name":"coreContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"TokenPurchased","type":"event"},{"inputs":[],"name":"MIN_AUCTION_DURATION_SECONDS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"},{"internalType":"uint8","name":"emergencyHoursToAdd","type":"uint8"}],"name":"adminAddEmergencyAuctionHours","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"},{"internalType":"uint24","name":"numTokensToMint","type":"uint24"}],"name":"adminArtistAutoMintTokensToWinners","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"},{"internalType":"uint32[]","name":"bidIds","type":"uint32[]"}],"name":"adminArtistDirectMintTokensToWinners","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"},{"internalType":"uint32[]","name":"bidIds","type":"uint32[]"}],"name":"adminArtistDirectRefundWinners","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"},{"internalType":"uint24","name":"numBidsToRefund","type":"uint24"}],"name":"adminAutoRefundWinners","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"},{"internalType":"uint32[]","name":"bidIds","type":"uint32[]"}],"name":"collectSettlements","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"coreContract","type":"address"}],"name":"contractConfigurationDetails","outputs":[{"internalType":"enum RAMLib.AdminMintingConstraint","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"},{"internalType":"uint16","name":"slotIndex","type":"uint16"}],"name":"createBid","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"}],"name":"getAuctionDetails","outputs":[{"internalType":"uint256","name":"auctionTimestampStart","type":"uint256"},{"internalType":"uint256","name":"auctionTimestampEnd","type":"uint256"},{"internalType":"uint256","name":"basePrice","type":"uint256"},{"internalType":"uint256","name":"numTokensInAuction","type":"uint256"},{"internalType":"uint256","name":"numBids","type":"uint256"},{"internalType":"uint256","name":"numBidsMintedTokens","type":"uint256"},{"internalType":"uint256","name":"numBidsErrorRefunded","type":"uint256"},{"internalType":"uint256","name":"minBidSlotIndex","type":"uint256"},{"internalType":"bool","name":"allowExtraTime","type":"bool"},{"internalType":"bool","name":"adminArtistOnlyMintPeriodIfSellout","type":"bool"},{"internalType":"bool","name":"revenuesCollected","type":"bool"},{"internalType":"enum RAMLib.ProjectMinterStates","name":"projectMinterState","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"}],"name":"getIsErrorE1","outputs":[{"internalType":"bool","name":"isError","type":"bool"},{"internalType":"uint256","name":"numBidsToRefund","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"}],"name":"getLowestBidValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"}],"name":"getMinimumNextBid","outputs":[{"internalType":"uint256","name":"minNextBidValueInWei","type":"uint256"},{"internalType":"uint256","name":"minNextBidSlotIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"}],"name":"getPriceInfo","outputs":[{"internalType":"bool","name":"isConfigured","type":"bool"},{"internalType":"uint256","name":"tokenPriceInWei","type":"uint256"},{"internalType":"string","name":"currencySymbol","type":"string"},{"internalType":"address","name":"currencyAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"}],"name":"getProjectBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"coreContract","type":"address"}],"name":"isEngineView","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"},{"internalType":"uint24","name":"maxInvocations","type":"uint24"}],"name":"manuallyLimitProjectMaxInvocations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"}],"name":"maxInvocationsProjectConfig","outputs":[{"components":[{"internalType":"bool","name":"maxHasBeenInvoked","type":"bool"},{"internalType":"uint24","name":"maxInvocations","type":"uint24"}],"internalType":"struct MaxInvocationsLib.MaxInvocationsProjectConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minterConfigurationDetails","outputs":[{"internalType":"uint256","name":"minAuctionDurationSeconds","type":"uint256"},{"internalType":"uint256","name":"auctionBufferSeconds","type":"uint256"},{"internalType":"uint256","name":"maxAuctionExtraSeconds","type":"uint256"},{"internalType":"uint256","name":"maxAuctionAdminEmergencyExtensionHours","type":"uint256"},{"internalType":"uint256","name":"adminArtistOnlyMintTimeSeconds","type":"uint256"},{"internalType":"uint24","name":"minterRefundGasLimit","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minterFilterAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minterType","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minterVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"}],"name":"projectMaxHasBeenInvoked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"}],"name":"projectMaxInvocations","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"}],"name":"purchase","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"}],"name":"purchaseTo","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"},{"internalType":"uint40","name":"auctionTimestampEnd","type":"uint40"}],"name":"reduceAuctionLength","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"},{"internalType":"uint40","name":"auctionTimestampStart","type":"uint40"},{"internalType":"uint40","name":"auctionTimestampEnd","type":"uint40"},{"internalType":"uint256","name":"basePrice","type":"uint256"},{"internalType":"bool","name":"allowExtraTime","type":"bool"},{"internalType":"bool","name":"adminArtistOnlyMintPeriodIfSellout","type":"bool"}],"name":"setAuctionDetails","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"coreContract","type":"address"},{"internalType":"enum RAMLib.AdminMintingConstraint","name":"adminMintingConstraint","type":"uint8"}],"name":"setContractConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"},{"internalType":"uint16","name":"slotIndex","type":"uint16"}],"name":"slotIndexToBidValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"syncProjectMaxInvocationsToCore","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"},{"internalType":"uint32","name":"bidId","type":"uint32"},{"internalType":"uint16","name":"newSlotIndex","type":"uint16"}],"name":"topUpBid","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint24","name":"minterRefundGasLimit","type":"uint24"}],"name":"updateRefundGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"},{"internalType":"uint32[]","name":"bidIds","type":"uint32[]"}],"name":"winnerDirectMintTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"},{"internalType":"uint32[]","name":"bidIds","type":"uint32[]"}],"name":"winnerDirectRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"coreContract","type":"address"}],"name":"withdrawArtistAndAdminRevenues","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60c06040526001805462ffffff19166175301790553480156200002157600080fd5b5060405162005fe938038062005fe9833981016040819052620000449162000144565b60016000556001600160a01b038116608081905260a05260405161025881527f4ef0f5aca00c220a4058c318e0dd5526680003d4e6fceb9ad65087452a8313fa9060200160405180910390a160015460405162ffffff90911681527ff28602592f2788507e76a86523ec8d5ef26873807e258d4cae31571370c0e6c89060200160405180910390a16040805161012c8152610e1060208201527f0c92d75d9ae429e723cd03b00b1498b72fd1a30fd4337bf4cbdf14650599dd38910160405180910390a160405161020081527f93eac00dcf92d1cee4f4605f83f625533396c288555591736b62533e656beaf69060200160405180910390a15062000176565b6000602082840312156200015757600080fd5b81516001600160a01b03811681146200016f57600080fd5b9392505050565b60805160a051615e1c620001cd600039600081816108a8015281816109c801528181610a9901528181610b1201528181610cfe01528181610dde015261103c01526000818161067a0152610f420152615e1c6000f3fe60806040526004361061019e5760003560e01c806241673c146101a357806301000da7146101d6578063014053a014610206578063047fef49146102285780631290b96b1461026057806317e70c3c1461028057806340b790bd146102935780634869f3df146102ca5780634e8d8787146102ea57806363076680146102fd57806365e92cde1461034c57806366133e291461036c578063711ce3911461038c5780637ca340a6146103ac5780637e86d370146103cc5780638f13865e146103ec5780638fe8a90b1461040c5780639a94488a1461042c5780639b7b55851461046e578063a5514c7e14610484578063ae77c237146104a4578063b000e334146104b7578063b9daf3b5146104d7578063bf54d5fb146104f7578063c1b9281e14610517578063cce7c90914610537578063d009cb9d14610557578063d3ddabe61461058c578063d4f6d0e3146105cb578063d8b4e3ba146105f8578063d9bffbce14610618578063d9eb16db14610638578063dd85582f14610668578063e624db9f146106b4578063e9d1e8ac146106d4578063f5a759b71461070b575b600080fd5b3480156101af57600080fd5b506101c36101be366004615165565b61071e565b6040519081526020015b60405180910390f35b3480156101e257600080fd5b506101f66101f13660046151a3565b610754565b60405190151581526020016101cd565b34801561021257600080fd5b506102266102213660046151c0565b61078c565b005b34801561023457600080fd5b5061024861024336600461524b565b6107e2565b6040516101cd9c9b9a99989796959493929190615291565b34801561026c57600080fd5b5061022661027b36600461531f565b610826565b61022661028e366004615165565b610870565b34801561029f57600080fd5b506102b36102ae36600461524b565b610969565b6040805192151583526020830191909152016101cd565b3480156102d657600080fd5b506101c36102e536600461524b565b610982565b6101c36102f8366004615354565b610997565b34801561030957600080fd5b5060015460408051610258815261012c6020820152610e1091810191909152604860608201526203f480608082015262ffffff90911660a082015260c0016101cd565b34801561035857600080fd5b50610226610367366004615396565b6109f9565b34801561037857600080fd5b506102266103873660046153d3565b610a3e565b34801561039857600080fd5b506102266103a73660046151c0565b610a5f565b3480156103b857600080fd5b506102266103c73660046151c0565b610ac3565b3480156103d857600080fd5b506102266103e7366004615413565b610b3c565b3480156103f857600080fd5b506102266104073660046151c0565b610bc5565b34801561041857600080fd5b5061022661042736600461524b565b610c1c565b34801561043857600080fd5b5061044c61044736600461524b565b610c6a565b6040805182511515815260209283015162ffffff1692810192909252016101cd565b34801561047a57600080fd5b506101c361025881565b34801561049057600080fd5b5061022661049f3660046154a6565b610c7c565b6101c36104b236600461524b565b610ccd565b3480156104c357600080fd5b506102266104d23660046154a6565b610d2e565b3480156104e357600080fd5b506102266104f23660046154a6565b610d94565b34801561050357600080fd5b506101c361051236600461524b565b610e08565b34801561052357600080fd5b506102266105323660046151c0565b610e14565b34801561054357600080fd5b506101f661055236600461524b565b610e56565b34801561056357600080fd5b5061057761057236600461524b565b610e62565b604080519283526020830191909152016101cd565b34801561059857600080fd5b506105be60405180604001604052806006815260200165076302e302e360d41b81525081565b6040516101cd919061552b565b3480156105d757600080fd5b506105eb6105e63660046151a3565b610e7a565b6040516101cd919061553e565b34801561060457600080fd5b506101c361061336600461524b565b610e85565b34801561062457600080fd5b5061022661063336600461524b565b610ec1565b34801561064457600080fd5b5061065861065336600461524b565b610f00565b6040516101cd9493929190615558565b34801561067457600080fd5b5061069c7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101cd565b3480156106c057600080fd5b506102266106cf366004615592565b610f3d565b3480156106e057600080fd5b506105be6040518060400160405280600b81526020016a04d696e74657252414d56360ac1b81525081565b6102266107193660046155c1565b611004565b60008061072b85856110f0565b60060154600160901b90046001600160581b0316905061074b8184611121565b95945050505050565b600080610760836111b7565b8054909150610100900460ff161561077c575460ff1692915050565b610785836111f0565b9392505050565b6002600054036107b75760405162461bcd60e51b81526004016107ae90615610565b60405180910390fd5b6002600055600180546107d79186918691869186919062ffffff16611366565b505060016000555050565b6000806000806000806000806000806000806107fe8e8e611568565b9b509b509b509b509b509b509b509b509b509b509b509b509295989b509295989b509295989b565b6002600054036108485760405162461bcd60e51b81526004016107ae90615610565b60026000556108588383336116c7565b610866838383610258611711565b5050600160005550565b6002600054036108925760405162461bcd60e51b81526004016107ae90615610565b6002600055604051635845de1f60e01b815230907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635845de1f906108e79087908790600401615647565b602060405180830381865afa158015610904573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610928919061565e565b6001600160a01b03161461094e5760405162461bcd60e51b81526004016107ae9061567b565b600154610866908490849084903390349062ffffff16611951565b6000806109768484611c55565b50909590945092505050565b600061098e8383611cc2565b90505b92915050565b60006002600054036109bb5760405162461bcd60e51b81526004016107ae90615610565b60026000556109ec8484847f0000000000000000000000000000000000000000000000000000000000000000611ce2565b6001600055949350505050565b600260005403610a1b5760405162461bcd60e51b81526004016107ae90615610565b6002600055610a338233306332f4966f60e11b611efc565b610866838383611f57565b610a518233306366133e2960e01b611efc565b610a5b828261210e565b5050565b600260005403610a815760405162461bcd60e51b81526004016107ae90615610565b6002600055600180546107d7918691869186918691907f00000000000000000000000000000000000000000000000000000000000000009062ffffff16612199565b600260005403610ae55760405162461bcd60e51b81526004016107ae90615610565b6002600055610afe84843330633e51a05360e11b612368565b6001546107d79085908590859085906000907f00000000000000000000000000000000000000000000000000000000000000009062ffffff16612199565b600260005403610b5e5760405162461bcd60e51b81526004016107ae90615610565b6002600055610b6e8787336116c7565b610258610b7b86866156bc565b64ffffffffff161015610ba05760405162461bcd60e51b81526004016107ae906156da565b610bb787878787610bb0886123d1565b878761243d565b505060016000555050505050565b600260005403610be75760405162461bcd60e51b81526004016107ae90615610565b6002600055610c0084843330634789c32f60e11b612368565b6001546107d790859085908590859060009062ffffff16611366565b600260005403610c3e5760405162461bcd60e51b81526004016107ae90615610565b6002600055610c5782823330638fe8a90b60e01b612368565b610c61828261278e565b50506001600055565b610c7261511f565b61098e8383612943565b600260005403610c9e5760405162461bcd60e51b81526004016107ae90615610565b6002600055610cb68233306352a8a63f60e11b611efc565b6001546108669084908490849062ffffff16612973565b6000600260005403610cf15760405162461bcd60e51b81526004016107ae90615610565b6002600055610d223384847f0000000000000000000000000000000000000000000000000000000000000000611ce2565b60016000559392505050565b610d398383336116c7565b6000610d458484612b60565b90506000816004811115610d5b57610d5b61527b565b14610d785760405162461bcd60e51b81526004016107ae90615705565b610d83848484612c90565b610d8d8484612d49565b5050505050565b600260005403610db65760405162461bcd60e51b81526004016107ae90615610565b6002600055610dcf8383333063b9daf3b560e01b612368565b600154610866908490849084907f00000000000000000000000000000000000000000000000000000000000000009062ffffff16612dca565b600061098e8383612fdf565b600260005403610e365760405162461bcd60e51b81526004016107ae90615610565b60026000556001546107d7908590859085908590339062ffffff16613001565b600061098e83836130e5565b600080610e6f84846131bd565b909590945092505050565b600061099182613357565b600080610e928484613386565b9150506000610ea185856110f0565b60060154600160901b90046001600160581b0316905061074b8183611121565b60405162461bcd60e51b81526020600482015260146024820152731058dd1a5bdb881b9bdd081cdd5c1c1bdc9d195960621b60448201526064016107ae565b60008060606000610f11868661341a565b60408051808201909152600381526208aa8960eb1b602082015291989097509095506000945092505050565b610f707f0000000000000000000000000000000000000000000000000000000000000000333063e624db9f60e01b613554565b611b588162ffffff161015610fb85760405162461bcd60e51b815260206004820152600e60248201526d04f6e6c792067746520375f3030360941b60448201526064016107ae565b6001805462ffffff191662ffffff83169081179091556040519081527ff28602592f2788507e76a86523ec8d5ef26873807e258d4cae31571370c0e6c89060200160405180910390a150565b6002600054036110265760405162461bcd60e51b81526004016107ae90615610565b6002600055604051635845de1f60e01b815230907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635845de1f9061107b9088908890600401615647565b602060405180830381865afa158015611098573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110bc919061565e565b6001600160a01b0316146110e25760405162461bcd60e51b81526004016107ae9061567b565b6107d78484848433346135a9565b60006110fa61382a565b6001600160a01b039290921660009081526020928352604080822094825293909252502090565b60006102008261ffff16106111485760405162461bcd60e51b81526004016107ae9061572f565b611155600861020061577b565b6111639061ffff841661577b565b6001600160581b038416901b905061117e600861020061577b565b61118b600861020061577b565b6111999061ffff851661578f565b6111a390836157a3565b6111ad919061577b565b61098e90826157ba565b6001600160a01b031660009081527f69f22dd730b53ff235fa96b4306a31bef5dad48fe4bac28b1ceebbce14401b396020526040902090565b6040516000602482018190526044820181905290819060640160408051601f198184030181529181526020820180516001600160e01b0316638639415b60e01b1790525190915060009081906001600160a01b038616906112529085906157cd565b600060405180830381855afa9150503d806000811461128d576040519150601f19603f3d011682016040523d82523d6000602084013e611292565b606091505b5091509150816112f25760405162461bcd60e51b815260206004820152602560248201527f6765745072696d617279526576656e756553706c69747328292063616c6c2066604482015264185a5b195960da1b60648201526084016107ae565b805160c08190036113095750600095945050505050565b806101000361131e5750600195945050505050565b60405162461bcd60e51b815260206004820152601e60248201527f556e657870656374656420726576656e75652073706c6974206279746573000060448201526064016107ae565b8260006113738888612b60565b905060038160048111156113895761138961527b565b146113a65760405162461bcd60e51b81526004016107ae906157e9565b6000806113b38a8a611c55565b5091509150816113d55760405162461bcd60e51b81526004016107ae9061581e565b808411156113f55760405162461bcd60e51b81526004016107ae90615848565b505050600061140488886110f0565b905060006114118261384e565b90506000805b8481101561151d5760008989838181106114335761143361587f565b90506020020160208101906114489190615895565b63ffffffff166000818152602087905260409020805491925090600160501b90046001600160a01b03168061148f5760405162461bcd60e51b81526004016107ae906158b0565b61149a8260016138b5565b806114ab57506114ab8260026138b5565b156114b857505050611515565b89156114e657336001600160a01b038216146114e65760405162461bcd60e51b81526004016107ae906158d8565b8154611504908f908f908990600160401b900461ffff16878e6138ce565b8461150e81615907565b9550505050505b600101611417565b50808360050160198282829054906101000a900462ffffff166115409190615929565b92506101000a81548162ffffff021916908362ffffff16021790555050505050505050505050565b6000806000806000806000806000806000806115848e8e612b60565b905060006115928f8f6110f0565b90508060060160009054906101000a900464ffffffffff1664ffffffffff169c5080600601600a9054906101000a900464ffffffffff1664ffffffffff169b508060060160129054906101000a90046001600160581b03166001600160581b03169a508060050160109054906101000a900462ffffff1662ffffff1699508060050160139054906101000a900462ffffff1662ffffff1698508060050160169054906101000a900462ffffff1662ffffff1697508060050160199054906101000a900462ffffff1662ffffff1696508060050160009054906101000a900461ffff1661ffff1695508060060160109054906101000a900460ff1694508060060160119054906101000a900460ff16935080600701600f9054906101000a900460ff169250509295989b509295989b509295989b565b6116d2838383613a28565b61170c5760405162461bcd60e51b815260206004820152600b60248201526a13db9b1e48105c9d1a5cdd60aa1b60448201526064016107ae565b505050565b600061171d85856110f0565b9050600161172b8686612b60565b600481111561173c5761173c61527b565b146117595760405162461bcd60e51b81526004016107ae90615945565b6006810154600160781b900460ff16156117b35760405162461bcd60e51b815260206004820152601b60248201527a273790383932bb34b7bab99030b236b4b71032bc3a32b739b4b7b760291b60448201526064016107ae565b6006810154600160281b810464ffffffffff908116600160501b90920416146117ee5760405162461bcd60e51b81526004016107ae90615970565b600681015464ffffffffff600160501b9091048116908416106118505760405162461bcd60e51b815260206004820152601a60248201527909edcd8f240e4cac8eac6ca40c2eac6e8d2dedc40d8cadccee8d60331b60448201526064016107ae565b600681015461186790839064ffffffffff166157ba565b8364ffffffffff161161188c5760405162461bcd60e51b81526004016107ae906156da565b428364ffffffffff16116118d95760405162461bcd60e51b81526020600482015260146024820152734f6e6c792066757475726520656e642074696d6560601b60448201526064016107ae565b600681018054600160281b600160781b031916600160501b64ffffffffff861690810264ffffffffff60281b191691909117600160281b919091021790556040516001600160a01b038516908690600080516020615da7833981519152906119429087906159a3565b60405180910390a35050505050565b600061195d87876110f0565b9050600161196b8888612b60565b600481111561197c5761197c61527b565b146119995760405162461bcd60e51b81526004016107ae90615945565b60068101546000906119bb90600160901b90046001600160581b031687611121565b9050808414611a0c5760405162461bcd60e51b815260206004820152601f60248201527f6d73672e76616c7565206d75737420657175616c20736c6f742076616c75650060448201526064016107ae565b600782018054859190600090611a2c9084906001600160781b03166159b5565b92506101000a8154816001600160781b0302191690836001600160781b031602179055508160050160139054906101000a900462ffffff1662ffffff16600003611a8657611a7a8888613ab1565b611a848888612d49565b505b6005820154600160801b900462ffffff1680611adb5760405162461bcd60e51b81526020600482015260146024820152732737903a37b5b2b7399034b71030bab1ba34b7b760611b60448201526064016107ae565b6005830154600160981b900462ffffff168111801590611c3a576000611b03858c8c89613b6c565b9050611b0f8188613d94565b611b545760405162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e74206269642076616c756560501b60448201526064016107ae565b6006850154600090600160801b900460ff168015611b9057506006860154611b8d9061012c90600160501b900464ffffffffff166159d5565b42115b90508015611c37576006860154611bcd90611bbc90610e1090600160281b900464ffffffffff166157ba565b611bc861012c426157ba565b613dea565b86600601600a6101000a81548164ffffffffff021916908364ffffffffff1602179055508a6001600160a01b03168c600080516020615da783398151915288600601600a9054906101000a900464ffffffffff16604051611c2e91906159a3565b60405180910390a35b50505b611c49848b8b8b8b6000613e00565b50505050505050505050565b600080600080611c6586866110f0565b90506000611c728261411f565b90506000611c80888861416c565b9050808211955085611c93576000611c9d565b611c9d81836159d5565b945085611cb357611cae82826159d5565b611cb6565b60005b93505050509250925092565b600080611ccf84846141d3565b54610100900462ffffff16949350505050565b600080611cef85856110f0565b90506000611cfd8686612b60565b90506003816004811115611d1357611d1361527b565b1480611d3057506004816004811115611d2e57611d2e61527b565b145b611d705760405162461bcd60e51b81526020600482015260116024820152704f6e6c792073746174652044206f72204560781b60448201526064016107ae565b6000611d7c8787611c55565b9250505060008111611dca5760405162461bcd60e51b815260206004820152601760248201527652656163686564206d617820696e766f636174696f6e7360481b60448201526064016107ae565b50506006810154600160901b90046001600160581b0316348114611e305760405162461bcd60e51b815260206004820152601f60248201527f4f6e6c792073656e642061756374696f6e20726573657276652070726963650060448201526064016107ae565b6040516117cd60e21b81526001600160a01b03851690615f3490611e5e908a908a908a9033906004016159e8565b6020604051808303816000875af1158015611e7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea19190615a13565b9250611eae8682876141fb565b846001600160a01b0316867fdfd0b295795ee66148297b0ff929867a78b799aca7c8def4666dfd1110e58070858a604051611eea929190615647565b60405180910390a35050949350505050565b611f08848484846143bc565b611f515760405162461bcd60e51b815260206004820152601a60248201527913db9b1e4810dbdc994810591b5a5b9050d308185b1b1bddd95960321b60448201526064016107ae565b50505050565b6000611f6384846110f0565b90506001611f718585612b60565b6004811115611f8257611f8261527b565b14611f9f5760405162461bcd60e51b81526004016107ae90615945565b6006810154600160281b810464ffffffffff908116600160501b9092041614611fda5760405162461bcd60e51b81526004016107ae90615970565b6006810154600090611ff7908490600160781b900460ff16615a2c565b905060488160ff16111561204b5760405162461bcd60e51b815260206004820152601b60248201527a09edcd8f240cadacae4cecadcc6f240d0deeae4e640d8e840dac2f602b1b60448201526064016107ae565b600061205c60ff8516610e10615a45565b600684015461207d9161ffff1690600160501b900464ffffffffff16615a63565b60068401805465ffffffffffff60501b1916600160781b60ff86160264ffffffffff60501b191617600160501b64ffffffffff84169081029190911764ffffffffff60281b1916600160281b919091021790556040519091506001600160a01b038616908790600080516020615da7833981519152906120fe9085906159a3565b60405180910390a3505050505050565b8061211761382a565b6001600160a01b03841660009081526001918201602052604090208054909160ff199091169083600281111561214f5761214f61527b565b0217905550816001600160a01b03167f7e87227cdb277003c1fb102daa540277f21bae680e463f9b0022e4726cb59ab08260405161218d919061553e565b60405180910390a25050565b60006121a588886110f0565b905060006121b28261384e565b90508560006121c18b8b612b60565b905060038160048111156121d7576121d761527b565b146121f45760405162461bcd60e51b81526004016107ae906157e9565b6121fd8461411f565b82111561221c5760405162461bcd60e51b81526004016107ae90615a81565b5060005b8181101561235b57600089898381811061223c5761223c61587f565b90506020020160208101906122519190615895565b63ffffffff166000818152602087905260409020805491925090600160501b90046001600160a01b0316806122985760405162461bcd60e51b81526004016107ae906158b0565b6122a38260016138b5565b806122b457506122b48260026138b5565b156122c157505050612353565b89156122ef57336001600160a01b038216146122ef5760405162461bcd60e51b81526004016107ae906158d8565b600587018054600160b01b900462ffffff1690601661230d83615907565b91906101000a81548162ffffff021916908362ffffff1602179055505061234f8e8e888560000160089054906101000a900461ffff1661ffff16878e8e614444565b5050505b600101612220565b5050505050505050505050565b612373858585613a28565b806123855750612385848484846143bc565b610d8d5760405162461bcd60e51b815260206004820152601d60248201527f4f6e6c7920417274697374206f7220436f72652041646d696e2041434c00000060448201526064016107ae565b60006001600160581b038211156124395760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201526538206269747360d01b60648201526084016107ae565b5090565b600061244988886110f0565b905060006124578989612b60565b60048111156124685761246861527b565b146124855760405162461bcd60e51b81526004016107ae90615705565b66b1a2bc2ec50000846001600160581b031610156124e45760405162461bcd60e51b815260206004820152601c60248201527b09edcd8f240c4c2e6ca40e0e4d2c6ca40cee8ca40605c606a408aa8960231b60448201526064016107ae565b428664ffffffffff16116125315760405162461bcd60e51b81526020600482015260146024820152734f6e6c79206675747572652061756374696f6e7360601b60448201526064016107ae565b600061253c88613357565b905060018160028111156125525761255261527b565b036125a957826125a45760405162461bcd60e51b815260206004820152601d60248201527f4f6e6c792061646d696e2d617274697374206d696e7420706572696f6400000060448201526064016107ae565b612610565b60028160028111156125bd576125bd61527b565b036126105782156126105760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79206e6f2061646d696e2d617274697374206d696e7420706572696f6460448201526064016107ae565b61261a8989613ab1565b868260060160006101000a81548164ffffffffff021916908364ffffffffff1602179055508582600601600a6101000a81548164ffffffffff021916908364ffffffffff160217905550858260060160056101000a81548164ffffffffff021916908364ffffffffff160217905550848260060160126101000a8154816001600160581b0302191690836001600160581b03160217905550838260060160106101000a81548160ff021916908315150217905550828260060160116101000a81548160ff02191690831515021790555060006126f68a8a612d49565b60058401805461ffff19166102001790556040805164ffffffffff8b811682528a1660208201526001600160581b038916918101919091528615156060820152851515608082015260a081018290529091506001600160a01b038a16908b907ff5182d65d8ff8a191c9e2f9f31fa4757a3e046c58e19c304b66f1766ec3993829060c00160405180910390a350505050505050505050565b600061279a83836110f0565b905060006127a88484612b60565b905060048160048111156127be576127be61527b565b146127fa5760405162461bcd60e51b815260206004820152600c60248201526b4f6e6c79207374617465204560a01b60448201526064016107ae565b6007820154600160781b900460ff16156128535760405162461bcd60e51b815260206004820152601a6024820152792932bb32b73ab2b99030b63932b0b23c903bb4ba34323930bbb760311b60448201526064016107ae565b60078201805460ff60781b1916600160781b17905560006128738361384e565b600584015490915060009061289490600160b01b900462ffffff16836157a3565b60078501805491925082916000906128b69084906001600160781b0316615ab8565b92506101000a8154816001600160781b0302191690836001600160781b031602179055506128e58682876141fb565b6040805177185d58dd1a5bdb94995d995b9d595cd0dbdb1b1958dd195960421b8152600160208201526001600160a01b0387169188917fbb5f9d4f49f83650956b76c40de0f082a06430bf0222e1b6b3f90a7a0f845c4d91016120fe565b61294b61511f565b6129558383611cc2565b62ffffff16602082015261296983836130e5565b1515815292915050565b600061297f8585612b60565b905060028160048111156129955761299561527b565b146129b25760405162461bcd60e51b81526004016107ae90615ad8565b6000806129bf8787611c55565b5091509150816129e15760405162461bcd60e51b81526004016107ae9061581e565b808562ffffff161115612a065760405162461bcd60e51b81526004016107ae90615848565b5050506000612a1585856110f0565b90506000612a228261384e565b6005830154600160401b9081900463ffffffff1660008181526020869052604081205493945090929190910461ffff16905b8662ffffff16811015612af45782600003612a8c57600585015461ffff16600081815260028701602052604090205493509150612aa4565b6000928352602085905260409092205463ffffffff16915b82600003612ada57612ac085612abb8460016157ba565b6144b8565b61ffff166000818152600287016020526040902054935091505b612aec8989868561ffff16878b6138ce565b600101612a54565b808560050160198282829054906101000a900462ffffff16612b169190615929565b92506101000a81548162ffffff021916908362ffffff160217905550828560050160086101000a81548163ffffffff021916908363ffffffff160217905550505050505050505050565b600080612b6d84846110f0565b600681015490915064ffffffffff1680158015904283119080612b8d5750805b15612b9f576000945050505050610991565b6006840154600160501b900464ffffffffff1642811080612bc95760019650505050505050610991565b600586015460009062ffffff600160981b8204811691612bfa91600160c81b8204811691600160b01b900416615929565b62ffffff161490508015612c18576004975050505050505050610991565b6006870154600090600160881b900460ff168015612c4f5750600588015462ffffff600160801b82048116600160981b9092041610155b8015612c665750612c636203f480856157ba565b42105b90508015612c7f57600298505050505050505050610991565b5060039a9950505050505050505050565b600080612c9d8585614573565b91509150808362ffffff161115612cc65760405162461bcd60e51b81526004016107ae90615afe565b818362ffffff161015612ceb5760405162461bcd60e51b81526004016107ae90615afe565b6000612cf786866141d3565b805462ffffff861685811463ffffffff19909216610100820260ff1916179190911782556040519081529091506001600160a01b038616908790600080516020615d87833981519152906020016120fe565b600080612d5684846110f0565b9050612d62848461416c565b60058201805462ffffff60801b1916600160801b62ffffff8416021790556040518181529092506001600160a01b0384169085907fe61b855b975f8c5d6051b121797e73a9c4e2b5fce1e570689013b3591427efa89060200160405180910390a35092915050565b6000612dd686866110f0565b90506000612de38261384e565b90506000612df18888612b60565b90506002816004811115612e0757612e0761527b565b14612e245760405162461bcd60e51b81526004016107ae90615ad8565b612e2d8361411f565b8662ffffff161115612e515760405162461bcd60e51b81526004016107ae90615a81565b506005820154600160201b900463ffffffff16600081815260208490526040812054600160401b900461ffff16905b8762ffffff16811015612f725782600003612ebe57600585015462010000900461ffff16600081815260018701602052604090205493509150612f5b565b600092835260208590526040832054600160201b900463ffffffff1692839003612f5b57612ef685612ef16001856159d5565b6145f1565b61ffff1691506102008210612f475760405162461bcd60e51b81526020600482015260176024820152761cdb1bdd081dda5d1a08189a59081b9bdd08199bdd5b99604a1b60448201526064016107ae565b600082815260018601602052604090205492505b612f6a8a8a8685878c8c614444565b600101612e80565b808560050160168282829054906101000a900462ffffff16612f949190615929565b92506101000a81548162ffffff021916908362ffffff160217905550828560050160046101000a81548163ffffffff021916908363ffffffff16021790555050505050505050505050565b600080612fec84846110f0565b600701546001600160781b0316949350505050565b600061300d87876110f0565b9050600061301b8888612b60565b905060028160048111156130315761303161527b565b148061304e5750600381600481111561304c5761304c61527b565b145b61308e5760405162461bcd60e51b815260206004820152601160248201527013db9b1e481cdd185d194810c81bdc8811607a1b60448201526064016107ae565b50600061309a8261384e565b90508460005b81811015611c49576130dd848b8b868c8c878181106130c1576130c161587f565b90506020020160208101906130d69190615895565b8b8b61468d565b6001016130a0565b6000806130f28484612b60565b905060008160048111156131085761310861527b565b0361315957600061311985856110f0565b600681015490915064ffffffffff1615613146576005810154600160801b900462ffffff16159250613153565b6131508585614760565b92505b506131b6565b600181600481111561316d5761316d61527b565b036131a357600061317e85856110f0565b6005015462ffffff600160801b82048116600160981b90920416101592506131b69050565b60006131af8585611c55565b1594505050505b5092915050565b60008060006131cc8585612b60565b905060006131da86866110f0565b905060008260048111156131f0576131f061527b565b0361326a57600681015464ffffffffff161515806132495760405162461bcd60e51b8152602060048201526016602482015275185d58dd1a5bdb881b9bdd0818dbdb999a59dd5c995960521b60448201526064016107ae565b506006810154600160901b90046001600160581b031693506000925061334e565b600581015462ffffff600160801b82048116600160981b909204161015600183600481111561329b5761329b61527b565b036132e95780156132c95760058201546132bc908890889061ffff16614779565b955061ffff16935061334c565b6006820154600160901b90046001600160581b031694506000935061334c565b80156133305760405162461bcd60e51b8152602060048201526016602482015275185d58dd1a5bdb88195b9919590b081cd95b1b1bdd5d60521b60448201526064016107ae565b6006820154600160901b90046001600160581b03169450600093505b505b50509250929050565b600061336161382a565b6001600160a01b03909216600090815260019290920160205250604090205460ff1690565b600080600061339585856110f0565b6005810154909150600160981b900462ffffff166133ea5760405162461bcd60e51b81526020600482015260126024820152712737903134b2399034b71030bab1ba34b7b760711b60448201526064016107ae565b600581015461ffff1660008181526002830160209081526040808320548352939052919091209590945092505050565b60008060006134298585612b60565b9050600061343786866110f0565b9050600082600481111561344d5761344d61527b565b0361348457600681015464ffffffffff16158015945061347f576006810154600160901b90046001600160581b031692505b61334e565b60058101546001945062ffffff600160801b82048116600160981b909204161015848360048111156134b8576134b861527b565b036134fe5780156134e25760058201546134d9908890889061ffff16614779565b945061334c9050565b6006820154600160901b90046001600160581b0316935061334c565b8015613533576006820154600583015461352c91600160901b90046001600160581b03169061ffff16611121565b935061334c565b50600601549295600160901b9093046001600160581b031694509192505050565b613560848484846143bc565b611f515760405162461bcd60e51b815260206004820152601a60248201527913db9b1e48135a5b9d195c919a5b1d195c8810591b5a5b9050d360321b60448201526064016107ae565b60006135b587876110f0565b63ffffffff86166000908152602082905260409020805491925090600160401b900461ffff1660016135e78a8a612b60565b60048111156135f8576135f861527b565b146136155760405162461bcd60e51b81526004016107ae90615945565b8154600160501b90046001600160a01b03166136705760405162461bcd60e51b815260206004820152601a60248201527942696420646e65202d207765726520796f75206f75746269643f60301b60448201526064016107ae565b81546001600160a01b03868116600160501b90920416146136d15760405162461bcd60e51b815260206004820152601b60248201527a13db9b1e48189a5919195c881bd988195e1a5cdd1a5b99c8189a59602a1b60448201526064016107ae565b60068301546000906136f390600160901b90046001600160581b031683611121565b905060006137188560060160129054906101000a90046001600160581b031689611121565b90508061372587846157ba565b1461376a5760405162461bcd60e51b8152602060048201526015602482015274696e636f72726563742061646465642076616c756560581b60448201526064016107ae565b505060078301805485919060009061378c9084906001600160781b03166159b5565b92506101000a8154816001600160781b0302191690836001600160781b031602179055506137c183828963ffffffff166147dc565b6137cf838a8a89898c613e00565b6040805163ffffffff8916815261ffff881660208201526001600160a01b038a16918b917fbcc60406b6a319d70c3feea7347029fbdfd768eecb981b0d2f6735b1e9633c5e91015b60405180910390a3505050505050505050565b7fa3fe13710cb596cbb938328f55db0dd5473d105cbcbbac73fbdbd94800043ab490565b600581015460009062ffffff600160801b82048116600160981b9092041610158061388d576006830154600160901b90046001600160581b0316610785565b6006830154600584015461078591600160901b90046001600160581b03169061ffff16611121565b815460009061098e90600160f01b900460ff1683614963565b60006138da87876110f0565b6000848152602082905260408120805492935091600160501b90046001600160a01b031690879061390b84826138b5565b6139425761391c8460006001614972565b50600684015460019061393f90600160901b90046001600160581b031689611121565b91505b61394f8460026001614972565b60078501805483919060009061396f9084906001600160781b0316615ab8565b92506101000a8154816001600160781b0302191690836001600160781b0316021790555061399e8383886149ce565b80156139d757896001600160a01b03168b600080516020615dc7833981519152896040516139ce91815260200190565b60405180910390a35b896001600160a01b03168b7fa59312996dc68b7f0224b341fed75d5afeb3bb20624107d37942d14f5942815689604051613a1391815260200190565b60405180910390a35050505050505050505050565b60405163a47d29cb60e01b8152600481018490526000906001600160a01b0384169063a47d29cb90602401602060405180830381865afa158015613a70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a94919061565e565b6001600160a01b0316826001600160a01b03161490509392505050565b6000613abd83836141d3565b9050613ac98383614a03565b15613ad85761170c8383614a36565b600080613ae58585614573565b84549193509150610100900462ffffff1681811115613b5157835483831463ffffffff1990911661010062ffffff85160260ff1916171784556040518281526001600160a01b038616908790600080516020615d878339815191529060200160405180910390a3613b64565b808310613b6457835460ff191660011784555b505050505050565b600584015461ffff16600081815260028601602052604081205490919080613bc05760405162461bcd60e51b81526020600482015260076024820152664e6f206269647360c81b60448201526064016107ae565b600081815260208881526040808320805461ffff8716855260028c01909352922063ffffffff82169081905560058a018054600160501b9093046001600160a01b031692600160981b900462ffffff16906013613c1c83615b2f565b91906101000a81548162ffffff021916908362ffffff160217905550508063ffffffff16600003613c945761ffff8516600081815260018c016020526040812055613c68908b90614ab0565b613c778a612abb876001615b4e565b60058b01805461ffff191661ffff92909216919091179055613cb8565b63ffffffff8116600090815260208b905260409020805463ffffffff60201b191690555b60068a0154613cd790600160901b90046001600160581b031686611121565b60078b0180549197508791600090613cf99084906001600160781b0316615ab8565b82546001600160781b039182166101009390930a928302919092021990911617905550600084815260208b90526040902080546001600160f81b0319169055613d438287896149ce565b876001600160a01b0316897f9d1a4511ddb5e2e227897ca79bbe1d71a9af123cd7c7bde8d2bcb292243310c986604051613d7f91815260200190565b60405180910390a35050505050949350505050565b60006706f05b59d3b20000831115613dc857612710613db58461280a6157a3565b613dbf919061577b565b82119050610991565b612710613dd7846129046157a3565b613de1919061577b565b90911192915050565b6000818310613df9578161098e565b5090919050565b63ffffffff8116158015613e4d57600587018054600c90613e2d90600160601b900463ffffffff16615b69565b91906101000a81548163ffffffff021916908363ffffffff160217905591505b60008760020160008661ffff1681526020019081526020016000205490506040518060a001604052808263ffffffff168152602001600063ffffffff1681526020018661ffff168152602001856001600160a01b03168152602001600060ff168152508860000160008563ffffffff16815260200190815260200160002060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548161ffff021916908361ffff160217905550606082015181600001600a6101000a8154816001600160a01b0302191690836001600160a01b03160217905550608082015181600001601e6101000a81548160ff021916908360ff1602179055509050508263ffffffff168860020160008761ffff1681526020019081526020016000208190555080600003613fdc5761ffff85166000908152600189016020526040902063ffffffff84169055614007565b6000818152602089905260409020805463ffffffff60201b1916600160201b63ffffffff8616021790555b600588018054600160981b900462ffffff1690601361402583615907565b91906101000a81548162ffffff021916908362ffffff16021790555050806000036140b557614058888661ffff16614b0b565b600588015461ffff90811690861610156140805760058801805461ffff191661ffff87161790555b600588015461ffff62010000909104811690861611156140b55760058801805463ffff000019166201000061ffff8816021790555b8115614115576040805161ffff8716815263ffffffff851660208201526001600160a01b038681168284015291519188169189917fd278a5272d5c4a1fbd78fd96e1dc404c29b3e6fc9a525421b777de714354f5a5919081900360600190a35b5050505050505050565b60058101546000906141469062ffffff600160c81b8204811691600160b01b900416615929565b60058301546141619190600160981b900462ffffff16615b82565b62ffffff1692915050565b600080600061417b8585614573565b91509150600061418b86866141d3565b80549091506000906141a8908490610100900462ffffff16613dea565b90508084106141be576000945050505050610991565b6141c884826159d5565b979650505050505050565b60007f73e3af67f35f30fb72bbaaf6cc07b987364ed643c93ba201702e213464e877ee6110fa565b8160000361420857505050565b600061421382614b5a565b905060008060008060008060008088156142b157604051638639415b60e01b8152600481018d9052602481018c90526001600160a01b038b1690638639415b9060440161010060405180830381865afa158015614274573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142989190615b9e565b969e50949c50929a509098509650945092509050614331565b604051638639415b60e01b8152600481018d9052602481018c90526001600160a01b038b1690638639415b9060440160c060405180830381865afa1580156142fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143219190615c26565b949c50929a509096509450925090505b8a828561433e898c6157ba565b61434891906157ba565b61435291906157ba565b1461439e5760405162461bcd60e51b815260206004820152601c60248201527b496e76616c696420726576656e75652073706c697420746f74616c7360201b60448201526064016107ae565b6143ae86868a8a88888888614ba8565b505050505050505050505050565b60405163230448b160e01b81526001600160a01b03848116600483015283811660248301526001600160e01b0319831660448301526000919086169063230448b1906064016020604051808303816000875af1158015614420573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074b9190615c8f565b600061445088886110f0565b600085815260208290526040902090915061446d81600180614972565b805461448f908a908a908890600160501b90046001600160a01b031688614e4a565b61449a8160006138b5565b6144ad576144ad828a8a89898c89614f0a565b505050505050505050565b6000806101ff8361ffff1611156144e15760405162461bcd60e51b81526004016107ae90615cac565b600060ff8461ffff1611156145165760048501546144ff9085614ffa565b9250905061450f610100826157ba565b9050614551565b60038501546145259085614ffa565b925090508161455157600485015461453e906000614ffa565b9250905061454e610100826157ba565b90505b816145625761020092505050610991565b91506109919050565b505092915050565b604051630ea5613f60e01b81526004810183905260009081906001600160a01b03841690630ea5613f9060240160c060405180830381865afa1580156145bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145e19190615ce2565b5093989297509195505050505050565b6000806101ff8361ffff16111561461a5760405162461bcd60e51b81526004016107ae90615cac565b60006101008461ffff1610156146425760038501546146399085615060565b92509050614551565b60048501546146519085615060565b92509050614661610100826157ba565b9050816145515760038501546146789060ff615060565b92509050816145625761020092505050610991565b63ffffffff8316600090815260208890526040902080546001600160a01b03848116600160501b90920416146146f35760405162461bcd60e51b815260206004820152600b60248201526a27b7363c903134b23232b960a91b60448201526064016107ae565b6146fe8160006138b5565b156147415760405162461bcd60e51b815260206004820152601360248201527213db9b1e481d5b8b5cd95d1d1b195908189a59606a1b60448201526064016107ae565b805461411590899089908990600160401b900461ffff16888a88614f0a565b60008061476d84846141d3565b5460ff16949350505050565b600080600061478886866110f0565b6006810154909150600160901b90046001600160581b031660006147ac8287611121565b9050855b6001016147bd8382611121565b94506147c98286613d94565b156147b057989397509295505050505050565b60008181526020849052604081208054909163ffffffff80831692600160201b9004169082900361482a5761ffff85166000908152600187016020526040902063ffffffff8216905561485e565b63ffffffff80831660009081526020889052604090208054918316600160201b0263ffffffff60201b199092169190911790555b8063ffffffff1660000361488f5761ffff85166000908152600287016020526040902063ffffffff831690556148b8565b63ffffffff8181166000908152602088905260409020805463ffffffff19169184169190911790555b600586018054600160981b900462ffffff169060136148d683615b2f565b91906101000a81548162ffffff021916908362ffffff160217905550508163ffffffff16600014801561490d575063ffffffff8116155b15613b6457614920868661ffff16614ab0565b600586015461ffff808716911603613b645761494186612abb876001615b4e565b60058701805461ffff9290921661ffff19909216919091179055505050505050565b600160ff919091161b16151590565b80156149af578254600160ff8481169190911b600160f01b90920416175b835460ff91909116600160f01b0260ff60f01b19909116178355505050565b825461499090600160f01b900460ff1683600160ff919091161b191690565b600080600080858786f161170c57826000526073600b5360ff6020536016600b83f061170c57620f42405a1161170c57600080fd5b600080614a1084846141d3565b8054909150610100900462ffffff16158015614a2e5750805460ff16155b949350505050565b600080614a438484614573565b915091506000614a5385856141d3565b9050614a5e826150bb565b815460ff1962ffffff92909216610100029190911663ffffffff19909116178383141781556040516001600160a01b038516908690600080516020615d87833981519152906119429086815260200190565b6102008110614ad15760405162461bcd60e51b81526004016107ae9061572f565b610100811015614af3576003820154600160ff83161b19165b60038301555050565b6004820154600160ff83161b19165b60048301555050565b6102008110614b2c5760405162461bcd60e51b81526004016107ae9061572f565b610100811015614b48576003820154600160ff83161b17614aea565b6004820154600160ff83161b17614b02565b600080614b66836111b7565b8054909150610100900460ff1615614b82575460ff1692915050565b6000614b8d846111f0565b825481151561ffff1990911617610100179092555092915050565b8715614c53576000876001600160a01b03168960405160006040518083038185875af1925050503d8060008114614bfb576040519150601f19603f3d011682016040523d82523d6000602084013e614c00565b606091505b5050905080614c515760405162461bcd60e51b815260206004820181905260248201527f506c6174666f726d2050726f7669646572207061796d656e74206661696c656460448201526064016107ae565b505b8515614cfe576000856001600160a01b03168760405160006040518083038185875af1925050503d8060008114614ca6576040519150601f19603f3d011682016040523d82523d6000602084013e614cab565b606091505b5050905080614cfc5760405162461bcd60e51b815260206004820152601e60248201527f52656e6465722050726f7669646572207061796d656e74206661696c6564000060448201526064016107ae565b505b8315614da1576000836001600160a01b03168560405160006040518083038185875af1925050503d8060008114614d51576040519150601f19603f3d011682016040523d82523d6000602084013e614d56565b606091505b5050905080614d9f5760405162461bcd60e51b8152602060048201526015602482015274105c9d1a5cdd081c185e5b595b9d0819985a5b1959605a1b60448201526064016107ae565b505b8115614115576000816001600160a01b03168360405160006040518083038185875af1925050503d8060008114614df4576040519150601f19603f3d011682016040523d82523d6000602084013e614df9565b606091505b50509050806144ad5760405162461bcd60e51b815260206004820152601f60248201527f4164646974696f6e616c205061796565207061796d656e74206661696c65640060448201526064016107ae565b6040516117cd60e21b81526000906001600160a01b03831690615f3490614e7b9086908a908a9033906004016159e8565b6020604051808303816000875af1158015614e9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614ebe9190615a13565b6040805163ffffffff87168152602081018390529192506001600160a01b0387169188917f3c81bf6062ef45a4f3a4407699b008e79d9310eb22ba240838820f37535a928591016120fe565b63ffffffff8316600090815260208890526040812090614f2d9082906001614972565b600083614f518a60060160129054906101000a90046001600160581b031688611121565b614f5b91906159d5565b90508015614fc957600789018054829190600090614f839084906001600160781b0316615ab8565b92506101000a8154816001600160781b0302191690836001600160781b03160217905550614fc982600001600a9054906101000a90046001600160a01b031682856149ce565b60405163ffffffff861681526001600160a01b038816908990600080516020615dc783398151915290602001613817565b6000808260ff1684901c600003615017575060ff90506000615059565b8260ff1691505b60ff8210801561503557506150338483614963565b155b1561504c578161504481615d3d565b92505061501e565b6150568483614963565b90505b9250929050565b60008061506e8360ff615d56565b60ff1684901b60000361508657506000905080615059565b8260ff1691505b6000821180156150a457506150a28483614963565b155b1561504c57816150b381615d6f565b92505061508d565b600062ffffff8211156124395760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203260448201526534206269747360d01b60648201526084016107ae565b604080518082019091526000808252602082015290565b6001600160a01b038116811461514b57600080fd5b50565b803561ffff8116811461516057600080fd5b919050565b60008060006060848603121561517a57600080fd5b83359250602084013561518c81615136565b915061519a6040850161514e565b90509250925092565b6000602082840312156151b557600080fd5b813561078581615136565b600080600080606085870312156151d657600080fd5b8435935060208501356151e881615136565b925060408501356001600160401b038082111561520457600080fd5b818701915087601f83011261521857600080fd5b81358181111561522757600080fd5b8860208260051b850101111561523c57600080fd5b95989497505060200194505050565b6000806040838503121561525e57600080fd5b82359150602083013561527081615136565b809150509250929050565b634e487b7160e01b600052602160045260246000fd5b6000610180820190508d82528c60208301528b60408301528a60608301528960808301528860a08301528760c08301528660e0830152851515610100830152841515610120830152831515610140830152600583106152f2576152f261527b565b826101608301529d9c50505050505050505050505050565b803564ffffffffff8116811461516057600080fd5b60008060006060848603121561533457600080fd5b83359250602084013561534681615136565b915061519a6040850161530a565b60008060006060848603121561536957600080fd5b833561537481615136565b925060208401359150604084013561538b81615136565b809150509250925092565b6000806000606084860312156153ab57600080fd5b8335925060208401356153bd81615136565b9150604084013560ff8116811461538b57600080fd5b600080604083850312156153e657600080fd5b82356153f181615136565b915060208301356003811061527057600080fd5b801515811461514b57600080fd5b600080600080600080600060e0888a03121561542e57600080fd5b87359650602088013561544081615136565b955061544e6040890161530a565b945061545c6060890161530a565b93506080880135925060a088013561547381615405565b915060c088013561548381615405565b8091505092959891949750929550565b803562ffffff8116811461516057600080fd5b6000806000606084860312156154bb57600080fd5b8335925060208401356154cd81615136565b915061519a60408501615493565b60005b838110156154f65781810151838201526020016154de565b50506000910152565b600081518084526155178160208601602086016154db565b601f01601f19169290920160200192915050565b60208152600061098e60208301846154ff565b60208101600383106155525761555261527b565b91905290565b841515815283602082015260806040820152600061557960808301856154ff565b905060018060a01b038316606083015295945050505050565b6000602082840312156155a457600080fd5b61098e82615493565b803563ffffffff8116811461516057600080fd5b600080600080608085870312156155d757600080fd5b8435935060208501356155e981615136565b92506155f7604086016155ad565b91506156056060860161514e565b905092959194509250565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b9182526001600160a01b0316602082015260400190565b60006020828403121561567057600080fd5b815161078581615136565b6020808252601190820152704d696e746572206e6f742061637469766560781b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b64ffffffffff8281168282160390808211156131b6576131b66156a6565b602080825260119082015270105d58dd1a5bdb881d1bdbc81cda1bdc9d607a1b604082015260600190565b60208082526010908201526f27b7363c9038393296b0bab1ba34b7b760811b604082015260600190565b6020808252601c908201527b4f6e6c7920736c6f7420696e646578206c74204e554d5f534c4f545360201b604082015260600190565b634e487b7160e01b600052601260045260246000fd5b60008261578a5761578a615765565b500490565b60008261579e5761579e615765565b500690565b8082028115828204841417610991576109916156a6565b80820180821115610991576109916156a6565b600082516157df8184602087016154db565b9190910192915050565b6020808252601b908201527a13db9b1e481c1bdcdd0b585d58dd1a5bdb881bdc195b881b5a5b9d602a1b604082015260600190565b60208082526010908201526f4f6e6c7920696e20737461746520453160801b604082015260600190565b6020808252601f908201527f6269647320746f20726566756e6420677420617661696c61626c652071747900604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156158a757600080fd5b61098e826155ad565b6020808252600e908201526d1a5b9d985b1a5908109a5908125160921b604082015260600190565b60208082526015908201527427b7363c9039b2b73232b91034b9903134b23232b960591b604082015260600190565b600062ffffff80831681810361591f5761591f6156a6565b6001019392505050565b62ffffff8181168382160190808211156131b6576131b66156a6565b60208082526011908201527027b7363c903634bb329030bab1ba34b7b760791b604082015260600190565b6020808252601990820152784e6f7420616c6c6f77656420696e2065787472612074696d6560381b604082015260600190565b64ffffffffff91909116815260200190565b6001600160781b038181168382160190808211156131b6576131b66156a6565b81810381811115610991576109916156a6565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b600060208284031215615a2557600080fd5b5051919050565b60ff8181168382160190811115610991576109916156a6565b61ffff81811683821602808216919082811461456b5761456b6156a6565b64ffffffffff8181168382160190808211156131b6576131b66156a6565b6020808252601d908201527f746f6b656e7320746f206d696e7420677420746f6b656e73206f776564000000604082015260600190565b6001600160781b038281168282160390808211156131b6576131b66156a6565b6020808252600c908201526b4f6e6c79207374617465204360a01b604082015260600190565b602080825260179082015276496e76616c6964206d617820696e766f636174696f6e7360481b604082015260600190565b600062ffffff821680615b4457615b446156a6565b6000190192915050565b61ffff8181168382160190808211156131b6576131b66156a6565b600063ffffffff80831681810361591f5761591f6156a6565b62ffffff8281168282160390808211156131b6576131b66156a6565b600080600080600080600080610100898b031215615bbb57600080fd5b885197506020890151615bcd81615136565b60408a015160608b01519198509650615be581615136565b60808a015160a08b01519196509450615bfd81615136565b60c08a015160e08b01519194509250615c1581615136565b809150509295985092959890939650565b60008060008060008060c08789031215615c3f57600080fd5b865195506020870151615c5181615136565b604088015160608901519196509450615c6981615136565b608088015160a08901519194509250615c8181615136565b809150509295509295509295565b600060208284031215615ca157600080fd5b815161078581615405565b6020808252601c908201527b27b7363c9039ba30b93a1039b637ba1034b73232bc10363a101a989960211b604082015260600190565b60008060008060008060c08789031215615cfb57600080fd5b86519550602087015194506040870151615d1481615405565b6060880151909450615d2581615405565b608088015160a08901519194509250615c8181615405565b600060018201615d4f57615d4f6156a6565b5060010190565b60ff8281168282160390811115610991576109916156a6565b600081615d7e57615d7e6156a6565b50600019019056fe1c3e74a6c6fefbaeee166b031cd2016349c6c863d5188b67c9bbd0b0dcb2e237520e05d2a73ab549525f701daae4d8ac1897891bb1afca813602709aafc7a830e152fe384870d25a8d821270b8b8043fada748f138ab7f8512af64c65c726136a26469706673582212201be61649a635efb061b2ea27baa094eaa05101acc5df025a1d0875c9f9be0d3c64736f6c63430008160033000000000000000000000000a2ccfe293bc2cdd78d8166a82d1e18cd2148122b
Deployed Bytecode
0x60806040526004361061019e5760003560e01c806241673c146101a357806301000da7146101d6578063014053a014610206578063047fef49146102285780631290b96b1461026057806317e70c3c1461028057806340b790bd146102935780634869f3df146102ca5780634e8d8787146102ea57806363076680146102fd57806365e92cde1461034c57806366133e291461036c578063711ce3911461038c5780637ca340a6146103ac5780637e86d370146103cc5780638f13865e146103ec5780638fe8a90b1461040c5780639a94488a1461042c5780639b7b55851461046e578063a5514c7e14610484578063ae77c237146104a4578063b000e334146104b7578063b9daf3b5146104d7578063bf54d5fb146104f7578063c1b9281e14610517578063cce7c90914610537578063d009cb9d14610557578063d3ddabe61461058c578063d4f6d0e3146105cb578063d8b4e3ba146105f8578063d9bffbce14610618578063d9eb16db14610638578063dd85582f14610668578063e624db9f146106b4578063e9d1e8ac146106d4578063f5a759b71461070b575b600080fd5b3480156101af57600080fd5b506101c36101be366004615165565b61071e565b6040519081526020015b60405180910390f35b3480156101e257600080fd5b506101f66101f13660046151a3565b610754565b60405190151581526020016101cd565b34801561021257600080fd5b506102266102213660046151c0565b61078c565b005b34801561023457600080fd5b5061024861024336600461524b565b6107e2565b6040516101cd9c9b9a99989796959493929190615291565b34801561026c57600080fd5b5061022661027b36600461531f565b610826565b61022661028e366004615165565b610870565b34801561029f57600080fd5b506102b36102ae36600461524b565b610969565b6040805192151583526020830191909152016101cd565b3480156102d657600080fd5b506101c36102e536600461524b565b610982565b6101c36102f8366004615354565b610997565b34801561030957600080fd5b5060015460408051610258815261012c6020820152610e1091810191909152604860608201526203f480608082015262ffffff90911660a082015260c0016101cd565b34801561035857600080fd5b50610226610367366004615396565b6109f9565b34801561037857600080fd5b506102266103873660046153d3565b610a3e565b34801561039857600080fd5b506102266103a73660046151c0565b610a5f565b3480156103b857600080fd5b506102266103c73660046151c0565b610ac3565b3480156103d857600080fd5b506102266103e7366004615413565b610b3c565b3480156103f857600080fd5b506102266104073660046151c0565b610bc5565b34801561041857600080fd5b5061022661042736600461524b565b610c1c565b34801561043857600080fd5b5061044c61044736600461524b565b610c6a565b6040805182511515815260209283015162ffffff1692810192909252016101cd565b34801561047a57600080fd5b506101c361025881565b34801561049057600080fd5b5061022661049f3660046154a6565b610c7c565b6101c36104b236600461524b565b610ccd565b3480156104c357600080fd5b506102266104d23660046154a6565b610d2e565b3480156104e357600080fd5b506102266104f23660046154a6565b610d94565b34801561050357600080fd5b506101c361051236600461524b565b610e08565b34801561052357600080fd5b506102266105323660046151c0565b610e14565b34801561054357600080fd5b506101f661055236600461524b565b610e56565b34801561056357600080fd5b5061057761057236600461524b565b610e62565b604080519283526020830191909152016101cd565b34801561059857600080fd5b506105be60405180604001604052806006815260200165076302e302e360d41b81525081565b6040516101cd919061552b565b3480156105d757600080fd5b506105eb6105e63660046151a3565b610e7a565b6040516101cd919061553e565b34801561060457600080fd5b506101c361061336600461524b565b610e85565b34801561062457600080fd5b5061022661063336600461524b565b610ec1565b34801561064457600080fd5b5061065861065336600461524b565b610f00565b6040516101cd9493929190615558565b34801561067457600080fd5b5061069c7f000000000000000000000000a2ccfe293bc2cdd78d8166a82d1e18cd2148122b81565b6040516001600160a01b0390911681526020016101cd565b3480156106c057600080fd5b506102266106cf366004615592565b610f3d565b3480156106e057600080fd5b506105be6040518060400160405280600b81526020016a04d696e74657252414d56360ac1b81525081565b6102266107193660046155c1565b611004565b60008061072b85856110f0565b60060154600160901b90046001600160581b0316905061074b8184611121565b95945050505050565b600080610760836111b7565b8054909150610100900460ff161561077c575460ff1692915050565b610785836111f0565b9392505050565b6002600054036107b75760405162461bcd60e51b81526004016107ae90615610565b60405180910390fd5b6002600055600180546107d79186918691869186919062ffffff16611366565b505060016000555050565b6000806000806000806000806000806000806107fe8e8e611568565b9b509b509b509b509b509b509b509b509b509b509b509b509295989b509295989b509295989b565b6002600054036108485760405162461bcd60e51b81526004016107ae90615610565b60026000556108588383336116c7565b610866838383610258611711565b5050600160005550565b6002600054036108925760405162461bcd60e51b81526004016107ae90615610565b6002600055604051635845de1f60e01b815230907f000000000000000000000000a2ccfe293bc2cdd78d8166a82d1e18cd2148122b6001600160a01b031690635845de1f906108e79087908790600401615647565b602060405180830381865afa158015610904573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610928919061565e565b6001600160a01b03161461094e5760405162461bcd60e51b81526004016107ae9061567b565b600154610866908490849084903390349062ffffff16611951565b6000806109768484611c55565b50909590945092505050565b600061098e8383611cc2565b90505b92915050565b60006002600054036109bb5760405162461bcd60e51b81526004016107ae90615610565b60026000556109ec8484847f000000000000000000000000a2ccfe293bc2cdd78d8166a82d1e18cd2148122b611ce2565b6001600055949350505050565b600260005403610a1b5760405162461bcd60e51b81526004016107ae90615610565b6002600055610a338233306332f4966f60e11b611efc565b610866838383611f57565b610a518233306366133e2960e01b611efc565b610a5b828261210e565b5050565b600260005403610a815760405162461bcd60e51b81526004016107ae90615610565b6002600055600180546107d7918691869186918691907f000000000000000000000000a2ccfe293bc2cdd78d8166a82d1e18cd2148122b9062ffffff16612199565b600260005403610ae55760405162461bcd60e51b81526004016107ae90615610565b6002600055610afe84843330633e51a05360e11b612368565b6001546107d79085908590859085906000907f000000000000000000000000a2ccfe293bc2cdd78d8166a82d1e18cd2148122b9062ffffff16612199565b600260005403610b5e5760405162461bcd60e51b81526004016107ae90615610565b6002600055610b6e8787336116c7565b610258610b7b86866156bc565b64ffffffffff161015610ba05760405162461bcd60e51b81526004016107ae906156da565b610bb787878787610bb0886123d1565b878761243d565b505060016000555050505050565b600260005403610be75760405162461bcd60e51b81526004016107ae90615610565b6002600055610c0084843330634789c32f60e11b612368565b6001546107d790859085908590859060009062ffffff16611366565b600260005403610c3e5760405162461bcd60e51b81526004016107ae90615610565b6002600055610c5782823330638fe8a90b60e01b612368565b610c61828261278e565b50506001600055565b610c7261511f565b61098e8383612943565b600260005403610c9e5760405162461bcd60e51b81526004016107ae90615610565b6002600055610cb68233306352a8a63f60e11b611efc565b6001546108669084908490849062ffffff16612973565b6000600260005403610cf15760405162461bcd60e51b81526004016107ae90615610565b6002600055610d223384847f000000000000000000000000a2ccfe293bc2cdd78d8166a82d1e18cd2148122b611ce2565b60016000559392505050565b610d398383336116c7565b6000610d458484612b60565b90506000816004811115610d5b57610d5b61527b565b14610d785760405162461bcd60e51b81526004016107ae90615705565b610d83848484612c90565b610d8d8484612d49565b5050505050565b600260005403610db65760405162461bcd60e51b81526004016107ae90615610565b6002600055610dcf8383333063b9daf3b560e01b612368565b600154610866908490849084907f000000000000000000000000a2ccfe293bc2cdd78d8166a82d1e18cd2148122b9062ffffff16612dca565b600061098e8383612fdf565b600260005403610e365760405162461bcd60e51b81526004016107ae90615610565b60026000556001546107d7908590859085908590339062ffffff16613001565b600061098e83836130e5565b600080610e6f84846131bd565b909590945092505050565b600061099182613357565b600080610e928484613386565b9150506000610ea185856110f0565b60060154600160901b90046001600160581b0316905061074b8183611121565b60405162461bcd60e51b81526020600482015260146024820152731058dd1a5bdb881b9bdd081cdd5c1c1bdc9d195960621b60448201526064016107ae565b60008060606000610f11868661341a565b60408051808201909152600381526208aa8960eb1b602082015291989097509095506000945092505050565b610f707f000000000000000000000000a2ccfe293bc2cdd78d8166a82d1e18cd2148122b333063e624db9f60e01b613554565b611b588162ffffff161015610fb85760405162461bcd60e51b815260206004820152600e60248201526d04f6e6c792067746520375f3030360941b60448201526064016107ae565b6001805462ffffff191662ffffff83169081179091556040519081527ff28602592f2788507e76a86523ec8d5ef26873807e258d4cae31571370c0e6c89060200160405180910390a150565b6002600054036110265760405162461bcd60e51b81526004016107ae90615610565b6002600055604051635845de1f60e01b815230907f000000000000000000000000a2ccfe293bc2cdd78d8166a82d1e18cd2148122b6001600160a01b031690635845de1f9061107b9088908890600401615647565b602060405180830381865afa158015611098573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110bc919061565e565b6001600160a01b0316146110e25760405162461bcd60e51b81526004016107ae9061567b565b6107d78484848433346135a9565b60006110fa61382a565b6001600160a01b039290921660009081526020928352604080822094825293909252502090565b60006102008261ffff16106111485760405162461bcd60e51b81526004016107ae9061572f565b611155600861020061577b565b6111639061ffff841661577b565b6001600160581b038416901b905061117e600861020061577b565b61118b600861020061577b565b6111999061ffff851661578f565b6111a390836157a3565b6111ad919061577b565b61098e90826157ba565b6001600160a01b031660009081527f69f22dd730b53ff235fa96b4306a31bef5dad48fe4bac28b1ceebbce14401b396020526040902090565b6040516000602482018190526044820181905290819060640160408051601f198184030181529181526020820180516001600160e01b0316638639415b60e01b1790525190915060009081906001600160a01b038616906112529085906157cd565b600060405180830381855afa9150503d806000811461128d576040519150601f19603f3d011682016040523d82523d6000602084013e611292565b606091505b5091509150816112f25760405162461bcd60e51b815260206004820152602560248201527f6765745072696d617279526576656e756553706c69747328292063616c6c2066604482015264185a5b195960da1b60648201526084016107ae565b805160c08190036113095750600095945050505050565b806101000361131e5750600195945050505050565b60405162461bcd60e51b815260206004820152601e60248201527f556e657870656374656420726576656e75652073706c6974206279746573000060448201526064016107ae565b8260006113738888612b60565b905060038160048111156113895761138961527b565b146113a65760405162461bcd60e51b81526004016107ae906157e9565b6000806113b38a8a611c55565b5091509150816113d55760405162461bcd60e51b81526004016107ae9061581e565b808411156113f55760405162461bcd60e51b81526004016107ae90615848565b505050600061140488886110f0565b905060006114118261384e565b90506000805b8481101561151d5760008989838181106114335761143361587f565b90506020020160208101906114489190615895565b63ffffffff166000818152602087905260409020805491925090600160501b90046001600160a01b03168061148f5760405162461bcd60e51b81526004016107ae906158b0565b61149a8260016138b5565b806114ab57506114ab8260026138b5565b156114b857505050611515565b89156114e657336001600160a01b038216146114e65760405162461bcd60e51b81526004016107ae906158d8565b8154611504908f908f908990600160401b900461ffff16878e6138ce565b8461150e81615907565b9550505050505b600101611417565b50808360050160198282829054906101000a900462ffffff166115409190615929565b92506101000a81548162ffffff021916908362ffffff16021790555050505050505050505050565b6000806000806000806000806000806000806115848e8e612b60565b905060006115928f8f6110f0565b90508060060160009054906101000a900464ffffffffff1664ffffffffff169c5080600601600a9054906101000a900464ffffffffff1664ffffffffff169b508060060160129054906101000a90046001600160581b03166001600160581b03169a508060050160109054906101000a900462ffffff1662ffffff1699508060050160139054906101000a900462ffffff1662ffffff1698508060050160169054906101000a900462ffffff1662ffffff1697508060050160199054906101000a900462ffffff1662ffffff1696508060050160009054906101000a900461ffff1661ffff1695508060060160109054906101000a900460ff1694508060060160119054906101000a900460ff16935080600701600f9054906101000a900460ff169250509295989b509295989b509295989b565b6116d2838383613a28565b61170c5760405162461bcd60e51b815260206004820152600b60248201526a13db9b1e48105c9d1a5cdd60aa1b60448201526064016107ae565b505050565b600061171d85856110f0565b9050600161172b8686612b60565b600481111561173c5761173c61527b565b146117595760405162461bcd60e51b81526004016107ae90615945565b6006810154600160781b900460ff16156117b35760405162461bcd60e51b815260206004820152601b60248201527a273790383932bb34b7bab99030b236b4b71032bc3a32b739b4b7b760291b60448201526064016107ae565b6006810154600160281b810464ffffffffff908116600160501b90920416146117ee5760405162461bcd60e51b81526004016107ae90615970565b600681015464ffffffffff600160501b9091048116908416106118505760405162461bcd60e51b815260206004820152601a60248201527909edcd8f240e4cac8eac6ca40c2eac6e8d2dedc40d8cadccee8d60331b60448201526064016107ae565b600681015461186790839064ffffffffff166157ba565b8364ffffffffff161161188c5760405162461bcd60e51b81526004016107ae906156da565b428364ffffffffff16116118d95760405162461bcd60e51b81526020600482015260146024820152734f6e6c792066757475726520656e642074696d6560601b60448201526064016107ae565b600681018054600160281b600160781b031916600160501b64ffffffffff861690810264ffffffffff60281b191691909117600160281b919091021790556040516001600160a01b038516908690600080516020615da7833981519152906119429087906159a3565b60405180910390a35050505050565b600061195d87876110f0565b9050600161196b8888612b60565b600481111561197c5761197c61527b565b146119995760405162461bcd60e51b81526004016107ae90615945565b60068101546000906119bb90600160901b90046001600160581b031687611121565b9050808414611a0c5760405162461bcd60e51b815260206004820152601f60248201527f6d73672e76616c7565206d75737420657175616c20736c6f742076616c75650060448201526064016107ae565b600782018054859190600090611a2c9084906001600160781b03166159b5565b92506101000a8154816001600160781b0302191690836001600160781b031602179055508160050160139054906101000a900462ffffff1662ffffff16600003611a8657611a7a8888613ab1565b611a848888612d49565b505b6005820154600160801b900462ffffff1680611adb5760405162461bcd60e51b81526020600482015260146024820152732737903a37b5b2b7399034b71030bab1ba34b7b760611b60448201526064016107ae565b6005830154600160981b900462ffffff168111801590611c3a576000611b03858c8c89613b6c565b9050611b0f8188613d94565b611b545760405162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e74206269642076616c756560501b60448201526064016107ae565b6006850154600090600160801b900460ff168015611b9057506006860154611b8d9061012c90600160501b900464ffffffffff166159d5565b42115b90508015611c37576006860154611bcd90611bbc90610e1090600160281b900464ffffffffff166157ba565b611bc861012c426157ba565b613dea565b86600601600a6101000a81548164ffffffffff021916908364ffffffffff1602179055508a6001600160a01b03168c600080516020615da783398151915288600601600a9054906101000a900464ffffffffff16604051611c2e91906159a3565b60405180910390a35b50505b611c49848b8b8b8b6000613e00565b50505050505050505050565b600080600080611c6586866110f0565b90506000611c728261411f565b90506000611c80888861416c565b9050808211955085611c93576000611c9d565b611c9d81836159d5565b945085611cb357611cae82826159d5565b611cb6565b60005b93505050509250925092565b600080611ccf84846141d3565b54610100900462ffffff16949350505050565b600080611cef85856110f0565b90506000611cfd8686612b60565b90506003816004811115611d1357611d1361527b565b1480611d3057506004816004811115611d2e57611d2e61527b565b145b611d705760405162461bcd60e51b81526020600482015260116024820152704f6e6c792073746174652044206f72204560781b60448201526064016107ae565b6000611d7c8787611c55565b9250505060008111611dca5760405162461bcd60e51b815260206004820152601760248201527652656163686564206d617820696e766f636174696f6e7360481b60448201526064016107ae565b50506006810154600160901b90046001600160581b0316348114611e305760405162461bcd60e51b815260206004820152601f60248201527f4f6e6c792073656e642061756374696f6e20726573657276652070726963650060448201526064016107ae565b6040516117cd60e21b81526001600160a01b03851690615f3490611e5e908a908a908a9033906004016159e8565b6020604051808303816000875af1158015611e7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea19190615a13565b9250611eae8682876141fb565b846001600160a01b0316867fdfd0b295795ee66148297b0ff929867a78b799aca7c8def4666dfd1110e58070858a604051611eea929190615647565b60405180910390a35050949350505050565b611f08848484846143bc565b611f515760405162461bcd60e51b815260206004820152601a60248201527913db9b1e4810dbdc994810591b5a5b9050d308185b1b1bddd95960321b60448201526064016107ae565b50505050565b6000611f6384846110f0565b90506001611f718585612b60565b6004811115611f8257611f8261527b565b14611f9f5760405162461bcd60e51b81526004016107ae90615945565b6006810154600160281b810464ffffffffff908116600160501b9092041614611fda5760405162461bcd60e51b81526004016107ae90615970565b6006810154600090611ff7908490600160781b900460ff16615a2c565b905060488160ff16111561204b5760405162461bcd60e51b815260206004820152601b60248201527a09edcd8f240cadacae4cecadcc6f240d0deeae4e640d8e840dac2f602b1b60448201526064016107ae565b600061205c60ff8516610e10615a45565b600684015461207d9161ffff1690600160501b900464ffffffffff16615a63565b60068401805465ffffffffffff60501b1916600160781b60ff86160264ffffffffff60501b191617600160501b64ffffffffff84169081029190911764ffffffffff60281b1916600160281b919091021790556040519091506001600160a01b038616908790600080516020615da7833981519152906120fe9085906159a3565b60405180910390a3505050505050565b8061211761382a565b6001600160a01b03841660009081526001918201602052604090208054909160ff199091169083600281111561214f5761214f61527b565b0217905550816001600160a01b03167f7e87227cdb277003c1fb102daa540277f21bae680e463f9b0022e4726cb59ab08260405161218d919061553e565b60405180910390a25050565b60006121a588886110f0565b905060006121b28261384e565b90508560006121c18b8b612b60565b905060038160048111156121d7576121d761527b565b146121f45760405162461bcd60e51b81526004016107ae906157e9565b6121fd8461411f565b82111561221c5760405162461bcd60e51b81526004016107ae90615a81565b5060005b8181101561235b57600089898381811061223c5761223c61587f565b90506020020160208101906122519190615895565b63ffffffff166000818152602087905260409020805491925090600160501b90046001600160a01b0316806122985760405162461bcd60e51b81526004016107ae906158b0565b6122a38260016138b5565b806122b457506122b48260026138b5565b156122c157505050612353565b89156122ef57336001600160a01b038216146122ef5760405162461bcd60e51b81526004016107ae906158d8565b600587018054600160b01b900462ffffff1690601661230d83615907565b91906101000a81548162ffffff021916908362ffffff1602179055505061234f8e8e888560000160089054906101000a900461ffff1661ffff16878e8e614444565b5050505b600101612220565b5050505050505050505050565b612373858585613a28565b806123855750612385848484846143bc565b610d8d5760405162461bcd60e51b815260206004820152601d60248201527f4f6e6c7920417274697374206f7220436f72652041646d696e2041434c00000060448201526064016107ae565b60006001600160581b038211156124395760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201526538206269747360d01b60648201526084016107ae565b5090565b600061244988886110f0565b905060006124578989612b60565b60048111156124685761246861527b565b146124855760405162461bcd60e51b81526004016107ae90615705565b66b1a2bc2ec50000846001600160581b031610156124e45760405162461bcd60e51b815260206004820152601c60248201527b09edcd8f240c4c2e6ca40e0e4d2c6ca40cee8ca40605c606a408aa8960231b60448201526064016107ae565b428664ffffffffff16116125315760405162461bcd60e51b81526020600482015260146024820152734f6e6c79206675747572652061756374696f6e7360601b60448201526064016107ae565b600061253c88613357565b905060018160028111156125525761255261527b565b036125a957826125a45760405162461bcd60e51b815260206004820152601d60248201527f4f6e6c792061646d696e2d617274697374206d696e7420706572696f6400000060448201526064016107ae565b612610565b60028160028111156125bd576125bd61527b565b036126105782156126105760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79206e6f2061646d696e2d617274697374206d696e7420706572696f6460448201526064016107ae565b61261a8989613ab1565b868260060160006101000a81548164ffffffffff021916908364ffffffffff1602179055508582600601600a6101000a81548164ffffffffff021916908364ffffffffff160217905550858260060160056101000a81548164ffffffffff021916908364ffffffffff160217905550848260060160126101000a8154816001600160581b0302191690836001600160581b03160217905550838260060160106101000a81548160ff021916908315150217905550828260060160116101000a81548160ff02191690831515021790555060006126f68a8a612d49565b60058401805461ffff19166102001790556040805164ffffffffff8b811682528a1660208201526001600160581b038916918101919091528615156060820152851515608082015260a081018290529091506001600160a01b038a16908b907ff5182d65d8ff8a191c9e2f9f31fa4757a3e046c58e19c304b66f1766ec3993829060c00160405180910390a350505050505050505050565b600061279a83836110f0565b905060006127a88484612b60565b905060048160048111156127be576127be61527b565b146127fa5760405162461bcd60e51b815260206004820152600c60248201526b4f6e6c79207374617465204560a01b60448201526064016107ae565b6007820154600160781b900460ff16156128535760405162461bcd60e51b815260206004820152601a6024820152792932bb32b73ab2b99030b63932b0b23c903bb4ba34323930bbb760311b60448201526064016107ae565b60078201805460ff60781b1916600160781b17905560006128738361384e565b600584015490915060009061289490600160b01b900462ffffff16836157a3565b60078501805491925082916000906128b69084906001600160781b0316615ab8565b92506101000a8154816001600160781b0302191690836001600160781b031602179055506128e58682876141fb565b6040805177185d58dd1a5bdb94995d995b9d595cd0dbdb1b1958dd195960421b8152600160208201526001600160a01b0387169188917fbb5f9d4f49f83650956b76c40de0f082a06430bf0222e1b6b3f90a7a0f845c4d91016120fe565b61294b61511f565b6129558383611cc2565b62ffffff16602082015261296983836130e5565b1515815292915050565b600061297f8585612b60565b905060028160048111156129955761299561527b565b146129b25760405162461bcd60e51b81526004016107ae90615ad8565b6000806129bf8787611c55565b5091509150816129e15760405162461bcd60e51b81526004016107ae9061581e565b808562ffffff161115612a065760405162461bcd60e51b81526004016107ae90615848565b5050506000612a1585856110f0565b90506000612a228261384e565b6005830154600160401b9081900463ffffffff1660008181526020869052604081205493945090929190910461ffff16905b8662ffffff16811015612af45782600003612a8c57600585015461ffff16600081815260028701602052604090205493509150612aa4565b6000928352602085905260409092205463ffffffff16915b82600003612ada57612ac085612abb8460016157ba565b6144b8565b61ffff166000818152600287016020526040902054935091505b612aec8989868561ffff16878b6138ce565b600101612a54565b808560050160198282829054906101000a900462ffffff16612b169190615929565b92506101000a81548162ffffff021916908362ffffff160217905550828560050160086101000a81548163ffffffff021916908363ffffffff160217905550505050505050505050565b600080612b6d84846110f0565b600681015490915064ffffffffff1680158015904283119080612b8d5750805b15612b9f576000945050505050610991565b6006840154600160501b900464ffffffffff1642811080612bc95760019650505050505050610991565b600586015460009062ffffff600160981b8204811691612bfa91600160c81b8204811691600160b01b900416615929565b62ffffff161490508015612c18576004975050505050505050610991565b6006870154600090600160881b900460ff168015612c4f5750600588015462ffffff600160801b82048116600160981b9092041610155b8015612c665750612c636203f480856157ba565b42105b90508015612c7f57600298505050505050505050610991565b5060039a9950505050505050505050565b600080612c9d8585614573565b91509150808362ffffff161115612cc65760405162461bcd60e51b81526004016107ae90615afe565b818362ffffff161015612ceb5760405162461bcd60e51b81526004016107ae90615afe565b6000612cf786866141d3565b805462ffffff861685811463ffffffff19909216610100820260ff1916179190911782556040519081529091506001600160a01b038616908790600080516020615d87833981519152906020016120fe565b600080612d5684846110f0565b9050612d62848461416c565b60058201805462ffffff60801b1916600160801b62ffffff8416021790556040518181529092506001600160a01b0384169085907fe61b855b975f8c5d6051b121797e73a9c4e2b5fce1e570689013b3591427efa89060200160405180910390a35092915050565b6000612dd686866110f0565b90506000612de38261384e565b90506000612df18888612b60565b90506002816004811115612e0757612e0761527b565b14612e245760405162461bcd60e51b81526004016107ae90615ad8565b612e2d8361411f565b8662ffffff161115612e515760405162461bcd60e51b81526004016107ae90615a81565b506005820154600160201b900463ffffffff16600081815260208490526040812054600160401b900461ffff16905b8762ffffff16811015612f725782600003612ebe57600585015462010000900461ffff16600081815260018701602052604090205493509150612f5b565b600092835260208590526040832054600160201b900463ffffffff1692839003612f5b57612ef685612ef16001856159d5565b6145f1565b61ffff1691506102008210612f475760405162461bcd60e51b81526020600482015260176024820152761cdb1bdd081dda5d1a08189a59081b9bdd08199bdd5b99604a1b60448201526064016107ae565b600082815260018601602052604090205492505b612f6a8a8a8685878c8c614444565b600101612e80565b808560050160168282829054906101000a900462ffffff16612f949190615929565b92506101000a81548162ffffff021916908362ffffff160217905550828560050160046101000a81548163ffffffff021916908363ffffffff16021790555050505050505050505050565b600080612fec84846110f0565b600701546001600160781b0316949350505050565b600061300d87876110f0565b9050600061301b8888612b60565b905060028160048111156130315761303161527b565b148061304e5750600381600481111561304c5761304c61527b565b145b61308e5760405162461bcd60e51b815260206004820152601160248201527013db9b1e481cdd185d194810c81bdc8811607a1b60448201526064016107ae565b50600061309a8261384e565b90508460005b81811015611c49576130dd848b8b868c8c878181106130c1576130c161587f565b90506020020160208101906130d69190615895565b8b8b61468d565b6001016130a0565b6000806130f28484612b60565b905060008160048111156131085761310861527b565b0361315957600061311985856110f0565b600681015490915064ffffffffff1615613146576005810154600160801b900462ffffff16159250613153565b6131508585614760565b92505b506131b6565b600181600481111561316d5761316d61527b565b036131a357600061317e85856110f0565b6005015462ffffff600160801b82048116600160981b90920416101592506131b69050565b60006131af8585611c55565b1594505050505b5092915050565b60008060006131cc8585612b60565b905060006131da86866110f0565b905060008260048111156131f0576131f061527b565b0361326a57600681015464ffffffffff161515806132495760405162461bcd60e51b8152602060048201526016602482015275185d58dd1a5bdb881b9bdd0818dbdb999a59dd5c995960521b60448201526064016107ae565b506006810154600160901b90046001600160581b031693506000925061334e565b600581015462ffffff600160801b82048116600160981b909204161015600183600481111561329b5761329b61527b565b036132e95780156132c95760058201546132bc908890889061ffff16614779565b955061ffff16935061334c565b6006820154600160901b90046001600160581b031694506000935061334c565b80156133305760405162461bcd60e51b8152602060048201526016602482015275185d58dd1a5bdb88195b9919590b081cd95b1b1bdd5d60521b60448201526064016107ae565b6006820154600160901b90046001600160581b03169450600093505b505b50509250929050565b600061336161382a565b6001600160a01b03909216600090815260019290920160205250604090205460ff1690565b600080600061339585856110f0565b6005810154909150600160981b900462ffffff166133ea5760405162461bcd60e51b81526020600482015260126024820152712737903134b2399034b71030bab1ba34b7b760711b60448201526064016107ae565b600581015461ffff1660008181526002830160209081526040808320548352939052919091209590945092505050565b60008060006134298585612b60565b9050600061343786866110f0565b9050600082600481111561344d5761344d61527b565b0361348457600681015464ffffffffff16158015945061347f576006810154600160901b90046001600160581b031692505b61334e565b60058101546001945062ffffff600160801b82048116600160981b909204161015848360048111156134b8576134b861527b565b036134fe5780156134e25760058201546134d9908890889061ffff16614779565b945061334c9050565b6006820154600160901b90046001600160581b0316935061334c565b8015613533576006820154600583015461352c91600160901b90046001600160581b03169061ffff16611121565b935061334c565b50600601549295600160901b9093046001600160581b031694509192505050565b613560848484846143bc565b611f515760405162461bcd60e51b815260206004820152601a60248201527913db9b1e48135a5b9d195c919a5b1d195c8810591b5a5b9050d360321b60448201526064016107ae565b60006135b587876110f0565b63ffffffff86166000908152602082905260409020805491925090600160401b900461ffff1660016135e78a8a612b60565b60048111156135f8576135f861527b565b146136155760405162461bcd60e51b81526004016107ae90615945565b8154600160501b90046001600160a01b03166136705760405162461bcd60e51b815260206004820152601a60248201527942696420646e65202d207765726520796f75206f75746269643f60301b60448201526064016107ae565b81546001600160a01b03868116600160501b90920416146136d15760405162461bcd60e51b815260206004820152601b60248201527a13db9b1e48189a5919195c881bd988195e1a5cdd1a5b99c8189a59602a1b60448201526064016107ae565b60068301546000906136f390600160901b90046001600160581b031683611121565b905060006137188560060160129054906101000a90046001600160581b031689611121565b90508061372587846157ba565b1461376a5760405162461bcd60e51b8152602060048201526015602482015274696e636f72726563742061646465642076616c756560581b60448201526064016107ae565b505060078301805485919060009061378c9084906001600160781b03166159b5565b92506101000a8154816001600160781b0302191690836001600160781b031602179055506137c183828963ffffffff166147dc565b6137cf838a8a89898c613e00565b6040805163ffffffff8916815261ffff881660208201526001600160a01b038a16918b917fbcc60406b6a319d70c3feea7347029fbdfd768eecb981b0d2f6735b1e9633c5e91015b60405180910390a3505050505050505050565b7fa3fe13710cb596cbb938328f55db0dd5473d105cbcbbac73fbdbd94800043ab490565b600581015460009062ffffff600160801b82048116600160981b9092041610158061388d576006830154600160901b90046001600160581b0316610785565b6006830154600584015461078591600160901b90046001600160581b03169061ffff16611121565b815460009061098e90600160f01b900460ff1683614963565b60006138da87876110f0565b6000848152602082905260408120805492935091600160501b90046001600160a01b031690879061390b84826138b5565b6139425761391c8460006001614972565b50600684015460019061393f90600160901b90046001600160581b031689611121565b91505b61394f8460026001614972565b60078501805483919060009061396f9084906001600160781b0316615ab8565b92506101000a8154816001600160781b0302191690836001600160781b0316021790555061399e8383886149ce565b80156139d757896001600160a01b03168b600080516020615dc7833981519152896040516139ce91815260200190565b60405180910390a35b896001600160a01b03168b7fa59312996dc68b7f0224b341fed75d5afeb3bb20624107d37942d14f5942815689604051613a1391815260200190565b60405180910390a35050505050505050505050565b60405163a47d29cb60e01b8152600481018490526000906001600160a01b0384169063a47d29cb90602401602060405180830381865afa158015613a70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a94919061565e565b6001600160a01b0316826001600160a01b03161490509392505050565b6000613abd83836141d3565b9050613ac98383614a03565b15613ad85761170c8383614a36565b600080613ae58585614573565b84549193509150610100900462ffffff1681811115613b5157835483831463ffffffff1990911661010062ffffff85160260ff1916171784556040518281526001600160a01b038616908790600080516020615d878339815191529060200160405180910390a3613b64565b808310613b6457835460ff191660011784555b505050505050565b600584015461ffff16600081815260028601602052604081205490919080613bc05760405162461bcd60e51b81526020600482015260076024820152664e6f206269647360c81b60448201526064016107ae565b600081815260208881526040808320805461ffff8716855260028c01909352922063ffffffff82169081905560058a018054600160501b9093046001600160a01b031692600160981b900462ffffff16906013613c1c83615b2f565b91906101000a81548162ffffff021916908362ffffff160217905550508063ffffffff16600003613c945761ffff8516600081815260018c016020526040812055613c68908b90614ab0565b613c778a612abb876001615b4e565b60058b01805461ffff191661ffff92909216919091179055613cb8565b63ffffffff8116600090815260208b905260409020805463ffffffff60201b191690555b60068a0154613cd790600160901b90046001600160581b031686611121565b60078b0180549197508791600090613cf99084906001600160781b0316615ab8565b82546001600160781b039182166101009390930a928302919092021990911617905550600084815260208b90526040902080546001600160f81b0319169055613d438287896149ce565b876001600160a01b0316897f9d1a4511ddb5e2e227897ca79bbe1d71a9af123cd7c7bde8d2bcb292243310c986604051613d7f91815260200190565b60405180910390a35050505050949350505050565b60006706f05b59d3b20000831115613dc857612710613db58461280a6157a3565b613dbf919061577b565b82119050610991565b612710613dd7846129046157a3565b613de1919061577b565b90911192915050565b6000818310613df9578161098e565b5090919050565b63ffffffff8116158015613e4d57600587018054600c90613e2d90600160601b900463ffffffff16615b69565b91906101000a81548163ffffffff021916908363ffffffff160217905591505b60008760020160008661ffff1681526020019081526020016000205490506040518060a001604052808263ffffffff168152602001600063ffffffff1681526020018661ffff168152602001856001600160a01b03168152602001600060ff168152508860000160008563ffffffff16815260200190815260200160002060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548161ffff021916908361ffff160217905550606082015181600001600a6101000a8154816001600160a01b0302191690836001600160a01b03160217905550608082015181600001601e6101000a81548160ff021916908360ff1602179055509050508263ffffffff168860020160008761ffff1681526020019081526020016000208190555080600003613fdc5761ffff85166000908152600189016020526040902063ffffffff84169055614007565b6000818152602089905260409020805463ffffffff60201b1916600160201b63ffffffff8616021790555b600588018054600160981b900462ffffff1690601361402583615907565b91906101000a81548162ffffff021916908362ffffff16021790555050806000036140b557614058888661ffff16614b0b565b600588015461ffff90811690861610156140805760058801805461ffff191661ffff87161790555b600588015461ffff62010000909104811690861611156140b55760058801805463ffff000019166201000061ffff8816021790555b8115614115576040805161ffff8716815263ffffffff851660208201526001600160a01b038681168284015291519188169189917fd278a5272d5c4a1fbd78fd96e1dc404c29b3e6fc9a525421b777de714354f5a5919081900360600190a35b5050505050505050565b60058101546000906141469062ffffff600160c81b8204811691600160b01b900416615929565b60058301546141619190600160981b900462ffffff16615b82565b62ffffff1692915050565b600080600061417b8585614573565b91509150600061418b86866141d3565b80549091506000906141a8908490610100900462ffffff16613dea565b90508084106141be576000945050505050610991565b6141c884826159d5565b979650505050505050565b60007f73e3af67f35f30fb72bbaaf6cc07b987364ed643c93ba201702e213464e877ee6110fa565b8160000361420857505050565b600061421382614b5a565b905060008060008060008060008088156142b157604051638639415b60e01b8152600481018d9052602481018c90526001600160a01b038b1690638639415b9060440161010060405180830381865afa158015614274573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142989190615b9e565b969e50949c50929a509098509650945092509050614331565b604051638639415b60e01b8152600481018d9052602481018c90526001600160a01b038b1690638639415b9060440160c060405180830381865afa1580156142fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143219190615c26565b949c50929a509096509450925090505b8a828561433e898c6157ba565b61434891906157ba565b61435291906157ba565b1461439e5760405162461bcd60e51b815260206004820152601c60248201527b496e76616c696420726576656e75652073706c697420746f74616c7360201b60448201526064016107ae565b6143ae86868a8a88888888614ba8565b505050505050505050505050565b60405163230448b160e01b81526001600160a01b03848116600483015283811660248301526001600160e01b0319831660448301526000919086169063230448b1906064016020604051808303816000875af1158015614420573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074b9190615c8f565b600061445088886110f0565b600085815260208290526040902090915061446d81600180614972565b805461448f908a908a908890600160501b90046001600160a01b031688614e4a565b61449a8160006138b5565b6144ad576144ad828a8a89898c89614f0a565b505050505050505050565b6000806101ff8361ffff1611156144e15760405162461bcd60e51b81526004016107ae90615cac565b600060ff8461ffff1611156145165760048501546144ff9085614ffa565b9250905061450f610100826157ba565b9050614551565b60038501546145259085614ffa565b925090508161455157600485015461453e906000614ffa565b9250905061454e610100826157ba565b90505b816145625761020092505050610991565b91506109919050565b505092915050565b604051630ea5613f60e01b81526004810183905260009081906001600160a01b03841690630ea5613f9060240160c060405180830381865afa1580156145bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145e19190615ce2565b5093989297509195505050505050565b6000806101ff8361ffff16111561461a5760405162461bcd60e51b81526004016107ae90615cac565b60006101008461ffff1610156146425760038501546146399085615060565b92509050614551565b60048501546146519085615060565b92509050614661610100826157ba565b9050816145515760038501546146789060ff615060565b92509050816145625761020092505050610991565b63ffffffff8316600090815260208890526040902080546001600160a01b03848116600160501b90920416146146f35760405162461bcd60e51b815260206004820152600b60248201526a27b7363c903134b23232b960a91b60448201526064016107ae565b6146fe8160006138b5565b156147415760405162461bcd60e51b815260206004820152601360248201527213db9b1e481d5b8b5cd95d1d1b195908189a59606a1b60448201526064016107ae565b805461411590899089908990600160401b900461ffff16888a88614f0a565b60008061476d84846141d3565b5460ff16949350505050565b600080600061478886866110f0565b6006810154909150600160901b90046001600160581b031660006147ac8287611121565b9050855b6001016147bd8382611121565b94506147c98286613d94565b156147b057989397509295505050505050565b60008181526020849052604081208054909163ffffffff80831692600160201b9004169082900361482a5761ffff85166000908152600187016020526040902063ffffffff8216905561485e565b63ffffffff80831660009081526020889052604090208054918316600160201b0263ffffffff60201b199092169190911790555b8063ffffffff1660000361488f5761ffff85166000908152600287016020526040902063ffffffff831690556148b8565b63ffffffff8181166000908152602088905260409020805463ffffffff19169184169190911790555b600586018054600160981b900462ffffff169060136148d683615b2f565b91906101000a81548162ffffff021916908362ffffff160217905550508163ffffffff16600014801561490d575063ffffffff8116155b15613b6457614920868661ffff16614ab0565b600586015461ffff808716911603613b645761494186612abb876001615b4e565b60058701805461ffff9290921661ffff19909216919091179055505050505050565b600160ff919091161b16151590565b80156149af578254600160ff8481169190911b600160f01b90920416175b835460ff91909116600160f01b0260ff60f01b19909116178355505050565b825461499090600160f01b900460ff1683600160ff919091161b191690565b600080600080858786f161170c57826000526073600b5360ff6020536016600b83f061170c57620f42405a1161170c57600080fd5b600080614a1084846141d3565b8054909150610100900462ffffff16158015614a2e5750805460ff16155b949350505050565b600080614a438484614573565b915091506000614a5385856141d3565b9050614a5e826150bb565b815460ff1962ffffff92909216610100029190911663ffffffff19909116178383141781556040516001600160a01b038516908690600080516020615d87833981519152906119429086815260200190565b6102008110614ad15760405162461bcd60e51b81526004016107ae9061572f565b610100811015614af3576003820154600160ff83161b19165b60038301555050565b6004820154600160ff83161b19165b60048301555050565b6102008110614b2c5760405162461bcd60e51b81526004016107ae9061572f565b610100811015614b48576003820154600160ff83161b17614aea565b6004820154600160ff83161b17614b02565b600080614b66836111b7565b8054909150610100900460ff1615614b82575460ff1692915050565b6000614b8d846111f0565b825481151561ffff1990911617610100179092555092915050565b8715614c53576000876001600160a01b03168960405160006040518083038185875af1925050503d8060008114614bfb576040519150601f19603f3d011682016040523d82523d6000602084013e614c00565b606091505b5050905080614c515760405162461bcd60e51b815260206004820181905260248201527f506c6174666f726d2050726f7669646572207061796d656e74206661696c656460448201526064016107ae565b505b8515614cfe576000856001600160a01b03168760405160006040518083038185875af1925050503d8060008114614ca6576040519150601f19603f3d011682016040523d82523d6000602084013e614cab565b606091505b5050905080614cfc5760405162461bcd60e51b815260206004820152601e60248201527f52656e6465722050726f7669646572207061796d656e74206661696c6564000060448201526064016107ae565b505b8315614da1576000836001600160a01b03168560405160006040518083038185875af1925050503d8060008114614d51576040519150601f19603f3d011682016040523d82523d6000602084013e614d56565b606091505b5050905080614d9f5760405162461bcd60e51b8152602060048201526015602482015274105c9d1a5cdd081c185e5b595b9d0819985a5b1959605a1b60448201526064016107ae565b505b8115614115576000816001600160a01b03168360405160006040518083038185875af1925050503d8060008114614df4576040519150601f19603f3d011682016040523d82523d6000602084013e614df9565b606091505b50509050806144ad5760405162461bcd60e51b815260206004820152601f60248201527f4164646974696f6e616c205061796565207061796d656e74206661696c65640060448201526064016107ae565b6040516117cd60e21b81526000906001600160a01b03831690615f3490614e7b9086908a908a9033906004016159e8565b6020604051808303816000875af1158015614e9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614ebe9190615a13565b6040805163ffffffff87168152602081018390529192506001600160a01b0387169188917f3c81bf6062ef45a4f3a4407699b008e79d9310eb22ba240838820f37535a928591016120fe565b63ffffffff8316600090815260208890526040812090614f2d9082906001614972565b600083614f518a60060160129054906101000a90046001600160581b031688611121565b614f5b91906159d5565b90508015614fc957600789018054829190600090614f839084906001600160781b0316615ab8565b92506101000a8154816001600160781b0302191690836001600160781b03160217905550614fc982600001600a9054906101000a90046001600160a01b031682856149ce565b60405163ffffffff861681526001600160a01b038816908990600080516020615dc783398151915290602001613817565b6000808260ff1684901c600003615017575060ff90506000615059565b8260ff1691505b60ff8210801561503557506150338483614963565b155b1561504c578161504481615d3d565b92505061501e565b6150568483614963565b90505b9250929050565b60008061506e8360ff615d56565b60ff1684901b60000361508657506000905080615059565b8260ff1691505b6000821180156150a457506150a28483614963565b155b1561504c57816150b381615d6f565b92505061508d565b600062ffffff8211156124395760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203260448201526534206269747360d01b60648201526084016107ae565b604080518082019091526000808252602082015290565b6001600160a01b038116811461514b57600080fd5b50565b803561ffff8116811461516057600080fd5b919050565b60008060006060848603121561517a57600080fd5b83359250602084013561518c81615136565b915061519a6040850161514e565b90509250925092565b6000602082840312156151b557600080fd5b813561078581615136565b600080600080606085870312156151d657600080fd5b8435935060208501356151e881615136565b925060408501356001600160401b038082111561520457600080fd5b818701915087601f83011261521857600080fd5b81358181111561522757600080fd5b8860208260051b850101111561523c57600080fd5b95989497505060200194505050565b6000806040838503121561525e57600080fd5b82359150602083013561527081615136565b809150509250929050565b634e487b7160e01b600052602160045260246000fd5b6000610180820190508d82528c60208301528b60408301528a60608301528960808301528860a08301528760c08301528660e0830152851515610100830152841515610120830152831515610140830152600583106152f2576152f261527b565b826101608301529d9c50505050505050505050505050565b803564ffffffffff8116811461516057600080fd5b60008060006060848603121561533457600080fd5b83359250602084013561534681615136565b915061519a6040850161530a565b60008060006060848603121561536957600080fd5b833561537481615136565b925060208401359150604084013561538b81615136565b809150509250925092565b6000806000606084860312156153ab57600080fd5b8335925060208401356153bd81615136565b9150604084013560ff8116811461538b57600080fd5b600080604083850312156153e657600080fd5b82356153f181615136565b915060208301356003811061527057600080fd5b801515811461514b57600080fd5b600080600080600080600060e0888a03121561542e57600080fd5b87359650602088013561544081615136565b955061544e6040890161530a565b945061545c6060890161530a565b93506080880135925060a088013561547381615405565b915060c088013561548381615405565b8091505092959891949750929550565b803562ffffff8116811461516057600080fd5b6000806000606084860312156154bb57600080fd5b8335925060208401356154cd81615136565b915061519a60408501615493565b60005b838110156154f65781810151838201526020016154de565b50506000910152565b600081518084526155178160208601602086016154db565b601f01601f19169290920160200192915050565b60208152600061098e60208301846154ff565b60208101600383106155525761555261527b565b91905290565b841515815283602082015260806040820152600061557960808301856154ff565b905060018060a01b038316606083015295945050505050565b6000602082840312156155a457600080fd5b61098e82615493565b803563ffffffff8116811461516057600080fd5b600080600080608085870312156155d757600080fd5b8435935060208501356155e981615136565b92506155f7604086016155ad565b91506156056060860161514e565b905092959194509250565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b9182526001600160a01b0316602082015260400190565b60006020828403121561567057600080fd5b815161078581615136565b6020808252601190820152704d696e746572206e6f742061637469766560781b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b64ffffffffff8281168282160390808211156131b6576131b66156a6565b602080825260119082015270105d58dd1a5bdb881d1bdbc81cda1bdc9d607a1b604082015260600190565b60208082526010908201526f27b7363c9038393296b0bab1ba34b7b760811b604082015260600190565b6020808252601c908201527b4f6e6c7920736c6f7420696e646578206c74204e554d5f534c4f545360201b604082015260600190565b634e487b7160e01b600052601260045260246000fd5b60008261578a5761578a615765565b500490565b60008261579e5761579e615765565b500690565b8082028115828204841417610991576109916156a6565b80820180821115610991576109916156a6565b600082516157df8184602087016154db565b9190910192915050565b6020808252601b908201527a13db9b1e481c1bdcdd0b585d58dd1a5bdb881bdc195b881b5a5b9d602a1b604082015260600190565b60208082526010908201526f4f6e6c7920696e20737461746520453160801b604082015260600190565b6020808252601f908201527f6269647320746f20726566756e6420677420617661696c61626c652071747900604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156158a757600080fd5b61098e826155ad565b6020808252600e908201526d1a5b9d985b1a5908109a5908125160921b604082015260600190565b60208082526015908201527427b7363c9039b2b73232b91034b9903134b23232b960591b604082015260600190565b600062ffffff80831681810361591f5761591f6156a6565b6001019392505050565b62ffffff8181168382160190808211156131b6576131b66156a6565b60208082526011908201527027b7363c903634bb329030bab1ba34b7b760791b604082015260600190565b6020808252601990820152784e6f7420616c6c6f77656420696e2065787472612074696d6560381b604082015260600190565b64ffffffffff91909116815260200190565b6001600160781b038181168382160190808211156131b6576131b66156a6565b81810381811115610991576109916156a6565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b600060208284031215615a2557600080fd5b5051919050565b60ff8181168382160190811115610991576109916156a6565b61ffff81811683821602808216919082811461456b5761456b6156a6565b64ffffffffff8181168382160190808211156131b6576131b66156a6565b6020808252601d908201527f746f6b656e7320746f206d696e7420677420746f6b656e73206f776564000000604082015260600190565b6001600160781b038281168282160390808211156131b6576131b66156a6565b6020808252600c908201526b4f6e6c79207374617465204360a01b604082015260600190565b602080825260179082015276496e76616c6964206d617820696e766f636174696f6e7360481b604082015260600190565b600062ffffff821680615b4457615b446156a6565b6000190192915050565b61ffff8181168382160190808211156131b6576131b66156a6565b600063ffffffff80831681810361591f5761591f6156a6565b62ffffff8281168282160390808211156131b6576131b66156a6565b600080600080600080600080610100898b031215615bbb57600080fd5b885197506020890151615bcd81615136565b60408a015160608b01519198509650615be581615136565b60808a015160a08b01519196509450615bfd81615136565b60c08a015160e08b01519194509250615c1581615136565b809150509295985092959890939650565b60008060008060008060c08789031215615c3f57600080fd5b865195506020870151615c5181615136565b604088015160608901519196509450615c6981615136565b608088015160a08901519194509250615c8181615136565b809150509295509295509295565b600060208284031215615ca157600080fd5b815161078581615405565b6020808252601c908201527b27b7363c9039ba30b93a1039b637ba1034b73232bc10363a101a989960211b604082015260600190565b60008060008060008060c08789031215615cfb57600080fd5b86519550602087015194506040870151615d1481615405565b6060880151909450615d2581615405565b608088015160a08901519194509250615c8181615405565b600060018201615d4f57615d4f6156a6565b5060010190565b60ff8281168282160390811115610991576109916156a6565b600081615d7e57615d7e6156a6565b50600019019056fe1c3e74a6c6fefbaeee166b031cd2016349c6c863d5188b67c9bbd0b0dcb2e237520e05d2a73ab549525f701daae4d8ac1897891bb1afca813602709aafc7a830e152fe384870d25a8d821270b8b8043fada748f138ab7f8512af64c65c726136a26469706673582212201be61649a635efb061b2ea27baa094eaa05101acc5df025a1d0875c9f9be0d3c64736f6c63430008160033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a2ccfe293bc2cdd78d8166a82d1e18cd2148122b
-----Decoded View---------------
Arg [0] : minterFilter (address): 0xa2ccfE293bc2CDD78D8166a82D1e18cD2148122b
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000a2ccfe293bc2cdd78d8166a82d1e18cd2148122b
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.