Transfer Assignment

I had it like this:

function withdraw(uint amount) public returns (uint){
//msg.sender is an address
require(balance[msg.sender] >= amount, “Insufficient balance”);
msg.sender.transfer(amount);
balance[msg.sender] -= amount;
return balance[msg.sender];

2 Likes

I did just notice that I had the:

msg.sender.transfer(amount);
balance[msg.sender] -= amount;

around a different way to Filip. Does that matter at all?

2 Likes

My function is not so different from the posts here:

function withdraw(uint amount) public returns(uint){
        require(balance[msg.sender] >= amount);
        balance[msg.sender] == balance[msg.sender] - amount;
        msg.sender.transfer(amount);
        return balance[msg.sender];
    }
1 Like
    //the balance reduce with function withdrawal
    function withdraw(uint amount) public returns (uint){
        //!!important to require that you have equal or more in contract 
        //than the amount you want to withdraw
        require(balance[msg.sender]>=amount);
        //msg.sender is an address you withdraw to
        payable(msg.sender).transfer(amount);
        //reducing our balance in contract for amount
        balance[msg.sender]=-amount;
        //return our new balance in contract
        return balance[msg.sender];
    }

you can also do without payable function inside

1 Like

Can someone clarify me the meaning and the difference of using . and [] in our functions like msg.sender.transfer and balance[msg.sender] I get confuse on writing in my code is it gonna be a . or [].

1 Like
    function withdraw(uint amount) public returns (uint) {
        require(amount <= balance[msg.sender], "You can't withdraw more than you own.");
        uint previousBalance = balance[msg.sender];
        msg.sender.transfer(amount);
        balance[msg.sender] -= amount;
        assert(balance[msg.sender] == previousBalance - amount);
        return balance[msg.sender];
    }
1 Like

function withdraw (uint amount) public onlyOwner returns (uint){
require(balance[msg.sender] >= amount, “You not have enought ETH”);
payable(msg.sender).transfer(amount);
balance[msg.sender] -= amount;
return balance[msg.sender];
}

Couldnt find the WHY payable(msg.sender).transfer(amount) doesn’t work without payable(), since almost everybody says it does work, this was the only way to don’t have errors in the compiler :wink:

1 Like

pragma 0.8.4

  function withdraw(uint amount) public onlyOwner returns (uint) {
         require(balance[msg.sender] >= amount,"Insufficient Balance");
         payable(msg.sender).transfer(amount);
         balance[msg.sender] -= amount;
         return balance[msg.sender];
}
1 Like

I think I can try to help with this, though the terminology might not be 100% as I’m coming from Python programming.

Let’s set up some example code as the explanation depends on the data type:

    struct User{
        address id;
        uint balance;
    }

    mapping(uint => User) users;

Here we have a custom data type, User. It contains two attributes - ID (which corresponds with an address) and balance (a positive whole number).

The mapping creates a dictionary of multiple entries, all of which are individual User data types so must contain those two attributes.

Now first we use [] to access a particular entry in the dictionary. You can think of [] as always looking something up:

// dictionaryName[dataToLookup]
users[msg.sender]

This will look up the address of the active user in the mapping to find the ID and balance associated with that one record in the dictionary.

We can then access those individual attributes by using . and adding the attribute name:

users[msg.sender].balance

…will access only the balance of the active user and:

users[msg.sender].id

…will return only the ID of the user (which in this instance is pointless as it’s just the address, which we already have access to using msg.sender)

I’ve found while learning it can help to assign multiple steps like this to variables to break them down, eg:

address activeUser = users[msg.sender]
uint activeUserBalance = activeUser.balance

Similarly, msg.sender accesses the sender attribute of the msg object.

The other thing using . can do is access a method associated with an object. A method runs an existing function specific to that object to make a change. It looks different because it always has brackets after it:

// object.methodToApply()

A method may or may not need additional input to run

// object.methodTo Apply()
// or
// object.attribute.methodToApply(data)
msg.sender.transfer(amount)

Here the method transfer() is being applied to the attribute sender from the object (or data type) msg. The method requires additional data as without that input it can’t be used. This is fed in as the variable ‘amount’.

I hope that helps to make some sense of it a bit.

2 Likes

Edit: still on a train, still can’t compile so committing to this untested!

    function withdrawBalance(uint amount) public returns (uint) {
        require(balance[msg.sender] >= amount,"The balance is not high enough to withdraw this amount.");
        msg.sender.transfer(amount);
        balance[msg.sender] -= amount;
        return balance[msg.sender];
    }

Edit again - got this wrong, tried to pass in a variable to a modifier. Forget modifier variables need fixing in the function header, which won’t work here.

1 Like
pragma solidity 0.7.5;

contract Bank {

    mapping(address => uint) balance;
    address owner;
    
    event transferCompleted(uint amount, address transferredFrom, address transferredTo);
    event depositMade(uint amount, address indexed depositedTo);
    
    modifier onlyOwner {
        require(msg.sender == owner);
        _; 
    }
    
    constructor(){
        owner = msg.sender;
    }
    
    function deposit() public payable returns (uint){
        balance[msg.sender] += msg.value;
        emit depositMade(msg.value, msg.sender);
        return balance[msg.sender];
    }
    
    function getBalance() public view returns (uint){
        return balance[msg.sender];
    }
    
    function withdraw(uint amount) public returns (uint){
        require(balance[msg.sender] >= amount, "Withdrawal amount exceeds current balance");
        balance[msg.sender] -= amount;
        msg.sender.transfer(amount);
        return balance[msg.sender];
    }
    
    function transfer(address recipient, uint amount) public {
        require(balance[msg.sender] >= amount, "Insufficient balance");
        require(msg.sender != recipient, "Transfers cannot be made to your own account");
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);

        emit transferCompleted(amount, msg.sender, recipient);

        assert(balance[msg.sender] == previousSenderBalance - amount);
    }
    
    function _transfer(address from, address to, uint amount) private{
        balance[from] -= amount;
        balance[to] += amount;
    }
}
1 Like
pragma solidity 0.7.5;

