Hyperledger Fabric, as an enterprise blockchain platform for business application, provides real values in a business network composed of participating organizations who by nature do not trust each other. Enterprise blockchain platform comes with the mechanism like a trustworthy source of truth, permission control, and automated execution of business logic. This platform is good for certain types of application in which all participants can benefit.
Here we pick one of a simple but reasonable use case to show this value. Invoice financing is a way to obtain loan from banks. Here we build a bank network such that participating banks have the same source of data about each invoice and amount borrowed initiated by one bank. The simple business logic protects against over-borrowing.
We will make a quick introduction on invoice financing. Then we go into the Bank Network and business logic we build, with demonstration how things work and what happens during the demonstration. Finally we do a quick discussion on the overall process.
The code is already in repository and you can easily do the same demonstration once you have a fabric node.
Introduction: Invoicing Financing
Invoice financing, according to Investopedia, is “a way for businesses to borrow money against the amounts due from customers”. In our business world, when a company (say Alice Software House, simply say Alice from now on) provides service or delivers goods to another company (say Bob Shop, simply say Bob), Alice issues an invoice to Bob for payment. This payment is always in credit term, which means Alice allows Bob to pay after a period of time.
In case Alice needs cash for whatever reasons before the payment is made by Bob, Alice can use that invoice to obtain financing from financial institutions (say a bank). This is called invoice financing, or accounts receivable financing. For safety, the bank only loans a portion of the invoice amount, and of course, at an interest and a term specified.
Despite this simple explanation, we may immediately see some potential risks: double-financing and over-borrowing. Both involve a company borrowing money from more than one banks with the same invoice. While some banks avoid double financing on the same invoice, others may be more aggressive, with a bottom line that the company shall not borrow money more than the invoice amount on a given invoice.
For example, Alice uses the same invoice to loan from two banks. Say the invoice with amount $10,000 can get $7,000 from both banks, the total loan amount $14,000 exceeds the original invoice amount. This increases bank’s risk.
In real life there are many ways to handle this challenge. Here we are considering to build a Bank Network, which participating banks share certain data and agree on business logic that can protect against this type of risk. The Bank Network is implemented with Hyperledger Fabric (1.4.2 and 1.4.3 tested).
The overall project can be broken into several parts.
In our setup we have two banks, Alpha and Beta. Converted into Hyperledger Fabric design, these are two organizations. Each bank has a Certificate Authority (CA), issuing digital identity to authorized staff in the bank, and two peer nodes. There is a separate Orderer organization, performing the ordering service to this bank network. We do not touch on the Orderer portion in this setup.
A channel called invoicechannel is created and all the peer nodes (total four) joining it. This is the foundation of Bank Network.
The Bank Network is adapted from First Network of Fabric Samples.
Note that in the demonstration we have all components, even from different banks, running in a localhost with containers. In real life, each bank will keep their own asset (peer nodes, CA) under their control, which are usually deployed in their own datacenter or in the designated cloud providers.
Theoretically this design can be applied to more banks. What we need is to prepare the appropriate crypto material for all components and reflect this in the channel setup.
Chaincode is the business logic interacting with the ledger stored on each peer node. Here we have one simple chaincode, invfinancing, written in Go.
The data structure in our ledger contains two items: InvoicedAmount and BorrowedAmount. And we use the company name and invoice number as “key” to the two items as “value”. For example, for company Alice of invoice invbob001 with amount 10000 and 7000 is already loaned, the record is
Alice-invbob001 => (invoicedamount: 10000, borrowedamount: 7000)
Three functions are defined for interacting with the data record.
- initInv(): To initialize a new invoice record. Company name, invoice number and invoice amount are required.
- queryInv(): To query an existing invoice record. Company name and invoice number are required.
- requestLoan(): To request loan on an existing invoice. Company name, invoice number and the amount to be borrowed are required. Borrowed amount is checked against exceeding invoice amount.
The chaincode structure is adapted from several chaincode examples from Fabric Samples. Note that the same chaincode does not contain any information about the underlying fabric network: no organization, no channel, etc. It can be used in the current Bank Network setup, or in a setup with more banks to join.
There are three client applications created for demonstration purpose,
requestLoan-bank.js, corresponding the three chaincode functions to be invoked or queried. Meanwhile, in our bank network, we have two banks defined: alpha and beta. To reflect the right connection profiles (alpha is using alpha’s nodes, etc.) we create two sets of client applications, with name bank substituted with alpha or beta.
Meanwhile, we need identity for authorized staff in both banks. We use two scripts
registerUser-bank.js, to enrol one staff for each bank, which is, user-alpha and user-beta. Those identities are stored under
Note that all scripts and wallets are kept in same directory. They are purely for demonstration. In real life each bank will have their own set of client applications and identity of their authorized staff.
The client applications are adapted from fabcar example from Fabric Samples.
Here is the repository of the code.
Invoice Financing demo on a Bank Network using Hyperledger Fabric The Bank Network is composed of two banks…
All the codes mentioned above are stored in directory
The definition of bank network is inside
bank-network directory. The crypto material (certificates and signing key for everything) and channel artifacts are generated and kept in the repository. You can generate your own set of material. What you need to do is to update .env to point the newly generated CA signing key.
Chaincode is stored inside
chaincode directory. The chaincode just contains a file invfinancing.go.
Besides there are two shell script files:
teardowneverything.sh. The scripts are self-explanatory, and the commands inside are also readable. Basically
starteverything.sh begins with bringing up the containers, channel creation and join by all peer nodes, chaincode installation and instantiation. After this script completes we can perform demonstration with client applications. The
teardowneverything.sh simply tears down all running containers, and removes those containers and images created during chaincode execution.
Step 0: Prepare a fabric node
A fabric node is a host containing the prerequisite, Hyperledger Fabric images, fabric-samples and binary tools. You can refer to this article for a fabric node.
Setup a Hyperledger Fabric Host and Create a Machine Image
Use machine image (e.g. AMI) to speed up the preparation of a Hyperledger Fabric host for testing and practicing
Step 1: Git clone the code
git clone https://github.com/kctam/invfinancing-banknetwork.git
Step 2: Bring up the bank network, invoicechannel, and chaincode
Step 3: Install the required SDK
Step 4: Enrol user-alpha and user-beta for the client applications. And see both users appear in the wallet directory.
node registerUser-alpha.jsnode enrollAdmin-beta.js
node registerUser-beta.jsls wallet
Step 5: Let’s simulate a scenario.
Company Alice has an invoice invbob001 of amount 10,000. Alice applies for invoice financing from Bank Alpha. Bank Alpha records this new invoice.
node initInv-alpha.js Alice invbob001 10000node queryInv-alpha.js Alice invbob001
And we see this invoice is found in the ledger, with borrowed amount 0.
Bank Alpha decides to loan 7,000 upon this invoice.
node requestLoan-alpha.js Alice invbob001 7000node queryInv-alpha.js Alice invbob001
Now this invoice has borrowed amount 7,000.
Assuming Alice goes to Bank Beta. Bank Beta tries to record this invoice but found the invoice is already in record.
node initInv-beta.js Alice invbob001 10000
Alice then asks Bank Beta to loan 5,000 upon this invoice. The Bank Network immediately finds that the total borrowed amount would exceed the invoice amount (12,000 > 10,000) and it is not allowed.
node requestLoan-beta.js Alice invbob001 5000
Assuming Bank Beta decides to loan 2,000 to Alice upon this invoice. The loan request is successful, and the ledger is updated (now the borrowed amount is 9,000).
node requestLoan-beta.js Alice invbob001 2000node queryInv-beta.js Alice invbob001
You can try adding other invoices for other companies.
Step 6: Clean Up
Despite this oversimplified setup, we see how to build a blockchain application with a properly designed data structure and logic to achieve our basic business goal: to avoid over-borrowing in invoice financing.
What is to be kept in ledger / blockchain?
This is by far the most common question. We understand information written in the ledger will be visible to all participants, and all peer nodes will process when committing block. Here is the recommendation:
- Only needed information shall be stored in the ledger. Blockchain platform is never designed as a replacement of database or repository of everything. You can see the minimum information stored in our example to achieve our business needs.
- Only information that visible to all parties shall be stored in the ledger. In real business world, invoice financing needs more information, such as the loan term between the lender (bank) and the borrower (invoice holder), the interest rate, payment term, etc. This is business confidential information, just relevant between the lender and borrower, and shall never be placed in the blockchain.
- Those relevant information should just be kept as how it is handled today. A database inside the bank with good protection is good enough.
Enriching the setup
Again, this setup is by far good for demonstration. It is far from real business case where more complex process may be involved. Here are some potential areas to make this setup close to real life.
- A more robust ordering service setup. Currently we are using one Orderer. In real life we can use orderer cluster.
- The network can be expanded by adding new banks (organizations) and/or adding new peer on bank for better performance. The chaincode here can be used in such expanded network, while proper client applications for new banks shall be provided.
- Inside chaincode we can enforce some access control. In our example, we have only one type of user who can perform all chaincode functions. In a more realistic implementation there may be two types of staff: those authoirzed can execute initialize invoice and request loan, while another can only query an existing invoice. This can be achieved using access control at chaincode level with certificate authority and proper affiliation setup.
- Another possible improvement on the chaincode is to add function to check whether the invoice is a fake invoice or by fake company. This may involve initial logging of an invoice, and confirmed by both companies. Bank only processes invoice when the two companies have confirmed.
We can have more ideas to make this network more interesting. The critical part is to have this big picture BEFORE we start designing the chaincode. It is never a good practice to start coding before we have all the business logic agreed.
Thanks for reading!
Time for practising! In case you have any questions on the setup, or see any discrepancy on the code, please let me know on email@example.com.