A payment channel is a process where participants can make multiple transfers without sending a transaction to the Ethereum blockchain. Once the final transaction occurs between the participants the recipient can claim their funds by submitting one final transaction to the smart contract on the blockchain. This allows both parties to avoid fees involved with multiple transactions.
Before you begin make sure you have read part 1: how to sign & verify an Ethereum message off chain. This information is needed to understand the concepts of off chain transactions. Below we will discuss part 2: how to create a payment channel.
Payment Channel Process
The payment channel process is very simple:
- A sender creates a smart contract and puts funds in escrow in the contract
- The recipient is guaranteed to receive funds because the smart contract escrows the Ether and honors a valid signed message for withdrawal.
- The sender and receiver decide how long to keep the payment channel open. The smart contract contains a timeout so the sender is guaranteed to eventually recover funds even if the recipient refuses to close the channel.
Examples of different types of payment channels:
- Short lived channels – paying for coffee, an evening at a bar or restaurant, etc.
- Longer lived channels – paying an employee, paying a contractor to build a house, etc.
The example below illustrates Alice buying drinks throughout the day and Bob claiming funds by sending one transaction to the blockchain for processing.
Payment Channel Solidity Code
Below is a payment channel Solidity smart contract that contains the basic functions to get started. Read the code comments to get a better understanding of how the contract works.
This code is a sample for learning and has not been audited. Use at your own risk.
pragma solidity >=0.4.24 <0.6.0;
contract PaymentChannel {
address payable public sender; // the account sending payments
address payable public recipient; // the account receiving the payments
uint256 public expiration; // timeout in case the recipient never closes the channel
// in the constructor pass in the recipient address and the duration of the payment channel
constructor (address payable _recipient, uint256 duration) public payable {
sender = msg.sender;
recipient = _recipient;
expiration = now + duration;
}
// check that the signature is from the payment sender
function isValidSignature(uint256 amount, bytes memory signature) internal view returns (bool){
bytes32 message = prefixed(keccak256(abi.encodePacked(this, amount)));
return recoverSigner(message, signature) == sender;
}
// the recipient can close the channel at any time by presenting a
// signed amount from the sender. the recipient will be sent that amount,
// and the remainder will go back to the sender
function close(uint256 amount, bytes memory signature) public {
require(msg.sender == recipient);
require(isValidSignature(amount, signature));
recipient.transfer(amount);
selfdestruct(sender);
}
// the sender can extend the expiration of the contract at any time
function extend(uint256 newExpiration) public {
require(msg.sender == sender);
require(newExpiration > expiration);
expiration = newExpiration;
}
// if the timeout is reached without the recipient closing the channel,
// then the Ether is released back to the sender.
function claimTimeout() public {
require(now >= expiration);
selfdestruct(sender);
}
}
Try it in Remix
Signed off chain messages
The Solidity smart contract above combined with signing an Ethereum message off chain will allow you to create a payment channel in your dapp. This is very simple and not as complex as it sounds.
This code is for learning and entertainment purposes only. The code has not been audited and use at your own risk. Remember smart contracts are experimental and could contain bugs.
Click here for more information about how to use the Ethereum test network and how to obtain test ETH.
1 thought on “How to create a payment channel on Ethereum”