Ethereumウォレットを作るときのTips

Ethereumウォレットを作るときのTips

どうも、CTOの(森下)です。

今回は、2018年11月10日に開催されたHi-Conで話した内容の重要な部分だけまとめた記事です。

発表では Ethereumウォレットである Ginco の開発中に気づいたTipsとKyber Networkのインテグレーションについて話しました。 Kyberのインテグレーションについては、この記事で詳しく説明されていますのでぜひ見てください。

この記事ではEhtereumウォレット作るときにハマったり、気づいたりしたことについて解説します。

発表資料はこちらです。

ウォレットを作る上でのTipsとDex実装の話

ウォレット開発で気づいたところ

Ethereumへの接続

第一にEhtereumへの接続方法についてです。 Ethereumネットワークに接続するには次の方法があります。

まずは、自分でEhtereumノードを立ててそれに対して接続する方法です。次が、INFRA などといったプロバイダサービスを使って接続する方法。 そして、最後が Etherscan のパブリックAPIを使う方法です。 それぞれに、メリット・デメリットがあるのでそれについて説明します。

自分ノードを立てる場合は、ノードのパラメータなどを自分で好きなように設定できるので自由度が高いです。また、ほかのサービスのようにリクエスト制限がないことが強みです。 しかし、同期が必要ですし、常にノードの面倒を自分で見なければならないのでランニングコストがかなり高いので個人開発などではおすすめしません。

一方、プロバイダサービスは手軽に使えて、コストが低いことがメリットです。 しかし、ノードの細かい設定ができなかったり、リクエストに対して謎のエラーが帰ってきたりと、本格的に使おうと思うと少し足りないといったこともあります。

パブリックAPIはGethのプロトコルであるJSON-RPCではなく一般的なRESTなのでいままでWebでやってきた人からするととっつきやすいと思います。 また、アドレスに関連した履歴を取得したりといった、GethにはないAPIもあったりして非常に便利です。 しかし、リクエスト制限がきつかったり、Gethの基本的なAPIしかなかったりするのでコアな開発は向かないと思います。

GasLimitについて

Gasの概念はEthereum開発において最初の砦みたいな感じだと思います。エンジニアでも最初は理解が難しいですよね。

GasLimitは、トランザクションが実行される際に使われるGasの上限のことです。 万が一、無限ループを起こすようなコントラクトがあった場合にユーザーの資産が全て手数料に消えないようにしてくれます。 したがって、GasLimitはむやみやたらに大きい値にせず、適切な値を設定してください。

また、トランザクションはブロックのGasの空き容量以下のGasLimitでないと取り込まれません。 つまり、使われるGasにGasLimitをできるだけ近づけることでブロックに取り込まれやすくなります。

では、具体的にどのようにGasLimitを設定するかを説明します。 まず、Etherの送金のトランザクションに関しては使われるGasが21000と固定されています。 したがってGasLimitも21000にしておけば大丈夫です。

コントラクトの実行のトランザクションの場合は2種類あって、estimateGas() を使う方法と固定値を使う方法です。 estimateGas() はコントラクトの実行にどれくらいGasが使われるのか推測をしてくれる関数です。これを使えば大体の値は予測できます。 予め叩くコントラクトが決まっている場合には、そのコントラクトにどれくらいGasが使われるか予測できるのでそれを上回る値を固定値として使えば良いです。

注意としては estimateGas() の値をそのままGasLimitにしないことです。 estimateGas() の値は正確な値ではないので、たまに実際よりも少ない値が帰ってくることもあり、それがエラーの原因となります。 また、コントラクトによっては巨大な値となる可能性もあり、GasLimitとして機能しなくなることもあります。

GasPriceについて

GasPriceはトランザクションの手数料を決めるための値です。これが大きいほど早くブロックに取り込まれます。

GasPriceは基本的にユーザーに決めてもらう方法と GasPrice() を使う方法があります。 簡単なのはユーザーに決めてもらう方法ですが、慣れていないユーザーはいくらが適切なのかがわからないので困ってしまいます。 GasPrice() は直近のブロックに入っているトランザクションのGasPriceの中央値を返してくれる関数です。 これを使うことでその時点での妥当なGasPriceがわかるので、よくわからないユーザーはこのGasPriceを使って送れば良いわけです。

最新のGasの情報に関してはEtherscanのGas TrackerETH Gas Stationといったモニタリングサービスもあるので活用してください。

また、ETH Gas Stationでは、主要マイナーの最低GasPriceを見ることができます。これを参考にGasPriceの最低値を決めると良いでしょう。

Nonceについて

Nonceはトランザクションの処理順を決めるものです。 EthereumはBitcoinのようなUTXOを持たないためNonceを使ってトランザクションをシーケンシャルに処理をしています。 Nonceは絶対に0から連番になるように設定しなければなりません。 もし、0,1を送ったあとに10を送ったりすると2~9のトランザクションが処理されるまで永遠に処理されなくなってしまいます。

Nonceの決め方としては、3種類あります。 一番シンプルなのは送ったトランザクションをカウントしておき、その数を使う方法です。 または、送ったトランザクションの数を取得できる GetTransactionCount() を使う方法です。 トリッキーな方法としては、Etherscanの履歴を取得して送信のトランザクションをカウントするといった技もあります。

GetTransactionCount() は承認されたトランザクションの数を取得できます。 Pendingトランザクションについては正確ではないので注意が必要です。

入力バリデーション

送金金額の入力バリデーションはウォレットのUXにおいて非常に重要です。 入力フォームではユーザーは自分がいくら送金できるのか確認できる必要があります。 そして、それ以上にの値関してはバリデーションをかけてあげると親切です。

送金可能額の計算方法はシンプルで 残高 - 手数料 となります。 手数料というのは Etherの送金にかかるGas(21000)とGasPriceをかけ合わせたものです。

ERC20の場合も同様で、使用されるGasとGasPriceをかけ合わせたものになります。 使用されるGasに関してはGasLimitのセクションで説明した方法で算出するのが良いでしょう。 ERC20の送金は、手数料として使われるのがEtherのため、ERC20の残高がそのまま送金可能額となります。

全額入力

全額入力は送金金額入力のUXにおいてかなり重要です。 ロジックしては非常にシンプルで、ただ単に送金可能額をそのまま入力してあげるだけです。 これがあるとないとでは快適さがぜんぜん違うので実装をおすすめします。

まとめ

本記事では、Ginco での Ethereumウォレット開発中に得た知見について解説しました。 基本的にはこの内容があれば、簡単なEthereumウォレットを作成するのには困らないと思います。 Ginco はこれ以外にも UI/UX を良くするためのアイデアがたくさん盛り込まれていますので、 ウォレット開発を検討されている方はぜひ触ってみてください。

質問等ありましたら、森下(森下)にリプでもDMでも飛ばしてください。

Tip us!

エンジニアチームがブログを書くモチベーションが上がります!

image