Simple Convention for Human Readable Terms for Smart Contracts

Published June 29th, 2016 edit replace rm!

Smart Contract Acceptance

In the Ethereum world "Smart Contracts" refer to code. On its own a Smart Contract doesn't necessarily create a legally binding contract. A Contract is neither code, nor a PDF file nor a printed signed document.

A legally enforceable contract describes a (1) relationship between 2 or more parties (2) with rights and obligations attached which (3) is enforceable by a governmental authority.

A contract can be written down on paper or (sometimes) be based on a verbal understanding. Verbal understandings as well as Smart Contracts can be problematic because they may not include all of the terms necessary to address future potential problems.

A human readable contract document is particularly useful because it can describe the relationship in language that the parties understand. It also allow gives non-parties such as external dispute resolution systems (judges, arbitrators, reddit etc.) a roadmap of the expected relationship between the parties. This can used afterwards to clean things up if something bad happens.

Smart contracts are particularly useful when they are able to automate components of human readable contracts and, in doing so, avoiding conflicts that human language and human agreements can sometimes cause.

Software code isn't perfect, however. Indeed, as we’ve seen recently, Smart Contracts can suffer from many of the same problems that verbal contracts have, because smart contract code doesn't include all of the terms that traditional written contracts might include (indemnity, termination, are a few examples).

“But Pelle, Smart Contracts contain all the rules of the contract.”

If we look at Smart Contracts as just code that may be correct. However if it is intended to serve as a legally enforceable contract, the expectations about it may often be more important than what is written down and in code.

One limitation Smart Contracts currently face is their inability to monitor and enforce off-chain obligations. But it can’t express what happens off chain. I expected 10 sacks of Coffee delivered on August 1st and you didn't deliver. It also can’t express every single possible failure case in the future, such as unexpected bugs or regulatory attack.

Scope: Provide a simple technical foundation that business and legal minds can build on

Solidity and Ethereum need a framework that allow lawyers, business people and developers to work together to make it easier to create legally enforceable Smart Contracts.

To that end, I've created this proposal and example code that begins to allow this, with the specific aim of helping Solidity and Ethereum developers do what we’re good at and let lawyers and business people do what they are good at.

This proposal can easily be added to any new Solidity smart contract. It can be done at various levels. At the minimum add the first step.

1. Upload your terms to IPFS and store the hash at a known place

This is simply adding the convention of adding a single line of code to your Solidity contract:

contract FancyDAO {
  bytes32 public terms = 0x28678b42f7fcf403009f1805e4e...;

Now wallets and other third party code can always extract the terms for your Smart Contract.

IPFS is a distributed protocol allowing you to store any static data. It is a great complement to Ethereum.

For more advanced functionality you can use my new Solidity library SolidTerms.

2. Add Acceptance

In many cases publishing the terms alone is fine. You maybe be able to get away with saying something like: “Sending Ether to this smart contract means you’ve accepted the terms”.

But particular when dealing with money it is often a good idea to have a firm procedure of recording acceptance of the contract.

To avoid you writing your own I have written this simple Abstract Contract Acceptable that implements this.

import "Acceptable.sol";
contract FancyDAO is Acceptable {
 bytes32 public terms = 0x28678b42f7fcf403009f1805e4e...;

 function split(...) hasAccepted public {

This adds an accepted mapping to the contract and a public function called accept(bytes32 _terms).

Once a user through their wallet calls accept it is recorded on the blockchain.

The library also adds a nice little modifier called hasAccepted that you can use on your own functions. This requires acceptance to be able to call the given function.

Did you notice that the accept(bytes32 _terms) function takes a parameter? It requires the user to present the same IPFS hash of the terms. This is primarily to encourage the wallet user interface to actually load and show the user the terms.

3. Add change management

Sometimes contracts need to change and the terms behind them as well.

You could write your own, but if we have a common interface, third party tools can be created allowing non technical people to update the terms in a simple transparent manner.

I have a simple abstract contract here Changeable that will allow you to add this with very little code to your own Smart Contracts

import "Acceptable.sol";
contract FancyDAO is Acceptable, Changeable {
 bytes32 public terms = 0x28678b42f7fcf403009f1805e4e...;

 // Override this method to decide who can change therms
 function canProposeChange() constant returns(bool) {
   return (msg.sender == offerer );
// Adds the following function to be called from a GUI with changed terms
// function proposeChange(bytes32 _terms) {};

// Now you can ensure that the function caller has always accepted the latest version
function split(...) hasAcceptedLatest public {

4. Standard Events

It would be useful to have a set of standard events that auditing tools and wallets can listen to.

Here are the 3 most basic events I think are necessary:

// Event created when agreement is reached (active)
event AgreementReached (
  bytes32 indexed terms
// Event to be created when terms are accepted by a single party
event TermsAccepted(
  address indexed accepter,
  bytes32 indexed terms
// Event to be created if Terms are changed
event TermsChanged(
  address indexed changer,
  bytes32 indexed terms

Example implementations

Here are 3 more complete examples:

  • TermsOfService A simple complete Terms of Service implementation that can be used in your own Smart Contracts
  • SimpleAgreement An example of a 2 party negotiable contract. An offerer invites the invitee and they both can change the contract until they both accept it. This could be used as the basis for a sales or consulting contract.
  • RicardoCoin Is an example of adding the TermsOfService contract to a really simple token issuance contract.

Isn’t this a Ricardian Contract?

Well I’m glad you asked. This is indeed my interpretation of a Ricardian Contract. I have another article drafted on why Ricardian Contracts are awesome. So watch this space.

Format of Terms

Lawyers would probably instinctively post a PDF file of the terms to IPFS and use that. I would recommend against that as it would be useful that they can easily be viewed in a mobile app or web browser. So I would personally recommend plain text, markdown or html.

An IPFS hash can actually point to a folder. So you could have multiple files as part of your terms.

Technical note regarding storing IPFS hashes in Smart Contracts

IPFS hashes are 34 byte Base58 encoded MultiHash strings. We can easily store 34 bytes in a dynamic byte array in Ethereum, but it is more efficient to store them as a fixed byte32 value.

There may be many of these both in transaction calls, contract storage and events. So I think we might as well save the gas The first 2 bytes just tell MultiHash what kind of algorithm it is.

In javascript you can convert the hex back to IPFS like this:

var bs58 = require('bs58');
function hex2ipfshash(hash) {
 return bs58.encode(new Buffer("1220" + hash.slice(2), 'hex'))

function ipfs2hex(ipfshash) {
 return "0x" + new Buffer(bs58.decode(ipfshash).slice(2)).toString('hex');

I will shortly release a small javascript library for wallet and dApp developers to use. This will include the above functions as well as extract the full terms of any SmartContract that supports the basic conventions outlined above.

Thanks to Stephen Palley and Ian Grigg for reviewing this. Neither my writing nor their review should be considered legal advice.

Robot handshake image copyright: alperium / 123RF Stock Photo

About me

Pelle gravatar 160

My name is Pelle Braendgaard. Pronounce it like Pelé the footballer (no relation). CEO of Notabene where we are building FATF Crypto Travel Rule compliance software.

Most new articles by me are posted on our blog about Crypto markets, regulation and compliance

More about me:

Current projects and startups:

Other under Ethereum

Popular articles