Fix my Bike Again: Demonstration of Navigator in Daml


In my previous works on Daml, I keep using Daml Studio to learn, practice, and test this modeling language. Besides code editing, Daml Studio has an environment of script execution, which is good for code development and workflow simulation. Through simulation we can observe the lifecycle of contracts in the Daml ledger and make interactions with these active contracts through exercising choices.

Daml comes with another good tool, Navigator, which gives us a more intuitive graphical user interface (GUI) and lets us interact with the contracts on the fly. No test script is needed as everything is done on the GUI. In this article, we are using the BikeShop example again and see how the demonstration is done with Navigator.

You can refer to my previous article about the BikeShop example and how to use Daml Studio for simulation. We will use the same set of code, and you can make comparisons between these two tools.


While Daml Studio comes with everything for simulation, Navigator is a frontend of a stack, in which the Daml code is first compiled and then working with a Daml ledger. Our demonstration is using Daml Sandbox, while Navigator can work with other Daml ledgers.

The launch of this stack is done in a simple Daml command, with proper configuration in the configuration file daml.yaml. We are using the empty skeleton template as it is good enough to build what we need in this demonstration.

Demonstration Setup

Create a project bikedemo with template empty skeleton.

daml new bikedemo --template empty-skeleton
cd bikedemo

We need to work on two files.

We first modify the configuration file, daml.yaml. The basic configuration is good enough for demonstration. We just change the parties to those relevant to us. Remove Alice and Bob, and insert Martin, BikeShop and SwissBank. These will be seen when Navigator is launched.

sdk-version: 1.10.0
name: bikedemo
source: daml
- Martin
- BikeShop
- SwissBank

version: 0.0.1
- daml-prim
- daml-stdlib
- daml-script
- --wall-clock-time

Also we create the file daml/BikeShop.daml. Here is the code we directly copy from my previous article. We do not need a test script here as we do not test it in the Daml Studio.

module BikeShop wheredata Currency = USD | EUR | GBP | CHF
deriving (Eq, Show)
template Cash
issuer: Party
owner: Party
currency: Currency
amount: Decimal
signatory issuer
controller owner can
Transfer : ContractId Cash
newOwner: Party
create this with owner=newOwner
template BikeRepair
bikeShop: Party
bikeOwner: Party
description: Text
price: Decimal
paymentDue: Date
signatory bikeShop, bikeOwner
controller bikeOwner can
Pay : ContractId Cash
cashCid: ContractId Cash
cash <- fetch cashCid
assert (
cash.currency == CHF &&
cash.amount == price)
exercise cashCid Transfer with newOwner=bikeShop
template BikeRepairProposal
proposer: Party
receiver: Party
proposal: BikeRepair
signatory proposer
controller receiver can
Accept : ContractId BikeRepair
create proposal

To launch the stack,

daml start

This command will first compile our code into DAR files. Then both Daml Sandbox and Navigator are being launched.

Launch Daml Sandbox and Navigator with one command

Navigator is launched automatically, or you can access it http://localhost:7500 on a browser.


In “Choose your role”, we see those parties configured in daml.yaml.

Now we are ready for using Navigator to perform our interaction.


Login with any party (say Martin). We see Martin’s view in Navigator.

There are two views in Navigator: Contracts and Templates. In Contracts, we will see active contracts, and archived contracts if we check “include archived”. In Templates, we will see the templates coded in our model.

You can refer to my previous article about Contracts and Templates in Daml.

Contracts Page

Templates Page

Currently we see no contracts in the Contracts page, meaning that there are no active contracts seen by Martin. In the Templates page, we see the three templates coded in the model: Cash, BikeRepairProposal and BikeRepair.

We can try other parties (SwissBank and BikeShop) and see similar results. As our model is newly deployed, there are no active contracts yet in the ledger.

We first login as SwissBank. Select Template Cash. A page is shown requesting parameters defined in the template Cash. They are issuer, owner, currency and amount.

To create a contract with template Cash, we need to provide certain information. According to our demonstration, we input information

  • issuer: SwissBank
  • owner: Martin
  • currency: CHF
  • amount: 200.0

A pull-down menu is given if we define a data type as enum (like currency in Cash template).

After we Submit, an active Cash contract is now seen in SwissBank.

An active Cash contract in the ledger.

Note the contract ID (000c3d9…) of this Cash contract. Click this contract and we see the details.

Details of this Cash contract, and choices available

Besides the detail, we also see the two choices available in this Cash contract: Transfer and Archive. The Archive is the default one for all contracts. Transfer is the choice coded in the model.

Here Martin is in Observers, which means that Martin can see this contract. Logout from SwissBank and login as Martin. We immediately see the same Cash contract in Martin’s contracts page (note the same contract ID).

Martin sees the same result as an observer

We say this Cash contract is active in the ledger, and currently visible to both SwissBank and Martin.

Now Martin visits the BikeShop asking for a repair service for his bike. BikeShop creates a BikeRepairProposal contract with Martin.

Login as BikeShop. First, we see nothing (not the Cash contract) in BikeShop’s view. We know that there is an active Cash contract in the ledger, but it is only the matter between SwissBank and Martin. It is not visible to BikeShop.

BikeShop sees nothing on the active Cash contract.

