Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

CuttingBoardDutchAuction

Git Source

Inherits: Upgradeable

Title: CuttingBoardDutchAuction

Dutch auction for temporary control rights over validator cutting boards

Extends the cutting board auction model to grant full manual control of validator reward allocations. Winners receive an NFT that allows them to update the cutting board multiple times during the allocation period, enabling dynamic yield optimization. Key features:

  • Auctions specific validators (identified by pubkey)
  • Winner must provide initial cutting board on claim
  • Mints NFT representing control rights
  • NFT holder can update cutting board via CuttingBoardManager
  • Linear price decay (Dutch auction model)
  • Control expires after allocationDuration
  • Configurable auction parameters (duration, portion size, max auctions).
  • Starting price: Configurable multiplier of previous closing price.
  • Base price (floor): Configurable divisor of previous closing price.
  • Payment in specified payment token.
  • Single winner claims the full portion per auction.
  • On-chain claim: Anyone can claim by paying exactly the current price.

Uses ERC-7201 namespaced storage pattern for upgradeability

State Variables

CUTTING_BOARD_DUTCH_AUCTION_STORAGE_LOCATION

bytes32 private constant CUTTING_BOARD_DUTCH_AUCTION_STORAGE_LOCATION =
    0x67c283459ab08c5e5e83c645bebd5b8d5f91d5b9fb7d2a34ff4694a99438fd00

__gap

uint256[20] private __gap

Functions

_getCuttingBoardDutchAuctionStorage

function _getCuttingBoardDutchAuctionStorage()
    private
    pure
    returns (CuttingBoardDutchAuctionStorage storage $);

infrared

function infrared() public view returns (IInfrared);

paymentToken

function paymentToken() public view returns (ERC20);

treasury

function treasury() public view returns (address);

chef

function chef() public view returns (IBeraChefVaultCheck);

controlNFT

function controlNFT() public view returns (CuttingBoardNFT);

controlManager

function controlManager() public view returns (CuttingBoardManager);

auctionDuration

function auctionDuration() public view returns (uint256);

allocationDuration

function allocationDuration() public view returns (uint256);

maxAuctions

function maxAuctions() public view returns (uint256);

startingPriceMultiplier

function startingPriceMultiplier() public view returns (uint256);

basePriceDivisor

function basePriceDivisor() public view returns (uint256);

minimumPrice

function minimumPrice() public view returns (uint256);

lastClosingPrice

function lastClosingPrice() public view returns (uint256);

constructor

Note: oz-upgrades-unsafe-allow: constructor

constructor() ;

initialize

Initialize the CuttingBoardDutchAuction contract

Validates all parameters and sets contract references Requires all addresses to be non-zero and numeric parameters to be within valid ranges

function initialize(InitParams calldata params) external initializer;

Parameters

NameTypeDescription
paramsInitParamsInitialization parameters struct containing all configuration values

startCuttingBoardAuction

Start auction for a specific validator

Callable by keeper. Price params derived from lastClosingPrice. Prevents starting a new auction if the previous one hasn't been claimed. If previous auction was unclaimed, uses its base price as the closing price.

function startCuttingBoardAuction(bytes calldata validatorPubkey)
    external
    virtual
    onlyKeeper
    whenNotPaused;

Parameters

NameTypeDescription
validatorPubkeybytesThe validator pubkey to auction control rights for

claimCuttingBoardControl

Claim validator control by paying current price

function claimCuttingBoardControl(
    uint256 auctionId,
    IBeraChef.Weight[] calldata initialWeights
) external virtual whenNotPaused;

Parameters

NameTypeDescription
auctionIduint256The auction ID to claim
initialWeightsIBeraChef.Weight[]Initial cutting board configuration

_processClaim

Internal function to process claim and reduce stack depth

