Skip to main content
This page is a technical reference for the staking precompile interface. For a developer-oriented guide to common workflows, visit the overview.

Address

Functions and selectors

Constants

State-modifying functions

addValidator

Creates a validator with an associated delegator account and returns the resultant validatorId. Function selector
Function signature
Parameters
  1. payload - consists of the following fields, packed together in big endian (equivalent to abi.encodePacked() in Solidity):
    • bytes secpPubkey (unique SECP public key used for consensus)
    • bytes blsPubkey (unique BLS public key used for consensus)
    • address authAddress (address used for the validator’s delegator account. This address has withdrawal authority for the validator’s staked amount)
    • uint256 amount (amount the validator is self-staking. Must equal msg.value)
    • uint256 commission (commission charged to delegators multiplied by 1e18, e.g. 10% = 1e17)
  2. signedSecpMessage - SECP signature over payload
  3. signedBlsMessage - BLS signature over payload
Gas cost 505,125 Behavior The function starts by unpacking the payload to retrieve the secpPubkey, blsPubkey, authAddress, amount, and commission, then verifying that the signedSecpMessage and signedBlsMessage correspond to the payload signed by the corresponding SECP and BLS private keys.
  • The validator must provide both a unique BLS key and a unique SECP key. Submissions with any repeated public keys will revert.
  • Both signatures (signedSecpMessage and signedBlsMessage) must be valid and must sign over the payload.
  • Multiple validators may share the same authAddress.
  • msg.value must be equal or greater than MIN_AUTH_ADDRESS_STAKE or the call will revert.
  • If the msg.value is also equal or greater than ACTIVE_VALIDATOR_STAKE then the validator will become active in the future:
    • If addValidator was called before the boundary block, then in epoch n+1;
    • Otherwise it will become active in epoch n+2.
Usage Here is an example of assembling the payload and signing:

delegate

Creates a delegator account if it does not exist and increases the delegator’s balance. Function selector
Function signature
Parameters
  1. validatorId - id of the validator that delegator would like to delegate to
  2. msg.value - the amount to delegate
Gas cost 260,850 Behavior
  • The delegator account is determined by msg.sender.
  • validatorId must correspond to a valid validator.
  • msg.value must be >= DUST_THRESHOLD.
  • If this delegation causes the validator’s total stake to exceed ACTIVE_VALIDATOR_STAKE, then the validator will be added to execution_valset if not already present.
  • The delegator stake becomes active
    • in epoch n+1 if the request is before the boundary block
    • in epoch n+2 otherwise

undelegate

Deducts amount from the delegator account and moves it to a withdrawal request object, where it remains in a pending state for WITHDRAWAL_DELAY epochs before the funds are claimable via the withdraw function. Function selector
Function signature
Parameters
  1. validatorId - id of the validator to which sender previously delegated, from which we are removing delegation
  2. amount - amount to undelegate, in Monad wei
  3. withdrawId - integer between 0 and 255, inclusive, which serves as the identifier for a delegator’s withdrawal. For each (validator, delegator) tuple, there can be a maximum of 256 in-flight withdrawal requests
Gas cost 147,750 Behavior
  • The delegator account is determined by msg.sender.
  • validatorId must correspond to a valid validator to which the sender previously delegated
  • The delegator must have stake >= amount.
  • If the withdrawal causes Val(validatorId).stake() to drop below ACTIVE_VALIDATOR_STAKE, then the validator is scheduled to be removed from the valset.
  • If the authAddress on a validator undelegates enough of their own stake to drop below MIN_AUTH_ADDRESS_STAKE, then the validator is scheduled to be removed from the valset.
  • The function will revert if there is a pending withdrawal with the same withdrawId. withdrawIds can be reused after calling withdraw.
  • A delegator can only remove a stake after it has been activated. This is the stake field in the delegator struct. Pending delegations cannot be removed until they are active.
  • The delegator stake becomes inactive in the valset
    • in epoch n+1 if the request is before the boundary block
    • in epoch n+2 otherwise
  • The delegator stake becomes withdrawable, and thus no longer subject to slashing
    • in epoch n + 1 + WITHDRAWAL_DELAY if the request is before the boundary block
    • in epoch n + 2 + WITHDRAWAL_DELAY otherwise
timeline of undelegation and withdrawal

Timeline of withdrawability of stake relative to undelegate command

withdraw

Completes an undelegation action (which started with a call to the undelegate function), sending the amount to msg.sender, provided that sufficient epochs have passed. Function selector
Function signature
Parameters
  1. validatorId - id of the validator to which sender previously delegated, from which we previously issued an undelegate command
  2. withdrawId - identifier for a delegator’s previously created withdrawal; the same id previously supplied to undelegate. For each (validator, delegator) tuple, there can be a maximum of 256 in-flight withdrawal requests.
