Beginner’s Guide to Design Patterns in DAML

Reading Time: 6 minutes

DAML is an open-source language used to write distributed applications quickly,concisely and correctly. It runs on leading blockchain platforms like Hyperledger Sawtooth , fabric and Corda.

It is used to build smart contracts for distributed ledgers and provide us with ability to focus more on business workflow instead of the blockchain implementation.

In our previous blogs, Building Powerful Smart Contracts, Getting started with building Templates and DAML supported data types we have covered basics of DAML which will help you understand the language and need of language and also a guide to get you started with it. I would recommend you all to go through them before going forward with this blog.

In this blog we will go through DAML design patterns that we should follow while building our application.

What are Design Patterns ?

Design patterns are used to represent some of the best practices adapted by experienced software developers. A design pattern systematically names, motivates, and explains a general design that addresses a recurring design problem in systems. It describes the problem, the solution, when to apply the solution, and its consequences. It also gives implementation hints and examples.

A design pattern isn’t a finished design that can be transformed directly into code. It is a description or template for how to solve a problem that can be used in many different situations.

They help in speeding up the development process. 

Here are some of the DAML design patterns we can use for building applications using DAML
  1. Initiate and Accept 
  2. Multiparty Agreement
  3. Delegation
  4. Authorisation
  5. Locking

Initiate and Accept

This design pattern demonstrates how we can start building templates when only two parties are involved in the project. As the title suggests one party initiates the workflow by creating a proposal or an invite contract. The other party will accept, reject or renegotiate the contract.

As shown in this diagram the two cards represent two templates. The first template is the initiation template or the invite template and the other is the Accept template which the user will use to accept the invite.

Lets understand better with an example :

In this example we have two templates for Initiation and Acceptance. This example we are to issue coins to the user once the user has accepted the agreement. This code is not in complete 

And is just used to give you guys an idea of the concept.

template CoinIssueProposal
  with
    coinAgreement: CoinIssueAgreement
  where
    signatory coinAgreement.issuer

    controller coinAgreement.owner can
      AcceptCoinProposal
        : ContractId CoinIssueAgreement
        do create coinAgreement

Initiate Template

The CoinIssueProposal contract has Issuer as the signatory, and Owner as the controller to the Accept choice. As we can see the choice available is of only AcceptCoinProposal but in reality different choices like reject or renegotiate are also provided.

template CoinIssueAgreement
  with
    issuer: Party
    owner: Party
  where
    signatory issuer, owner

    controller issuer can
      nonconsuming Issue : ContractId Coin
        with amount: Decimal
        do create Coin with issuer; owner; amount; delegates = []

Result Contract

Once the owner exercises the AcceptCoinProposal choice on the initiate contract to express their consent, it returns a result contract representing the agreement between the two parties. In this example, the result contract is of type CoinIssueAgreement. Note, it has both issuer and owner as the signatories, implying they both need to consent to the creation of this contract. Both parties could be controllers on the result contract, depending on the business case.

Multiparty Agreement

In the previous topic we saw the best way to make the contract when only two parties are involved but in the real world multiple parties can be part of the contract. When  multiple parties are involved bilateral contracts are not the way to go as no two parties can be sure if there is a conflict between their two contracts and third contract between their partners.

 So what approach should we follow in that case? Let’s find out!

The Multiple Party Agreement pattern uses a Pending contract as a wrapper for the Agreement contract. Any one of the signatory parties can kick off the workflow by creating a Pending contract on the ledger, filling in themselves in all the signatory fields. The Agreement contract is not created on the ledger until all parties have agreed to the Pending contract, and replaced the initiator’s signature with their own.

template Agreement
  with
    signatories: [Party]
  where
    signatory signatories
    ensure
      unique signatories
  -- The rest of the template to be agreed to would follow here

Agreement Contract

This represents final agreement between all the parties. It has multiple signatories.

