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

<AgentInstructions>

## Submitting Feedback

If you encounter incorrect, outdated, or confusing documentation on this page, submit feedback:

POST https://docs.ton.org/feedback

```json
{
  "path": "/ecosystem/staking/stake-calculation",
  "feedback": "Description of the issue"
}
```

Only submit feedback when you have something specific and actionable to report.

</AgentInstructions>

# Stake calculation

export const Aside = ({type = "note", title = "", icon = "", iconType = "regular", children}) => {
  const asideVariants = ["note", "tip", "caution", "danger"];
  const asideComponents = {
    note: {
      outerStyle: "border-sky-500/20 bg-sky-50/50 dark:border-sky-500/30 dark:bg-sky-500/10",
      innerStyle: "text-sky-900 dark:text-sky-200",
      calloutType: "note",
      icon: <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="w-4 h-4 text-sky-500" aria-label="Note">
          <path fill-rule="evenodd" clip-rule="evenodd" d="M7 1.3C10.14 1.3 12.7 3.86 12.7 7C12.7 10.14 10.14 12.7 7 12.7C5.48908 12.6974 4.0408 12.096 2.97241 11.0276C1.90403 9.9592 1.30264 8.51092 1.3 7C1.3 3.86 3.86 1.3 7 1.3ZM7 0C3.14 0 0 3.14 0 7C0 10.86 3.14 14 7 14C10.86 14 14 10.86 14 7C14 3.14 10.86 0 7 0ZM8 3H6V8H8V3ZM8 9H6V11H8V9Z"></path>
        </svg>
    },
    tip: {
      outerStyle: "border-emerald-500/20 bg-emerald-50/50 dark:border-emerald-500/30 dark:bg-emerald-500/10",
      innerStyle: "text-emerald-900 dark:text-emerald-200",
      calloutType: "tip",
      icon: <svg width="11" height="14" viewBox="0 0 11 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="text-emerald-600 dark:text-emerald-400/80 w-3.5 h-auto" aria-label="Tip">
          <path d="M3.12794 12.4232C3.12794 12.5954 3.1776 12.7634 3.27244 12.907L3.74114 13.6095C3.88471 13.8248 4.21067 14 4.46964 14H6.15606C6.41415 14 6.74017 13.825 6.88373 13.6095L7.3508 12.9073C7.43114 12.7859 7.49705 12.569 7.49705 12.4232L7.50055 11.3513H3.12521L3.12794 12.4232ZM5.31288 0C2.52414 0.00875889 0.5 2.26889 0.5 4.78826C0.5 6.00188 0.949566 7.10829 1.69119 7.95492C2.14321 8.47011 2.84901 9.54727 3.11919 10.4557C3.12005 10.4625 3.12175 10.4698 3.12261 10.4771H7.50342C7.50427 10.4698 7.50598 10.463 7.50684 10.4557C7.77688 9.54727 8.48281 8.47011 8.93484 7.95492C9.67728 7.13181 10.1258 6.02703 10.1258 4.78826C10.1258 2.15486 7.9709 0.000106649 5.31288 0ZM7.94902 7.11267C7.52078 7.60079 6.99082 8.37878 6.6077 9.18794H4.02051C3.63739 8.37878 3.10743 7.60079 2.67947 7.11294C2.11997 6.47551 1.8126 5.63599 1.8126 4.78826C1.8126 3.09829 3.12794 1.31944 5.28827 1.3126C7.2435 1.3126 8.81315 2.88226 8.81315 4.78826C8.81315 5.63599 8.50688 6.47551 7.94902 7.11267ZM4.87534 2.18767C3.66939 2.18767 2.68767 3.16939 2.68767 4.37534C2.68767 4.61719 2.88336 4.81288 3.12521 4.81288C3.36705 4.81288 3.56274 4.61599 3.56274 4.37534C3.56274 3.6515 4.1515 3.06274 4.87534 3.06274C5.11719 3.06274 5.31288 2.86727 5.31288 2.62548C5.31288 2.38369 5.11599 2.18767 4.87534 2.18767Z"></path>
        </svg>
    },
    caution: {
      outerStyle: "border-amber-500/20 bg-amber-50/50 dark:border-amber-500/30 dark:bg-amber-500/10",
      innerStyle: "text-amber-900 dark:text-amber-200",
      calloutType: "warning",
      icon: <svg className="flex-none w-5 h-5 text-amber-400 dark:text-amber-300/80" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-label="Warning">
          <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
        </svg>
    },
    danger: {
      outerStyle: "border-red-500/20 bg-red-50/50 dark:border-red-500/30 dark:bg-red-500/10",
      innerStyle: "text-red-900 dark:text-red-200",
      calloutType: "danger",
      icon: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" className="text-red-600 dark:text-red-400/80 w-4 h-4" aria-label="Danger">
          <path d="M17.1 292c-12.9-22.3-12.9-49.7 0-72L105.4 67.1c12.9-22.3 36.6-36 62.4-36l176.6 0c25.7 0 49.5 13.7 62.4 36L494.9 220c12.9 22.3 12.9 49.7 0 72L406.6 444.9c-12.9 22.3-36.6 36-62.4 36l-176.6 0c-25.7 0-49.5-13.7-62.4-36L17.1 292zm41.6-48c-4.3 7.4-4.3 16.6 0 24l88.3 152.9c4.3 7.4 12.2 12 20.8 12l176.6 0c8.6 0 16.5-4.6 20.8-12L453.4 268c4.3-7.4 4.3-16.6 0-24L365.1 91.1c-4.3-7.4-12.2-12-20.8-12l-176.6 0c-8.6 0-16.5 4.6-20.8 12L58.6 244zM256 128c13.3 0 24 10.7 24 24l0 112c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-112c0-13.3 10.7-24 24-24zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"></path>
        </svg>
    }
  };
  let variant = type;
  let gotInvalidVariant = false;
  if (!asideVariants.includes(type)) {
    gotInvalidVariant = true;
    variant = "danger";
  }
  const iconVariants = ["regular", "solid", "light", "thin", "sharp-solid", "duotone", "brands"];
  if (!iconVariants.includes(iconType)) {
    iconType = "regular";
  }
  return <>
      <div className={`callout my-4 px-5 py-4 overflow-hidden rounded-2xl flex gap-3 border ${asideComponents[variant].outerStyle}`} data-callout-type={asideComponents[variant].calloutType}>
        <div className="mt-0.5 w-4" data-component-part="callout-icon">
          {}
          {icon === "" ? asideComponents[variant].icon : <Icon icon={icon} iconType={iconType} size={14} />}
        </div>
        <div className={`text-sm prose min-w-0 w-full ${asideComponents[variant].innerStyle}`} data-component-part="callout-content">
          {gotInvalidVariant ? <p>
              <span className="font-bold">
                Invalid <code>type</code> passed!
              </span>
              <br />
              <span className="font-bold">Received: </span>
              {type}
              <br />
              <span className="font-bold">Expected one of: </span>
              {asideVariants.join(", ")}
            </p> : <>
              {title && <p className="font-bold">{title}</p>}
              {children}
            </>}
        </div>
      </div>
    </>;
};