Gas cost 68,675 Behavior
  • The delegator is msg.sender. The withdrawal is identified by msg.sender, validatorId, and withdrawId
  • The withdraw action can take place once the undelegation is complete, and the withdraw delay has passed:
    • in epoch n + 1 + WITHDRAWAL_DELAY if the undelegate request is before the boundary block
    • in epoch n + 2 + WITHDRAWAL_DELAY otherwise

compound

Converts the delegator’s accumulated rewards into additional stake. Function selector
Function signature
Parameters
  1. validatorId - id of the validator to which sender previously delegated, for which we are compounding rewards
Gas cost 289,325 Behavior
  • The account compounded is determined by msg.sender. If a delegator account does not exist, then the call reverts
  • validatorId must correspond to a valid validator to which the sender previously delegated
  • The delegator rewards become active in the valset
    • in epoch n+1 if the request is before the boundary block
    • in epoch n+2 otherwise.

claimRewards

Allows a delegator to claim any rewards instead of compounding them. Function selector
Function signature
Parameters
  1. validatorId - id of the validator to which sender previously delegated, for which we are claiming rewards
Gas cost 155,375 Behavior
  • validatorId must correspond to a valid validator to which the sender previously delegated
  • If delegator account does not exist for this (validatorId, msg.sender) tuple, then the call reverts
  • The delegator’s accumulated rewards are transferred to their delegation

changeCommission

Allows the authAddress for a validator to modify the commission for the validator. Function selector
Function signature
Parameters
  1. validatorId - id of the validator, who would like to change their commission rate
  2. commission - commission rate taken from block rewards, expressed in 1e18 units (e.g., 10% = 1e17)
Gas cost 39,475 Behavior
  • The msg.sender must be the authAddress for the respective validator Id.
  • The commission cannot be set larger than MAX_COMMISSION (currently 100%).
  • The change in commission occurs in the following epochs:
    • in epoch n+1 if request is not in the epoch delay rounds.
    • in epoch n+2 if request is in the epoch delay rounds.

externalReward

Allows anyone to send extra MON to the stakers of a particular validator, typically called by the validator themselves to share extra tips to their delegators. Function selector
Function signature
Parameters
  1. validatorId - id of the validator
  2. msg.value - the MON to add to unclaimed rewards
Gas cost 66,575 Behavior
  • This can only be called for a validator currently in the consensus validator set; otherwise the transaction reverts.
  • msg.value must be between 1 MON and 1,000,000 MON; otherwise the transaction reverts.
  • Commission is not deducted from this and diverted to the validator’s auth_address. If you wish for a portion to be deducted, it should be deducted before sending.

View functions

Because only CALLs are allowed to the staking precompile, all view functions are given the default nonpayable state mutability.

getValidator

Returns a complete view of the validator’s state across execution, consensus, and snapshot contexts.
  • ValExecution (execution view)
  • Stake and commission (consensus view)
  • Stake and commission (snapshot view)
Function selector
Function signature
Parameters
  1. validatorId - id of the validator
Gas cost 97,200

getDelegator

Returns the delegator’s DelInfo for the specified validator, providing a view of the delegator’s stake, accumulated rewards, and pending changes in stake. Function selector
Function signature
Parameters
  1. validatorId - id of the validator
  2. delegator - address of the delegator about whose stake we are inquiring
Gas cost 184,900

getWithdrawalRequest

Returns the pending WithdrawalRequest for the (validatorId, delegator, withdrawId) tuple. Function selector
Function signature
Gas cost 24,300

get*ValidatorSet

Returns the consensus, snapshot, and execution validator IDs, respectively. Function selectors
Function signatures
Parameters
  1. startIndex - since the list being looked up is potentially very long, each of these functions is paginated, returning a fixed-length subset of the desired list. Pass startIndex to indicate where in the list to start.
Gas cost 814,000 gas (assuming PAGINATED_RESULTS_SIZE = 100). Behavior getExecutionValidatorSet() returns the entire active validator set of all validators that meet the staking criteria to be considered for inclusion. getSnapshotValidatorSet() returns the subset of validators that have been chosen to be leaders in the next epoch. getConsensusValidatorSet() returns the subset of validators that are leaders in the current epoch. Each call retrieves up to PAGINATED_RESULTS_SIZE validator IDs starting from startIndex and returns a tuple (bool done, uint32 nextIndex, uint256[] valids). The bool isDone indicates whether the end of the list was reached. The uint32 nextIndex is the last slot in the array.

getDelegations

Returns a paginated list of validator IDs that a given delegator address has delegated to. Function selector
Function signature
Parameters
  1. delegator - the address whose delegations we want to look up
  2. startValId
Gas cost 814,000 Behavior Each call retrieves up to PAGINATED_RESULTS_SIZE validator ids starting from startValId and returns a tuple (bool isDone, uint64 nextValId, uint64[] valIds) with delegation from the input delegator address. The bool isdone indicates whether the end of the list was reached. The uint64 nextValId is the id after the last element in valIds. Use it as the startValId for the next call. If delegator has delegated to over PAGINATED_RESULTS_SIZE validator ids, multiple calls are required (while isDone is false). To capture the full set, make the first function call using startValId = 0.