function _processClaim(
    uint256 auctionId,
    Auction storage auction,
    uint256 currentPrice,
    bytes memory validatorPubkey,
    IBeraChef.Weight[] calldata initialWeights
) internal virtual returns (uint256 tokenId);

Parameters

NameTypeDescription
auctionIduint256The auction ID
auctionAuctionStorage reference to auction
currentPriceuint256The current auction price
validatorPubkeybytesThe validator pubkey
initialWeightsIBeraChef.Weight[]Initial cutting board weights

Returns

NameTypeDescription
tokenIduint256The minted NFT token ID

getCurrentPrice

Get current auction price

Reverts if auction has expired (past auctionDuration)

function getCurrentPrice(uint256 auctionId)
    public
    view
    virtual
    returns (uint256);

Parameters

NameTypeDescription
auctionIduint256The auction ID

Returns

NameTypeDescription
<none>uint256Current price (decays linearly)

isValidatorAvailable

Check if a validator is available for auction

function isValidatorAvailable(bytes calldata validatorPubkey)
    external
    view
    virtual
    returns (bool);

Parameters

NameTypeDescription
validatorPubkeybytesThe validator pubkey to check

Returns

NameTypeDescription
<none>boolTrue if validator can be auctioned

isValidatorAllocated

Check if a validator is currently allocated to NFT holder

function isValidatorAllocated(bytes calldata validatorPubkey)
    external
    view
    virtual
    returns (bool);

Parameters

NameTypeDescription
validatorPubkeybytesThe validator pubkey to check

Returns

NameTypeDescription
<none>boolTrue if validator is currently allocated to NFT holder

getAuctionValidator

Get validator pubkey for an auction

function getAuctionValidator(uint256 auctionId)
    external
    view
    virtual
    returns (bytes memory);

Parameters

NameTypeDescription
auctionIduint256The auction ID

Returns

NameTypeDescription
<none>bytesThe validator pubkey

getAuction

Get complete auction details

function getAuction(uint256 auctionId)
    external
    view
    virtual
    returns (Auction memory auction_, bytes memory validatorPubkey);

Parameters

NameTypeDescription
auctionIduint256The auction ID

Returns

NameTypeDescription
auction_AuctionThe auction struct data
validatorPubkeybytesThe validator pubkey for this auction

getAuctionCount

Get total number of auctions

function getAuctionCount() external view virtual returns (uint256);

Returns

NameTypeDescription
<none>uint256The total number of auctions created

isAuctionActive

Check if an auction is active

function isAuctionActive(uint256 auctionId)
    external
    view
    virtual
    returns (bool);

Parameters

NameTypeDescription
auctionIduint256The auction ID

Returns

NameTypeDescription
<none>boolTrue if auction is active (started and not claimed), false otherwise

getActiveAuction

Get the current active auction

function getActiveAuction()
    external
    view
    virtual
    returns (uint256 auctionId, bool isActive);

Returns

NameTypeDescription
auctionIduint256The ID of the active auction (0 if none active)
isActiveboolTrue if there is an active auction, false otherwise

getLastAuction

Get the most recent auction regardless of validator

Useful for keepers to check the current auction state

function getLastAuction()
    external
    view
    virtual
    returns (
        uint256 auctionId,
        Auction memory auction_,
        bytes memory validatorPubkey,
        bool exists
    );

Returns

NameTypeDescription
auctionIduint256The ID of the last auction (0 if none exist)
auction_AuctionThe auction struct data
validatorPubkeybytesThe validator pubkey for this auction
existsboolTrue if at least one auction exists, false otherwise

getLastValidatorAuction

Get the most recent auction for a specific validator

Iterates backwards through auctions to find the last one for the given validator. Useful for keepers to check if a validator has been auctioned before and its history.

function getLastValidatorAuction(bytes calldata validatorPubkey)
    external
    view
    virtual
    returns (uint256 auctionId, Auction memory auction_, bool exists);

Parameters

NameTypeDescription
validatorPubkeybytesThe validator pubkey to search for (must be 48 bytes)

