Continuing our blog series on Central Bank Digital Currency (CBDC), in this post, we will highlight the main features of digital money and how they can be implemented with Daml smart contracts. We are also going to show some examples in the form of the actual Daml code.
Let us consider what features digital cash should have. On the one hand, several requirements come from physical cash, such as:
On the other hand, digital currencies can provide additional features on top of what we can do with physical cash. For example:
Each feature can be selected for implementation or even all of them. Moreover, one may choose a limited implementation for some features to improve privacy further. For example, history can be tracked only by the Central Bank.
There are many technology stacks one can use to model such digital currency. A few examples are Solidity for Ethereum based ledgers, Chaincode for Fabric, and a subset of Kotlin for Corda ledgers. Looking at this list, you can already see a problem. You have to decide first which distributed ledger the solution is going to run on. The language and its feature set are going to be a result of that decision.
An excellent alternative to this approach is modeling the use case with Daml. Daml was not only specifically designed to tackle the difficulties of building smart contracts, but it can also run on a plethora of underlying infrastructures. This allows you to focus on the use case first, and commit to an infrastructure selection only once the non-functional requirements are clear. Another of Daml's strengths is the inclusion of business concepts such as agreements (Daml contracts), signatories (Daml signatories), privacy (Daml observers), rights (Daml controllers), and more. Combining this with the modern functional programming paradigm makes software development more efficient and less error-prone. Let’s see how these properties of Daml benefit the use case of CBDC. We will build a simplified Daml model in multiple steps, capturing some of the main features that CBDC should have.
Daml’s focus on capturing rights and making trust relationships transparent allows us to ensure that the Monetary Authority has the final say about the creation and destruction of CBDC. We achieve that by recording which party is the issuer of CBDC on the Daml contract that represents it. With this information, it is easy to verify whether one recognizes the issuer as the monetary authority.
As discussed above, the issuer should be recorded on the Daml contract. But how can we ensure that the issuer has authorized the creation of the contract representing CBDC? In other words, is it impossible to impersonate the issuer? The answer is yes: each Daml contract has verifiable signatories.
Traditionally, signatories are parties who need to sign a contract willingly for it to be binding. A signatory in Daml is similar, but they use digital signatures. For our example, this means that if the issuer is not only mentioned in the Daml Contract but is also declared as a signatory, it becomes impossible for any other party to create the contract that represents CBDC without the issuer’s consent.
A simplified Daml template capturing this would look something like this:
Similarly to how physical cash can be transferred, digital cash needs to implement that capability as well. In Daml, we capture this right of the owner with a so-called choice. Extending the CBDCv1 model from before with the choice called SimplifiedTransfer results in the following:
The owner can only exercise this choice if they also say who the receiver should be. If they do that, two things happen atomically.
When we say atomically, we mean that either both of these things complete successfully or none of them if anything goes wrong.
Let us show how this looks like with a quick example. Let’s assume that the Central Bank issued money and named Alice as the first owner.
status | issuer | owner | amount | currency |
active | 'Central Bank' | 'Alice' | 100 | USD |
Then Alice exercises the choice to give the money to Bob. This action results in one archived and one active contract on the ledger:
status | issuer | owner | amount | currency |
archived | 'Central Bank' | 'Alice' | 100 | USD |
active | 'Central Bank' | 'Bob' | 100 | USD |
As we have modeled so far, the only signatory of CBDCv2 is the issuer (i.e., the central bank). The modeled currency completely lacks the consent of its owner. Two main implications follow. Firstly, the issuer can archive the contract unilaterally, effectively taking the money away from the owner. Secondly, money modeled in such a way can be given to someone without their consent. That consent is relevant because owning money usually comes with responsibilities (e.g., think of taxes or that owning physical counterfeit money is illegal).
To fix this, we add the actual owner to the list of signatories.
However, after this change, the issuer can not create this currency where the owner is an arbitrary party because they do not have their consent. To make this work, the issuer can issue the money and add itself as the owner. In the second step, they can propose to transfer it to another party. If that party accepts, then all authorizations have been collected, and the transfer can be settled.
We saw that the model CBDCv3 requires the consent of the receiving party before the transfer, but how do we ask for it?
You can think of a digital payment as a two-step process. The initiator first makes a proposal or a request to transfer to the recipient. Then the new owner can choose to accept the offer for the transaction to be executed.
Note that the choice Transfer consumes the CBDCv4 contract. This consumption means the contract can be used only for one transfer. This behavior prevents double-spending.
When paying in a shop with physical cash, the merchant won’t know the previous and subsequent holders of the bill. They will also not necessarily get to know the identity of the buyer. This level of privacy is an important feature that we would want to model as well. Daml enables modeling of such properties:
Thanks to these properties, anonymous payments can be modeled easily. For CBDCv2, subtransaction privacy guarantees that the receiver does not learn the identity of the payer. This is because the only part of the transaction that is disclosed to the receiver is the one creating the CBDCv2 contract. The receiver does not learn the details of the old contract..
While paying with CBDCv2 is anonymous by design, this is not the case for CBDCv4. Due to the extra step of the payer requesting the transfer and the receiver accepting it, the receiver also sees the payer embedded in the TransferRequest. Is there a way to make payments anonymously using the same approach as CBDCv4? Let’s take the original CBDCv4 template and add a new choice called AnonymousTransfer:
The choice transfers the money from the owner to the receiver in two steps: first, it creates a TransferRequest towards the issuer and accepts it. The second step is creating a new TransferRequest from the issuer to the receiver. Although this is a two-step process, it is encapsulated in a transaction, which guarantees atomicity. The following diagram shows this in a transaction tree:
As explained above, the choice AnonymousTransfer creates a TransferRequest to the receiver in the final step. Sub-transaction privacy guarantees that this is the only step disclosed to the receiver, as highlighted in the diagram. The receiver can then accept the request in a new transaction. Note that the sender does not participate in this new transaction at all, so they cannot see the resulting contract either.
Daml naturally supports auditing and tracking transactions. The ledger can be seen as an immutable database. It stores the contracts (identified by their contract ids) and the history of each transaction. Immutability and distributedness also contribute significantly to the integrity of the database.
To further fine-tune trackability of the contracts, the observers of a Daml contract can also be customized to allow more transparency and visibility.
Authority has the option to control who can own money programmatically. For example, they can maintain blacklists or whitelists.
Transactions can be grouped to form a more complex transaction. As mentioned in an earlier example, a Daml choice can carry out multiple money transfers in an atomic way. This is why we say it is one transaction. This feature is often leveraged in Delivery Versus Payment scenarios without a trusted third party.
As Daml is a programming language, it provides ways to reliably test a Daml model to verify the features mentioned above. For example:
As we have seen, digital money can add a large number of new features to the ones of conventional physical cash. Daml can easily be used to implement all of these features of digital money. The tools provided in the Daml SDK and techniques discussed in the documentation make it easy to write correct and testable code. The implementation is compact yet easy to read. Daml can be deployed on various infrastructures ranging from centralized databases to distributed ledgers. The next entry in this series will be covering the infrastructure side of the solution.
The complete source code, along with tests, can be downloaded from our GitHub repo.
Daml has also a new learn section where you can begin to code online:
This blog post was written by Gabor Hosszu and Richard Kapolnai from Digital Asset.