3rd Party Integration Guide
Last updated
Last updated
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.
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 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.
requestUnlock(uint96 shares)
):Users initiate the redemption process by calling requestUnlock
, specifying the amount of sMON shares
they wish to redeem.
The specified sMON shares are transferred from the user to the StakedMonad contract.
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
.
The requested shares are added to the batchUnlockRequests
mapping for the corresponding batchId
.
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.
sendBatchUnlockRequests(uint40[] calldata batchIds)
):This function can be called by anyone, but is intended to be automated to process completed unlock request batches.
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
).
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.
The batchUnlockRequests
for these batches are updated with the spotValue
and submissionTime
(the timestamp when the batch was sent for unbonding).
The total aggregated shares from the processed batches are burned from the contract's total supply.
The _doUnbonding
function is called with the aggregateSpotValue
to initiate the unbonding process with the underlying nodes, reducing the totalPooled
amount.
redeem(uint256 unlockIndex, address payable receiver)
):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.
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
).
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.
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.
The user's specific unlock request is deleted from their userUnlockRequests
array.
The calculated assets
(MON) are transferred to the specified receiver
address.
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.
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.