code4rena-2021-06-pooltogether-h05
[H-05] IdleYieldSource doesn’t use mantissa calculations
Summary
부동소수점으로 처리하지 않아 _tokenToShares 나눗셈 결과가 0이 나오면 토큰을 예치해도 share를 받을 수 없다.
Keyword
floating point, mantissa calculation, division, arithmetic error, calcutation, rounding error
Vulnerability
부동소수점으로 계산하지 않았기 때문에 _tokenToShares 함수와 _sharesToToken 함수가 0을 리턴할 수 있다.
function _tokenToShares(uint256 tokens) internal view returns (uint256 shares) {
shares = (tokens * ONE_IDLE_TOKEN) / _price();
}
function _sharesToToken(uint256 shares) internal view returns (uint256 tokens) {
tokens = (shares * _price()) / ONE_IDLE_TOKEN;
}_sharesToToken 함수는 토큰을 입출금할 시 영수증 토큰을 얼마나 mint 또는 burn할지를 계산한다. 만약 나눗셈 결과로 0이 나온다면 토큰을 입금했음에도 영수증 토큰을 받지 못하게 된다.
function supplyTokenTo(uint256 mintAmount, address to) external nonReentrant override {
uint256 mintedTokenShares = _tokenToShares(mintAmount);
_depositToIdle(mintAmount);
_mint(to, mintedTokenShares);
emit SuppliedTokenTo(msg.sender, mintedTokenShares, mintAmount, to);
}
/// @notice Redeems tokens from the yield source from the msg.sender, it burn yield bearing tokens and return token to the sender.
/// @param redeemAmount The amount of `token()` to withdraw. Denominated in `token()` as above.
/// @return redeemedUnderlyingAsset The actual amount of tokens that were redeemed.
function redeemToken(uint256 redeemAmount) external override nonReentrant returns (uint256 redeemedUnderlyingAsset) {
uint256 redeemedShare = _tokenToShares(redeemAmount);
_burn(msg.sender, redeemedShare);
redeemedUnderlyingAsset = IIdleToken(idleToken).redeemIdleToken(redeemedShare);
IERC20Upgradeable(underlyingAsset).safeTransfer(msg.sender, redeemedUnderlyingAsset);
emit RedeemedToken(msg.sender, redeemedShare, redeemAmount);
}Impact
토큰을 예치해도 share를 받을 수 없다.
Mitigation
동일 프로젝트의 다른 컨트랙트 구현(ATokenYieldSource)처럼 부동소수점(mantissa calculation)을 이용한다.
tags: bughunting, pooltogether, smart contract, solidity, arithmetic error, rounding error, severity high