Hi @tbem,
You have added the additional lines of code needed to solve the problem with the withdraw function
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. Besides, we do already have the getBalance() function which a user can call to consult their own individual updated balance after a withdrawal.
However, we should not mark the withdraw function as payable
, because it doesn’t need to receive Ether from an external address in order to update the contract balance. If we make it payable
, then, if the caller sends an Ether value to the withdraw function by mistake (as well as calling it with a withdrawal amount) then this Ether would be added to the contract balance and potentially lost to the user: this is because the withdraw function does not make an equivalent accounting adjustment to the mapping for such a deposit (only for withdrawals). However, the function is much securer if we leave it as non-payable, because then, if the caller makes the same mistake, the function will revert, and the Ether won’t be sent.
A function only needs to be marked payable
when it receives ether from an external address to add to the contract address balance. It might help to think of payable
as the code that enables msg.value
to be added to the contract address balance, without us having to add any further code for this. In the deposit function, this happens automatically because we have marked the function as payable
. The line   balance[msg.sender] += msg.value;
  then adds the same value to the individual user’s balance in the mapping, in order to keep track of their share of the total funds held in the contract.
In contrast, the withdraw function is deducting ether from the contract balance and sending it to an external address. It does this using the address member transfer
(which is like a method called on a payable address)…
<address payable>.transfer(uint256 amount);
Your withdraw event is a nice thing to add. The event declaration is well coded, but from what I’ve just explained about the function type payable
, you can probably now see why referencing msg.value
in the corresponding emit statement will not log the withdrawal amount: msg.value
will only log a value if Ether is also sent to the function and, as I’ve mentioned above, we want to prevent that from happening by leaving the function type as undefined (i.e. non-payable). Instead, the emit statement needs to reference the amount
parameter. You correctly deducted amount
(and not msg.value
) from the individual user’s balance in the mapping, so that it continues to accurately reflect their share of the total amount of Ether held in the contract…
balance[msg.sender] -= amount;
This amount
is the same value you want your withdraw event to log for the withdrawal amount, together with the withdrawer’s address (msg.sender
).
Now have a look at this post which explains an important security modification that should be made to the order of the statements within your withdraw function body.
Can you also add your transfer() function? That way we can see your transfer event’s corresponding emit statement, and your full solution to the Events Assignment from the Events video lecture.
Let me know if anything is unclear, or if you have any questions