External Contracts & Calls Discussion

Welcome to the discussion thread about this lecture section. Here you can feel free to discuss the topic at hand and ask questions.

2 Likes

First! Sorry, old habits lol.

So I was reading some of the Solidity recommendations on smart contract best practices from the Consensys github, and they recommend avoiding .send() and .transfer() because the 2300 gas stipend is only effective if gas costs are assumed to be constant. They continue:

Recently EIP 1283 (backed out of the Constantinople hard fork at the last minute) and EIP 1884 (expected to arrive in the Istanbul hard fork) have shown this assumption to be invalid.

To avoid things breaking when gas costs change in the future, it’s best to use .call.value(amount)("") instead.

Here’s the link to the page where I was reading it. What is your opinion on the matter?

As someone still learning Solidity, would it be better to continue using .transfer() or .send() until these gas cost changes are confirmed? Or should I try to become more familiar with .call.value(amount)("") since it seems inevitable this will be more applicable in production?

9 Likes

Hey, thanks for sharing that. Interesting changes for sure. But I would think that they would adjust the 2300 gas stipend to still be safe in such a hard fork, but perhaps not.

It could be dangerous for some contracts out there. But, you will still be safe using send() or transfer() if you design your contract after the principle of checks-effects-interaction (which we teach). If you do that, even if the 2300 gas stipend would suddenly be enough for another call, you would be safe from re-entrency. But it’s definitely something worth keeping track of :slight_smile:

6 Likes

Agreed, very interesting. Always something new in this space. I’m very excited to see what January brings.:joy:

1 Like

Hi, about push & pull. The other advantage I see on pull is giving flexibility to the user, so if for example its a bet game… he could decide to withdraw when he gets to 1 eth… or withdraw a part and let the other. If its a micropayments systems between 2 smartcontracs this will avoid all the micropayment fees, and will only withdraw in significant chunks of the total amount

1 Like

Re-entry attacks

Even if you set the user balance to zero before sending funds in the withdrawAll function, if an attacker can make many simultaneous calls in parallel would it still be possible to multi-withdraw before the state balance change is seen by parallel calls? Multi-threading can be nasty. This is why locks and atomicity are so important in traditional databases. Is this a concern with smart contracts?

1 Like

filip, is it possible for someone to make a contract that completely ignores this effects code and just transfer the funds and restart the function?

Ignores this code in the contract?
balances[msg.sender]= 0;

It won’t because at the end all your transaction will be validate in one block.
So let’s say tx 1 to 10 are broadcasted.
Miner 1 takes 1/2/3
Miner 2 takes 4-10
If miner 1 validate the block he will execute your functions and deduces 1 / 2 and 3 if their is no funds for the third transaction it ll be reverted.
Regarding tx 4-10 they will be validated at the next block.

https://github.com/ethereum/wiki/wiki/What-is-Ethereum
Ethereum can be viewed as a single computer that the whole world can use. It notionally has only a single processor (no multi-threading or parallel execution),
Even if you mutli-thread you can still implement locks to only allow one thread at a time to modify a variable

1 Like

Hi @andersbraath1
I m not sure to understand your function , but basically a contract A can’t modify the content of contract B

2 Likes

I found this code on ConsenSys.net

function withdraw() external {
1         uint256 amount = balanceOf[msg.sender];
2         balanceOf[msg.sender] = 0;
3         (bool success, ) = msg.sender.call.value(amount)("");
4         require(success, "Transfer failed.");
 }

Can you explain LINE 3 please?

Hi @tung
Sure, payable function doesn’t return any value, they are only sending back a transaction receipt.
So this function is checking if the ETH transfert succeded, otherwhise it will revert the transaction and the balance of the sender will not be set to zero

3 Likes

Hi gabba, thanks for your reply. However I still don’t understand (bool success, ). What kind of variable is this and what does it represent? Thank you

they are just defining a boolean on the fly, the result of this function will be true or false.
The name of the variable is success

Hi, how can I check the value received by a functionY of contractB when it is called by a functionX of contractA using contractB.call.value(somevalue)(“functionY()”)? Msg.value does not work here because that gives the value that for example a user sends when calling contractA in the very beginning (and not the value specified by call.value()()). Is there something like “call.value” which gives the value provided by address.call.value(somevalue)(“function()”) that works similarly to msg.value? If not, what is the best workaround?

Hey @xbtcollector

Please provide your code and an example of your question by using existing functions in your repo.
I will be glad to help.

Happy learning,
Dani

1 Like

The call in Contract A:

Called function in Contract B:

Do you have an example of what you want to do?

As mentioned in the question, I would like to know how I can get the value that is passed when contractA calls contractB, ie, call.value(queryPrice). In other words, how the called function “createQuery()” can get this value? Of course, I can pass this as an extra argument, but this seems a bit dumb and possibly opens up vulnerabilities.

Hi Filip, is it possible to see some small use cases /examples to further explain when to use send / transfer /.call.value functions?

@filip if transfer(x) has a require built in so that it will revert the Tx when it fails, what happens when you use send(x) and the Tx fails? the gas is still spent even though the Tx fails?

1 Like