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