Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: medium
Invalid

Recursive Fee Collection on FeeCollector's Token Burns Causes Burn Allocation To Never Fully Be Burnt

Summary

The RAACToken contract collects fees on all token burns, including those made by the FeeCollector during reward distribution. This causes less tokens than allocated to be burnt as a portion is taken as fees and sent back to the FeeCollector.

Vulnerability Details

The issue occurs because RAACToken's `burn` function applies fees to all burns without exempting the FeeCollector.

POC

To use foundry in the codebase, follow the hardhat guide here: Foundry-Hardhat hybrid integration by Nomic foundation

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {FeeCollector} from "../../../../contracts/core/collectors/FeeCollector.sol";
import {RAACToken} from "../../../../contracts/core/tokens/RAACToken.sol";
import {veRAACToken} from "../../../../contracts/core/tokens/veRAACToken.sol";
import {Test, console} from "forge-std/Test.sol";
contract TestSuite is Test {
FeeCollector feeCollector;
RAACToken raacToken;
veRAACToken veRAACTok;
address treasury;
address repairFund;
address admin;
uint256 initialSwapTaxRate = 100; //1%
uint256 initialBurnTaxRate = 50; //0.5%
function setUp() public {
treasury = makeAddr("treasury");
repairFund = makeAddr("repairFund");
admin = makeAddr("admin");
raacToken = new RAACToken(admin, initialSwapTaxRate, initialBurnTaxRate);
veRAACTok = new veRAACToken(address(raacToken));
feeCollector = new FeeCollector(address(raacToken), address(veRAACTok), treasury, repairFund, admin);
vm.startPrank(admin);
raacToken.setFeeCollector(address(feeCollector));
raacToken.setMinter(admin);
vm.stopPrank();
}
function testFeeCollectorBurnTokensNeverCompletelyBurnt() public {
uint256 amount = 1e18;
// mint tokens to feeCollector
vm.startPrank(admin);
raacToken.mint(address(feeCollector), amount);
vm.stopPrank();
// FeeCollector burns tokens but always has residual tokens left
vm.startPrank(address(feeCollector));
raacToken.burn(amount);
vm.stopPrank();
uint256 balanceAfterBurn = raacToken.balanceOf(address(feeCollector));
console.log("Balance of feeCollector after burn: ", balanceAfterBurn);
assertGt(balanceAfterBurn, 0);
}
}

Impact

Burn allocation never fully burnt as fee collection causes tokens to always remain in the FeeCollector.

Tools Used

Manual review, foundry test suite

Recommendations

Add a specific burn fee exemption for FeeCollector in `RAACToken::burn`

Updates

Lead Judging Commences

inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Appeal created

uddercover Submitter
3 months ago
inallhonesty Lead Judge
3 months ago
inallhonesty Lead Judge 2 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.