Core Contracts

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

missing decimal divider when calculating `Auction::buy` results in really small amount of zeno for an affordable price

Summary

User can buy zeno bond token by interacting in auction cotract, but when the buy function called, the calculation is not considering the decimals when calculating the price. This resulting the price would be really high for normal amount of zeno token, or really small amount of zeno token for an affordable price.

Vulnerability Details

https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/zeno/Auction.sol#L84-L97

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

here when calling buy, user need to specify the amount that later would be minted to the user.
but the cost calculation does not account the decimal difference between these two token.

if the price of 1 zeno token at the time of calling is 10 USDC, the getPrice would later return 10e6
if the user intend to buy 1 zeno token, then the amount would be 1e18
thus making the cost calculation really big :

cost = price * amount
cost = 10e6 * 1e18
cost = 10e24 -> 10e18 USDC

there is no way user can paid such big cost in USDC

the only way for reasonable amout is to buy 1 wei amout of zeno:

cost = price * amount
cost = 10e6 * 1
cost = 10e6 -> 10 USDC

this resulting to buying a fraction amount of zeno bond token, which when we consider about composability and ERC20 standard, we should be using the decimals of the said token so we dont come into precision loss in other DeFi ecosystem.

Impact

user can only buy small amount of zeno token with reasonable price, which also can be considered dust amount and prone to precision loss when interacting with other defi ecosystem.

Tools Used

manual review

Recommendations

calculate the cost by dividing the decimals of zeno token:

diff --git a/contracts/zeno/Auction.sol b/contracts/zeno/Auction.sol
index aeafc19..4f53b5f 100644
--- a/contracts/zeno/Auction.sol
+++ b/contracts/zeno/Auction.sol
@@ -84,7 +85,7 @@ contract Auction is IAuction, Ownable {
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 / zeno.decimals();
require(usdc.transferFrom(msg.sender, businessAddress, cost), "Transfer failed");
bidAmounts[msg.sender] += amount;
Updates

Lead Judging Commences

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