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

Introduction

Overview of Bike Shop Example

Demonstration Flow

Step 0: Setup environment

daml new bikeshopdemo --template empty-skeletoncd bikeshopdemodaml studio

Step 1: Create a record type Cash

module BikeShop whereimport Daml.Scriptdata Currency = USD | EUR | GBP | CHF
deriving (Eq, Show)
data Cash = Cash
with
issuer: Party
owner: Party
currency: Currency
amount: Decimal
test = do
bank <- allocateParty "SwissBank"
martin <- allocateParty "Martin"
let
cash = Cash
with
issuer = bank
owner = martin
currency = CHF
amount = 200.0
pure()

Step 2: Create a contract for Cash

module BikeShop whereimport Daml.Scriptdata Currency = USD | EUR | GBP | CHF
deriving (Eq, Show)
template Cash
with
issuer: Party
owner: Party
currency: Currency
amount: Decimal
where
signatory issuer
test = do
bank <- allocateParty "Bank"
martin <- allocateParty "Martin"
let
cash = Cash
with
issuer = bank
owner = martin
currency = CHF
amount = 200.0
submit bank do
createCmd cash
pure()

Step 3: Add a choice Transfer on Cash contract

module BikeShop whereimport Daml.Scriptdata Currency = USD | EUR | GBP | CHF
deriving (Eq, Show)
template Cash
with
issuer: Party
owner: Party
currency: Currency
amount: Decimal
where
signatory issuer
controller owner can
Transfer : ContractId Cash
with
newOwner: Party
do
create this with owner=newOwner
test = do
bank <- allocateParty "SwissBank"
martin <- allocateParty "Martin"
bikeshop <- allocateParty "BikeShop"
let
cash = Cash
with
issuer = bank
owner = martin
currency = CHF
amount = 200.0
cashCid <- submit bank do
createCmd cash

submit martin do
exerciseCmd cashCid Transfer with
newOwner = bikeshop
pure()

Step 4: Bike Repair contract requiring two signatories

module BikeShop whereimport Daml.Script
import DA.Date
data Currency = USD | EUR | GBP | CHF
deriving (Eq, Show)
template Cash
with
issuer: Party
owner: Party
currency: Currency
amount: Decimal
where
signatory issuer
controller owner can
Transfer : ContractId Cash
with
newOwner: Party
do
create this with owner=newOwner
template BikeRepair
with
bikeShop: Party
bikeOwner: Party
description: Text
price: Decimal
paymentDue: Date
where
signatory bikeShop, bikeOwner
test = do
bank <- allocateParty "SwissBank"
martin <- allocateParty "Martin"
bikeshop <- allocateParty "BikeShop"
let
cash = Cash
with
issuer = bank
owner = martin
currency = CHF
amount = 200.0
cashCid <- submit bank do
createCmd cash
let
bikeRepair = BikeRepair with
bikeShop = bikeshop
bikeOwner = martin
description = "fix the bike"
price = 200.0
paymentDue = date 2021 Feb 17
submit martin do
createCmd bikeRepair
pure()
test = do
bank <- allocateParty "SwissBank"
martin <- allocateParty "Martin"
bikeshop <- allocateParty "BikeShop"
let
cash = Cash
with
issuer = bank
owner = martin
currency = CHF
amount = 200.0
cashCid <- submit bank do
createCmd cash
let
bikeRepair = BikeRepair with
bikeShop = bikeshop
bikeOwner = martin
description = "fix the bike"
price = 200.0
paymentDue = date 2021 Feb 17
submit bikeshop do
createCmd bikeRepair
pure()

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

