Hi @thanasornsawan,
You have added all of the lines of code needed to solve the problem with the withdraw function and your statements are also in the correct order within the function body to reduce security risk
- Check inputs (require statements)
- Effects (update the contract state)
- External Interactions (e.g.
transfer
method)
Just as you have done, itâs important to modify the contract state for the reduction in the individual userâs balanceâŚ
before actually transferring the funds out of the contract to the external addressâŚ
This is to prevent what is known as a re-entrancy attack from occuring after the transfer, but before the userâs individual balance (effectively, the share of the total contract balance they are entitled to withdraw) is reduced to reflect this operation. Youâll learn more about this type of attack, and how the above order of operations helps to prevent it, in the courses which follow this one. But itâs great youâre already getting into good habits in terms of smart contract security
Some additional comments âŚ
(1)âHave you also restricted access to the deposit() function and the transfer() function to the contract owner with the onlyOwner modifier? If you have, then also adding the onlyOwner modifier to the withdraw() function header makes sense, as there will be no other users with individual balances to withdraw. However, this would be a very limited Bank contract if there can only ever be one user, the contract owner, and would also mean we wouldnât need the balance
mapping to store multiple user balances.
Instead, the aim of our contract is to simulate a bank with bank account holders, with multiple addresses being able to deposit funds and make internal transfers between themselves. This means that we donât want to restrict access to any of our functions to the contract owner, including the withdraw() function, because while the contract is still deployed it only seems fair that all users should be able to withdraw their funds
(2)âYour withdraw event and corresponding emit statement are both coded correctly. The emit statement is in the correct position in the withdraw() function body and will log the withdrawal amount when the withdraw() function is successfully executed. Is the reason why the event is only logging the withdrawal amount, and not the withdrawerâs address, because only the contract owner can make withdrawals? If, for the reasons Iâve mentioned above, we allow multiple users to withdraw funds, you will want your withdraw event to also log the withdrawerâs address, in the same way that our deposit event logs both the amount deposited and the depositorâs address.
(3)
This line of code withdraws the wei amount
from the contractâs ether balance and transfers it to the callerâs (msg.sender
's) external address balance (showing in the Account field in the Deploy & Run Transactions panel in Remix). Itâs important to understand that the callerâs (msg.sender
's) individual balance stored in the mapping records and tracks their individual share of the total contract address balance (effectively, their entitlement to withdraw ether from the contract balance). The individual userâs balance in the mapping is adjusted to reflect changes in their share of the total contract balance, but isnât actually where the ether is transferred out of the contract from.
Also, donât forget to post your solution to the Events Assignment here. This is the assignment from the Events video lecture, which is near the end of the Additional Solidity Concepts section of the course.
Let me know if anything is unclear, or if you have any questions about any of these points