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

# Validator staking

# ValidatorStaking

The `ValidatorStaking` contract (Solidity name `NotareumValidatorStaking`) manages the NOTA-denominated stakes that validators post to participate in the network. It enforces tier thresholds, tracks active stake, applies unstake cooldowns, distributes attestation rewards, and exposes the `isActive`/`tierOf` view functions that `VerificationEngine` relies on when admitting attestations.

## Tiers

Four tiers, each with a minimum stake, daily attestation cap, reward multiplier, and slash rate:

| Tier          | Minimum stake (NOTA) | Daily attestations | Reward multiplier | Max slash rate |
| ------------- | -------------------: | -----------------: | ----------------: | -------------: |
| Basic         |               10,000 |                 10 |              1.0× |            10% |
| Professional  |               50,000 |                 50 |              1.5× |            15% |
| Enterprise    |              250,000 |                200 |              2.0× |            20% |
| Institutional |            1,000,000 |          unlimited |              2.5× |            25% |

Higher tiers carry higher trust, higher income potential, and higher downside on misbehavior. These parameters are governance-adjustable via [FeeManager](fee-manager.md) and [SlashingManager](slashing-manager.md) respectively; the values above are the initial constants.

## Data structures

```solidity theme={"system"}
struct ValidatorInfo {
    uint256 stake;              // effective bonded stake
    uint256 pendingUnstake;     // amount in cooldown
    uint64  unstakeUnlockAt;    // timestamp when pending is withdrawable
    uint64  registeredAt;
    uint64  lastAttestationAt;
    uint32  attestationsToday;
    uint32  dayOfYear;          // rotates daily-cap window
    Tier    tier;
    bool    active;
}

enum Tier { Basic, Professional, Enterprise, Institutional }
```

`tier` is derived from `stake` at every state transition; validators cannot override it.

## Lifecycle

```mermaid theme={"system"}
stateDiagram-v2
    [*] --> Unregistered
    Unregistered --> Active: stake(>= 10k)
    Active --> Active: stake (tier up)
    Active --> Cooldown: unstake(x)
    Cooldown --> Active: claim remaining (partial)
    Cooldown --> Exited: withdrawPending (full)
    Active --> Slashed: SlashingManager.slash
    Slashed --> Active: stake again (if above minimum)
    Slashed --> Exited: unstake remainder
```

## Functions

### `stake`

```solidity theme={"system"}
function stake(uint256 amount) external;
```

Transfers `amount` NOTA from the caller to the contract (requires prior `approve`) and increases the caller's bonded stake. If the caller is new, registers them as an active validator. Recomputes tier based on the new total. Emits `Staked(validator, amount, newStake, newTier)`.

Reverts if the new stake is below the Basic tier minimum (the caller stays unregistered until they reach 10,000 NOTA).

### `unstake`

```solidity theme={"system"}
function unstake(uint256 amount) external;
```

Moves `amount` NOTA from `stake` to `pendingUnstake` and starts the cooldown. Tier is recomputed on the remaining bonded stake. If the remaining stake falls below the Basic minimum, the validator becomes inactive immediately but can still claim pending after cooldown.

Cooldown is tier-dependent:

| Tier          | Cooldown |
| ------------- | -------: |
| Basic         |  14 days |
| Professional  |  21 days |
| Enterprise    |  28 days |
| Institutional |  42 days |

Emits `UnstakeRequested(validator, amount, unlockAt)`.

### `withdrawPending`

```solidity theme={"system"}
function withdrawPending() external;
```

After cooldown, transfers all `pendingUnstake` back to the validator. Emits `Unstaked(validator, amount)`.

### `claimRewards`

```solidity theme={"system"}
function claimRewards() external returns (uint256 amount);
```

Transfers accumulated attestation rewards (from `VerificationEngine`) and staking yield to the validator. Rewards accrue as the validator submits attestations on finalized requests, weighted by the tier multiplier. Emits `RewardsClaimed(validator, amount)`.

### `isActive` / `tierOf`

```solidity theme={"system"}
function isActive(address validator) external view returns (bool);
function tierOf(address validator) external view returns (Tier);
```

Used by `VerificationEngine.submitAttestation` to gate admittance. `isActive` returns true only when the validator has bonded stake at or above the Basic minimum and is not currently under a slashing freeze.

### Governance-only setters

