Core Contracts

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

amounts between zeno tokens and usdc tokens should be normalized

During auction the price to determine the cost of usdc to zeno Token we have;

function buy(uint256 amount) external whenActive {
require(amount <= state.totalRemaining, "Not enough ZENO remaining");
uint256 price = getPrice();
@> uint256 cost = price * amount;
@> require(usdc.transferFrom(msg.sender, businessAddress, cost), "Transfer failed");
bidAmounts[msg.sender] += amount;
state.totalRemaining -= amount;
state.lastBidTime = block.timestamp;
state.lastBidder = msg.sender;
zeno.mint(msg.sender, amount);
emit ZENOPurchased(msg.sender, amount, price);
}
  • USDC has a decimal of 6.

  • ZENO has a decimal of 18.

A user attempts to purchase 10 ZENO tokens (10e18).

Assuming price = 1e6 (1 USDC)

cost = price * amount
= 1e6 * 10e18
= 10e24
= 10,000,000,000,000,000,000 USDC

The user would need to pay 10 quintillion USDC to purchase 10 ZENO tokens, which is infeasible.

Impact

users cannot purchase zeno tokens due to missing normalization of token decimals

Recommendation

consider the following changes
https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/zeno/Auction.sol#L87

function buy(uint256 amount) external whenActive {
require(amount <= state.totalRemaining, "Not enough ZENO remaining");
uint256 price = getPrice();
- uint256 cost = price * amount;
+ uint256 cost = price * amount / 1e18;
require(usdc.transferFrom(msg.sender, businessAddress, cost), "Transfer failed");
bidAmounts[msg.sender] += amount;
state.totalRemaining -= amount;
state.lastBidTime = block.timestamp;
state.lastBidder = msg.sender;
zeno.mint(msg.sender, amount);
emit ZENOPurchased(msg.sender, amount, price);
}

https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/zeno/ZENO.sol#L73

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);
+ uint256 amountUsdc = amount / 1e12;//@audit possibly include an exchangeRate to give a fairer conversion
+ USDC.safeTransfer(msg.sender, amountUsdc);
}
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

Auction.sol's buy() function multiplies ZENO amount (18 decimals) by price (6 decimals) without normalization, causing users to pay 1 trillion times the intended USDC amount

Support

FAQs

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

Give us feedback!