Multiple decimal precision issues in ticket calculation
calculateTicketsToMint hardcodes 18 decimals for all tokens and mishandles Pyth oracle expo data, so users with non-18-decimal tokens receive orders of magnitude more or fewer tickets than intended.
Description
The calculateTicketsToMint function in the MonadexV1Library contract contains multiple critical issues related to decimal precision handling. These issues stem from incorrect assumptions about token decimals, price representations, and Pyth oracle data formatting.
Key issues identified:
- Hardcoded 18 decimal places assumption for all tokens.
- Incorrect representation of the ticket price without proper decimal scaling.
- Mishandling of Pyth oracle data, which may not always be in 18 decimal precision.
Impact
Users could receive orders of magnitude more or fewer tickets than intended, especially for tokens with decimals other than 18.
The raffle system's economy could be completely destabilized, with some users gaining a massive unfair advantage. If more tickets are minted than intended, the prize pool could be drained much faster than designed.
Recommendation
- Modify the function to accept and use the specific decimal places of each token:
function calculateTicketsToMint(uint256 _amount,PythStructs.Price memory _pythPrice,uint256 _pricePerTicket,uint8 _tokenDecimals) internal pure returns (uint256) {uint256 adjustedAmount = _amount * 10**(18 - _tokenDecimals);// ... rest of the calculation}
- Ensure the
PRICE_PER_TICKETconstant is correctly scaled:
uint256 internal constant PRICE_PER_TICKET = 1e18; // $1 with 18 decimal places
- Use Pyth's utility functions to correctly interpret price data:
import "@pythnetwork/pyth-sdk-solidity/PythUtils.sol";uint256 price = PythUtils.convertToUint(_pythPrice.price, _pythPrice.expo, 18);uint256 confidence = PythUtils.convertToUint(_pythPrice.conf, _pythPrice.expo, 18);

