🏠 Home
Beginner
01 — Introduction to Solidity 02 — Setting Up Your Environment 03 — Your First Smart Contract 04 — Data Types & Variables 05 — Functions & Visibility 06 — Control Flow 07 — Arrays & Mappings 08 — Structs & Enums
Intermediate
09 — Events & Logging 10 — Modifiers 11 — Inheritance 12 — Interfaces & Abstract Contracts 13 — Error Handling 14 — Ether & Wei 15 — Payable Functions 16 — msg.sender & msg.value 17 — Storage vs Memory vs Stack
Advanced
18 — Gas Optimization 19 — ERC-20 Tokens 20 — ERC-721 NFT Standard 21 — Contract Security 22 — Reentrancy Attacks 23 — Oracles & Chainlink 24 — Upgradeable Contracts 25 — Deploying to Mainnet
SolidityMaster / Lesson 15
Lesson 15 of 25

Payable Functions

Accept ETH payments, handle receive() and fallback() functions.

Intermediate

The payable Keyword

A function must be declared payable to accept Ether. Sending ETH to a non-payable function will cause the transaction to revert.
Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract PiggyBank {
    address public owner;
    mapping(address => uint256) public deposits;

    event Deposited(address indexed user, uint256 amount);
    event Withdrawn(address indexed owner, uint256 amount);

    constructor() { owner = msg.sender; }

    // payable — accepts ETH
    function deposit() public payable {
        require(msg.value > 0, "Send some ETH");
        deposits[msg.sender] += msg.value;
        emit Deposited(msg.sender, msg.value);
    }

    function withdraw() public {
        require(msg.sender == owner, "Not owner");
        uint256 amount = address(this).balance;
        (bool ok, ) = owner.call{value: amount}("");
        require(ok, "Transfer failed");
        emit Withdrawn(owner, amount);
    }
}

receive() and fallback()

  • receive() — called when ETH is sent with no calldata (plain ETH transfer). Must be external payable.
  • fallback() — called when no matching function signature is found, or when ETH is sent with calldata. Can be payable.
Solidity
contract FallbackDemo {
    event Received(address sender, uint256 amount);
    event FallbackCalled(address sender, bytes data);

    // Called when ETH is sent with no data
    receive() external payable {
        emit Received(msg.sender, msg.value);
    }

    // Called when no function matches, or as backup
    fallback() external payable {
        emit FallbackCalled(msg.sender, msg.data);
    }

    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }
}

Payable Constructor

Constructors can also be payable — this allows sending ETH at deployment time.
Solidity
contract FundedAtDeploy {
    address public owner;

    // Accepts ETH at deployment
    constructor() payable {
        owner = msg.sender;
        require(msg.value >= 0.1 ether, "Need at least 0.1 ETH");
    }

    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }
}