Solidity Payable Functions - Discussion

Correct, it was an extra parameter that you dont need.

payable allows to use msg.value to receive ethers.

In Ethereum Smart Contract Programming 201, you will learn how to use truffle, which is another tool to compile solidity contracts.

To interact with dapps, yes.

through web3.js library.

Connection to nodes directly.

Carlos Z

Thank you very much for your answers.
I wonder how does calling payable function works when connecting nodes directly.
Could you explain or tell where I could find explanation?

Kacper Pajak

1 Like

I think this video explain pretty well what you are asking. :face_with_monocle:

https://www.youtube.com/watch?v=5HRmpeFbdnI

Carlos Z

Guys I have a question. What balance is the getBalance function getting in the tutorial? Is that the smart contract balance or the internal balance … It wasn’t very clear that. thanks

2 Likes

image

Why my function doesnt works?

1 Like

Hey @Artrex_G, hope you are ok.

The receiver must be a payable address, by default msg.sender is not, please share your code in the following way so i can review it properly:

Carlos Z

Did the following solution:

function withdraw(uint amount) public returns(uint) {

    uint assertTransfer = balance[msg.sender];
    
    msg.sender.transfer(amount);
    
    assert(balance[msg.sender] == assertTransfer - amount);
1 Like

Thanks, it helped me a lot.

I’m still learning, and here in Brazil the material is still very old.

I’m learning a lot here.

1 Like

Hi,

I am having problems with the transfer function. I wrote this simple code in attempts to understand how to use transfer correctly. I was thinking everything I deposit into the contract would be able to be withdrawn to the current address (msg.sender) however whenever I withdraw an amount it is never added to the current address (msg.sender) and when I display the balance using the showBalance function the balance only changes when I deposit but nothing happens when I withdraw… somebody please help. Thanks.

contract bank {

mapping (address => uint) balance;

function deposit () public payable returns (uint){
balance[msg.sender] += msg.value;
return balance[msg.sender];
}

function showBalance () public view returns (uint){
return balance[msg.sender];
}

function withdraw (uint amount) public returns(uint){
msg.sender.transfer(amount);
}
}

Hey @Rob1, hope you are ok.

The only issue that I see with your withdraw function is that you never update the balance of your mapping, also the msg.sender must be casted as payable.

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.7;

contract bank {

    mapping (address => uint) balance;

    function deposit () public payable returns (uint){
    balance[msg.sender] += msg.value;
    return balance[msg.sender];
    }
    
    function showBalance () public view returns (uint){
    return balance[msg.sender];
    }
    
    function withdraw (uint amount) public {
        balance[msg.sender] -= amount;
        payable(msg.sender).transfer(amount);
    }
}

Carlos Z

I’m trying to understand how this deposit() function really works.
How is msg.value being passed to this function?

In remix, it only shows a “Deposit” button without a field. So no value is actually being deposited (???).

For comparison, withdraw(uint amount) is being passed an amount value.

Can someone explain how this deposit function is supposed to work?

function deposit() public payable returns(uint) {
        balance[msg.sender] += msg.value;
        emit depositDone(msg.value, msg.sender);
        return balance[msg.sender];
    }
1 Like

and, when i run this with the full contract in Remix, how can i see the event being emitted? i do not see events being printed in the Remix console … so where are events emitted to?

Hey @bcripy,

I’m glad the information helped, and I hope you’re still learning lots :muscle:

Hi @gaio,

In Remix, when you send ETH to a contract, and call the function which RECEIVES that ether value, you need to input the amount of ether/wei you want to send in the VALUE field (below the Account and Gas Limit fields) and set the dropdown to the relevant unit of currency (wei, gwei, finney or ether). You need to do this before you call the deposit function (by clicking the “Deposit” button), otherwise, as you have discovered, no value will be deposited.

The input fields which appear next to the function-call buttons are for arguments/parameters that are explicity defined in the function header, such as   address recipient   or   uint amount , for example. However, when a smart contract function RECEIVES ETH from an external address, Solidity does not require this to be explicity defined as a parameter, and the ether value will be automatically passed to the function. It is still available as an implicit parameter, though, and can be referenced and handled with msg.value.

Another implicit parameter which Solidity automatically passes to a function (i.e.without needing to be explicity defined as a parameter in the function header) is msg.sender . In Remix, this address value will always be the address which is set in the Account field — the calling address. When the deposit function is called, both the calling address (Account field) and the ether/wei value sent/deposited (Value field) are automatically passed to the function. The ether/wei value is automatically added to the contract address balance, and this does not require any additional code. However, we can reference and handle this value with msg.value and the depositor’s address with msg.sender . We need to reference and handle these values in order to keep track of each account holder’s share of the total contract balance, which we do with the line…

balance[msg.sender] += msg.value;

This internal accounting (recorded by the mapping) is crucial, because the contract balance figure represents the total pooled funds (i.e. the sum of all account holder balances).


The withdraw function works differently. It uses the syntax…

<address payable>.transfer(uint amount)

… to deduct the withdrawal amount from the contract balance and transfer it to the caller’s address. As with the deposit function, the caller’s address can be referenced with msg.sender , but the withdrawal amount needs to be input as a uint value, which can then be referenced by its parameter name (amount)…

msg.sender.transfer(amount);

I hope that makes things clearer; but just let me know if you have any further questions :slight_smile:

2 Likes

Once you’ve called the function with an ether/wei value, as I’ve described, then your emit statement should successfully log your deposit event data: the deposit amount (always in wei), and the depositor’s address. You should see this event log if you expand the transaction confirmation (with the green tick) in the Remix console, and scroll down to logs. You should see something like…

[{
	"from": "0xd914...138",    // Smart contract address
	"topic": "0x4bc...a53",
	"event": "depositDone",    // Event name
	"args": { // Logged data, according to the defined event arguments
              // Same data given twice (i) by index (ii) by argument name      
		"0": "4000000000000000000",       // Amount deposited (always in wei)
		"1": "0x5B3...dC4",               // Depositor's address
		"amount": "4000000000000000000",  // Amount deposited (repeated)
		"depositedTo": "0x5B3...dC4"      // Depositor's address (repeated)
	}
}]

Obviously, this is assumes you’ve defined your event at the top of the contract, as well as emitting it :wink:

Just let me know if anything is still unclear.

1 Like
pragma solidity 0.7.5;
contract Bank {
    
    event Log(uint amount,address to );
    function Deposit() public payable {
        emit Log(msg.value,msg.sender);
    }
}

The log shows a “from” address and a “to” address.
I know the “to” is the contract address.
My question is what is the from address?

[ { "from": "0x7EF2e0048f5bAeDe046f6BF797943daF4ED8CB47", "topic": "0x451fd692d761946da28778ba4fec74700fa4197e441dad0b36dd8284f65f9f7f", "event": "Log", "args": { "0": "1000", "1": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4", "amount": "1000", "to": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4" } } ]

1 Like

I don’t get the transfer in withdraw function.
My question is:
The amount is transferred from which address to which address?

 function withdraw(uint amount) public {
        msg.sender.transfer(amount);
    }
1 Like

@filip
why we are increasing the balance of the sender by one ether if the sender is depositing 1 ether.
The balance should be decreased by 1 ether right?

1 Like

Thanks for your help! This is more clear.

Two more questions. An event transferDone successfully printed to log in the console:

{
		"from": "0x7EF2e0048f5bAeDe046f6BF797943daF4ED8CB47",
		"topic": "0xb0ee4d593b8cd94a0820e9d3cc9719bd6fb3fb6c50b0f0e1d5e3fc7356fc7ee9",
		"event": "transferDone",
		"args": {
			"0": "2",
			"1": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
			"2": "0xd28374186360650595864e657B7fcA15AD2CBaFF",
			"amount": "2",
			"sentFrom": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
			"sentTo": "0xd28374186360650595864e657B7fcA15AD2CBaFF"
		}
	}
]

