EthereumのDappをスマートフォンから利用する方法について

EthereumのDappをスマートフォンから利用する方法について調べました。

## 環境

* go-ethereum: 1.7.0-stable
* Mist: 0.9.1
* im.status.ethereum-8ef9ff.apk: 26-Sep-2017 23:32

## PCから利用する場合 (Mist)

まずはスマートフォンではなくPC上でDappを利用する方法についておさらいします。

PC上でDappを利用する場合には，[Mist](https://github.com/ethereum/mist/releases) を使うのが便利です。MistはEthereumのウォレットの機能とDappを動かすためのブラウザが一体化したもので，ウォレットの秘密鍵をDapp側に渡すことなく安全にDappを利用することができます。

今回は練習としてプライベート・ネットで以下のDappを動かしてみました。

[How to build server less applications for Mist - Ethereum Blog](https://blog.ethereum.org/2016/07/12/build-server-less-applications-mist/)

最初にプライベート・ネットを作成します。`--dev` を指定しているとガスの価格が0になってしまうので適当に設定しています。詳細は [「Ethereum入門」を Geth 1.6.7 で進めてみた（インストールからetherの送金まで）](https://qiita.com/shora_kujira16/items/ab05f9d4a58bfa05a96c) を参照してください。

```console
$ geth --datadir . --dev --gasprice 18000000000
```

トランザクションを承認するためにcoinbaseのアカウントを作ってマイニングもしておきましょう。

```
$ geth attach ipc:geth.ipc
> personal.newAccount("password")
> miner.start(1)
```

次にMistを起動します。プライベート・ネットに接続する場合には `geth.ipc` の位置を指定する必要があります。

```console
$ /Applications/Mist.app/Contents/MacOS/Mist --rpc geth.ipc
```

Mistが起動したらコントラクトをデプロイします。Solidityのソースコードが以下のURLにあるのでコピーします。

https://github.com/alexvandesande/stake-voice/blob/0fb823659c6ac213ce78ecc30380956eceff4629/contract.sol

Mistでコントラクトのタブの「新しいコントラクトを配置」を選択してSolidityのソースコードを貼り付けてデプロイします。18行目は `throw` だったのですが，警告が出てデプロイできなかったので `revert()` に書き換えました（errorではなくwarningなのに…）。

![スクリーンショット 2017-09-28 15.01.16.png](https://qiita-image-store.s3.amazonaws.com/0/154409/797a404d-b81c-3cb6-5ac5-3239586d8114.png)

コントラクトをデプロイするには手数料としてetherの支払いが必要なのでユーザーに確認が求められます。

![スクリーンショット 2017-09-28 15.01.31.png](https://qiita-image-store.s3.amazonaws.com/0/154409/d1b70aa4-5f08-ac02-8f8c-88ff16357362.png)

次にDappをMistから利用する準備をします。まずはコントラクトのアドレスをコピーします。

![スクリーンショット 2017-09-28 15.09.34.png](https://qiita-image-store.s3.amazonaws.com/0/154409/1ce16f41-3670-9cbd-9cb7-d51960012bdc.png)

Dappのリポジトリ (https://github.com/alexvandesande/stake-voice.git) をcloneしてきて `scripts.js` に書いてあるコントラクトのアドレスを変更します。

```diff
 // Set some initial variables

 var ethervote, ethervoteContract, proposalHash, totalVotes, proposal, totalPro, 
 totalAgainst;
 var voteMap = {};

-var contractAddress = '0x8a57d2708d1f228dac2f7934f5311cd2a0a1cda4';
+var contractAddress = 'ここにアドレスをペーストする';
 var contractAddressTestnet = '0x4ad62d4aaec13098832b1be635fc01581d97325c'; // Rinkeby
 // Ropsten: 0x47ab800a75990b0bd5bb4a54cfbec777972c973c 
```

変更したら [http-server](https://www.npmjs.com/package/http-server) を起動するなどしてDappのUIにアクセスできる状態にします。Mistのアドレスバーに `localhost:8080` などと書くとDappのUIにアクセスできます。

![スクリーンショット 2017-09-28 15.03.30.png](https://qiita-image-store.s3.amazonaws.com/0/154409/7d6665e2-71eb-a9b8-3d98-0f64d527726b.png)

![スクリーンショット 2017-09-28 15.23.42.png](https://qiita-image-store.s3.amazonaws.com/0/154409/9429ecfc-57a9-59fb-2d30-b4b64bbd630e.png)

"Click here to add an account on Mist" で指定されている箇所をクリックすると，Dappを使うためのアカウントを指定する画面になります。

![スクリーンショット 2017-09-28 15.23.50.png](https://qiita-image-store.s3.amazonaws.com/0/154409/466df07c-bdf0-8431-78ce-dce121958740.png)

Dappのテキストボックスに何か適当に入力すると投票の画面になります。

![スクリーンショット 2017-09-28 18.01.30.png](https://qiita-image-store.s3.amazonaws.com/0/154409/18bc2b06-499a-8089-15fb-e4503479c6a2.png)

投票を行おうとすると，コントラクトを実行してもよいかどうかの確認画面が表示されます。コントラクトの実行にも手数料としてetherが必要です。

![スクリーンショット 2017-09-28 15.24.40.png](https://qiita-image-store.s3.amazonaws.com/0/154409/658aa9a7-6df1-40bd-d548-69714e047851.png)

Dappの挙動が若干あやしくて，投票結果の表示がおかしいような気がしますが，Mistのコントラクト管理画面を見るとたしかにコントラクトが実行されたことがわかります。

![スクリーンショット 2017-09-28 15.30.37.png](https://qiita-image-store.s3.amazonaws.com/0/154409/4f2f1988-546f-8234-0872-ecfc98e5c6c4.png)

コントラクトの実行の流れをシーケンス図として以下に示します。Dappがコントラクトに書き込む場合などetherの支払いが必要になる場面では，Mistがユーザーに確認を求め，トランザクションへの署名やP2Pネットワークへの送信も代行しています。

![mist@1-17.png](https://qiita-image-store.s3.amazonaws.com/0/154409/4ad8e385-e0bd-c6da-b231-9a9a62789c8d.png)

## スマートフォンで利用する場合の検討事項

Mistの仕組みははDapp側にウォレットの秘密鍵を渡す必要がないという点で利用者に優しいだけでなく，開発者の視点でも [web3.js](https://github.com/ethereum/web3.js/) というインターフェースを使うことでEthereumの低レイヤーな処理を書く必要がなくなるという点で大変魅力的です。しかしながら，Mistをそのままスマートフォンで使うことはできないため，現段階では代わりの方法を見つける必要があります。

代わりの方法として考えられるものについて，以下の2つの点に着目して考察しました。

* スマートフォンから直接EthereumのP2Pネットワークに接続するのかどうか
* Dappとウォレットを分離するのかどうか

まずスマートフォンからEthereumのP2Pネットワークに直接接続するのかどうかについてです。仮想通貨の非中央集権性を重要視するならば当然そのように実装されるべきです。しかしながらストレージの容量や通信量といったスマートフォン特有の問題を考慮するならば，P2Pネットワークとスマートフォンの間にサーバーを挟んでサーバーがP2Pネットワークに接続するというアーキテクチャのほうが利便性が高いかもしれません。

スマートフォンからP2Pネットワークに接続する難易度は高いですが，整備されつつあります。Ethereumクライアントはブロックを全てダウンロードして数GBのストレージを利用するのでスマートフォン上で利用するのは現実的ではありません。そのため [BitcoinにおけるSPVクライアント](http://bitcoin.peryaudo.org/comparison.html#spvクライアント-multibit-bitcoin-wallet) のように数100MB程度のストレージ利用で済むように [Light Ethereum Subprotocol (LES)](https://github.com/zsfelfoldi/go-ethereum/wiki/Light-Ethereum-Subprotocol-%28LES%29) の仕様が策定中です。また，スマートフォンから利用するには当然ながらLESを実装したクライアントが必要となりますが，GethではLESの実装である light client mode を `--light` というオプションで利用することができます。さらに，GethをAndroid or iOSで利用するための仕組みも整備されつつあります ([Mobile: Introduction · ethereum/go-ethereum Wiki](https://github.com/ethereum/go-ethereum/wiki/Mobile%3A-Introduction))。

続いてDappとウォレットを分離するのかどうかについてです。コントラクトに対して変更操作を行うためには手数料としてetherが必要となるので誰かがウォレットを管理する必要がありますが，管理するのがDappのインターフェースとなるスマホアプリで良いのかという問題です。MistのようにDappとウォレットが分離されていてDappに秘密鍵が渡らない方式のほうが望ましいですが，私の調べた限りではMistの役割を代行してくれるスマホアプリは少ししか見つかりませんでした。Dappがウォレットを管理する方法は簡単な方法ですが個人的には不健全すぎると感じてしまいます。

この後は4通りの実装について詳しく見ていきます。

### スマートフォンからP2Pネットワークに直接接続 & ウォレットとDappが分離されている

Mistをそのままスマートフォンに移植したようなものです。Statusというアプリが該当しています。

[Status | The Mobile Ethereum Client](https://status.im/)

Statusは非常に高度な技術で実装されていて，アプリ自体は ClojureScript + React Native で書かれています。さらに，スマートフォンからP2Pネットワークに接続するために [go-ethereum (Geth) を独自に改造しています](https://github.com/status-im/go-ethereum/tree/status/1.6.7-stable)。

Statusは現在テストネットのRopstenでテスト中で，Android端末ならデバッグモードでapkのnightly buildをインストールすることができます。オープンソースなので自分でビルドしても良いですが，私はReact NativeのJavaScriptコードの転送がうまくいきませんでした。やる気のある人は [Statusの開発者向けWiki](https://wiki.status.im/Developer_Documentation) を参考にビルドしてみてください。また，公式サイトでメールアドレスを登録するとGoogle Playページを教えてもらえるのですが，ベータプログラムの人数制限によりインストールすることができません。

StatusからDappを利用するには [Mistで利用するときのようにweb3を使ったHTML+JavaScriptを記述すればよいよいです](https://wiki.status.im/Frequently_Asked_Questions)。

[サンプルのウォレットアプリ](https://status.im/dapps/wallet/) を使ったときのスクリーンショットを載せておきます。Dapp側でSendのボタンを押すとStatusが確認を要求してきます。

<img src="https://qiita-image-store.s3.amazonaws.com/0/154409/b5285744-8fe8-f21a-b71c-5c244be8fca6.png" width=50%>

<img src="https://qiita-image-store.s3.amazonaws.com/0/154409/f2c78457-a6d1-151d-c807-7affa5a85254.png" width=50%>

<img src="https://qiita-image-store.s3.amazonaws.com/0/154409/fe9a8dcd-971b-0524-0954-992a9e99290f.png" width=50%>

最初にMistで動かした投票アプリも試してみたのですが，なぜかトランザクションの確認を要求してくるダイアログが表示されず投票も行えませんでした。ただ，画面を見た感じだとweb3は認識できているようなので，あとでもっと簡単なアプリでデバッグしたいと思います。

<img src="https://qiita-image-store.s3.amazonaws.com/0/154409/57436ba8-a221-6734-5f42-8ae9d80bd222.png" width=50%>

コントラクトの実行の流れをシーケンス図として以下に示します。MistがStatusになっただけです。

![status@1-17.png](https://qiita-image-store.s3.amazonaws.com/0/154409/034907f6-94ab-ad3a-e08a-4c88b7fb71f3.png)


#### この方式のここがすごい

* (Statusのような既存のアプリを使う場合）HTML+CSS+JavaScriptでweb3を使ったコードを書くだけでDappをスマホ対応にすることができる
* Dappに秘密鍵が渡らないので安心（Statusを信用する必要はある）

#### この方式のここがダメ

* (StatusのようにHTML+CSS+JavaScriptで開発する場合）Dapp側でネイティブアプリっぽいことをやるのに制限がある（ストレージの利用，外部との通信，通知，…）

### スマートフォンからP2Pネットワークに直接接続 & ウォレットとDappが同じ

おそらくこのような実装をしているアプリもあるのだと思いますが，私は新参者でよく知らないので，ご存知の方はコメントかTwitterで教えてください。

コントラクトの実行の流れをシーケンス図として以下に示します。Dappを利用するアプリが直接トランザクションに署名を行うため，秘密鍵をアプリに登録するか，専用のアカウントに事前にetherをチャージしてもらう必要があります。

![app@1-13.png](https://qiita-image-store.s3.amazonaws.com/0/154409/e2c68573-05df-b931-322e-a00502f133f6.png)

#### この方式のここがすごい

* ネイティブアプリなのでなんでもできる

#### この方式のここがダメ

* モバイル版go-ethereumを扱う必要があるなど，高度な実装が要求される
* アプリに秘密鍵を渡す or アプリ専用のアカウントにetherを事前にチャージしてもらう必要がある

### サーバーを経由してP2Pに接続 & ウォレットとDappが分離されている

[Ethereum Android](https://medium.com/@pacs_IT/an-ethereum-api-for-android-app-developers-3f46b820f8f6) というクライアントが同様のことをやろうとしているように見えます（まだ試していません）。サーバーを経由することになるので「非中央集権性とはいったい何だったのか」という気持ちになってしまいますが，バッテリーや通信量の少なさなどの観点では検討しても良いでしょう。

コントラクトの実行の流れをシーケンス図として以下に示します。Statusの図にサーバーが追加された用な感じです。

![wallet@1-18.png](https://qiita-image-store.s3.amazonaws.com/0/154409/fba30b1a-ad81-2e55-bb4f-d09f3a6c8d38.png)


#### この方式のここがすごい

* スマホ側ではP2P通信は行わないのでバッテリーや通信量が少なくて済む

#### この方式のここがダメ

* サーバーに処理を経由する必要があり，非中央集権性とはいったい何だったのかという気分になる

### サーバーを経由してP2Pに接続 & ウォレットとDappが同じ

おそらく最も簡単な方法です。

コントラクトの実行の流れをシーケンス図として以下に示します。

![naive@1-15.png](https://qiita-image-store.s3.amazonaws.com/0/154409/99cbca64-4dc6-0b0d-7d0d-d14c7578d481.png)

#### この方式のここがすごい

* 実装がおそらく最も簡単
* スマホ側ではP2P通信は行わないのでバッテリーや通信量が少なくて済む

#### この方式のここがダメ

* サーバーに処理を経由する必要があり，非中央集権性とはいったい何だったのかという気分になる
* アプリに秘密鍵を渡す or アプリ専用のアカウントにetherを事前にチャージしてもらう必要がある

## おわりに

この記事ではEthereumのDappをスマートフォンから利用する方法についての考察を行いました。スマートフォンからDappを利用した経験がある方は，アプリの使い勝手などを教えて頂けると幸いです。

## 追記

Webウォレットなのですが，[BlockOne ID for Ethereum](https://blockoneid.thomsonreuters.com/) というWebサービスがあって，プロモーションビデオを見た感じでは本来あるべき形のように見えます。Dappでお金を使おうとするとウォレット側のウィンドウが開いてユーザーに確認を求める方式で，ユーザーはDappには秘密鍵を渡さなくてよくて，ユーザーはBlockOne IDのウォレットのみ管理しておけば良いという感じです。

## 追記2

関連のあるStackExchangeの記事のリファレンスを付けておきます。

* [Using Dapps on mobile \- Ethereum Stack Exchange](https://ethereum.stackexchange.com/questions/24257/using-dapps-on-mobile?noredirect=1&lq=1)
* [mobile wallet \- Ethereum library for iOS/Android? \- Ethereum Stack Exchange](https://ethereum.stackexchange.com/questions/4556/ethereum-library-for-ios-android/6611#6611)
* [web3js \- How can dapps work on smartphones? \- Ethereum Stack Exchange](https://ethereum.stackexchange.com/questions/18461/how-can-dapps-work-on-smartphones?noredirect=1&lq=1)
* [web3js \- How to build a front end for dApp \- Ethereum Stack Exchange](https://ethereum.stackexchange.com/questions/13128/how-to-build-a-front-end-for-dapp?rq=1)