Now let's examine the
updateCollateral() function, which is used when a Minter wants to prove its collateral. This function accepts extensive data in its parameters, such as a list of validators, timestamps, and signatures. This design enables the Minter to collect all necessary approvals off-chain and present them in a single transaction, eliminating the need for on-chain approvals. Additionally, there is a
bytes32 metadataHash_ parameter, allowing the inclusion of an off-chain information hash if the collateral approval process requires additional off-chain activity validation.
The function begins with signature
verification, saving the minimum timestamp from all signatures. The signature validation procedure
iterates over all the signatures to check whether it meets the required
threshold, which is a
constant determined by governance. The signature check itself is straightforward, and the main
verifications include ensuring that the signature's timestamp is not in the future and is not earlier than this validator's last recorded timestamp. The validator must also be listed in the approved
Validators list.
Once all signatures are verified, it's time to
impose penalties, and the first type of penalty is a "missed collateral update penalty", imposed if a validator has failed to update the collateral amount in the past periods. At this stage, the function
determines missed intervals, calculating how many intervals were
missed since the Minter's last update. The penalty is then
applied to the Minter.
Interestingly, in the
_imposePenalty() function, the penalty is
added to the Minter's MToken balance. At first glance, it might seem that penalties reward the Minter. However, since "owed MTokens" actually represent debt, increasing the balance heightens the Minter's collateral redemption costs(Minter will need to repay more BOLD to return their collateral). The protocol cannot touch the collateral itself or perform operations such as "mint", "burn", or "transfer", as the collateral represents a real-world asset (RWA) and this asset cannot be transferred or modified without off-chain interactions. Such constraints pose challenges to all RWA-related blockchain projects, where off-chain operations cannot be conducted fully on-chain, and RWA handling is limited to off-chain participants verifying off-chain operations.
The
_imposePenaltyIfUndercollateralized() function implements the second type of penalty - "undercollateralization penalty". During this step, the function
retrieves the current amount of owed MTokens and calculates the
maximum allowed MTokens or collateral amount using the
mintRatio, a value set by governance (ranging from 100% to 650%). If the collateralization ratio is
valid, no penalty is applied. Otherwise, the function calculates the
excess MTokens, determines the
duration of undercollateralized intervals, and applies a penalty corresponding to the excess MTokens, weighted by the time the Minter was undercollateralized.
After this, the
updateCollateral() function
processes the pending retrievals of collateral. This operation
essentially "does nothing" besides updating the retrieval queue and the "total retrievals" value, as actual interactions with RWAs are handled off-chain by the Minter.
The function then
updates the collateral balance of the Minter and the last update timestamp.
The final step in
updateCollateral() is the
updateIndex(), which adjusts two indices (rates): the minter index, which continuously increases the MToken balance, and the earning index, which increases the MToken balances of holders who have enabled the "is earning" flag for their MTokens. We will explore these indices in detail in a separate section of this article.
Next in the protocol is collateral retrieval, which involves two steps: proposing a retrieval and "
executing" it later during the next call to
updateCollateral(). The proposal is implemented in the
proposeRetrieval() function. Each retrieval is assigned a unique
retrievalId, and its amount is
added to the "pending" retrievals field. This "pending" amount is
excluded from the "active" collateral balance through the collateralOf() function.