CuttingBoardDutchAuction
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
| Name | Type | Description |
|---|---|---|
params | InitParams | Initialization 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
| Name | Type | Description |
|---|---|---|
validatorPubkey | bytes | The 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
| Name | Type | Description |
|---|---|---|
auctionId | uint256 | The auction ID to claim |
initialWeights | IBeraChef.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
| Name | Type | Description |
|---|---|---|
auctionId | uint256 | The auction ID |
auction | Auction | Storage reference to auction |
currentPrice | uint256 | The current auction price |
validatorPubkey | bytes | The validator pubkey |
initialWeights | IBeraChef.Weight[] | Initial cutting board weights |
Returns
| Name | Type | Description |
|---|---|---|
tokenId | uint256 | The 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
| Name | Type | Description |
|---|---|---|
auctionId | uint256 | The auction ID |
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Current price (decays linearly) |
isValidatorAvailable
Check if a validator is available for auction
function isValidatorAvailable(bytes calldata validatorPubkey)
external
view
virtual
returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
validatorPubkey | bytes | The validator pubkey to check |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | True 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
| Name | Type | Description |
|---|---|---|
validatorPubkey | bytes | The validator pubkey to check |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | True 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
| Name | Type | Description |
|---|---|---|
auctionId | uint256 | The auction ID |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bytes | The validator pubkey |
getAuction
Get complete auction details
function getAuction(uint256 auctionId)
external
view
virtual
returns (Auction memory auction_, bytes memory validatorPubkey);
Parameters
| Name | Type | Description |
|---|---|---|
auctionId | uint256 | The auction ID |
Returns
| Name | Type | Description |
|---|---|---|
auction_ | Auction | The auction struct data |
validatorPubkey | bytes | The validator pubkey for this auction |
getAuctionCount
Get total number of auctions
function getAuctionCount() external view virtual returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | The total number of auctions created |
isAuctionActive
Check if an auction is active
function isAuctionActive(uint256 auctionId)
external
view
virtual
returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
auctionId | uint256 | The auction ID |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | True 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
| Name | Type | Description |
|---|---|---|
auctionId | uint256 | The ID of the active auction (0 if none active) |
isActive | bool | True 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
| Name | Type | Description |
|---|---|---|
auctionId | uint256 | The ID of the last auction (0 if none exist) |
auction_ | Auction | The auction struct data |
validatorPubkey | bytes | The validator pubkey for this auction |
exists | bool | True 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
| Name | Type | Description |
|---|---|---|
validatorPubkey | bytes | The validator pubkey to search for (must be 48 bytes) |
Returns
| Name | Type | Description |
|---|---|---|
auctionId | uint256 | The ID of the last auction for this validator (0 if not found) |
auction_ | Auction | The auction struct data (empty if not found) |
exists | bool | True 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
| Name | Type | Description |
|---|---|---|
price | uint256 | The 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
| Name | Type | Description |
|---|---|---|
_auctionDuration | uint256 | New 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
| Name | Type | Description |
|---|---|---|
_allocationDuration | uint256 | New allocation duration in seconds |
setMaxAuctions
Update the maximum number of auctions
function setMaxAuctions(uint256 _maxAuctions)
external
virtual
onlyGovernor;
Parameters
| Name | Type | Description |
|---|---|---|
_maxAuctions | uint256 | New 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
| Name | Type | Description |
|---|---|---|
_minimumPrice | uint256 | New 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
| Name | Type | Description |
|---|---|---|
_basePriceDivisor | uint256 | New 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
| Name | Type | Description |
|---|---|---|
_startingPriceMultiplier | uint256 | New multiplier (e.g., 2e18 = 2x previous price) |
_isValidatorAvailable
Check if a validator is available for a new auction
A validator is available if:
- No active auction exists for this validator
- Control period has expired (if previously controlled)
function _isValidatorAvailable(bytes32 validatorHash)
internal
view
virtual
returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
validatorHash | bytes32 | Keccak256 hash of the validator pubkey |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | True 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
| Name | Type | Description |
|---|---|---|
auctionId | uint256 | The unique identifier for the auction |
validatorHash | bytes32 | Hash of validator pubkey for cutting board auction |
startingPrice | uint256 | The initial price at auction start |
basePrice | uint256 | The floor price after auction duration |
startTime | uint256 | The timestamp when the auction started |
allocationDuration | uint256 | The 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
| Name | Type | Description |
|---|---|---|
auctionId | uint256 | The unique identifier for the auction |
winner | address | The address that won the auction |
validatorHash | bytes32 | Hash of validator pubkey for cutting board auction |
pricePaid | uint256 | The final price paid to claim the auction |
controlTokenId | uint256 | The NFT id with cutting board control |
allocationDuration | uint256 | The duration in seconds the winner controls the allocation |
AuctionDurationUpdated
Emitted when auction duration is updated
event AuctionDurationUpdated(uint256 newDuration);
Parameters
| Name | Type | Description |
|---|---|---|
newDuration | uint256 | The new auction duration in seconds |
AllocationDurationUpdated
Emitted when allocation duration is updated
event AllocationDurationUpdated(uint256 newDuration);
Parameters
| Name | Type | Description |
|---|---|---|
newDuration | uint256 | The new allocation duration in seconds |
MaxAuctionsUpdated
Emitted when max auctions is updated
event MaxAuctionsUpdated(uint256 newMaxAuctions);
Parameters
| Name | Type | Description |
|---|---|---|
newMaxAuctions | uint256 | The new maximum number of auctions |
MinimumPriceUpdated
Emitted when minimum price is updated
event MinimumPriceUpdated(uint256 newPrice);
Parameters
| Name | Type | Description |
|---|---|---|
newPrice | uint256 | The new minimum price |
BasePriceDivisorUpdated
Emitted when base price divisor is updated
event BasePriceDivisorUpdated(uint256 newDivisor);
Parameters
| Name | Type | Description |
|---|---|---|
newDivisor | uint256 | The new base price divisor |
StartingPriceMultiplierUpdated
Emitted when starting price multiplier is updated
event StartingPriceMultiplierUpdated(uint256 newMultiplier);
Parameters
| Name | Type | Description |
|---|---|---|
newMultiplier | uint256 | The new starting price multiplier |
InitialPriceSet
Emitted when initial price is set
event InitialPriceSet(uint256 price);
Parameters
| Name | Type | Description |
|---|---|---|
price | uint256 | The 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;
}