Skip to main content
A vesting contract 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. Vesting scheduleVesting 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
  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
Security: Verify code hashNever 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.

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: Get-method result example on TonviewerGet-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.
Whitelist securityOnce 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.

Sending messages via UI

The vesting contract can be managed through the 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)
  • Not include 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.
Protect owner walletBack 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.

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 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. 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
    • 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.
Staking rewardsStaking rewards are distributed according to the pool’s reward scheme. See staking rewards distribution for details on how rewards are calculated and split between validators and nominators.

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
    Message formatThis 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.
    Send this message via the 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
    Tonstakers deposit traceTonstakers deposit trace Tonstakers jetton walletTonstakers 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)
    Withdrawal amountSpecify the exact amount of tsTON to burn. Check the tsTON balance in the jetton wallet before creating the burn message.
    To build the burn message cell in TypeScript, use the following code:
    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 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 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
    Bemo staking traceBemo staking trace Bemo jetton walletBemo 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)
    Withdrawal amountSpecify the exact amount of bmTON to unstake. Check the bmTON balance in the jetton wallet before creating the burn message.
    To build the burn message cell in TypeScript, use the following code:
    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.
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 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