Hi @valleria,
Sorry for the delay in giving you some feedback!
withdraw()
function
(1) You should have found that your contract code didn’t compile, and so couldn’t be deployed…
Your pragma
statement is declaring that the code should be compiled based on Solidity v0.8 syntax. That’s absolutely fine, but then you also need to bear in mind that this course material is based on v0.7 syntax. The compiler will always generate an error when your syntax needs to be changed for v0.8, and the error message will tell you why, and often what you should change it to. In this case, you will have got a red compiler error for this line of code…
In order to receive Ether, an address needs to be payable
. Prior to Solidity v0.8, msg.sender
is payable by default and so doesn’t need to be explicitly converted. However, from v0.8, msg.sender
is non-payable by default, and so when it needs to refer to a payable address, it has to be explicitly converted. One of the ways to do this is using payable()
e.g.
payable(msg.sender).transfer(amount);
If you make this modification, you will notice that the compiler error disappears.
(2) The require statement you’ve added is correct, but your withdraw function is also missing an essential line of code …
If you deploy your contract, make a deposit, and then call your withdraw function as it is, you will notice that the caller’s external address receives the requested withdrawal amount, but their balance in the mapping is not reduced! This means that they can make repeat withdrawals — each one no greater than their initial balance, which isn’t being reduced — up to the total amount of Ether held in the contract (the sum of all of the individual account holders’ balances). So, I’m sure you can see why this is a very serious bug!
payable(msg.sender).transfer(amount)
transfers Ether from the contract address balance to the caller’s external address, but it doesn’t adjust the individual user balances in the mapping. These balances perform an internal accounting role, and record each user’s share of the contract’s total Ether balance. So, just as we increase a user’s individual balance when they deposit Ether in the contract, we need to do the opposite whenever they make a withdrawal.
(3) Notice that the withdraw function header also includes returns(uint)
. This is not mandatory to include, and the function can still operate effectively without returning a value. But as it’s been included in the function header, you should also include a return statement in the function body. Once the red compiler error (described above) has been corrected, the compiler will still give you an orange warning about this issue.
(4) Once you’ve made the above modifications to your code, have a look at this post which explains the importance of the order of the statements within your withdraw function body.
Transfer Event (from the Events Assignment)
Your transfer event declaration is well coded, and the corresponding emit statement, which you’ve added to the transfer() function body, will log data when the transfer() function is successfully executed.
However, you are emitting the msg.sender
address as the event’s to
address parameter, and the recipient
address as the event’s from
address parameter. Can you see that you’ve got these the wrong way round? The position of each value in the emit statement must be the same as that of its corresponding parameter in the event declaration, in terms of both data type and name. If the data types don’t correspond, then the contract won’t compile, but if the names are mixed up, then the affected data will be logged against potentially misleading identifiers (which is what will happen with your solution).
But you have referenced amount
in the correct position in your emit statement
Just one other observation …
In general, an emit statement is probably better placed after an assert() statement.
Let me know if anything is unclear, if you have any questions about any of these points, or if you need any further help to correct your solution code