Fragmetric Restaking Program

Off-Chain (Private)
Audited on 2025/07/03
No active critical issues

Summary

<h3>Fix Review</h3> </br> The client fixed/mitigated all the high and medium-severity issues. <h3>Engagement Overview</h3> </br> The codebase is well-engineered with a modular approach, and the test suite covers several happy and unhappy paths. The quality of the documentation is good with both textual descriptions and visual flows. We highly appreciate that the Fragmetric team was highly engaged and responsive throughout the audit, promptly addressing our questions and participating in productive discussions. The audit identified 2 high severity issues, both of which were also identified by the development team during the audit. <h3> Protocol Overview </h3> </br> Fragmetric is a re-staking protocol, that allows users to stake `SOL`, or different liquid staking derivatives supported by Fragmetric, to mint `fragSol`. `fragSol` represents a user share in the total `SOL` equivalent amount held by the protocol. Currently, the protocol supports two LSTs, namely `jitoSol` and `mSol` (Marinade LST). The protocol relies on the spot price of `SPL Stake Pools` or `Marinade Stake Pools` to update prices. Price updates happen whenever the user interacts with the protocol, during deposits and withdrawals, and protocol operators can perform arbitrary price updates as well. As an incentive, the protocol offers different types of rewards, such as points or SPL tokens. The fund manager adds rewards that are stored in the system in the form of reward blocks, which can be claimed by users on demand, or when they deposit or request withdrawal. Currently, `fragSol` is not transferrable, but the protocol implements custom transfer hooks in order to track `fragSol` transfers across the Solana network once transfers are enabled. The reward calculation mechanism in the protocol performs reward allocation updates during deposits, withdrawals, and transfers (when they are enabled). Rewards are mainly a function of the `contribution accrual rate` which itself is just the amount deposited by a user multiplied by the time elapsed. There are two levels for tracking contributions: - Tracking the global contribution of all users across the global `RewardPool`. - Tracking the contribution of a specific user across their `UserRewardPool`. </br> In almost all cases, the `RewardPool` and `UserRewardPool` are updated together in the same instruction. The only exception is the instruction `user_update_reward_pools`which performs an update for the `UserRewardPool`. <b>It is worth noting that reward claiming is currently not implemented in the protocol. </b> The default value for a contribution rate is `100`, meaning that no multiplier is used. However, the admin can allow deposits performed through a specific wallet to earn a higher contribution rate. For this, the admin will sign a `metadata` object that contains information about the allowed wallet. Then, users can use that signature with the deposit instructions to earn a higher contribution rate. It is worth mentioning that if a user requests a withdrawal, and then cancels the withdrawal request, the contribution rate resets to its default value of `100`. For withdrawals, users need to submit a withdrawal request, that is then added to a batch. An operator then needs to invoke the `process()` method after a pre-determined amount of time passed or if the batch threshold amount of `fragSol` is reached. After a batch is processed, users can call the `withdraw()` function to get their withdrawal in `SOL`. This means that even if the user deposited in `jitoSol` or `mSol`, when they withdraw, they will get the equivalent amount of `SOL` at the time of withdrawal. However, in the first phase, are not supported and will not be enabled.


Issues (17)

Low
Medium
High
Critical
Total
Not fixed
112--13
Fixed
112-4
Total1232017


Contract (1)