Core Contracts

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

`ZENO.redeem()` is transferring the wrong amount to the user

Summary

ZENO.redeem() is transferring the wrong amount to the user since USDC has 6 decimals.

Vulnerability Details

The prices of ZENO tokens (in USDC) is handling USDC decimals, see these values from Integration.test.js:

startingPrice = ethers.parseUnits("100", 6); // 100 USDC
reservePrice = ethers.parseUnits("10", 6); // 10 USDC

But in the redeem function the amount of USDC being sent to the user is the same amount of ZENO being burned.
See the ZENO.redeem() function:

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

USDC has 6 decimals, this way if a user redeems 10 ZENOs he will get 0.00001 USDC in return.

Impact

This will lead to users losing funds, and the protocol losing trust.
no one will be buying ZENOs.

Tools Used

Manual Review.

Recommendations

USDC or other ERC20 usable in Zeno, but also within the pools.

Zeno bond should be compatible with other stablecoins, this info was taken from the README/Compatibilities.

Since the Zeno bond can use others ERC20 than USDC here is a proper implementation of both redeem() and redeemAll() :

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 * (10 ** USDC.decimals()));
}
function redeemAll() external nonReentrant {
if (!isRedeemable()) {
revert BondNotRedeemable();
}
uint256 amount = balanceOf(msg.sender);
totalZENORedeemed += amount;
_burn(msg.sender, amount);
+++ USDC.safeTransfer(msg.sender, amount * (10 ** USDC.decimals()));
}
Updates

Lead Judging Commences

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