Skip to main content
StakeManager is the main contract for validator-related activities including checkPoint signature verification, reward distribution, and stake management on Ethereum. Ownership is tracked via NFT IDs; transferring ownership or changing the signer does not affect system state. Stakers are divided into validators, delegators, and watchers (for fraud reporting). Source: StakeManager.sol
From a single Ethereum address, a staker can only function as either a validator or a delegator (design choice, not a technical constraint).

Validator admissions and replacement

Admissions

The system allows a maximum of 105 active validators at any given time. New validators join the active set only when a currently active validator unbonds or is removed for low performance.

Replacement

PIP4 introduced validator performance management. Validators in an unhealthy state for an extended period are off-boarded; the slot is made available to the next in the waitlist.

Methods and variables

validatorThreshold

Stores the maximum number of validators (slots) accepted by the system.

AccountStateRoot

  • Account root for validator and delegator accounting on Heimdall, submitted with each checkpoint.
  • Used by claimRewards and unStakeClaim.

stake / stakeFor

StakeManager.sol
function stake(
    uint256 amount,
    uint256 heimdallFee,
    bool acceptDelegation,
    bytes calldata signerPubkey
) public;

function stakeFor(
    address user,
    uint256 amount,
    uint256 heimdallFee,
    bool acceptDelegation,
    bytes memory signerPubkey
) public;
  • Allows staking if amount exceeds minDeposit and currentValidatorSetSize is less than validatorThreshold.
  • Requires transfer of amount + heimdallFee.
  • updateTimeLine updates the timeline data structure tracking active validators and stake per epoch/checkpoint.
  • Mints one unique NFT per stake or stakeFor call (one NFT per Ethereum address).
  • Setting acceptDelegation to true deploys a ValidatorShare contract for the validator.

unstake

  • Removes validator from validator set in the next epoch.
  • Updates the timeline data structure; records exit epoch.
  • If delegation is active, collects all rewards and locks the delegation contract against new delegations.

unstakeClaim

function unstakeClaim(uint256 validatorId) public;
After WITHDRAWAL_DELAY period, validators call this function to settle with stakeManager: collect remaining rewards, retrieve staked tokens, and burn the NFT.

restake

function restake(uint256 validatorId, uint256 amount, bool stakeRewards) public;
  • Allows validators to increase stake using new tokens, accumulated rewards, or both.
  • Updates the timeline for active stake.

withdrawRewards

function withdrawRewards(uint256 validatorId) public;
Withdraws accumulated rewards for a validator. If the validator accepts delegation, rewards from the delegation contract are also included.

updateSigner

function updateSigner(uint256 validatorId, bytes memory signerPubkey) public
Updates the signer address used to validate blocks on Polygon and checkpoint signatures on stakeManager.

topUpForFee

function topUpForFee(uint256 validatorId, uint256 heimdallFee) public;
Tops up a validator’s Heimdall fee balance.

claimFee

function claimFee(
        uint256 validatorId,
        uint256 accumSlashedAmount,
        uint256 accumFeeAmount,
        uint256 index,
        bytes memory proof
    ) public;
Withdraws fees from Heimdall. accountStateRoot is updated on each checkpoint; validators provide a proof of inclusion in this root to withdraw fees. accountStateRoot is re-written per checkpoint to prevent double exits.

Staking NFT

Standard ERC721 contract with one token per user, minted sequentially.

checkSignatures

function checkSignatures(
        uint256 blockInterval,
        bytes32 voteHash,
        bytes32 stateRoot,
        bytes memory sigs
    ) public;
  • Called by the RootChain contract when submitting checkpoints.
  • Validates unique signatures and checks for 2/3+12/3+1 stake weight on voteHash.
  • currentValidatorSetTotalStake provides the current active stake.
  • Rewards are distributed proportionally to validator stake.

isValidator

Checks whether a given validator is active in the current epoch.

Timeline data structure

struct State {
    int256 amount;
    int256 stakerCount;
}

mapping(uint256 => State) public validatorState;
Figure: Knowledge base - node setup 1

StakingInfo

Centralized logging contract for validator and delegation events. Includes read-only functions. Source: StakingInfo.sol

ValidatorShareFactory

Factory contract that deploys a ValidatorShare contract for each validator that opts into delegation. Source: ValidatorShareFactory.sol