├── web ├── .bowerrc ├── .jshintrc ├── app │ ├── scripts │ │ ├── config.js │ │ ├── user-service.js │ │ ├── app.js │ │ ├── demo-controller.js │ │ ├── time-service.js │ │ └── peer-service.js │ ├── partials │ │ └── demo.html │ ├── styles │ │ └── app.css │ └── app.html ├── bower.json ├── package.json └── gulpfile.js ├── .gitignore ├── README.md └── docs └── p2p-insurance.md /web/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "app/bower_components/" 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .project 3 | web/app/bower_components 4 | web/dist 5 | web/node_modules 6 | web/ionic/plugins 7 | web/ionic/www/lib 8 | web/ionic/.io-config.json -------------------------------------------------------------------------------- /web/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 2, 11 | "newcap": true, 12 | "noarg": true, 13 | "quotmark": "single", 14 | "undef": true, 15 | "unused": "vars", 16 | "strict": false, 17 | "predef": ["$","jQuery","angular","_","moment","AWS","DynamoDB","Stripe","chance","emailAddresses","md5","toastr","jstz"], 18 | "camelcase" : false 19 | } 20 | -------------------------------------------------------------------------------- /web/app/scripts/config.js: -------------------------------------------------------------------------------- 1 | angular.module('config', []) 2 | .constant('cfg', 3 | { 4 | endpoint: 'https://deadbeef-6d99-41a8-988a-c31ce4ae14dc_vp1-api.blockchain.ibm.com:443/chaincode', 5 | secureContext: 'user_type1_deadbeef', 6 | chaincodeID: 'badeadbeeff1ec5ab1d077cb38907780c79260420fd94c288d6bddb710114c44969b9d560d365e38b62d379681e2acaa5b88536ebd22d6ed56c0605736349', 7 | users: [{id: 'user0', role: 'role0'}, 8 | {id: 'user1', role: 'role0'}, 9 | {id: 'user2', role: 'role1'}, 10 | {id: 'user3', role: 'role1'}] 11 | } 12 | ); 13 | -------------------------------------------------------------------------------- /web/app/scripts/user-service.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @class UserService 3 | * @classdesc 4 | * @ngInject 5 | */ 6 | function UserService($log, cfg) { 7 | 8 | // jshint shadow: true 9 | var UserService = this; 10 | 11 | var user = cfg.users[0]; 12 | 13 | UserService.setUser = function(u) { 14 | user = u; 15 | }; 16 | 17 | UserService.getUser = function() { 18 | return user; 19 | }; 20 | 21 | UserService.getUsers = function() { 22 | return cfg.users; 23 | }; 24 | 25 | } 26 | 27 | angular.module('userService', []).service('UserService', UserService); -------------------------------------------------------------------------------- /web/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hyperledger-poc", 3 | "version": "0.0.0", 4 | "authors": [ 5 | "Oleg Abdrashitov" 6 | ], 7 | "license": "MIT", 8 | "ignore": [ 9 | "**/.*", 10 | "node_modules", 11 | "bower_components", 12 | "test", 13 | "tests" 14 | ], 15 | "dependencies": { 16 | "angular": "~1.4.7", 17 | "bootstrap": "~3.3.5", 18 | "angular-ui": "~0.4.0", 19 | "angular-ui-bootstrap": "~0.14.3", 20 | "angular-ui-router": "~0.2.15", 21 | "components-font-awesome": "~4.4.0", 22 | "lodash": "^4.13.1" 23 | }, 24 | "devDependencies": {} 25 | } 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Peer-to-Peer Insurance Proof Of Concept 2 | Proof of concept demo allowing users to organize into mutual insurance pools with automatic payout on Hyperledger blockchain. 3 | Please read the [functional spec document](docs/p2p-insurance.md). 4 | 5 | # Web Application 6 | Demo is served by an Angular single page web application. Please install and run in `web` directory. 7 | 8 | ## Install 9 | ``` 10 | npm install 11 | bower install 12 | ``` 13 | Will download developer dependencies which may take a little while. 14 | 15 | ## Run 16 | The web app is built and run by `gulp`: 17 | 18 | ``` 19 | gulp serve 20 | ``` 21 | -------------------------------------------------------------------------------- /web/app/scripts/app.js: -------------------------------------------------------------------------------- 1 | angular.module('app', ['ui.router', 2 | 'ui.bootstrap', 3 | 'timeService', 4 | 'userService', 5 | 'peerService', 6 | 'demoController', 7 | 'config']) 8 | 9 | .config(function($stateProvider, $urlRouterProvider) { 10 | 11 | $urlRouterProvider.otherwise('/'); 12 | 13 | $stateProvider 14 | .state('demo', { 15 | url: '/', 16 | templateUrl: 'partials/demo.html', 17 | controller: 'DemoController as ctl' 18 | }) 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /web/app/scripts/demo-controller.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @class DemoController 3 | * @classdesc 4 | * @ngInject 5 | */ 6 | function DemoController($log, $q, $interval, $timeout, 7 | cfg, TimeService, UserService, PeerService) { 8 | 9 | var ctl = this; 10 | 11 | ctl.now = function() { 12 | return TimeService.now; 13 | }; 14 | 15 | ctl.tick = function() { 16 | TimeService.tick(); 17 | }; 18 | 19 | ctl.clock = function() { 20 | TimeService.clock(); 21 | }; 22 | 23 | ctl.user = UserService.getUser(); 24 | 25 | ctl.users = UserService.getUsers(); 26 | 27 | ctl.setUser = function(u) { 28 | UserService.setUser(u); 29 | }; 30 | 31 | } 32 | 33 | angular.module('demoController', []) 34 | .controller('DemoController', DemoController); -------------------------------------------------------------------------------- /web/app/scripts/time-service.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @class TimeService 3 | * @classdesc 4 | * @ngInject 5 | */ 6 | function TimeService($log, $interval, cfg) { 7 | 8 | // jshint shadow: true 9 | var TimeService = this; 10 | 11 | TimeService.now = new Date(2016, 5, 1, 12, 0); 12 | 13 | var clockStepMonths = 1; 14 | 15 | var addTime = function() { 16 | TimeService.now.setMonth(TimeService.now.getMonth() + clockStepMonths); 17 | }; 18 | 19 | TimeService.tick = function() { 20 | // call monthly function 21 | addTime(); 22 | }; 23 | 24 | var stop; 25 | 26 | TimeService.clock = function() { 27 | if(angular.isDefined(stop)) { 28 | $interval.cancel(stop); 29 | stop = undefined; 30 | } 31 | else { 32 | stop = $interval(TimeService.tick, 2 * 1000); 33 | } 34 | }; 35 | 36 | } 37 | 38 | 39 | angular.module('timeService', []).service('TimeService', TimeService); -------------------------------------------------------------------------------- /web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "browser-sync": "^1.3.0", 4 | "del": "^1.1.0", 5 | "gulp": "3.8.3", 6 | "gulp-cache": "0.2.2", 7 | "gulp-if": "^1.2.5", 8 | "gulp-imagemin": "^2.3.0", 9 | "gulp-inject": "^3.0.0", 10 | "gulp-jshint": "^1.6.3", 11 | "gulp-load-plugins": "^0.8.0", 12 | "gulp-minify-css": "^1.2.0", 13 | "gulp-minify-html": "0.1.5", 14 | "gulp-ng-annotate": "^1.0.0", 15 | "gulp-replace": "^0.5.4", 16 | "gulp-rev": "^5.1.0", 17 | "gulp-size": "^1.0.0", 18 | "gulp-uglify": "^1.2.0", 19 | "gulp-usemin": "^0.3.11", 20 | "jshint-stylish": "^1.0.0", 21 | "ng-annotate": "^1.0.1", 22 | "opn": "^1.0.0", 23 | "psi": "^1.0.4", 24 | "run-sequence": "^1.1.1" 25 | }, 26 | "engines": { 27 | "node": ">=0.10.0" 28 | }, 29 | "private": true, 30 | "scripts": { 31 | "test": "gulp && git status | grep 'working directory clean' >/dev/null || (echo 'Please commit all changes generated by building'; exit 1)" 32 | }, 33 | "dependencies": { 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /web/app/partials/demo.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Demo

5 |
6 |
7 |
8 |
Menu
9 |
10 |
    11 |
  • role0 0
  • 12 |
  • role0 1
  • 13 |
14 |
    15 |
  • role1 0
  • 16 |
  • role1 1
  • 17 |
18 |
19 |
20 |
21 |
22 |
23 |
Logged in User
24 |
25 | 28 |
29 |
30 |
31 |
32 |
33 |
Current Date
34 |
35 |
{{ctl.now() | date:'longDate'}}
36 |
37 |
38 |
39 |
40 | 41 |
-------------------------------------------------------------------------------- /web/app/styles/app.css: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | */ 4 | 5 | .loading { 6 | text-align: center; 7 | font-size: 2em; 8 | } 9 | 10 | /* fixes content shifting left on modal open https://github.com/twbs/bootstrap/commit/3f87bf46e463b113760a2e45158a684825bf9d50 */ 11 | body.modal-open, 12 | .modal-open .navbar-fixed-top, 13 | .modal-open .navbar-fixed-bottom { 14 | margin-right: 16px; 15 | } 16 | 17 | .panel-default .list-group-item.active 18 | { 19 | color: #000; 20 | background-color: #DDD; 21 | border-color: #DDD; 22 | } 23 | 24 | .inline-icon-link { 25 | cursor: pointer; 26 | margin-right: 1em; 27 | } 28 | 29 | .icon-inline { 30 | font-size:x-large; 31 | vertical-align: middle; 32 | margin-right: .3em; 33 | margin-left: .3em; 34 | } 35 | 36 | .toptext {color: #333} 37 | 38 | .row-padded-bottom, .row-border-bottom, .row-head, .row-inner-head { 39 | padding-bottom: 1em; 40 | margin-bottom: 1em; 41 | } 42 | 43 | .row-border-bottom, .row-head, .row-inner-head { 44 | border-bottom: /* thin solid #ddd */inherit; 45 | } 46 | 47 | .row-padded-top, .row-border-top { 48 | padding-top: 1em; 49 | margin-top: 1em; 50 | } 51 | 52 | .row-border-top { 53 | border-top: thin solid #ddd; 54 | } 55 | 56 | .row-head, .row-inner-head { 57 | font-weight: bold; 58 | } 59 | 60 | .row-inner-head { 61 | padding-top: 1em; 62 | } 63 | 64 | p.description { 65 | padding-top: 1em; 66 | font-size: smaller; 67 | } 68 | 69 | span.icon-pointer, span.icon-two, span.icon-three { 70 | cursor: pointer; 71 | text-align: center; 72 | } 73 | 74 | span.icon-three { 75 | width: 30%; 76 | } 77 | 78 | span.icon-two { 79 | width: 50%; 80 | } 81 | -------------------------------------------------------------------------------- /web/app/scripts/peer-service.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @class PeerService 3 | * @classdesc 4 | * @ngInject 5 | */ 6 | function PeerService($log, $q, $http, cfg, UserService) { 7 | 8 | // jshint shadow: true 9 | var PeerService = this; 10 | 11 | var payload = { 12 | 'jsonrpc': '2.0', 13 | 'params': { 14 | 'type': 1, 15 | 'chaincodeID': { 16 | name: cfg.chaincodeID 17 | }, 18 | 'ctorMsg': {} 19 | }, 20 | 'id': 0 21 | }; 22 | 23 | var invoke = function(functionName, functionArgs) { 24 | $log.debug('PeerService.invoke'); 25 | 26 | payload.method = 'invoke'; 27 | payload.params.ctorMsg['function'] = functionName; 28 | payload.params.ctorMsg.args = functionArgs; 29 | payload.secureContext = UserService.getUser().id; 30 | 31 | $log.debug('payload', payload); 32 | 33 | return $http.post(cfg.endpoint, angular.copy(payload)).then(function(data) { 34 | $log.debug('result', data.data.result); 35 | }); 36 | }; 37 | 38 | var query = function(functionName, functionArgs) { 39 | $log.debug('PeerService.query'); 40 | 41 | var d = $q.defer(); 42 | 43 | payload.method = 'query'; 44 | payload.params.ctorMsg['function'] = functionName; 45 | payload.params.ctorMsg.args = functionArgs; 46 | payload.secureContext = UserService.getUser().id; 47 | 48 | $log.debug('payload', payload); 49 | 50 | $http.post(cfg.endpoint, angular.copy(payload)).then(function(data) { 51 | $log.debug('result', data.data.result); 52 | d.resolve(data.data.result); 53 | }); 54 | 55 | return d.promise; 56 | }; 57 | 58 | } 59 | 60 | 61 | angular.module('peerService', []).service('PeerService', PeerService); -------------------------------------------------------------------------------- /web/app/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Hyperledger Proof Of Concept 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /web/gulpfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Stripped from Google Web Starter Kit 3 | */ 4 | 5 | 'use strict'; 6 | 7 | // Include Gulp & tools we'll use 8 | var gulp = require('gulp'); 9 | var $ = require('gulp-load-plugins')(); 10 | var del = require('del'); 11 | var runSequence = require('run-sequence'); 12 | var browserSync = require('browser-sync'); 13 | var pagespeed = require('psi'); 14 | var reload = browserSync.reload; 15 | 16 | // Lint JavaScript 17 | gulp.task('jshint', function () { 18 | return gulp.src('app/scripts/**/*.js') 19 | .pipe(reload({stream: true, once: true})) 20 | .pipe($.jshint()) 21 | .pipe($.jshint.reporter('jshint-stylish')) 22 | .pipe($.if(!browserSync.active, $.jshint.reporter('fail'))); 23 | }); 24 | 25 | // Optimize images 26 | gulp.task('images', function () { 27 | return gulp.src('app/images/**/*') 28 | .pipe($.cache($.imagemin({ 29 | progressive: true, 30 | interlaced: true 31 | }))) 32 | .pipe(gulp.dest('dist/images')) 33 | .pipe($.size({title: 'images'})); 34 | }); 35 | 36 | // Copy all non html files at the root level (app) 37 | gulp.task('copy', function () { 38 | return gulp.src([ 39 | 'app/*.*', 40 | '!app/*.html' 41 | ], { 42 | dot: true 43 | }).pipe(gulp.dest('dist')) 44 | .pipe($.size({title: 'copy'})); 45 | }); 46 | 47 | var minify = function(path, env) { 48 | gulp.src([path]) 49 | .pipe($.replace(/scripts\/config.js/g, 50 | env ? 'scripts/config-'.concat(env).concat('.js') : 'scripts/config.js')) 51 | .pipe($.usemin({ 52 | html: [$.minifyHtml({empty: true})], 53 | css: [$.minifyCss(), 54 | $.size({title: 'css ' + path}), 55 | 'concat'], 56 | vendor: [$.uglify(), 57 | $.size({title: 'vendor ' + path}), 58 | 'concat'], 59 | js: [$.ngAnnotate(), 60 | $.uglify(), 61 | $.size({title: 'js ' + path}), 62 | 'concat'] 63 | })) 64 | .pipe(gulp.dest('dist')); 65 | }; 66 | 67 | //Minify css and js marked in html for build 68 | gulp.task('minify', function() { 69 | minify('app/app.html'); 70 | }); 71 | 72 | //Minify css and js marked in html for build, for prod env 73 | gulp.task('minify-prod', function() { 74 | minify('app/app.html', 'prod'); 75 | }); 76 | 77 | // Minify partials html 78 | gulp.task('partials', function() { 79 | gulp.src('app/partials/*.html') 80 | .pipe($.minifyHtml({empty: true})) 81 | .pipe(gulp.dest('dist/partials/')); 82 | }); 83 | 84 | // Copy icon fonts 85 | gulp.task('icons', function() { 86 | gulp.src(['app/bower_components/font-awesome/fonts/**.*']) 87 | .pipe(gulp.dest('dist/fonts')); 88 | }); 89 | 90 | // Clean output directory 91 | gulp.task('clean', del.bind(null, ['dist/*', '!dist/.git'], {dot: true})); 92 | 93 | // Watch files for changes & reload web app 94 | gulp.task('serve', [], function () { 95 | browserSync({ 96 | notify: false, 97 | logPrefix: 'gulp serve', 98 | server: {baseDir: 'app', index: 'app.html'}, 99 | port: 8103 100 | }); 101 | 102 | //gulp.watch(['app/**.html'], reload);*/ 103 | gulp.watch(['app/app.html'], reload); 104 | gulp.watch(['app/partials/*.html'], reload); 105 | gulp.watch(['app/styles/*.css'], reload); 106 | gulp.watch(['app/scripts/**/*.js'], ['jshint']); 107 | gulp.watch(['app/images/**/*'], reload); 108 | }); 109 | 110 | // Watch files for changes & reload mobile app 111 | gulp.task('serve:ionic', [], function () { 112 | browserSync({ 113 | notify: false, 114 | logPrefix: 'gulp serve:ionic', 115 | server: {baseDir: 'ionic/www', index: 'index.html', 116 | routes: { 117 | '/scripts': 'app/scripts', 118 | '/bower_components': 'app/bower_components', 119 | '/vendor_mods': 'app/vendor_mods' 120 | }}, 121 | port: 8100 122 | }); 123 | 124 | gulp.watch(['ionic/www/**/*.html'], reload); 125 | gulp.watch(['ionic/www/css/*.css'], reload); 126 | gulp.watch(['ionic/www/js/**/*.js'], ['jshint']); 127 | 128 | gulp.watch(['app/scripts/**/*.js'], ['jshint']); 129 | }); 130 | 131 | // Build and serve the output from the dist build 132 | gulp.task('serve:dist', [], function () { 133 | browserSync({ 134 | notify: false, 135 | logPrefix: 'gulp serve:dist', 136 | server: {baseDir: 'dist', index: 'app.html'}, 137 | port: 8104 138 | }); 139 | }); 140 | 141 | var dist = function(env) { 142 | var seq = ['jshint', 'partials', 'icons', 'images', 'copy']; 143 | if(env) { 144 | seq.push('minify-'.concat(env)); 145 | } 146 | else { 147 | seq.push('minify'); 148 | } 149 | runSequence('clean', seq); 150 | } 151 | 152 | //Build minified files, the default task 153 | gulp.task('default', function(cb) { 154 | dist(); 155 | }); 156 | 157 | //Build minified files for prod 158 | gulp.task('prod', function(cb) { 159 | dist('prod'); 160 | }); 161 | 162 | //Build minified files for dev 163 | gulp.task('dev', function(cb) { 164 | dist('dev'); 165 | }); 166 | 167 | // Run PageSpeed Insights 168 | gulp.task('pagespeed', function (cb) { 169 | // Update the below URL to the public URL of your site 170 | pagespeed.output('example.com', { 171 | strategy: 'mobile', 172 | // By default we use the PageSpeed Insights free (no API key) tier. 173 | // Use a Google Developer API key if you have one: http://goo.gl/RkN0vE 174 | // key: 'YOUR_API_KEY' 175 | }, cb); 176 | }); 177 | -------------------------------------------------------------------------------- /docs/p2p-insurance.md: -------------------------------------------------------------------------------- 1 | # Peer-to-peer Insurance Proof Of Concept 2 | This is a functional specification document for the Proof Of Concept of a system enabling users to organize into pools of mutual insurance and insurance companies to insure the risk not covered by the pool. 3 | 4 | Best viewed with [Markdown Reader Plugin for Chrome](https://chrome.google.com/webstore/detail/markdown-reader/gpoigdifkoadgajcincpilkjmejcaanc?utm_source=chrome-app-launcher-info-dialog). 5 | Present with [Markdown Slides Plugin for Chrome](https://chrome.google.com/webstore/detail/markdown-slides/ndpkdbdonkcnidnnmdgphflfcojnhoaa?utm_source=chrome-app-launcher-info-dialog). 6 | 7 | --- 8 | # Peer-to-peer Insurance 9 | 10 | > The aim of peer-to-peer insurance concepts is to make insurance cheaper. For this purpose, a certain number of policyholders pool together. In the event of any claim they support each other financially. If there is no claim, the insurance premiums are reduced. 11 | There are many types of peer-to-peer insurance. This article describes peer-to-peer insurance in the form of the creation of insurance brokers (as opposed to insurance companies). In this model, insurance policyholders will form small groups online. A part of the insurance premiums paid flow into a group fund, the other part to the insurer. Minor damages to the insured policyholder are firstly paid out of this group fund. For claims above the deductible limit the regular insurer is called upon. When there is no insurance claim, the policyholder gets his/her share refunded from the group pool or credited towards the next policy year. If the group pool happens to be empty, a special insurance comes into force. 12 | 13 | https://en.wikipedia.org/wiki/Peer-to-peer_insurance 14 | 15 | --- 16 | # Problem 17 | 18 | * Groups of people would like to insure themselves against risks not commonly insured such as ones in sports, travel, farming, small business. 19 | * The insured would like to simplify and automate the process of claiming and getting paid, especially when the insurance event is a matter of public record such as a delayed flight or a weather condition. 20 | * Insurance companies would like to find new revenue streams covering _long tail_ risks but not take the burden of processing small claims. 21 | 22 | --- 23 | # Solution 24 | 25 | * Permissioned Blockchain 26 | * immutable ledger 27 | * very low cost of deployment and maintenance 28 | * fully transparent to instill trust in consumers 29 | * identity obfuscated to other members 30 | 31 | * Chaincode 32 | * software executed on the blockchain trusted to change records in the ledger 33 | * automate payouts thru integration with systems of public record and payment 34 | * members execute chaincode functions based on their roles 35 | 36 | --- 37 | # Optimization of Insurance Premium 38 | 39 | In an ideal situation the sum of all premiums paid to the p2p insurance pool should equal the sum of all claim payouts. However, the number of claims is initially unknown and varies from year to year. A simple optimization mechanism is proposed where the premium is adjusted every year depending on the sum of payouts the previous year. If there's not enough money in the pool to pay for all claims the pool's insurer steps in and covers the difference. 40 | 41 | * if there's money left in the pool at the end of the year 42 | * the premium for the next year is reduced by a fraction of the remainder 43 | * the remainder is divided and paid back to the members 44 | * if claim payouts exceed the money in the pool 45 | * the premium for the next year is increased by a fraction of the difference between payouts and premiums 46 | * the pool's insurer pays the coverage amounts of the claims not paid by the pool 47 | 48 | --- 49 | # Money 50 | 51 | Users can pay for the insurance and get compensated via various mechanisms each having its pros and cons: 52 | 53 | * coins: tokens unique for this blockchain. Coins move between accounts representing payments. When users register in the system they convert fiat money to coins via a payment system such as credit card, bank transfer or PayPal. They can also withdraw: convert their coins back to fiat money. 54 | * _pros_ easy to develop 55 | * _cons_ for deposit and withdrawal the pool requires an account with a payment system and thus needs an operator registered as a legal entity 56 | * cryptocurrency: the chaincode can invoke gateways to popular cryptocurrency chains such as Bitcoin or Ethereum. These calls can be made within the same transaction and don't involve payment systems. 57 | * _pros_ does not require a pool operator as a legal entity with a bank account 58 | * _cons_ users may not have accounts in cryptocurrencies 59 | 60 | --- 61 | 62 | * payment oracle: fiat money is transferred outside of the blockchain by payment systems such as ACH for bank transfers, Stripe for credit cards or PayPal. Clients of these systems are trusted by the users and inform the blockchain of fiat money transferred between users' accounts. 63 | * _pros_ little friction with familiar payments: users provide their credit cards or bank accounts or PayPal 64 | * _cons_ requires an account with a payment system and thus needs an operator registered as a legal entity 65 | 66 | We choose the _payment oracle_ mechanism for this POC. 67 | 68 | --- 69 | # Records 70 | 71 | Records are stored on the blockchain either as the chaincode's key value sets or tables. 72 | 73 | * Pool 74 | insurance pool is policy created by members 75 | 76 | * MemberPool 77 | members may enter many pools so the many-to-many relationship is maintained in a separate table 78 | 79 | --- 80 | # Actors 81 | 82 | Actors are users of various roles in the system. Their ids and roles are defined in the blockchain's member services records. Other attributes may also be defined in the member services or on the blockchain or in a separate persistence store. For the POC it's sufficient to predefine a set of users with all of their attributes in the member services `yaml` files. 83 | 84 | * Member 85 | person organizing and entering insurance pools 86 | 87 | * Insurer 88 | insurance company insuring risks exceeding capacity of the pool 89 | 90 | --- 91 | # Oracles 92 | 93 | *Oracle* is a mechanism to inject events occurring outside of the blockchain. It is a third party agreed to be trusted by all members and operates as a node on the blockchain with special permissions to the chaincode methods. 94 | 95 | * Claim Oracle 96 | notifies the blockchain that a claim condition is triggered 97 | _example_ a public weather service reports no wind. Organizers of a yacht regatta insured themselves against this condition; their claim is processed automatically and they get paid right away to spend on a champaign and lobster lunch for sailors onshore. 98 | _example_ a flight tracking service reports a delayed flight. A traveller insured himself against this condition; his claim gets processed automatically and he spends the payout on a night in a hotel. 99 | 100 | --- 101 | 102 | _example_ a small crops farmer plants an internet connected moisture sensor, one per acre of his land. When the sensor reports low levels for 30 consecutive days a drought condition is triggered and the farmer gets paid automatically 103 | _example_ a hotelier in a developing country insured himself against a power blackout. When a smart electricity meter reports an outage the hotelier gets paid right away to spend on diesel for the hotel's generator to provide uninterrupted power for his guests. 104 | 105 | --- 106 | 107 | * Payment Oracle 108 | notifies the blockchain that a transfer of fiat money occurred between members' accounts. Can be a client listening on events in a payment system such as ACH network, Stripe, PayPal. 109 | _example_ an ACH client permissioned by the insurance pool operator to listen on events in their accounts payable. 110 | Calls the chaincode method to notify the blockchain that a payment of a claim to the insured occurred. The chaincode decrements the size of the pool and adds a record of the claim to the transaction history. 111 | _example_ an ACH client permissioned by the pool operator to listen on events in their accounts receivable. 112 | Notifies the blockchain of payment of a premium from a member. The chaincode increments the size of the pool and adds a record of the payment the to transaction history. 113 | 114 | --- 115 | # Member 116 | 117 | Both roles: members and insurers have these attributes. 118 | 119 | - id 120 | unique id chosen by members 121 | _example_ manuel, vladimir, Allianz 122 | - password 123 | a secret needs to be passed to the blockchain's member services to authenticate the member to transact 124 | - paymentAccount 125 | various payment oracles will identify members by accounts in respective payment systems 126 | - aba.account 127 | composite unique identifier of the member's fiat money bank account used by a bank transfer ACH oracle. When a payment of fiat money occurs the payment oracle will report to the blockchain a money transfer event with parties' bank aba and account numbers. 128 | aba: member bank identifier, account: member bank account identifier 129 | - paypalEmail 130 | for pools selecting PayPal as their payment mechanism 131 | 132 | --- 133 | # Pool 134 | 135 | - id 136 | sequential identifier unique within the chaincode 137 | - name 138 | descriptive name 139 | _example_ JFK flight delay 140 | - trigger 141 | a condition reported by claim oracle or approved by a claims processor that triggers a payout to the insured 142 | _example_ 1 hour delay of Jet Blue flight 101 on Jun 10 2016: a delay in flight departure making it impossible to board the next flight in a specific itinerary 143 | _example_ dryness level over 70% for 30 consecutive days in Arizona: indicates a drought condition 144 | - coverage 145 | amount paid to the insured per claim 146 | _example_ $300 per flight delayed 147 | _example_ $1,000 per acre of farm land affected by drought 148 | 149 | --- 150 | 151 | - premium 152 | one time or yearly payment by each member into the pool 153 | _example_ one time $10 fee insuring a traveller against a flight delayed in his specific itinerary 154 | _example_ yearly $100 fee per acre a small crops farmer pays insuring against drought 155 | - amount 156 | current total amount held in the pool 157 | - insurerId 158 | member id of the insurance company covering payouts exceeding pool's capacity. Initially not set until an insurer decides to insure the pool 159 | _example_ Allianz 160 | - insurerPremium 161 | part of the premium paid to the insurance company to insure claims exceeding pool's capacity 162 | _example_ $10 of the $100 member premium 163 | 164 | --- 165 | # Web Application 166 | 167 | The POC is presented as a web application with pages offering functionality to 168 | * Members: create and enter pools 169 | * Insurers: select pools to insure 170 | 171 | The following sections describe these pages per actor. 172 | 173 | --- 174 | # Member: Enter Pool 175 | 176 | A public page listing available insurance pools. 177 | 178 | name | trigger | coverage | premium | | 179 | ---|---|---|---|--- 180 | Drought Arizona | 30 days dryness over 70%, per acre in Arizona in 2016 | $1000 | $100 | enter / insure 181 | JFK flight delay | flight out of JFK delayed over 1 hour in June 2016 | $200 | $10 | enter / insure 182 | No wind Long Island Regatta | wind below 5 knots June 10 2016 in Long Island Sound | $2000 | $100 | enter / insure 183 | 184 | When a user clicks _enter_ to select a pool a modal confirmation window comes up prompting to agree to terms and enter the pool. 185 | 186 | https://boughtbymany.com is a p2p insurance broker. Their home page serves as a good example. 187 | 188 | For the POC, the user is assumed to be logged in to the web site; otherwise the user is asked to login or create an account. 189 | 190 | --- 191 | # Member: Create Pool 192 | 193 | When a _Create Pool_ button is clicked on the public page a modal window comes up where the user can enter details of a new pool and propose it to other users. 194 | 195 | CREATE | Pool 196 | ---|--- 197 | name | Drought Arizona 198 | trigger | (dropdown of conditions: `Drought Arizona 2016`, `JFK flight delay Jun 2016`) 199 | coverage | $1000 200 | premium | $100 201 | 202 | When _Create_ button is clicked a method of the chaincode is called to create a record of the new pool and a record in member-pool table with the creator as its first member. 203 | 204 | The pool appears on the Pools public page for other members to enter and for insurers to select to insure. 205 | 206 | --- 207 | # Insurer: Insure Pool 208 | 209 | A representative of an insurance company selects a pool the company finds profitable to insure. In the real world multiple insurance companies bid on a pool and the chaincode selects the one with better terms. For the POC the scenario is simplified. 210 | 211 | When _insure_ link is clicked on a row on the public Pools page a modal window comes up prompting the insurer to enter their terms to insure this pool. 212 | 213 | INSURE | Pool 214 | ---|--- 215 | premium | $10 216 | 217 | When _Insure_ button is clicked a method of the chaincode is called to add the insurer to the record of the selected pool. 218 | 219 | --- 220 | # Payment Oracle 221 | 222 | For the POC this will be a simple demo page imitating a call from an ACH client informing the blockchain of a money transfer for a premium payment to the pool or a claim payout to member. 223 | 224 | TRANSFER | Money | 225 | ---|--- 226 | from aba.account | 02100210.12345678 227 | to aba.account | 03200320.09876543 228 | amount | $500 229 | purpose | (dropdown of premium, insurerPremium, payout) 230 | id | id of pool, insurer or member 231 | 232 | Once the _Transfer_ button is clicked the chaincode's method is invoked with the transfer details entered. The chaincode in turn finds the pool by id and verifies parties of the transfer. 233 | 234 | --- 235 | # Claim Oracle 236 | 237 | For the POC this will be a simple demo page imitating a call from a public service client informing the blockchain of an insurance event. 238 | 239 | TRIGGER | Event | 240 | ---|--- 241 | select | (dropdown of `Drought Arizona 2016`, `JFK flight delay Jun 2016`) 242 | 243 | Once the _Trigger_ button is clicked the chaincode's method is invoked to search for all pools whose trigger matches the one selected and marks them as needed to pay their members. 244 | 245 | --- 246 | # Timing Mechanism 247 | 248 | A mechanism: either an oracle or a service offered by the blockchain is to inform the chaincode of progression of time. 249 | 250 | For the POC that service can be imitated by an interval service of a browser calling the chaincode's method to progress time and at the same time displaying current month and year on every page. The progression of time in the demo needs to be accelerated so a month is changed every minute, and controlled via _start_ and _stop_ buttons. 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | --------------------------------------------------------------------------------