[Ethereum] Internal contract-to-contract call

ethergasgas-limitgas-pricesolidity

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?

Best Answer

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);
  }
}
Related Topic