Quantstamp reviewed Yield Basis on 25 Apr 2025: 6 findings, 0 critical; all marked fixed.
Report hosted on certificate.quantstamp.com.
Trustblock does not review code.
Statuses are the security firm’s own, from its report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 0 | 3 |
| Medium | 0 | 0 | 2 |
| Low | 0 | 0 | 1 |
The `VirtualPool` contract makes use of a crvUSD flashloan provider to amplify user arbitrage for price correction. However, the flashloan integration is incomplete. 1. The `onFlashLoan()` function needs to be external according to ERC3156. 2. The `onFlashLoan()` function should verify the `initiator` and `token` addresses. 3. The `exchange()` function calls a `FLASH.ceiling()` function that appears to be undefined based on the intended integrated flash contract, [Curve Flashlender](https://etherscan.io/address/0x26de7861e213a5351f6ed767d00e0839930e9ee1#code). 4. The `exchange()` function should be `@nonreentrant`.
`LT.min_admin_fee` is never assigned, preventing any admin fees to be charged from the LT contract.
If the `set_staker()` function is called and the `staker` address is updated without transferring the previous staker's `balanceOf` to the new staker, the following issues could arise: 1. The previous staker's balance would remain with the old staker's address, leaving the new staker with a zero balance. This could lead to a situation where the new staker cannot perform any operations that require a balance, such as withdrawing staked tokens. 2. Incorrect calculations of staked tokens would result in the `_calculate_values()` function producing different values than expected.
If the `Factory` contract `admin` were to reclaim the `Factory`'s allocated crvUSD from the `AMM` contract via `LT.allocate_stablecoins()`, the `LT` contract debt could become higher than half of the available crvUSD. In such a case, the protocol could become insolvent, resulting in halted deposits and imbalanced reserves, potentially preventing the execution of the `AMM.exchange()` function.
If the `Factory` creates a market using `add_market()` before a `staker_impl` is set, a staker can be added later by calling the `fill_staker_vpool()` function. However, this function does not call the `LT.setStaker()` function to update the staker in the `LT` contract.
In the function `fill_staker_vpool()`, a `staker` contract is deployed for the given `market` if the `staker_impl` contract address is set and if the `staker` contract was not already deployed from executing `add_market()`. However, the `staker_impl` contract address is not updatable in the `Factory` contract. Therefore, if the `staker_impl` is not set during deployment, the `staker` contract will not be deployed when `fill_staker_vpool()` is called as the following code block will never execute: ``` if market.staker == empty(address) and self.staker_impl != empty(address): market.staker = create_from_blueprint( self.staker_impl, market.lt) ```
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (28)
240 projects reviewed · 338 reports · latest Nov 2026
See Quantstamp’s auditsSomething 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