Web3医療DAppを開発する！

![MedicalDApp.001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299653/f4baaeed-fd22-73aa-5e9a-3ea1fd415789.jpeg)


皆さんこんにちは！！

今回は、スマートコントラクトを利用して患者の医療データを管理するアプリを開発するアプリの作成に挑んでみましたのでその過程等をまとめていきます！
UNCHAINというWeb3エンジニアコミュニティに参加させていただいているのですが、一定条件を満たすとUNCHAIN STARとなることができます。

その一定条件というのが、UNCHAIN STAR試験に合格するというものです！

## 目次

1. 開発したアプリの概要
2. 簡単な機能一覧等の説明
3. 画面の説明
4. 最後に

### 開発したアプリの概要

今回挑戦した試験の概要は<a href="https://unchain-shiftbase.notion.site/2-Distributed-medical-database-Japanese-18540901b8114aa787e7ec3aa30d5602">下のサイト</a>をご覧ください！

https://unchain-shiftbase.notion.site/2-Distributed-medical-database-Japanese-18540901b8114aa787e7ec3aa30d5602

また、vercel上にアプリを公開しておりますので、まずアプリに触れてみたい！という方は下のURLからアクセスしてください！

https://web3-medical-dapp.vercel.app/

ざっくりと説明すると患者と医者の間でやり取りするカルテ情報の管理と治療費と支払い、医師の登録を可能とするWeb3アプリとなっています！画面は4画面存在して下記の通りとなっています。

|No.|画面名|
|---|---|
|1|Connect Wallet画面|
|2|Home画面|
|3|Regist画面|
|4|DoctorInfo画面|

実際に患者と医者の間でこのアプリを使用した時の想定のやり取りをフロー図に起こしたものがありますのでそちらも貼り付けます。

![mermaid-diagram-2022-07-09-181130.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299653/7e41dd3c-a000-fd51-6290-96955432989a.png)

デプロイしたスマートコントラクトですがgoreliとmunbaiの2つのネットワークにデプロイしました。内容については差異はないのでお好みの方をEtherScanかPolygonScanでご確認ください。

| No  | ネットワーク | コントラクト名 | アドレス                                                                                                                                   |
| --- | ------------ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| 1   | goreli       | MedicalData    | <a href="https://goerli.etherscan.io/address/0x177acf501eF7d2b090d94fd3bd2BE773736598E1">0x177acf501eF7d2b090d94fd3bd2BE773736598E1</a>    |
| 2   | munbai       | MedicalData    | <a href="https://mumbai.polygonscan.com/address/0x83f15ccdD1278908dF5bC646E903afE2f342deC1">0x83f15ccdD1278908dF5bC646E903afE2f342deC1</a> |

### 簡単な機能一覧等の説明

それでは機能等の解説になります。
今回のアプリを作成するにあたり、一番核となるMedicalDataコントラクトに実装した機能一覧をまとめます。

#### 機能一覧表

| 機能名                 | 説明                                                                                                     |
| ---------------------- | -------------------------------------------------------------------------------------------------------- |
| Connect Wallet 機能    | 患者と医療従事者の両方が、自分のウォレットをアプリケーションに接続できる                                 |
| 医療データ閲覧機能     | 患者は、アプリケーションのダッシュボードで、自分の秘密鍵を使って、自分の医療データを閲覧することができる |
| 医療データ新規登録機能 | 患者のデータを医者が新規に追加する                                                                       |
| アクセス許可提供機能   | 医療提供者に自分の医療データへのアクセスを提供する機能                                                   |
| 編集権限承認要求機能   | 患者の医療データを編集する際、患者に承認を求める機能                                                     |
| 医療データ編集機能     | 医療従事者はその患者の医療データを編集する機能                                                           |
| 閲覧権限変更機能       | 医療データへのアクセス権限を一度承認した医療提供者から再度制限できる機能                                 |
| 医師情報登録機能       | 医者の情報を新たに登録できる機能                                                                         |
| 医師情報確認機能       | 医者又は患者が医師の情報を確認できる機能                                                                 |
| 治療費支払い機能       | 患者が医者に治療費を支払う機能                                                                           |
| 治療費受け取り機能     | 医者が治療費を受け取る機能                                                                               |

また、コントラクトに実装した変数とメソッドの概要も表にまとめましたので記載いたします。
名前と更新日時、血液データという少ないデータだからこその実装かもしれませんがベース部分はこの考え方で良いと考えています。

#### 変数一覧

