The getPrice()
function in the Auction.sol
contract suffers from precision loss due to Solidity’s integer division behavior. Since Solidity truncates decimal values instead of rounding them, the calculated price is sometimes lower than expected. This results in users paying slightly less than they should when purchasing ZENO
tokens via the buy()
function.
The getPrice()
function calculates the price of ZENO
using the formula: https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/zeno/Auction.sol#L69-L78
Solidity’s integer division truncates decimals instead of rounding, leading to an artificially lower price in certain cases.
This error is most evident when (block.timestamp - state.startTime) / (state.endTime - state.startTime)
is not a whole number.
As a result, the computed price is slightly lower than the expected theoretical value, allowing users to purchase ZENO
tokens at a discounted rate.
startingPrice = 105
reservePrice = 20
startTime = 10
endTime = 20
t (timestamp) |
Expected Price | Solidity-Truncated Price | Difference |
---|---|---|---|
10 | 105 | 105 | 0 |
11 | 96.5 | 96 | -0.5 |
12 | 88 | 88 | 0 |
13 | 79.5 | 79 | -0.5 |
14 | 71 | 71 | 0 |
15 | 62.5 | 62 | -0.5 |
16 | 54 | 54 | 0 |
17 | 45.5 | 45 | -0.5 |
18 | 37 | 37 | 0 |
19 | 28.5 | 28 | -0.5 |
20 | 20 | 20 | 0 |
This precision loss issue results in users getting a small, unintended discount when buying ZENO tokens.
Since the price is slightly lower than expected, users can consistently buy ZENO at a discount over time. While this doesn’t lead to direct losses for the protocol, it reduces expected revenue from the auction, impacting the intended pricing mechanism.
Manual Review
To preserve precision and avoid unintended rounding, modify the getPrice()
function to use fixed-point arithmetic.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.