Fix my bike: Use Daml to model a real life example


Andreas Lochbihler of Digital Asset conducted a guest lecture at Rapperswil last May, and in the lecture he demonstrated a real life example, showing how a bike shop offers a repair service for a bike owner in return of the cash the bike owner is holding. Here you can find his guest lecture:

This is a good guided tutorial for those who are interested to learn Daml and build a more complex contract step by step. This article serves as a supplementary work to his demonstration, providing the code and some explanation on the test result. The code is directly adopted from his demonstration, and rewritten with Daml SDK v1.10.0.

Overview of Bike Shop Example

In the Bike Shop example, three parties are involved.

  • SwissBank: issuing cash as contracts
  • Martin: the bike owner, who owns cash issued by the Bank
  • BikeShop: the bike shop, who provides service to bike owners in exchange of cash

Here is the flow of this demonstration.

  1. Create record type Cash, which is a named tuple.
  2. Create template Cash and let SwissBank issue the cash to Martin who owns this cash.
  3. Make this cash transferable by adding choice on the cash template
  4. Explore a bilateral service contract, which requires both parties, BikeShop and Martin to agree on a service at a price. Either party cannot apply this contract to the other party without their own consent.
  5. Build this bilateral contract through the propose-accept model.
  6. Add a choice to show Martin’s satisfaction on the service and complete payment.
  7. Add constraints to ensure the cash received meets the requirement of the service contract.

Demonstration Flow

Step 0: Setup environment

In your terminal, use this command to launch the project. (If you have not yet installed the Daml SDK, please refer to the installation instruction here.)

Since we demonstrate the flow in Daml Studio directly, we are safe to just use an empty skeleton for our example.

Here is a quick introduction on how to use Daml Studio.

In each step, we provide both Daml Code and Test Script. Simply paste them into the editor panel. If Test Script works well, we will see the Script results shown on top of Test Script. Click the Script results, and we can see the result shown on the right side.

Over the rest of this example we will be editing or copying code for both Daml Code and Test Script. Daml Code and Test Script are provided throughout this example, as well as examples of the result screen. The code and test script in bold face is the newly added or updated part from the previous step.

Step 1: Create a record type Cash

In this step we make observations on a data type Record, which is a named tuple. We will compare this with templates in the next step.

Daml code

Test script, to show what happens in the ledger when we assign values to the Cash data record type.

Result of test script

We see no active contracts in the ledger. This is because the record Cash here just keeps some data, and not yet a contract created in the ledger. We see how this is used in the next step when we create a contract with this record type.

Step 2: Create a contract for Cash

In this step we start working on contracts in ledger, and see how a contract is created from a template. The template is coded in Daml, and the simulation of contract creation is done in the test script. This example is a Cash contract, an amount of money issued by a bank (a party) and owned by somebody (a party). Note how our Cash definition has changed from data to template so that we can instantiate it and store it on our ledger.

Daml code

Test script code to show how the signatory creates a Cash contract in the ledger (that is, SwissBank issues cash to Martin).

Result of test script

Now we see a Cash contract is created in the ledger. In the Daml code we can see the template has a similar declaration as the data record (the with block). A template also requires a signatory (in the where block), the party (-ies) required when a contract is created from the template. In our test script, it is SwissBank which created this contract. Later we see choices are added in a template in the where block as well.

Step 3: Add a choice Transfer on Cash contract

We see the simple contract template in the previous step. Now we add an action item on this contract such that the owner can transfer this cash to another party. The action is done by choice(s) being added in the template. We also simulate a transfer of cash in the test script.

Daml code

Test script code to show that one party can transfer cash to another party (here Martin transfers the cash, issued by SwissBank, to BikeShop).

Result of test script

We first observe active contract(s) in ledger (uncheck Show archived).

We see one active Cash contract, which is the cash issued by SwissBank and now owned by BikeShop. We can also see archived contracts in the ledger by checking Show archived.

