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);
}
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);
}
@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?
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?
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;
}
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
No… the "from"
address is the Bank contract address. This is the address which is emitting the event.
The "to"
address is called "to"
because that’s the name you’ve given to the second event argument…
… and this event’s emit statement references msg.sender
as the "to"
address i.e. the caller of the deposit function — the depositor …
The emitted event data is in the “args” property value (an object) of the event log, and is repeated …
[ {
"from": "0x7EF...B47", // Smart contract address
"topic": "0x451...f7f",
"event": "Log", // Event name
"args": { // Logged data, according to the defined event arguments
// Same data given twice (i) by index (ii) by argument name
"0": "1000", // Amount deposited (always in wei)
"1": "0x5B3...dC4", // Depositor's address
"amount": "1000", // Amount deposited (repeated)
"to": "0x5B3...dC4" // Depositor's address (repeated)
}
} ]
Hi @chen,
<address payable>.transfer(uint amount)
This is an predefined address member (or method) in Solidity. It automatically deducts the amount
argument’s value (always in wei) from the contract address balance, and transfers it to
<address payable>
i.e. to the address the method is called on, which in our code is msg.sender
…
msg.sender.transfer(amount);
So, in other words, the wei amount is transferred from the contract address to the external address which calls the withdraw function.
I hope that makes things clearer, but just let me know if you have any further questions about any of these points
In our withdraw function,
The amount is sent from msg.sender to msg.sender?
In other words, the amount is sent to itself?
Hi @chen,
This is explained in more detail in the reply I’ve just sent you in the Transfer Assignment discussion topic
To summarise…
The address calling the withdraw function (msg.sender
) is requesting that the Bank contract transfers/sends the ether amount
from the Bank contract address to their own external address (let’s say their wallet).
Hi @gaio,
No … it’s not the transaction ID … that appears separately at the top of the whole transaction receipt as the transaction hash
(below status
).
"topic"
is the hash of the event name and its parameter types. This is known as the event signature e.g.
// For the event ....
event Transfer(address indexed from, address indexed to, uint256 amount);
// "topic" is the Keccak-256 hash of ...
Transfer(address, address, uint256)
Yes …
When a transaction emits an event, there can actually be from 1 to 4 topics stored in an Ethereum log record on the blockchain:
The first topic is the hash of the event name and its parameter types (as descibed above)
The other 3 topics will only be generated for any of the emitted event’s parameters which are indexed
— one topic for each indexed
parameter — which is why the maximum number of parameters that can be indexed
in a single event is 3
It is the topics which enable event data (stored in log records on the blockchain) to be searched, or listened for, according to specified parameters. For example, if none of the parameters are indexed, I think you can only search or listen by event name (e.g. all Transfer events). However, with my Transfer event example with 2 indexed address parameters …
event Transfer(address indexed from, address indexed to, uint256 amount);
… you could also search and listen for only those transfers (i) from a specific sender’s address (ii) to a specific recipient’s address, or even (iii) only those with both a specific sender’s address and a specific recipient’s address; but as the amount parameter isn’t indexed, you couldn’t search or listen for transfers of a specific amount.
I’ve tested calling a function which emits an event with indexed parameters, in Remix, but still only one topic appears in the transaction receipt logs. This is probably because the transaction receipt generated in Remix is what has been selected from the encoded data for presentation in the frontend in a simplified, human-readable format. In the following article (which includes some nice diagrams) you can read more detail about “topics” and how the other non-indexed event data is stored on the Ethereum blockchain in log records, how the EVM generates these for emitted events, and also about the other cost and data-type/structure factors that need to be considered (as well as searchability) when deciding which parameters to declare as indexed
.
https://medium.com/mycrypto/understanding-event-logs-on-the-ethereum-blockchain-f4ae7ba50378
The following article is also quite a nice introduction and overview of the contents of transaction receipts in Remix, and how they are generated:
https://medium.com/remix-ide/the-anatomy-of-a-transaction-receipt-d935aacc9fcd
And finally — despite having been written 5 years ago — the following article provides some good background information about events and logs in general:
Happy reading
Two additional lines are needed:
function withdraw(uint256 amount) public returns (uint256) {
require(amount <= balance[msg.sender]);
msg.sender.transfer(amount);
balance[msg.sender] -= amount;
}
Hi @AU-Stephen ,
You have added both of the essential lines of code needed to solve the problem with the withdraw function
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 you’ve included it in your function header, you should also include a return statement in your function body. You should have got a yellow/orange compiler warning about this.
In fact, best practice is to modify the contract state for the reduction in the individual user’s balance…
balance[msg.sender] -= amount;
before actually transferring the funds out of the contract to the external address…
msg.sender.transfer(amount);
This is to prevent what is known as a re-entrancy attack from occuring after the transfer, but before the user’s individual balance (effectively, their entitlement) is reduced to reflect this operation. You’ll learn more about this type of attack, and how the above order of operations helps to prevent it, in the courses which follow this one.
Just let me know if you have any questions
Thanks for the feedback, I’m revisiting the code I wrote. Yes you are right there is a yellow compiler warning about this, I didn’t know what to make of the message as I was coding but it makes sense after your explanation.
That’s interesting about the re-entrancy attack. I’m excited to learn more about it in the following courses. I’ll keep in mind to adjust the user’s balance before completing any sort of transaction for any future excercises.
i’m extremely confused when it comes to troubleshooting my interface code, which doesn’t want to stop reverting…
as part of this troubleshooting, i’m trying to go back to the payable and transfer video lessons in order to make sure i have the basics down.
However, at lines 27 and 36 of Filip’s code (e.g. at time point 3:06), seem not to be compatible (the former requests withdrawal to an address==msg.sender, which the latter explicitly forbids); is it that “transfer” is a method of addresses (“is a member of the address object”) independent of the “transfer” function starting on line 34? OR am i missing something in interpreting the code?
Hi @B_S,
Which video are you referring to? Can you give me the precise lesson? I’m not sure if you’re referring to the video where we code an interface in Bank for our Government contract, or an earlier one going through the theory of payable functions.
In the meantime, I think maybe this will help…
msg.sender.transfer(amount);
This line of code isn’t calling our smart contract’s transfer() function. To do that we wouldn’t call it on an address, and we would need to call it with two arguments (a recipient address
as well as the uint
amount) e.g.
transfer(recipient, amount);
Instead, what we have in the withdraw function is an address member, which is what you are referring to here …
This particular address member is a special type of function. It is pre-defined within Solidity’s syntax, and is similar to a method in JavaScript. This is the syntax…
<address payable>.transfer(uint amount)
…meaning that transfer
must be called on a payable address with a single uint
argument. The uint
value will always be the amount of wei which is deducted from the smart contract’s ether balance, and transferred to the external address which transfer
is called on.
The caller of the withdraw function is msg.sender
, so because the transfer
method (address member) is called on msg.sender
using dot notation, that’s why it will transfer the withdrawal amount to the caller’s external address.
ah! sorry about that; i said payable and transfer, but i should’ve specified (and probably quoted) “transfer” video/lesson.
i think you’ve answered my question (“transfer” is akin to a solidity method), and your points mostly make sense, but i do have a couple remaining questions:
if i understand your second and third code snippets correctly, calling just “transfer(addy, amt)” from anywhere within the contract sends the contract’s own funds, i.e. it seems to serve as a withdraw function from the point of view of ‘recipient’; however, in the first snippet, --“msg.sender.transfer(amount)”-- is ‘transfer’ from msg.sender to the contract in which it’s called? if not, then from whom (to msg.sender) if not contract?
on another note: is an official list of object members kept somewhere? or is that cumbersome enough that it’s not catalogued? i haven’t googled it, but i’m more wondering how complex / evolving it is if you have an opinion on it; i worked in matlab for a while, and they have function help as a call to “help [function]”, which gives its usage, inputs/outputs the code itself, etc, but javascript seemed not to have it, and i wonder about solidity now too…
Hi @B_S,
Yes
No …
If this line of code were to call the transfer() function (not the transfer
method) from within another function in the Bank contract, neither the contract balance nor any external address balances would be affected. The contract balance only changes when ether either enters or leaves the contract, for example, when the deposit function or the withdraw function is called. The transfer() function performs an internal transfer (i.e. within the contract) between two individual users. All that needs to change is the share of the total contract balance each user is entitled to, which is done by what is effectively an internal accounting adjustment…
msg.sender
as the key) and reduced by the value of the amount
parameter;recipient
parameter as the key) and increased by the value of the amount
parameter.The recipient address would now be entitled to withdraw more ether from the contract, but it would still have to call the withdraw() function to transfer any of this additional ether out of the contract and add it to its external address balance
FROM the contract address balance (built in to the pre-defined functionality of the transfer
method)
TO the external address balance referenced by msg.sender
This line of code, which implements Solidity’s pre-defined transfer
method, is called when the withdraw() function is executing. It deducts the value of the amount
parameter (input into the withdraw function in wei) from the contract balance, and increases the external address balance of msg.sender
(whichever address has called the withdraw function) by the same amount. This functionality is pre-defined for us by the syntax…
<address payable>.transfer(uint amount)
<address payable>
// external address receiving wei transferred out of contract
uint amount
// wei amount deducted from contract balance / added to external address balance
on another note: is an official list of object members kept somewhere?
All of this information is in the Solidity Documentation
When you first start learning, the documentation can seem extremely dense. As the terms used for different elements of the syntax can often be different to what you are used to from other languages, it can be hard at first to know where to look and what to search for. Here are some helpful lists which I think is the sort of thing you’re looking for. They come under a general heading of Global Variables and Functions, which I don’t think is the most helpful, especially as some are what we would consider methods… but anyway, here you go…
https://docs.soliditylang.org/en/latest/units-and-global-variables.html#members-of-address-types
https://docs.soliditylang.org/en/latest/units-and-global-variables.html#contract-related
There is also a Cheat Sheet which contains pretty much the same information, but organised differently. Amongst other useful lists, it includes a Global Variables section — but which in reality is an assortment of syntax, including methods / address members …
https://docs.soliditylang.org/en/latest/cheatsheet.html#global-variables
the transfer() function (not the
transfer
method)
ah! got it!
FROM the contract address balance (built in to the pre-defined functionality of the
transfer
method)
TO the external address balance referenced bymsg.sender
totally makes sense: double boom!
to your last point: yeah, i followed up on those links in your other comments that i hadn’t seen, which were exactly for what i was looking.
again thanks for your thorough explanations; i’ll definitely be back for the 201 course at some point
My Solution:
when i use the below code, I get this message:
transact to Bank.withdraw errored: VM error: revert.
revert
The transaction has been reverted to the initial state.
Reason provided by the contract: “Balance not sufficient”.
Debug the transaction to get more information.
function withdraw (uint amount) public returns (uint) {
require(balance[msg.sender]>=amount, "Balance not sufficient");
payable(msg.sender).transfer(amount);
}
I think this is the purpose. We don’t want to allow withdraw any amount of ether we don’t have in our balance. Require function will throw error.
Hi @skawal22,
Am I right to assume that this solution is an earlier version of the final one you posted for the Transfer Assignment, which I’ve already given you feedback for?
function withdraw (uint amount) public returns (uint) { require(balance[msg.sender]>=amount, "Balance not sufficient"); payable(msg.sender).transfer(amount); balance[msg.sender] -= amount; return balance[msg.sender]; }
I get this message:
transact to Bank.withdraw errored: VM error: revert.
revert
The transaction has been reverted to the initial state.
Reason provided by the contract: “Balance not sufficient”.
Debug the transaction to get more information.
We don’t want to allow withdraw any amount of ether we don’t have in our balance. Require function will throw error.
Correct … If the address calling the withdraw function has an individual balance in the contract (recorded in the mapping) which is less than the amount requested for withdrawal, then the require() statement will fail and revert the transaction. We want this to happen in order to prevent a user withdrawing more than their share of the total contract balance (i.e. from effectively stealing other users’ funds). We know which specific require() statement has triggered revert, because the error message included as its 2nd argument is included within the error message displayed in the console.
Calling this function with a withdrawal amount, before having deposited any ether by calling the deposit() function with the same address, will always generate this error message, because the address doesn’t yet have any deposited ether to withdraw.
And as I’m sure you’ve already realised, for the require() statement to perform its check correctly, you need to add an additional line of code to reduce the user’s individual balance in the mapping by the same amount as the ether transferred out of the contract and added to the user’s external address balance. You included this in the other solution you posted (as shown above).
Just let me know if you still have any questions about this.
Hi @jon_m, I mistakenly posted this one here. Yes you’re right, its an earlier version of the final one for the Transfer assignment.
Thanks,
Sk