contract Bank {
    
    mapping(address => uint) balance;
    address owner;
    
    event depositDone(uint amount, address indexed depositedTo);
    
    event transferDetails(uint amount, address indexed senderAddress, address indexed recipientAddress);
    
    modifier onlyOwner {
        require(msg.sender == owner);
        _; // run the function
    }
    
    constructor(){
        owner = msg.sender;
    }
    
    function deposit() public payable returns (uint) {
        balance[msg.sender] += msg.value;
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
    
    function withdraw(uint amount) public returns (uint) {
        require(balance[msg.sender] >= amount);
        msg.sender.transfer(amount);
        balance[msg.sender] -= amount;
        return balance[msg.sender];
    }
    
    function getBalance() public view returns (uint){
        return balance[msg.sender];
    }
    
    function transfer(address recipient, uint amount) public {
        require(balance[msg.sender] >= amount, "Balance not sufficient");
        require(msg.sender != recipient, "Don't transfer money to yourself");
        
        uint previousSenderBalance = balance[msg.sender];
        
        _transfer(msg.sender, recipient, amount);
        
        emit transferDetails(amount, msg.sender, recipient);
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
    }
    
    function _transfer(address from, address to, uint amount) private {
        balance[from] -= amount;
        balance [to] += amount; 
    }
    
}
1 Like

Nice solution @AngSin17 :ok_hand:

Apologies for the delay in giving you some feedback on your solution to this assignment!

You have added all of the necessary code needed to solve the problem with the withdraw function. And your additional checkWithdrawLimit modifier with amount parameter is well coded, and will allow the same require statement to be applied to the transfer function as well as the withdraw function, thereby helping to avoid code duplication and to keep your code concise.

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.

Just let me know if you have any questions :slight_smile:

1 Like

Hi @jtb,

Apologies for the delay in giving you some feedback on your solution to this assignment!

The require statement and the return statement you’ve added are both correct :ok_hand:
But you are missing one very important line of code…

If you deploy your contract, make a deposit, and then call your withdraw function, you will notice that the caller’s address receives the requested withdrawal amount, but their balance in the mapping is not reduced (call getBalance to check this). I’m sure you can see that this is a very serious bug because, even though there is a limit on each separate withdrawal, this limit is never reduced to reflect each withdrawal.

msg.sender.transfer(amount) transfers ether from the contract address balance to the caller’s external wallet 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.


You’ve modified the withdraw function with the onlyOwner modifier, but this means that only the contract owner can withdraw funds up to their own individual balance. But the contract allows multiple addresses to deposit funds (we are simulating a bank with bank account holders) and so it only seems fair that all users should be able to withdraw their funds as well, don’t you think? :sweat_smile:

Once you’ve had a go at making the above modifications, have a look at this post which explains the importance of the order of the statements within your withdraw function body.

Let me know if you have any questions about how to make the necessary modifications to your code, or if there is anything that you don’t understand :slight_smile:

Hi @KennethJP,

Here is a link to my review of your solution to this assignment. You’ve posted the exact same code in the Solidity Payable Functions discussion topic, and I saw that first :slight_smile:

Hi @MattPerry,

The require statement and the return statement you’ve added to your withdraw function are both correct :ok_hand:
But you are missing one very important line of code…

If you deploy your contract, make a deposit, and then call your withdraw function, you will notice that the caller’s address receives the requested withdrawal amount, but their balance in the mapping is not reduced (call getBalance to check this). I’m sure you can see that this is a very serious bug because, even though there is a limit on each separate withdrawal, this limit is never reduced to reflect each withdrawal.

msg.sender.transfer(amount) transfers ether from the contract address balance to the caller’s external wallet 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.

Once you’ve had a go at correcting your code for this, have a look at this post which explains the importance of the order of the statements within your withdraw function body.

Let me know if anything is unclear, or if you have any questions :slight_smile:

Hi @Flippy,

Here is a link to my review of your solution to this assignment. You’ve posted the exact same code in the Solidity Payable Functions discussion topic, and I saw that first :slight_smile:

Thanks again Jon,

I appreciate all the extra info. I understand why this would a bad bug to have. I will look at my code again and give it my best to fix it.

1 Like

Hi @Gomez1333,

Apologies for the delay in giving you some feedback on your solution to this assignment.

You have added all of the necessary code needed to solve the problem with the withdraw function :ok_hand:

However, 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. You should have got a yellow/orange compiler warning for this.

Also, have a look at this post which explains the importance of the order of the statements within your withdraw function body.

Just let me know if you have any questions :slight_smile:

Not sure what is going wrong but i think this is it, when i deploy contract is does not update the balance after withdraw.

    function withdraw(uint amount) public returns (uint){
        require(balance[msg.sender] >= amount, "Balance not sufficient");
         balance[msg.sender] -= amount;
        msg.sender.transfer(amount);
        return balance[msg.sender];
1 Like