James Bachini

Creating A Solidity Escrow Smart Contract

Escrow Contract

In this tutorial, we will create an Escrow contract using Solidity and deploy it to an Ethereum testnet. An Escrow contract is a financial agreement where a third party (the arbitrator) holds and regulates payment of the funds required for two parties involved in a given transaction. It helps make transactions more secure as it holds the money until all the terms of an agreement are met.

Escrow Solidity Example

Step 1: Setting Up the Environment

For simplicity, we’ll use Remix IDE, a browser based IDE for Solidity.

The full code can be found here: https://github.com/jamesbachini/Solidity-Snippets/blob/main/contracts/escrow.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract Escrow {

    struct Agreement {
        address bob;
        address alice;
        address arbitrator;
        uint amount;
        bool bobIn;
        bool aliceIn;

    Agreement[] public agreements;

    function newAgreement(address _bob, address _alice, uint _amount) external returns (uint) {
        require(_bob != _alice, "same buyer and seller");
        return agreements.length - 1;

    function deposit(uint _id) external payable {
        if (msg.sender == agreements[_id].bob && msg.value == agreements[_id].amount) {
            agreements[_id].bobIn = true;
        else if (msg.sender == agreements[_id].alice && msg.value == agreements[_id].amount) {
            agreements[_id].aliceIn = true;

    function refund(uint _id) external {
        if (msg.sender == agreements[_id].bob && agreements[_id].bobIn == true) {
            agreements[_id].bobIn = false;
        if (msg.sender == agreements[_id].alice && agreements[_id].aliceIn == true) {
            agreements[_id].aliceIn = false;

    function complete(uint _id, address _winner) external {
        require(msg.sender == agreements[_id].arbitrator, "Only arbitrator can complete");
        require(agreements[_id].bobIn == true, "Bob has not paid");
        require(agreements[_id].aliceIn == true, "Alice has not paid");
        if (agreements[_id].bob == _winner) {
            agreements[_id].bobIn = false;
            agreements[_id].aliceIn = false;
            payable(agreements[_id].bob).transfer(agreements[_id].amount * 2);
        else if (agreements[_id].alice == _winner) {
            agreements[_id].bobIn = false;
            agreements[_id].aliceIn = false;
            payable(agreements[_id].alice).transfer(agreements[_id].amount * 2);

Escrow Solidity Code Walkthrough

Creating the Agreement Struct

This structure holds the details of each agreement.

struct Agreement { address bob; address alice; address arbitrator; uint amount; bool bobIn; bool aliceIn; }

These are then stored in a dynamic array to store all agreements.

Creating a New Agreement

The arbitrator can create a new agreement by calling new

newAgreement(address _bob, address _alice, uint _amount);

This function pushes a new agreement to the array. Note that the amount is wei i.e. ETH at 18 decimals so 1e18 = 1 ETH.

Depositing Funds

Each party can then deposit to the contract using the id for the agreement.

deposit(uint _id) external payable { // Deposit logic }

This will set the boolean for bobIn and aliceIn to true.


Both participants can withdraw their funds if the deal isn’t completed by calling refund(uint _id);

Completing the Transaction

The arbitrator can complete the transaction by calling the complete function with the winners address which will receive both deposits.

complete(uint _id, address _winner);

Deploying and Testing

  1. Compile the contract in Remix using the Solidity compiler CTRL + S
  2. Deploy the contract to a local or remote test network using Remix.
  3. Test the functions:
    • Create a new agreement.
    • Deposit funds as Bob and Alice.
    • Either complete the transaction or refund.
Escrow solidity smart contract example

This tutorial covers the basic steps to create, deploy, and interact with an Escrow contract in Solidity. You can add more features like time constraints, dispute resolution mechanisms, or multi-signature requirements for the arbitrator’s decisions. Code is for example purposes only, always test thoroughly before deploying to the mainnet.

Get The Blockchain Sector Newsletter, binge the YouTube channel and connect with me on Twitter

The Blockchain Sector newsletter goes out a few times a month when there is breaking news or interesting developments to discuss. All the content I produce is free, if you’d like to help please share this content on social media.

Thank you.

James Bachini

Disclaimer: Not a financial advisor, not financial advice. The content I create is to document my journey and for educational and entertainment purposes only. It is not under any circumstances investment advice. I am not an investment or trading professional and am learning myself while still making plenty of mistakes along the way. Any code published is experimental and not production ready to be used for financial transactions. Do your own research and do not play with funds you do not want to lose.