Test how to execute BTC/USD Forward contract on R3 Corda
Inspired by this Commerzbank Conducts €500k FX Transaction Using R3’s Corda news, I decided to test a BTC/USD forward contract execution on R3’s Corda.
What is a Forward Contract?
For example, a property development company FinCo just signed a lot of contracts to sell their highly demanded new builds, and they are willing to accept bitcoin, but the customers only need to transfer the amount in 6 months time. Same time after 6 months, FinCo also will have an outgoing payment of US dollars to their material supplier in the States, and worried about the BTC/USD rate could go down in the future, FinCo struck a deal with FabBank for a forward contract, fixed an exchange rate between BTC and USD in 6 months. Therefore, in the settlement of the contract, FinCo can use the bitcoin received from the customer to pay FabBank, and pay their supplier the dollars received from FabBank with the locked BTC/USD rate, avoiding the future BTC/USD exchange rate risk.
What is Corda?
Corda is an open source blockchain project, designed for business from the start. Only Corda allows you to build interoperable blockchain networks that transact in strict privacy. Corda’s smart contract technology allows businesses to transact directly, with value.
How to run the test
-
Download or check out the source code here:
$ git clone git@github.com:finfabrik/fxforward-cordapp.git
-
then execute the following commands:
$ cd fxforward-cordapp
$ ./gradlew clean build deployNodes
-
if there was no issue building the project, start the nodes by running:
$ build/nodes/runnodes
runnodes will start up 3 nodes, one Notary node, one FinCo node and one FabBank node. Because there is no REST server for Notary, only one console window popped out for it. Both FinCo and FabBank will have two consoles windows popped out, one for the node itself and another is for the REST server. So you will have 5 console windows altogether.
After the 5 processes started successfully, you can import the FXForward-Cordapp.postman_collection.json
file under the project’s postman folder into your Postman.
Under the FXForward-Cordapp
postman folder, there are 12 GET requests, execute them one by one from the top to the bottom, you will have the whole process of issuing tokens, issuing forward contract and settling the contract.
- FinCo:Info
Return back info about FinCo
{ "me": "C=GB,L=London,O=FinCo" }
- FabBank:Info
Return back info about FabBank
{ "me": "C=US,L=New York,O=FabBank" }
- FabBank:IssueFXForward
FabBank issues a Forward Contract with FinCo as the counterparty, settlement time in 6 months, with FinCo buying 1,000,00 US dollars and selling 100 bitcoins.
Transaction id 9C0C5580A11B018833751E5A1DFF2DB43A744DC25DEDA0E38FE2B05211E0D642 committed to ledger. FXForward(84af6a3d-a6cc-47a9-a032-ee432f1abb21): GfHq2tTVk9z4eXgyQf1T4ncBLETWzf2iqxSAPKsXkLQhPxaaB6XBM2Rrbzoc owes GfHq2tTVk9z4eXgyQPBDzUi2rW1695TQYwBBHPTTrEwVp3qzxh91vxEtLFXA 1000000.00 USD 100 Commodity(commodityCode=BTC, displayName=BTC, defaultFractionDigits=0) 6M.
- FabBank:QueryFXForward
Check the issued contract by FabBank
[ { "base": "1000000.00 USD", "terms": "100 Commodity(commodityCode=BTC, displayName=BTC, defaultFractionDigits=0)", "buyer": "O=FinCo, L=London, C=GB", "seller": "O=FabBank, L=New York, C=US", "tenor": { "name": "6M" }, "linearId": { "externalId": null, "id": "84af6a3d-a6cc-47a9-a032-ee432f1abb21" }, "participants": [ "O=FinCo, L=London, C=GB", "O=FabBank, L=New York, C=US" ], "participantKeys": [ "MCowBQYDK2VwAyEACFeSun8yEqt/SB9MgNaE3VFpbwy+V2I8JjtqGzBjYkc=", "MCowBQYDK2VwAyEAOfB/dNfuT75Sa09rCP7tTziuHMqY5COpUyZ5+9MEXFg=" ] } ]
- FinCo:QueryFXForward
Check the issued contract by FinCo, should be exactly the same as FabBank’s output.
- FinCo:IssueBTC
FinCo issues BTC
Transaction id 1D1845DE47130D0CBFDC78185726B6AAACC460A34795C5A2FEF0FAD4746B234F committed to ledger. TransactionState(data=Token(amount=100 Commodity(commodityCode=BTC, displayName=BTC, defaultFractionDigits=0), owner=O=FinCo, L=London, C=GB, linearId=6486db80-e508-477a-9f3a-25c2c092609b), contract=com.finfabrik.corda.TokenContract, notary=O=Notary, L=London, C=GB, encumbrance=null, constraint=HashAttachmentConstraint(attachmentId=4B4E5A2F109FAB13350C0FF3AF6F59E5554D433F7A536EB9C584869B720A5414))
- FinCo:QueryTokens
Check the issued BTC by FinCo
[ { "state": { "data": { "amount": "100 Commodity(commodityCode=BTC, displayName=BTC, defaultFractionDigits=0)", "owner": "O=FinCo, L=London, C=GB", "linearId": { "externalId": null, "id": "6486db80-e508-477a-9f3a-25c2c092609b" }, "participants": [ "O=FinCo, L=London, C=GB" ] }, "contract": "com.finfabrik.corda.TokenContract", "notary": "O=Notary, L=London, C=GB", "encumbrance": null, "constraint": { "attachmentId": "4B4E5A2F109FAB13350C0FF3AF6F59E5554D433F7A536EB9C584869B720A5414" } }, "ref": { "txhash": "1D1845DE47130D0CBFDC78185726B6AAACC460A34795C5A2FEF0FAD4746B234F", "index": 0 } } ]
- FabBank:IssueUSD
FabBank issues US dollars
Cash(1000000.00 USD issued by O=FabBank, L=New York, C=US[00] at O=FabBank, L=New York, C=US[00] owned by O=FabBank, L=New York, C=US)
- FabBank:QueryCash
Check the issued dollars by FabBank
[ { "state": { "data": { "amount": "1000000.00 USD issued by O=FabBank, L=New York, C=US[00]", "owner": "O=FabBank, L=New York, C=US", "exitKeys": [ "MCowBQYDK2VwAyEAOfB/dNfuT75Sa09rCP7tTziuHMqY5COpUyZ5+9MEXFg=" ], "participants": [ "O=FabBank, L=New York, C=US" ] }, "contract": "net.corda.finance.contracts.asset.Cash", "notary": "O=Notary, L=London, C=GB", "encumbrance": null, "constraint": {} }, "ref": { "txhash": "EC54E26BC9D2D97A0C2699F21265F04E34121D4A60F127CA412A387E7D057F6F", "index": 0 } } ]
- FabBank:SettleFXForward
FabBank settles the contract. Here we need to fill out the Forward’s contractId and the BTC’s tokenId, which can be obtained from the previous queries’ outputs.
- FinCo:QueryCash
Check the received dollars by FinCo
[ { "state": { "data": { "amount": "1000000.00 USD issued by O=FabBank, L=New York, C=US[00]", "owner": "MCowBQYDK2VwAyEAlYyInbvEj9Lzg+Jnuo8Ea4gRLQhfkCLWOPWgxEksn1U=", "exitKeys": [ "MCowBQYDK2VwAyEAlYyInbvEj9Lzg+Jnuo8Ea4gRLQhfkCLWOPWgxEksn1U=", "MCowBQYDK2VwAyEAOfB/dNfuT75Sa09rCP7tTziuHMqY5COpUyZ5+9MEXFg=" ], "participants": [ "MCowBQYDK2VwAyEAlYyInbvEj9Lzg+Jnuo8Ea4gRLQhfkCLWOPWgxEksn1U=" ] }, "contract": "net.corda.finance.contracts.asset.Cash", "notary": "O=Notary, L=London, C=GB", "encumbrance": null, "constraint": {} }, "ref": { "txhash": "2056F5FD87EA3444B3C36C2FA9EDBC27EA65619ED4FC25B471A688E567179D14", "index": 1 } } ]
- FabBank:QueryTokens
Check the received bitcoins by FabBank
[ { "state": { "data": { "amount": "100 Commodity(commodityCode=BTC, displayName=BTC, defaultFractionDigits=0)", "owner": "O=FabBank, L=New York, C=US", "linearId": { "externalId": null, "id": "6486db80-e508-477a-9f3a-25c2c092609b" }, "participants": [ "O=FabBank, L=New York, C=US" ] }, "contract": "com.finfabrik.corda.TokenContract", "notary": "O=Notary, L=London, C=GB", "encumbrance": null, "constraint": { "attachmentId": "4B4E5A2F109FAB13350C0FF3AF6F59E5554D433F7A536EB9C584869B720A5414" } }, "ref": { "txhash": "2056F5FD87EA3444B3C36C2FA9EDBC27EA65619ED4FC25B471A688E567179D14", "index": 0 } } ]
Note
As a demo test version, the source code is not fully tested and not in production level of quality. So do not use it in production system.