Core Contracts

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

Precision Mismatch in ZENO Contract: `redeem()` and `redeemAll()` May Cause Scaling Issues and loss of USDC

Summary

The redeem() and redeemAll() functions in the ZENO contract assume a 1:1 conversion between ZENO and USDC. However, ZENO is an ERC-20 token that likely uses 18 decimals, whereas USDC typically uses 6 decimals. This discrepancy could lead to incorrect redemption amounts due to improper scaling.

Vulnerability Details

In both redeem() and redeemAll(), the contract transfers amount of USDC equivalent to the ZENO tokens burned. The relevant code is:

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);
}

https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/zeno/ZENO.sol#L46C2-L74C6

ZENO has 18 decimals and USDC has 6, the transferred amount will be 1e12 times higher than expected, leading to excessive token transfers and potential loss of funds for the protocol.

Impact

If this contract is deployed as-is:

  • Users may redeem far more USDC than intended, draining the contract’s USDC balance quickly.

  • The contract may become insolvent as it won’t have enough USDC to fulfill all redemptions.

Tools Used

Manual Review

Recommendations

To ensure proper scaling, adjust the transferred USDC amount by considering the difference in decimal places:

uint256 scaledAmount = amount / (10 ** (decimals() - USDC.decimals()));
USDC.safeTransfer(msg.sender, scaledAmount);
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!