getDelegators

Returns a paginated list of delegator addresses for a given validator. Function selector
Function signature
Parameters
  1. validatorId - the id of the validator for which we want to know the delegators
  2. startDelegator
Gas cost 814,000 Behavior Each call retrieves up to PAGINATED_RESULTS_SIZE delegator addresses starting from startDelegator and returns a tuple (bool isDone, address nextDelegator, address[] delegators) with delegation to the input validatorId. The bool isDone indicates the end of the list was reached. The nextDelegator is the address immediately after the last element in delegators. Use it as startDelegator for the next call. To capture the full set, the function should be called with startDelegator = 0.
The number of delegators to a given validator can be very large, so it is recommended to maintain an updated list via the events framework, rather than periodically calling this expensive lookup.

getEpoch

Returns the current epoch and timing within the epoch (before or after the boundary block). Function selector
Function signature
Gas cost 200 Behavior If inEpochDelayPeriod is false, the boundary block has not been reached yet and write operations at that time should be effective for epoch + 1. If inEpochDelayPeriod is true, the network is past the boundary block and and write operations at that time should be effective for epoch + 2

getProposerValId

Returns the validator ID of the current block proposer, corresponding to the SECP value of the block author. Function selector
Function signature
Gas cost 100

Syscalls

There are currently three syscalls. Users cannot invoke these directly. They are only triggered through special system transactions.

syscallOnEpochChange

Triggered at the end of the epoch delay rounds to finalize accumulator values and update epoch state. Function selector
Function signature
Parameters
  1. epoch - the new consensus epoch being entered
Behavior
  1. If the validator received a request to change stake in the previous epoch and participated in the previous epoch’s consensus validator set then it saves the corresponding accumulator value
  2. If any validator was active in the previous epoch but becomes inactive in the current epoch, it also saves their current accumulator value
  3. Sets the current epoch in state

syscallReward

Rewards the block-producing validator and their delegators with the configured block reward for every block. Function selector
Function signature
Parameters
  1. blockAuthor — the address of the validator that produced the block.
Behavior
  1. If the validator has a nonzero commission, a portion of the reward is allocated to the validator’s authAddress.
  2. The remaining reward is claimable to the validator’s delegators.
Note that the commission is calculated as a percentage of the total block reward.
  • Suppose that a validator’s personal stake comprises 20% of the total delegation to their validator.
  • The commission is set at 10% of total rewards.
Then the validator receives 10% of the total block reward as their commission. The remaining 90% of the reward is distributed to the stake pool. Since the validator owns 20% of the pool, they also receive 20% of that remaining amount.

syscallSnapshot

Sorts the current execution-layer validator set, selects the top N staked validators as the upcoming consensus validator set, stores the updated set in state, and clears the previous consensus set. Function selector
Function signature
Behavior

Events

The staking precompiles emit standard events that appear in transaction receipts. These events provide indexed information about validator and delegator actions.

ValidatorRewarded

Emitted when block reward is allocated via syscallReward, or when extra MON is sent to a validator’s stakers via externalReward.

ValidatorCreated

Emitted when a validator is added via addValidator.

ValidatorStatusChanged

Emitted during addValidator, delegate, undelegate, or compound. if the validator’s flags change.

Delegate

Emitted when delegation amount is increased, i.e. during addValidator, delegate, or compound.

Undelegate

Emitted when a delegator calls undelegate.

Withdraw

Emitted when a delegator executes withdraw successfully.

ClaimRewards

Emitted when a delegator claims rewards via claimRewards.

CommissionChanged

Emitted when a validator changes commission via changeCommission.

EpochChanged

Emitted when epoch changes via syscallOnEpochChange.

Precompile internals

Validator structs

Delegator structs

State variables

Mappings

Solidity Staking Interface

To copy to clipboard, click the button in the top right of the code block.

Staking ABI JSON

To copy to clipboard, click the button in the top right of the code block.

FAQ

There is no direct removeValidator function. Instead, if a validator’s auth_account removes enough stake through undelegate, the validator is removed from the consensus set in a future epoch.This occurs in either epoch n+1 or epoch n+2, depending on whether the undelegate occurred within the epoch delay rounds.Even when not active, a validator’s information is always retained. Validator ids are permanent since other delegators may still be delegating and need to reference that val_id to undelegate/withdraw.
A validator can change their commission by calling changeCommission.
See getDelegator.For pending withdrawals by that delegator from that validator, see getWithdrawalRequest.
Despite using Solidity selectors and ABI, it is a precompile. Accessing code at returns empty code. Its account is always accessed warm, and calls with invalid arguments consume all gas.Exception: if an account attempts to delegate to the staking precompile using EIP-7702, all calls to it will revert.