FiNANCiE Lab

ブロックチェーンで世界を変える、株式会社フィナンシェのテックチームブログです

ブロックチェーンで人をカード化して売買できるサービスを作ったので解説する

※本記事はQiita @ku_suke さんの記事の転載です。

TL;DR

 ブロックチェーンで人をカード化して売買できるサービスを作りました。何を言っているかわからないと思うので詳しくはこれを見てほしい。割とあまり事例のないことをやってきて苦労しまくったので、これからブロックチェーンプロジェクトを始める人の役に立てればと思って記事にまとめました。

Financie(フィナンシェと読みます)というサービスです。

※僕は代表して記事を書いているけど実際は10人くらいのエンジニアチームを含む30人くらいのスタートアップにしては大所帯のチーム。ブロックチェーン周りの設計とかCTOは@rudoさん。

なんで作ろうと思ったか

 さかのぼること1年くらい前、「仮想通貨は落ち込んでるけどブロックチェーンはきっと伸びるに違いない、ここで面白いことやろうよ!」といっていろんな案を考えた末、行きついたのがこのサービスでした。ブロックチェーンによる価値の民主化、分散、個人の時代、そんなキーワードを抱えながら、僕たちは始まりました。

もちろんその当時似たようなサービスではVALUもTimebankも海外ではPatreonもすでに世の中に出ていました。でも僕たちはもっと、有名人じゃなくても普通の人がかなえたい夢を応援するような、そんなサービスを考えていました。

その後大変な紆余曲折を経て今に至るのですが、Qiitaなので技術的な側面についてかきます。

そもそもブロックチェーンを使ったサービスとは

 ブロックチェーン上に構築されるサービスをざっくりDAppsといいます。DApp(s)とは分散型アプリのことですが、実はそのほとんどは、ブロックチェーンのコード量よりもそれ以外のAWSとかGCPにのっかってるコードやリソースの量が多いのです。

なぜなら2019年前半の現在、一番メジャーなプラットフォームであるEthereumを含め、ほとんどの分散アプリケーション実行環境は大量のアクセスを実行したり、画像をホスティングするには不向きな構造になっているからです。

 Financieではさらに、ブロックチェーンへのアクセスをユーザーから直接ではなくサーバ側から呼び出すように変更しました。そのため表側のアプリケーションはごく普通のRailsで書かれていて、価値を記録する部分であるカードの売り買い部分だけRailsからJSON-RPCを通じてEthereum上にデプロイした自前のコントラクトをたたいています。 f:id:re795h:20191029190413p:plain 普通は、ブラウザ拡張のMetaMaskやモバイルウォレット(TokenPocketやGo! WALLET)を使ってアクセスするのですが、より多くの方に参加してもらうためユーザー側に特別なソフトウエアが不要な設計にしました。

何ができるの?

f:id:re795h:20191029190500p:plain  Financieは「ヒーロー」と呼ばれる夢を持って頑張る人のカードを購入することができます。購入したカードの価値はブロックチェーン(Ethereum)上に記録され、同じくEthereum上で自律的に動くマーケットプレイスを通じていつでも売り買いすることができます。

 クラウドファンディングのように単発の支援ではなく、オンラインサロンとも違い、ファンはヒーローを応援することで自分が買ったトレカの価値が向上するといった仕組みを中心に、ヒーローとともに成長できる世界ができたらおもしろいんじゃないかとチャレンジしています。

 ちなみに、Ethereum上のトークンはいくつか規格があって、有名どころだとMyCryptoHeroesとかCryptoKittiesとかは、ERC721と呼ばれる、NonFunsibleTokenで実装されることが多いです。しかし、Financieでは普通のトークンというか、ERC20で実装しています。これはERC721が唯一性を実現している(ようは1枚1枚別の価値を持つ。)のと異なり、ヒーローカードは同じヒーローであれば1枚の価値は等しいからです。

ただしシンプルにERC20トークンでサービスを実装すると2号仮想通貨の該当性が論点に当たる可能性があるので注意。そのあたりもどこかで書きます。

ダッチオークション方式による売り出し

 Financieのカード販売は2つの方法があります。一定期間入札を受け付ける「売り出し」と、いつでもカードを売買できる「マーケットプレイス」です。どちらもSolidityによるスマートコントラクトで実装されていて、実行結果は各種ブロックチェーンエクスプローラで確認することができます。

 売り出しに関してはダッチオークション方式を採用しました。これは発売当初はものすごく単価が高いところからスタートして、徐々に単価が下がっていく方式です。最終的に募集総額まで集まった段階で購入単価が決定し、全員同じ単価で、入札金額に応じたカード枚数が付与される仕組みとなっています。

文字だけで説明するとわかりにくいので図で表すとこんな感じ

f:id:re795h:20191029190552p:plain この図でいうと、全員が1枚当たり単価30円でカードを購入することができます。さらに時間が過ぎると0.1円とかになります。100万枚が0.1円で募集終了すると、総額10万円分のカードが販売されることになります。

