What is Raga Finance?
Raga Finance is a yield aggregation platform that operates through a system of vaults and strategies. The platform allows users to deposit assets into ERC4626-compliant vaults that delegate yield-generating activities to their associated strategy contracts.
Core Components
1. RagaVaultRegistry
The central registry serves as a factory for vault deployment and global fee management. It maintains a list of all deployed vaults and handles fee configurations that apply across the platform.
2. RagaVault
ERC4626-compliant vaults hold user assets and delegate yield-generating activities to their associated strategy contracts. The vault handles deposits, withdrawals, accounting, and emergency controls.
3. Strategy Contracts
Strategy contracts implement specific yield-generating logic targeting various protocols. All strategies inherit from BaseStrategyUpgradeable and conform to the IStrategy interface.
Strategy Implementations
BaseStrategyUpgradeable
This abstract contract provides core functionality common to all strategies:
- Fee calculation and accumulation
- Slippage protection for DeFi interactions
- Storage management with the diamond storage pattern
- Access control via onlyVault and onlyRegistryOwner modifiers
- Upgrade mechanisms through the UUPS pattern.
BerapawStrategy
BerapawStrategy interacts with Berachain's Berapaw protocol to generate yield:
- Staked into wBERA/LBGT reward vault and get LBGT emissions
- Provide single-sided liquidity into the wBERA/LBGT pool using the LBGT emissions.
- Stake wBERA/LBGT LP tokens in the Berapaw’s wBERA/LBGT reward vault
InfraredStrategy
This strategy focuses on wBERA-iBGT LP positions:
- Staked into wBERA/iBGT reward vault and get iBGT emissions.
- Stake iBGT on Infrared’s iBGT vault.
- Claim rewards (wBERA and HONEY) and unstake iBGT tokens from the vault.
- Check HONEY balance; if above threshold (?), convert HONEY to wBERA.
- Provide single sided liquidity in wBERA/iBGT pool and repeat all the steps.
InfraredStableStrategy
Specializes in managing Honey/byUSD LP positions:
- Stake into Honey/byUSD reward vault and get iBGT emissions.
- Stake iBGT on Infrared’s iBGT vault.
- Claim rewards (wBERA and HONEY) and convert from wBERA to Honey. Then unstake iBGT too, and convert the iBGT to Honey too
- Swap wBERA to HONEY. (can be done with Kodiak router)
- Provide single-sided liquidity in the Honey/byUSD pool and start from step 1 again.
User Flow
Deposit Flow
- User calls deposit(uint256 assets, address receiver)or mint(uint256 shares, address receiver) on a RagaVault
- Vault accepts the user's tokens and mints shares
- Vault transfers tokens to the associated strategy
- Strategy calls deposit() to:
- Update internal accounting
- Compound existing rewards using harvest()
- Stake tokens in the appropriate yield-generating protocol
Withdrawal Flow
- User calls withdraw(uint256 assets, address receiver, address owner) or redeem(uint256 shares, address receiver, address owner) on a RagaVault
- Vault calculates the equivalent amount of assets
- If needed, the vault calls withdraw() on the strategy
Strategy:
- Unstakes necessary tokens from external protocols
- Harvests any pending rewards if beneficial
- Transfers requested tokens back to the vault
- Vault transfers tokens to the user and burns shares
Harvesting Flow
- Anyone can call harvest() on a strategy
- Strategy claims rewards from external protocols
- Strategy converts rewards to more LP tokens through:
- Token swaps
- Single-sided joins or balanced LP provision
- Strategy updates internal accounting, including:
- Calculating gross profit
- Setting aside performance fees
- Incrementing totalAssets by net profit
- If the strategy is auto-compounding, it re-stakes the compounded assets
Function Interactions
RagaVault to Strategy Interactions
- Deposit: Vault calls strategy's deposit() after transferring assets
- Withdrawal: Vault calls strategy's withdraw(amount) to retrieve specific amounts
- Emergency: Vault calls strategy's withdrawAll() during emergency scenarios
- Accounting: Vault calls strategy's getTotalAssets() to determine total managed assets
Strategy for External Protocol Interactions
- Staking: Strategy calls stake() on reward vaults to earn rewards
- Reward Claiming: Strategy calls getReward() to harvest rewards
- Token Swaps: Strategy uses DEX routers for token conversions
Emergency Controls
The system implements multiple safety mechanisms:
- Pause/Unpause: The Registry owner can temporarily halt deposits
- Emergency Withdraw: Pulls all funds from strategies to the vault
- Panic Mode: Combination of pause + emergency withdrawal
Advanced Strategy Functions
BerapawStrategy
- _claimAndCompound(): Claims LBGT rewards and converts to LP tokens
- _singleSidedJoin(): Performs single-asset pool joins with slippage protection
- _harvestWithoutStake(): Compounds rewards but keeps them liquid
InfraredStrategy
- claimIBgtAndStake(): Claims iBGT and stakes it in iBGT vault
- _buildWberaIbgtLp(): Creates LP tokens with optimal ratios
- _calculateSwapAmount(): Determines optimal swap amounts for balanced LP provision
InfraredStableStrategy
- claimIBgtAndStake(): Claims and stakes iBGT emissions
- _buildHoneyByUsdLp(): Creates stablecoin LP positions
- _exitToWant(): Converts all held tokens into the strategy's want token
Dedicated Audit Process for Raga Finance
Two highly experienced auditors from our team dedicated themselves to the Raga Finance Smart Contract audit for nearly 6 days.
1. Information Gathering
- Collected and reviewed all relevant documentation, including whitepaper, technical specifications, and design documents.
- Obtained a clear understanding of the Raga Finance Smart Contract’s functionality and intended user interactions.
- Discussed client concerns and specific areas of focus for the audit.
2. Manual Code Review:
Conducted a line-by-line review of the smart contract code, focusing on:
- Vulnerability identification: Searching for known vulnerabilities like reentrancy, front-running, integer overflows, and access control issues etc.
- Logic flaws: Identifying inconsistencies or unintended behaviours in the code logic.
3. Functional Testing:
- Developed and executed a comprehensive set of test cases covering various user interactions and edge cases.
- Leveraged tools like Hardhat and Ganache to deploy and test the smart contract locally.
4. Reporting & Remediation:
- Prepared a detailed report outlining all identified vulnerabilities, categorized by severity and potential impact.
- Provided clear recommendations for fixing each vulnerability, including code snippets and best practices.
- Collaborated with the Raga Finance team to prioritize and address the identified issues.
- Conducted additional verification testing after vulnerability fixes were implemented.
Comprehensive Audit Discoveries
Our thorough audit uncovered 16 vulnerabilities. Some of these findings are given below:-
1. Incorrect Staking of Accumulated Fees in Deposit
In the deposit() function, all want tokens in the address(this) are staked into the reward vault, and the s.totalAssets value is increased accordingly. However, in _harvestWithoutStake(), only gross-fee is considered when updating s.totalAssets, and the fee portion remains in the strategy but is not staked.
The core issue arises when a subsequent deposit() call includes the previously unclaimed fee, causing it to be staked and counted again in s.totalAssets. This results in the treasury losing access to the accumulated fees, as they are inadvertently reinvested instead of being claimed.
2. User Funds Become Permanently Inaccessible After emergencyWithdraw Due to Missing Idle Balance Redemption Logic
The emergencyWithdraw() function transfers all underlying assets from the strategy to the vault. However, the _withdraw() function only attempts to redeem funds by calling strategy.withdraw(assets) and calculating the balance change, rather than utilizing the vault’s local balance.
Post emergencyWithdraw(), the strategy holds zero assets, and all tokens reside in the vault. Since _withdraw() does not consider the vault's idle balance, user withdrawals yield zero—despite the vault holding assets.
This leads to a critical state where:
- The vault holds idle assets.
- Users possess valid shares.
- But no redemption path exists for users to convert shares into tokens.
Impact: Permanent fund lock-up and complete denial of service for vault users.
3. While calling withdrawAll(), All Fees Accumulated are Also Being Transferred to the Vault, leading to 0 Fees Paid to the Treasury
During an emergency scenario, calling withdrawAll() on the strategy results in the withdrawal of all want tokens, including fees accrued through harvesting. Consequently, the entire balance—both user funds and accumulated fees—is transferred to the vault.
As a result, the treasury misses its rightful fee allocation, receiving zero want tokens.
Proof of Concept:
- deposit() is called – funds are invested.
- harvest() is called – fees are accrued.
- withdrawAll() is invoked – the strategy is emptied, including the fee portion.
4. totalAssets Value in RagaVault Will Be Inflated Due to the Accumulated Fees on Strategies
The totalAssets value in RagaVault becomes artificially inflated due to unclaimed fees that accumulate within strategies. These unclaimed fees are mistakenly included in totalAssets during the next deposit(), even though they are intended for treasury and not actual user yield.
This inflation compounds with each new deposit, leading to a distorted view of the vault’s actual asset base.
Impact:
- Misleading totalAssets metric.
- Denial-of-Service risk for final withdrawers, as earlier users may redeem based on inflated values.
- Ultimately, fees vanish from both strategy and vault, but their effect lingers through inflated share redemptions.
5. Missing Access Control in the setVault Function
The setVault() function in BaseStrategyUpgradeable lacks any access restriction, and while it is marked as virtual, none of the derived strategy contracts implement access control.
Impact: An external actor can arbitrarily call setVault() and assign a malicious vault to the strategy, potentially hijacking control of user assets.
6. Incorrect Logic in Panic Function
The panic() function contains conflicting logic due to modifier misuse. It is protected with whenNotPaused, yet internally it invokes emergencyWithdraw(), which is only allowed under whenPaused.
Impact: As written, the panic() function cannot be successfully executed, rendering it non-functional during emergencies.
7. Incorrect Swap Formula in InfraredStrategy
In the _calculateSwapAmount function of InfraredStrategy, the logic for determining the iBGT amount to swap—specifically in iBGT-heavy scenarios—is flawed due to a mathematical error.
Impact: The incorrect calculation leads to inefficient liquidity provision, ultimately lowering the yield potential for users.
8. Attacker Can Make the RagaVault::mint Function Unusable with Dust Amounts
An attacker can exploit RagaVault::mint() by sending a dust-level amount of assets (e.g., 1000 wei) directly to the vault when no shares exist. This results in a vault state with non-zero assets but zero total shares.
Subsequent calls to mint() will compute required asset amounts using an inflated denominator, making it practically impossible for users to mint new shares.
Impact: The vault becomes unusable for future deposits, effectively causing a DoS for new minters.
Successful Collaboration & Project Security:
- Impressed by our findings and recommendations, the Raga Finance Team developers promptly fixed all identified vulnerabilities.
- Through our collaborative efforts, the Raga Finance protocol is now significantly more secure, ensuring the protection of user funds.
Conclusion
The Raga Finance Smart Contracts security audit identified and addressed several vulnerabilities, protecting user funds and ensuring platform stability. This case study demonstrates the importance of proactive security measures for blockchain-based projects, especially those dealing with financial assets. By conducting audits and addressing identified issues, the Raga Finance Team has taken a significant step towards securing its platform and safeguarding user trust.