Corda’s Accounts + Tokens: making blockchain more inclusive
June 15, 2020
By Sneha Damle, Developer Evangelist at R3
After working with partners and developers, it is interesting to see how the trade finance, supply chain applications and many more are migrating to using an account-based model from the node-based model.
By integrating accounts and tokens as the solution these developers and partners are taking their very first step and answering the important questions such as how can you achieve more in a node-based model, how can you get more people on-boarded and make the blockchain platform inclusive in a more cost-efficient manner and how can you have people building token-based applications to take the advantage of the same.
Let us dive into the world of accounts and tokens by looking at a world cup ticket booking system as explained below and see how easy it is to integrate both.
This sample talks about a scenario where typically when the Cricket season starts, BCCI (Board of Control for Cricket) starts selling tickets. There are multiple dealers whom the BCCI issues tickets and further these dealers sell tickets to their client. Dealer’s will represent their clients as accounts on their nodes. The tickets will be represented as tokens. Buyers (accounts) will be issued cash (tokens). Seller’s(accounts) will be issued a ticket(token). Buyers will then buy the ticket from the seller by giving him cash in the return. Below are the nodes used for this CorDapp.
BCCI Node-Board of Control For Cricket node. This node is the primary legal authority for all cricket matches. This node will issue Non-Fungible tokens representing tickets to dealer accounts.
Multiple Dealer Nodes-These are legal dealers verified by BCCI. They will set up accounts for all their customers on their nodes. They will be issued tickets by BCCI, which they can further sell to their customers.
Bank Node-Issue’s cash to different accounts.
Customer Accounts-Buyer who wish to buy a ticket from the dealer.
Step 1: Create and Share Account Info
To build a CorDapp which uses accounts, we need to create these accounts first. Accounts do not have legal identities like nodes but have an identity within the context of a node. So an account is always linked to a host node which will host this account. To have a transaction between accounts hosted on different nodes, both the nodes should be aware of the existence of the account. Hence the hosting node will share the account details with counterparties. Basic info like account name, hostname, account id is shared.
Let’s start with two dealer nodes: DealerNode1 and DealerNode2. Let’s create agent accounts on respective dealer nodes. Let’s also create a buyer accounts on respective nodes.
Step 2: Create the base token type
Create the base token type for the ticket by calling the built inflow. We will create an evolvable type for the ticket instead of fixed, with issuer being the only participant. This makes it easy to update the ticket holders in case of any changes to the ticket; let’s say the match is rescheduled because of adverse weather conditions.
Step 3: Issue Non-Fungible Token To Dealer Account
Once we have created a base ticket type, the dealer will issue non-fungible tokens representing the match tickets to dealers. It is advisable not to mix transactions involving participants as accounts and nodes. Either you use entirely accounts based model or node-based model. Hence in Step 1, we have created an account for the dealer as well. A default account is not created automatically for the node.
Step 4: Issue cash(Fungible Tokens) to accounts
Before the buyers can buy tickets, the bank will issue some cash to the buyers. To issue cash to the buyer, we will generate an anonymous key linked to this buyers account, assign this key as the holder of fungible token and issue cash. Notice the holder in class FungibleToken is of type AbstractParty, which implies the holder can either be a node or an account. In our case, it will be the buyer’s account.
Step 5: Perform DVP between buyer and seller’s account on the same node
To perform a DVP between two accounts, the buyer account will transfer cash to the seller account, and the seller account will transfer the ticket to the buyer account. This will be executed within one transaction. Part one of the DVP transaction is about moving the ticket from seller to buyer account by specifying the buyer account parameter.
The second part is about moving fungible tokens from buyer to seller account by specifying the seller account as the third param and specifying the buyer account as a change holder. When mixing accounts and tokens, do not forget to mention the query criteria by specifying account id using withExternalIds as specified on line 6 below. If you do not specify these criteria, all the unconsumed tokens will be available for transfer. To have tokens linked only to the account, specify the account id in the criteria.
To get signatures from both the buyer’s and seller’s account, we initiate the sessions with the accounts and call the CollectSignaturesFlow.
Step 6: Perform DVP between buyer and seller’s account on different nodes
This is an interesting flow where we will perform the DVP between accounts held on different nodes. Few important points to note are as below.
1. Since buyer’s and seller’s account want to transact with each other, buyers should be aware of the seller’s account and vice-versa. To do this, the node hosts will share the account info’s with each other. A node can share the account details created on its node with a counterparty by calling ShareAccountInfo. A node can also request for account info by calling RequestAccountInfo.
2. Since accounts do not have a true identity, we use Confidential Identities to generate a public-private key pair and assign it to an account. These keys can be used to transact with the accounts. These keys can be generated by calling RequestKeyForAccount. One account can be mapped to multiple keys. For the node to know which key belongs to which account, this mapping of keys to accounts must be present in the database. These keys are also used for signing the transaction. When we call CollectSignaturesFlow, the counterparty must know account<->key mapping, otherwise, it complains when it tries to resolve the transaction since this key is unknown to the node. To avoid such scenarios, it is good to call SyncKeyMappingFlow in advance which syncs all the account<->key mapping with the specified counterparty.
We will sync buyer’s and seller’s keys with the counterparty. However, when you will call the generateMove method of tokens to add inputs and outputs to a transaction, you will notice that it’s not only the buyer’s and seller’s accounts represented as anonymous keys but there is one more unknown anonymous party present in the transaction. The token’s flow internally uses CI to generate a new anonymous party for the token holder. Make sure to sync the key corresponding to this anonymous party as well.
3. Now a bit on a signing. Sometimes since with accounts, we are using Confidential Identities, it becomes pretty confusing to get hold of the actual keys used for signing. This might happen when you have multiple inputs/outputs/commands each having multiple signers. I used a simple approach for this as below.
I used the filterMyKeys method from the KeyManagementService, which gives me the keys used for signing given a transaction. These keys will have the exact set of anonymous keys used as signers in the command. Once we get hold of these signers, we can sign the transaction using these keys. We can then specify these signers as a third param to CollectSignaturesFlow telling CollectSignaturesFlow to ignore collecting signatures from these given keys as they have already signed the transaction.
Step 7: Confirm successful DVP
We can query the vault to confirm the DVP transfer by specifying the account id in the query criteria.
Looking at the database, the following tables are predominately used for accounts and tokens.
You can use below SQL query to get the token balance specific to an account by specifying the account name.
Points to Note:
- While integrating accounts and tokens, keep in mind that the new token holders are also added as anonymous parties. So make sure to sync their keys with appropriate counterparties.
- When using tokens, the holder of the token will now be an account instead of the node.
Sample code showing how to use Accounts and Tokens can be found here.
Accounts blog explaining a sample on Accounts can be found here.
Thanks to Roger, Will, Kasia, Stefano, Nitesh and The Corda Team
Want to learn more about building excellent blockchain applications on Corda? Be sure to visit corda.net, check out our community page to learn how to connect with other Corda developers, and sign up for one of our newsletters for the latest updates.
— Sneha Damle is a Developer Evangelist at R3, an enterprise blockchain software firm working with a global ecosystem of more than 350 participants across multiple industries from both the private and public sectors to develop on Corda, its open-source blockchain platform, and Corda Enterprise, a commercial version of Corda for enterprise usage.
Follow Sneha on Linkedin.