This is a minimal implementation of a bank as a business network using Hyperledger Composer.
In case you haven't done yet, please, clone this repository running:
git clone https://github.com/immontilla/hyperledger-composer-bank.git && cd hyperledger-composer-bank
Install
npm install
Run the tests - test/logic.js & features/sample.feature file
npm test
You should see something like
> nyc mocha -t 0 test/*.js && cucumber-js
#org.example.mynetwork
✓ Alice can add assets that she owns
✓ Alice cannot add assets that Bob owns
✓ Bob can add assets that he owns
✓ Bob cannot add assets that Alice owns
✓ Alice can submit a transaction from her assets
✓ Bob cannot submit a transaction due to Insufficient funds. from his account to Alice account
6 passing (2s)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 0 | 0 | 0 | 0 | |
----------|----------|----------|----------|----------|-------------------|
Feature: Sample
Scenario: Alice can add assets that she owns
✔ Given I have deployed the business network definition ..
✔ And I have added the following participants of type org.example.mynetwork.Holder
| holderId | firstName | lastName |
| aliceId | Alice | A |
| bobId | Bob | B |
✔ And I have added the following assets of type org.example.mynetwork.Account
| accountId | holder | balance |
| alice_account1 | aliceId | 500 |
| bob_account1 | bobId | 200 |
✔ And I have issued the participant org.example.mynetwork.Holder#aliceId with the identity alice1
✔ And I have issued the participant org.example.mynetwork.Holder#bobId with the identity bob1
✔ When I use the identity alice1
✔ And I add the following asset of type org.example.mynetwork.Account
| accountId | holder | balance |
| alice_account2 | aliceId | 300 |
✔ Then I should have the following assets of type org.example.mynetwork.Account
| accountId | holder | balance |
| alice_account2 | aliceId | 300 |
Scenario: Alice cannot add assets that Bob owns
✔ Given I have deployed the business network definition ..
✔ And I have added the following participants of type org.example.mynetwork.Holder
| holderId | firstName | lastName |
| aliceId | Alice | A |
| bobId | Bob | B |
✔ And I have added the following assets of type org.example.mynetwork.Account
| accountId | holder | balance |
| alice_account1 | aliceId | 500 |
| bob_account1 | bobId | 200 |
✔ And I have issued the participant org.example.mynetwork.Holder#aliceId with the identity alice1
✔ And I have issued the participant org.example.mynetwork.Holder#bobId with the identity bob1
✔ When I use the identity alice1
✔ And I add the following asset of type org.example.mynetwork.Account
| accountId | holder | balance |
| bob_account2 | bobId | 50 |
✔ Then I should get an error matching /does not have .* access to resource/
Scenario: Bob can add assets that he owns
✔ Given I have deployed the business network definition ..
✔ And I have added the following participants of type org.example.mynetwork.Holder
| holderId | firstName | lastName |
| aliceId | Alice | A |
| bobId | Bob | B |
✔ And I have added the following assets of type org.example.mynetwork.Account
| accountId | holder | balance |
| alice_account1 | aliceId | 500 |
| bob_account1 | bobId | 200 |
✔ And I have issued the participant org.example.mynetwork.Holder#aliceId with the identity alice1
✔ And I have issued the participant org.example.mynetwork.Holder#bobId with the identity bob1
✔ When I use the identity bob1
✔ And I add the following asset of type org.example.mynetwork.Account
| accountId | holder | balance |
| bob_account3 | bobId | 400 |
✔ Then I should have the following assets of type org.example.mynetwork.Account
| accountId | holder | balance |
| bob_account3 | bobId | 400 |
Scenario: Bob cannot add assets that Alice owns
✔ Given I have deployed the business network definition ..
✔ And I have added the following participants of type org.example.mynetwork.Holder
| holderId | firstName | lastName |
| aliceId | Alice | A |
| bobId | Bob | B |
✔ And I have added the following assets of type org.example.mynetwork.Account
| accountId | holder | balance |
| alice_account1 | aliceId | 500 |
| bob_account1 | bobId | 200 |
✔ And I have issued the participant org.example.mynetwork.Holder#aliceId with the identity alice1
✔ And I have issued the participant org.example.mynetwork.Holder#bobId with the identity bob1
✔ When I use the identity bob1
✔ And I add the following asset of type org.example.mynetwork.Account
| accountId | holder | balance |
| alice_account3 | aliceId | 400 |
✔ Then I should get an error matching /does not have .* access to resource/
Scenario: Alice can submit a transaction from her account to Bob account
✔ Given I have deployed the business network definition ..
✔ And I have added the following participants of type org.example.mynetwork.Holder
| holderId | firstName | lastName |
| aliceId | Alice | A |
| bobId | Bob | B |
✔ And I have added the following assets of type org.example.mynetwork.Account
| accountId | holder | balance |
| alice_account1 | aliceId | 500 |
| bob_account1 | bobId | 200 |
✔ And I have issued the participant org.example.mynetwork.Holder#aliceId with the identity alice1
✔ And I have issued the participant org.example.mynetwork.Holder#bobId with the identity bob1
✔ When I use the identity alice1
✔ And I submit the following transaction of type org.example.mynetwork.FundsTransfer
| sender | recipient | amount |
| alice_account1 | bob_account1 | 100 |
✔ Then I should have the following asset of type org.example.mynetwork.Account
| accountId | holder | balance |
| alice_account1 | aliceId | 400 |
| bob_account1 | bobId | 300 |
Scenario: Bob cannot submit a transaction due to Insufficient funds. from his account to Alice account
✔ Given I have deployed the business network definition ..
✔ And I have added the following participants of type org.example.mynetwork.Holder
| holderId | firstName | lastName |
| aliceId | Alice | A |
| bobId | Bob | B |
✔ And I have added the following assets of type org.example.mynetwork.Account
| accountId | holder | balance |
| alice_account1 | aliceId | 500 |
| bob_account1 | bobId | 200 |
✔ And I have issued the participant org.example.mynetwork.Holder#aliceId with the identity alice1
✔ And I have issued the participant org.example.mynetwork.Holder#bobId with the identity bob1
✔ When I use the identity bob1
✔ And I submit the following transaction of type org.example.mynetwork.FundsTransfer
| sender | recipient | amount |
| bob_account1 | alice_account1 | 1000 |
✔ Then I should get an error matching /Insufficient funds./
6 scenarios (6 passed)
48 steps (48 passed)
0m01.876s
If everything went OK, run these scripts in strict order
sh scripts/start-dev-environment.sh
sh scripts/generate-bna.sh
sh scripts/deploy-bna.sh
sh scripts/start-bna.sh
If you want to check if everything went OK, run:
composer network list --card admin@hyperledger-composer-bank
You should see something like
✔ List business network from card admin@hyperledger-composer-bank
models:
- org.hyperledger.composer.system
- org.example.mynetwork
scripts:
- lib/logic.js
registries:
org.example.mynetwork.Account:
id: org.example.mynetwork.Account
name: Asset registry for org.example.mynetwork.Account
registryType: Asset
org.example.mynetwork.Holder:
id: org.example.mynetwork.Holder
name: Participant registry for org.example.mynetwork.Holder
registryType: Participant
Command succeeded
Finally, run this script
sh scripts/publish-rest-server.sh
Open http://localhost:3000/explorer in a web browser and you will see a SwaggerUI-styled web: "Hyperledger Composer REST server". Additionally, you can run curl commands.
Create one holder
curl -iX POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{"$class": "org.example.mynetwork.Holder", "holderId": "1234", "firstName": "bart", "lastName": "simpson" }' 'http://localhost:3000/api/Holder'
and set a bank account to him
curl -iX POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{ "$class": "org.example.mynetwork.Account", "accountId": "BART", "holder": "org.example.mynetwork.Holder#1234", "balance": 300 }' 'http://localhost:3000/api/Account'
Create another holder
curl -iX POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{"$class": "org.example.mynetwork.Holder", "holderId": "7890", "firstName": "sideshow", "lastName": "bob" }' 'http://localhost:3000/api/Holder'
and set a bank account to him too
curl -iX POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{ "$class": "org.example.mynetwork.Account", "accountId": "BOB", "holder": "org.example.mynetwork.Holder#7890", "balance": 100 }' 'http://localhost:3000/api/Account'
You could check the holders running
curl -iX GET --header 'Accept: application/json' 'http://localhost:3000/api/Holder'
or check the accounts running
curl -iX GET --header 'Accept: application/json' 'http://localhost:3000/api/Account'
To transfer 200 from Bart to Sideshow Bob, run
curl -iX POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{ "$class": "org.example.mynetwork.FundsTransfer", "sender": "org.example.mynetwork.Account#BART", "recipient": "org.example.mynetwork.Account#BOB", "amount": 200 }' 'http://localhost:3000/api/FundsTransfer'
Finally, if you run:
curl -iX GET --header 'Accept: application/json' 'http://localhost:3000/api/Account'
You will get
HTTP/1.1 200 OK
Vary: Origin, Accept-Encoding
Access-Control-Allow-Credentials: true
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
X-Download-Options: noopen
X-Content-Type-Options: nosniff
Content-Type: application/json; charset=utf-8
Content-Length: 260
ETag: W/"104-ltIIum7o/SCzicWQnkDGczPLxF4"
Date: Wed, 08 Aug 2018 21:02:48 GMT
Connection: keep-alive
[{"$class":"org.example.mynetwork.Account","accountId":"BART","holder":"resource:org.example.mynetwork.Holder#1234","balance":100},{"$class":"org.example.mynetwork.Account","accountId":"BOB","holder":"resource:org.example.mynetwork.Holder#7890","balance":300}]