Core Contracts

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

`Auction.sol#price` calculate price without scaled factor

Vulnerability Details

Auction.sol#price calculates the auction price of ZENO/USDC, but the quotation does not consider the decimals of both tokens. As a result, Auction.sol#buy may overcharge USDC.

/**
* price of ZENO/USDC
* - ZENO scaled by 1e18
* - USDC scaled by 1e6
*/
function getPrice() public view returns (uint256) {
if (block.timestamp < state.startTime) return state.startingPrice;
if (block.timestamp >= state.endTime) return state.reservePrice;
return state.startingPrice - (
(state.startingPrice - state.reservePrice) *
(block.timestamp - state.startTime) /
(state.endTime - state.startTime)
);
}
// `amount` of zeno, scaled by 1e18
function buy(uint256 amount) external whenActive {
// price without scale
uint256 price = getPrice();
// `cost` scaled by 1e18
uint256 cost = price * amount;
// revert
require(usdc.transferFrom(msg.sender, businessAddress, cost), "Transfer failed");
}

Consider this example:

  1. Call Auction.sol#buy(amount = 1e18) to buy 1 ZENO

  2. Fetch the price, assuming its value is 1.

  3. The cost will be 1e18, which will charge use 1,000,000,000,000 of USDC.

Impact

Due to the overcharging of USDC, no one is able to purchase ZENO tokens.

Tools Used

Manual.

Recommendations

import "@openzeppelin/contracts/utils/math/Math.sol";
contract Auction is IAuction, Ownable {
uint256 constant FEED_DECIMAL = 18;
uint256 immutable SCALE_FACTOR;
constructor(/* ... */) Ownable(_initialOwner) {
zeno = ZENO(_zenoAddress);
usdc = IUSDC(_usdcAddress);
// scale factor decimal is (18 - 6 + 18) = 30
SCALE_FACTOR = 10 ** (FEED_DECIMAL - usdc.decimals() + zeno.decimals());
// check: price should be scale by FEED_DECIMAL
_check(_startingPrice);
_check(_reservePrice);
}
function buy(uint256 amount) external whenActive {
// ...
// price is scaled by FEED_DECIMAL
uint256 price = getPrice();
// cost's decimal = 18(amount) + 18(price) - 30(SCALE_FACTOR) = 6
uint256 cost = Math.mulDiv(amount, price, SCALE_FACTOR);
// ...
}
}
Updates

Lead Judging Commences

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