Core Contracts

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

Incorrect Decimal Handling in ZENO Redemption

Summary

The ZENO contract fails to handle decimal conversion when redeeming ZENO tokens for USDC. Since ZENO uses 18 decimals (ERC20 standard) while USDC uses 6 decimals, the direct 1:1 transfer in the redemption functions will cause severe calculation errors, potentially leading to failed transactions or massive economic losses.

Vulnerability Details

In both redeem() and redeemAll() functions, the contract attempts to transfer USDC tokens without adjusting for the decimal difference:

function redeem(uint amount) external nonReentrant {
// ... validity checks ...
totalZENORedeemed += amount;
_burn(msg.sender, amount);
USDC.safeTransfer(msg.sender, amount); // @audit-issue No decimal conversion
}
function redeem(uint amount) external nonReentrant {
// ... validity checks ...
totalZENORedeemed += amount;
_burn(msg.sender, amount);
USDC.safeTransfer(msg.sender, amount); // @audit-issue No decimal conversion
}

The raw amount of ZENO tokens (18 decimals) is directly used as the USDC transfer amount (6 decimals). This means:

  • 1 ZENO token (1e18) would attempt to transfer 1e18 USDC

  • The correct amount should be 1e6 USDC (adjusted for decimal difference)

  • The difference is a factor of 1e12 (1 trillion)

Impact

  • Transaction Failures: Most redemption attempts will revert due to insufficient USDC balance in the contract

  • Economic Loss: In the unlikely case where the contract has enough USDC balance, users would receive 1 trillion times more USDC than intended

  • Contract Unusability: The core redemption functionality of the bond system is effectively broken

  • Loss of Trust: The inability to properly redeem bonds could lead to loss of user trust and potential market value decline

Tools Used

  • Manual code review

Recommendations

  • Implement proper decimal conversion in redemption 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();
}
totalZENORedeemed += amount;
_burn(msg.sender, amount);
// Convert from 18 decimals to 6 decimals
uint256 usdcAmount = amount / 1e12;
USDC.safeTransfer(msg.sender, usdcAmount);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Decimal precision mismatch between ZENO token (18 decimals) and USDC (6 decimals) not accounted for in redemption, causing calculation errors and incorrect payments

Support

FAQs

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

Give us feedback!