0

I am confused with the following sentence in the Solidity documentation:

During the execution of the fallback function, the contract can only rely on the “gas stipend” it is passed (2300 gas) being available to it at that time.

My post is a continuation of this one. This post has an answer which says

The 'stipend' applies to internal sends from one smart contract to another. Because send has no way to specify the gas amount, (whereas call does), Solidity imposes a maximum amount of gas (i.e. 2300).

Because the OP's transaction was not an internal contract-to-contract send the 2300 stipend did not apply and the transaction went through.

So, what does "internal" mean? Suppose I (as an EOA) sign a transaction TX1 and broadcast it. This TX1 executes a function foo within a contract A which transfers, say ethers, to another contract B.

contract contractA
{
  //...
  function foo() external
  {
     //...
     contractB.transfer(1 ether);
  }
  //...
} 

Is contractB.transfer(1 ether); internal call? My guess it is external call because it calls on another contract.

What is the meaning of stipend if transactions always have gas limit set by sender? When, in what cases, does this damn 'stipend' apply?

Could someone please provide a piece of code or describe a scenario when 2300 stipend is not enough, and when we set gasLimit which is enough to execute transfer function?

2

What is the meaning of stipend if transactions are always have gas limit set by sender?

Not really. When EOA calls contract A, the gas limit is set in the transaction, this is true. However, when contract A calls contract B, contract A may set limit on how much gas the contract B is allowed to spend. This limit may be lower than the remaining gas contract A has by itself at the moment. In such case, even if call to contract B will run out of gas and thus fail, contract A will still have some gas to handle the situation.

When, in what cases, does this damn 'stipend' apply?

There are several ways how one contract may call another contract, and these ways behave differently:

  1. One may just call other contract's method as a function. In this case called contract will be allowed to spend all the gas remaining in the transaction.
  2. One may use functions call, delegatecall, or staticall that allow explicitly specifying how much gas to called contract will be allowed to spend (though by default these functions allow spending all the gas remaining).
  3. One may use functions transfer of send that allow called contract to spend at most 2300 gas, and this hardcoded value cannot be changed.

Could someone please provide a piece of code or describe a scenario when 2300 stipend is not enough?

Sure. Lets assume the following implementation of contract B:

contractB {
  uint private etherReceived = 0;

  function () external payable {
    etherReceived += msg.value;
  }
}

The contract tries to count how much Ether it ever received via fallback function. This implementation has a problem, as it updates storage variable inside fallback function and such update costs 5000 gas or more. Thus, transfer to such contract from another contract will fail.

Could someone please provide a piece of code or describe a scenario when ... we set gasLimit which is enough to execute transfer function?

Function transfer has hardcoded gas limit of 2300 which cannot be changed. However here is an example of a contract whose fallback function fits into this harsh limit and yet does something useful:

contractB {
  event Deposit (address from, uint value);

  function () external payable {
    emit Deposit (msg.sender, msg.value);
  }
}
  • You're missing payable from your first code example. – Lauri Peltonen Nov 15 '19 at 10:05
  • Yes, thank you. I missed it in both examples. – Mikhail Vladimirov Nov 15 '19 at 10:06
  • Thanks for reply. I don't understand why the code with ether counting has a problem? Doesn't a sender provide enough gas (at least 5000) to perform this function call? – fade2black Nov 15 '19 at 10:10
  • I guess the problem is that I don't understand the logic behind 2300 gas. It is not well documented and causes confusion. As far as I know WE ALWAYS must set a gas limit. I guess I need to ask it in a different post. – fade2black Nov 15 '19 at 10:15
  • This 2300 gas stipend was introduced to address recursive attacks. Unfortunately, the solution was not well well designed and caused more problems than solved. That's why it is not recommended to use it anymore: diligence.consensys.net/blog/2019/09/… – Mikhail Vladimirov Nov 15 '19 at 11:32
1

The stipend is 2300, not 23000.

A scenario where this stipend is not enough:

Changing a state-variable from zero to non-zero.

  • Thanks, was a typo. Fixed (23000 => 2300). Do you know what internal/external calls are? – fade2black Nov 15 '19 at 8:45
  • @fade2black: A wild guess: internal calls are when you call functions in the same contract, and external calls are when you call functions in other contracts. – goodvibration Nov 15 '19 at 9:14
  • I think the same. But it says "The 'stipend' applies to internal sends from one smart contract to another". INTERNAL sends from ONE smart contract to ANOTHER. Opposite what you say. – fade2black Nov 15 '19 at 9:19
  • @fade2black: Oh, sorry. In this context, your description is accurate (what I don't understand is why you are asking a question which you already know the answer to). – goodvibration Nov 15 '19 at 9:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.