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)
);
}
function buy(uint256 amount) external whenActive {
uint256 price = getPrice();
uint256 cost = price * amount;
require(usdc.transferFrom(msg.sender, businessAddress, cost), "Transfer failed");
}
Consider this example:
Call Auction.sol#buy(amount = 1e18)
to buy 1 ZENO
Fetch the price, assuming its value is 1.
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 = 10 ** (FEED_DECIMAL - usdc.decimals() + zeno.decimals());
_check(_startingPrice);
_check(_reservePrice);
}
function buy(uint256 amount) external whenActive {
uint256 price = getPrice();
uint256 cost = Math.mulDiv(amount, price, SCALE_FACTOR);
}
}