# Sending and Receiving Ether — Blockchain & Smart Contracts (Solidity)

Source: https://www.geekswithgeeks.com/en/solidity/i-ether

> Receive ether with receive and fallback, send it safely and use pull payments.

## Moving ether safely

A contract receives plain ether through a **`receive() external payable`** function, called when calldata is empty, and a **`fallback()`** function, called when no other function matches (it must be `payable` to accept ether). Without either, plain transfers to the contract revert. To **send** ether, use the low-level **`call`**: `(bool ok, ) = recipient.call{value: amount}("");` and **check `ok`**. The older `transfer` and `send` forward only 2,300 gas, which breaks recipients that are smart contract wallets or need more gas after gas cost changes, so they are no longer recommended. Because `call` forwards gas and hands control to the recipient, it creates **reentrancy** risk (section 6), so update state **before** sending. Prefer the **pull payment** pattern: instead of pushing ether to many recipients in a loop (where one failing recipient can block everyone), record what each is owed and let them **withdraw**. Note that a contract can receive ether without any function running (from validator rewards or a forced send), so never rely on `address(this).balance` equalling the sum of your internal accounting.

## Push versus pull payments

Pushing to many recipients can fail as a whole; pulling lets each withdraw independently.

![Left: one contract with arrows pushing coins to many people, one arrow blocked. Right: many people each pulling from their own drawer in a contract.](assets/figures/solidity/section-5-map.svg) — Figure 5.1 — Pull payments isolate failures.

## A split-payment contract using pull payments

Record balances, let recipients withdraw, check the call result.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract RevenueSplitter {
    address[] public payees;
    mapping(address => uint256) public sharesBps;     // basis points, total 10,000
    mapping(address => uint256) public owed;

    event Received(address indexed from, uint256 amount);
    event Withdrawn(address indexed payee, uint256 amount);

    error NothingOwed();
    error TransferFailed();

    constructor(address[] memory payees_, uint256[] memory shares_) {
        require(payees_.length == shares_.length && payees_.length > 0, "bad config");
        uint256 total;
        for (uint256 i = 0; i < payees_.length; i++) {
            payees.push(payees_[i]);
            sharesBps[payees_[i]] = shares_[i];
            total += shares_[i];
        }
        require(total == 10_000, "shares must total 100%");
    }

    // senders must forward enough gas (use call, not transfer): this loop needs more than 2,300 gas
    receive() external payable {
        uint256 distributed;
        for (uint256 i = 0; i < payees.length; i++) {
            uint256 part = (msg.value * sharesBps[payees[i]]) / 10_000;
            owed[payees[i]] += part;
            distributed += part;
        }
        owed[payees[0]] += msg.value - distributed;    // rounding dust to the first payee
        emit Received(msg.sender, msg.value);
    }

    function withdraw() external {
        uint256 amount = owed[msg.sender];
        if (amount == 0) revert NothingOwed();
        owed[msg.sender] = 0;                          // effect before interaction
        (bool ok, ) = msg.sender.call{value: amount}("");
        if (!ok) revert TransferFailed();
        emit Withdrawn(msg.sender, amount);
    }
}
```

## Bound your loops

A loop over an array that users can grow without limit may eventually exceed the block gas limit, making the function permanently unusable. Keep loops bounded (like a fixed payee list) or process work in batches.

**Quiz:** Why are transfer and send no longer recommended for sending ether?

- [x] They forward only 2,300 gas, which can make transfers to contract wallets fail
- [ ] They are too expensive
- [ ] They are not available in Solidity 0.8
- [ ] They do not move ether

*Answer:* They forward only 2,300 gas, which can make transfers to contract wallets fail. The fixed gas stipend breaks recipients that need more gas.
