Core Contracts

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

Wrong Zeno bond price scale leads buyer to pay more than they should

Summary

The wrong scaling of the cupon bond price makes Zeno buyers to pay more USDC than they should.

Vulnerability Details

Zeno it's a standard ERC20 token with 18 decimals.
Users can buy Zeno tokens using the Auction::buy function:

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

The Dutch auction price decreases linearly between startingPrice and reservePrice.
The cost, paid in usdc tokens is calculated as price * amount with no Zeno decimals scaling down.
For example, for a cupon bond price of 100e6 usdc, the buyer will pay 100e6 * 1e18 = 1e20 * 1e6 usdc.

Impact

Buyers will pay much more for each cupon bond.

Tools Used

Recommendations

Scale down the cost by the decimals of Zeno token. In this way the cost will be in usdc precision. To avoid leaking dust value, the buyer may only be allowed to buy whole zeno bonds amounts.

function buy(uint256 amount) external whenActive {
require(amount <= state.totalRemaining, "Not enough ZENO remaining");
uint256 price = getPrice();
+ amount = amount / 1e18 * 1e18; // no fractional amounts
- 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);
}
Updates

Lead Judging Commences

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

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!