この仕組みの何がうれしいかというと、Financieはあくまでヒーローの夢を応援したいので、お金持ちが大量に買い占めて人々にいきわたらないことをある程度防ぐ目的があります。もし買い占めたければ、3倍以上の単価で入札する必要があるため、より多くのファンにカードを少しでも手にしてもらいやすくなることを意図しています。

ダッチオークションの実装はRaidenのクラウドセールを参考にしました。@m0t0k1ch1さんの記事が分かりやすい。

Bancorによるマーケットプレイスの実装

 次に、購入したカードの売買については、Bancorと呼ばれる仕組みを採用しています。同名のプロジェクトでもDEX(分散型取引所)が運営されているけど、彼らのSolidity実装を取り込んで今回の要件に合う形に作らせてもらいました。 f:id:re795h:20191029190647p:plain

参考:Bancor Protocol

 Bancorの良いところは、いつでもおおむね無条件に売り買いできることです。スマートコントラクトを自販機のメタファーで解説することがありますが、Bancorはまさに自販機です。売る人が多ければ単価が下がり、買う人が多ければ単価が上がる自動ロジックのおかげで、買いたくても買えない、売りたくても売れないという流動性問題をある程度解消することができます。

 特に、超有名人でもない限り、毎日毎日注目を浴び続けるわけはなく、そのような状態ではカードを売りたくても買ってくれる人が見つからなかったり、その逆も容易に起こりえます。これを解消するためにBancorによるマーケットプレイスを開発しました。

 FinancieにおけるBancorの利用はちょっと特殊で、普通はネイティブトークンと呼ばれるETHとなにかを交換することが多いのですが、今回は都合でJPYとペッグした内部トークンとBancorのスマートトークン、スマートトークンとヒーローカードを2回交換しています(数式上は1回の場合と挙動が変わらない)

なんでこんなややこしい事しているの?

 手段の目的化は楽しい! いろいろ突っ込みどころはあるかもしれないけど、ヒーローとファンが持続的な関係性を築いていけるようなコミュニティを作りたいと思っています。だから投機の場にならないような設計(審査や手数料も含めて)や、コミュニティのスコア化などなどの運用を設計しました。 お金だけじゃだめだし、ファンあるいはヒーローが疲弊していくような焼き畑コミュニティにならないよう、とても難しいチャレンジをテクノロジーの力でやり遂げたいと思っています。

こんな大変だけどチャレンジングなサービスを一緒に作っていきたい人がいれば全力でお待ちしております。

次回はなぜ日本円決済にしたのか、UI面や法律周りの話も書こうと思います。

追記:2本目はこちら EthereumのDApps開発で、開発サーバを転々としたまとめ(geth, Ganache, Ropsten, getho.io)

EthereumのDApps開発で、開発サーバを転々としたまとめ(geth, Ganache, Ropsten, getho.io)

※本記事はQiitaからの移行です。

どうも、フィナンシェCTOの西出です。初投稿です。三度の飯よりカレーが好きです。

前回の @ku_suke さんの記事に引き続き、フィナンシェの開発したときの知見を共有します。今回はEthereum上での開発において、開発用チェーンを苦労しながら転々としたので、そのログをまとめます。

開発用チェーンとは何か

普通のEthereum(メインネット)をそのまま開発用に使うと、世界中のサービスが同居しているネットワークに負荷をかけることになり望ましくありません。また経済的な事情としても、GAS代(ETH)を無尽蔵に払い続けないといけないため、開発専用のネットワークを使うことが一般的です。 テストネットと呼ばれる公開ネットワークRopsten、自前ノードのみで構築されるプライベートチェーンを使う方法、またローカルのみで稼働させる揮発性のネットワークを使う方法(Ganache)などがあります。今回はこれら開発用のチェーンとそのサーバ構築について解説していきます。

最終的に固まった構成

現在の使い分けはこんなかんじ

環境 接続先ノード
ローカル 開発者ごとに好きなものを利用(Ganacheが多い)
Dev Ropsten
Production Mainnet

初期...Ropstenが動作しない問題

前回の記事で紹介したように、フィナンシェはBancorとダッチオークションというコントラクトを用意しているのですが、それ以外にも様々な機能をできるだけスマートコントラクトで実装しようと思っていました。

ある程度ライブラリを取り込み、さっそく使ってみようと一番有名なテストネットのRopstenに接続しようとしたところ、なんとGAS LIMITを超えてしまい動作しませんでした。コントラクトのバイトコードが巨大化していたため、デプロイすることができなかったのです。

Ropstenとは

