Core Contracts

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

Tax cannot be set to zero in RAACToken.sol

Summary

In RAACToken.sol, the swapTaxRate and burnTaxRate is assumed to be able to set to zero from the _update() function:

uint256 baseTax = swapTaxRate + burnTaxRate;
if (baseTax == 0 ...

However it is not possible to set swapTaxRate or burnTaxRate to zero because of the taxRateIncrementLimit which is limited to 1000 (10%).

Vulnerability Details

When changing the taxRates, the owner has to call _setTaxRate() with the newRate. The newRate must be within the taxRateIncrementLimit bounds of the oldTaxRate.

For example, if the swap tax is at 500 (5%) and taxRateIncrement is at 1000 (10%), then the new swap tax can only be within 90-110% of the current 500, so within ~450-550.

function _setTaxRate(uint256 newRate, bool isSwapTax) private {
if (newRate > MAX_TAX_RATE) revert TaxRateExceedsLimit();
uint256 currentRate = isSwapTax ? swapTaxRate : burnTaxRate;
if (currentRate != 0) {
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();
}
}
if (isSwapTax) {
swapTaxRate = newRate;
emit SwapTaxRateUpdated(newRate);
} else {
burnTaxRate = newRate;
emit BurnTaxRateUpdated(newRate);
}
}

This means that the tax rate cannot be set < 9, since the transaction will revert.

Here is a Remix test, set the taxRateIncrementLimit to 1000, then set the swapTax to any amount. Note that once it reaches 9, it cannot get lower or higher anymore:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract TaxRateManager {
uint256 public constant MAX_TAX_RATE = 1000; // Maximum rate (100% in basis points)
uint256 public taxRateIncrementLimit; // Maximum allowed increment
uint256 public swapTaxRate; // Current swap tax rate
uint256 public burnTaxRate; // Current burn tax rate
event SwapTaxRateUpdated(uint256 newRate);
event BurnTaxRateUpdated(uint256 newRate);
error TaxRateExceedsLimit();
error TaxRateChangeExceedsAllowedIncrement();
function _setTaxRate(uint256 newRate, bool isSwapTax) private {
if (newRate > MAX_TAX_RATE) revert TaxRateExceedsLimit();
uint256 currentRate = isSwapTax ? swapTaxRate : burnTaxRate;
if (currentRate != 0) {
uint256 maxChange = _percentMul(currentRate, taxRateIncrementLimit);
// Check if the new rate is too high or too low by more than the allowed increment
bool isTooHighOrTooLow = newRate > currentRate + maxChange || (newRate < currentRate && currentRate - newRate > maxChange);
if (isTooHighOrTooLow) {
revert TaxRateChangeExceedsAllowedIncrement();
}
}
if (isSwapTax) {
swapTaxRate = newRate;
emit SwapTaxRateUpdated(newRate);
} else {
burnTaxRate = newRate;
emit BurnTaxRateUpdated(newRate);
}
}
function updateSwapTaxRate(uint256 newRate) external {
_setTaxRate(newRate, true);
}
function updateBurnTaxRate(uint256 newRate) external {
_setTaxRate(newRate, false);
}
function updateIncrement(uint256 _taxRateIncrementLimit) external {
taxRateIncrementLimit = _taxRateIncrementLimit;
}
function _percentMul(uint256 value, uint256 percent) private pure returns (uint256) {
return (value * percent) / 10000;
}
}

Impact

Tax cannot be set at 0%

Tools Used

Manual Review

Recommendations

Allow the function to accept 0 as the new tax, and if the owner wants to set the tax again he can choose any arbitrary amount.

function _setTaxRate(uint256 newRate, bool isSwapTax) private {
if (newRate > MAX_TAX_RATE) revert TaxRateExceedsLimit();
> if (newRate == 0) {
if (isSwapTax) {
swapTaxRate = newRate;
emit SwapTaxRateUpdated(newRate);
return;
} else {
burnTaxRate = newRate;
emit BurnTaxRateUpdated(newRate);
return;
}
}
...
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Validated
Assigned finding tags:

RAACToken tax rates cannot be set to zero from any non-zero value due to percentage-based increment limit check in _setTaxRate(), preventing intended tax-free operation

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Validated
Assigned finding tags:

RAACToken tax rates cannot be set to zero from any non-zero value due to percentage-based increment limit check in _setTaxRate(), preventing intended tax-free operation

Support

FAQs

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