> ## Documentation Index
> Fetch the complete documentation index at: https://docs.monad.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Staking Overview

> How to interact with Monad's staking system

export const CopyToClipboard = ({value, children}) => {
  const [copied, setCopied] = useState(false);
  const handleCopy = async () => {
    try {
      await navigator.clipboard.writeText(value);
      setCopied(true);
      setTimeout(() => setCopied(false), 1000);
    } catch {
      const textarea = document.createElement("textarea");
      textarea.value = value;
      textarea.style.position = "fixed";
      textarea.style.opacity = "0";
      document.body.appendChild(textarea);
      textarea.select();
      document.execCommand("copy");
      document.body.removeChild(textarea);
      setCopied(true);
      setTimeout(() => setCopied(false), 1000);
    }
  };
  return <span style={{
    display: "inline",
    whiteSpace: "nowrap"
  }}>
      {children}
      <button onClick={handleCopy} title={copied ? "Copied!" : "Copy to clipboard"} style={{
    background: "none",
    border: "none",
    cursor: "pointer",
    padding: "2px",
    display: "inline-flex",
    alignItems: "center",
    verticalAlign: "middle",
    marginLeft: "4px",
    opacity: copied ? 1 : 0.4,
    transition: "opacity 0.15s"
  }} onMouseEnter={e => {
    if (!copied) e.currentTarget.style.opacity = "0.8";
  }} onMouseLeave={e => {
    if (!copied) e.currentTarget.style.opacity = "0.4";
  }}>
        {copied ? <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#22c55e" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
            <polyline points="20 6 9 17 4 12" />
          </svg> : <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
          </svg>}
      </button>
    </span>;
};

Monad uses a [precompile](/developer-essentials/precompiles) to manage validator delegation and rewards.

This page covers the key concepts and workflows for interacting with the staking precompile. For the full interface reference, visit the [API](/reference/staking/api) page. To learn how Monad's staking system works, visit the [learn](/monad-arch/consensus/staking) tab.

The staking precompile is at address <CopyToClipboard value="0x0000000000000000000000000000000000001000">`0x1000`</CopyToClipboard>.

## Key concepts

### Epochs and timing

Staking state changes don't take effect immediately. Monad divides time into **epochs**, and most actions only activate at the start of a new epoch.

Every 50,000 blocks (\~5.5 hours) is a **boundary block** that commits upcoming staking changes. After a 5,000-round delay (`EPOCH_DELAY_ROUNDS`), the new epoch starts.

<img src="https://mintcdn.com/monadfoundation-40611fb6/c3ZcPFY7YVeS_v57/static/img/developer-essentials/staking/staking-timeline.png?fit=max&auto=format&n=c3ZcPFY7YVeS_v57&q=85&s=0ee7ed2436b3407c56687f1764dccf9a" alt="timeline showing the placement of boundary blocks within an epoch" width="2983" height="647" data-path="static/img/developer-essentials/staking/staking-timeline.png" />

This means your action activates in either:

* **Epoch n+1** — if submitted before the boundary block
* **Epoch n+2** — if submitted after the boundary block (in the epoch delay period)

