An Escrow Smart Contract in SmartPy

Solomon Lederer, PhD
3 min readAug 26, 2019

--

Below is an example escrow contract in SmartPy — A new smart contract language for Tezos. This contract can be used when transacting with a physical item e.g. Alice wants to buy a harmonica from Bob. [This contract is based on a demo in Solidity I saw years ago. If you know who originated this solution, please let me know so I can give appropriate credit.]

For a primer on SmartPy see my intro video here.

This contract works as follows:

  1. The seller sets the price of the item and deposits twice that price into the contract i.e. if the price is 1 token, the seller deposits 2.
  2. The buyer deposits 2 tokens as well. Simply by depositing 2 tokens, that person is marked as the buyer.
    Note: The reason they deposit extra money is to lock both parties into an arrangement that neither party can unilaterally walk away from.
  3. At this point the contract has 4 tokens that is now in its control. There are only 2 ways to get the money out:
  4. Option A: The buyer receives her item. She confirms that the item is received which allows her to get her extra deposit back (1 token) and send the seller the remaining 3 tokens (1 for the item and 2 for his deposit).
  5. Option B: The seller can roll everything back and refund the buyer. The buyer gets her 2 tokens back, and the seller gets his 2 tokens back as well. He would do this in a scenario where he cannot ship the item, changes his mind, etc.
  6. That’s it. Note how the typical concerns with transacting without an escrow are now gone. The seller doesn’t have to worry about sending the item and never getting paid, because he can see that the buyer has already put up the money in the smart contract and is compelled to follow through. Conversely, the buyer doesn’t have to worry about selling money to a seller that will never ship the item, because she never sends the money into the seller’s hands.

Link to the script on SmartPy.io. [note this may only work on the dev version of SmartPy.io/dev]

import smartpy as sp#Both buyer and seller must send in twice the value of the item they are transacting on. This ensures that both parties are committed to see the transaction through to the end.class Escrow(sp.Contract):
def __init__(self):
self.init(seller = sp.none, buyer = sp.none, price = 0)
@sp.entryPoint
def setSeller(self, params):
#ensure seller hasn't already been set
sp.verify (~self.data.seller.isSome())

#the seller sets the price and must send 2x the price in tez
self.data.price = params.price
sp.verify (sp.amount == sp.tez(self.data.price * 2))
self.data.seller = sp.Some(sp.sender)
@sp.entryPoint
def setBuyer(self, params):
#ensure that there already is a seller
sp.verify (self.data.seller.isSome())
#ensure buyer hasnt already been set
sp.verify (~self.data.buyer.isSome())

sp.verify (sp.amount == sp.tez(self.data.price * 2))
self.data.buyer = sp.Some(sp.sender)

@sp.entryPoint
def confirmReceived(self, params):
sp.verify (sp.sender == self.data.buyer.openSome())
sp.send (self.data.buyer.openSome(), sp.tez(self.data.price))
sp.send (self.data.seller.openSome(), sp.balance)
self.resetContract()
@sp.entryPoint
def refundBuyer(self, params):
sp.verify (sp.sender == self.data.seller.openSome())
sp.send (self.data.buyer.openSome(), sp.tez(2 * self.data.price))
sp.send (self.data.seller.openSome(), sp.balance)
self.resetContract()

#clear out buyer and seller
def resetContract(self):
self.data.buyer = sp.none
self.data.seller = sp.none
self.data.price = 0
@addTest(name = "Test Escrow")
def testEscrow():
html = ""
seller = "AAA"
buyer = "BBB"
myContract = Escrow() #set the seller and price
html += myContract.setSeller(price = 1).run(sp.address(seller), amount = sp.tez(2)).html()

#set the buyer
html += myContract.setBuyer().run(sp.address(buyer), amount = sp.tez(2)).html()

# buyer confirms they received item
html += myContract.confirmReceived().run(sp.address("BBB")).html()

# seller decides to refund buyer
# html += myContract.refundBuyer().run(sp.address(seller)).html()

setOutput(html)

Link to the script on SmartPy.io.

--

--