Platform: Code4rena
Start Date: 11/11/2021
Pot Size: $50,000 USDC
Total HM: 9
Participants: 27
Period: 7 days
Judge: alcueca
Total Solo HM: 5
Id: 53
League: ETH
Rank: 10/27
Findings: 1
Award: $1,275.41
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: fatima_naz
866.6085 USDC - $866.61
fatima_naz
In line - 20 , 29 and 30. ERC20 transfer and transferFrom are used. The race condition that happens the most on the network today is the race condition in the ERC20 token standard. The ERC20 token standard includes a function called 'approve' which allows an address to approve another address to spend tokens on their behalf. Assume that Alice has approved Eve to spend n of her tokens, then Alice decides to change Eve's approval to m tokens. Alice submits a function call to approve with the value n for Eve. Eve runs a Ethereum node so knows that Alice is going to change her approval to m. Eve then submits a tranferFrom request sending n of Alice's tokens to herself, but gives it a much higher gas price than Alice's transaction. The transferFrom executes first so gives Eve n tokens and sets Eve's approval to zero. Then Alice's transaction executes and sets Eve's approval to m. Eve then sends those m tokens to herself as well. Thus Eve gets n + m tokens even thought she should have gotten at most max(n,m).
https://swcregistry.io/docs/SWC-114 https://medium.com/coinmonks/solidity-transaction-ordering-attacks-1193a014884e
use SafeERC20 - Library that brings an abstract layer above the ERC20 standard interface providing a way to call its methods safely by checking pre and post-conditions.
Add these 2 lines- import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; using SafeERC20 for IERC20
Replace transferFrom with SafeTransferFrom Replace transfer with SafeTransfer
#0 - adrien-supizet
2021-11-18T15:09:24Z
This is a mock contract that will obviously not be used in production, and only for tests.
#1 - alcueca
2021-12-03T15:53:00Z
Dispute rejected, scope wasn't set.
🌟 Selected for report: WatchPug
Also found by: fatima_naz
fatima_naz
In NestedFactory.sol line number - 299 assert(amountSpent <= _inputTokenAmount - feesAmount); If the condition fails then assert(false) compiles to 0xfe, which is an invalid opcode, using up all remaining gas, and reverting all changes. So we should use require because require(false) compiles to 0xfd which is the REVERT opcode, meaning it will refund the remaining gas. The opcode can also return a value (useful for debugging)
Gas efficiency assert(false) compiles to 0xfe, which is an invalid opcode, using up all remaining gas, and reverting all changes.
require(false) compiles to 0xfd which is the REVERT opcode, meaning it will refund the remaining gas.
Links - https://medium.com/blockchannel/the-use-of-revert-assert-and-require-in-solidity-and-the-new-revert-opcode-in-the-evm-1a3a7990e06e https://ethereum.stackexchange.com/questions/15166/difference-between-require-and-assert-and-the-difference-between-revert-and-thro
Change assert with require- require(amountSpent <= _inputTokenAmount - feesAmount); we can send some message if condition fails- assert(amountSpent <= _inputTokenAmount - feesAmount , "amountSpent is greater than required") ;
#0 - adrien-supizet
2021-11-18T11:50:26Z
duplicate #166
🌟 Selected for report: hyh
Also found by: MaCree, elprofesor, fatima_naz, gpersoon, gzeon, loop, palina, pauliax, pmerkleplant, xYrYuYx, ye0lde
fatima_naz
in function removeOperator in NestedFactory.sol function removeOperator(bytes32 operator) external override onlyOwner { uint256 i = 0; while (operators[i] != operator) { i++; } require(i > 0, "NestedFactory::removeOperator: Cant remove non-existent operator"); delete operators[i]; }
In the require condition i>0 but if the first element of operators i.e. operators[0] is equal to the operator the while loop will break just then. so i is 0 but require condition checks for i>0 so it will show that "NestedFactory::removeOperator: Cant remove non-existent operator" but actually the operator exist and it needs to be removed.
change the condition in require as i>=0
#0 - maximebrugel
2021-11-16T11:30:26Z
Duplicated : #58
#1 - alcueca
2021-12-03T11:15:44Z
Using #220
🌟 Selected for report: hyh
Also found by: MaCree, elprofesor, fatima_naz, gpersoon, gzeon, loop, palina, pauliax, pmerkleplant, xYrYuYx, ye0lde
fatima_naz
In function removeOperator - function removeOperator(bytes32 operator) external override onlyOwner { uint256 i = 0; while (operators[i] != operator) { i++; } require(i > 0, "NestedFactory::removeOperator: Cant remove non-existent operator"); delete operators[i]; }
In the while condition it is not checked that i<operators.length so if the required operator does not exist in the array then the condition operators[i] != operator will always be true and variable i will always increase. So once it is equal to the length of array it will try to access that index but that index is out of bound to it will throw an exception.
https://github.com/TokenMarketNet/smart-contracts/issues/101 https://jeancvllr.medium.com/solidity-tutorial-all-about-array-efdff4613694
we need to add a check in while loop that i<operators.length
#0 - maximebrugel
2021-11-16T11:29:30Z
Duplicated : #58
#1 - alcueca
2021-12-03T11:01:03Z
Duplicate of #59
#2 - alcueca
2021-12-03T11:04:09Z
Actually, taking #220