Platform: Code4rena
Start Date: 03/07/2023
Pot Size: $40,000 USDC
Total HM: 14
Participants: 74
Period: 7 days
Judge: alcueca
Total Solo HM: 9
Id: 259
League: ETH
Rank: 49/74
Findings: 1
Award: $17.52
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xprinc
Also found by: 0x11singh99, 0xAnah, 0xWaitress, 0xkazim, 2997ms, 33audits, 404Notfound, 8olidity, CRIMSON-RAT-REACH, CyberPunks, DanielWang888, Deekshith99, Eeyore, Eurovickk, Inspecktor, JGcarv, John, Jorgect, Kaysoft, LosPollosHermanos, MohammedRizwan, Qeew, QiuhaoLi, Rolezn, TheSavageTeddy, Topmark, Trust, Udsen, a3yip6, alexzoid, bigtone, codegpt, erebus, fatherOfBlocks, ginlee, glcanvas, hunter_w3b, josephdara, kaveyjoe, kutugu, mahdirostami, max10afternoon, oakcobalt, peanuts, pfapostol, ptsanev, qpzm, radev_sw, ravikiranweb3, sces60107, seth_lawson, te_aut, twcctop, zhaojie, ziyou-
17.5208 USDC - $17.52
Number | Issues Details | Context |
---|---|---|
[L-01] | In Well.sol init function ,use more efficient algorithms. | 1 |
[L-02] | Add a break to the for in the _getIJ function in Well.sol . | 1 |
[L-03] | Array length not checked. | 2 |
Total 3 issues
Well.sol init function
,use more efficient algorithms.There are nested for loops that determine if there are duplicate elements in the array. Time complexity is O(n^2).
for (uint256 i; i < _tokens.length - 1; ++i) { for (uint256 j = i + 1; j < _tokens.length; ++j) { if (_tokens[i] == _tokens[j]) { revert DuplicateTokens(_tokens[i]); } } }
It can be replaced with a more efficient algorithm with O(n) time complexity:
function hasDuplicate(IERC20[] memory arr) public pure returns (bool) { mapping(uint256 => bool) seen; for (uint256 i = 0; i < arr.length; i++) { if (seen[arr[i]]) { return true; } seen[arr[i]] = true; } return false; }
_getIJ
function in Well.sol
.If I and J are found, there is no need to continue the loop and we can add a break to break out of the loop.
before:
function _getIJ( IERC20[] memory _tokens, IERC20 iToken, IERC20 jToken ) internal pure returns (uint256 i, uint256 j) { bool foundI = false; bool foundJ = false; for (uint256 k; k < _tokens.length; ++k) { if (iToken == _tokens[k]) { i = k; foundI = true; } else if (jToken == _tokens[k]) { j = k; foundJ = true; } } if (!foundI) revert InvalidTokens(); if (!foundJ) revert InvalidTokens(); }
after:
function _getIJ( IERC20[] memory _tokens, IERC20 iToken, IERC20 jToken ) internal pure returns (uint256 i, uint256 j) { bool foundI = false; bool foundJ = false; for (uint256 k; k < _tokens.length; ++k) { if (iToken == _tokens[k]) { i = k; foundI = true; } else if (jToken == _tokens[k]) { j = k; foundJ = true; } else if (foundI && foundJ) { // <---add break break; } } if (!foundI) revert InvalidTokens(); if (!foundJ) revert InvalidTokens(); }
tokenAmountsIn
is input by the external, and the array length is not checked during the for loop, and the array may be out of bounds.
function _addLiquidity( uint256[] memory tokenAmountsIn, uint256 minLpAmountOut, address recipient, bool feeOnTransfer ) internal returns (uint256 lpAmountOut) { IERC20[] memory _tokens = tokens(); uint256[] memory reserves = _updatePumps(_tokens.length); if (feeOnTransfer) { for (uint256 i; i < _tokens.length; ++i) { if (tokenAmountsIn[i] == 0) continue; // <---tokenAmountsIn may be out of bounds tokenAmountsIn[i] = _safeTransferFromFeeOnTransfer(_tokens[i], msg.sender, tokenAmountsIn[i]); reserves[i] = reserves[i] + tokenAmountsIn[i]; } } ..... }
https://github.com/code-423n4/2023-07-basin/blob/c1b72d4e372a6246e0efbd57b47fb4cbb5d77062/src/Well.sol#L460C2-L460C2
minTokenAmountsOut
is input by the external, and the array length is not checked during the for loop, and the array may be out of bounds.
function removeLiquidity( uint256 lpAmountIn, uint256[] calldata minTokenAmountsOut, address recipient, uint256 deadline ) external nonReentrant expire(deadline) returns (uint256[] memory tokenAmountsOut) { IERC20[] memory _tokens = tokens(); uint256[] memory reserves = _updatePumps(_tokens.length); uint256 lpTokenSupply = totalSupply(); tokenAmountsOut = new uint256[](_tokens.length); _burn(msg.sender, lpAmountIn); tokenAmountsOut = _calcLPTokenUnderlying( wellFunction(), lpAmountIn, reserves, lpTokenSupply ); for (uint256 i; i < _tokens.length; ++i) { if (tokenAmountsOut[i] < minTokenAmountsOut[i]) { // <---minTokenAmountsOut may be out of bounds revert SlippageOut(tokenAmountsOut[i], minTokenAmountsOut[i]); } _tokens[i].safeTransfer(recipient, tokenAmountsOut[i]); reserves[i] = reserves[i] - tokenAmountsOut[i]; } _setReserves(_tokens, reserves); emit RemoveLiquidity(lpAmountIn, tokenAmountsOut, recipient); }
#0 - c4-pre-sort
2023-07-13T15:04:19Z
141345 marked the issue as high quality report
#1 - c4-pre-sort
2023-07-14T05:50:42Z
141345 marked the issue as low quality report
#2 - c4-judge
2023-08-04T21:01:52Z
alcueca marked the issue as grade-a