Raisebox Faucet

First Flight #50
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: medium
Valid

Over-Transfer of Tokens in BurnFaucetTokens Function

Over-Transfer of Tokens in BurnFaucetTokens Function

Description

The burnFaucetTokens function intends to burn amountToBurn tokens from the contract by transferring to owner then burning. It transfers full contract balance instead, letting owner keep excess after burn.

function burnFaucetTokens(uint256 amountToBurn) public onlyOwner {
require(amountToBurn <= balanceOf(address(this)), "Faucet Token Balance: Insufficient");
// transfer faucet balance to owner first before burning
// ensures owner has a balance before _burn (owner only function) can be called successfully
_transfer(address(this), msg.sender, balanceOf(address(this))); //@> transferring all tokens of contract instead of amountToBurn
_burn(msg.sender, amountToBurn);
}

Risk

Likelihood:

  • Owner burns partial amount from large balance.

  • Multiple burns without minting.

Impact:

  • Owner retains unintended tokens, disrupting supply control.

  • Enables owner enrichment, breaks burn accounting.

Proof of Concept

function testBurnFaucetTokensOverTransfersAllTokens() public {
uint256 initialSupply = 1_000_000_000e18;
uint256 amountToBurn = 1_000e18;
// Have Minted initial supply to contract for testing through contract deployment
uint256 initialContractBalance = raiseBoxFaucet.balanceOf(address(raiseBoxFaucet));
uint256 initialOwnerBalance = raiseBoxFaucet.balanceOf(owner);
uint256 initialTotalSupply = raiseBoxFaucet.totalSupply();
assertEq(initialContractBalance, initialSupply);
assertEq(initialOwnerBalance, 0);
// Burn only 1000e18, but transfers all 1e9 e18
vm.prank(owner);
raiseBoxFaucet.burnFaucetTokens(amountToBurn);
uint256 finalContractBalance = raiseBoxFaucet.balanceOf(address(raiseBoxFaucet));
uint256 finalOwnerBalance = raiseBoxFaucet.balanceOf(owner);
uint256 finalTotalSupply = raiseBoxFaucet.totalSupply();
// Expects: contract empty, owner has excess (1e9 e18 - 1_000e18), supply decreased by 1_000e18 only
assertEq(finalContractBalance, 0);
assertEq(finalOwnerBalance, initialSupply - amountToBurn); // Excess retained
assertEq(initialTotalSupply - finalTotalSupply, amountToBurn);
}

POC Explanation: Test uses deployed initial supply (1e9 e18 tokens). Calls burnFaucetTokens(1_000e18). Asserts contract empties, owner retains ~1e9 e18 - 1_000e18 excess, supply drops only by 1_000e18, confirming over-transfer and retention.

Recommended Mitigation

function burnFaucetTokens(uint256 amountToBurn) public onlyOwner {
require(amountToBurn <= balanceOf(address(this)), "Faucet Token Balance: Insufficient");
- // transfer faucet balance to owner first before burning
- // ensures owner has a balance before _burn (owner only function) can be called successfully
- _transfer(address(this), msg.sender, balanceOf(address(this)));
+ // Transfer only the burn amount to owner for burning
+ _transfer(address(this), msg.sender, amountToBurn);
_burn(msg.sender, amountToBurn);
}

Mitigation Key Points: Transfer exactly amountToBurn to owner, burn that amount. Preserves CEI; owner gets/burns precise value, no excess. Adds event for transparency if needed.

Updates

Lead Judging Commences

inallhonesty Lead Judge 12 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Unnecessary and convoluted logic in burnFaucetTokens

Support

FAQs

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