Smart contracting simplified (Escrow) in Solidity (Ethereum)

Pranav K
4 min readDec 8, 2017

--

Here we will learn about how to create a very simple escrow smart contract, and become comfortable with writing code for Ethereum in Solidity. You will need a basic idea of dApps (Decentralized/Distributed Applications), and the concept of interacting with contracts on the Ethereum blockchain.

Fear not if you don’t understand, as I will try to provide real life use cases where I can. Also, for brevity’s sake, this tutorial will not go over creating a UI for your smart contract, nor how to deploy it to a testnet. I will write or screencap a tutorial for that after this.

Most tutorials seem like streams of consciousness with a lot of information, which makes me feel like I am sipping from a firehose, which is exciting, but not conducive to retaining information. My intention with tutorials is to simply introduce a new idea/paradigm without the need to learn about all the moving parts.

For this tutorial, we will only use Remix (https://remix.ethereum.org/), which is an in-browser Solidity compilation tool, and Metamask (https://metamask.io/), which is a Chrome browser extension that lets you connect to an Ethereum network and call smart contracts on the Ethereum blockchain, or send ether to addresses.

First, a quick intro to what escrow is. In my definition, it is a framework for a buyer to be confident that he/she will not release funds to a seller unless he/she is happy with the product/service provided. Usually a third party is employed to serve as a sort of overseer of funds, and this is usually a trusted authority that charges fees. So, fundamentally, Escrow is done between two parties that are not trusting of each other. As it turns out, this is a perfect use case for smart contracts that operate in a trust-less manner.

In our single use escrow smart contract implementation, we have four paths to consider:

  1. Both buyer and seller accept the transaction, the seller gets paid
  2. Both buyer and seller cancel the transaction, the buyer gets instantly refunded
  3. Seller accepts the transaction, but the buyer does not. The funds will be eventually returned to the buyer (frozen for 30 days), but the seller has a chance to convince the buyer to accept the transaction by mediating with them.
  4. Buyer accepts the transaction, but the seller does not. The funds remain in the contract until it is killed by the escrow creator, and funds are returned instantly to the buyer.

Let’s start by writing some boilerplate code for the constructor function and a kill function that will be used to clear the contract from the blockchain.

pragma solidity ^0.4.11;contract Escrow {
function Escrow() public {}
function kill() public {}
}

We can start implementing the public methods:

  • deposit: increment the balance with
  • accept: allow buyer or seller to agree to make the transaction
  • cancel: allow buyer or seller to disagree

And the private methods (not able to be invoked externally):

  • payBalance: Making the actual payment from escrow contract to seller

Finally, it looks like this:

pragma solidity ^0.4.11;contract Escrow {
uint balance;
address public buyer;
address public seller;
address private escrow;
uint private start;
bool buyerOk;
bool sellerOk;
function Escrow(address buyer_address, address seller_address) public {
// this is the constructor function that runs ONCE upon initialization
buyer = buyer_address;
seller = seller_address;
escrow = msg.sender;
start = now; //now is an alias for block.timestamp, not really "now"
}

function accept() public {
if (msg.sender == buyer){
buyerOk = true;
} else if (msg.sender == seller){
sellerOk = true;
}
if (buyerOk && sellerOk){
payBalance();
} else if (buyerOk && !sellerOk && now > start + 30 days) {
// Freeze 30 days before release to buyer. The customer has to remember to call this method after freeze period.
selfdestruct(buyer);
}
}

function payBalance() private {
// we are sending ourselves (contract creator) a fee
escrow.transfer(this.balance / 100);
// send seller the balance
if (seller.send(this.balance)) {
balance = 0;
} else {
throw;
}
}

function deposit() public payable {
if (msg.sender == buyer) {
balance += msg.value;
}
}

function cancel() public {
if (msg.sender == buyer){
buyerOk = false;
} else if (msg.sender == seller){
sellerOk = false;
}
// if both buyer and seller would like to cancel, money is returned to buyer
if (!buyerOk && !sellerOk){
selfdestruct(buyer);
}
}

function kill() public constant {
if (msg.sender == escrow) {
selfdestruct(buyer);
}
}
}

Additional info:

  • If the .transfer() transaction cannot occur, it will throw an error and revert any previous changes whereas a failed .send() results in a False [bool] that lets you add some logic in that transaction.
  • “now” is just an alias for “block.timestamp”, and not exactly current time, but this is close enough for our use case.

And that’s all there is to it, you have an escrow contract you can interact with on the blockchain!

Feel free to deploy this on any testnet and test the heck out of it. Please let me know if I have made any errors or left any vulnerability! If you have any queries/clarifications, feel free to get in touch.

--

--