DAML is a great open source language for modeling rights and obligations between multiple parties.
A DAML agreement between two parties may require the obligor to perform an action such as provide health treatment, paint a fence or transfer an amount of money to the beneficiary. This obligation is conveniently expressed in the
agreement field of a DAML smart contract and is settled off-ledger.
Providing health treatment or painting someone’s fence means interacting with the physical world and therefore such obligations must be settled off-ledger. The same though doesn’t hold true when transferring value between parties, especially digital tokens.
Enter Hemera: A DAML library and accompanying app that lets you interact with the Ethereum Network. With Hemera you can build a DAML workflow that deploys and transacts with Ethereum smart contracts but also transfers Ether or any ERC-20 compliant token between addresses.
In this post we will use Hemera to settle a payment obligation created between two parties in a DAML workflow. We will do that by transferring Ether from the payer’s address to the payee’s and evidencing the transaction on the DAML ledger. To accomplish this, will draw inspiration from the example illustrated in DAML’s Ledger Model documentation page. The twist is that instead of transferring IOUs, we will transfer Ether.
Let’s suppose that Alice wants her house painted. She gets an offer from Bob the Painter in exchange for 1 Ether. Alice also happens to be a Hemera user, meaning she has a Hemera user role DAML contract enabling her to interact with the Ethereum Network. Interaction happens when Alice exercises non-consuming choices on her user contract and creates requests which are serviced through an operator party. The operator may be a third party known to Bob, or Bob himself. The operator’s responsibility is to help Alice build her Ethereum transaction and then forward it to the network. In Hemera all transaction signing happens locally for the user, so Alice will never have to share her private key with anyone.
Alice thinks that Bob’s offer is a bargain(!), so let us go ahead kick things off with a DAML scenario we will name
paintTheHouse. We will first bootstrap Hemera for Alice and then have Bob create his offer:
PaintOffer contract that Bob created, he specified himself as the painter and Alice as the beneficiary. He also added any trusted Hemera operator parties (in our case “Operator”), the amount of Ether he wants for his work and the deposit address for the Ether. The
PaintOffer template looks like this:
PaintOffer contract gives Alice (the beneficiary) a choice to accept Bob’s offer by exercising
AcceptOffer and passing in the address for the source of the funds and her Hemera user role Contract Id. Execution of the
AcceptOffer choice will result in the creation of a
PaintContract instance which is a binding agreement between Alice and Bob that obligates Bob to paint Alice’s house and obligates Alice to remit 1 Ether to Bob.
As a side effect,
AcceptOffer will also exercise the
User_SendEther choice on Alice’s user contract which in turn will create a Hemera request for the transfer of 1 Ether to Bob’s address. After Alice exercises
AcceptOffer, the resulting state of the DAML ledger is the following:
Great! As expected, we have successfully created a
PaintContract between Alice and Bob, as well as a
TransferRequest contract between Alice and the Operator. While Bob may start painting Alice’s house, the
TransferRequest contract will follow the standard Hemera Transfer workflow. Note that Bob will be unaware of the evolution of this transfer request flow (unless of course he acts as the operator), until it is time for Alice to present him evidence that she has made the payment. This is a feature of the privacy model in DAML that you get for free. The process of creating an Ethereum transaction is Alice and the Operator’s business — all Bob cares about is getting paid. After all we want him focussing on his job!
To service the
TransferRequest, the Operator will fetch the nonce of the source address (
0xC06b51647e3A52d770547B97b1d3c5CDdF264B85) as well as the default values for gas and gas price. the Operator will then archive the
TransferRequest and create an
UnsignedTransferTransaction with a
txToSign field containing the RLP encoded raw transaction that represents the Ether transfer. Below is a visualization of the
UnsignedTransferTransaction instance taken from the Navigator:
As I mentioned before, no one but Alice has access to the private key which unlocks the funds of the
from address. Therefore it is Alice’s turn to act. She needs to take the hex-encoded raw transaction in the
txToSign field and use her private key to sign it. Since manual transaction signing can be tedious, Hemera optionally provides a tool that Alice can run locally and sign the transaction! Finally, if Alice does not trust the transaction the Operator gave her to sign matches the details of the original request, she can easily verify by using any third party RLP decoder or service that she is comfortable with.
As soon as Alice signs the transaction, she passes the signed payload to the
UnsignedTransferTransaction_Sign choice converting it to a
Now when Bob finishes painting her house, Alice can broadcast the signed transaction to the Ethereum Network via the
SignedTransferTransaction_Send choice. Once sent, the Operator will update the
sendStatus variant of the
SignedTransferTransaction contract from
Sent and will include the time the transaction was sent, the version of the Ethereum node that sent it and last but not least, the transaction hash:
If you are curious, feel free to take a closer look at this transaction in etherscan.io by following this link.
We are almost done! There is one final step left and that’s settling the
PaintContract. Before we do this let’s have a look at it at the Navigator:
as well as take a deeper dive at its template:
Alice is given a choice on the
SettleTransfer where she can provide the Contract Id of the transfer transaction she signed and sent. The body of the
SettleTransfer choice will first assert that the
PaintContract has not yet been settled. It will then fetch the transfer transaction and assert that its details match the ones of the specified contract terms. It will then proceed to archive the
SignedTransferTransaction contract (so that Alice cannot provide it as proof to another contract). Finally it will update the
settled state to
True and populate the
txHash field with the Ethereum transaction hash of the transfer.
And that’s it! We have settled the payment obligation on Ethereum and successfully updated the
To recap, here’s a diagram of the entire workflow from start to finish:
If you want to create your own DAML + Ethereum workflow you can fork the Hemera GitHub repo. Also if you have any feedback or want to contribute to the project feel free to comment or submit a PR!