Smart contracts are good. Let's make them better.

Nick Szabo's smart contract in Daml

Smart contracts are an interesting concept that were first introduced by Nick Szabo in his seminal paper on smart contracts. The idea of representing agreements as code, making programs code more legible for non-programmers, and enforcing processes and agreements is quite attractive. But have we figured out how to best implement smart contracts? Is it solely legal contracts or is there wider applicability of these concepts? In short, can we do better?

It may first help to understand what we’ve learned about smart contracts now that they have been live on public (ex. Ethereum) and private networks for many years now. Namely:

  1. Interest outweighs usage. Experiments abound, and a small but sizeable number of intrepid programmers are exploring this vast new landscape
  2. They are not well suited to imperative languages, which often obscure their behavior and can lead to veryexpensivebugs
  3. They generally represent privately enforceable agreements between parties and rarely need their contents, execution, or enforcement to be public

So let’s take a look at one of Szabo’s earliest reified contracts, that of a leased car.

“(1) A lock to selectively let in the owner and exclude third parties;

(2) A back door to let in the creditor;

(3a) Creditor back door switched on only upon nonpayment for a certain period of time; and

(3b) The final electronic payment permanently switches off the back door.”

It may not be a lot of text but there’s a lot of things going on here, namely:

  1. Two parties to the contract, the creditor and the owner
  2. A lock that has configurable permissions
  3. A backdoor to the lock that has payment based permissions
  4. An implied ability for the car to be able to query a payment system

Let’s refine these assumptions a little for implementation and complexity

  1. There are actually three parties to the contract, the creditor, the owner, and the car (enforcing the rules)
  2. The lock governs starting the car and is a series of assertions about the state of the contract. If the assertions fail the lock stays locked
  3. The backdoor is also limited by such assertions
  4. The car has a privileged and uninterruptible knowledge of a payment system, be it a bank account, 3rd party attestation, or a public value transfer network like Bitcoin. While our design glosses over these specifics, the interesting implication here is that the car is a reasonably autonomous party to our contracts

We’ll also assume, as Szabo did, that the mechanism enforcing the rules of these contracts would cost more to remove or replace than the cost of the car. Given the availability of tamper-resistant processors this is a reasonable assumption to make.

So what does our contract look like then? Well, this is the whole thing, ~50 lines excluding comments, read it. You’ll find that not only is it short, but it’s also relatively legible even for non-programmers. This is one of the reasons we use a declarative language like Daml rather than an imperative language like Solidity or Java, it’s easier to reason about.

The other reason we like this is because these contracts don’t need to be public. They’re private and between only those parties that need to be aware of them, and only in the ways they need to be aware.

Only the creditor can create the `LeaseOperation` contract, and only the owner and car can see it, each of them can do some things to the contract, but none can do everything. 

Similarly the `Payment` contract is controlled exclusively by the car. Payments are involved, and they can be on any private (ex. Bank, Credit Card) or public network (ex. Bitcoin), but they are side effects to the contract and there’s no reason your public or private network needs to know, or be involved in, the terms of your agreement. They process your payment, they don’t enforce your contracts.

All variables are explicit and strongly typed, they are well known to the programmer, legal auditors, contract participants, the compiler, and the execution engine. All of these levels of checks and the ease with which this code is interpreted allows for far more participation and understanding of the contract than either a generic or imperative programming language or a legal contract alone. If you’re interested in a comparison between these approaches you can read this great article by Manish Tomer.

Similarly actions are much better when explicit authorizations are given about who can take the actions. We should write smart contracts like this, defaulting to no one being able to interact without authorization, rather than the common pattern of defaulting to everyone being able to interact and then coding to restrict these interactions. This is a nuanced but important distinction, one of the biggest examples of the latter being a hack that permanently lost about $150 million dollars worth of assets on Ethereum.

There’s no doubt as to who can start the car in the above snippet. Similarly there should be no doubt about who can move (or freeze) funds, or any other high value operation.

Ultimately better smart contracts boil down to the following: 

  1. Be explicit rather than implicit. Call them actions, choices, or functions, but no matter their name they should state exactly who has authority when, in all cases. If it’s ever unclear no contract should execute.
  2. Source code should be clear and legible to the point where even non-programmers can make reasonable sense of what the contract does, and who can do it.
  3. There should be many layers of fail safes, as many as possible, between when an application is designed, and when it is in use in the real world.
  4. Smart contracts do not need to encompass the whole world, they can stay private and their interactions with the real world can be side effects.

 

If you want to know more about Daml checkout our documentation, or come join our lively forum. This article is the second of many in an ongoing series of distributed ledger concepts, if you enjoyed it then check out the first post where we breakdown the practical implications of centralized, distributed, and decentralized systems.