Learning Objectives – after this chapter you will be able to:
- Write payable functions and read
msg.value. - Use
address payableand check a contract’s balance. - Compare
transfer,sendandcallfor sending Ether. - Send Ether safely using checks-effects-interactions and the withdrawal pattern.
Solidity Payable Function
- A payable function is a function that can receive Ether together with the call. The amount sent is available in
msg.value(in wei) and is added to the contract’s balance automatically. - A function without the
payablekeyword rejects any Ether sent to it – the transaction reverts. - A payable function can also be called with zero Ether; use
require(msg.value > 0)(or an exact amount) if a payment is mandatory. - The contract’s current balance is
address(this).balance.
All about Payable
- payable functions –
function deposit() external payable { }– receive Ether with a call. - receive / payable fallback – receive plain Ether that is sent without calling a named function (Chapter 23). The old unnamed
function () payablesyntax was replaced byreceive()andfallback()in Solidity 0.6.0. - payable constructor – lets Ether be sent at deployment (Chapter 17).
- address payable – the address type that can receive Ether through
transfer/send. Convert withpayable(addr), e.g.payable(msg.sender).
Methods for Sending Ether
| Method | Gas forwarded | On failure | Recommendation |
|---|---|---|---|
to.transfer(amount) | Fixed 2300 | Reverts automatically | Simple, but can fail if the recipient is a contract needing more than 2300 gas. |
to.send(amount) | Fixed 2300 | Returns false (no revert) | Must check the result, e.g. require(to.send(x)). Rarely used. |
to.call{value: amount}("") | All remaining gas (adjustable) | Returns (bool success, bytes data) | Recommended today – check success and protect against reentrancy. |
The old syntax
address.call.value(amount)() was removed in Solidity 0.7.0. Use address.call{value: amount}(""), and set gas explicitly only when needed with {value: amount, gas: g}.Sending Ether Safely
- Checks – Effects – Interactions: first check conditions, then update your contract’s state (e.g. set the balance to 0), and only then send Ether. This prevents reentrancy, where the recipient calls back into your function before the state is updated.
- Withdrawal (pull) pattern: instead of pushing payments to many users in one loop, record what each user is owed and let each user withdraw it. One failing recipient then cannot block everyone else.
- Always check the result of
sendandcall. - Amounts are in wei; write
1 etheror0.5 etherfor readability.
Example : Deposits and Safe Withdrawals
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract EtherWallet {
mapping(address => uint) public balances;
event Deposit(address indexed user, uint amount);
event Withdrawal(address indexed user, uint amount);
// payable: accepts Ether, amount in msg.value
function deposit() external payable {
require(msg.value > 0, "Send some Ether");
balances[msg.sender] += msg.value;
emit Deposit(msg.sender, msg.value);
}
// withdrawal (pull) pattern with checks-effects-interactions
function withdraw(uint amount) external {
require(balances[msg.sender] >= amount, "Insufficient balance"); // checks
balances[msg.sender] -= amount; // effects
(bool ok, ) = payable(msg.sender).call{value: amount}(""); // interaction
require(ok, "Transfer failed");
emit Withdrawal(msg.sender, amount);
}
function contractBalance() external view returns (uint) {
return address(this).balance;
}
// plain Ether sent to the contract is credited to the sender
receive() external payable {
balances[msg.sender] += msg.value;
emit Deposit(msg.sender, msg.value);
}
}
Key Takeaways
- Only payable functions (and receive/payable fallback) accept Ether; the amount is
msg.value. - Prefer
call{value: x}("")and always check its result. - Update state before sending Ether, and let users withdraw instead of pushing payments.
Download | Print E-Notes
The PDF E-Notes are the earlier printable version of this chapter. The notes on this page are the latest, revised version.
Question / Answer (15 questions)
Answer : A function marked payable can receive Ether with the call. The amount sent is available in msg.value (in wei) and is added to the contract’s balance.
Answer : The transaction reverts, so the Ether is not accepted.
Answer : Yes. To require payment, add a check such as
require(msg.value > 0) or require(msg.value == price).Answer : With
address(this).balance, which returns the balance in wei.Answer : address payable is an address type that has the transfer and send members for receiving Ether. A plain address is converted with
payable(addr).Answer :
addr.transfer(amount), addr.send(amount) and addr.call{value: amount}("").Answer : Both forward a fixed 2300 gas. transfer reverts automatically if sending fails; send returns false instead, so its result must be checked.
Answer : It forwards enough gas for recipients that are contracts with more complex receive logic and returns a success flag. The developer must check the flag and guard against reentrancy.
Answer : Since Solidity 0.7.0 the syntax is
address.call{value: amount}(""); gas can be set with {value: amount, gas: g}.Answer : A function first checks all conditions, then updates the contract’s own state, and only at the end interacts with other addresses (e.g. sends Ether). This prevents reentrancy attacks.
Answer : An attack in which the recipient of an external call calls back into the vulnerable function before its state is updated, for example withdrawing the same balance repeatedly.
Answer : Instead of sending Ether to many users in one transaction, the contract records how much each user is owed and each user calls withdraw() to collect it. One failing recipient cannot block the others.
Answer : They do not revert on failure; they return false. Ignoring the result could make the contract believe a payment succeeded when it did not.
Answer : receive() external payable, or a fallback() marked payable.
Answer : In wei. Amounts can be written with units such as
1 ether, 0.01 ether or 1 gwei.MCQ Test : Check Your Understanding (5 questions)
Select an option and press Check Answer, or answer all questions and press Submit Test to see your score. Each answer comes with an explanation.
Bibliography/References
The notes, questions and MCQs on this page are original explanations written for this course. The works listed below were consulted and are cited for attribution and further reading. Product names, logos and trademarks belong to their respective owners. Short quotations, where used, are marked and attributed.
- Solidity Team. (n.d.). Types (value types, reference types, mappings, operators, conversions). Solidity Documentation. https://docs.soliditylang.org/en/latest/types.html
- Solidity Team. (n.d.). Units and Globally Available Variables. Solidity Documentation. https://docs.soliditylang.org/en/latest/units-and-global-variables.html
- Solidity Team. (n.d.). Security Considerations. Solidity Documentation. https://docs.soliditylang.org/en/latest/security-considerations.html
- ethereum.org. (n.d.). Smart contract security. Ethereum Developer Documentation. https://ethereum.org/en/developers/docs/smart-contracts/security/
- Showwcase. (n.d.). Payable functions in Solidity. https://www.showwcase.com/show/33658/payable-functions-in-solidity
- Modi, R. (2018). Solidity Programming Essentials: A beginner’s guide to build smart contracts for Ethereum and blockchain. Packt Publishing. ISBN 978-1-78883-138-3.