Solidity Payable Functions
A payable function is a function marked payable that can receive ether along with a call. Ether is the built-in money of the network these contracts run on.
The payable keyword accepts ether
The word payable in the header lets ether arrive with the call. Inside the function, msg.value holds how much arrived.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
contract SavingsBox {
uint256 public totalSaved;
function deposit() public payable {
totalSaved += msg.value;
}
}
A deposit credits the sender in a mapping
A savings box credits each saver in a mapping keyed by address. The mapping grows by exactly the ether each call carried.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
contract SavingsBox {
mapping(address => uint256) public balanceOf;
function deposit() public payable {
balanceOf[msg.sender] += msg.value;
}
}
A function without payable refuses ether
setGoal takes no ether, so it stays plain. A call that tries to send ether to it fails, and nothing changes.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
contract SavingsBox {
mapping(address => uint256) public balanceOf;
uint256 public goal;
function deposit() public payable {
balanceOf[msg.sender] += msg.value;
}
function setGoal(uint256 newGoal) public {
goal = newGoal;
}
}
Example
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
contract SavingsBox {
mapping(address => uint256) public balanceOf;
uint256 public goal;
function deposit() public payable {
balanceOf[msg.sender] += msg.value;
}
function setGoal(uint256 newGoal) public {
goal = newGoal;
}
}
Key points
- Payable: add the word payable to a function header so callers can send ether with the call.
- msg.value: the amount of ether sent with the current call, counted in wei, the smallest unit of ether.
- Credit: a deposit function can add msg.value to the sender's entry in a mapping.
- Contract balance: ether sent to a payable function stays in the contract, and address(this).balance reads how much the contract holds.
- No payable, no ether: a call that sends ether to a function without payable fails.
In this example, the SavingsBox contract keeps a balanceOf mapping and a goal. The deposit function is payable, so it adds msg.value to the caller's mapping entry and the ether stays in the contract. The setGoal function is not payable, so it stores a number and refuses any ether sent to it.
Note
payable changes what a call may carry, not who may call the function.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Remix IDE
Exercise
A caller sends 2 ether along with a call to a function. What must be true for the call to succeed?