Returns

NameTypeDescription
auctionIduint256The ID of the last auction for this validator (0 if not found)
auction_AuctionThe auction struct data (empty if not found)
existsboolTrue if an auction was found for this validator, false otherwise

setInitialPrice

Set the initial price reference for the first auction

Can only be called before any auctions are started

function setInitialPrice(uint256 price) external virtual onlyGovernor;

Parameters

NameTypeDescription
priceuint256The initial closing price (must be > 0)

setAuctionDuration

Update the auction duration (price decay period)

Can only be called before any auctions are started

function setAuctionDuration(uint256 _auctionDuration)
    external
    virtual
    onlyGovernor;

Parameters

NameTypeDescription
_auctionDurationuint256New auction duration in seconds

setAllocationDuration

Update the allocation duration (control period length)

Can only be called before any auctions are started

function setAllocationDuration(uint256 _allocationDuration)
    external
    virtual
    onlyGovernor;

Parameters

NameTypeDescription
_allocationDurationuint256New allocation duration in seconds

setMaxAuctions

Update the maximum number of auctions

function setMaxAuctions(uint256 _maxAuctions)
    external
    virtual
    onlyGovernor;

Parameters

NameTypeDescription
_maxAuctionsuint256New maximum auction count

setMinimumPrice

Update the minimum price floor

Can be updated at any time by keeper

function setMinimumPrice(uint256 _minimumPrice)
    external
    virtual
    onlyKeeper;

Parameters

NameTypeDescription
_minimumPriceuint256New minimum price in payment token decimals

setClosingPriceReference

function setClosingPriceReference(uint256 price)
    external
    virtual
    onlyKeeper;

setBasePriceDivisor

Update the base price divisor (controls price floor)

Can be updated at any time by keeper, must be > 1e18

function setBasePriceDivisor(uint256 _basePriceDivisor)
    external
    virtual
    onlyKeeper;

Parameters

NameTypeDescription
_basePriceDivisoruint256New divisor (e.g., 2e18 = 0.5x previous price)

setStartingPriceMultiplier

Update the starting price multiplier (controls auction start price)

Can be updated at any time by keeper, must be > 1e18

function setStartingPriceMultiplier(uint256 _startingPriceMultiplier)
    external
    virtual
    onlyKeeper;

Parameters

NameTypeDescription
_startingPriceMultiplieruint256New multiplier (e.g., 2e18 = 2x previous price)

_isValidatorAvailable

Check if a validator is available for a new auction

A validator is available if:

  1. No active auction exists for this validator
  2. Control period has expired (if previously controlled)
function _isValidatorAvailable(bytes32 validatorHash)
    internal
    view
    virtual
    returns (bool);

Parameters

NameTypeDescription
validatorHashbytes32Keccak256 hash of the validator pubkey

Returns

NameTypeDescription
<none>boolTrue if validator can be auctioned, false otherwise

Events

AuctionStarted

Emitted when a new auction is started

event AuctionStarted(
    uint256 indexed auctionId,
    bytes32 indexed validatorHash,
    uint256 startingPrice,
    uint256 basePrice,
    uint256 startTime,
    uint256 allocationDuration
);

Parameters

NameTypeDescription
auctionIduint256The unique identifier for the auction
validatorHashbytes32Hash of validator pubkey for cutting board auction
startingPriceuint256The initial price at auction start
basePriceuint256The floor price after auction duration
startTimeuint256The timestamp when the auction started
allocationDurationuint256The duration in seconds the winner controls the allocation

AuctionClaimed

Emitted when an auction is claimed

event AuctionClaimed(
    uint256 indexed auctionId,
    address indexed winner,
    bytes32 indexed validatorHash,
    uint256 pricePaid,
    uint256 controlTokenId,
    uint256 allocationDuration
);

Parameters