We now have a more complete picture. The original Cash contract (issued by SwissBank to Martin) is archived, and the present Cash contract of the same content (CHF 200.0) is now owned by BikeShop, after Martin exercised the choice Transfer. Exercising a consuming (default) choice causes the current contract to be archived (#0:0), and a new contract is created according to the code in the exercised Transfer choice (#1:1).

Also note that adding a choice with controller owner sets owner an observer automatically. For example, in the current active contract (#1:1) BikeShop is the owner (designated as O), and therefore BikeShop is an observer as a result of being made a controller on a choice in the contract. (compared to Step 2).

Step 4: Bike Repair contract requiring two signatories

Now we can enrich the example with some real business contracts between two parties. In step 3 we see a simulation of Martin transferring his Cash contract to BikeShop. In reality it is the result after the BikeShop having completed a job such as repairing Martin’s bike. In this case we add this repair contract, and till the end of this example we will have a complete workflow.

Here we will see a bilateral template BikeRepair, which requires the consent or authorization of both parties before a contract is made. In Daml terms both the bike owner (Martin) and the bike shop (BikeShop) are the signatories on the BikeRepair contract that we instantiate below.

In this step, we first see how a template of this type of contract looks in the Daml code. Then we simulate situations where either side cannot create this contract without consent of the other side. In the next step we will see how to create this type of contract through propose-accept model.

Daml code

Test script to show either side cannot create BikeRepair as it requires signatories from both bikeShop and bikeOwner.

BikeOwner (Martin) cannot create a repair contract by himself.

We see the result: missing an authorization from BikeShop.

BikeShop likewise cannot create a repair contract by themselves.

Similarly, missing an authorization from Martin the bike’s owner.

Step 5: Create Bike Repair contract through propose-accept model

In the previous step we saw that a contract which required two signatories cannot be created directly by one single party. In real life the process of forming such a contract is through two steps: proposal and acceptance. This step shows how a new type of contract, called BikeRepairProposal helps to create this type of proposal. We simulate the flow in our test script and make observations on the results.

Daml code

Test script code to show how propose-accept works to create a contract with two signatories. BikeShop initiates the proposal step by creating a BikeRepairProposal contract. Martin then accepts the proposal by exercising the choice Accept in this BikeRepairProposal contract.

Result of test script (Cash contract is not shown)

If we just see the active contract, we now see the BikeRepair contract is successfully created, with both BikeShop and Martin as signatory.

By showing archived contracts, we see the BikeRepairProposal was created and now archived after Martin has accepted.

Step 6: Add a choice to pay once bike owner is satisfied with the work

Now we can add a choice to complete the example. In the BikeRepair contract we can add a choice that the bike owner accepts the job with satisfaction, which triggers a payment of his Cash to the BikeShop. Only when this choice is exercised is the cash of the BikeOwner transferred to the BikeShop. This choice is called Pay.

Daml code

Test script to show Martin is paying for the service, assuming he is satisfied with the service.

Result of test script

First, see the active contracts in the ledger. We see that only a Cash contract is there, with BikeShop as the owner.

By showing archived contracts, we can see the whole story. Those contracts like BikeRepairProposal and BikeRepair are all archived after the repair job is completed.

Worth mentioning is that in both BikeRepair and BikeRepairProposal, SwissBank is out of the scope. In fact it meets the real world requirement that the repair job is only a matter between BikeShop and Martin, and SwissBank should not have any information about this interaction. What SwissBank knows is that a transfer of a Cash contract, issued by SwissBank, is requested by Martin.

Step 7: Make sure the Cash contract meets the currency and price due to the BikeShop

In this final step we add some constraints when exercising a choice. In our example, we make sure that the amount specified in the Cash contract is identical to the price required in the BikeRepair contract. We simulate a case when it is not the case.

Daml code

Test script (to show assertion is working: that mismatch of Cash contract and the Repair price)

We can see assertion error.

This ends the demonstration of our Bike Shop example.

Andreas’ guest lecture provided very detailed explanation. I hope this guide help you follow this example with the codes and simulation. Wish to learn more about Daml? You can always start here.

Visit for all my works. Reach me on or follow me @kctheservant in Twitter.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store