Transfer Assignment

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

Btw where I can see the return value of the withdraw() function on remix?

image

The require function is used to ensure that the user cannot withdraw an amount larger than their balance. The amount is simply subtracted from the user’s balance after the withdrawal.

pragma solidity 0.7.5;


contract Bank {
    
    mapping(address => uint) balance;
    address owner;
    
    event depositDone(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 depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
    
    function withdraw(uint amount) public returns (uint){
        require(balance[msg.sender] >= amount, "Balance insufficient.");
        msg.sender.transfer(amount);
        balance[msg.sender] -= amount;
    }
    function getBalance() public view returns (uint){
        return balance[msg.sender];
    }
    
    function transfer(address recpient, uint amount) public {
        
        // checks balance
        require(balance[msg.sender] >= amount, "Balance not sufficient");
        require(msg.sender != recpient, "Don't transfer money to yourself!");
        
        uint previousSenderBalance =  balance[msg.sender];
        
        
        _transfer(msg.sender, recpient, amount);
        assert(balance[msg.sender] == previousSenderBalance - amount);
        
    }
    
    function _transfer(address from, address to, uint amount) private {
        
        balance[from] -= amount;
        balance[to] += amount;
    }
}

Hi @walacemaia

The withdraw function should not be payable because it does not receive any ether.

Cheers,
Dani

1 Like

Hi @bigbill

You can see the returned data in the transaction logs.

Cheers,
Dani

1 Like

Hey @Nicholas_Blom

You can remove the return statement as you are not returning anything :slight_smile:

    function withdraw(uint amount) public returns (uint){
        require(balance[msg.sender] >= amount, "Balance insufficient.");
        msg.sender.transfer(amount);
        balance[msg.sender] -= amount;
    }

Happy learning,
Dani

function withdraw(uint amount) public onlyOwner returns (uint) {
require (balance [msg.sender] >= amount);
msg.sender.transfer(amount);
}

My solution:
(Note: this is written in version 0.8.3)

function withdraw(uint _amount) public {
    require(balance[msg.sender] >= _amount);
    payable(msg.sender).transfer(_amount);
    balance[msg.sender] -= _amount;
}
1 Like

bro that will make your withdraw function only usable for owner of the contract.
Should not do that since everyone can have deposit/withdraw in this case.
Just that we need to limit the withdraw amount for each account to be the amount they deposited.

The right answer should be:
function withdraw(uint amount) public returns (uint) {
require (balance [msg.sender] >= amount);
balance[msg.sender] -= amount;
msg.sender.transfer(amount);
}

The balance[] is a tracker that stores the information of which account has interacted with the contract and deposited how much to it. It is a separate record of the account’s actual balance of ether. So your first step is right in checking the record in balance[] to make sure there is sufficient balance deposited in the past according to the record, but then you need to update the record the .transfer. That operation did not update your balance[], only the actual account’s balance.

It’s also a good practice according to Filip in one of the courses to update the record of state variable first before performing the transfer in case something goes wrong.

I think the concept of account in Ethereum needs to be explained further by Filip so that people can grasp the idea. Account can be individual account or smart contract’s account.

1 Like

Thankyou very much for taking time to explain. It’s much appreciated

Have a good day

Keith

1 Like

Lets see if this works

contract RestrictNegTransfer{

mapping(address => uint) balances;

function Deposit() public payable returns (uint addressBalance) {
    require(msg.sender != address(this), "Unable to transfer to this address");
    balances[msg.sender] = balances[msg.sender] + msg.value;
    
    return balances[msg.sender];
}

function GetBalance() public view returns(uint addressBalance) {
    return balances[msg.sender];
}

function Withdraw(uint ETHtot) public returns(uint addressBalance) {
    require(ETHtot <= balances[msg.sender], "Insufficient balance.");
    msg.sender.transfer (ETHtot);
    balances[msg.sender] = balances[msg.sender] - ETHtot;
    
    return balances[msg.sender];
}

}

1 Like

can it be like this?
we require the balance of sender to be greater or equal than amount
then we subtract amount from sender balance
then we transfer the amount

function withdraw(uint amount) public {
   require (balance[msg.sender] >= amount);
   balance[msg.sender] -= amount;
   msg.sender.transfer(amount);
}
1 Like

This is indeed the correct way to code a withdraw function.
Good job

1 Like

Did old course, now doing new course so I may have previously answered, here is my new answer:

    function withdraw(uint amount) public returns (uint){
        require(amount > 0, "Amount must be greater than zero");
        require(amount <= balance[msg.sender], "Amount exceeds balance");
        
        uint prevBalance =  balance[msg.sender];
        
        balance[msg.sender] -= amount;
        
        msg.sender.transfer(amount);
        
        assert(balance[msg.sender] == prevBalance - amount);
    }
1 Like
function withdraw (uint amount) public returns(uint) { 
    require (balance[msg.sender]>=amount, "balance not sufficient");
    msg.sender.transfer (amount);
    balance[msg.sender] -= amount; 
    return balance[msg.sender]; // why do we sometimes return, and sometimes not return? 
    
    uint PsenderBalance = balance[msg.sender];
    assert (balance [msg.sender]== PsenderBalance - amount ); 
    
}

//

  1. If i change the name PsenderBalance to previousSenderBalance which was used in transfer function, will there be error since both function are separate functions?

  2. Can i return balance[msg.sender] before the assert code ?

  3. i am a bit confused because i see that sometimes function does not return value like

mapping (address=> User) users; 

struct User{ 
    uint id;
    uint balance; 
}

function updateBalance (uint id, uint balance) public { 
   User storage user= users[id]; 
} 

// I am thinking maybe if the mapping is already declared at the top, then this would be storage data type automatically and hence do not need to be returned, so there is no need to return.

But in the withdraw function, the mapping with the name balance, is also declared, but it needs to be returned in withdraw function.

I am confused but keen to learn about it. Please advise me the way out of my doubts.
Thank you

Hi @M.K

Read this faq and follow its instructions to post readable code in the forum: FAQ - How to post code in the forum

  1. If i change the name PsenderBalance to previousSenderBalance which was used in transfer function, will there be error since both function are separate functions?
  2. Can i return balance[msg.sender] before the assert code ?
  • If previousSenderBalance is declared globally you can use it. If it was declared locally in another function you cannot.

  • You can return balance[msg.sender] before the assert code but the assert will never be called as return statements terminate the function immediately.

function updateBalance (uint id, uint balance) public { 
   User storage user= users[id]; 
} 

am thinking maybe if the mapping is already declared at the top, then this would be storage data type automatically and hence do not need to be returned, so there is no need to return.
But in the withdraw function, the mapping with the name balance, is also declared, but it needs to be returned in withdraw function.

  • You are not re-declaring the mapping, you are creating an instance of it inside the updateBalance function.
    You can also use the dot notation if you prefer:
users[msg.sender].id = _id;
user[msg.sender].balance = _balance;

Or you could also use:

user[msg.sender] = User(_id, _balance);

Regards,

HI Daniele, Thanks for the answers. Just to clarify

  1. actually previousSenderBalance is just a variable name created in a function . So my question is , in two different functions, example, 1 . transfer function and 2. withdraw function, am i able to use the same name as the variable name since they are different functions.

  2. I understand from you that if return statement is done before the assert function, whether the assert () finds variant or invariant, it will still not be called because return statement terminate the function immediately. Ok so return statement needs to be at the last part.

  3. i noticed sometimes we returns and sometimes we dont returns in function statements.
    => When do we returns and when do we not returns in function ?

  4. may i confirm your code
    users[msg.sender].id = _id;
    user[msg.sender].balance = _balance; // the user should be users ?

user[msg.sender] = User(_id, _balance); // user should be users?

Thanks for your help
Appreciate it

Hey Daniele and Carlos, hope you are well.

  1. Can we only declare a variable state in constructor ?
    for example, can we just declare variable states as below without constructor ?

uint a=1;
uint aa=2;
string b=“hello”;

pragma solidity ^0.5.0;

contract Base {
   uint data;
   constructor(uint _data) public {
      data = _data;   
   }
}

I copied the above from a website when i was checking what is constructor for.
After i see the code, i have a question.
=> If what we need is data, why is there a need to construct another _data, to be equal to data?
Why do we not directly use data instead?

Thank you

function withdraw(uint amount) public returns (uint){
        require(balance[msg.sender] >= amount);
        uint originalBalance = balance[msg.sender];
        msg.sender.transfer(amount);
        balance[msg.sender] -= amount;
        assert(originalBalance == amount + balance[msg.sender]);
    }
1 Like

Hey @M.K

There is no difference between initialise a variable during its declaration or in the constructor however you are using a really basic case in your example.

uint a = 10;
uint a;
constructor(uint _a){
   a = _a;
} 

Consider instead a project, where for example you deploy 2 different contracts:

  • The first contract calls a DEFI protocol (such for example Compound) and gets data from it;
  • These data are returned and used to deploy your second contract.

You well understand that you have to use a constructor in order to achieve this.

All these info will be clear once you start using Truffle to deploy your contracts.

Regards,
Dani

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

type or paste code here

1 Like