Hi @kasunkv,
You have added both of the essential 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
Just as you have done, it’s important to modify the contract state for the reduction in the individual user’s 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 the courses which follow this one. But it’s great you’re already getting into good habits in terms of smart contract security
You are also right that it’s not necessary to return the updated balance, and so returns(uint)
can be removed from the function header. It is useful information to return, but we do already have the getBalance function which can be called separately to consult the individual account holder’s updated balance after the withdrawal.
Your withdraw event and corresponding emit statement are both correct and well coded. The emit statement is in the correct position in the withdraw() function body and will log appropriate data when the withdraw() function is successfully executed
The transfer() function was initially implemented to perform internal transfers between two users, without any ether actually leaving the contract. In this scenario, the total contract balance remains the same. Only the sender’s and the recipient’s individual balances in the mapping need to be adjusted to reflect a change in each user’s share of the total contract balance. The sender’s share (individual balance) is reduced, and the recipient’s share is increased by the same amount …
However, by including …
… your transfer() function does transfer ether out of the contract, to the recipient’s external address. In this case, only the sender’s individual balance in the mapping should be adjusted, because the recipient’s share of the contract balance shouldn’t be affected by the increase to their external address balance. In this respect, your transfer() function performs similar operations to the withdraw() function. Both reduce the total contract balance by the transaction amount. The only difference is that calling your transfer() function increases the recipient’s external address balance by the transaction amount, whereas calling the withdraw() function increases the caller’s own external address balance by this amount.
So, to perform an internal transfer within the contract, you need to remove …
And to perform an external transfer, you need to remove…
Your transfer event and corresponding emit statement are both correct and well coded. The emit statement is in the correct position in the transfer() function body and will log appropriate data when the transfer() function is successfully executed. However, whereas deposit and withdraw transactions only involve one user address, a transfer involves two: the sender and the recipient. So, I think you can make two improvements to your transfer event:
- Log both addresses (the sender’s as well as the recipient’s)
- Make it clear whose new balance is being logged (the sender’s not the recipient’s). You can do this easily by changing the parameter name e.g. from
balance
to senderBalance
Let me know if anything is unclear, or if you have any questions about any of these points