The payable keyword in Solidity and how to send and receive Ether

In this tutorial, we are going to learn about the payable keyword in Solidity and how to use it to send and receive Ether in your smart contract.

In this tutorial, we are going to learn about the payable keyword in Solidity and how to use it to send and receive Ether in your smart contract.

Here are a few examples of what you can do with the payable keyword:

// SPDX-License-Identifier: MIT

pragma solidity 0.8.7;

contract PayableKeyword {

    address[] public donators;

    // Marking the construcor as payable allows to initialise your contract with some Ether
    constructor() payable {
        donators = [];
    }

    // A function that is payable can be called allong with some Ether
    // That Ether will then be in the smart contract
    // A non-payable function will throw a function if called along with some Ether
    function donate() public payable {
        donators.push(msg.sender);
        
        // The amount of Eth sent is stored in msg.value
        amountDonated += msg.value;
    }

    // This function allows you to withdraw the Ether that the contract has
    function withdrawAll() public {
        // get the amount of Ether the contract has
        uint256 amount = address(this).balance;

        // Send all the Ether to a payable address
        // If it's an address and not a payable address, it will fail
        (bool success, ) = payable(msg.sender).call{value: amount}("");
        require(success, "Failed to send Ether");
    }
}

How to receive Ether in your smart contract

To allow users to send Ether to your contract along with calling a function, that function needs to be marked as payable.

Here is an example:

function deposit() external payable {
    deposits += msg.value;
}

The amount of Ether that was sent along with calling that payable function will be stored in msg.value. That amount will be in Wei, meaning it is an integer that has 18 decimals of precision.

One of the use cases of msg.value is to know if the user has sent enough Ether to pay for something.

If the function is not payable and the user tries to call it and send some Ether along with it, it will revert and throw an error.

Same for your constructor, if you want to fund your contract when you deploy it, the constructor needs to use the payable keyword.

Here is an example:

constructor() payable {
    initialBalance = msg.value;
}

How to get the Ether balance of your smart contract

Once you allowed users to send Ether to your smart contract, you might need to know, at any point in time, what's the amount of Ether that is stored in the smart contract.

To do that, we get the address of the smart contract using address(this) and then just read the .balance property:

address(this).balance;

That works with all variables of type address so if you want to read the balance of an address, just read the balance property of that variable.

How to send Ether from your smart contract

We've covered that part more in details here:

https://www.0xdev.co/how-to-send-a-transaction-in-solidity-from-a-smart-contract/

But to summarise, if you want to send Ether from your smart contract, you need to convert the address of the smart contract into a payable address.

Payable addresses are a type of their own and they are different than the address type. The difference is that payable addresses can send and receive Ether and you can check their balance and non-payable addresses can't.

Here is an example:

function withdrawAll() public {
    uint256 = address(this).balance;
    (bool success, ) = payable(msg.sender).call{value: amount}("");
}

And that's it 🎉

Thank you for reading this article