> ## 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": "/standard/vesting",
  "feedback": "Description of the issue"
}
```

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

</AgentInstructions>

# Vesting contracts

export const Image = ({src, darkSrc, alt = '', darkAlt, href, target, height = 342, width = 608, noZoom = false, center = false}) => {
  const isSVG = src.match(/\.svg(?:[#?].*?)?$/i) !== null;
  const shouldInvert = isSVG && !darkSrc;
  const shouldCreateLink = href !== undefined;
  const minPx = 9;
  const maxPx = 608;
  const expectedPx = `a number or a string with a number that is greater than ${minPx - 1} and less than or equal to ${maxPx}`;
  const createInvalidPropCallout = (title, received, expected) => {
    return <Danger>
        <span className="font-bold">
          Invalid <code>{title.toString()}</code> passed!
        </span>
        <br />
        <span className="font-bold">Received: </span>
        {received.toString()}
        <br />
        <span className="font-bold">Expected: </span>
        {expected.toString()}
        {}
      </Danger>;
  };
  const checkValidDimensionValue = value => {
    switch (typeof value) {
      case "string":
      case "number":
        const num = Number(value);
        return Number.isSafeInteger(num) && num >= minPx && num <= maxPx;
      default:
        return false;
    }
  };
  let callouts = [];
  if (height && !checkValidDimensionValue(height)) {
    callouts.push(createInvalidPropCallout("height", height, expectedPx));
  }
  if (width && !checkValidDimensionValue(width)) {
    callouts.push(createInvalidPropCallout("width", width, expectedPx));
  }
  if (callouts.length !== 0) {
    return callouts;
  }
  const heightPx = Number(height);
  const widthPx = Number(width);
  const shouldCenter = center === "true" || center === true ? true : false;
  const shouldNotZoom = noZoom === "true" || noZoom === true ? true : false;
  const images = <>
      <img className="block dark:hidden" src={src} alt={alt} {...height && ({
    height: heightPx
  })} {...width && ({
    width: widthPx
  })} {...(shouldCreateLink || shouldInvert || shouldNotZoom) && ({
    noZoom: "true"
  })} />
      <img className={`hidden dark:block ${shouldInvert ? "invert" : ""}`} src={darkSrc ?? src} alt={darkAlt ?? alt} {...height && ({
    height: heightPx
  })} {...width && ({
    width: widthPx
  })} {...(shouldCreateLink || shouldInvert || shouldNotZoom) && ({
    noZoom: "true"
  })} />
    </>;
  if (shouldCreateLink) {
    if (shouldCenter) {
      return <div style={{
        display: "flex",
        justifyContent: "center"
      }}>
          <a href={href} target={target ?? "_self"}>
            {images}
          </a>
        </div>;
    }
    return <a href={href} target={target ?? "_self"}>
        {images}
      </a>;
  }
  if (shouldCenter) {
    return <div style={{
      display: "flex",
      justifyContent: "center"
    }}>{images}</div>;
  }
  return images;
};

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>
    </>;
};

A [vesting contract](https://en.wikipedia.org/wiki/Vesting) is a financial agreement that outlines how and when an individual earns rights to certain assets over a specified period. On TON, vesting contracts enable secure, scheduled distribution of Toncoin assets with built-in staking capabilities.

## What is vesting

Vesting is a mechanism that locks assets for a defined period and gradually releases them according to a predetermined schedule. Traditional vesting includes a cliff period where no rights are granted initially, followed by gradual vesting over time.

On TON, vesting contracts function as smart escrow services that lock Toncoin and release it according to configurable parameters. These contracts also support staking locked funds, allowing recipients to earn rewards while tokens remain locked.

## How staking works with vesting

When funds are locked in a vesting contract, they cannot be sent to arbitrary addresses until unlocked. However, the contract supports a whitelist mechanism that allows sending locked funds to specific, approved destinations—primarily for staking purposes.

The vesting sender controls which addresses can receive locked funds by adding them to a whitelist. This security measure ensures that locked funds can only move to trusted, verified contracts that support staking operations.

Once whitelisted, locked funds can be staked through various methods:

* Direct validation through the system Elector
* Single nominator pools
* Liquid staking protocols
* Standard nominator pools

Staking rewards accumulate normally and remain accessible even while funds are locked. The vesting contract enforces restrictions only on destinations, not on the funds themselves once they are staked.

## Contract capabilities

A vesting contract operates with two key roles:

**Vesting sender**: The entity that creates the contract and locks the funds. The sender can:

* Add addresses to the whitelist at any time
* Receive funds back to their address at any time (even if locked)
* Cannot remove addresses from the whitelist once added

**Owner**: The recipient of the vesting contract who can:

* Send funds from the contract to whitelisted addresses or the sender address
* Send unlocked funds to any address after the vesting period ends
* Stake funds through approved methods

The contract maintains a whitelist of approved destinations. Funds can be sent to whitelisted addresses even while locked, enabling staking operations. Once unlocked, funds can be sent anywhere without restrictions.

## Unlock mechanism

The vesting contract uses a time-based unlock schedule with these parameters:

* **Vesting start time**: Unix timestamp when the vesting period begins
* **Total duration**: Total vesting period in seconds (e.g., 31,104,000 for one year)
* **Unlock period**: Time interval between releases in seconds (e.g., 2,592,000 for monthly)
* **Cliff duration**: Initial lock period before the first release (e.g., 5,184,000 for two months)

Before the vesting start time, all funds are locked. After the start time, funds unlock proportionally according to the schedule. If a cliff period exists, nothing unlocks during that time. Once the cliff ends, funds unlock according to the formula.

Example: With a total duration of 10 months, unlock period of 1 month, and total amount of 500 TON, the contract unlocks 50 TON each month. If a 3-month cliff exists, nothing unlocks for the first 3 months, then 150 TON unlocks at once, followed by 50 TON monthly.

Use the `get_locked_amount(int at_time)` method to calculate how much remains locked at any specific time.

<Image src="/resources/images/vesting/vesting_chart_light.png" darkSrc="/resources/images/vesting/vesting_chart_dark.png" alt="Vesting schedule" />

## Deploy and verify a vesting contract

Deploying a vesting contract requires careful verification before sending funds. Follow these steps:

### Step 1: Prepare recipient wallet

The vesting sender requests the recipient's TON wallet address. If the wallet is not deployed, the sender transfers 1 TON to the recipient and requests they send it back. This verifies wallet access and ensures deployment.

### Step 2: Create the vesting contract

1. Visit [vesting.ton.org](https://vesting.ton.org/)
2. Enter the recipient's wallet address in the "Address" field
3. Select "Create new vesting for this user"

### Step 3: Configure vesting parameters

Provide these details:

* **Vesting start date**: Choose a deferred date for lockup without accumulation before the date
* **Total amount**: Total vesting amount in TON
* **Total vesting duration**: Duration in days (including cliff), e.g., 760 days for 2 years
* **Cliff duration**: Period in days after vesting starts when vesting accumulates but cannot be withdrawn (zero if no cliff)
* **Unlocking frequency**: Frequency in days (equal to total duration if no partial unlocking), e.g., 30 days for monthly
* **In masterchain**: Check this if direct validation from the vesting wallet is required. Direct validation means participating in the blockchain's proof-of-stake consensus as a validator with a stake of 300,000 TON or more
* **Whitelist addresses**: Add addresses for staking contracts (e.g., single nominator pool addresses)

Constraints:

* Total vesting duration must be divisible by unlocking frequency
* Cliff duration must be divisible by unlocking frequency

### Step 4: Deploy and verify

1. Select "Create" to generate the vesting wallet contract (costs 0.5 TON)
2. The vesting wallet page opens after creation
3. Verify all parameters are correct before proceeding
4. Share the link with the recipient so they can verify parameters

### Step 5: Verify contract code hash

Before sending funds to the deployed contract, verify the contract code hash matches the official version:

**Official vesting contract code hash**: `b48b531abec3b714638291f7d77ed6dc9f6a2729efca20477137374d4ae8b590`

To verify:

1. Open the vesting contract address in a [block explorer]
2. Check the contract code hash
3. Verify it matches the official hash above

<Aside type="danger" title="Security: Verify code hash">
  Never send funds to a vesting contract until the code hash is verified to match the official version. A mismatched code hash indicates a modified or malicious contract that could steal funds.
</Aside>

### Step 6: Verify parameters via get-method

After deployment but before sending funds, verify all parameters using the `get_vesting_data()` get-method:

* Confirm all time parameters match expectations
* Verify sender and owner addresses are correct
* Check that duration constraints are satisfied

Example result on [Tonviewer](/ecosystem/explorers/tonviewer):

<Image src="/resources/images/vesting/getmethod.png" alt="Get-method result example on Tonviewer" />

### Step 7: Send funds

Only after verification is complete, send the vesting amount to the contract address from any wallet.

## Reviewing contracts for whitelist

Before adding any address to the whitelist, verify the contract is legitimate and safe:

1. **Check contract verification**: Use a [block explorer] to verify the contract is verified and matches known contract code hashes
2. **Verify contract type**: Confirm the contract is one of the supported types (single nominator pool, liquid staking protocol, etc.)
3. **Review contract source**: If available, review the contract source code or audit reports
4. **Check operational history**: Review the contract's transaction history for suspicious activity
5. **Verify addresses**: Double-check addresses match official documentation from the protocol

Supported whitelist destinations include:

* System Elector address (`-1:3333333333333333333333333333333333333333333333333333333333333333`)
* System Config address (`-1:5555555555555555555555555555555555555555555555555555555555555555`)
* Single nominator pool contracts
* Liquid staking protocol contracts (Tonstakers, Bemo)
* Standard nominator pool contracts
* Whales nominator pool contracts

Technically, any address can be added to the whitelist, including regular wallet addresses like wallet-v4. However, adding a wallet address defeats the purpose of vesting, as the owner would be able to withdraw locked funds immediately. Whitelist addresses should only include contracts that support staking operations and cannot be used for direct withdrawals.

<Aside type="caution" title="Whitelist security">
  Once an address is added to the whitelist, it cannot be removed. Review all addresses carefully before adding them. Only add addresses from trusted, verified protocols.
</Aside>

## Sending messages via UI

The vesting contract can be managed through the [vesting.ton.org](https://vesting.ton.org/) interface:

1. Open the vesting contract page using the shared link
2. Connect the owner wallet
3. Select "Send from Vesting" to create a new transaction
4. Enter the destination address
5. Enter the amount
6. For staking operations, add the appropriate message body:

   * Empty message for single nominator pools or Bemo
   * Text comment "d" for standard nominator pools (deposit)
   * Text comment "w" for standard nominator pools (withdraw)
   * Text comment "Stake" for Whales pools
   * Text comment "Withdraw" for Whales pools

   Select the message format: Text, Base64, or HEX. Use Text for simple text comments, and Base64 or HEX for serialized BoC messages (e.g., Tonstakers deposit operations).
7. Review and confirm the transaction

The interface handles message formatting automatically, ensuring compliance with whitelist restrictions.

## Security measures

Vesting contracts include multiple security layers:

### Whitelist restrictions

Messages sent to whitelisted addresses must:

* Use `send_mode == 3` only
* Be bounceable (non-bounceable messages are rejected)
* Include *no* `state_init` attachments

### Operation restrictions

The contract enforces specific operation codes based on the destination address:

**System Elector address**:

* `op::elector_new_stake` (0x4e73744b)
* `op::elector_recover_stake` (0x47657424)
* `op::vote_for_complaint` (0x56744370)
* `op::vote_for_proposal` (0x566f7465)

**System Config address**:

* `op::vote_for_proposal` (0x566f7465)

**Other whitelisted addresses**:

* Empty messages (no body)
* Text comments where the first character is "d", "w", "D", or "W"
* Operation codes:
  * `op::single_nominator_pool_withdraw` (0x1000)
  * `op::single_nominator_pool_change_validator` (0x1001)
  * `op::ton_stakers_deposit` (0x47d54391)
  * `op::jetton_burn` (0x595f07bc)
  * `op::ton_stakers_vote` (0x69fb306c)
  * `op::vote_for_proposal` (0x566f7465)
  * `op::vote_for_complaint` (0x56744370)

### Lock protection

The contract reserves locked funds when sending to non-whitelisted addresses (except the sender address). This prevents accidental loss of locked funds while allowing approved staking operations.

### Sender address safety

Funds can always be sent back to the vesting sender address without restrictions, even if locked. This provides a safety mechanism to return funds if needed.

<Aside type="caution" title="Protect owner wallet">
  Back up the recovery phrase for the owner wallet that controls the vesting contract. If access to the owner wallet is lost, control over vesting funds cannot be recovered.
</Aside>

## Staking options

Vesting contracts support multiple staking methods. Each method has specific requirements and limitations.

### Direct staking

Use the vesting contract directly as a validator wallet.

**Requirements**:

* Vesting contract must be deployed in masterchain
* Elector address must be whitelisted

**Steps**:

1. Request whitelisting of Elector address: `-1:3333333333333333333333333333333333333333333333333333333333333333`

2. [Import](/ecosystem/nodes/cpp/mytonctrl/wallet) the private key and vesting address into MyTonCtrl and use it as a standard wallet-v3.

   **Important**: Direct staking does not use owner wallet contract for management. Instead, it uses the vesting contract's public key and private key directly. By default, vesting.ton.org sets the vesting contract's public key to match the owner wallet's public key. Therefore, when importing into MyTonCtrl, use the seed phrase from the owner wallet.

   **Advanced**: Advanced users can deploy a vesting contract with a different public key than the owner wallet to avoid using the same seed phrase on the validator node. This requires using deployment scripts from the [vesting-contract GitHub repository](https://github.com/ton-blockchain/vesting-contract/blob/main/wrappers/VestingWallet.ts). When deploying with a custom public key, use the seed phrase corresponding to that public key when importing into MyTonCtrl.

3. Adding the Config address to the whitelist is not required for basic staking operations.

4. To vote on configuration proposals, request whitelisting of the Config address: `-1:5555555555555555555555555555555555555555555555555555555555555555`

**Limitations**: Requires storing the vesting private key on the validator node, which increases security risk.

### Single nominator pool

Create a single nominator pool and stake through it. This is the recommended approach for most users.

**Advantages**:

* Vesting private key does not need to be stored on the validator node
* Pool contract handles validator interactions
* More secure than direct staking

**Steps**:

1. Deploy a single nominator pool contract
2. Request whitelisting of the pool address from the vesting sender
3. Once whitelisted, send locked funds to the pool using [vesting.ton.org](https://vesting.ton.org/)
   * Destination: single nominator pool address
   * Amount: desired stake amount
   * Body: empty message
4. Manage staking through MyTonCtrl with the pool contract

For detailed setup instructions, see [MyTonCtrl single nominator pool mode](/ecosystem/nodes/cpp/mytonctrl/pools#single-nominator-pool-operations-single-nominator-mode).

<Aside type="tip" title="Staking rewards">
  Staking rewards are distributed according to the pool's reward scheme. See [staking rewards distribution](/ecosystem/staking/overview#nominator-validator-rewards-distribution) for details on how rewards are calculated and split between validators and nominators.
</Aside>

### Liquid staking: Tonstakers

Stake through the Tonstakers liquid staking protocol.

**Limitations**:

* Recipients can return coins from the pool (exchange tokens back to Toncoin) during vesting
* Recipients cannot transfer `tsTON` jettons to others until vesting expires
* Recipients cannot use `tsTON` jettons in DeFi protocols until vesting expires
* Voting rights are unavailable during vesting

**Steps**:

1. Request whitelisting of Tonstakers pool: `0:a45b17f28409229b78360e3290420f13e4fe20f90d7e2bf8c4ac6703259e22fa`

2. Send deposit message to the pool from vesting:

   * Destination: pool address above
   * Amount: desired stake amount
   * Body: serialized deposit message in HEX format (not a text comment)

   The deposit message uses this scheme with `query_id=0`:

   ```
   tonstakers_pool_deposit#47d54391 query_id:uint64 = InternalMsgBody;
   ```

   HEX message body: `b5ee9c7201010101000e00001847d543910000000000000000`

   <Aside type="caution" title="Message format">
     This is a serialized BoC message, not a text comment. Do not insert this into the "Comment" field in wallet applications. Use the HEX format option in the vesting interface.
   </Aside>

   Send this message via the [vesting.ton.org](https://vesting.ton.org/) interface by selecting HEX format.

3. Find the jetton wallet address:

   * Open the deposit transaction in a [block explorer]
   * Look at the transaction trace and find the newly deployed jetton wallet
   * Verify that:
     * The jetton wallet is verified
     * The "Holder address" equals the vesting contract address

   <Image src="/resources/images/vesting/tstakers_trace.png" alt="Tonstakers deposit trace" />

   <Image src="/resources/images/vesting/tstakers_jwallet.png" alt="Tonstakers jetton wallet" />

4. Request whitelisting of the jetton wallet address. This is required to withdraw the stake later.

5. To withdraw (unstake), send a burn message to the jetton wallet:

   * Destination: jetton wallet address (from step 3)
   * Amount: gas fee (\~0.5 TON)
   * Body: burn message with operation code `op::jetton_burn` (0x595f07bc)

   <Aside type="caution" title="Withdrawal amount">
     Specify the exact amount of `tsTON` to burn. Check the `tsTON` balance in the jetton wallet before creating the burn message.
   </Aside>

   To build the burn message cell in TypeScript, use the following code:

   ```typescript 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"]}}
   import { beginCell, Cell, toNano } from '@ton/core';

   // jetton_burn#595f07bc query_id:uint64 jetton_amount:Coins
   //      forward_payload:(Maybe ^Cell) = InternalMsgBody;

   const jettonAmount = toNano(123); // amount of tsTON to burn

   const burnMessage = beginCell()
       .storeUint(0x595f07bc, 32) // op::jetton_burn
       .storeUint(0, 64) // query_id
       .storeCoins(jettonAmount) // jetton_amount
       .storeRef(Cell.EMPTY) // forward_payload (empty)
       .endCell();

   // convert to HEX for vesting.ton.org interface
   const hexMessage = burnMessage.toBoc().toString('hex');
   console.log(hexMessage);
   ```

   Use the HEX output in the vesting interface when sending the burn message.

### Liquid staking: Bemo

[Bemo](https://bemo.finance) is a liquid staking protocol in TON. When staking TON, the protocol mints `bmTON` tokens that represent the staked position and automatically accumulate rewards.

**Limitations**:

* The vesting contract supports only basic staking through empty messages
* `bmTON` jettons remain locked in the vesting contract until vesting expires
* Jettons accumulate staking rewards automatically
* Staking and unstaking TON is possible during vesting
* Transferring `bmTON` to others is not possible until vesting expires
* Using `bmTON` in DeFi protocols is not possible until vesting expires

**Steps**:

1. Request whitelisting of Bemo v2 Financial contract: `0:92c4664f1ea6b74ed9ce0e031a9fc0843348dfe87a58faea27fcd31e1608caaa` (or `EQCSxGZPHqa3TtnODgMan8CEM0jf6HpY-uon_NMeFgjKqkEY` in user-friendly format)

2. Stake TON by sending an empty message to the Financial contract:

   * Destination: Financial contract address above
   * Amount: desired stake amount (e.g., 100 TON)
   * Body: empty message (no payload)

   Use the [vesting.ton.org](https://vesting.ton.org/) interface.

3. Find the `bmTON` jetton wallet address:

   * Open the staking transaction in a [block explorer]
   * Look at the transaction trace and find the newly deployed jetton wallet
   * Verify that:
     * It's a `bmTON` jetton wallet (should show "bmTON" and be verified)
     * The "Holder address" equals the vesting contract address

   <Image src="/resources/images/vesting/bemo_trace.png" alt="Bemo staking trace" />

   <Image src="/resources/images/vesting/bemo_jwallet.png" alt="Bemo jetton wallet" />

4. Request whitelisting of the `bmTON` jetton wallet address. This is required to withdraw the stake later.

5. To withdraw (unstake), send a burn message to the `bmTON` jetton wallet:

   * Destination: `bmTON` jetton wallet address (from step 3)
   * Amount: \~0.5 TON (for gas fees)
   * Body: burn message with operation code `op::jetton_burn` (0x595f07bc)

   <Aside type="caution" title="Withdrawal amount">
     Specify the exact amount of `bmTON` to unstake. Check the `bmTON` balance in the jetton wallet before creating the burn message.
   </Aside>

   To build the burn message cell in TypeScript, use the following code:

   ```typescript 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"]}}
   import { beginCell, Cell, toNano } from '@ton/core';

   // jetton_burn#595f07bc query_id:uint64 jetton_amount:Coins
   //      forward_payload:(Maybe ^Cell) = InternalMsgBody;

   const jettonAmount = toNano(100); // amount of bmTON to burn

   const burnMessage = beginCell()
       .storeUint(0x595f07bc, 32) // op::jetton_burn
       .storeUint(0, 64) // query_id
       .storeCoins(jettonAmount) // jetton_amount
       .storeRef(Cell.EMPTY) // forward_payload (empty)
       .endCell();

   // convert to HEX for vesting.ton.org interface
   const hexMessage = burnMessage.toBoc().toString('hex');
   console.log(hexMessage);
   ```

   Use the HEX output in the vesting interface when sending the burn message.

   After burning `bmTON`, TON is returned to the vesting contract after a cooldown period. Check the current cooldown on [Bemo documentation](https://docs.bemo.fi).

**Alternative: Bemo v1 (deprecated)**

For Bemo v1, the process is similar:

* Financial contract address: `0:cd872fa7c5816052acdf5332260443faec9aacc8c21cca4d92e7f47034d11892` (`EQDNhy-nxYFgUqzfUzImBEP67JqsyMIcyk2S5_RwNNEYku0k`)
* It mints `stTON` instead of `bmTON`
* The rest of the process is the same as Bemo v2

### Standard nominator pools

Standard nominator pools are the original TON staking pools where multiple nominators can pool their stakes together with a validator.

**Requirements**:

* Pool must be in basechain (workchain 0)
* Vesting contract must be in basechain (workchain 0)
* Pool address must be in basechain format (starts with `0:`)

**Steps**:

1. Request whitelisting of the nominator pool address. Ensure the pool address is in basechain format (starts with `0:`).

2. Deposit stake by sending text comment "d" (lowercase):

   * Destination: nominator pool address
   * Amount: desired stake amount + 1 TON (deposit processing fee)
   * Body: text comment "d" (lowercase)

   The pool may not accept the stake if it doesn't meet the minimum requirements or if the pool is full.

3. Check the pool's parameters:

   * Each pool has its own `min_nominator_stake` (minimum stake amount)
   * Each pool has `max_nominators_count` (maximum number of nominators)
   * Deposit processing fee is typically 1 TON

   Check these parameters using the pool's get-methods.

4. Withdraw stake by sending text comment "w" (lowercase):

   * Destination: the same nominator pool address
   * Amount: small amount for network fee (1 TON is enough)
   * Body: text comment "w" (lowercase)

   Unspent TONs attached to the message will be returned except in very rare cases.

   Withdrawal behavior depends on the pool balance:

   * If there are enough Toncoin on the pool balance, withdrawal will be made immediately. All funds will be available on the pool balance when it has completed participation in the validation round but has not yet submitted a request for participation in a new round.
   * If there are not enough Toncoin on the pool balance, a withdraw request will be created, and Toncoin will be withdrawn automatically after the end of the current validation round.

   Only full withdrawal is supported. Partial withdrawal is not supported.

**Limitations**:

* Depositing and withdrawing stake is supported
* Voting on configuration proposals is supported (if sender whitelists Config address)
* Stake earns validation rewards
* Only "d" and "w" text comments are allowed
* The vesting contract must be in basechain (workchain 0)

### Whales nominator pools

[Whales nominator pools](https://tonwhales.com/staking) are community-run staking pools with a slightly different interface.

**Requirements**:

* Pool must be in basechain (workchain 0)
* Vesting contract must be in basechain (workchain 0)
* Whales pools are typically in the basechain

**Steps**:

1. Request whitelisting of the Whales pool address.

2. Deposit stake by sending text comment "Stake" (capital S, case-sensitive):

   * Destination: Whales pool address
   * Amount: desired stake amount + deposit fee
   * Body: text comment "Stake" (capital S, case-sensitive)

   Each pool has different deposit fees and minimum stake amounts. Check the specific pool information before depositing.

3. Withdraw stake by sending text comment "Withdraw" (capital W, case-sensitive):

   * Destination: the same Whales pool address
   * Amount: withdraw fee (check specific pool information)
   * Body: text comment "Withdraw" (capital W, case-sensitive)

   Withdrawal is a two-step process:

   * First message creates a withdrawal request
   * Withdrawal may be immediate
   * If withdrawal isn't immediate, wait for the pool to process the request (typically within 18 hours or less), then send another "Withdraw" message to complete it

**Limitations**:

* Depositing and withdrawing stake is supported
* Stake earns validation rewards
* Deposit and withdraw fees vary by pool
* Only "Stake" and "Withdraw" text comments are allowed (case-sensitive)
* The vesting contract must be in basechain (workchain 0)

## Sending funds back to sender

At any time, even while funds are locked, they can be sent back to the vesting sender address without restrictions. This provides a safety mechanism to return funds if staking is not desired or if issues arise.

The sender address does not need to be added to the whitelist separately—it is always allowed as a destination.

## After vesting ends

Once the vesting period completes and all funds are unlocked, the contract operates without restrictions:

* Funds can be sent to any address
* No whitelist restrictions apply
* All message types are allowed
* The contract functions like a standard wallet

Unlocked funds remain unrestricted regardless of destination, including previously whitelisted addresses.

## Code hash verification

The official vesting contract code hash is:

```
b48b531abec3b714638291f7d77ed6dc9f6a2729efca20477137374d4ae8b590
```

Always verify this code hash matches before sending funds to any vesting contract. A mismatched hash indicates a modified or malicious contract.

To verify:

1. Open the contract address in a [block explorer]
2. Navigate to the "Code" or "Contract" tab
3. Click on "Bytecode", then click on "Hex hash"
4. Compare the code hash with the official hash above
5. Do not proceed if hashes do not match

## See also

* [Vesting contract source code](https://github.com/ton-blockchain/vesting-contract)
* [Vesting contract technical documentation](https://github.com/ton-blockchain/vesting-contract/blob/main/README.md)
* [Vesting contract instruction (old and low level)](https://github.com/ton-blockchain/vesting-contract/blob/main/instruction.md)
  single-nominator-pool#run-a-single-nominator-pool-with-a-vesting-contract)
* [Standard wallets documentation](/standard/wallets/history)
* [Staking organization scenarios on TON](/ecosystem/staking/overview)

[block explorer]: /ecosystem/explorers/overview
