Core Contracts

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

Partial Token Burning When Fee Collector is Disabled in RAACToken

Summary

When a user calls the burn() function while the fee collector is disabled (set to zero address), only a portion of tokens are actually burned while the remaining tax amount stays in the user's balance, violating the user's intention to burn their entire specified amount.

Vulnerability Details

The burn() function in RAACToken implements a tax mechanism where a portion of the burned amount (determined by burnTaxRate) is meant to be sent to the fee collector. Here's how it works:

function burn(uint256 amount) external {
uint256 taxAmount = amount.percentMul(burnTaxRate);
_burn(msg.sender, amount - taxAmount);
if (taxAmount > 0 && feeCollector != address(0)) {
_transfer(msg.sender, feeCollector, taxAmount);
}
}

The issue arises because:

  1. The function first calculates the tax amount using burnTaxRate

  2. It then burns only (amount - taxAmount) tokens

  3. The remaining taxAmount is only transferred to the fee collector if:

    • taxAmount > 0 AND

    • feeCollector != address(0)

When feeCollector is set to address(0) (which is explicitly allowed by the setFeeCollector function):

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

This creates a situation where:

  • The user intends to burn amount tokens

  • Only (amount - taxAmount) tokens are burned

  • The taxAmount portion remains in the user's balance because the condition for transfer fails

  • This effectively results in a partial burn, contrary to the user's intention to burn their entire specified amount

PoC

  1. Contract deploys with burnTaxRate = 50 (0.5%)

  2. Owner calls setFeeCollector(address(0)) to disable fee collection

  3. Alice has 1000 tokens and calls burn(1000)

  4. Expected: All 1000 tokens should be burned

  5. Actual result:

    • taxAmount = 1000 * 0.5% = 5 tokens

    • Only 995 tokens are burned

    • 5 tokens remain in Alice's balance

Impact

Users trying to burn tokens while fee collection is disabled will always end up with residual tokens, as the tax portion remains unburned in their balance. This violates the principle of burning operations and could interfere with token economics and user expectations.

Tools Used

Manual code review

Recommendations

Modify the burn function to burn the entire amount when fee collector is disabled:

function burn(uint256 amount) external {
uint256 taxAmount = amount.percentMul(burnTaxRate);
if (feeCollector != address(0) && taxAmount > 0) {
_burn(msg.sender, amount - taxAmount);
_transfer(msg.sender, feeCollector, taxAmount);
} else {
_burn(msg.sender, amount);
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 6 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 6 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.