Holdings

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:

  1. we first create accounts for Alice and Bob at the Bank
  2. we then proceed to issue a cash instrument, representing tokenized dollars
  3. 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 CreateAccount workflow.

  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 implementations.

Similarly, we define a holding factory, which is used within an account to create (Credit) holdings.

  holdingFactoryCid <- toInterfaceContractId @Holding.F <$> submit bank do
    createCmd Fungible.Factory with
      provider = bank
      observers = fromList [("Settlers", S.fromList [alice, bob])]

This factory contract instantiates a specific implementation of holdings, which are defined in Daml.Finance.Holding.Fungible and are both fungible, as well as transferable.

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 owner. 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 CreditAccount workflow. 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.

To summarize

  • 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?

You might be wondering why we use account factories and holding factories instead of creating an Account or Holding directly.

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.

Summary

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.