Codementor Events

Code An Escrow Smart Contract In Solidity

Published Mar 21, 2020
Code An Escrow Smart Contract In Solidity

Video Explanation

Tradtionally, escrow payments are handled by banks or lawyers. A buyer wishing to buy an expensive item would deposit funds with an escrow manager. The manager would hold the funds as a security measure giving the seller confidence that the funds were there so they could then give the item to the buyer.

Today, the role of an escrow manager can be replaced by a smart contract, an unchangeable piece of code that lives on the blockchain. Any rules surrounding the exchange cannot be altered once on the blockchain. This gives both buyer and seller confidence that they won't be cheated during the exchange.

Let's code a very simple contract now.

pragma solidity ^0.6.0;

contract Escrow {
    // Do stuff
}

First we'll create a contract called Escrow.

pragma solidity ^0.6.0;

contract Escrow {
    //...
    enum State { AWAITING_PAYMENT, AWAITING_DELIVERY, COMPLETE }
    
    State public currState;
    
    address public buyer;
    address payable public seller;
    //....
}

Next we'll define an "enum" type with three states "Awaiting Payment", "Awaiting Delivery" and "Complete"

We'll create a variable of that new type as well as variables for the buyer and seller. The seller must be defined as payable because they will actually receive Ether in the end.

pragma solidity ^0.6.0;

contract Escrow {
  
  	//...
  
  modifier onlyBuyer() {
        require(msg.sender == buyer, "Only buyer can call this method");
        _;
    }
  
  	//...
}

Next we'll create a modifier to ensure only the buyer can call certain methods.

pragma solidity ^0.6.0;

contract Escrow {
  
  	//...
  
  constructor(address _buyer, address payable _seller) public {
        buyer = _buyer;
        seller = _seller;
    }
  
  	//...
}

In our constructor we'll initialize the buyer and seller addresses.

pragma solidity ^0.6.0;

contract Escrow {
  
  	//...
  
  function deposit() onlyBuyer external payable {
        require(currState == State.AWAITING_PAYMENT, "Already paid");
        currState = State.AWAITING_DELIVERY;
    }
  
  	//...
}

Then we'll create a deposit method. It's payable so it receives ether. Only the buyer can call it and it can only be called when there are no funds already in the escrow. Once called we set the current state to "Awaiting Delivery".

pragma solidity ^0.6.0;

contract Escrow {
  
  	//...
  
  function confirmDelivery() onlyBuyer external {
        require(currState == State.AWAITING_DELIVERY, "Cannot confirm delivery");
        seller.transfer(address(this).balance);
        currState = State.COMPLETE;
    }
  
  	//...
}

The second and final method allows the buyer to confirm that they actually received the item. Once again, only the buyer can call it. It can only be called in the "Awaiting Delivery" state. Once called it transfers the funds from the contract to the seller and marks the escrow complete.

pragma solidity ^0.6.0;

contract Escrow {
    enum State { AWAITING_PAYMENT, AWAITING_DELIVERY, COMPLETE }
    
    State public currState;
    
    address public buyer;
    address payable public seller;
    
    modifier onlyBuyer() {
        require(msg.sender == buyer, "Only buyer can call this method");
        _;
    }
    
    constructor(address _buyer, address payable _seller) public {
        buyer = _buyer;
        seller = _seller;
    }
    
    function deposit() onlyBuyer external payable {
        require(currState == State.AWAITING_PAYMENT, "Already paid");
        currState = State.AWAITING_DELIVERY;
    }
    
    function confirmDelivery() onlyBuyer external {
        require(currState == State.AWAITING_DELIVERY, "Cannot confirm delivery");
        seller.transfer(address(this).balance);
        currState = State.COMPLETE;
    }
}

The completed contract would look something like this.

This is a very simple example and there is a lot more you could and probably SHOULD do.

Discover and read more posts from Ed Zynda
get started
post commentsBe the first to share your opinion
Gilbert01
5 months ago

In the fascinating realm of blockchain development, crafting an escrow smart contract in Solidity emerges as a pivotal skill. To delve into this immersive coding experience, aspiring developers can find valuable resources and tutorials at https://arbstore.org, fostering a community dedicated to mastering Solidity and advancing the decentralized landscape. Solidity, the programming language of choice for Ethereum-based contracts, allows developers to seamlessly encode conditional transactions, ensuring security and transparency. By defining rules within the smart contract, funds are held in escrow until predefined conditions are met, offering a trustless framework for various applications like decentralized finance and online transactions.

Domenico Cusumano
a year ago

What happens if the buyer just never says they received the item? How will the seller get the funds?

Stefano Rosso
a year ago

This code must be interfaced with carrier to auto track the shipment

Aaron Shackelford
2 years ago

Thanks for this article! When I write the code in Remix I get this error. Any idea what to do with it? from solidity:
Warning: Visibility for constructor is ignored. If you want the contract to be non-deployable, making it “abstract” is sufficient.
–> contracts/Escrow.sol:18:5:
|
18 | constructor(address _buyer, address payable _seller) public {
| ^ (Relevant source part starts here and spans across multiple lines).

Show more replies