<Aside type="caution" title="Stake affects locked funds">
  Stake configuration directly controls how much TON is locked in the elector contract for a full validation round. Misconfiguration can lock the entire balance, leaving no funds for the next election. Review each setting carefully before applying changes on TON Mainnet.
</Aside>

MyTonCtrl automatically calculates the stake amount before submitting an election entry. The calculation balances operator preferences, staking mode, network-imposed limits, and fee reserves to produce a single integer value (in TON) sent to the [elector contract](/foundations/system).

## Inputs

The calculation draws on several sources:

| Source                                                           | Parameter              | Role                                                                                                              |
| ---------------------------------------------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------- |
| Operator setting                                                 | `stake`                | Fixed stake amount (TON). When set, overrides percentage-based calculation.                                       |
| Operator setting                                                 | `stakePercent`         | Percentage of balance to stake. Defaults to `100` when unset.                                                     |
| Wallet state                                                     | `balance`              | Current TON balance of the staking account (validator wallet, pool, or controller).                               |
| Validator console                                                | Active validator count | Number of validators currently running on this node. Determines whether the node is new or already participating. |
| [On-chain config #17](/foundations/config#param-17-stake-limits) | `minStake`             | Network minimum stake. Submissions below this value are rejected by the elector.                                  |
| [On-chain config #17](/foundations/config#param-17-stake-limits) | `maxStake`             | Network maximum stake. Submissions above this value are clamped.                                                  |
| Node configuration                                               | Staking mode           | Whether the node uses a nominator pool, single nominator pool, liquid staking controller, or direct staking.      |

Configure `stake` and `stakePercent` with the [`set`](/ecosystem/nodes/cpp/mytonctrl/core#set) command:

```mytonctrl theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
set stake 500000
```

```mytonctrl theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
set stakePercent 99
```

Retrieve current values with `get stake` or `get stakePercent`.

## How the priority cascade works

MyTonCtrl evaluates stake sources in a fixed priority order. The first rule that produces a value wins; later rules are skipped.

### Priority 1: Saved fixed stake

If the operator previously ran `set stake <VALUE>`, MyTonCtrl uses that stored amount directly. No additional fee reserve is subtracted at this stage; the value passes straight to the validation guards.

### Priority 2: Nominator pool mode

When the node operates through a standard nominator pool (not a single nominator pool), MyTonCtrl sets:

```text theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
stake = balance - 20
```

The 20 TON reserve covers the higher fee overhead of pool operations (deploy, process, and distribute messages).

<Aside type="note">
  Single nominator pools are excluded from this rule. They fall through to the percentage-based calculation (Priority 4) because single nominator pools behave like direct staking economically.
</Aside>

### Priority 3: Liquid staking controller mode

When the node uses a liquid staking controller, MyTonCtrl sets:

```text theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
stake = balance - 50
```

The 50 TON reserve is the largest of all modes. Liquid staking controllers perform complex multi-step transactions (minting, burning, and balance adjustments), requiring a bigger fee cushion.

### Priority 4: Percentage-based calculation (default)

If none of the above rules produce a value, MyTonCtrl falls back to percentage-based calculation using `stakePercent`. This is the most common path for single nominator pools and direct staking.

The logic depends on whether the node already has active validators:

* **New validator** (no active validators):

  ```text theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
  stake = balance * stakePercent / 100 / 2
  ```

  The balance is halved. This solves a cold-start problem: on the first election, the elector locks the entire stake for a full validation round. By staking only half, the node keeps the other half available for the next election, which opens before the current round ends. Without halving, a new validator would be locked out of alternating rounds.

  **Exception:** if halving produces a value below `minStake`, MyTonCtrl abandons the halving and stakes the full percentage instead. Participating in one round is better than being rejected by the elector for staking too little.

* **Existing validator** (active validators present):

  ```text theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
  stake = balance * stakePercent / 100
  ```

  No halving is needed. The returning stake from the previous round replenishes the balance in time for the next election.

  **Fee deduction at 100%:** when `stakePercent` is exactly `100`, MyTonCtrl subtracts 20 TON from the result to prevent draining the wallet completely. At lower percentages, the non-staked remainder covers fees implicitly.

## Validation guards

After the stake amount is determined, three sequential checks run regardless of which priority rule produced the value:

| Check                | Condition          | Action                                                                     |
| -------------------- | ------------------ | -------------------------------------------------------------------------- |
| Maximum stake        | `stake > maxStake` | Clamps stake down to `maxStake`. Logs a warning. Election entry continues. |
| Minimum stake        | `stake < minStake` | Raises an error. Election entry is aborted.                                |
| Insufficient balance | `stake > balance`  | Raises an error. Election entry is aborted.                                |

The asymmetry is intentional. Exceeding the maximum is recoverable — MyTonCtrl clamps and continues. Falling below the minimum or exceeding the available balance would waste transaction fees on a doomed submission, so MyTonCtrl aborts instead.

## Safety reserves by mode

Each staking mode reserves a different amount for transaction fees:

| Mode                              | Reserve (TON) | Reason                                                        |
| --------------------------------- | ------------- | ------------------------------------------------------------- |
| Saved fixed stake                 | 0             | The stored value is used as-is; only validation guards apply. |
| Nominator pool                    | 20            | Multiple messages for pool lifecycle operations.              |
| Liquid staking controller         | 50            | Complex multi-step DeFi transactions.                         |
| Percentage at 100% (default mode) | 20            | General safety margin when no non-staked remainder exists.    |

## Examples

### New validator with 800,000 TON balance

Settings: `stakePercent = 99`, no fixed `stake`, single nominator pool mode.

1. No saved fixed stake, not a standard nominator pool, not a controller.
2. Falls through to percentage-based calculation (Priority 4).
3. No active validators detected (new node): halving applies.
4. `stake = 800,000 * 99 / 100 / 2 = 396,000`.
5. `396,000 > minStake` (300,000): halving is kept.
6. Result: **396,000 TON** is submitted. The remaining balance covers the next election.

### Returning validator with 1,600,000 TON balance

Settings: `stakePercent = 99`, single nominator pool mode, already validating.

1. Falls through to percentage-based calculation.
2. Active validators present: no halving.
3. `stake = 1,600,000 * 99 / 100 = 1,584,000`.
4. Result: **1,584,000 TON** is submitted.

### New validator with exactly 600,100 TON (near minimum)

Settings: `stakePercent = 100`, single nominator pool mode.

1. Falls through to percentage-based calculation.
2. No active validators: halving would give `600,100 / 2 = 300,050`.
3. `300,050 > minStake` (300,000): halving is kept.
4. `stakePercent == 100`: 20 TON fee deduction applies: `300,050 - 20 = 300,030`.
5. Result: **300,030 TON** is submitted.

### New validator with exactly 500,000 TON (halving would go below minimum)

Settings: `stakePercent = 100`, single nominator pool mode.

1. Falls through to percentage-based calculation.
2. No active validators: halving would give `500,000 / 2 = 250,000`.
3. `250,000 < minStake` (300,000): halving is abandoned.
4. Full percentage is used: `500,000`.
5. `stakePercent == 100`: 20 TON fee deduction: `500,000 - 20 = 499,980`.
6. Result: **499,980 TON** is submitted.

<Aside type="note">
  When halving is abandoned due to minimum stake constraints, the node participates only in every second validation round until the balance grows enough to cover both rounds.
</Aside>

### Nominator pool with 2,000,000 TON balance

Settings: standard nominator pool mode (not single nominator).

1. Pool mode detected (Priority 2).
2. `stake = 2,000,000 - 20 = 1,999,980`.
3. Result: **1,999,980 TON** is submitted.

## See also

* [Staking overview](/ecosystem/staking/overview) — comparison of staking solutions and minimum requirements.
* [Run a validator](/ecosystem/nodes/cpp/run-validator#step-4-set-optimal-stake-for-validator) — step-by-step guide for setting optimal stake.
* [MyTonCtrl settings](/ecosystem/nodes/cpp/mytonctrl/core#supported-settings) — full list of configurable parameters including `stake` and `stakePercent`.
* [Single nominator pools](/ecosystem/staking/single-nominator) — recommended staking contract for large holders.
