Nice assignment solution @Adrian_Zumba 
You have included all of the additional functionality needed to solve the problem with the withdraw function.
Your decision to use a modifier for the require statement is a good one, and it is well coded. As you know, using modifiers helps us to avoid code duplication and keep our code concise, so Iâm interested to know if you have also used this same checkSenderBalance modifier in your transfer function to avoid having to repeat the same require statement in its function body?
Iâve noticed that you have expilicity converted msg.sender to a payable address usingâ payable(msg.sender)
.â Are you, therefore, using Solidity v.0.8? If so, well done for finding out that msg.sender
is no longer payable by default from v.0.8, and so needs to be explicitly converted whenever it needs to be payable. This isnât necessary in earlier versions of Solidity, such as the one we are using in the video lectures for this course (v.0.7.5). If you are using a later version than v0.7.5 (and thatâs perfectly fine), always include the â pragma solidity ...
â compiler version declaration in the code you post, as it is important for us to know what syntax we are reviewing.
However, in our withdraw() function, it is only the address receiving the ether which needs to be payable â and not the function itself. A function only needs to be marked payable
when it needs to receive ether. So, unlike the deposit() function, we donât want to mark withdraw() as payable in its function header. Marking it as payable doesnât prevent the code from compiling, or the function from executing, but it is bad practice and poor risk management not to restrict a function to non-payable if it doesnât need to receive ether, because if someone sends ether by mistake, this amount will still be transferred to the contract.
Your use of a private helper function to deliver a distinct part of the withdraw functionality is certainly logical, and demonstrates that you understand the importance of modularity within your code. The _withdraw() function itself is also very well coded⌠However, we also want to keep our code readable and, where possible, concise. Do you think that creating a separate helper function to parcel off just one line of code from the main function does that? I think the argument for this is always stronger the more code we are parcelling off.
Finally, in order to reduce security risk, the statements should be in the following order:
- check inputs (require statements)
- effects (update the contract state)
- external interactions
Itâs important to modify the contract state for the reduction in the balanceâŚ
balance[msg.sender] -= amount;
before actually transferring the funds out of the contract to the external addressâŚ
payable(msg.sender).transfer(amount);
⌠just in case there is an attack after the transfer, but before the state is modified to reflect this operation. Youâll learn about the type of attack this prevents, and how it does it, in later courses. We wouldnât expect you to know this at this early stage, though, so Iâm just telling you for extra information. But it does mean that, even though your solution compiles and works, it isnât very secure, because you are performing the transfer of funds (the external interaction) before updating the contract state for the effect of this transfer.
So, how would you modify your solution to make it more attack-resistant? Does this also affect the appropriateness of the additional _withdraw() helper function?
Let me know if you have any questions. Youâre making great progress 