```solidity theme={"system"}
function setTierMinimum(Tier tier, uint256 minStake) external; // role: VALIDATOR_ADMIN
function setCooldown(Tier tier, uint64 seconds_) external;     // role: VALIDATOR_ADMIN
function setDailyAttestationCap(Tier tier, uint32 cap) external; // role: VALIDATOR_ADMIN
function setRewardMultiplier(Tier tier, uint16 bps) external;  // role: VALIDATOR_ADMIN
```

All setters are delay-gated through [AccessManager](access-manager.md).

## Tier upgrade and downgrade

Tier recomputation is pure and synchronous: every `stake`, `unstake`, or slashing event recalculates `tier` from the resulting bonded amount. There is no upgrade application, fee, or delay beyond the stake transfer itself. A validator at Professional who stakes an additional 200,000 NOTA is instantly Enterprise; a validator slashed below the Enterprise minimum is instantly Professional.

The engine also records `Tier priorTier` in the event when the tier changes:

```solidity theme={"system"}
event TierChanged(address indexed validator, Tier priorTier, Tier newTier, uint256 stake);
```

## Cooldown interaction with slashing

If a validator is slashed while funds are in `pendingUnstake`, slashing applies to `stake + pendingUnstake` in that order. A validator cannot escape slashing by pre-emptively initiating unstake; the cooldown is long enough to cover normal dispute windows plus safety margin.

## Rewards model

Each finalized approval on `VerificationEngine` credits all approving validators according to:

```
reward_i = baseReward(level) * multiplier(tier_i) / sum(multiplier(tier_j))
```

where the sum is over approving validators. This allocates a fixed pool per attestation round proportional to tier weight. Base rewards per level are governance-set and funded from `FeeManager` out of the verification fee.

A periodic staking yield is also distributed from the treasury allocation for validator incentives:

```
yield_i = stake_i * annualYieldBps / 10000 * elapsed / 365d
```

Rewards accrue off-book (in a `rewards[validator]` counter) and materialize on `claimRewards`.

## Daily attestation cap

The cap prevents a single cheap validator from dominating a request's attestation slots. The contract rotates `dayOfYear` every 24 hours (`block.timestamp / 86400 % 366`) and resets per-validator counters. `Institutional` validators have `cap = 0`, which the engine interprets as unlimited.

## Access by other contracts

```solidity theme={"system"}
// Called only by VerificationEngine
function recordAttestation(address validator) external;
function creditAttestationReward(address validator, uint256 amount) external;

// Called only by SlashingManager
function applySlash(address validator, uint256 amount) external returns (uint256 slashed);
```

These interfaces are gated via `AccessManager` to the exact contract address of `VerificationEngine` or `SlashingManager`, wired at initialization.

## Events

```solidity theme={"system"}
event Staked(address indexed validator, uint256 amount, uint256 newStake, Tier newTier);
event UnstakeRequested(address indexed validator, uint256 amount, uint64 unlockAt);
event Unstaked(address indexed validator, uint256 amount);
event RewardsClaimed(address indexed validator, uint256 amount);
event TierChanged(address indexed validator, Tier priorTier, Tier newTier, uint256 stake);
event SlashApplied(address indexed validator, uint256 slashed, Tier newTier);
```

## SDK usage

```typescript theme={"system"}
import { Notareum } from "@notareum/sdk";

const ntm = Notareum({ provider, signer, contracts });

// Approve and stake
await ntm.nota.approve(ntm.staking.address, parseNota("50000"));
await ntm.staking.stake(parseNota("50000"));

// Check tier
const tier = await ntm.staking.tierOf(myAddr); // "Professional"
const info = await ntm.staking.getValidator(myAddr);

// Begin unstake (enters cooldown)
await ntm.staking.unstake(parseNota("20000"));

// After cooldown
await ntm.staking.withdrawPending();

// Claim accrued rewards
const claimed = await ntm.staking.claimRewards();
```

## Invariants

1. `stake + pendingUnstake` equals the sum of contract deposits minus withdrawals per validator.
2. `tier == tierFromStake(stake)` at every function exit.
3. A validator's daily attestation count never exceeds `dailyCap(tier)` within a 24-hour window.
4. `pendingUnstake` cannot be claimed before `unstakeUnlockAt`.

## Related pages

* [VerificationEngine](verification-engine.md)
* [SlashingManager](slashing-manager.md)
* [FeeManager](fee-manager.md)
* [NOTA Token](nota-token.md)
* [Staking and Tiers protocol doc](../protocol/staking-and-tiers.md)
