Platform: Code4rena
Start Date: 07/04/2023
Pot Size: $47,000 USDC
Total HM: 20
Participants: 120
Period: 6 days
Judge: GalloDaSballo
Total Solo HM: 4
Id: 230
League: ETH
Rank: 96/120
Findings: 2
Award: $14.01
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: adriro
Also found by: 0xNorman, 0xRobocop, Aymen0909, ElKu, GT_Blockchain, Josiah, KrisApostolov, RaymondFam, SpicyMeatball, ToonVH, Voyvoda, anodaram, aviggiano, bin2chen, climber2002, giovannidisiena, jpserrat, minhtrng, rbserver, sashik_eth, shaka, wintermute
8.0283 USDC - $8.03
The function PrivatePool.flashFee
, which is used for calculating fee in flashLoan()
, returns changeFee
directly.
changeFee
is before applying decimals. So this part is definitely wrong.
File: PrivatePool.sol 750: function flashFee(address, uint256) public view returns (uint256) { 751: return changeFee; 752: }
Comment description about changeFee
: (which shows changeFee
is before applying decimals)
File: PrivatePool.sol 87: /// @notice The change/flash fee to 4 decimals of precision. For example, 0.0025 ETH = 25. 500 USDC = 5_000_000. 88: uint56 public changeFee;
In function flashLoan
, it used flashFee
directly for transferring the baseToken
.
File: PrivatePool.sol 623: function flashLoan(IERC3156FlashBorrower receiver, address token, uint256 tokenId, bytes calldata data) 624: external 625: payable 626: returns (bool) 627: { ... 632: uint256 fee = flashFee(token, tokenId); ... 635: if (baseToken == address(0) && msg.value < fee) revert InvalidEthAmount(); ... 651: if (baseToken != address(0)) ERC20(baseToken).transferFrom(msg.sender, address(this), fee); ... 654: }
VSCode
Fixed code:
File: PrivatePool.sol 750: function flashFee(address, uint256) public view returns (uint256) { 751: return changeFee * 10 ** ERC20(baseToken).decimals() / 10 ** 4; 752: }
#0 - c4-pre-sort
2023-04-20T15:08:01Z
0xSorryNotSorry marked the issue as duplicate of #864
#1 - c4-judge
2023-05-01T07:06:49Z
GalloDaSballo changed the severity to 2 (Med Risk)
#2 - c4-judge
2023-05-01T07:07:10Z
GalloDaSballo marked the issue as satisfactory
5.9827 USDC - $5.98
In PrivatePool.changeFeeQuote
, it assumes that baseToken.decimals
is not smaller than 4.
We should take care about some ERC20 tokens have decimals smaller than 4.
File: PrivatePool.sol 733: uint256 exponent = baseToken == address(0) ? 18 - 4 : ERC20(baseToken).decimals() - 4;
Example of ERC20 tokens with decimals smaller than 4.
- Hyperion Token (HYN)
- HoloToken (HOT)
- Moss Carbon Credit (MCO2)
- DAOstack (GEN)
If the baseToken
is one of these, we can't call changeFeeQuote
.
VSCode
Need to check the decimals of baseToken
if it is bigger enough when initialize.
Another way is:
Original:
uint256 exponent = baseToken == address(0) ? 18 - 4 : ERC20(baseToken).decimals() - 4; uint256 feePerNft = changeFee * 10 ** exponent;
Fixed:
uint256 feePerNft = changeFee; if (baseToken == address(0)) feePerNft *= 10 ** 14; else if (ERC20(baseToken).decimals() >= 4) feePerNft *= 10 ** (ERC20(baseToken).decimals() - 4); else feePerNft /= 10 ** (4 - ERC20(baseToken).decimals());
#0 - c4-pre-sort
2023-04-20T15:23:07Z
0xSorryNotSorry marked the issue as duplicate of #858
#1 - c4-judge
2023-05-01T07:14:09Z
GalloDaSballo marked the issue as satisfactory