Use [`getEpoch()`](/reference/staking/api#getepoch) to check the current epoch and whether the boundary has passed:

```solidity theme={null}
(uint64 epoch, bool inEpochDelayPeriod) = IMonadStaking(STAKING_ADDRESS).getEpoch();
// If inEpochDelayPeriod is false: changes take effect in epoch + 1
// If inEpochDelayPeriod is true:  changes take effect in epoch + 2
```

<Note>
  A round is not a block — rounds increment even on missed proposals. You cannot calculate epoch boundaries with modular arithmetic on block numbers. Always use `getEpoch()`.
</Note>

### Withdrawal delay

Undelegated stake is not immediately available. After calling `undelegate`, you must wait `WITHDRAWAL_DELAY` (1 epoch) before calling `withdraw` to reclaim the funds.

## Common actions

### Delegate

To delegate MON to a validator, call `delegate(validatorId)` with the amount as `msg.value`:

```solidity theme={null}
IMonadStaking(STAKING_ADDRESS).delegate{value: amount}(validatorId);
```

* `msg.value` must be at least `DUST_THRESHOLD` (1 gwei).
* Your delegation becomes active in the next epoch (or the one after, if past the boundary block).
* If this causes the validator's total stake to meet `ACTIVE_VALIDATOR_STAKE`, the validator is added to the active set.

### Undelegate and withdraw

Removing stake is a two-step process:

**Step 1: Undelegate** — Initiate the withdrawal by specifying the amount and a `withdrawId` (0–255):

```solidity theme={null}
IMonadStaking(STAKING_ADDRESS).undelegate(validatorId, amount, withdrawId);
```

**Step 2: Withdraw** — After `WITHDRAWAL_DELAY` epochs have passed, call `withdraw` to reclaim the funds:

```solidity theme={null}
IMonadStaking(STAKING_ADDRESS).withdraw(validatorId, withdrawId);
```

<img src="https://mintcdn.com/monadfoundation-40611fb6/c3ZcPFY7YVeS_v57/static/img/developer-essentials/staking/undelegate-timeline.png?fit=max&auto=format&n=c3ZcPFY7YVeS_v57&q=85&s=8511c75f512336d15c497ca89b1ea653" alt="timeline of undelegation and withdrawal" width="400" style={{marginLeft: "auto", marginRight: "auto"}} data-path="static/img/developer-essentials/staking/undelegate-timeline.png" />

<p style={{textAlign: "center", fontSize: "0.875rem", opacity: 0.65, marginTop: "0.5rem", fontStyle: "italic"}}>Timeline of withdrawability of stake relative to <code>undelegate</code></p>

* You can only undelegate **active** stake (not pending delegations).
* Each `(validator, delegator)` pair supports up to 256 concurrent withdrawal requests.
* `withdrawId`s can be reused after the withdrawal completes.

### Claim and compound rewards

Rewards accumulate automatically as your validator produces blocks. You have two options:

* **Claim rewards** — withdraw accumulated rewards to your account:
  ```solidity theme={null}
  IMonadStaking(STAKING_ADDRESS).claimRewards(validatorId);
  ```
  Claims take effect **immediately** — no epoch delay.

* **Compound rewards** — re-delegate accumulated rewards, increasing your stake:
  ```solidity theme={null}
  IMonadStaking(STAKING_ADDRESS).compound(validatorId);
  ```
  Compounded rewards activate in the next epoch (following the standard timing rules).

### Query staking state

Key view methods for reading staking state:

| Method                                                                                                  | Purpose                                                                  |
| ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| [`getValidator(validatorId)`](/reference/staking/api#getvalidator)                                      | Full validator state across execution, consensus, and snapshot views     |
| [`getDelegator(validatorId, address)`](/reference/staking/api#getdelegator)                             | Delegator's stake, rewards, and pending changes for a specific validator |
| [`getWithdrawalRequest(validatorId, address, withdrawId)`](/reference/staking/api#getwithdrawalrequest) | Status of a pending withdrawal                                           |
| [`getEpoch()`](/reference/staking/api#getepoch)                                                         | Current epoch and whether boundary has passed                            |
| [`getConsensusValidatorSet(startIndex)`](/reference/staking/api#getvalidatorset)                        | Current epoch's leader validators (paginated)                            |
| [`getSnapshotValidatorSet(startIndex)`](/reference/staking/api#getvalidatorset)                         | Next epoch's leader validators (paginated)                               |
| [`getExecutionValidatorSet(startIndex)`](/reference/staking/api#getvalidatorset)                        | All validators meeting active staking criteria (paginated)               |
| [`getProposerValId()`](/reference/staking/api#getproposervalid)                                         | Validator ID of the current block's proposer                             |
| [`getDelegations(address, startValId)`](/reference/staking/api#getdelegations)                          | All validators a delegator has delegated to (paginated)                  |
| [`getDelegators(validatorId, startDelegator)`](/reference/staking/api#getdelegators)                    | All delegators for a validator (paginated)                               |

Paginated methods return up to 100 results per call. Pass `startIndex = 0` for the first call, then use `nextIndex` for subsequent calls until `isDone` is true.

## Constraints

Because the staking system is a precompile rather than a smart contract, it has some behavioral differences.

* **Only `CALL` is allowed.** `STATICCALL`, `DELEGATECALL`, and `CALLCODE` will revert. This means all view methods use `nonpayable` state mutability rather than `view`.
* **No forked environment testing.** The staking system is a precompile, not a smart contract — there is no code at the address, so forked testing environments won't work.
* **Boundary block timing.** Actions submitted during the epoch delay period (after the boundary block) won't take effect until two epochs later. Check `getEpoch()` if timing matters.
* **Dust threshold.** Delegations below `DUST_THRESHOLD` (1 gwei) will revert.
* **EIP-7702 caveat.** If an account delegates to the staking precompile address using EIP-7702, all calls to it will revert.

## Further reading

* [API reference](/reference/staking/api) — Full reference for the staking precompile with method signatures, parameters, gas costs, events, structs, and ABI
* [How staking works](/monad-arch/consensus/staking) — How Monad's staking system determines validator voting weights, epoch scheduling, and reward distribution