module BikeShop whereimport Daml.Script
import DA.Date
data Currency = USD | EUR | GBP | CHF
deriving (Eq, Show)
template Cash
with
issuer: Party
owner: Party
currency: Currency
amount: Decimal
where
signatory issuer
controller owner can
Transfer : ContractId Cash
with
newOwner: Party
do
create this with owner=newOwner
template BikeRepair
with
bikeShop: Party
bikeOwner: Party
description: Text
price: Decimal
paymentDue: Date
where
signatory bikeShop, bikeOwner
template BikeRepairProposal
with
proposer: Party
receiver: Party
proposal: BikeRepair
where
signatory proposer
controller receiver can
Accept : ContractId BikeRepair
do
create proposal
test = do
bank <- allocateParty "SwissBank"
martin <- allocateParty "Martin"
bikeshop <- allocateParty "BikeShop"
let
cash = Cash
with
issuer = bank
owner = martin
currency = CHF
amount = 200.0
cashCid <- submit bank do
createCmd cash
let
bikeRepair = BikeRepair with
bikeShop = bikeshop
bikeOwner = martin
description = "fix the bike"
price = 200.0
paymentDue = date 2021 Feb 17
proposalCid <- submit bikeshop do
createCmd BikeRepairProposal
with
proposer = bikeshop
receiver = martin
proposal = bikeRepair
submit martin do
exerciseCmd proposalCid Accept
pure()

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

module BikeShop whereimport Daml.Script
import DA.Date
data Currency = USD | EUR | GBP | CHF
deriving (Eq, Show)
template Cash
with
issuer: Party
owner: Party
currency: Currency
amount: Decimal
where
signatory issuer
controller owner can
Transfer : ContractId Cash
with
newOwner: Party
do
create this with owner=newOwner
template BikeRepair
with
bikeShop: Party
bikeOwner: Party
description: Text
price: Decimal
paymentDue: Date
where
signatory bikeShop, bikeOwner
controller bikeOwner can
Pay : ContractId Cash
with
cashCid: ContractId Cash
do
exercise cashCid Transfer with newOwner=bikeShop
template BikeRepairProposal
with
proposer: Party
receiver: Party
proposal: BikeRepair
where
signatory proposer
controller receiver can
Accept : ContractId BikeRepair
do
create proposal
test = do
bank <- allocateParty "SwissBank"
martin <- allocateParty "Martin"
bikeshop <- allocateParty "BikeShop"
let
cash = Cash
with
issuer = bank
owner = martin
currency = CHF
amount = 200.0
cashCid <- submit bank do
createCmd cash
let
bikeRepair = BikeRepair with
bikeShop = bikeshop
bikeOwner = martin
description = "fix the bike"
price = 200.0
paymentDue = date 2021 Feb 17
proposalCid <- submit bikeshop do
createCmd BikeRepairProposal
with
proposer = bikeshop
receiver = martin
proposal = bikeRepair
repairCid <- submit martin do
exerciseCmd proposalCid Accept
submit martin do
exerciseCmd repairCid Pay with cashCid
pure()

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

module BikeShop whereimport Daml.Script
import DA.Date
data Currency = USD | EUR | GBP | CHF
deriving (Eq, Show)
template Cash
with
issuer: Party
owner: Party
currency: Currency
amount: Decimal
where
signatory issuer
controller owner can
Transfer : ContractId Cash
with
newOwner: Party
do
create this with owner=newOwner
template BikeRepair
with
bikeShop: Party
bikeOwner: Party
description: Text
price: Decimal
paymentDue: Date
where
signatory bikeShop, bikeOwner
controller bikeOwner can
Pay : ContractId Cash
with
cashCid: ContractId Cash
do
cash <- fetch cashCid
assert (
cash.currency == CHF &&
cash.amount == price)

exercise cashCid Transfer with newOwner=bikeShop
template BikeRepairProposal
with
proposer: Party
receiver: Party
proposal: BikeRepair
where
signatory proposer
controller receiver can
Accept : ContractId BikeRepair
do
create proposal
test = do
bank <- allocateParty "SwissBank"
martin <- allocateParty "Martin"
bikeshop <- allocateParty "BikeShop"
let
cash = Cash
with
issuer = bank
owner = martin
currency = CHF
amount = 2000.0
cashCid <- submit bank do
createCmd cash
let
bikeRepair = BikeRepair with
bikeShop = bikeshop
bikeOwner = martin
description = "fix the bike"
price = 200.0
paymentDue = date 2021 Feb 17
proposalCid <- submit bikeshop do
createCmd BikeRepairProposal
with
proposer = bikeshop
receiver = martin
proposal = bikeRepair
repairCid <- submit martin do
exerciseCmd proposalCid Accept
submit martin do
exerciseCmd repairCid Pay with cashCid
pure()

Visit http://www.ledgertech.biz/kcarticles.html for all my works. Reach me on https://www.linkedin.com/in/ktam1/ 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