Lesson 15 of 25
Payable Functions
Accept ETH payments, handle receive() and fallback() functions.
IntermediateThe 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 beexternal 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;
}
}