NameTypeDescription
auctionIduint256The unique identifier for the auction
winneraddressThe address that won the auction
validatorHashbytes32Hash of validator pubkey for cutting board auction
pricePaiduint256The final price paid to claim the auction
controlTokenIduint256The NFT id with cutting board control
allocationDurationuint256The duration in seconds the winner controls the allocation

AuctionDurationUpdated

Emitted when auction duration is updated

event AuctionDurationUpdated(uint256 newDuration);

Parameters

NameTypeDescription
newDurationuint256The new auction duration in seconds

AllocationDurationUpdated

Emitted when allocation duration is updated

event AllocationDurationUpdated(uint256 newDuration);

Parameters

NameTypeDescription
newDurationuint256The new allocation duration in seconds

MaxAuctionsUpdated

Emitted when max auctions is updated

event MaxAuctionsUpdated(uint256 newMaxAuctions);

Parameters

NameTypeDescription
newMaxAuctionsuint256The new maximum number of auctions

MinimumPriceUpdated

Emitted when minimum price is updated

event MinimumPriceUpdated(uint256 newPrice);

Parameters

NameTypeDescription
newPriceuint256The new minimum price

BasePriceDivisorUpdated

Emitted when base price divisor is updated

event BasePriceDivisorUpdated(uint256 newDivisor);

Parameters

NameTypeDescription
newDivisoruint256The new base price divisor

StartingPriceMultiplierUpdated

Emitted when starting price multiplier is updated

event StartingPriceMultiplierUpdated(uint256 newMultiplier);

Parameters

NameTypeDescription
newMultiplieruint256The new starting price multiplier

InitialPriceSet

Emitted when initial price is set

event InitialPriceSet(uint256 price);

Parameters

NameTypeDescription
priceuint256The initial closing price reference

Errors

InvalidPaymentToken

Thrown when an invalid payment token address is provided

error InvalidPaymentToken();

InvalidDuration

Thrown when an invalid auction duration is provided (zero)

error InvalidDuration();

InvalidMaxAuctions

Thrown when an invalid max auctions value is provided (zero)

error InvalidMaxAuctions();

InvalidMultiplier

Thrown when an invalid starting price multiplier is provided (<= 1e18)

error InvalidMultiplier();

InvalidDivisor

Thrown when an invalid base price divisor is provided (<= 1e18)

error InvalidDivisor();

InvalidTreasury

Thrown when an invalid treasury address is provided

error InvalidTreasury();

InvalidMinimumPrice

Thrown when an invalid minimum price is provided (zero)

error InvalidMinimumPrice();

InvalidAllocationDuration

Thrown when an invalid allocation duration is provided (zero)

error InvalidAllocationDuration();

AllAuctionsCompleted

Thrown when attempting to start an auction after max auctions reached

error AllAuctionsCompleted();

SetInitialPriceFirst

Thrown when attempting to start the first auction without setting initial price

error SetInitialPriceFirst();

InvalidPriceRange

Thrown when starting price is not greater than base price

error InvalidPriceRange();

InvalidAuctionId

Thrown when an invalid auction ID is provided

error InvalidAuctionId();

AuctionNotStarted

Thrown when attempting to interact with an auction that hasn't started

error AuctionNotStarted();

AuctionExpired

Thrown when attempting to claim or get price for an expired auction

error AuctionExpired();

AlreadyClaimed

Thrown when attempting to claim an already claimed auction

error AlreadyClaimed();

InvalidPrice

Thrown when an invalid price is provided (zero or invalid calculation)

error InvalidPrice();

AuctionsAlreadyStarted

Thrown when attempting to update parameters after auctions have started

error AuctionsAlreadyStarted();

PreviousAuctionNotClaimed

Thrown when attempting to start a new auction before the previous one is claimed

error PreviousAuctionNotClaimed();

PriceOverflow

Thrown when a price calculation would overflow

error PriceOverflow();

InvalidNFT

