Core Contracts

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

`burnTax` amount is not burned when `RaacToken::feeCollector` is address(0);

Summary

RaacToken has 2 types of fees: swapTaxRate and burnTaxRate.
Setting feeCollector to address(0) should disable the fees collection. As a sideffect, instead of burning entire amount, only amount - burnFee is destroyed. The burnFee amounts remains in caller's ballance.

Vulnerability Details

RaacToken implements 2 types of fees: swapTaxRate and burnTaxRate. On each transfer, excluding minting and burning, the swap tax amount is transferred to feeCollector and burn amount is burned.

function _update(
address from,
address to,
uint256 amount
) internal virtual override {
uint256 baseTax = swapTaxRate + burnTaxRate;
// Skip tax for whitelisted addresses or when fee collector disabled
// @audit-note minting and burning is excluded from tax -> OK
@> if (baseTax == 0 || from == address(0) || to == address(0) || whitelistAddress[from] || whitelistAddress[to] || feeCollector == address(0)) {
super._update(from, to, amount);
return;
}
// All other cases where tax is applied
uint256 totalTax = amount.percentMul(baseTax);
uint256 burnAmount = totalTax * burnTaxRate / baseTax;
@> super._update(from, feeCollector, totalTax - burnAmount);
@> super._update(from, address(0), burnAmount);
super._update(from, to, amount - totalTax);
}

When feeCollector is set to address(0) it should act as a switch off and disable fee collection, as implemented in setFeeCollector:

function setFeeCollector(address _feeCollector) external onlyOwner {
@> // Fee collector can be set to zero address to disable fee collection
if(feeCollector == address(0) && _feeCollector != address(0)){
emit FeeCollectionEnabled(_feeCollector);
}
if (_feeCollector == address(0)){
@> emit FeeCollectionDisabled();
}
feeCollector = _feeCollector;
emit FeeCollectorSet(_feeCollector);
}


When tokens are burn-ed, the burn tax is transferred to feeCollector.

function burn(uint256 amount) external {
uint256 taxAmount = amount.percentMul(burnTaxRate);
@> _burn(msg.sender, amount - taxAmount); // @audit-issue `taxAmount` is not burned
if (taxAmount > 0 && feeCollector != address(0)) {
_transfer(msg.sender, feeCollector, taxAmount);
}
}

The problem is that burn function burns only amount - taxAmount.
The taxAmount remains in msg.sender balance.

Admin could try to set burnTaxRate to 0. The taxRateIncrementLimit limits the maxChange between old tax rate and the new tax rate to 10%( eg. from 100bps to 90, then 81, etc).

function _setTaxRate(uint256 newRate, bool isSwapTax) private {
...
@> uint256 maxChange = currentRate.percentMul(taxRateIncrementLimit);
// Check if the new rate is too high (newRate > currentRate + maxChange) or too low (newRate < currentRate && currentRate - newRate > maxChange) by more than the allowed increment
bool isTooHighOrTooLow = newRate > currentRate + maxChange || newRate < currentRate && currentRate - newRate > maxChange;
if (isTooHighOrTooLow) {
revert TaxRateChangeExceedsAllowedIncrement();
}
...

Because of this change rate limit, it requires 28 _setTaxRate calls to set the swapTaxRate to 4pbs. It can't be set lower than that because percentMul(4, 1000) returns 0, disallowing setting the fee rate to 0.

raacToken.burn is called from FeeColector contract to burn the burnShare amount for each of the 8 fee types.

Impact

Admin can't disable the burnTaxRate. The tax remains in caller's balance.
If admin tries to reduce the burn tax, it can be set down to 4pbs but this incurs significant gas fee costs due to the 28 transactions required.
FeeCollector will accumulate unburned RAACToken amounts, diluting the value of existing tokens.

Tools Used

Recommendations

Update RaacToken::burn function and burn entire amount when feeCollector is set to `address(0).

Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

RAACToken::burn incorrectly deducts tax amount but doesn't burn or transfer it when feeCollector is address(0), preventing complete token burns

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

RAACToken::burn incorrectly deducts tax amount but doesn't burn or transfer it when feeCollector is address(0), preventing complete token burns

Support

FAQs

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

Give us feedback!