| 変数名           | タイプ                          | 内容                                                                       |
| ---------------- | ------------------------------- | -------------------------------------------------------------------------- |
| owner            | address                         | コントラクトの管理者                                                       |
| patientName      | String                          | 患者の名前                                                                 |
| bloodYype        | String                          | 血液型                                                                     |
| lastUpdate       | String                          | 最終更新日時(yyyy/mm/dd HH:mm:ss 形式)                                     |
| MedicalInsDatas  | Struct                          | 最終更新日時、最終更新医療機関                                             |
| medicalData      | Struct                          | 患者の医療データ用の Struct 型の変数                                       |
| doctorInfo       | Struct                          | 患者が持つ医者についてのデータを保管する Struct 型の変数                   |
| medicalMap       | (address ⇨ medicalData)         | 患者のアドレスと医療データを紐付ける Map                                   |
| doctorMap        | (address → String)              | 医者のアドレスと名前を紐づける Map                                         |
| doctorRoleMap    | (address → bool)                | アドレスが医者であることを紐づける Map                                     |
| doctorBalanceMap | (address → uint256)             | 医者のアドレスと受け取る治療費を紐づける Map                               |
| doctors          | [address]                       | 医療機関に所属する医者のアドレスを格納する                                 |
| approveMap       | (address ⇨ (address ⇨ boolean)) | 患者のデータに対して医者側が閲覧権限を所有しているか保持するための Map     |
| requireMap       | (address ⇨ (address ⇨ boolean)) | 患者のデータに対して医者側が閲覧権限を要求している状態を保持するための Map |

#### メソッド一覧

| メソッド名               | 内容                                               |
| ------------------------ | -------------------------------------------------- |
| approve                  | 医者側に閲覧・編集権限を付与するメソッド           |
| changeStatus             | 閲覧・編集権限を停止するメソッド                   |
| createMedicalData        | 医療データを新規で登録するメソッド                 |
| editMedicalData          | 医療データを編集するメソッド                       |
| deleteMedicalData        | 医療データを削除するメソッド                       |
| selectMedicalData        | 自分の医療データを取得するメソッド                 |
| selectPatientMedicalData | 患者の医療データを取得するメソッド                 |
| registDoctor             | 医師のデータを新たに登録するメソッド               |
| claimApprove             | 患者に対して医師が閲覧権限を要求できるメソッド     |
| getDoctors               | 現在登録中の全ての医師のアドレスを取得するメソッド |
| getDoctorInfo            | 患者に紐づく全て医師の情報を取得するメソッド       |
| pay                      | 患者が医者に治療費を支払うためのメソッド           |
| withdraw                 | 医者が治療費を受け取るためのメソッド               |

医療データという大切なデータを取り扱うスマートコントラクトですのでテストコードもしっかりと書きました！！ かなり長くなってしまうのでコードの掲載は割愛させていただきますが、正常系はもちろんのこと、医者の権限を持つアドレスからの呼び出ししか許さないメソッドを患者のアドレスから呼び出そうとした時にエラーが発生するかなど、異常系のテストシナリオも記載しています。

テストの結果は下記の通りです！

```cmd
Using network 'development'.


Compiling your contracts...
===========================
> Compiling ./contracts/MedicalData.sol
> Artifacts written to /var/folders/0c/vbkwk57s4lb21y1ts4ndr9zh0000gn/T/test--2339-yBPTyliYIpnH
> Compiled successfully using:
   - solc: 0.8.0+commit.c7dfd78e.Emscripten.clang



  Contract: MedicalData Contract tests!!
    initialization
      ✓ confirm owner address
      ✓ confirm doctor's address (40ms)
      ✓ confirm doctor's name (116ms)
    get doctor info tests
      ✓ get doctor info
    add a new doctor
      ✓ confirm doctor's address and name (231ms)
      ✓ Should revert when contract is called from invalid address (421ms)
    approve method tests
      ✓ approve (99ms)
      ✓ chageStatus (60ms)
      ✓ should revert when contract is called from invalid role address (135ms)
      ✓ should revert when contract is called from invalid role address (47ms)
    claim approve method tests
      ✓ require approvement (88ms)
      ✓ should revert when contract is called from invalid role address (48ms)
    create a new medical data!!
      ✓ create (289ms)
      ✓ should revert when contract is called from invalid role address
      ✓ get patient's medical data (318ms)
      ✓ should revert when contract is called from invalid role address (367ms)
      ✓ should revert when contract is called from invalid role address (143ms)
    update a medical data!!
      ✓ edit (589ms)
      ✓ should revert when contract is called from invalid role address (420ms)
    delete a medical data!!
      ✓ delete (528ms)
      ✓ should revert when contract is called from invalid role address (305ms)
    test for paying Treatment costs!!
value: 10000000000000000
contractBalance: 20000000000000000
      ✓ pay !! (393ms)
value: 10000000000000000
      ✓ should revert when contract is called from invalid role address (57ms)
value: 10000000000000000
contractBalance: 20000000000000000
      ✓ should revert when contract is called from invalid role address (172ms)


  24 passing (12s)
```

