Core Contracts

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

Missing USDC Balance Validation Could Lead to Failed Redemptions

Description

The ZENO token's redeem functions lack critical validation of the contract's USDC balance before processing redemptions. This oversight could result in failed transactions and users being unable to redeem their tokens, effectively creating a situation where user funds become locked in the contract.

Affected code

function redeem(uint amount) external nonReentrant {
if (!isRedeemable()) {
revert BondNotRedeemable();
}
if (amount == 0) {
revert ZeroAmount();
}
uint256 totalAmount = balanceOf(msg.sender);
if (amount > totalAmount) {
revert InsufficientBalance();
}
totalZENORedeemed += amount;
_burn(msg.sender, amount);
USDC.safeTransfer(msg.sender, amount);
}

Vulnerability details

The current implementation burns ZENO tokens before verifying if the contract has sufficient USDC balance to honor the redemption. In scenarios where the USDC.safeTransfer fails due to insufficient balance, the user's ZENO tokens would already be burned, leading to a loss of tokens when the transaction reverts. This creates a race condition where early redemptions might succeed while later ones fail, with no mechanism for users to validate the contract's solvency before attempting redemption. The absence of a 1:1 backing guarantee exacerbates this issue, potentially leaving users with worthless tokens.

Tools Used

Manual Review

Recommended Mitigation Steps

The contract should implement a comprehensive balance verification system before processing any redemptions. This should include adding an explicit USDC balance check before burning tokens, introducing a public view function for users to check USDC availability, and implementing a redemption queue system to ensure fair processing of redemption requests. Additionally, the contract should emit events for failed redemption attempts to provide transparency to users and monitoring systems. Here's the recommended implementation:

function redeem(uint amount) external nonReentrant {
if (!isRedeemable()) {
revert BondNotRedeemable();
}
if (amount == 0) {
revert ZeroAmount();
}
uint256 totalAmount = balanceOf(msg.sender);
if (amount > totalAmount) {
revert InsufficientBalance();
}
if (USDC.balanceOf(address(this)) < amount) {
revert InsufficientUSDCBalance();
}
totalZENORedeemed += amount;
_burn(msg.sender, amount);
USDC.safeTransfer(msg.sender, amount);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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