template Pending
  with
    finalContract: Agreement
    alreadySigned: [Party]
  where
    signatory alreadySigned
    observer finalContract.signatories
    ensure
      -- Can't have duplicate signatories
      unique alreadySigned

    -- The parties who need to sign is the finalContract.signatories with alreadySigned filtered out
    let toSign = filter (`notElem` alreadySigned) finalContract.signatories

    choice Sign : ContractId Pending with
        signer : Party
      controller signer
        do
          -- Check the controller is in the toSign list, and if they are, sign the Pending contract
          assert (signer `elem` toSign)
          create this with alreadySigned = signer :: alreadySigned

     choice Finalize : ContractId Agreement with 
         signer : Party 
       controller signer do -- Check that all the required signatories have signed Pending 
          assert (sort alreadySigned == sort finalContract.signatories)
           create finalContract

Pending Contract

This pending contract contains the Agreement as one of the parameters so that all the parties know what they are signing for.

Here the pending contract has the list of parties which have signed the contract and the list of parties which are yet to sign the contract. Once all the parties have signed the contract using the Finalize choice. This checks that all of the signatories for the Agreement have signed the pending contract.

Delegation

This is an important design pattern because it gives one party the right to exercise a choice on behalf of another party. In the real world this is very useful because there may be many cases where somebody would like to give another person the right to exercise the choice on their behalf. For eg: when a company may give the rights to their chosen bank to hold their securities and settle transactions on their behalf.

Delegation design pattern can be implemented using:

template Coin
  with
    owner: Party
    issuer: Party
    amount: Decimal
    delegates : [Party]
  where
    signatory issuer, owner
    observer delegates

    controller owner can

      Transfer : ContractId TransferProposal
        with newOwner: Party
        do   
            create TransferProposal
             with coin=this; newOwner

      Disclose : ContractId Coin
        with p : Party
        do create this with delegates = p :: delegates

Pre-Condition Contract

This contract exists with the choice for Party A to delegate execution of the choice to Party B. Here the control of the choice is given to the owner who can pass the authority to another party to exercise choice on its behalf.

template CoinPoA
  with
    attorney: Party
    principal: Party
  where
    signatory principal
    
    controller principal can
      WithdrawPoA
        : ()
        do return ()

    controller attorney can 
       nonconsuming TransferCoin : ContractId TransferProposal with 
          coinId: ContractId Coin 
          newOwner: Party 
        do 
            exercise coinId Transfer with newOwner

Delegation Contract

Here the original coin owner is the signatory of delegation. This signatory is required to authorise the transfer choice on the coin. Attorney is the controller of the Delegation choice on the contract. Within the choice, the Principal exercises the choice Transfer on the Coin contract.Coin contracts need to be disclosed to the Attorney before they can be used in an exercise of Transfer. This can be done by adding an Attorney to Coin as an Observer. This is done using the Disclose choice in the pre-condition contract.

Authorisation

In this business world it is very important to make sure that the contracts choices are exercised by the right person. If any person who is not authorized or does not have the permission is able to exercise a choice then it’s consequences can be bad for business. 

It is important to make sure that the parties are authorised to before taking part in the business transaction. This can be achieved by using an Authorised pattern model.

template CoinOwnerAuthorization
  with
    owner: Party
    issuer: Party
  where
    signatory issuer
    observer owner

    controller issuer can
      WithdrawAuthorization
        : ()
        do return ()

Authorisation Contract

In this example we can see that issuer is the signatory here and owner is the observer. This makes sure that the owner is an authorised person. This is a simple example, in real business use cases we can add many things.

Locking

Locking is an important concept for business contracts. In a real world scenario like in the case of the settlement process between two parties the securities under the ownership of seller need to be locked so they cannot be used for other purposes, and so should be the funds on the buyer’s account. The locked state should remain throughout the settlement Payment versus Delivery process. Once the ownership is exchanged, the lock is lifted for the new owner to have full access.

This can be achieved in three ways:

References :

  1. https://sourcemaking.com/design_patterns
  2. https://docs.daml.com/daml/patterns.html

Knoldus-blog-footer-image