The structure and flow of Daml smart contracts: Part 2
In the first part of this series, I walked you through the structure of Daml smart contracts (or better, smart contract templates). In this second part, I will show you how this smart contract structure is set in motion by the Daml contract flow, which expresses the lifecycle of business relationships.
As a recap, the Daml smart contract structure reflects the purpose of the Daml platform, which is to record facts, rights, and obligations while enforcing need-to-know-basis visibility rules. Daml smart contracts themselves are either unilateral declarations or multi-party agreements based on such facts, rights, and obligations.
Daml smart contract structure:
- represents real-world actors as ledger parties
- records facts as the contract payload
- expresses obligations of real-world actors by specifying the signatories of contracts
- expresses rights of real-world actors as contract choices controlled by ledger parties
- and implements atomic composition of workflow steps within the ‘do’ block of choice bodies.
The Lifecycle of business relationships
In real life, a business relationship never consists of a single contract that remains valid with the same content forever. Already the simplest contract between two parties has a lifecycle: stage one, draft with no signatory; stage two, a draft contract with one signatory; and stage three, a final contract with two signatories.
The Daml template package
The Daml platform implements this dynamic nature of business relationships so that the unit of reasoning is not the single contract template, but rather the template package. The package contains all the templates that are necessary to implement the various stages of the business lifecycle. In this way, the structure of the individual smart contracts is extended by a higher-order smart contract architecture, implementing the transition rules.
The example demonstrated in part I contains only one template — the ‘TicketOffer’ template. If you copy this template into Daml Studio, you will see that the compiler is complaining about several errors, marked with comments in the code below:
The reason for this is that the ‘Accept’ choice contains references to two other contract templates, and a choice:
- the ‘TicketAgreement’ template (representing the actual ticket bought by the buyer, who becomes the owner of the ticket through the transaction)
- the ‘Cash’ template (representing the money the buyer is paying for the ticket), and
- the ‘Transfer’ choice on the ‘Cash’ contract, implementing the payment.
You can also see here how a ‘do’ block implements an atomic workflow composition: The delivery of the ticket to the buyer/owner only happens if the money transfer to the organizer also happens in the same transaction. If the ‘Cash’ contract, referenced by the ‘cashId’ contract id, has already been spent, or the ‘Transfer’ choice on it isn’t successful for whatever reason, the ‘TicketAgreemen’` contract doesn’t get created either.
The unique package ID
This seems to be a technical detail, and it actually is, but it’s an important one: Every Daml package gets a unique ID when it’s compiled, by way of hashing its contents. This package ID serves an important purpose.
The main use case of the Daml platform is that the Daml code implements a business mechanism (state machine) shared by several business parties. The package ID guarantees that the business mechanism is the same across various participant nodes of a distributed system. It also makes it possible to upgrade Daml packages and distinguish contract instances generated from the first version from instances generated from the upgraded version.
A picture is worth a thousand words
The Daml platform has a business-friendly tool to visualize the higher-order contract architecture of Daml packages. The graph of the minimal package, implementing the ticket purchase use case, looks like this:
The two arrows starting at the ‘Accept’ choice of the ‘TicketOffer’ contract represent the atomic composition of the two legs of the ticket purchase transaction.
The fact that the unit of reasoning in Daml is the template package, and that the template choice body implements workflow composition, makes it possible to implement interaction patterns, or smart contract design patterns, which are indispensable in business relationships.
In the aforementioned ticket purchase implementation, the ‘TicketAgreement’ contract is signed by two parties, the organizer and the owner (who is the same party as the buyer of the ‘TicketOffer’ contract). Two parties usually cannot sign a contract together in one step, so we need two steps: The organizer authorizes the agreement by creating the ‘TicketOffer,’ and the buyer/owner by exercising the ‘Accept’ choice on it.
This mechanism is so prevalent in business that we have a general name for it. It’s called the “initiate and accept” pattern. The contract flow starts with a proposal contract signed by an offeror, specifying the draft agreement that should be eventually created. When the offeree approves the proposal, the agreement contract gets created with two signatories. See more details in the docs.
The “multiple party agreement” is an advanced version of the ‘initiate and accept’ pattern, and is a way to create contracts with an arbitrary number of signatories. See more details here.
Another often-seen business pattern is delegation, or the power of attorney, sometimes tied to conditions and in a revocable manner. It can be implemented by a Daml package like this.
What about Solidity?
When we say “smart contract,” many think about Solidity smart contracts. So the question arises naturally: How do Solidity and Daml smart-contract structures compare?
In his blog post Ethereum versus Daml, an analysis of Enterprise Blockchain, Shaul Kfir makes a high-level comparison of the two platforms, concluding: “If your project demands a higher level of security, flexibility, and interoperability, Daml offers the facility to maintain the privacy of an organization’s information and improves the effectiveness of deployment.”
Solidity faces serious security and usability challenges. So the recommended way to use it is to utilize a library containing standard, tested, and community-reviewed contracts to minimize the risks. One such is the OpenZeppelin library, which also explains Solidity design patterns.
About the author
György Balázsi is a certified Daml developer and an active community member on the Daml Forum. Holder of one of the community recognition rewards. He is a digital strategist and consultant, working in the intersection of business and IT.