Posted at

EOSIOで独自の仮想通貨トークンを発行・送金してみる

開発環境の構築とかはこちら参照:

https://qiita.com/YukiSekiguchi/items/623359857269aff74586

https://qiita.com/YukiSekiguchi/items/f84afbf35f4fa039859c


今回やること

https://developers.eos.io/eosio-home/docs/token-contract に沿ってEOSIOのプライベートネットワーク上で仮想通貨トークンを発行、送金してみる


準備

nodeosのコンテナが動いてないようなら動かす

$docker start 1574a37de3c6

まずはウォレットをopenする+unlockする。

$cleos wallet open -n default

$cleos wallet unlock -n default

トークン発行するスマートコントラクト用にアカウントを作成。開発用の鍵を使う。

$cleos create account eosio eosio.token EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV

トークン発行用のスマートコントラクトの実装は公式が提供してくれているので、これを持ってくる

$git clone https://github.com/EOSIO/eosio.contracts

そのままコンパイルするだけ。簡単。

$cd eosio.contracts

$eosio-cpp -o eosio.token.wasm src/eosio.token.cpp -I include/


トークンの作成

コンテナの中にeosio.token.wasmとabiを持っていったら

$ cleos set contract eosio.token <eosio.token.wasmがおいてあるコンテナ内のパス> --abi <eosio.token.abiのおいてあるコンテナ内のパス> -p eosio.token@active

とすると

Reading WASM from /home/eosio.contracts/eosio.token/eosio.token.wasm...

Publishing contract...
executed transaction: c12511f41efb3ec72e64a9ab8ce040f2c65c54a7d7d21ef847bb758b0b49e79c 9320 bytes 1490 us
# eosio <= eosio::setcode {"account":"eosio.token","vmtype":0,"vmversion":0,"code":"0061736d0100000001b0011d60037f7e7f0060047f...
# eosio <= eosio::setabi {"account":"eosio.token","abi":"0e656f73696f3a3a6162692f312e30010c6163636f756e745f6e616d65046e616d65...
2018-10-08T12:07:31.800 thread-0 main.cpp:481 print_result warning: transaction executed locally, but may not be confirmed by the network yet

と出てスマートコントラクトがネットワーク上にデプロイされる。

この状態で次のコマンドを打つとトークンが作成できる。

cleos push action eosio.token create '[ "eosio", "1000000000.0000 HOGE"]' -p eosio.token@active

1000000000.0000は発行上限が1000000000で、最小単位が0.0001になること表す。

またHOGEの部分は任意の大文字アルファベットを入れる。これがトークンの単位になる。普通は3文字にする(と思う)。

今回はこのままHOGEコインということで進める。


トークンの発行

発行(issue)と作成(create)は違う概念で、createはトークンの上限と最小単位と単位を規定し、実際のトークンはeosio.token自身が持つ。

トークンを通常のアカウント向けに渡すのが発行である(この辺の理解は怪しい)。

前回作ったalicebobにトークンを発行し、やりとりさせてみる。

まずalice100.0000 HOGE発行する。

$ cleos push action eosio.token issue '[ "alice", "100.0000 HOGE", "memo" ]' -p eosio@active

executed transaction: deafe9a28bbd20697c28f1e2a2b7c2997d589115c661d5010cbe25a909074460 128 bytes 6136 us
# eosio.token <= eosio.token::issue {"to":"alice","quantity":"100.0000 HOGE","memo":"memo"}
# eosio.token <= eosio.token::transfer {"from":"eosio","to":"alice","quantity":"100.0000 HOGE","memo":"memo"}
# eosio <= eosio.token::transfer {"from":"eosio","to":"alice","quantity":"100.0000 HOGE","memo":"memo"}
# alice <= eosio.token::transfer {"from":"eosio","to":"alice","quantity":"100.0000 HOGE","memo":"memo"}

memoの部分は文字通りメモで、取引について好きなメモを残せる。

なおHOGEコインの最小単位は0.0001にしたので、きっちり.0000まで書かないと以下のようにエラーになる。

$ cleos push action eosio.token issue '[ "alice", "100.0 HOGE", "memo" ]' -p eosio@active

Error 3050003: eosio_assert_message assertion failure

また、-dをつけるとdry runができる(見てもよくわからない)。

$ cleos_d push action eosio.token issue '[ "alice", "100.0000 HOGE", "memo" ]' -p eosio@active -d

{
"expiration": "2018-10-08T12:41:28",
"ref_block_num": 52702,
"ref_block_prefix": 2512073667,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [{
"account": "eosio.token",
"name": "issue",
"authorization": [{
"actor": "eosio",
"permission": "active"
}
],
"data": "0000000000855c3440420f000000000004484f4745000000046d656d6f"
}
],
"transaction_extensions": [],
"signatures": [
"SIG_K1_KexcdCmckuWp9bVBKeiLNDuLQA1L4Jenicy44TBTFxajF9dFrpAutrjRd4gvZdWrA8VA8ftrZ5qvEAF9FtDAYPHLpJPv2U"
],
"context_free_data": []
}

アカウントが持つトークンは次のように確認できる

$ cleos get currency balance eosio.token alice HOGE

100.0000 HOGE


トークンの送金

これでalice100.0000HOGE持っているので、bobに送金してみる。

試しにmemoに日本語を入れたけど大丈夫だった(途中で切れてしまったが)。

$ cleos push action eosio.token transfer '[ "alice", "bob", "25.0000 HOGE", "アリスからボブに25.0000HOGE送金する" ]' -p alice@active

executed transaction: 8378a1d8577444796660e9ae5f417f71ad05bcfb54fa4f1e82ed4f65dacd1d5e 176 bytes 2931 us
# eosio.token <= eosio.token::transfer {"from":"alice","to":"bob","quantity":"25.0000 HOGE","memo":"アリスからボブに25.0000HOGE送�...
# alice <= eosio.token::transfer {"from":"alice","to":"bob","quantity":"25.0000 HOGE","memo":"アリスからボブに25.0000HOGE送�...
# bob <= eosio.token::transfer {"from":"alice","to":"bob","quantity":"25.0000 HOGE","memo":"アリスからボブに25.0000HOGE送�...
2018-10-08T12:45:34.574 thread-0 main.cpp:481 print_result warning: transaction executed locally, but may not be confirmed by the network yet

bobのトークン所有量を見てみると、

$cleos get currency balance eosio.token bob HOGE

25.0000 HOGE

となり、aliceのトークン所有量を見てみると、

$cleos get currency balance eosio.token alice HOGE

75.0000 HOGE

となっていて、aliceからbob25.0000 HOGE送金できたことがわかる。

ちなみに試しにbobが勝手にaliceからbobに送金しようとする(最後をbob@activeに変える)と何が起きるかというと

$ cleos push action eosio.token transfer '[ "alice", "bob", "25.0000 HOGE", "アリスからボブに勝手に25.0000HOGE送金する" ]' -p bob@active

Error 3090004: Missing required authority

となり、勝手なことはできないようになっている。

これはsrc/eosio.token.cppの中身を見てみると

void token::transfer( account_name from,

account_name to,
asset quantity,
string memo )
{
eosio_assert( from != to, "cannot transfer to self" );
require_auth( from );
eosio_assert( is_account( to ), "to account does not exist");
auto sym = quantity.symbol.name();
stats statstable( _self, sym );
const auto& st = statstable.get( sym );


となっており、前回もやったrequire_auth( from )が効いているからであることがわかる。