
Libraの登場で関心を集めているステーブルコイン。その1つであるMakerDAOの「DAI」について、安定化や発行のメカニズムをICOVO社のエンジニア 三野泰佑氏がわかりやすく解説します。今回は、mcd-cliというコマンドラインツールを使って複数担保型DAIのCDPのライフサイクルを1周してみることで理解を深めます。
関連記事:MakerDAOのステーブルコイン「DAI」 はなぜ安定するのか? そのメカニズムを詳解
はじめに
MakerDAOは2016年12月に「SAI」をαバージョンとしてリリースし、2017年12月に「DAI」をβバージョンとしてリリースしました。現在のDAIは単一担保型で、一種類の資産しか担保として使うことができず、サポートされている資産はETH(正確にいうとPETH)のみですが、将来的には2つ以上の担保を使える複数担保型に移行します(ちなみにPETHは除外され、ETHが他の資産と一緒に担保として使われるようになります)。ERC20トークン、NFT、またその他のERC777標準に則ったトークンなどがまずは担保として使われることになると思います。例えば、Digixという金によって裏付けられているトークンが担保の候補として挙げられています。
このアップグレードによって、担保をロックするときの選択肢が増え、DAIを発行することは容易になります。また、担保を分散化することで過少担保のリスクも減らせます。ETHしか担保資産がないと、ETHの価格のみにCDPの担保率が影響を受けてしまいますが、担保を増やせば1つの資産に依存せずにリスクを分散させることができます。
単一担保型の仕組みがまだよくわからないという方は、前回の記事を読んでみてください。
すでにKovanテストネットでは、複数担保型DAIのスマートコントラクトがリリースされています。また、ポータルサイト、コマンドラインツール、Dai.jsライブラリなど、複数担保型DAIのシステムとやりとりするツールもいくつか公開されています。今回の記事ではmcd-cliというコマンドラインツールを使ってCDPのライフサイクルを1周してみます。
なお、この記事はmcd-cliの公式ガイドを元にして書かれていますが、わかりにくい部分や省かれている部分があったため、セットアップも含めて説明を付け足しています。また、Linuxでも問題なく動作するかの検証まではしておりませんので、Macで作業することをお勧めします。
では、早速はじめましょう!
セットアップ
まずはセットアップを済ませます。スマートコントラクトとやりとりするための新しいEthereumのアカウントを作り、mcd-cliをインストールし、ETHとCOL1トークンを入手していきます。COL1トークンというのは、テスト目的で作られた複数担保型DAIの担保トークンです。価値は大体1USDに対して10COL1になっています。以下が、より具体的なステップになります。1つ1つ順番にセットアップしていきます。
1)parityのインストール
2)アカウントの作成
3)dapps toolsのインストール
4)mcdパッケージのインストール
5).sethrcファイルの設定
6)Kovan ETHの入手
7)COL1 tokensの入手
1)parityのインストール
1 2 3 4 5 6 |
// Rustのインストール $ curl https://sh.rustup.rs -sSf | sh // parityクライアントのインストール $ bash <(curl https://get.parity.io -L) -r stable |
※gethもサポートされていますが、未テストのためparityの使用をお勧めします。
2)アカウントの作成
1 2 3 4 5 6 7 |
$ parity --chain kovan account new Please note that password is NOT RECOVERABLE. Type password: ********* Repeat password: ********* // パスワードを入力してください。 // このパスワードは後で使うので、忘れないようにしてください。 0x5e232581fc1cb8cafacfcd951de05cf906e73f93 |
以下のコマンドでアカウントをリストできます。
1 2 |
$ parity --chain kovan account list 0x5e232581fc1cb8cafacfcd951de05cf906e73f93 |
3)dapps toolsのインストール
以下のコマンドですぐにインストールできます(GNU/LinuxもしくはmacOSのみ)。
1 |
$ curl https://dapp.tools/install | sh |
dapp.toolsは、ブロックチェーン上の開発で使えるかなりイケてるコマンドラインツールです! LinuxのNixOSで使われているnixパッケージマネージャーを使っています。このスクリプトはnixパッケージマネージャーをダウンロードし、Cachixでバイナリのキャッシュをセットアップして、dapp、seth、solc、hevm、ethsignなどのツールを一緒にインストールしてくれます。
4)mcdパッケージのインストール
1 |
$ dapp pkg install mcd |
v0.2.6 を使っています。
1 2 |
$ mcd — version mcd 0.2.6-rc.1 |
※他のバージョンでは動かない可能性があるので、必ずv0.2.6をインストールしてください。
5).sethrcファイルの設定
mcd-cliはEthereumの万能ツールであるsethがベースになっています。スマートコントラクトの関数の呼び出しをcurl、post、rpcメソッドなどを使って行う必要がなく、簡潔なコマンドで呼べるようになります。
ホームディレクトリにある.sethrcファイルの編集
1 2 3 4 |
export ETH_FROM=0x5e232581fc1cb8cafacfcd951de05cf906e73f93 # 作成したアドレスをここに指定 export MCD_CHAIN=kovan export SETH_CHAIN=kovan |
※キーファイルの場所をデフォルトではなくカスタムで指定したい場合は、 ETH_KEYSTORE変数を使ってください。
6)Kovan ETHを入手
こちらのfaucetにいき、自分のアドレスにKovanETHを送ってください。GitHubアカウントでログインし、ETHのアドレスをフォームに記入してリクエストを送るだけです。また、GitterチャンネルでKovanETHをもらうこともできます。知り合いからもらえる方は0.2KovanETHはもらっておいてください。KovanETHが入手できたかは、Etherscanで確認することができます(例)。
7) COL1 tokensを入手
次にCOL1トークンを入手しましょう。こちらはスマートコントラクトから入手することができます。
COL1のアドレスを環境変数に設定
1 |
$ export COL1A=0xc644e83399f3c0b4011d3dd3c61bc8b1617253e5 |
Faucetのアドレスを環境変数に設定
1 |
$ export FAUCET=0xa402e771a4662dcbe661e839a6e8c294d2ce44cf |
gulp(address)関数を呼んで、COL1トークンを入手
1 2 3 4 5 6 |
$ seth send $FAUCET 'gulp(address)' $COL1A seth-send: warning: `ETH_GAS’ not set; using default gas amount Ethereum account passphrase (not echoed): seth-send: Published transaction with 36 bytes of calldata. seth-send: 0xf0ac981342ac8ac9c59cd25107667ecc7fd2dadc4089e59aa0b09055d5d08d09 seth-send: Waiting for transaction receipt… seth-send: Transaction included in block 11268445. |
コマンドを走らせるとパスワードの入力を求められます。sethはキーとパスワードをgethとparityのデフォルトのダイレクトリから探し、トランズアクションを送ります。
コマンドラインを使ってトークンの残高を確認できます。
1 2 |
$ mcd --ilk=COL1-A gem balance ext 50.000000000000000000 |
また、コマンドのアウトプットにあるトランズアクションのハッシュ値から、Etherscanで残高を確認することも可能です(例)。自分のアカウントに飛ぶと、COL1トークンが入手できたことがわかるはずです。
※Etherscan上ではTOK1という表記になっていますが、気にしなくて大丈夫です。
コマンドラインツールでCDPライフサイクルを1周する
では、これからCOL1トークンを担保として、CDPのライフサイクルを1周してみます! 大きく分けて、以下のような6つのステップで進めます。
1)CDPを開く
2)COL1トークンをデポジットする
3)DAIを引き出す
4)DAIを返済する
5)担保を除く
6)CDPを閉じる
コマンドの性質上、1つ1つのステップに分けづらいので、まずは最初の3つのステップをカバーします。
1)CDPを開く / 2)COL1トークンをデポジットする / 3)DAIを引き出す
まず、以下のコマンドを走らせてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$ mcd --ilk=COL1-A gem join 30 Insufficient allowance: ETH_FROM: 0x5e232581fc1cb8cafacfcd951de05cf906e73f93 Grant approval to move COL1 to 0xc4e81c9690bb664d682826e3415134c23d08e7bb? [Y/n]: y seth-send: warning: `ETH_GAS' not set; using default gas amount Ethere account passphrase (not echoed): seth-send: Published transaction with 68 bytes of calldata. seth-send: 0x2b5572b04a676533769ffd917c463e02507e7195e1c78981d784268ac6d4af71 seth-send: Waiting for transaction receipt.... seth-send: Transaction included in block 11268499. seth-send: warning: `ETH_GAS' not set; using default gas amount Ethereum account passphrase (not echoed): seth-send: Published transaction with 68 bytes of calldata. seth-send: 0x2ca98bbd831afc3de4d8b03d469350f8cc0d2a9bac5cf32e9f87558f984f76ff seth-send: Waiting for transaction receipt.... seth-send: Transaction included in block 11268505. vat 30.000000000000000000 Unlocked collateral (COL1) ink 0.000000000000000000 Locked collateral (COL1) ext 20.000000000000000000 External account balance (COL1) |
すると、以下のようなアウトプットが表示されます。
1 2 3 |
vat 30.000000000000000000 Unlocked collateral (COL1) ink 0.000000000000000000 Locked collateral (COL1) ext 20.000000000000000000 External account balance (COL1) |
COL1トークンが担保としてvat
という内部レジストリに追加されました。上のアウトプットでvat
内の担保の残高が30になっていることがわかると思います。ただ、実はまだCDPにロックされているわけではありません。ink
というのがCDPにロックされている残高を示しています。見てのとおり、まだどのCDPにも割り当てられていないのでink
は現在0になっています。ext
というのはMakerDAOのシステム外のトークンの残高です。30トークンをvat
に移したため、現在は20になっています。
gem
コマンドを見てみましょう。
1 |
$ mcd --ilk=COL1-A gem join 30 |
join
サブコマンドは送り手のアカウントからvat
に担保を追加することができます。ilk=COL1-A
というフラグで担保の種類を指定しています。30というのは送るトークンの量です。
次にCOL1トークンをCDPにロックして、DAIを引き出します。
以下のコマンドを走らせてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ mcd --ilk=COL1-A frob 30 1 seth-send: warning: `ETH_GAS' not set; using default gas amount Ethereum account passphrase (not echoed): seth-send: Published transaction with 196 bytes of calldata. seth-send: 0x1a8bdfc017d96c921b1cba172dccf9449eac1f28d0e03e26f90194f7ab5c9bba seth-send: Waiting for transaction receipt... seth-send: Transaction included in block 11268516. ilk COL1-A Collateral type urn 0x5e232581Fc1cB8caFAcfCd951De05cF906e73F93 Urn handler ink 30.000000000000000000 Locked collateral (COL1) art 1.000000000000000000 Issued debt (Dai) tab 1.000479620379870482338446891 Outstanding debt (Dai) rap 0.000479620379870482338446891 Accumulated stability fee (Dai) --> 2.36 Collateralization ratio spot 0.078725888888888888888888889 COL1 price with safety mat (USD) rate 1.000479620379870463446010918 COL1 DAI exchange rate |
以下のようなアウトプットが表示されます。
1 2 3 4 |
ilk COL1-A Collateral type urn 0x5e232581Fc1cB8caFAcfCd951De05cF906e73F93 Urn handler ink 30.000000000000000000 Locked collateral (COL1) art 1.000000000000000000 Issued debt (Dai) |
inkにCOL1トークンの残高が移り、CDPにCOL1トークンがロックされました。
※urn
というのは特定のCDPのことです。
また、DAIが発行されたこともわかります(art
)。
frob
コマンドを使ってvat
からトークンをロックするコマンドを走らせたことで、トークンがurn
にロックされてDAIが生成されました。
frob
コマンドは 担保の種類をilk=COL1-A
フラグで、30という数字でロックしたいトークンの量を、そして末尾の1という数字で生成したいDAIの量を指定しています。
1 |
$ mcd --ilk=COL1-A frob 30 1 |
DAIはまだvat
にあるため、これからDAIを引き出し、Ethereumのアカウントに送ります。
以下のコマンドを走らせてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ mcd dai exit 1 Vat Dai: approval required: urn: 0x5e232581Fc1cB8caFAcfCd951De05cF906e73F93 Grant approval to move Dai from the Vat? [Y/n]: y seth-send: warning: `ETH_GAS' not set; using default gas amount Ethereum account passphrase (not echoed): seth-send: Published transaction with 36 bytes of calldata. seth-send: 0x12a1b3276f3a308d96084d1c090a0337892b06a7ba5eba17e542abf0c83f4ff7 seth-send: Waiting for transaction receipt.... seth-send: Transaction included in block 11268535. seth-send: warning: `ETH_GAS' not set; using default gas amount Ethereum account passphrase (not echoed): seth-send: Published transaction with 68 bytes of calldata. seth-send: 0x9ea17c6de80fe99abb8165c0f490c7066a75dc07ad82413c2ace68a8e46888b4 seth-send: Waiting for transaction receipt.... seth-send: Transaction included in block 11268540. vat 0.000479620379870463446010918000000000000000000 Vat Dai balance ext 1.000000000000000000 ERC20 Dai balance |
これでDAIがvat
からext
に移ります。
1 2 |
vat 0.000479620379870463446010918000000000000000000 Vat Dai balance ext 1.000000000000000000 ERC20 Dai balance |
dai
コマンドのexit
サブコマンドは、引き出したいDAIの量を指定できます。
以下のbalance
サブコマンドでDAIのバランスをチェックすることもできます。
1 2 3 |
$ mcd dai balance vat 0.000479620379870463446010918000000000000000000 Vat Dai balance ext 1.000000000000000000 ERC20 Dai balance |
ここまでで、CDPを開き、COL1トークンを担保としてCDPにロックし、発行したDAIを引き出しました。
では、今度は逆にDAIを返済し、担保をCDPから取り出して、CDPを閉じてみましょう。
4)DAIを返済する / 5)担保を除く / 6)CDPを閉じる
まず以下のコマンドを走らせてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ mcd dai join 1 ERC20 Dai: insufficient allowance: ETH_FROM: 0x5e232581fc1cb8cafacfcd951de05cf906e73f93 Grant approval to transfer Dai to the 0x7bb403aae0330f1acaad8f2a06ebe4b4e4784418? [Y/n]: y seth-send: warning: `ETH_GAS' not set; using default gas amount Ethereum account passphrase (not echoed): seth-send: Published transaction with 68 bytes of calldata. seth-send: 0x0792f68611a51b66793bee3bf20c8f923e324f2791e2eeeda73141e3216e5959 seth-send: Waiting for transaction receipt.... seth-send: Transaction included in block 11268942. seth-send: warning: `ETH_GAS' not set; using default gas amount Ethereum account passphrase (not echoed): seth-send: Published transaction with 68 bytes of calldata. seth-send: 0x6093fa6877ad9342077415313e28584c943f85135e597751f97b997f2a086ed2 seth-send: Waiting for transaction receipt... seth-send: Transaction included in block 11268946. vat 1.000479620379870463446010918000000000000000000 Vat Dai balance ext 0.000000000000000000 ERC20 Dai balance |
これでDAIがext
から内部レジストリであるvat
に移動しました。
1 2 |
vat 1.000479620379870463446010918000000000000000000 Vat Dai balance ext 0.000000000000000000 ERC20 Dai balance |
またbalance
サブコマンドで残高を確認できます。
1 2 3 |
$ mcd dai balance vat 1.000479620379870463446010918000000000000000000 Vat Dai balance ext 0.000000000000000000 ERC20 Dai balance |
dai
コマンドのjoin
サブコマンドはurn
に返済したいDAIの量を指定することができます。
1 |
$ mcd dai join 1 |
次にDAIを焼却して、担保であるCOL1トークンをink
から取り出します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ mcd --ilk=COL1-A frob -- -30 -1 seth-send: warning: `ETH_GAS' not set; using default gas amount Ethereum account passphrase (not echoed): seth-send: Published transaction with 196 bytes of calldata. seth-send: 0xa04330cbf6f5755e702fb3d4e2c37fe07825d3723b385f46a66912a31d192649 seth-send: Waiting for transaction receipt.... seth-send: Transaction included in block 11329728. ilk COL1-A Collateral type urn 0x5e232581Fc1cB8caFAcfCd951De05cF906e73F93 Urn handler ink 0.000000000000000000 Locked collateral (COL1) art 0.000000000000000000 Issued debt (Dai) tab 0 Outstanding debt (Dai) rap 0 Accumulated stability fee (Dai) --> 0 Collateralization ratio spot 0.078725888888888888888888889 COL1 price with safety mat (USD) rate 1.000479620379870463446010918 COL1 DAI exchange rate |
前にfrob
コマンドを使った時のアウトプットを見ると、担保をink
にロックしてDAIをart
に生成しましたことがわかります。
1 2 3 4 |
ilk COL1-A Collateral type urn 0x5e232581Fc1cB8caFAcfCd951De05cF906e73F93 Urn handler ink 30.000000000000000000 Locked collateral (COL1) art 1.000000000000000000 Issued debt (Dai) |
では今回のアウトプットを見てみましょう。
1 2 3 4 |
ilk COL1-A Collateral type urn 0x5e232581Fc1cB8caFAcfCd951De05cF906e73F93 Urn handler ink 0.000000000000000000 Locked collateral (COL1) art 0.000000000000000000 Issued debt (Dai) |
今回は逆にink
にあったロックされていた担保とart
にあったDAIがなくなっているのがわかります。
今回はilk=
フラグで担保の種類を指定し、30という数字でink
から取り除くトークンの量を指定し、末尾の1という数字で焼却したいDAIの量を指定しています。
1 |
$ mcd --ilk=COL1-A frob — -30 -1 |
COL1トークンがvat
にあるのがわかります。
1 2 3 4 |
$ mcd gem --ilk=COL1-A balance vat 30.000000000000000000 Unlocked collateral (COL1) ink 0.000000000000000000 Locked collateral (COL1) ext 20.000000000000000000 External account balance (COL1) |
最後にvat
からCOL1トークンを取り除きます。
1 2 3 4 5 6 7 8 9 |
$ mcd --ilk=COL1-A gem exit 30 seth-send: warning: `ETH_GAS' not set; using default gas amount Ethereum account passphrase (not echoed): seth-send: Published transaction with 68 bytes of calldata. seth-send: 0x880fe9d00953f229be96bbc170867238c1b547f6a28e6ac29f7618d8bde105c2 seth-send: Waiting for transaction receipt... seth-send: Transaction included in block 11329744. vat 0.000000000000000000 Unlocked collateral (COL1) ink 0.000000000000000000 Locked collateral (COL1) ext 50.000000000000000000 External account balance (COL1) |
トークンがvat
からext
に移りました。
1 2 3 |
vat 0.000000000000000000 Unlocked collateral (COL1) ink 0.000000000000000000 Locked collateral (COL1) ext 50.000000000000000000 External account balance (COL1) |
parityアカウントを確認すると、COL1トークンが戻っているはずです。これでCDPのライフサイクルを1周できました!
複数担保型と単一担保型の違いはいくつもあるのでまた記事にする予定です。自分で学びたいという方は、MakerDAOの用語集やスマートコントラクトも参考にしてみてください。
関連記事:MakerDAOのステーブルコイン「DAI」 はなぜ安定するのか? そのメカニズムを詳解
Profile
解説:三野泰佑
クリプトエンジニア
2013年頃からブロックチェーンに関わり、スマートコントラクトのベストプラクティスを閲覧できるサイトやSolidityの監査をするサービスを開発。現在はICOVOのエンジニアとして開発や執筆をしながら、ステーブルコインに特化したモバイルウォレットも開発している。