How we used Ethereum and DAI to create, tokenise and settle a ‘self-executing’ smart invoice
Note to the reader: The target audience for this blog post are mainly developers familiar with Blockchain and Smart Contracts. We have abstracted away business terms in order to focus on the technical process.
Not all developers have strong backgrounds in business, economics and finance. Therefore, we recommend reading our blog post on these aspects.
The open-sourced code that we share is intended to be inspirational and we do not hold ourselves responsible for any undesired or unexpected behaviour resulted from its usage.
Github repository for the open-sourced project can be found here: https://github.com/TradeshiftFrontiers/frontiers-smartinvoice-blockchain
Background — defining a “smart invoice”
Our goal is to show how we can use smart contracts to specify and execute the payment of a real world invoice, thus transferring money from a buyer to a seller. More specifically, we wanted to implement a functionality to ensure that once the buyer accepts the invoice, he is committed to pay it at the due date (the ‘self-executing’ part of the title of this blogpost).
There are certain limitations when creating Ethereum smart contracts that affect how to structure a solution that fulfils these goals.
On Ethereum, it is not possible to perform “triggers”, “event driven programming”, “observer patterns” and similar paradigms where something needs to happen as a decoupled response to something else. As a result, we cannot implement a solution where the payment transfer is automatically executed at the due date. Instead we create a flow where it is guaranteed that anybody can trigger the payment execution, once the due date has been reached.
We use three contracts in order to settle a real Tradeshift invoice and they are the following:
A smart invoice contract needs to be as simple as possible from a design point of view. A buyer commits to pay it and therefore it is necessary that he can audit and understand all possible consequences that encompasses such a commit.
The smart invoice holds the payment amount, due date, payer, and beneficiary for the payment. The beneficiary can be changed by the current beneficiary. All other fields are static, which is important for the buyer to know in order to know what he commits to.
Smart Invoice Token
We also tokenise the payment. We do this by creating a ERC20 token for the smart invoice. This entitles holders to get a share of the payment once the underlying invoice is settled. We do this to illustrate use cases for smart invoices, such as selling your invoice tokens before settlement in order to get early payment.
Both the buyer and seller creates and controls their own smart contract wallet. This wallet can hold value, in our case DAI and interact with smart invoices. A buyer can commit to pay a given smart invoice through his wallet. A commitment means that anyone can force the buyer wallet to pay the invoice upon due date.
If the wallet does not contain enough money, then the settlement fails and can be retried. This means that the invoice payment is not risk free, but relies on trust in the buyer’s wallet. This trust greatly increases if the buyer also has incoming payment commitments.
Guided tour through our end-to-end test
One of the biggest challenges of using Ethereum is to gain a high level of confidence in your solution. It is especially true for the enterprise segment where vast amounts of money need to pass through the implementation.
In this project we have focused on tooling and development around unit-tests. In this section we use our end-to-end test as a means of explaining all the steps involved in the process of creating, tokenising and executing the payment of an invoice.
The tech stack used for development is composed of: Node.js, TypeScript, Solidity and Truffle Framework. The following code snippets are part of the end-to-end test. We also performed a pilot on Mainnet, using a simple CLI. We settled a real invoice and have included Etherscan links for our pilot in the steps bellow.
1. Buyer and Seller should each have an account containing Ether for gas.
The first step is all about checking if both the buyer and seller have Ether in their accounts. It is mandatory that both of them afford to pay the gas fees that transactions on the Ethereum Blockchain imply.
2. Buyer has DAI in his account (not in wallet).
We could have used any ERC20 compliant crypto currency to do this project, but we settled on DAI. First and foremost it was a requirement that we use a “Stablecoin” as no business will accept crypto-currency exchange rate risk. Second, we have a partnership with Maker. Third, decentralised finance is something we potentially can build on top of smart invoices (more on that in another post).
In this step we add DAI to the buyer’s account. We use the ‘BigNumber’ dependency in order to convert the sum in the desired format (10 to the power of 18 times 1000).
3. Buyer creates wallet.
The buyer wallet can hold DAI tokens and interact with smart invoices.
4. Seller creates a wallet.
Same as previous step, but in the case of seller.
5. Seller creates a Tradeshift invoice for buyer.
Normally, there would be an invoice created on the Tradeshift platform. The invoice ID will be used as the smart invoice identifier (so that buyer knows to whom she should send payment). For the sake of our project, we created an object and added the required properties.
In the pilot we used a real Tradeshift invoice.
6. Seller creates a smart invoice and token for Tradeshift invoice.
This is the step where the seller creates a smart contract instance that ‘wraps’ all the necessary information about the self-executing invoice.
Now we have a smart invoice created. We just need the buyer to commit to it (after he verifies its details).
7. Buyer commits to pay smart invoice.
Buyer verifies if the commitment sum inside the smart invoice is the same as the one established on the initial invoice created on the Tradeshift platform. Afterwards he commits on paying it at due date, when it gets executed.
8: Seller owns all invoice tokens and confirms that buyer has committed to pay.
Now it’s the seller’s time to act. He checks if the buyer committed. As for what we are concerned now, we wait until due date and then seller (he is the one incentivised) will trigger the smart invoice execution.
9. Time passes until due date.
Even though throughout this step none of the agents actually take any action, we thought that it would be interesting to show how we test if time actually passes by as expected (we might as well make it a complete, proper end-to-end test).
10. Buyer transfers DAI to his own wallet.
Normally, at due date, the buyer should already have DAI transferred to his own wallet. How to act in case a buyer does not have enough money at the moment of payment it is out of this project’s scope.
11. Seller triggers payment of smart invoice.
It’s time for the seller to settle the smart invoice. We check if the smart invoice status is set to ‘committed’. This is true because we saw that the buyer committed for payment at step 7. At this point the seller triggers the smart invoice.
Since each token stands for exactly 1 DAI, we compare the token balance with the invoice amount to see if they match.
12. Seller redeems invoice tokens in exchange of DAI.
Now that the seller settled the smart invoice, he can redeem the amount of DAI that the buyer owed him.
13. Seller transfers DAI from wallet to own account.
We now have a complete process where two agents establish a smart invoice between them. If the supplier wishes to withdraw DAI from his wallet, he is free to do so. We have included this test step so that we can properly follow the money end to end.
This pilot was about imagining how smart invoices would work in the world of Ethereum. Obviously, this project is not meant to be scaled to high volumes of invoices, but more as an illustration of how smart contracts and Blockchain fits in the world of B2B.
At Tradeshift Frontiers, we constantly strive to learn and understand how to apply emerging technologies in today’s B2B space. For those of you who are interested in finding more details about the pilot, feel free to contact Mads Stolberg-Larsen, Andreas Thorning and Alexandru Todea.