Message Calls: Learn how to use .call to send ether

Message Calls

  • Send value and calldata to contracts
  • The first message call is the beginning of the transaction (EOA -> contract)
  • Each subsequent message call is part of the same transaction (contract -> contract)
  • The transaction and any state changes only complete when the initial function call finishes execution

💡 Message calls are actions taken to communicate with a smart contract.

💡 EOA can communicate with a smart contract or a smart contract can communicate with another smart contract.

Message Call Breakdown

  • As we saw message calls can contain gasvalue and calldata
  • These message values become available as globals in solidity:
    • msg.sender – who made the last message call
    • msg.value – amount in wei sent
    • msg.data – calldata
    • msg.sig – the function identifier

How Do EOAs and Contracts Call Other Contracts?

  • They use the address of the contract they want to communicate with
  • This is a data type in solidity that is 20 bytes long
  • The msg.sender from the previous slide is an address

What does that look like?

contract X {
  address deployer;
  address otherContract;

  constructor(address _otherContract) {
    deployer = msg.sender;
    otherContract = _otherContract;
  }
}

Can any method call receive ether?

Only payable methods can:

contract X {
  receive() external payable {
    // no calldata necessary here
    // just send a value on the message call
  }

  function pay() external payable {
    // in this case, we target pay with a value
  }
}

What does sending value look like?

The .call syntax is .call{ gas, value }(calldata)

contract X {
  address otherContract;

  constructor(address _otherContract) payable {
    otherContract = _otherContract;
    _otherContract.call{ value: msg.value }("");
  }
}

Handle the success

The solidity compiler will warn you if you don’t handle success

contract X {
  address otherContract;

  constructor(address _otherContract) payable {
    otherContract = _otherContract;
    (bool success, ) = _otherContract.call{ value: msg.value }("");
    require(success);
  }
}

Hands-on

learn-solidity-presentations\2-sending-ether\examples\0-send-ether\src\Example.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

import "forge-std/console.sol";

contract A {
    address b;

    constructor(address _b) payable {
        b = _b;
        console.log(msg.value);
        console.log(address(this).balance);
    }

    function payHalf() external {
        uint256 balance = address(this).balance;
        (bool success,) = b.call{value: balance / 2}("");
        require(success);
    }
}

contract B {
    receive() external payable {}
}

learn-solidity-presentations\2-sending-ether\examples\0-send-ether\test\Example.t.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

import "forge-std/Test.sol";
import "../src/Example.sol";

contract ExampleTest is Test {
    A public a;
    B public b;

    function setUp() public {
        b = new B();
        a = new A{ value: 1 ether }(address(b));
    }

    function testExample() public {
        assertEq(address(a).balance, 1 ether);
        assertEq(address(b).balance, 0 ether);
        a.payHalf();
        assertEq(address(a).balance, 0.5 ether);
        assertEq(address(b).balance, 0.5 ether);
        a.payHalf();
        assertEq(address(a).balance, 0.25 ether);
        assertEq(address(b).balance, 0.75 ether);
        a.payHalf();
        assertEq(address(a).balance, 0.125 ether);
        assertEq(address(b).balance, 0.875 ether);
    }
}

edo@DESKTOP-4POSOVK:/mnt/e/Programming/Solidity/learn-solidity-presentations/2-sending-ether/examples/0-send-ether$ forge test -vv
[⠰] Compiling...
No files changed, compilation skipped

Ran 1 test for test/Example.t.sol:ExampleTest
[PASS] testExample() (gas: 36663)
Logs:
  1000000000000000000
  1000000000000000000

Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 558.50µs (87.50µs CPU time)

Ran 1 test suite in 48.58ms (558.50µs CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)

Learn Solidity. Alchemy University.
Accessed November 25, 2024
https://university.alchemy.com/overview/solidity