Ethereumの主要なテストネットの一つ。JSON-RPCのサーバはinfura(https://infura.io/)を使うことが一般的です。 テストネットでもガスが不要なわけではなく、テストネット用ETHを入手する必要があります。自分がバリデーターとなってマイニングすることも可能ですが、faucet(蛇口)とよばれるところでお恵みをもらうことができます。Ropstenネットワークで作成した自分のウォレットアドレスを入力し、入金を待ちます。

代表的なFaucet

しかしながら、Ropstenは前述の理由から当初使えなかったため、自前でのネットワーク&ノード構築にチャレンジしました。

gethをEC2に構築

gethとはgoで書かれたEthereumの公式ノードパッケージです。gethをEC2にインストールし、GAS LIMITを高めに設定して稼働させることで、ひとまずは動かすことができるようになりました。

Go Ethereum - Official Go implementation of the Ethereum protocol https://geth.ethereum.org/

速度が遅く開発に時間がかかる

gethの構築によって開発は無事スタートしたのですが、ほとんどデフォルト設定で使っていたため、ブロックの生成、トランザクションの承認に時間がかかり、しょっちゅうつまって頻繁に5分程度の承認待ち時間が発生していました。これはよくありません。

そのタイミングでちょうどご縁があり、プライベートネットワークをSaaSで提供(アルファ版)していたgethoを紹介してもらい使い始めました。

開発用チェーンSaaSのgetho.io

getho(ゲソ)はパラメータチューニング済みのプライベートチェーンノードが1クリックで起動するSaaSです。まだ絶賛開発中ということで、専用Slackチャンネルに入っていただき、要望を山盛りぶん投げさせていただきました。

Slack - getho.png gas limit 追加要求の様子

gethoを導入してからは(いくつか機能追加のタイミングで再起動や不安定になることはあったものの)コントラクトのデプロイやトランザクションがスムーズに流れるようになって非常に開発がサクサク進むようになりました。

また、後半の方ではブロックチェーンエクスプローラのような開発画面も追加してパワーアップしました。gethoは最小構成は無料で使えるのでぜひ試してみてください。

getho https://getho.io/

ローカルはGanacheも併用し始めた

gethoは快適ですがインターネット越しで使うので、ローカルでさらなる安定感が必要な人はGanacheを導入し始めました。Ganacheは開発用の便利ツールで、Truffleと呼ばれるコアをElectronベースのGUIでラップしたものです。

Ganacheは起動すると、100ETHが入金済みのウォレットアカウント10個を用意した状態で起動してくれるので、あとは少しGAS LIMITをいじるだけですぐに使い始めることができます。 ganache.png GanacheをUbuntuで動作させているところ

このようにして、ローカルもdevサーバも比較的サクサクと開発を進められるようになりました。フィナンシェの開発自体もすすみ、ある程度の機能セットが固まったので、コントラクトを分割して整理することにしました。

コントラクトの整理とは

ウォレットから1回に呼び出せるコントラクト/ファンクションは1個だけなのですが、コントラクト内でさらに別のコントラクトを呼び出すことは可能です。そのため、1コントラクトに全部詰め込むのではなくある程度まとまった機能単位で分割することで、一般的な開発言語におけるライブラリのような使い方をすることができます。

メリット:

デメリット・リスク:

  • コントラクト間の呼び出しはすべてpublicになるため、自前で呼び出しの権限管理などをきっちりやる必要がある
  • コントラクトまたぎで呼び出すことによる多少の実行コスト(ガス代)の上昇

今回は特に、ユーザーデータの管理コントラクトとそれに対するオペレーション用のコントラクトに分割しました。これによりまずバイトコードが小さくなり、またデータを引き継いだままオペレーション部分の機能追加・改善が可能となりました。膨大なコントラクト内データを、次のコントラクトに「スマートコントラクト内で」「1トランザクションとして」引き継ぐことは非常に困難なので、少なくともデータ構造だけは最初にデプロイしたコントラクトを永続的に使うつもりで設計する必要があります。

再度Ropstenにチャレンジ

ある程度テストも動作したのですが、いよいよクローズドβテストの締め切りが近づいてきて、「あまりサクサク動いてしまうといざメインネットで稼働させた時に起こりうる課題を見落とすかも」ということで再びRopstenにチャレンジすることにしました。幸いこの間にRopstenもGAS LIMITが引き上げられ、我々のコードも整理できたため、問題なくデプロイすることができました。 また、このタイミングではsolidityに関する知見がたまっており、最適化オプションも活用しました。コンパイル時に適切な最適化オプションをかけることで、同じ効果を得られるバイトコードのままでもサイズを削減できる仕組みです。

まとめ

このように、開発フェーズや目的によってさまざまなチェーンを使い分けることにより、スムーズな開発ができるようになります。ほかには別のテストネットであるKOVANや、TECHFUNDとMicrosoftが組んでいるACCEL BaaS、あとはGincoさんも似たようなサービスを開発中のようです。

現在のユーザー規模では一旦現状の構成でうまくワークしています。が、今後ユーザー数が拡大していくにつれてまた課題が出てくると思われるため、引き続きEthereumの最新動向を見つつ最適な方法を模索していきたいと思います!

また、フィナンシェではエンジニアを募集しております。コンシューマー向けサービスとして既に提供を始めているブロックチェーンサービスってまだまだ少ないので、未踏の地に切りこんでいく人柱フロンティアスピリッツをお持ちの方は是非こちらからお声がけください!