ACH Payments on Smart Contracts — A Daml & Dwolla Example
Smart contracts are great tools for storing value in digital form as well as defining the behavior of how that value can be transferred, split, locked or simply destroyed. However, describing smart contract state transitions without specifying who is allowed to perform them and when, is like playing a game of chess where each player can move any piece on the board regardless of their turn. In this regard Daml, the platform-agnostic smart contract programming language developed by Digital Asset, shines.
Daml provides a higher level abstraction of the business logic from the nitty-gritty details of the data persistence layer implementation, be it a relational database or a blockchain. Its smart contracts also offer fine-grained permissions that hide all of the public address and transaction signing cryptography (should there be any) under the concept of a Party, a primitive type of the Daml language.
In this post I’ll try to demonstrate how to use Daml and its permissions in order to transfer value between parties in the form of ACH Payments. For this we will use Drachma — a library of Daml modules with a Python app that wrap the powerful Dwolla APIs for interfacing with the ACH Network. To set the stage, let’s use a scenario similar to the one in Settling a Daml Payment Obligation on Ethereum.
This time, Alice is looking to mow the lawn of her freshly painted house. She gets an offer from (you guessed it..) Bob the Gardener in exchange for $59.99. Bob, being a Drachma user, can set up a Daml agreement with Alice and receive payment in the form of an ACH transfer that will deposit the funds directly to his savings bank account. Daml will handle all the workflow and permissions between the two parties and Dwolla will power the ACH transaction.
Bootstrapping Alice to the ledger
Alice would like to accept Bob’s offer but unfortunately is not a Drachma user yet. She decides to get onboard and asks the Drachma operator to extend her a
UserInvitation. (In Drachma, the “operator” is a trusted third party responsible for on-boarding users and servicing their requests):
Now that Alice is a Drachma user and has a
User role contract, she will need to register herself as a Dwolla personal verified customer and attach her checking bank account from which she will send the funds. To kick off the registration process she exercises the
User_VerifiedCustomerRequest choice on her role contract and provides the necessary fields for the Dwolla API
The operator forwards the request to Dwolla and a successful response leads to the creation of a personal verified customer resource for Alice as well as an equivalent Daml
Customer contract for Alice.
Adding Alice’s bank account
The next step for Alice is to attach her bank account as a Dwolla Customer funding source. To accomplish that, she will exercise the
Customer_UnverifiedFundingSourceRequest choice on her
The request is once again forwarded to Dwolla which creates a funding source resource for Alice and the corresponding Daml
Unverified Dwolla funding sources however may only receive funds. In order for Alice to be able to send funds, she will need to verify her bank account. Dwolla offers a number of options for verification of a funding source — among them is the Micro-deposit verification process.
In this workflow, Alice will instruct Dwolla through the operator to transfer two deposits of less than $0.10 to her bank account. After the two random amounts post, she can fetch them from her statement and use them to verify her account. Let’s see how this unfolds in Drachma:
Verifying Alice’s bank account
Alice navigates to her
FundingSource contract and exercises the
FundingSource_InitiateMicroDeposits choice. This initiates the two random micro deposits and creates a micro-deposits resource on Dwolla’s side and a
MicroDeposits contract in Daml. According to Dwolla, it will take 1–2 business days until the status of the deposits changes from pending to processed.
Thankfully we are on a sandboxed environment so we don’t have to wait! Alice’s micro deposits have already posted and she is ready to proceed with verification. She exercises the
MicroDeposits_Verify choice on the
MicroDeposits contract and passes the two amounts as arguments.
The amounts make their way to the Dwolla API and if they match the ones sent, the bank account gets verified! Alice is now a verified customer with a verified bank account and is ready to make a deal with Bob.
Bob makes an offer Alice can refuse
Daml does a heck of a job modeling a party’s rights and obligations. Therefore Alice can never get into an obligable position against her will.
Bob goes ahead and drafts a
GardeningOffer contract. He becomes the signatory of that contract and offers Alice the choice to accept it or refuse it. In his offer, Bob mentions the amount of money he is to receive for his work, an id for the payment (should Alice accept it) and finally a list of his trusted Drachma operator parties that Alice can use for the ACH payment.
Notice that if Alice (the beneficiary) chooses the
AcceptOffer happy path, a
GardeningContract and a
ReceiveFundsRequest contract will be created. The
GardeningContract will be the official agreement between Alice and Bob and the
ReceiveFundsRequest will be a contract addressed to Bob in order to receive payment.
Let’s take a closer look at the body of the
AcceptOffer choice. It requires Alice to pass her
Customer contract id as well as the id of her bank account that she just verified. Daml will fetch the
Customer contract and assert that it belongs to Alice and that the operator is one that Bob also trusts. It will then create two
Metadata records that will piggyback on the ACH payment and help identify it later. Finally it will exercise the
Customer_SendFunds choice on behalf of Alice and create the
GardeningContract agreement between the two parties.
It’s official. Per the
GardeningContract Bob must mow Alice’s lawn and Alice must reimburse Bob with $59.99 in the form of an ACH transfer. Bob may start mowing, but he also needs to respond to the
ReceiveFundsRequest and specify where he would like the funds to be deposited.
For that he exercises the
ReceiveFundsRequest_AcceptFunds choice and passes his bank account id and optionally any clearing instructions addressed to his bank. This creates a
TransferAgreement that is validated by the operator and converted into a
TransferRequest which once again hits the Dwolla API. The request will create a transfer resource in Dwolla’s side and a
Transfer Daml contract containing the details of the ACH transfer.
Settling the deal
Being a top professional, Bob has done an awesome job mowing Alice’s lawn. The ACH Network has also processed the fund transfer between Alice and Bob’s bank accounts. What is left is to settle the
GardeningContract. Before we do that let’s take a look at it:
The contract is signed by both Alice and Bob (gardener and beneficiary are both signatories). Recall that neither party was forced into this obligation, as Bob created a
GardeningOffer and Alice accepted. Daml would refuse to create this contract outright, should either Alice or Bob attempt it, since it would be missing the consent (signature) of the other party.
To settle it, Alice can exercise the
SettleTransfer choice and pass the
Transfer contract id as proof of payment. Daml will first assert that the contract has not already been settled and then fetch the details of the transfer in order to validate them against the contract terms. The sender, receiver, amount, status of transfer and invoice id are checked. Finally the contract is updated with a populated
optAchId field containing the id of the ACH transfer.
We have used the power of Daml and Dwolla to create a multi-party workflow that triggers an ACH transfer and settles an agreement. I would encourage you to further explore the Drachma GitHub project and submit any valuable feedback or contributions! I am leaving you with a snapshot of the final Daml ledger active contract set. Cheers!