Core Contracts

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

Insufficient USDC Balance for Redemption

Summary

The redeem and redeemAll functions transfer USDC to users based on the amount of ZENO tokens they are redeeming.

However, the contract does not check whether it holds enough USDC to fulfill the redemption request.

If the contract does not have sufficient USDC balance, the safeTransfer call will revert, causing the redemption to fail.

Vulnerability Details

  1. The contract mints 1,000 ZENO tokens to User A.

  2. The contract only holds 500 USDC (instead of 1,000 USDC).

  3. After the maturity date, User A attempts to redeem all 1,000 ZENO tokens.

  4. The safeTransfer call fails because the contract only has 500 USDC, and the transaction reverts.

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);
}
function redeemAll() external nonReentrant {
if (!isRedeemable()) {
revert BondNotRedeemable();
}
uint256 amount = balanceOf(msg.sender);
totalZENORedeemed += amount;
_burn(msg.sender, amount);
USDC.safeTransfer(msg.sender, amount);
}
function getDetails() external view returns (ZENODetails memory) {
return ZENODetails(address(this), MATURITY_DATE, name(), symbol());
}

}

Impact

Users may be unable to redeem their ZENO tokens for USDC, even after the maturity date.

This could lead to a loss of trust in the contract and financial losses for users.

Tools Used

Recommendations

To address this issue, the contract should ensure that it holds enough USDC to fulfill redemption requests. This can be done by adding a check in the redeem and redeemAll functions.

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();
}
// Check if the contract has enough USDC to fulfill the redemption
uint256 usdcBalance = USDC.balanceOf(address(this));
if (amount > usdcBalance) {
revert InsufficientUSDCBalance();
}
totalZENORedeemed += amount;
_burn(msg.sender, amount);
USDC.safeTransfer(msg.sender, amount);
}
function redeemAll() external nonReentrant {
if (!isRedeemable()) {
revert BondNotRedeemable();
}
uint256 amount = balanceOf(msg.sender);
// Check if the contract has enough USDC to fulfill the redemption
uint256 usdcBalance = USDC.balanceOf(address(this));
if (amount > usdcBalance) {
revert InsufficientUSDCBalance();
}
totalZENORedeemed += amount;
_burn(msg.sender, amount);
USDC.safeTransfer(msg.sender, amount);
}
Updates

Lead Judging Commences

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

Give us feedback!