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

CuttingBoardManager

Git Source

Inherits: Upgradeable

Title: CuttingBoardManager

Manages validator cutting board updates for NFT holders with 2-step proposal/approval process

Acts as a KEEPER_ROLE intermediary between NFT holders and the Infrared contract. NFT holders propose cutting board updates, keepers approve them. This contract must be granted KEEPER_ROLE on the Infrared contract.

Uses ERC-7201 namespaced storage pattern for upgradeability

State Variables

CUTTING_BOARD_MANAGER_STORAGE_LOCATION

bytes32 private constant CUTTING_BOARD_MANAGER_STORAGE_LOCATION =
    0x9fd5aaf305ec5d9d4acf2d4a2d8f6d67e82cf32b8c76929329ec5790707b7d00

__gap

uint256[20] private __gap

Functions

_getCuttingBoardManagerStorage

function _getCuttingBoardManagerStorage()
    private
    pure
    returns (CuttingBoardManagerStorage storage $);

infrared

function infrared() public view returns (IInfrared);

controlNFT

function controlNFT() public view returns (CuttingBoardNFT);

chef

function chef() public view returns (IBeraChefVaultCheck);

proposalValidityDuration

function proposalValidityDuration() public view returns (uint256);

constructor

Note: oz-upgrades-unsafe-allow: constructor

constructor() ;

initialize

Initialize the CuttingBoardManager

function initialize(
    address _infrared,
    address _controlNFT,
    address _chef,
    address _governance,
    address _keeper,
    uint256 _proposalValidityDuration
) external initializer;

Parameters

NameTypeDescription
_infraredaddressAddress of the Infrared contract
_controlNFTaddressAddress of the CuttingBoardNFT contract
_chefaddressAddress of the BeraChef contract
_governanceaddressAddress of governance (receives GOVERNANCE_ROLE and DEFAULT_ADMIN_ROLE)
_keeperaddressAddress of the keeper (receives KEEPER_ROLE)
_proposalValidityDurationuint256Duration in seconds for which proposals are valid

proposeCuttingBoard

Propose a cutting board update for a validator controlled by NFT

function proposeCuttingBoard(
    uint256 tokenId,
    IBeraChef.Weight[] calldata weights
) external virtual whenNotPaused;

Parameters

NameTypeDescription
tokenIduint256NFT token ID proving control rights
weightsIBeraChef.Weight[]New cutting board distribution

approveCuttingBoard

Approve a cutting board proposal (keeper only)

function approveCuttingBoard(uint256 tokenId)
    external
    virtual
    whenNotPaused
    onlyKeeper;

Parameters

NameTypeDescription
tokenIduint256NFT token ID of the proposal to approve

cancelProposal

Cancel a pending proposal

function cancelProposal(uint256 tokenId) external virtual;

Parameters

NameTypeDescription
tokenIduint256NFT token ID of the proposal to cancel

getLastUpdateBlock

Get the last update block for an NFT

function getLastUpdateBlock(uint256 tokenId)
    external
    view
    virtual
    returns (uint256);

Parameters

NameTypeDescription
tokenIduint256The NFT token ID

Returns

NameTypeDescription
<none>uint256The block number of the last update

getPendingProposalTokenIds

Get all token IDs that have valid pending proposals awaiting keeper approval

Iterates through all minted NFTs to find those with non-expired proposals. Uses a two-pass approach: first counts valid proposals, then fills the array. Useful for keepers to discover which proposals need review.

function getPendingProposalTokenIds()
    external
    view
    virtual
    returns (uint256[] memory tokenIds);

Returns

NameTypeDescription
tokenIdsuint256[]Array of token IDs with pending proposals (may be empty)

_isPendingProposal

Check if a token ID has a valid pending proposal

function _isPendingProposal(
    CuttingBoardManagerStorage storage $,
    uint256 tokenId
) internal view virtual returns (bool);

Parameters

NameTypeDescription
$CuttingBoardManagerStorageStorage reference
tokenIduint256The token ID to check

Returns

NameTypeDescription
<none>boolTrue if there is a valid pending proposal for this token

_checkForDuplicateReceivers

Duplicate vault check in proposed cutting board

function _checkForDuplicateReceivers(IBeraChef.Weight[] calldata weights)
    internal
    pure;

getProposal

Get proposal details for a token ID

function getProposal(uint256 tokenId)
    external
    view
    virtual
    returns (
        address proposer,
        uint64 startBlock,
        uint64 proposedAt,
        bool exists,
        IBeraChef.Weight[] memory weights
    );

Parameters

NameTypeDescription
tokenIduint256The NFT token ID

Returns

NameTypeDescription
proposeraddressAddress of the proposer
startBlockuint64Block when allocation activates
proposedAtuint64Timestamp when proposed
existsboolWhether the proposal exists
weightsIBeraChef.Weight[]The proposed weights

isProposalExpired

Check if a proposal has expired

function isProposalExpired(uint256 tokenId)
    external
    view
    virtual
    returns (bool);

Parameters

NameTypeDescription
tokenIduint256The NFT token ID

Returns

NameTypeDescription
<none>boolTrue if the proposal exists and has expired

canProposeNow

Check if an NFT can propose now