### 画面の説明

次に各画面の説明になります。
画面のコンポーネント自体はベースとなるindex.jsとApp.jsを除いて大きく4つの画面用のコンポーネントで構成されていますが権限により表示を切り替えるなどしています！

#### 1. Connect Wallet 画面
ウォレットで接続する前の画面
右上のボタンから接続する。

![connectWallet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299653/d9c87b2d-1332-4bdf-4524-84a69d9d6202.png)


#### 2. Home 画面
この画面は接続したウォレットのアドレスによって描画される内容が変化します。

|No.	|パターン|	描画される内容|
|---|----|----|
|1|	患者で医療データが未登録の場合|	メッセージが描画されるだけ|
|2|	患者で医療データが登録されている場合|	医療データが描画される|
|3|	医者の場合	|初期状態では検索画面が描画される。|
|4|	医者の場合で検索したアドレスから承認権限が付与されていなかった場合|	承認権限を要求するボタンを描画する。|
|5|	医者の場合で検索したアドレスから承認権限が付与されて且つ医療データが登録されていなかった場合|	医療データ入力フォームと新規登録ボタンを描画する。|
|6|	医者の場合で検索したアドレスから承認権限が付与されて且つ医療データが登録されていた場合|	医療データ入力フォームと更新・削除ボタンをを描画する。|

##### Home 画面 パターン 1

![notregisterd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299653/2d4bf94f-978b-6af6-8a0f-531864e6e8a5.png)


##### Home 画面 パターン 2

![medicaldata.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299653/1618cbe5-b9ce-7c07-84a9-bed68f643bf5.png)


##### Home 画面 パターン 3

![view2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299653/14f7ffcc-a7ab-9f21-c682-257fd2f19546.png)


##### Home 画面 パターン 4

![notapproved.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299653/2fff4cea-e876-362a-d357-5f5d9918697c.png)


##### Home 画面 パターン 5

![create.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299653/23a27cdd-f87f-5734-c72d-0ab2d45c3f39.png)


##### Home 画面 パターン 6

![update.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299653/ea511526-a9f7-1ffd-5c2a-506992866952.png)


#### 3. Regist 画面
この画面は管理者権限専用の画面で新規に医者を登録することができる画面になります。
管理者以外がアクセスすると入力フォーム等は描画されません。

##### Regist 画面 管理者の場合

![owner.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299653/fc268b6a-9f2e-6e85-8b38-7eae1deb5611.png)


##### Regist 画面 管理者以外の場合

![noowner.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299653/4efe1508-cfd8-e9c3-4ccb-af800cdf8236.png)

#### 4. DoctorInfo 画面
この画面も患者と医者で画面表記が変化します。
医者の場合は自分のアドレスと名前が表示されます。
患者の場合は、このコントラクトに登録されている医者の情報と承認権限を付与するボタン・剥奪するボタンが描画されます。(医者から承認権限を要求されている場合にはその旨のメッセージも表示されます。)

##### DoctorInfo 画面 医者の場合

![doctorInfoforDoc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299653/dbe4d5cd-f58e-c02f-7c45-a7d159774777.png)

##### DoctorInfo 画面 患者の場合

![doctorInfoRequire.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299653/e1d9073f-d806-d8ec-47e7-65be9993a1a7.png)

### 最後に

残課題としては、医療データというプライベートデータを以下にしてオンチェーン上で安全に管理するかということです。皆から過去のブロックデータを全て確認できるというパブリックブロックチェーンを使っているからこその課題なのですが、ここが最も難しい点だと考えています。

暗号化されたデータであってもブロックに一度登録してしまうと過去に遡って参照できてしまうので、鍵の情報が漏洩したり、暗号アルゴリズムが解読されたりするとアウトなので、やはりデータ本体はオフチェーンのほうが良さそうです。そしたらそのデータをどこに管理するの？？という課題が出てくるわけで難しいですね笑。

EUで進めているというデジタルIDウォレットの仕組みが気になるところではありますが、SBTや Lit Protocol等を使ってアクセスコントロールをうまく制御できれば面白そうなアプリが出来そうです！！引き続きアプリを改良していきたいと思います！

読んでいただきありがとうございました！！