This tutorial introduces the core asset model of the library through a simple example. The purpose is to illustrate the concepts of account, instrument, and holding, as well as to show some useful patterns when working with Daml interfaces.
We are going to use the Daml Finance library to create tokenized cash on the ledger. This is done in three steps:
- we first create accounts for Alice and Bob at the Bank
- we then proceed to issue a cash instrument, representing tokenized dollars
- we finally credit a cash holding to Alice’s account
The holding contract represents the record of ownership on the ledger for Alice’s tokenized cash.
Run the script¶
In order to show how this works in practice, let us explore the
Holding script step-by-step.
Create Account, Holding, and Instrument Factories¶
The first instruction instantiates an account factory. This is a template that is used by a party
(the Bank in this case) to create accounts as part of the
accountFactoryCid <- toInterfaceContractId @Account.F <$> submit bank do createCmd Account.Factory with provider = bank observers = empty
Notice how the
ContractId is immediately converted to an interface upon creation: this is
because our workflows, such as
CreateAccount, do not have any knowledge of concrete template
Similarly, we define a holding factory,
which is used within an account to create (
holdingFactoryCid <- toInterfaceContractId @Holding.F <$> submit bank do createCmd Fungible.Factory with provider = bank observers = fromList [("Settlers", S.fromList [alice, bob])]
Finally, we create a factory template which is used to instantiate token instruments.
tokenFactoryCid <- toInterfaceContractId @Token.F <$> submit bank do createCmd Token.Factory with provider = bank observers = empty
Open Alice’s and Bob’s Accounts¶
Once the factory templates are setup, we leverage the
CreateAccount workflow to create accounts
at the Bank for Alice and Bob.
The creation of an account needs to be authorized by both Alice and the Bank. Authorization is collected using a propose / accept pattern.
aliceRequestCid <- submit alice do createCmd CreateAccount.Request with owner = alice custodian = bank aliceAccount <- submit bank do exerciseCmd aliceRequestCid CreateAccount.Accept with label = "Alice@Bank" description = "Account of Alice at Bank" accountFactoryCid = accountFactoryCid holdingFactoryCid = holdingFactoryCid observers = 
The Bank acts as the
custodian, or account provider, whereas Alice is the account
Bob’s account is created in a similar fashion.
Create the Cash Instrument¶
In order to credit Alice’s account with some cash, we first create a cash instrument. An instrument is a representation of what it is that we are holding against the Bank. It can be as simple as just a textual label (like the Token Instrument used in this case) or it can include complex on-ledger lifecycling logic.
let instrumentId = Id "USD" instrumentVersion = "0" instrumentKey = InstrumentKey with issuer = bank depository = bank id = instrumentId version = instrumentVersion now <- getTime submit bank do exerciseCmd tokenFactoryCid Token.Create with token = Token with instrument = instrumentKey description = "Instrument representing units of a generic token" validAsOf = now observers = empty
Notice how in this case the Bank acts both as the issuer and depository of the cash instrument. This means that we fully trust the Bank with any action concerning the instrument contract.
Deposit Cash in Alice’s Account¶
We can now deposit cash in Alice’s account, using the
Alice creates a request to deposit
USD 1000 at the Bank, the Bank then accepts the request and
a corresponding Holding is created.
aliceRequestCid <- submit alice do createCmd CreditAccount.Request with account = aliceAccount instrument = instrumentKey amount = 1000.0 aliceCashHoldingCid <- submit bank do exerciseCmd aliceRequestCid CreditAccount.Accept
You can imagine that the latter step happens only after Alice has shown up at the Bank and delivered physical banknotes corresponding to the amount of the deposit.
The holding contract represents the record of ownership on the ledger. In this scenario,
Alice’s holding of
1000 units of the cash instrument means that she is entitled to claim
USD 1000 from holding’s custodian, the Bank.
- an instrument defines what a party holds (the rights and obligations).
- a holding defines how much (i.e., the amount) of an instrument and against which party (i.e., the custodian) the instrument is being held.
Frequently Asked Questions¶
What are accounts used for?¶
An account is used as the proof of a business relationship between an owner and a custodian: Alice may transfer cash to Bob because Bob has a valid account at the Bank.
This is done to avoid that Alice transfers cash to Charlie without Charlie being vetted and acknowledged by the Bank.
The account is also used to determine who is required to authorize incoming and outgoing transfers. For the account at hand, the owner acts as a controller for both incoming and outgoing transfers. The other options are explained as part of the settlement tutorials.
Why do we need factories?¶
This is done to avoid having to reference the
Daml.Finance.Holding package directly in the
user workflows (and hence simplify upgrading procedures).
This pattern is described in detail in the Daml Finance Patterns page and is based on the assumption that there are very few factory contracts which are setup on ledger initialization.
You now know how to setup basic accounts, holdings, and instruments. The key concepts to take away are:
- Holdings represent the ownership of a financial instrument at a custodian.
- Instruments define the economic terms of a financial contract.
- Accounts ensure that only known parties can obtain ownership.
- Factories are used to create the respective contracts without having to depend on implementation packages.