function withdraw(uint amount) public returns(uint){
require(balance[msg.sender]>=amount);
msg.sender.transfer(amount);
balance[msg.sender]-=amount;
return balance[msg.sender];
}
Yes, because onlyOwner
triggers the require statement in the modifier with that name:
require(msg.sender == owner, "Function can only be called by contract owner");
If you still have this modifier, the constructor and the owner state variable in your contract, then
this restriction would be applied to the withdraw function inputs before any of the other code in its function body executes.
Excellent @inahan
You have added all of the additional code that was missing.
The only improvement that can be made is to put
balance[msg.sender] -= amount;
â before âmsg.sender.transfer(amount);
This is important for security. We wouldnât expect you to know this at this early stage, though, so Iâm just telling you for extra info. Youâll learn about the type of attack this prevents, and how it does it, in later courses. In summary, itâs important to modify the contract state before you actually perform the transfer of funds out of the contract, just in case there is an attack after the transfer, but before the state is modified to reflect this operation. But donât worry about the details for now, but itâs good to be aware of and to start getting into good habits
Thank you so much for your time!
Its not easy with us starters
I changed it to:
pragma solidity 0.7.5;
import â./Ownable.solâ;
import â./Destroyableâ;
contract Bank is Ownable, Destroyable {
mapping(address => uint) balance;
event depositDone(address indexed depositedTo, uint ammount);
function deposit() public payable returns(uint) {
balances[msg.sender] += msg.value;
emit depositDone(msg.sender, msg.value);
return balances[msg.sender];
}
function transfer(address recipient, uint amount) public {
require(balances[msg.sender] >= amount, âNot enough balance!â);
require (msg.sender != recipient, âdont send money to yourselfâ);
uint previousSenderBalance = balance [msg.sender];
_transfer(msg.sender, recipient, amount);
}
function _transfer(address sender, address recipient, uint amount) private {
balances[sender] -= amount;
balances[recipient] += amount;
}
function withdraw(uint amount) public returns(uint) {
require(balances[msg.sender] >= amount, âNot enough balance!â);
require (msg.sender != recipient, âdont send money to yourselfâ);
balances[msg.sender] -= amount;
msg.sender.transfer(amount);
return balances[msg.sender];
}
function getbalance() public view returns(uint) {
return balances[msg.sender];
}
}
and now Im gettinâ another error saying ânot found browser/Destroyableâ
Thank you for the help!
So if I code; modifier balanceOf(uint amount){
require(balance[msg.sender] >= amount);
_;
}
Is this correct then?
function withdraw(uint amount) public onlyOwner returns(uint){
require(balance[msg.sender] >= amount);
//address payable test = ;
//test.transfer(amount);
msg.sender.transfer(amount);//transfer reverts and gives an error if its something wrong
balance[msg.sender] -= amount;
return balance[msg.sender];
function withdraw(uint amount) public returns (uint){
require(balance[msg.sender] >= amount, âInsufficient fundsâ);
//msg.sender.transfer(amount);----old location
balance[msg.sender]-=amount;
msg.sender.transfer(amount);//new location
return balance[msg.sender];
}
Hi @Gorana,
Youâve got some additional code from a later assignment mixed in here. Either remove the imports of Ownable.sol and Destroyable.sol, and also âis Ownable, Destroyable
â from the contract header, or make sure you have the relevant Ownable.sol and Destroyable.sol files in Remix so that Bank can do what itâs being told to do and import and inherit from them. If you are executing Bank with the imports and inheritance, then before clicking âDeployâ, check the dropdown in the âCONTRACTâ field just above and you should have all 3 contracts listed there. You need to make sure that Bank is selected from the dropdown and showing in the field when the dropdown is collapsed.
This is now all correct apart from the 2nd require statement. This is for the transfer function, and seems to have crept in here somehow It will give you a compiling error, because recipient
isnât a parameter in this function, or a defined variable.
You have also used the mapping name balance
inconsistently throughout the contract. Sometimes you have balances
instead. This will also give you compiling errors.
If you correct those things, then it should work a dream!
Hey @Lamar,
No, you canât use a modifier here, because the require statement for our withdraw function references the function parameter amount
. The function needs to accept different values for this input parameter (depending how much the different users want to withdraw). Your modifier balanceOf would only be of any use if amount
was fixed for each function it was used in â it could be a different amount in different functions, but fixed for each one. To code this, you would need to put the fixed amount in parentheses after the modifier name in your function header e.g. if the fixed amount for the withdraw function was 100, we would have
function withdraw(uint amount) public balanceOf(100) returns(uint) { ... }
Notice that we would have to use the name of the modifier we want to use in the function header (not onlyOwner â thatâs a different modifier and not correct here because we donât want to restrict withdrawals to just the contract owner).
As you can probably see, this is now a completely useless function, because we want the restriction to change depending on the requested withdrawal amount. So, your withdraw function is correct if you remove onlyOwner from the function header, and add the missing closing curly bracket at the end of the function. In this case, it is correct to have the require statement within the function body on the first line (as you have) and not in a modifier.
Have a read through my previous post again, where I give an example of where a modifier with a require statement and a parameter is appropriate.
Also, have a look at this post where I explain another important security modification that should be made to the order of the statements within your withdraw function body.
Let us know if anything is still unclear, or if you have any further questions.
Excellent @ArtCenter1
You have added all of the additional code that was missing.
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.
Thank you!
Thank you for your reply. I can see now that the solution is buggy for no reason (I didnât know that with assignment a pointer is created and I tried to find the optimal solution).
Itâs was an enlightening insight.
function withdraw(uint amount) public returns (uint){
require(balance[msg.sender] >= amount, âNot enough available funds.â);
balance[msg.sender]-=amount;
msg.sender.transfer(amount);
return balance[msg.sender];
}
I added the ârequireâ function thatâll compare the current balance of the sender to amount theyâre trying to withdraw. If this ârequireâ statement resolves as false then the message âNot enough available funds.â will return and the transaction will revert. If the function is successful, the now updated balance of the sender will be returned.
function withdraw(uint amount) public returns (uint){
require(balanceMapp[msg.sender] >= amount);
msg.sender.transfer(amount);
balanceMapp[msg.sender] -= amount;
I modified the function to check whether the msg.sender has more funds than he wants to withdraw and also his balance is reduced by the amount withdrawn.
I checked it and it seems to be working although itâs not really clear to me why itâs working.
So, I added the following:
- Require to make sure the withdrawal does not exceed the deposited amount
- Updated the internal balance after transfer
- Added assertions to make sure the new balance is correct and not below zero.
function withdraw(uint amount) public returns(uint) {
require(balance[msg.sender] >= amount);
uint oldBalance = balance[msg.sender];
balance[msg.sender] -= amount;
msg.sender.transfer(amount);
assert(balance[msg.sender] == oldBalance - amount);
assert(balance[msg.sender] >= 0);
return balance[msg.sender];
}
It is always more easy to understand if we comment each line of code, that way we could have a guideline on what that function suppose to do.
Here is an example based on your function:
//withdraw funds from contract, transfer to msg.sender the required amount if is permitted
function withdraw(uint amount) public returns (uint){
// check that balance of the user account is less or equal to amount requested
require(balanceMapp[msg.sender] >= amount);
//transfer the amount to msg.sender
msg.sender.transfer(amount);
//update the mapping value for that account after a successful transfer
balanceMapp[msg.sender] -= amount
If you have any more questions, please let us know so we can help you!
Carlos Z.
function withdraw(uint amount) public returns(uint){
** msg.sender.transfer(amount);**
** uint newBalance;**
** newBalance = balance[msg.sender] - amount;**
** return newBalance;**
** }**
I created a new value called ânewBalanceâ which should act as the balance after withdraw has been made. They specifying what it will do, the new balance should be equal to the function callers amount minus the withdrawn amount. Then it will be saved to the caller of the function and not across multiple addresses. In the end I returned the new balance.
Let me know if I have missed something or got something wrong!
modifier withEnoughtBalance(uint amount) {
require(balance[msg.sender] >= amount);
_;
}
function withdraw(uint amount) public withEnoughtBalance(amount) returns(uint) {
msg.sender.transfer(amount);
return balance[msg.sender];
}
@filip I submitted the answer previously, just a quick question, besides addresses depositing in to a contract what are the other ways a Contract holds value, so in the example we are just selecting from value button the amount we want to deposit in to an account, but my question is how does Contract gets that value initially?
function withdraw(uint amount) public returns (uint){
// only transfer if msg.senders balance is >= amount
require(balance[msg.sender] >= amount, âNon-sufficient Fundsâ);
balance[msg.sender] -= amount;
msg.sender.transfer(amount);
return balance[msg.sender];
}
Hi @ArvidK,
Your solution wonât prevent the caller from withdrawing more than their account balance, because your function is missing two important lines of code:
-
You need a require statement to check that the callerâs balance is sufficient to cover the withdrawal amount. If you donât include this, then they can withdraw any amount up to the overall contract balance!
-
You are recording the correct new balance and returning it as the output, but you donât update the mapping for this. Your
newBalance
is a local variable and so its value is lost once the function has finished executing. In the mapping,balance[msg.sender]
will remain as the previous balance, and so even after adding the require statement Iâve mentioned above, the address withdrawing the funds could still keep calling the withdraw function repeatedly for an amount lower than their original balance, even after theyâve withdrawn all of it. In this particular scenario, there isnât actually any need to store the remaining balance locally before updating the mapping. You can perform this with just one single line of code.
Once youâve had a go at making the above modifications, have a look at this post where I explain another important security modification that should be made to the order of the statements within your withdraw function body.
Let us know if anything is unclear, or if you have any questions and weâll help you