In the first part of my two-part sub-series of this DAML Masterclass about the Finance Library, I started to reverse engineering the Financial Library reference application.
I have identified 5 Big Ideas in it, out of which I have presented 3 in the first part. Here are the remaining two ideas.
Big Idea #4: a dynamic set of signatories
Sometimes it is necessary for a contract to have a dynamic set of signatories.
This can be important because the signatories authorise in advance the choices of the contract.
This mechanism is working also in a simple propose/accept pattern, which makes it possible to create contracts signed by multiple parties.
The propose/accept pattern in general works like this: The proposal contract has a variable set a signatories. All necessary signatories of the final contract get added to the set of signatories step by step through the evolution (archival and creation) of the proposal contract instances. By the time all intended signatories have signed the proposal contract, they have authorised the creation of the final contract, containing a fixed set of signatories, which can be pulled off by any one of them. (See about this topic my previous blog post How DAML smart contracts are digital twins of human relationships.)
Something similar works in the case of a settlement chain, presented in the third section (Big Idea #3: multistep settlement chain) of the first part of this sub-series, where all intermediary senders of the individual steps want to authorise the transfer of their allocated funds (asset deposit contracts) in advance. This is the purpose of asset allocation.
This happens so, that those senders, who already have allocated their funds (members of the
sendersDone list), become signatories of the next
SettlementInstruction contract instance, while those senders who haven’t yet allocated their funds (members of the
sendersPending list), become observers:
The members of the
sendersDone and the
sendersPending list are collected by the following list function, which uses the Either data type and the
The senders who have already allocated their funds can be recognized by the fact that they are senders of steps where the optional asset deposit contract id field has been filled in already, which is checked by the
isSome boolean function. The
partitionEithers function creates a partition based on the Either values so that it collects the
Left a values into the first partition, and the
Right a values into the second partition.
To make sure that you fully understand what the
Either data type and the
partitionEithers function does, check out a simplified version of the function in the DAML REPL. The DAML expression below partitions the odd and even values of a list. In order for it to work, we need to add the
DA.Either library module.
daml> :m + DA.Eitherdaml> let odd (x : Int) = x % 2 == 1daml> let (oddMembers, evenMembers) = partitionEithers $ map (\x -> if odd x then Left x else Right x) [1..10]daml> oddMembers[1,3,5,7,9]daml> evenMembers[2,4,6,8,10]daml>
Big Idea #5: advanced ledger update: fetch and archive
This one might seem innocent because the
fetchAndArchive function (defined in the Utils module) is simple and short, and does nothing more than what its name implies:
But this function is conceptually important, for the following reason:
DAML ledger updates follow the UTXO model, so they are in some sense similar to Bitcoin’s operating model. Every ledger update is a transaction which has zero or more inputs, which may or may not be consumed by the transaction, and zero or more outputs.
DAML doesn’t have a ledger update transaction syntax separate from contract template syntax. Every ledger update gets performed on either a contract template with issuing a
create command, or on an existing contract instance with the
exercise <contract> <choice> command.
One might wonder, how a DAML ledger update transaction can consume two or more input contracts. And the answer is, that the update is programmed as a choice on a specific contract, and the choice needs to contain an update which fetches the other input(s) of the transaction, and archives them (of course, only if we want the input to be consumed). The standalone
fetchAndArchive function is a shorthand for this important case. So a transaction for instance which consumes two existing contract instances as inputs, conceptually looks like the following: