July 13th, 2023
In this blog post, we’ll explain some of the advantages and challenges of learning Daml, the open-source smart contract language developed by Digital Asset and specifically designed for building distributed applications and creating digital contracts.
The term “smart contract” was introduced by computer scientist and legal scholar Nick Szabo in 1994, way before blockchain became a buzzword. The real-world things which inspired Szabo’s thinking were “smart property” (“smart” meaning here embedding some legal relationships) and derivative contracts traded on stock exchanges.
To the first category belongs his widely cited example: the vending machine. As Szabo puts it in his 1997 paper The Idea of Smart Contracts:
“A canonical real-life example, which we might consider to be the primitive ancestor of smart contracts, is the humble vending machine. (...) the machine takes in coins, and via a simple mechanism (...) dispenses change and product according to the displayed price. The vending machine is a contract with bearer: anybody with coins can participate in an exchange with the vendor.”
Szabo also writes about “a hypothetical digital security system for automobiles”, on which there is an automatically enforced lien: “we can create a smart lien protocol: if the owner fails to make payments, the smart contract invokes the lien protocol, which returns control of the car keys to the bank”.
In the second category of real-life things as predecessors of smart contracts belong derivatives like futures and options. Szabo discusses these in his 2002 paper A Formal Language for Analyzing Contracts together with the goals and semantics of his proposed smart contract language.
In this latter paper, Szabo also elaborates on his goal to find the “atoms” of contracts and the composition rules which allow for building new contracts.
One important limitation of Szabo’s concept is that he only contemplates two-party contracts, made between a Holder and a Counterparty. Each party owns a different contract, which are the mirror images of each other (one party’s rights are the other party’s obligations and vice versa) and can be deduced from each other.
Szabo never implemented his smart contract language, but he cites the E domain specific language in his papers as a possible implementation. Also, he didn’t elaborate on how the contracts would be stored and transacted upon. On the other hand, Szabo writes extensively about physical sensors triggering state transitions for smart physical property, and the passing of time triggering state transitions for derivative contracts.
The term “smart contract” and “smart contract language” became even more famous (and acquired a different meaning) with the birth of Ethereum. The concept is central to Ethereum, which is already emphasized by the title of its 2013 whitepaper: A Next-Generation Smart Contract and Decentralized Application Platform.
The paper contains a link to Szabo’s 1997 aforementioned paper, but the authors don't explain why they reuse the term “smart contract”, which, used for Ethereum, completely lacks the legal relevance which was the key part for Szabo.
In the introduction of the Ethereum whitepaper, it states: “What Ethereum intends to provide is a blockchain with a built-in fully fledged Turing-complete programming language that can be used to create "contracts" that can be used to encode arbitrary state transition functions.” No mention about legal relationships here. And later on they explicitly reject the legal aspect: “Note that "contracts" in Ethereum should not be seen as something that should be "fulfilled" or "complied with"; rather, they are more like "autonomous agents" that live inside of the Ethereum execution environment, always executing a specific piece of code when "poked" by a message or transaction, and having direct control over their own ether balance and their own key/value store to keep track of persistent variables.”
After Ethereum, a lot of smart contract languages were born. They can be different in how much they resemble the original “legal relationship” concept and the “arbitrary state transition function” concept of Ethereum.
In the year 2000, between Szabo’s first papers and the Ethereum whitepaper, a less famous but not less important paper came out which doesn’t mention the words “smart” and “contract” together, but uses the term “financial contracts”, and “composition”. The paper was written by Simon Peyton Jones, creator of the Haskell programming language, and his colleagues, with the title Composing contracts: an adventure in financial engineering.
The “composing contracts” paper describes a set of Haskell functions (combinators) which implement the basic building blocks of derivatives (like “one”, a contract which immediately pays to the holder one unit of a certain currency) and functions which create new, more complex rights and obligations from simple building blocks (like “or”, “and” or “truncate”, the latter of which expresses expiry). If this reminds you of the contract “atoms” and composition rules described by Szabo, it’s not a coincidence. The paper, just like Szabo’s smart contract concept, only deals with two-party contracts.
This paper became the inspiration for creating Daml and the Daml Finance library. Daml was created by a Swiss company operating in Zurich, called Elevence. Elevence was acquired by Digital Asset in 2016. The people working with Elevence became the founding members of the Zurich office of DA. Daml was originally called “Digital Asset Modelling Language”, but was rebranded later to just the abbreviation. The name Canton also reflects the Swiss origins – a canton is an administrative unit in Switzerland.
From this historical overview it becomes clear that Daml delivers on the original promise of the smart contract concept: it implements legal relationships and transactions based on these relationships. Seeing the two-party limitation of earlier versions of this concept, we can especially appreciate the flexibility of Daml, where smart contracts can have an unlimited number of stakeholders. As you already know from our earlier blog posts, Daml comes together with Canton and the Canton network, which embed smart contracts into a distributed storage and transaction system.
On top of Daml being useful for implementing legal relationships, learning it is intellectually rewarding, because it is a good introduction to the functional programming paradigm.
The essence of functional programming is that the type systems of such languages account not only for the return values of functions, but also potentially for some “context” surrounding the return value. This “context” can be, for example, that the return value may or may not exist in cases where a function in a procedural language would run the risk of panicking. Incorporating this uncertainty into the type system helps to typecheck the composition of “contextual” functions and can be seen as a typesafe alternative to error handling. Such “contexts”, adhering to some rules, are called monads.
The functional paradigm is a good fit for a ledger, because a ledger update can succeed or fail for whatever reason, e.g. because the asset provided for a transaction was “spent” (using Bitcoin terms) for another transaction.
In the Daml lingo, monads are called Action. The Update typeclass which describes the uncertain return values of ledger updates, is a specific case of Action. Composing update functions in Daml signals to the compiler that the underlying ledger update mechanism will accept or reject the series of update requests in an “all or nothing” way, allowing for passing the return value from one update to another one.
Functional programming in itself is an intellectual adventure. If you are interested in the mathematical background of it, you may want to check out Bartosz Milewski’s Category Theory for Programmers blog post series.
Besides the advantages, learning and using Daml also comes with some challenges.
One challenge is that there is no obvious connection between the smart contract code and some legal prose describing the rights and obligations expressed by the code.
The creators of Daml never promised that the Daml code is human readable. Still, when we think about practical use cases we may wish some human readable representation exists. Coming back to Nick Szabo, he envisioned a smart contract language which is machine readable and human readable at the same time. He writes in his aforementioned article: “A law degree is not required to use the language, but some familiarity with contract law and the drafting of contracts is recommended. A lawyer who did reasonably well on the analytical and logical sections of the U.S. LSAT or its overseas equivalent, will, I suspect, have better luck drafting contracts in this language than a programmer whose sole experience lies in traditional procedural language. That is why I call this a drafting language not a programming language.”
A Daml contract template can contain an “agreement” field with a text template describing the content of the agreement, filled in with payload values at contract creation. The Daml docs say about this field: Represents what the contract means in text. Such agreements are usually the boundary between on-ledger and off-ledger rights and obligations.
The challenge with this agreement field is that nothing guarantees that the text template is a correct representation of the contract template code. Theoretically, any contracting party, before signing a contract with such a field, can check this for themselves – but in order to be able to do this, they already need to accurately understand the contract template code. In the “paint offer” example in the docs, this field is being used to formulate an off-ledger promise arising from signing the contract, rather than the contents of the contract itself.
Another challenge is that in order to understand the Daml ledger model and the story behind a specific ledger, the dynamic elements of the ledger, namely the choice exercise events are at least as, or even more important than the static elements, namely contract creation events (or contracts for short). Still, these remain usually hidden.
As an explanation, the essence of the Daml ledger model in a nutshell is the following:
The ledger stores an event graph. The nodes of the graph are creation events for the creation of contracts, and exercise events performed on previously created contracts. The edges of the graph are the “consuming” and “consequence” relationships attached to exercise events and pointing to other events.
The event graph is append-only during normal operation. This guarantees atomic transaction composition, because the new event nodes (and edges attached to exercise events) of a transaction are either added or not as a whole.
The current state of the ledger (also called the active contract set, ACS for short) consists of such creation events for which no consuming exercise was recorded on the ledger.
Ledger parties have access to a subset of the event graph containing the events they are entitled to see. This guarantees sub-transaction privacy.
The ledger can be pruned under certain circumstances, removing events which are not needed for operation.
For obvious reasons, UIs usually only display the active contracts, or in the case of the Navigator UI, on demand also the archived contracts. Exercise events are the links between ledger states, and remain the “missing links” in this way. For pedagogic purposes (and for audit) it’s useful to visualize and analyze the full event graph of the ledger, available through the transaction trees API service.
A third challenge is that Daml looks like Haskell (apart from the template syntax) but it actually isn’t Haskell.
The Daml language contains elements of Haskell, but in a limited way. The Daml compiler uses the GHC Haskell compiler but not the end result of the compilation (the LLVM byte code) but an intermediary result of it. The compiled Daml code is packaged and interpreted in a very different way from Haskell. (You can learn the details from the Deep Dive into the Daml Compiler video.)
Apart from performance differences, this can be challenging in two ways:
For those new Daml users who don’t know Haskell, the Haskell-like syntax of helper functions can seem intimidating. For such users it’s a good idea to pick up at least some basic Haskell syntax and understand the use of functors, applicatives and monads in Haskell.
For those new Daml users who know Haskell, it can be not obvious at first how the Action type class is the equivalent of Haskell monads, and such limitations as e.g. the lack of lazy evaluation.
And finally, a fourth challenge is that the Daml compiler error messages are mostly coming from the underlying Haskell compiler and Shake build system, and reference a desugared version of the Daml code.
To better understand such error messages, here are some useful bits of information:
Daml template and choice names actually refer to record data types created in the background. Error messages will likely treat templates and choices as Haskell records.
As a consequence of the previous point, choice names must be unique within a file (module). Additionally, if we want to exercise a choice in a different module from where it was created, it must be imported in the same way as other record data types (using the double dot syntax).
Choices are monadic functions in disguise. The input type of the choice function is the choice name record type with the same fields as the choice fields are, the return type of the function is the return type specified in the template, wrapped into the Update type class.
For more on Daml, stay tuned for our upcoming blog on how to communicate with a Daml ledger.