Now go to templates and select BikeRepairProposal. Fill in the required parameters and click Submit.

  • proposer: BikeShop
  • receiver: Martin
  • proposal.bikeShop: BikeShop
  • proposal.bikeOwner: Martin
  • proposal.description: “Fix the bike”
  • proposal.price: 200.0
  • proposal.paymentDue: 2021–03–05

With this, now there is an active BikeRepairProposal contract, visible by BikeShop.

BikeRepairProposal: proposed by BikeShop.

Per our template design, Martin the receiver is set as Observers. Besides, Martin the receiver can accept this contract. Logout from BikeShop and login Martin.

We now see two active contracts in Martin’s view. The Cash contract issued by SwissBank, and the BikeRepairProposal contract created by BikeShop.

Martin sees the BikeRepairProposal contract

Click the BikeRepairProposal contract for the details. Assuming Martin agrees to the term and accepts this proposal. In Daml term Martin is going to exercise the choice Accept in BikeRepairProposal contract.

We can click the Choice and see the choices Martin can act here. This is the same as Martin doing this inside the contract.

Here select Accept. This comes a page showing the Contract information and further information required (nothing is required in this choice). After everything looks good, click Submit to exercise this choice.

After the ledger is updated, we now see the BikeRepairProposal contract gone, and a new BikeRepair contract is there. This is the service contract between Martin and BikeShop, with both authorization (and consent), showing the job detail and the price.

By checking Include archived, we will see the BikeRepairProposal contract. It was archived after Martin accepted the proposal.

The BikeRepairProposal (middle, grey in colour) gets archived after acceptance by Martin.

And of no surprise, we see this same BikeRepair contract in BikeShop.

Same BikeRepair contract, binding both Martin and BikeShop.

Assuming Martin is happy with the service and uses his Cash contract, issued by SwissBank, to pay BikeShop.

Login as Martin, in the BikeRepair contract, and exercise the Pay choice. Let us first see what is needed when exercising this choice.

A Cash Contract ID is needed to exercise the Pay choice.

Besides the contract detail, a Cash contract ID is required in order to exercise the Pay choice. Therefore we need to copy the Cash contract ID first.

Go back to the Cash contract, copy the ID. Here it is.

Martin’s Cash Contract ID: 000c3d9…

Now fill in the Pay choice in BikeRepair contract with this Cash contract ID and click Submit.

Fill in the Cash Contract ID and click Submit

After Pay choice is completely exercised, we see no more active contracts in Martin’s view.

No more active contracts in Martin’s view

And those previously active contracts were all archived according to the code. The obligation he needs to fulfil in the BikeRepair contract (agree to pay 200.0 to BikeShop for the repair service) and his asset Cash contract is paid to BikeShop. Therefore no more contractual binding on Martin.

All previous active contracts got archived (grey in colour)

In BikeShop’s view, we only see the active Cash contract (contract ID: 00ddfc05…). It is the result after his fulfilment of service in the BikeRepair contract. The detail is same as Martin’s previous Cash contract except for that the owner is now BikeShop.

BikeShop sees an active Cash contract

Similarly, the BikeRepair contract is archived as everything in that contract is fulfilled.

BikeRepair contract is archived (grey in colour)

Finally, make observations from SwissBank. There is one active Cash contract and one archived Cash contract seen. The active one is the one owned by BikeShop, while the archived one is owned by Martin. As we see here, though the content (CHF 200.0) is identical, these two are different contracts (see the contract IDs).

SwissBank only sees Cash contracts.


There are two observations during our demonstration.

Data privacy is properly enforced in Daml. While contracts are active in the ledger, whether they are visible to individual parties depends on the model we design in the code. For example, SwissBank only sees one active Cash contract, first created and owned by Martin and later owned by BikeShop. SwissBank has no information why this happens and the business (repair contract) between Martin and BikeShop. This meets the business requirement in real life.

Besides, in Navigator, a choice visible to a party does not mean that this party can exercise it. It is still subject to the model we design in the code. For example, in the Cash template only the owner can exercise Transfer choice. We can do a quick test: login to SwissBank, select the Cash contract and exercise Transfer choice. The transfer fails. It also meets real life requirements as no one except for the owner can transfer the cash, not even the issuer.


We have repeated our demonstration in the previous article with the Navigator, which gives us a user friendly browser-based tool to interact with our model deployed in the ledger (here we are using Sandbox). Hope this brings you more information when you learn and practice with Daml. You can refer to Daml documentation for more about Navigator.




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

Love podcasts or audiobooks? Learn on the go with our new app.

“Hack” your own Instagram — Ep.1 Instagram’s Inferred Interests

Migrate Octopus Variables to Azure DevOps Library

Delivering Tangible Value with Redis

Java 8 Functional Programming Simplified

Centralizing our Doctor Data

It is possible to save time when creating a subscription with Github Login Integration

How to Install Apache on AWS EC2 Instance Ubuntu 18.04

Demon Expedition Campaign “Poker Game”

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
KC Tam

KC Tam

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

More from Medium

How To Build Apps On Rametron

How To Build Apps On Rametron

Learn to Build a Swap Application with Solana Wallet Adapter and Raydium SDK — Part 2

Budget Tracking Using Active Record & Ruby

Deploy: StackPath’s web application firewall to protect your Solana RPC