LogoLogo
  • Overview
    • Introduction
    • Proof-of-Stake Blockchains
    • Liquid Staking
  • Monad Blockchain
    • Liquid Staking on Monad
  • The Kintsu Protocol
    • How It Works
    • Staking and Unstaking with Kintsu
    • Earning Yield
    • Definitions
    • Architecture & Integration
      • Staking and Un-staking Mechanisms
      • StakedMonad Contract
      • 3rd Party Integration Guide
      • Contract Interface & Functions
      • Community Actions
    • Official Contract Addresses
  • Community
    • Community & Social Media
  • Development Team
    • Our Philosophy
    • Why We Build
  • Resources
    • Bug Reports
    • Feature Requests
    • Support
Powered by GitBook
LogoLogo
On this page
  • Depositing and Redeeming sMON Tokens
  • Depositing MON
  • Redeeming sMON
  • Key Considerations for Users
  1. The Kintsu Protocol
  2. Architecture & Integration

3rd Party Integration Guide

PreviousStakedMonad ContractNextContract Interface & Functions

Last updated 1 day ago

Depositing and Redeeming sMON Tokens

Interacting with the Kintsu Staked Monad (sMON) contract involves two primary actions: depositing native MON to receive sMON shares and redeeming sMON shares to receive MON back. This process incorporates a staking mechanism, a fee structure, and a batched unbonding process for redemptions.

Depositing MON

Users can deposit native MON into the contract to obtain sMON shares, which represent their proportional ownership of the total pooled MON within the protocol. There are two functions available for depositing: deposit and mint. Both are one-step processes which will immediately exchange MON for sMON tokens.

  • deposit(uint96, address receiver): This is the standard deposit function adhering to the ERC7535/ERC4626 standard. When calling this function, the amount of MON to deposit is specified via msg.value. The assets parameter is present for standard compliance but is not directly used for the deposit amount (which comes from msg.value). The receiver address will receive the newly minted sMON shares. A crucial requirement is that the deposited amount (msg.value) must be greater than or equal to MINIMUM_DEPOSIT.

  • mint(uint96 shares, address receiver): This function allows users to specify the number of sMON shares they wish to receive. The required amount of MON to send with the transaction (msg.value) is calculated based on the desired shares and the current redemption ratio (convertToAssets). The user must send at least this calculated amount of MON. Any excess MON sent will be refunded to the caller so 3rd parties must handle this refund. Similar to deposit, the required MON amount must meet the MINIMUM_DEPOSIT.

Both deposit functions trigger an internal _updateFees() call to ensure the protocol fees are accounted for before calculating the redemption ratio and minting shares. A Deposit event is emitted upon successful completion.

Redeeming sMON

Redeeming sMON shares for native MON is a two-step process designed to manage the unbonding of staked assets from the underlying protocol. This process involves requesting an unlock, a waiting period, and then finally redeeming the MON.

Requesting an Unlock (requestUnlock(uint96 shares)):

  1. Users initiate the redemption process by calling requestUnlock, specifying the amount of sMON shares they wish to redeem.

  2. The specified sMON shares are transferred from the user to the StakedMonad contract.

  3. The unlock request is added to a batch based on the current batch interval. The contract determines the currentBatchUnlockId based on the block timestamp and the BATCH_INTERVAL_DELAY from the CREATION_TIME.

  4. The requested shares are added to the batchUnlockRequests mapping for the corresponding batchId.

  5. Each user's unlock requests are tracked in the userUnlockRequests mapping, allowing a user to have multiple pending unlock requests.

Important: Shares requested for unlock are put in escrow and cannot be transferred or used for further staking.

Sending Batch Unlock Requests (sendBatchUnlockRequests(uint40[] calldata batchIds)):

  1. This function can be called by anyone, but is intended to be automated to process completed unlock request batches.

  2. It takes an array of batchIds that are ready to be processed. These batch IDs must be in ascending order and must belong to past batch intervals (i.e., batchId < currentBatchUnlockId).

  3. The function iterates through the provided batch IDs, calculates the total MON value (aggregateSpotValue) corresponding to the aggregated shares (aggregateShares) in those batches at the time of processing, based on the then-current redemption ratio.

  4. The batchUnlockRequests for these batches are updated with the spotValue and submissionTime (the timestamp when the batch was sent for unbonding).

  5. The total aggregated shares from the processed batches are burned from the contract's total supply.

  6. The _doUnbonding function is called with the aggregateSpotValue to initiate the unbonding process with the underlying nodes, reducing the totalPooled amount.

Note: This step continues the unbonding process but does not immediately return MON to the users.

Redeeming Unlocked MON (redeem(uint256 unlockIndex, address payable receiver)):

  1. Users can call this function to claim their unlocked MON after the COOLDOWN_PERIOD has passed since the submissionTime of the batch containing their unlock request.

  2. The user specifies the unlockIndex corresponding to their specific unlock request within their userUnlockRequests array. The function checks that the specified unlockIndex is valid and that the batch associated with the request has been submitted (batch.submissionTime > 0) and the cooldown period has elapsed (block.timestamp > batch.submissionTime + COOLDOWN_PERIOD).

  3. The amount of MON to redeem (assets) is calculated proportionally based on the user's shares in the batch and the spotValue recorded for that batch when it was sent for unbonding.

  4. If the contract's current balance is less than the amount to be redeemed, the _doWithdrawUnbonded() function is called to attempt to claim unbonded MON from the nodes.

  5. The user's specific unlock request is deleted from their userUnlockRequests array.

  6. The calculated assets (MON) are transferred to the specified receiver address.

Cancelling Unlock Requests (cancelUnlockRequest(uint256 unlockIndex))

Users have a limited window to cancel an unlock request.

  • A request can only be cancelled within the same batch interval in which it was originally sent.

  • The user specifies the unlockIndex of the request they wish to cancel.

  • The function verifies that the request exists and that the current batch ID matches the batch ID of the request.

  • The shares from the cancelled request are removed from the corresponding batchUnlockRequests.

  • The unlock request is deleted from the user's userUnlockRequests array.

  • The sMON shares are transferred back to the user.

Key Considerations for Users

  • Minimum Deposit: Deposits must meet the MINIMUM_DEPOSIT requirement.

  • Redemption is Two-Step: Unlike some staking mechanisms, redemption is not instant. It requires requesting an unlock and then waiting for a cooldown period after the batch is processed.

  • Batching: Unlock requests are processed in batches. The timing of when a batch is sent for unbonding depends on external calls to the sendBatchUnlockRequests function.

  • Cooldown Period: After a batch is sent for unbonding, there is a COOLDOWN_PERIOD before the redeemed MON can be claimed.

  • Cancellation Window: Unlock requests can only be cancelled within the same batch interval they were initiated. The active batch can be found via the getBatchUnlockIdAtTime function.

  • Slippage: The value of sMON relative to MON can change between the time an unlock is requested (and the batch is sent) and the time it is redeemed, as the spotValue for the batch is fixed when the batch is sent.

  • Node Performance: The ability to redeem MON after the cooldown period is dependent on the underlying staking nodes successfully unbonding and returning the MON to the contract. The _doWithdrawUnbonded function is called during redemption if necessary to pull unbonded funds.

Make sure to check out the StakedMonad for more details on how to interact with it.

StakedMonad
contract interface