Fragmetric Restaking Program

QuantstampFiles named in the report

Quantstamp reviewed Fragmetric Restaking Program on 1 Nov 2024: 17 findings, 0 critical; 4 marked fixed, 12 acknowledged, 1 open.

No open critical findings
Open the reportOpen Fragmetric Restaking Program’s security record

Report hosted on certificate.quantstamp.com.

Trustblock does not review code.

Findings17

Statuses are the security firm’s own, from its report.

SeverityOpenAcknowledgedFixed
Critical000
High002
Medium111
Low0111
HighClosing a Rewardpool Will Block Deposits, Withdrawals, Updates, and TransfersFixed

A given `RewardAccount` can contain up to 4 pools of the type `RewardPool`. When `fragSol` moves from one user to another, or during minting and burning, the function `update_reward_pools_token_allocation` is invoked to update the reward pools in the given `rewardAccount`. This happens in the following loop: ``` for reward_pool in self.get_related_pools(&from.user, receipt_token_mint)? { ... reward_pool.update(effective_deltas, current_slot)?; ... } ``` However, if a `RewardPool` is closed, the `update()` function will throw an error: ```  fn update( &mut self, deltas: Vec<TokenAllocatedAmountDelta>, current_slot: u64, ) -> Result<Vec<TokenAllocatedAmountDelta>> { if self.is_closed() { err!(ErrorCode::RewardPoolClosedError)? } ... } ``` Thus, closing a single `RewardPool` in any `RewardAccount` will prevent updating all the reward pools. And also all user reward pools.

HighUpdating Price Before Withdrawal Can Cause Inaccuracies for the Withdrawal AmountFixed

The protocol updates `fragSol` price with respect to `SOL` in order to maintain an up-to-date price. The price update is triggered through the following statement: `fund.update_token_prices(ctx.remaining_accounts)?;` The `update_token_prices()` first verifies that the `ctx.remaining_accounts` contain the address of a pricing source that is specified by the admin when they add a `supportedToken`. Then, it proceeds to get the current price of the asset by getting the spot price from either `Marinade pool` or `SPL Stake pool`. When a user requests withdrawal, by calling the `request_withdrawal()` function, a withdrawal request is created and added to a batch. Then an operator needs to call the `process()` method to start processing the batch. During processing, the `fragSol` amount is converted into `SOL` and the total `SOL` amount to be withdrawn is reserved in the `fundAccount.withdrawalStatus.reserved_fund`. Then, the user can call the `withdraw()` function to finally receive their `SOL` amount. The issue is, the token price can still be updated between the user calling `request_withdrawl()`. This can happen if another user calls the `deposit_sol()` because it will trigger a price update. Or if an operator calls the `update_prices()` function. Currently, even the `withdraw()` function performs a price update. and `withdraw()`. - Some users may not be able to withdraw because the subtraction from `sol_remaining` in `reserved_fund` could fail due to underflow. - The calculation for the value of `SOL` per `fragSol` would be inaccurate since the amount of `SOL` could be greater than the amount of SOL subtracted from `sol_operation_reserved_amount` which is used in `assets_total_sol_value()`. This would result in an artificially inflated token value. The inflated token price would allow more `SOL` to be withdrawn per token than expected. If `SOL` is withdrawn more than what is subtracted from `sol_operation_reserved_amount`, then the SOL stored for the rent-exemption could be transferred out.

MediumDenial of Service when Updating Pool ParametersFixed

The function `set_capacity_amount()` allows the admin to set a new `capacity_amount` for the `SupportedTokenInfo` type. However, it currently compares between two state variables instead of comparing against the input provided: ``` if self.capacity_amount < self.accumulated_deposit_amount { err!(ErrorCode::FundInvalidUpdateError)? } ``` The same issue also exists in the function `set_sol_capacity_amount()`: ``` if self.sol_capacity_amount < self.sol_accumulated_deposit_amount { err!(ErrorCode::FundInvalidUpdateError)? } ``` It is also worth noting that the `sol_accumulated_deposit_amount` and `accumulated_deposit_amount` do not seem to be decreasing at any point. So it will always be needed to update the capacity; and if the admin mistakenly sets the capacity to a value lower than `accumulated_deposit_amount`, the admin will not be able to update the capacity again.

LowImpact of using `from_utf8_trim_null()` for objects `RewardPool`, `Holder` and `Reward`.Fixed

There are three issues related to using the function `from_utf8_trim_null()` for the objects `RewardPool`, `Holder` and `Reward`. 1. There is a mismatch between the code and the spec for the function `from_utf8_trim_null()`, where the comment says: ``` /// Truncates null (0x0000) at the end. ``` But the function removes all `null` in `v`, not only at the end. 2. When objects mentioned above are initialized, the value of `name` or `description` is saved without being trimmed. However, what is returned by the functions `name()` and `description()` is trimmed. As a result, trimming is done `n` times instead of only once at initialization. Also, when calling `add_reward_pool()`, `add_holder()`, and `add_reward()`, the check of an existing item with the same name can be bypassed by using a name with added `null` chars. The values will differ, but once the object is added, the function `name()` will return the same value (trimmed) for both objects. 3. These objects can be created with an empty name or description.

Contracts in scope

No deployed address is recorded for this audit.

The report names a repository or files. Open the report to see its scope.

Repository and files the report names (1)

  • programs/restaking/src/**

Part of Fragmetric Restaking Program’s security record

Fragmetric Restaking Program
Audits3 audits by 1 firmLast audit Oct 2025, by Quantstamp.
Critical findingsNo open critical findingsAcross 3 reports.
Open Fragmetric Restaking Program’s security record

Security firm

Quantstamp

236 projects reviewed · 332 reports · latest Oct 2026

See Quantstamp’s audits

Something wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.

Tell us