Very Simple Bi-party Escrow in Solidity

This is an extremely simple application of Escrow to a trading relationship between two counterparties. Instead of paying directly, Counterparty 1 (let’s say Alan) transfers the money to a smart contract on Ethereum in order to do business with Counterparty 2 (we’ll call her Betty). They’ll both have protection — Alan can hold back the money if Betty doesn’t come up with the goods, while Betty, once she’s agreed to enter into the contract, can stop Alan from running off without paying.

Here’s the code:

contract VerySimpleBiPartyEscrow {
    address public alan;
    address public betty;
   
    bool public alanStatus;
    bool public bettyStatus;
   
    uint256 public escrowVal;
   
    constructor(address _betty) public payable {
        require(msg.sender != _betty);
       
        alan = msg.sender;
        betty = _betty;
        alanStatus = true;
        bettyStatus = false;
       
        escrowVal = msg.value;
    }
   
    function bettyValidate() public {
        require(msg.sender == betty);
        require(bettyStatus == false);
       
        bettyStatus = true;
    }
   
    function alanClose() public {
        require(msg.sender == alan);
        require(bettyStatus);
       
        selfdestruct(betty);
    }
   
    function alanWithdraw() public {
        require(!bettyStatus);
        selfdestruct(alan);
    }
}

Contract opening

Counterparties will be tracked by their address and their validation of the contractual arrangement. So, for contract variables we have two addresses and two statuses (alanStatus and bettyStatus), plus a public variable showing the amount of ether in a contract.

Each contract must have two distinct counterparty addresses (cunningly referred to in the code as alan and betty). The first counterparty sets the second counterparty at contract opening.

The constructor function is called by passing in an address for betty and some ether. The constructor function does this:

  1. Check the opener is not nominating themselves as a counterparty (our man Alan can’t do escrow against himself, no matter how confused he might be).
  2. Msg.sender is assigned to alan, the passed in address is assigned to betty.
  3. alan has, by opening the contract, already consented to the arrangement and his status is set to true, but betty hasn’t yet done so and starts at false.
  4. We set the publicly visible variable to the amount of ether passed in.

bettyValidate()

Without consenting to the contract, betty can’t play ball. So they have to validate their participation, which only they can do and only once. Ideally betty has already checked the right amount of ether is in the contract and is ready to deliver her side of the deal.

This is where the contract value proposition lies. Up until betty’s validation, alan can withdraw the ether from the contract back to himself at any time. After it’s done, he cannot. All he can do is transfer it to betty.

alanClose()

After betty has validated, only alan alone can send her the ether by calling a selfdestruct() in her favour. In practice, this is a little impractical since there would be no easily accessible record of the contract on Ethereum, but it’ll do for now (it does say Very Simple in the title).

alanWithdraw()

Before betty validates — ‘pre-flop’, if you’re a poker person — alan can decide against it, and withdraw all the funds back to himself, again killing the contract via a selfdestruct().

Benjamin Stanley
Benjamin Stanley

Ben is the CEO of SureVX. He’s a long-time crypto guy and loves playing the blues.