bemo liquid staking
  • 👋Welcome to bemo
    • Introduction
    • What is liquid staking?
      • TON staking
      • Staking limitations
      • Liquid staking
      • bemo benefits
    • How bemo works
      • Staking
      • Validation
      • Unstaking
    • bmTON
      • bmTON explained
      • bmTON pricing
    • stTON
      • stTON explained
      • stTON pricing
  • 💻DEVELOPERS
    • bemo v1 (deprecated)
      • Stake
      • Unstake
      • Tracking unstake requests
      • How to get TON-stTON rate
    • bemo v2
      • Stake
      • Unstake
      • Tracking unstake requests
      • How to get TON-bmTON rate
  • 🚀Get Started
    • How to stake TON
    • FAQ
    • Ambassador Program
  • 🏦Tokenomics
    • Incentive Rewards Program
    • stXP
      • stXP FAQ
    • BMO Token
  • Legal
    • Disclaimer
    • Terms of Use
    • Privacy policy
  • 🆘Support
Powered by GitBook
On this page
  1. DEVELOPERS
  2. bemo v2

Stake

This section describes how to stake.

Overview

In Financial contract there're op-codes OP::SIMPLE_TRANSFER and OP::STAKE. They're used to perform staking of TON in the contract, resulting in the creation of a corresponding amount of bmTON in exchange for the staked TON. The current pools of bmTON and TON are taken into account, allowing the calculation of the amount of bmTON to be created dynamically. If the operation is successful, the total supply of bmTON and TON is updated, and the newly minted bmTON jettons are sent to the user's wallet address.

  • OP::SIMPLE_TRANSFER: Calls the mint function with a query_id of 0 and null for the forward_payload. It is a simple invocation that doesn’t pass any extra data aside from msg_value and fwd_fee.

  • OP::STAKE: Calls the mint function with a query_id (provided in in_msg_body), a forward_ton_amount (specified TON amount to forward) and a forward_payload (optional cell for forwarding additional data). These parameters enable more complex interactions, such as sending additional data for use in staking-related functions.

When a user stakes a certain amount of TON, the number of bmTON jettons to be minted is determined based on the existing bmTON and TON pools.

The number of bmTON minted is calculated using the formula:

stake_jetton_amount = jetton_total_supply * stake_ton_amount / ton_total_supply

Where:

  • jetton_total_supply is the total supply of bmTON before staking.

  • ton_total_supply is the total amount of staked TON before the staking operation.

  • stake_ton_amount is the amount of TON to be staked after subtracting any relevant fees (int stake_ton_amount = msg_value - get_ton_amount_for_stake(forward_ton_amount, fwd_fee)).

TL-B scheme for stake message

stake#4253c4d5 query_id:uint64 forward_ton_amount:Coins forward_payload:(Either Cell ^Cell) = InternalMsgBody;

Steps to verify the result of the staking operation:

To ensure the staking operation was executed correctly, follow these steps:

  1. Check the updated bmTON and TON pools:

  • Verify that the jetton_total_supply has increased by the calculated stake_jetton_amount.

  • Ensure that the ton_total_supply has increased by stake_ton_amount.

  1. Confirm the transfer of bmTON:

  • The minted bmTON should be sent to the user’s jetton wallet address. Verify that the correct amount was transferred.

  • The transaction should use the OP::INTERNAL_TRANSFER, and the query_id should match the identifier in the staking request.

Validate any additional data transfers:

  • If the staking operation included forwarding any additional payload (forward_payload), ensure that it was correctly forwarded with the transfer.

Common errors that may occur during processing OP::STAKE and OP::SIMPLE_TRANSFER

When performing operations in a smart contract, various errors can occur due to incorrect input, insufficient funds, or other issues. To handle these errors effectively, it’s important to understand what kind of errors might arise, how to catch them, and how to determine the underlying issue. Below is a detailed guide on common errors, how to detect them, and troubleshooting strategies.

  1. ERROR::INSUFFICIENT_MSG_VALUE

    • Cause: This error occurs when the provided message value is less than the required amount to perform the operation. For example, the amount of TON sent may not be enough to cover the staking amount after subtracting fees.

    • How to Detect: Check if the contract throws this error when the condition msg_value < required_amount is true.

    • Troubleshooting: Ensure that the amount sent in the transaction is enough to cover the required fees and the intended operation. Recalculate the required amount based on the operation and include enough extra funds for transaction fees.

  2. ERROR::NOT_BASECHAIN

    • Cause: This error happens when the message is sent from a non-basechain workchain (i.e., not workchain 0). The contract may be designed to only accept transactions from the main chain.

    • How to Detect: The contract checks if the sender’s workchain is not equal to 0 and throws this error if true.

    • Troubleshooting: Ensure that the transaction is being sent from the basechain (workchain = 0). Verify the sender address and ensure that it matches the expected workchain for the operation.

Example of sending stake message using pytoniq

So, to create a payload cell you need to provide the following params:

  • OP::STAKE (0x4253c4d5) - The operation code indicating the type of operation. Represented by a 32-bit unsigned integer

  • query_id - A unique identifier for the request, used for tracking the operation. It is a 64-bit unsigned integer that should be unique for each transaction.

  • forward_ton_amount - The amount of TON to be forwarded in another message or included in the response. This amount is excluded from the staking calculation.

  • forward_payload - An optional payload that can be included in the message to be forwarded. This data will be passed along with the forwarding message.

Or you can just send TON attached to the empty message to the Financial contract

Let's write a simple code that builds payload cell and sends message to Financial:

from pytoniq import WalletV4R2, LiteBalancer, begin_cell
import asyncio
mnemonics = ["your", "mnemonics", "here"]

async def main():
    provider = LiteBalancer.from_mainnet_config(1)
    await provider.start_up()

    OP_STAKE = 0x4253c4d5

    FINANCIAL_ADDRESS = "EQCSxGZPHqa3TtnODgMan8CEM0jf6HpY-uon_NMeFgjKqkEY"

    stake_msg = begin_cell()\
        .store_uint(OP_STAKE, 32)\
        .store_uint(123, 64)\   # example query_id, should be unique for each request
        .store_coins(int(0.01*1e9))\
    .end_cell()

    ton_to_stake = 100  # example value
    wallet = await WalletV4R2.from_mnemonic(provider=provider, mnemonics=mnemonics)
    await wallet.transfer(destination=FINANCIAL_ADDRESS,
                          amount=int(ton_to_stake*1e9),
                          body=stake_msg)

    await provider.close_all()

asyncio.run(main())

Previousbemo v2NextUnstake

Last updated 27 days ago

💻