Compliance Server on stellar network

# Compliance Server on stellar network

[合同会社kumanote](https://kumano-te.com/)の田中です。
引き続きstellarの実装調査を行いましたので、そのメモになります。

**前回までの記事**

- [getting started stellar with javascript SDK - Qiita](http://qiita.com/KumanoT/items/059a32a62af34f74a28d)
- [Let's become an anchor on stellar network - Qiita](http://qiita.com/KumanoT/items/41d32aa44b3e5d32d9ed)
- [Federation Server on stellar network - Qiita](http://qiita.com/KumanoT/items/5fc823724c87b7462c37)


## Compliance Serverとは

金融的なサービスの運営者は、社会的悪にその力を貸さないようにする義務があります。
マネーロンダリング、振込詐欺、脱税等に助力しないということです。

このため、サービス内では、誰が誰に対して送金しているかをチェックし、サービスがコンプライアンスを満たしているかをチェックする義務がでてきます。
この部分を切り出し、汎用的に利用できるようにしたものがCompliance Serverということになります。

BitcoinやEthereum上のサービスも当然こういう性質をもつべきなのですが、そこがないものが多いですよね。
それが魅力でもあり、規制対象でもあるのでしょうが。。。
規制が厳しくなる方向で世の中が動いていますが、確実にこういうサービスは需要がでてくると思います。
（各暗号通貨の）アドレスと個人情報（KYC）をあつめたデータベースを構築し、Complianceをチェックする機関がでてくるかもしれませんね。
こういうのも含めて、結局は送金手数料がかかってくるようになってしまいそうで・・面白くないですね。

まあ、世の中の流れはおいておいて、以下試した内容をかいつまんでご紹介します。

## complianceの仕組みの流れ

[compliance-protocol](https://www.stellar.org/developers/guides/compliance-protocol.html)に準じるのが良いみたいです。

### example of flow case a1 send some credit to b1

#### objects

- 自社システム: A(bankA.com)
  - そのアカウント: a1
- 他者システム: B(bankB.com)
  - そのアカウント: b1

#### flow

- b1を問い合わせる（Bのfederation）（送信するため）
  - Aがhttps://bankB.com/.well-known/stellar.toml を参照し、BのFEDERATION_SERVERのendpointを取得する
  - AがBのFEDERATION_SERVERに対し、b1の情報を取得するためのリクエストを投げる
- Aがb1のcomplianceチェックを委託する
  - Aがhttps://bankB.com/.well-known/stellar.toml を参照し、BのAUTH_SERVERのendpointを取得する
  - AがBのAUTH_SERVERに対して、a1の情報を送信する
- Bがcompliance(auth request)チェックを行う
  - Bがリクエストのsender情報を元に、https://bankA.com/.well-known/stellar.toml を参照し、AのSIGNING_KEYを取得する
  - Bがauth requestのキーチェックを行う。（ちゃんとAから送信されていること）
  - Bがリクエストのsender情報を元に、senderのcomplianceチェックを行う
  - Bが以下の情報を元にAML情報を開示するかどうかを決める
    - b1が自身の情報を公開しているか
    - b1がAを許可しているか
    - b1がa1を許可しているか
    - BがAを許可しているか
  - もしb1が上記のいずれの条件も当てはまらない場合は、Bはb1に対して、Aに対して情報を開示しても良いかを問い合わせる必要がある
    - この場合、BはAに対して、`info_status:"pending"`のレスポンスを返す
  - もしBがb1の情報を開示する場合は、`dest_info`にb1のAML情報を格納してレスポンスを返す
- AがBのcomplianceチェックした結果を元に処理を行う
  - Aは、もし`info_status:"pending"`のレスポンスがBから返却されている場合、`pending`秒後に再度リクエストを行う
  - Aは、もし`dest_info`がBから返却されている場合、complianceチェックを行い、問題なければ、stellar networkに対してトランザクションを送信する
- Bが送金受理を行う
  - Bがトランザクションハッシュのチェックまたはa1のcompliance再チェックを行う
  - 問題なければ、Bはb1に対してクレジットを発行する


## try out

- [ここ](https://www.stellar.org/developers/guides/anchor/4-compliance-server.html)を見ながら、試してみます。

基本的には、以下のコラボレーションで動かす感じです。

- bridge server
- federation server
- compliance server
- stellar.toml hosting server

[ここ](https://github.com/KumanoTanaka/test-stellar/blob/master/docker-compose.yml)に構成を記載しています。

```yml
version: "2"
services:
  stellar-kumano-te.com:
    build: ./stellar
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "./stellar/keys:/etc/nginx/keys"
      - "./stellar/sites-enabled:/etc/nginx/sites-enabled"
      - "./stellar/.well-known:/var/www/stellar-kumano-te.com/.well-known"
    container_name: stellar-kumano-te.com
  bridge-kumano-te.com:
    build: ./bridge-server
    ports:
      - "8001:8001"
    command: ./wait-for-it.sh bridge-db:3306 -t 600 -s -- ./bridge
    depends_on:
      - bridge-db
    container_name: bridge-kumano-te.com
  bridge-db:
    image: mysql:5.6
    environment:
      MYSQL_ROOT_PASSWORD: bridge
      MYSQL_DATABASE: bridge
      MYSQL_USER: bridge
      MYSQL_PASSWORD: bridge
      TZ: JST
    volumes:
      - ./bridge-db/conf.d:/etc/mysql/conf.d
      - bridge-db-data:/var/lib/mysql
    container_name: bridge-db
  federation-kumano-te.com:
    build: ./federation-server
    ports:
      - "8002:8002"
    command: ./wait-for-it.sh federation-db:3306 -t 600 -s -- ./federation
    depends_on:
      - federation-db
    container_name: federation-kumano-te.com
  federation-db:
    image: mysql:5.6
    environment:
      MYSQL_ROOT_PASSWORD: federation
      MYSQL_DATABASE: federation
      MYSQL_USER: federation
      MYSQL_PASSWORD: federation
      TZ: JST
    volumes:
      - ./federation-db/init.d:/docker-entrypoint-initdb.d
      - ./federation-db/conf.d:/etc/mysql/conf.d
      - federation-db-data:/var/lib/mysql
    container_name: federation-db
  compliance-kumano-te.com:
    build: ./compliance-server
    ports:
      - "8003:8003"
      - "8004:8004"
    command: ./wait-for-it.sh compliance-db:3306 -t 600 -s -- ./compliance
    depends_on:
      - compliance-db
    container_name: compliance-kumano-te.com
  compliance-db:
    image: mysql:5.6
    environment:
      MYSQL_ROOT_PASSWORD: compliance
      MYSQL_DATABASE: compliance
      MYSQL_USER: compliance
      MYSQL_PASSWORD: compliance
      TZ: JST
    volumes:
      - ./compliance-db/conf.d:/etc/mysql/conf.d
      - compliance-db-data:/var/lib/mysql
    container_name: compliance-db
  callbacks-kumano-te.com:
    build: ./callbacks
    ports:
      - "8005:8005"
    command: npm start
    depends_on:
      - bridge-db
      - federation-db
      - compliance-db
    container_name: callbacks-kumano-te.com
volumes:
  bridge-db-data:
    driver: local
  federation-db-data:
    driver: local
  compliance-db-data:
    driver: local
```

### tips

自己証明書を今回は使用したのですが、公式のbridge-serverは自己証明書だと動かないため
公式をフォークし[修正](https://github.com/KumanoTanaka/bridge-server/commit/495d63d1a28e42e155d412a2463b4ec39add846c)したものを使用することにしました。

### 結果

以下を実行すると、各サーバーがコラボして、処理を行います。

```js
(function() {
  var request = require('request');
  request.post({
    url: 'http://localhost:8001/payment',
    form: {
      amount: '1',
      asset_code: 'KumaDollar',
      asset_issuer: 'GAOOFELY4CO2L4YWOVOEF2J233NF4XHVWTKFUUJU5QJO7UKJ2T2MBTR7',
      destination: 'amy_smith*stellar-kumano-te.com',
      source: 'SB5PJSVV3K62V3MSQGG6DKMNHR4BONGAEK5TTSMFPQCQZJE6RVHXWETN',
      sender: 'tunde_adebayo*stellar-kumano-te.com',
      // `extra_memo` is required for compliance (use it instead of `memo`)
      extra_memo: 'Test transaction',
    }
  }, function(error, response, body) {
    if (error || response.statusCode !== 200) {
      console.error('ERROR!', error || body);
    }
    else {
      console.log('SUCCESS!', body);
    }
  });
})();

> SUCCESS! {
  "hash": "db4cee9cbec4ff13e11c23f20687f0742e6d2a999c62abc0682227d9e22efb21",
  "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=",
  "ledger": 3903847
}
```

以下、`docker-compose up`上のログになります。

```bash
$ docker-compose up
Creating stellar-kumano-te.com ... 
Creating compliance-db ... 
Creating federation-db ... 
Creating bridge-db ... 
Creating stellar-kumano-te.com
Creating bridge-db
Creating compliance-db
Creating federation-db ... done
Creating compliance-kumano-te.com ... 
Creating bridge-db ... done
Creating federation-kumano-te.com
Creating callbacks-kumano-te.com ... 
Creating compliance-kumano-te.com
Creating bridge-kumano-te.com ... 
Creating callbacks-kumano-te.com
Creating bridge-kumano-te.com ... done
Attaching to stellar-kumano-te.com, compliance-db, federation-db, bridge-db, federation-kumano-te.com, compliance-kumano-te.com, callbacks-kumano-te.com, bridge-kumano-te.com
compliance-db               | 2017-09-12 03:40:27 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
compliance-db               | 2017-09-12 03:40:27 0 [Note] mysqld (mysqld 5.6.36) starting as process 1 ...
federation-db               | 2017-09-12 03:40:27 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
federation-db               | 2017-09-12 03:40:27 0 [Note] mysqld (mysqld 5.6.36) starting as process 1 ...
bridge-db                   | 2017-09-12 03:40:28 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
bridge-db                   | 2017-09-12 03:40:28 0 [Note] mysqld (mysqld 5.6.36) starting as process 1 ...
federation-kumano-te.com    | wait-for-it.sh: waiting 600 seconds for federation-db:3306
federation-kumano-te.com    | wait-for-it.sh: federation-db:3306 is available after 0 seconds
federation-kumano-te.com    | time="2017-09-12T03:40:29Z" level=info msg="starting federation server - devel" pid=1
federation-kumano-te.com    | time="2017-09-12T03:40:29Z" level=info msg="listening on 0.0.0.0:8002" pid=1
compliance-kumano-te.com    | wait-for-it.sh: waiting 600 seconds for compliance-db:3306
compliance-kumano-te.com    | wait-for-it.sh: compliance-db:3306 is available after 0 seconds
compliance-kumano-te.com    | time="2017-09-12T03:40:29Z" level=info msg="Starting external server on :8003" 
compliance-kumano-te.com    | time="2017-09-12T03:40:29Z" level=info msg="Starting internal server on :8004" 
bridge-kumano-te.com        | wait-for-it.sh: waiting 600 seconds for bridge-db:3306
bridge-kumano-te.com        | wait-for-it.sh: bridge-db:3306 is available after 0 seconds
bridge-kumano-te.com        | time="2017-09-12T03:40:30Z" level=info msg="Creating and initializing TransactionSubmitter" 
bridge-kumano-te.com        | time="2017-09-12T03:40:30Z" level=info msg="Initializing Authorizing account" 
bridge-kumano-te.com        | time="2017-09-12T03:40:30Z" level=info msg="Loading account" accountID=GAOOFELY4CO2L4YWOVOEF2J233NF4XHVWTKFUUJU5QJO7UKJ2T2MBTR7 service=Horizon 
callbacks-kumano-te.com     | npm info it worked if it ends with ok
callbacks-kumano-te.com     | npm info using npm@5.3.0
callbacks-kumano-te.com     | npm info using node@v8.4.0
callbacks-kumano-te.com     | npm info lifecycle callbacks@1.0.0~prestart: callbacks@1.0.0
callbacks-kumano-te.com     | npm info lifecycle callbacks@1.0.0~start: callbacks@1.0.0
callbacks-kumano-te.com     | 
callbacks-kumano-te.com     | > callbacks@1.0.0 start /usr/local/src/callbacks
callbacks-kumano-te.com     | > node index.js
callbacks-kumano-te.com     | 
callbacks-kumano-te.com     | Bridge server callbacks running on port 8005!
bridge-kumano-te.com        | time="2017-09-12T03:40:32Z" level=info msg="Account loaded" accountID=GAOOFELY4CO2L4YWOVOEF2J233NF4XHVWTKFUUJU5QJO7UKJ2T2MBTR7 service=Horizon 
bridge-kumano-te.com        | time="2017-09-12T03:40:32Z" level=info msg="Initializing Base account" 
bridge-kumano-te.com        | time="2017-09-12T03:40:32Z" level=info msg="Loading account" accountID=GATLCZMS3ITTVSCM2VB55KT2I7OHHXOWD2QM6O4BNK5LQTD2A3T7DINC service=Horizon 
bridge-kumano-te.com        | time="2017-09-12T03:40:32Z" level=info msg="Account loaded" accountID=GATLCZMS3ITTVSCM2VB55KT2I7OHHXOWD2QM6O4BNK5LQTD2A3T7DINC service=Horizon 
bridge-kumano-te.com        | time="2017-09-12T03:40:32Z" level=info msg="TransactionSubmitter created" 
bridge-kumano-te.com        | time="2017-09-12T03:40:32Z" level=info msg="Creating and starting PaymentListener" 
bridge-kumano-te.com        | time="2017-09-12T03:40:32Z" level=info msg="Loading account" accountID=GATLCZMS3ITTVSCM2VB55KT2I7OHHXOWD2QM6O4BNK5LQTD2A3T7DINC service=Horizon 
bridge-kumano-te.com        | time="2017-09-12T03:40:32Z" level=info msg="Account loaded" accountID=GATLCZMS3ITTVSCM2VB55KT2I7OHHXOWD2QM6O4BNK5LQTD2A3T7DINC service=Horizon 
bridge-kumano-te.com        | time="2017-09-12T03:40:32Z" level=info msg="PaymentListener created" 
bridge-kumano-te.com        | time="2017-09-12T03:40:32Z" level=info msg="Started listening for new payments" accountId=GATLCZMS3ITTVSCM2VB55KT2I7OHHXOWD2QM6O4BNK5LQTD2A3T7DINC cursor=16765688307781633 service=PaymentListener 
federation-kumano-te.com    | time="2017-09-12T03:40:48Z" level=info msg="starting request" host="localhost:8002" ip="172.23.0.1:53858" method=GET path="/federation?q=amy_smith%2Astellar-kumano-te.com&type=name" pid=1 subsys=http
federation-kumano-te.com    | time="2017-09-12T03:40:48Z" level=info msg="finished request" bytes=111 duration=2.857338ms pid=1 status=200 subsys=http
federation-kumano-te.com    | time="2017-09-12T03:40:58Z" level=info msg="starting request" host="federation-kumano-te.com:8002" ip="172.23.0.7:41610" method=GET path="/federation?q=amy_smith%2Astellar-kumano-te.com&type=name" pid=1 subsys=http
federation-kumano-te.com    | time="2017-09-12T03:40:58Z" level=info msg="finished request" bytes=111 duration=1.15153ms pid=1 status=200 subsys=http
compliance-kumano-te.com    | time="2017-09-12T03:40:58Z" level=info msg=HandlerAuth data="{\"sender\":\"tunde_adebayo*stellar-kumano-te.com\",\"need_info\":false,\"tx\":\"AAAAACaxZZLaJzrITNVD3qp6R9xz3dYeoM87gWq6uEx6BufxAAAAZAAAAAAAAAAAAAAAAAAAAAO++vwHaNENts80IR5ZqBIHB8YMbPhEPQm5KvYKUsNC9gAAAAEAAAAAAAAAAQAAAAAmsWWS2ic6yEzVQ96qekfcc93WHqDPO4FqurhMegbn8QAAAAJLdW1hRG9sbGFyAAAAAAAAHOKReOCdpfMWdVxC6Tre2l5c9bTUWlE07BLv0UnU9MAAAAAAAJiWgAAAAAA=\",\"attachment\":\"{\\\"nonce\\\":\\\"1505187658244446627\\\",\\\"transaction\\\":{\\\"sender_info\\\":{\\\"address\\\":\\\"GATLCZMS3ITTVSCM2VB55KT2I7OHHXOWD2QM6O4BNK5LQTD2A3T7DINC\\\",\\\"first_name\\\":\\\"Tunde\\\",\\\"last_name\\\":\\\"Adebayo\\\"},\\\"route\\\":\\\"amy_smith\\\",\\\"note\\\":\\\"\\\",\\\"extra\\\":\\\"Test transaction\\\"},\\\"operations\\\":null}\"}" sig="czmn4BddjNlG6FWDN/oyan4gnCEi8BhsL6+b1L+JQL6szDzvaO/+JWUgGjp5yQg4a+Du9UvtYSc1srbSy++PAA==" 
bridge-kumano-te.com        | time="2017-09-12T03:41:05Z" level=info msg="Success response from horizon" ledger=0xc42033c228 service=Horizon 
bridge-kumano-te.com        | time="2017-09-12T03:41:05Z" level=info msg="New received payment" id=16766895193591809 service=PaymentListener 
bridge-kumano-te.com        | time="2017-09-12T03:41:06Z" level=info msg="Loaded memo" memo="vvr8B2jRDbbPNCEeWagSBwfGDGz4RD0JuSr2ClLDQvY=" service=PaymentListener type=hash 
bridge-kumano-te.com        | time="2017-09-12T03:41:06Z" level=info msg="Sending request to compliance server" body=map[memo:[vvr8B2jRDbbPNCEeWagSBwfGDGz4RD0JuSr2ClLDQvY=]] service=PaymentListener url="http://compliance-kumano-te.com:8004/receive" 
callbacks-kumano-te.com     | /receive
callbacks-kumano-te.com     | { amount: '1.0000000',
callbacks-kumano-te.com     |   asset_code: 'KumaDollar',
callbacks-kumano-te.com     |   asset_issuer: 'GAOOFELY4CO2L4YWOVOEF2J233NF4XHVWTKFUUJU5QJO7UKJ2T2MBTR7',
callbacks-kumano-te.com     |   data: '{"sender":"tunde_adebayo*stellar-kumano-te.com","need_info":false,"tx":"AAAAACaxZZLaJzrITNVD3qp6R9xz3dYeoM87gWq6uEx6BufxAAAAZAAAAAAAAAAAAAAAAAAAAAO++vwHaNENts80IR5ZqBIHB8YMbPhEPQm5KvYKUsNC9gAAAAEAAAAAAAAAAQAAAAAmsWWS2ic6yEzVQ96qekfcc93WHqDPO4FqurhMegbn8QAAAAJLdW1hRG9sbGFyAAAAAAAAHOKReOCdpfMWdVxC6Tre2l5c9bTUWlE07BLv0UnU9MAAAAAAAJiWgAAAAAA=","attachment":"{\\"nonce\\":\\"1505187658244446627\\",\\"transaction\\":{\\"sender_info\\":{\\"address\\":\\"GATLCZMS3ITTVSCM2VB55KT2I7OHHXOWD2QM6O4BNK5LQTD2A3T7DINC\\",\\"first_name\\":\\"Tunde\\",\\"last_name\\":\\"Adebayo\\"},\\"route\\":\\"amy_smith\\",\\"note\\":\\"\\",\\"extra\\":\\"Test transaction\\"},\\"operations\\":null}"}',
callbacks-kumano-te.com     |   from: 'GATLCZMS3ITTVSCM2VB55KT2I7OHHXOWD2QM6O4BNK5LQTD2A3T7DINC',
callbacks-kumano-te.com     |   id: '16766895193591809',
callbacks-kumano-te.com     |   memo: 'vvr8B2jRDbbPNCEeWagSBwfGDGz4RD0JuSr2ClLDQvY=',
callbacks-kumano-te.com     |   memo_type: 'hash',
callbacks-kumano-te.com     |   route: 'amy_smith' }
bridge-kumano-te.com        | time="2017-09-12T03:41
```

## 最後に

前回からの流れで、一通りstellarを使った金融サービスを構築する際の基本構成を試すことができました。
かなり得られた気づきがあり、とても良かったです。
個人的には、こういった構成やプロトコルはstellarに閉じた話ではないと感じましたので、応用していけたらと思います。

以上になります。