Thrown when an invalid NFT contract address is provided (zero address)

error InvalidNFT();

InvalidManager

Thrown when an invalid manager contract address is provided (zero address)

error InvalidManager();

InvalidChef

Thrown when an invalid BeraChef contract address is provided (zero address)

error InvalidChef();

InvalidValidatorPubkey

Thrown when an invalid validator pubkey is provided (wrong length or not registered)

error InvalidValidatorPubkey();

InvalidWeights

Thrown when cutting board weights are invalid (not whitelisted vaults or total != 10000)

error InvalidWeights();

ValidatorNotAvailable

Thrown when attempting to auction a validator that is not currently available

error ValidatorNotAvailable();

ZeroAddress

Thrown when a zero address is provided where a valid address is required

error ZeroAddress();

Structs

CuttingBoardDutchAuctionStorage

Note: storage-location: erc7201:infrared.storage.CuttingBoardDutchAuction

struct CuttingBoardDutchAuctionStorage {
    /// @notice Infrared address
    IInfrared infrared;
    /// @notice Payment token for auction bids (must be a plain ERC20 i.e. not fee on transfer or blacklist)
    ERC20 paymentToken;
    /// @notice Treasury address receiving auction payments
    address treasury;
    /// @notice BeraChef contract for vault whitelist validation
    IBeraChefVaultCheck chef;
    /// @notice CuttingBoardNFT contract for minting control rights
    CuttingBoardNFT controlNFT;
    /// @notice CuttingBoardManager for queueing initial cutting boards
    CuttingBoardManager controlManager;
    /// @notice Auction duration in seconds (price decay period)
    uint256 auctionDuration;
    /// @notice Allocation duration in seconds (how long winner controls validator)
    uint256 allocationDuration;
    /// @notice Maximum number of auctions
    uint256 maxAuctions;
    /// @notice Starting price multiplier (e.g., 2e18 = 2x previous price)
    uint256 startingPriceMultiplier;
    /// @notice Base price divisor (e.g., 2e18 = 0.5x previous price)
    uint256 basePriceDivisor;
    /// @notice Minimum price floor
    uint256 minimumPrice;
    /// @notice Reference to last closing price for next auction
    uint256 lastClosingPrice;
    /// @notice Array of all auctions
    Auction[] auctions;
    /// @notice Mapping from auction ID to validator pubkey
    mapping(uint256 => bytes) auctionValidators;
    /// @notice Mapping from validator pubkey hash to active auction ID (0 = none)
    mapping(bytes32 => uint256) activeValidatorAuctions;
    /// @notice Mapping from validator pubkey hash to control token id
    mapping(bytes32 => uint256) validatorControlTokenId;
}

Auction

Auction data structure (optimized for storage)

Packed to minimize storage slots

struct Auction {
    /// @dev Timestamp when the auction started (uint128 to save gas)
    uint128 startTime;
    /// @dev Initial auction price at start time
    uint128 startingPrice;
    /// @dev Floor price after full auction duration
    uint128 basePrice;
    /// @dev Actual price paid when claimed (0 if not claimed)
    uint128 claimPrice;
    /// @dev Address of the auction winner (address(0) if not claimed)
    address winner;
    /// @dev Whether the auction has been claimed
    bool claimed;
    /// @dev Duration in seconds the winner controls the validator
    uint32 allocationDuration;
    /// @dev Token ID of the minted control NFT (0 if not claimed)
    uint256 controlTokenId;
}

InitParams

Initialization parameters struct to avoid stack too deep

struct InitParams {
    address infrared;
    address paymentToken;
    address treasury;
    address chef;
    address controlNFT;
    address controlManager;
    address governance;
    address keeper;
    uint256 auctionDuration;
    uint256 allocationDuration;
    uint256 maxAuctions;
    uint256 startingPriceMultiplier;
    uint256 basePriceDivisor;
    uint256 minimumPrice;
}