function canProposeNow(uint256 tokenId)
    external
    view
    virtual
    returns (bool);

Parameters

NameTypeDescription
tokenIduint256The NFT token ID

Returns

NameTypeDescription
<none>boolTrue if the NFT can propose a cutting board update

setProposalValidityDuration

Update proposal validity duration

proposal duration should be less than allocation duration, though not enforced

function setProposalValidityDuration(uint256 _proposalValidityDuration)
    external
    virtual
    onlyGovernor;

Parameters

NameTypeDescription
_proposalValidityDurationuint256New duration in seconds

revokeControl

Emergency: Invalidate an NFT's control rights

function revokeControl(uint256 tokenId) external virtual onlyGovernor;

Parameters

NameTypeDescription
tokenIduint256The NFT token ID to invalidate

_validateWeights

Validate cutting board weights

function _validateWeights(IBeraChef.Weight[] calldata weights)
    internal
    virtual;

Parameters

NameTypeDescription
weightsIBeraChef.Weight[]The weights to validate

Events

CuttingBoardProposed

Emitted when a cutting board proposal is created

event CuttingBoardProposed(
    uint256 indexed tokenId,
    address indexed proposer,
    bytes validatorPubkey,
    IBeraChef.Weight[] weights
);

Parameters

NameTypeDescription
tokenIduint256The NFT token ID used for authorization
proposeraddressThe address that created the proposal
validatorPubkeybytesThe validator whose cutting board will be updated
weightsIBeraChef.Weight[]The proposed cutting board weights

CuttingBoardApproved

Emitted when a cutting board proposal is approved

event CuttingBoardApproved(
    uint256 indexed tokenId,
    address indexed approver,
    bytes validatorPubkey,
    uint64 startBlock,
    IBeraChef.Weight[] weights
);

Parameters

NameTypeDescription
tokenIduint256The NFT token ID used for authorization
approveraddressThe keeper who approved the proposal
validatorPubkeybytesThe validator whose cutting board was updated
startBlockuint64The block when the new allocation activates
weightsIBeraChef.Weight[]The new cutting board weights

ProposalCancelled

Emitted when a cutting board proposal is cancelled

event ProposalCancelled(uint256 indexed tokenId, address indexed canceller);

Parameters

NameTypeDescription
tokenIduint256The NFT token ID
cancelleraddressThe address that cancelled the proposal

ProposalValidityDurationUpdated

Emitted when the proposal validity duration is changed

event ProposalValidityDurationUpdated(
    uint256 oldDuration, uint256 newDuration
);

Parameters

NameTypeDescription
oldDurationuint256The previous duration in seconds
newDurationuint256The new duration in seconds

Errors

NotNFTOwner

Thrown when caller is not the NFT owner

error NotNFTOwner();

NFTExpired

Thrown when NFT has expired

error NFTExpired();

NFTInactive

Thrown when NFT is inactive

error NFTInactive();

UpdateTooSoon

Thrown when trying to update too soon after last update

error UpdateTooSoon();

InvalidWeightSum

Thrown when weights don't sum to exactly 10000 (100%)

error InvalidWeightSum();

VaultNotWhitelisted

Thrown when a vault in weights is not whitelisted

error VaultNotWhitelisted();

EmptyWeights

Thrown when weights array is empty

error EmptyWeights();

InvalidAddress

Thrown when invalid address provided in initializer

error InvalidAddress();

InvalidProposer

Thrown when ownership changes and old proposer is no longer valid

error InvalidProposer();

NoProposalExists

Thrown when no proposal exists for the given tokenId

error NoProposalExists();

ProposalAlreadyExists

Thrown when a proposal already exists for the tokenId

error ProposalAlreadyExists();

ProposalExpired

Thrown when a proposal has expired

error ProposalExpired();

NotProposer

Thrown when caller is not the proposer

error NotProposer();

TooManyWeights

Thrown when cutting board allocation has too many vaults

error TooManyWeights();

InvalidWeight

Thrown when cutting board vault has either 0 or a percentage greater than max defined by berachain

error InvalidWeight();

AlreadyQueue

Thrown when outstanding cutting board queue for validator prevents new update

error AlreadyQueue();

DuplicateReceiver

Thrown when duplicate vaults provided in cutting board

error DuplicateReceiver();

InvalidDuration

Thrown when proposalValidityDuration is zero

error InvalidDuration();

Structs

CuttingBoardManagerStorage

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

struct CuttingBoardManagerStorage {
    /// @notice Reference to the Infrared core contract
    IInfrared infrared;
    /// @notice Reference to the CuttingBoardNFT contract
    CuttingBoardNFT controlNFT;
    /// @notice Reference to BeraChef for vault whitelist validation
    IBeraChefVaultCheck chef;
    /// @notice Duration in seconds for which a proposal remains valid
    uint256 proposalValidityDuration;
    /// @notice Last block number an NFT updated its cutting board
    mapping(uint256 => uint256) lastUpdateBlock;
    /// @notice Active proposals by tokenId
    mapping(uint256 => Proposal) proposals;
}

Proposal

Represents a cutting board update proposal

struct Proposal {
    address proposer;
    uint64 startBlock;
    uint64 proposedAt;
    bool exists;
    IBeraChef.Weight[] weights;
}