Transfer Assignment

Hi @mervxxgotti

If for whatever reason the transfer method fails, the function reverts.
A good lecture from you: https://vomtom.at/solidity-send-vs-transfer/

Cheers,
Dani

2 Likes

clarified! thank you!

1 Like

To ensure that the user cannot withdraw more than their balance, we have to require that his balance is greater than or equal to the amount withdrawn.
See code below;
function withdraw(uint amount) public returns (uint){
require(balance[msg.sender] >= amount, "Balance not up to amount);//checks user
//balance is adequate
balance[msg.sender] -= amount;//deducts amount from user balance
msg.sender.transfer(amount);//transfers the amount
return balance[msg.sender];//retrieves the user balance after transfer
}

1 Like

Adding the necessary require() to insure a user cannot withdraw more than we think they’re entitled to. Also note the “Checks–>Effects -->Interactions” pattern is in play:

function withdraw(uint amount) public returns (uint){
        require(balance[msg.sender] >= amount,"Insuficient Funds");
        balance[msg.sender] -= amount;
        msg.sender.transfer(amount);
        return balance[msg.sender];
    }
1 Like
    function withdraw(uint amount) public returns (uint) {
        require(balance[msg.sender] >= amount, "Not enough funds");
        balance[msg.sender] -= amount;
        msg.sender.transfer(amount);
        return balance[msg.sender];
    }
1 Like
require(balance[msg.sender] >= amount
1 Like
pragma solidity 0.7.5;

contract Bank {
   
    mapping(address => uint) balance;
    address owner;
    
    constructor() {
        owner = msg.sender;
    }
    
    event depositDone(uint amount, address indexed depositedTo);
    
    modifier onlyOwner {
        require(msg.sender == owner, 'only owner can add balance');
        _;
    }
    
    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, 'cannot exceed your own balance');
        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,'amount cannot exceed balance');
        require(msg.sender != recipient);
        _transfer(msg.sender, recipient, amount);
    }
    
    function _transfer(address from, address to, uint amount) private {
        balance[from] -= amount;
        balance[to] += amount;
    }
}
1 Like
msg.sender.transfer(amount);
balance[msg.sender] -= amount;

@filip I checked the solution you posted. The order of these two statements matter? It’s the opposite in your solution.

1 Like

check this answer, which play a patter that will be explained to you in the next lessons.

Carlos Z

function withdraw(uint amount) public returns (uint){
require (balance[msg.sender] >= amount, “Balance not sufficient”); //make sure this address has sufficient balance at this contract
msg.sender.transfer(amount); //transfer function has in-built error throwing
balance[msg.sender] -= 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];
    }
1 Like
    function withdraw(uint amount) public returns (uint){
        //msg.sender is an address (payable by default)
        //address payable toSend = 0x1aE0EA34a72D944a8C7603FfB3eC30a6669E454C
        require(balance[msg.sender] >= amount, "You have insufficient funds!");
        msg.sender.transfer(amount);
        balance[msg.sender] -= amount;
    }
1 Like
       return balance[msg.sender];

I got this to work but I was trying to get rid of the additional function. I don’t understand why the effect on memory vs storage is different by adding function.

pragma solidity 0.7.5;
contract Bank {
    
    //storage - permanent storage of data (state variables)
    //memory - temporary storage used in function execution
    //calldata - save arguments/inputs to our functions
    //strings, arrays, mappings, structs

    mapping(address => uint) balance;
    
    address owner;
    
    modifier onlyOwner {
        require(msg.sender == owner);
        _; //run the function
    }
    
    event depositDone(uint amount, address indexed depositedTo);
    event transfers(address transferFrom, address transferTo, uint amount);
    
    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 payable returns (uint){
        //msg.sender is an address
        require(balance[msg.sender] >= amount, "Balance not sufficient");
        msg.sender.transfer(amount);
        
        uint previousSenderBalance = balance[msg.sender];
        
        _withdraw(msg.sender, amount);
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
        
    }
    
    function _withdraw(address from, uint amount) private {
        balance[from] -= amount;
    }
    
    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);
        
        assert(balance[msg.sender] == previousSenderBalance - amount);
        emit transfers(msg.sender, recipient, amount);
    }
    
    function _transfer(address from, address to, uint amount) private {
        balance[from] -= amount;
        balance[to] += amount;
    }
    

}
pragma solidity 0.7.5;

contract Bank {
    
    mapping(address => uint) balance;
    
    event depositDone(uint amount, address indexed depositedTo);
    
    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[msg.sender] -= amount;
        msg.sender.transfer(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);
                
        assert(balance[msg.sender] == previousSenderBalance - amount);
    }
    
    function _transfer(address from, address to, uint amount) private {
        balance[from] -= amount;
        balance[to] += amount;
    }
    
}

Here’s my solution:

    function withdraw(uint a_amount) public returns(uint){
        require(balances[msg.sender] >= a_amount, "Insufficient Balance");
        balances[msg.sender] -= a_amount;
        msg.sender.transfer(a_amount);
        return balances[msg.sender];
    }

I’d particularly like to commend @marsrvr for referencing the Checks Effects Interactions pattern which is well demonstrated here. By executing the transfer last, reentrant code can’t abuse internal state because the effect of the withdrawal (namely the mutation of the mapping) has already been applied.

1 Like

Implemented require function to check if the amount input is valid. Also added an assert function to check that the balance got adjusted correctly.
Question to this: would this assert function actually add security to my contract or is it unnecessary?

function withdraw(uint amount) public returns (uint) {
            require(amount <= balance[msg.sender], "Insufficient balance");
            uint previousSenderBalance = balance[msg.sender];
            balance[msg.sender] -= amount;

            msg.sender.transfer(amount);

            assert(balance[msg.sender] == previousSenderBalance - amount);
            return balance[msg.sender];
        }
1 Like

Hey @Santiago

The assert statement is unnecessary here as the whole function would revert in case the .trasfer method fails.

Cheers,
Dani

2 Likes

First check if the balance is >= then the amount you want to withdraw
then subtract the amount from the balance
as last return the balance

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

The require amount > 0 is just to reduce gas fees if user accidentally withdraws 0–otherwise it isn’t needed to solve this problem.

function withdraw(uint amount) public returns (uint) {
    require(balance[msg.sender] >= amount, "Insufficient funds!");
    require(amount > 0, "Must withdraw more than 0!");
    uint initialBalance = balance[msg.sender];

    msg.sender.transfer(amount);
    balance[msg.sender] -= amount;
    
    assert(initialBalance > balance[msg.sender]);
}
1 Like