what is “topic”? the transaction id ?

And are these logs something only in context to Remix, or if choosing indexed in the event, is this same data schema also indexed on the blockchain?

1 Like

Hi @saishet,

If you are talking about the deposit function, then…

  • The ether amount deposited (the Value sent to the deposit function) will be deducted from the account of the calling address (you will see their account balance decreasing by this amount in the Account field at the top of the Deploy & Run Transactions panel). Think of this as the balance of the depositor’s external wallet address being reduced by the amount of ether they send and deposit within the Bank smart contract.

  • The ether value is automatically added to the contract address balance (it’s a payable function, so it can receive ether). If you want to check that this is actually happening, you can add the following function to your contract to get the Bank contract balance (the total pooled funds held in the smart contract from all account holders) …

    function getContractBalance() public view returns(uint) {
        return address(this).balance;
    }
  • The amount of ether deposited into the contract also needs to be added to the depositor’s individual Bank account balance (recorded in the mapping). This internal accounting adjustment is crucial, because the contract needs to keep track of each account holder’s individual share of the total contract balance in order to ensure that users cannot withdraw more ether than they are entitled to.

It’s important to understand that when a user deposits ether into the Bank contract, they are transferring ether from one address (e.g. their external wallet address) to the Bank smart contract address. They still “have” the same amount of ether, but the amount transferred is now part of a different Ethereum account balance — it’s included within the Bank contract’s ether balance.

I hope that makes things clearer; but just let me know if you have any further questions :slight_smile:

1 Like