Root + Impact / Magic number usage can block minting when Faucet is out of tokens
Description
-
The initial version of DeployRaiseBoxFaucet.s.sol::DeployRaiseboxContract ensures that the RaiseBoxFaucet.sol::faucetDrip value and the balance comparison value used in the RaiseBoxFaucet.sol::mintFaucetTokens function are identical. Therefore, when the standard (“happy path”) deployment script is used, this issue does not occur.
-
However, future Faucet deployments based on this contract may be vulnerable when a different deployment script is used that sets a greater value for faucetDrip.
function mintFaucetTokens(address to, uint256 amount) public onlyOwner {
if (to != address(this)) {
revert RaiseBoxFaucet_MiningToNonContractAddressFailed();
}
@> if (balanceOf(address(to)) > 1000 * 10 ** 18) {
revert RaiseBoxFaucet_FaucetNotOutOfTokens();
}
_mint(to, amount);
Risk
Likelihood:
Impact:
When the faucet balance falls below the faucetDrip value but remains above the hardcoded magic number (1000 * 10 ** 18), the protocol will be unable to mint new faucet tokens. As a result, the claim faucet functionality will be blocked, making the protocol inoperable.
Proof of Concept
Add the following test to RaiseBoxFaucet.t.sol to reproduce the issue:
function test_audit_magicNumberUsageCanBlockMintingWhenFaucetIsOutOfTokens()
public
{
vm.startPrank(owner);
uint256 increasedFaucetDrip = 10000 * 10 ** 18;
uint256 mintThreshold = 1000 * 10 ** 18;
RaiseBoxFaucet testRaiseBox = new RaiseBoxFaucet(
"raiseboxtoken",
"RB",
increasedFaucetDrip,
0.005 ether,
1 ether
);
testRaiseBox.burnFaucetTokens(INITIAL_SUPPLY_MINTED);
testRaiseBox.mintFaucetTokens(address(testRaiseBox), mintThreshold * 2);
vm.stopPrank();
vm.prank(user1);
vm.expectRevert(
RaiseBoxFaucet.RaiseBoxFaucet_InsufficientContractBalance.selector
);
testRaiseBox.claimFaucetTokens();
vm.prank(owner);
vm.expectRevert(
RaiseBoxFaucet.RaiseBoxFaucet_FaucetNotOutOfTokens.selector
);
testRaiseBox.mintFaucetTokens(
address(testRaiseBox),
increasedFaucetDrip
);
}
Recommended Mitigation
Compare the balance against the actual faucetDrip value instead of using a hardcoded magic number.
function mintFaucetTokens(address to, uint256 amount) public onlyOwner {
if (to != address(this)) {
revert RaiseBoxFaucet_MiningToNonContractAddressFailed();
}
- if (balanceOf(address(to)) > 1000 * 10 ** 18) {
+ if (balanceOf(address(to)) > faucetDrip) {
revert RaiseBoxFaucet_FaucetNotOutOfTokens();
}
_mint(to, amount);