Core Contracts

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

Incorrect Scaling of Mint and Transfer Amounts in Auction Contract

Summary

The Auction contract has a critical issue with scaling amounts when users bid for ZENO tokens using USDC. Specifically:

  • ZENO: 18 decimals (standard ERC20 precision).

  • USDC: 6 decimals (common for stablecoins).

The buy function does not correctly scale the amounts when transferring USDC and minting ZENO tokens.

Vulnerability Details

The issue arises because the buy function does not account for the decimal difference between ZENO (18 decimals) , USDC (6 decimals) and also doesnt handle price precison. Specifically the buy function does not correctly scale the amounts when transferring USDC and minting ZENO tokens. As a result:

  • If the sale price is 10^6 (1 USDC) and the user bids 1 token only , the contract transfers 1e6 USDC but mints only 1 wei ZENO(not 1e18)

  • During redemption, 1 ZENO can only redeem 1 wei USDC (not 1e6 ), which is incorrect due to the decimal mismatch.

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);
}
//ZENO
//@audit default 18 decimal
contract ZENO is IZENO, ERC20, Ownable, ReentrancyGuard {
function mint(address to, uint256 amount) external onlyOwner {
if (amount == 0) {
revert ZeroAmount();
}
_mint(to, amount);
totalZENOMinted += amount;
}
function isRedeemable() public view returns (bool _redeemable) {
_redeemable = (block.timestamp >= MATURITY_DATE);
}
function redeem(uint amount) external nonReentrant {
totalZENORedeemed += amount;
_burn(msg.sender, amount);
USDC.safeTransfer(msg.sender, amount);
}

Impact

Users receive far fewer ZENO tokens than they should for their USDC bids and can redeem dust USDC

Tools Used

Manual

Recommendations

Ensure the cost calculation accounts for the price precision:

uint256 cost = price * amount / PRICE_PRECISION; // Adjust for decimal difference

Scale the USDC amount to match ZENO's 18-decimal precision before minting.

uint256 scaledAmount = cost * 1e12; // Scale USDC (6 decimals) to ZENO (18 decimals)
zeno.mint(msg.sender, scaledAmount);
Updates

Lead Judging Commences

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