第4回 Move言語でEthereumのERC20のような独自コインを作れるか試す

第4回 Move言語でEthereumのERC20のような独自コインを作れるか試す

Libraに関するセミナーのご依頼、その他ブロックチェーンに関するコンサルティングのお問い合わせはこちらからお願いいたします。(ページ右下の「サポート」をクリック)
連載全5回のインデックスはこちら

実践的なプログラムの作成②

今回は実践的なプログラムの作成として、EthereumのERC20を使った独自コインのようなものがMove言語で作れるかどうかを試してみます。

ERC20の詳細は割愛しますが、OpenZeppelinのERC20を扱うためのライブラリでは、以下のような機能が提供されており、これらをMove言語で実装できるか検証してみます。
  • コインに名前を付けて取得ができる
  • コインの合計発行量を取得できる
  • コインの発行ができる
  • コインの送金ができる
  • 指定したアドレスの残高を取得できる

プログラム

検証のために作成したプログラムは以下の通りです。
modules:
 
module CBCoin {
 
  // コイン全体を表すリソース
  resource CB_COIN {
    name: bytearray,
    total_supply: u64,
  }
 
  // アカウントごとの残高を表すリソース
  resource WALLET {
    balance: u64,
  }
 
  // 初期化関数
  public publish() {
    move_to_sender(CB_COIN{ name: b"cb", total_supply: 0 });
    move_to_sender(WALLET{ balance: 0 });
    return;
  }
 
  // コインの名前を取得する関数
  public get_coin_name(): bytearray {
    let cbcoin_ref: &mut R#Self.CB_COIN;
    let name: bytearray;
    let sender: address;
 
    sender = get_txn_sender();
    cbcoin_ref = borrow_global(move(sender));
    name = *(&move(cbcoin_ref).name);
 
    return move(name);
  }
 
  // 合計発行量を取得する関数
  public total_supply(): u64 {
    let cbcoin_ref: &mut R#Self.CB_COIN;
    let supply: u64;
    let sender: address;
 
    sender = get_txn_sender();
    cbcoin_ref = borrow_global(move(sender));
    supply = *(&move(cbcoin_ref).total_supply);
 
    return move(supply);
  }
 
  // コインを発行する関数
  public mint(addr: address, value: u64) {
    let cbcoin_ref: &mut R#Self.CB_COIN;
    let total_supply: u64;
    let wallet_ref: &mut R#Self.WALLET;
    let balance: u64;
 
    cbcoin_ref = borrow_global(copy(addr));
    total_supply = *(©(cbcoin_ref).total_supply);
    *(&mut move(cbcoin_ref).total_supply) = move(total_supply) + copy(value);
 
    wallet_ref = borrow_global(move(addr));
    balance = *(©(wallet_ref).balance);
    *(&mut move(wallet_ref).balance) = move(balance) + copy(value);
 
    return;
  }
 
  // 残高を取得する関数
  public balance_of(addr: address): u64 {
    let coin_ref: &mut R#Self.WALLET;
    let coin_value: u64;
 
    coin_ref = borrow_global(copy(addr));
    coin_value = *(&move(coin_ref).balance);
 
    return move(coin_value);
  }
 
  // 送金する関数
  public transfer(recipient_address: address, amount: u64) {
    let sender: address;
    let sender_wallet_ref: &mut R#Self.WALLET;
    let sender_balance: u64;
    let receiver_wallet_ref: &mut R#Self.WALLET;
    let receiver_balance: u64;
 
    sender = get_txn_sender();
    sender_wallet_ref = borrow_global(copy(sender));
    sender_balance = *(©(sender_wallet_ref).balance);
    *(&mut move(sender_wallet_ref).balance) = move(sender_balance) - copy(amount);
 
    //receiver_wallet_ref = borrow_global(move(recipient_address));
    //receiver_balance = *(©(receiver_wallet_ref).balance);
    //*(&mut move(receiver_wallet_ref).balance) = move(receiver_balance) + copy(amount);
 
    return;
  }
 
}
 
 
script:
import Transaction.CBCoin;
import 0x0.LibraAccount;
 
main() {
  let sender: address;
  let name: bytearray;
  let total_supply: u64;
  let balance: u64;
  let recipient_address: address;
  let sender_balance: u64;
  let recipient_balance: u64;
 
  sender = get_txn_sender();
  recipient_address = 0xb0b;
 
  CBCoin.publish();
 
  // コインのnameを取得して検証
  name = CBCoin.get_coin_name();
  assert(copy(name) == b"cb", 99);
 
  // コインの合計発行量が0であることを検証
  total_supply = CBCoin.total_supply();
  assert(copy(total_supply) == 0, 99);
 
  // コインを発行し、発行先のアドレスの残高を検証
  CBCoin.mint(copy(sender), 100);
  balance = CBCoin.balance_of(copy(sender));
  assert(move(balance) == 100, 99);
 
  LibraAccount.create_new_account(copy(recipient_address), 0);
 
  // コインを送金
  CBCoin.transfer(copy(recipient_address), 70);
 
  // 送金元の残高を取得して検証
  sender_balance = CBCoin.balance_of(copy(sender));
  assert(move(sender_balance) == 30, 99);
 
  // 送金先の残高を取得して検証
  //recipient_balance = CBCoin.balance_of(copy(recipient_address));
  //assert(move(recipient_balance) == 70, 99);
 
  // コインの合計発行量を検証
  total_supply = CBCoin.total_supply();
  assert(move(total_supply) == 100, 99);
 
  return;
 
}
上記のプログラムをテスト実行すると、
test functional_tests::cb_coin/CBCoin.mvir ... ok
とOKなりますが、一部コメントアウトしている部分があります。これらを外して実行すると、「Execution(MissingData)」というエラーが発生します。その内容については後述の検証結果にて説明します。

検証結果

検証項目に対する結果は以下のとおりです。
  • コインに名前を付けて取得ができる
    • 可能。ただし、Moveは文字列を扱うことができないので、bytearrayでの格納、取得になる。
  • コインの合計発行量を取得できる
    • 可能。ただし、適切な管理方法が不明。(後述)
  • コインの発行ができる
    • 一部可能。トランザクション実行者であれば、発行した数に応じて合計発行量や残高を増やすこともできたが、それ以外のアカウントではエラーとなった。
  • コインの送金ができる
    • 不可能。詳細は後述。
  • 指定したアドレスの残高を取得できる
    • 一部可能。トランザクション実行者であれば、残高を確認することができたが、それ以外のアカウントではエラーとなった。

Libraにおけるリソースの扱いについて

Libraではリソースの保存領域はアカウントごとになります。そのため、送金を行った際には、送金元のリソースと送金先のリソースをMoveで扱うことになりますが、トランザクション実行者以外のリソースを初期化する手段がなく、初期化しないまま取得しようとすると、「Execution(MissingData)」というエラーが発生して処理を続行することができませんでした。

また、合計発行量のようなシステムで一意となる情報をどこに保存すべきかという点にも悩みました。今回はトランザクション実行者のリソースに保存していますが、実際にメインネット等にデプロイした際には、コントラクトアドレスのリソースで管理する等の方法が適切であると思いますが、デプロイ時の挙動が不明瞭なため、この点は今後の課題となります。

Moveでは連想配列のような情報の持ち方が現状サポートされていないため、各アカウントの情報を配列で保持するようなこともできません。それぞれのアカウントのリソースにアクセスできないと、アカウント間での情報のやり取りを行うようなプログラムが作れない状況になってしまいます。

第3回で行った標準のLibraコインの送金では、送金先の残高も取得できたため、何らかの手段はあると考えていますが、現段階では解決ができませんでした。

まとめ

今回は、EthererumのERC20のような使い方がLibraで可能であるか検証しました。実装可能である部分とうまくいかない部分とがありましたが、惜しいところまではいっていると思うので、引き続き調査、検証を実施していきたいと考えています。

次回は、Ethereumの別の規格ERC721が実装可能であるか検証してみます。
     

免責事項

本記事に掲載されている記事の内容につきましては、正しい情報を提供することに務めてはおりますが、提供している記事の内容及び参考資料からいかなる損失や損害などの被害が発生したとしても、弊社では責任を負いかねます。実施される際には、法律事務所にご相談ください。

技術・サービス・実装方法等のレビュー、その他解説・分析・意見につきましてはblock-chani.jp運営者の個人的見解です。正確性・正当性を保証するものではありません。本記事掲載の記事内容のご利用は読者様個人の判断により自己責任でお願いいたします。

     

コンセンサス・ベイス(株)とブロックチェーン事業を行なってみませんか?

当サイトを運営するコンセンサス・ベイス株式会社は、2015年設立の国内で最も古いブロックチェーン専門企業です。これまでに、大手企業の顧客を中心に、日本トップクラスのブロックチェーンの開発・コンサルティング実績があります。

ブロックチェーンに関わるビジネスコンサル・システム開発・教育・講演などご希望でしたら、お気軽にお問い合わせください。

     
     

ブロックチェーン学習に最適の書籍の紹介

図解即戦力 ブロックチェーンのしくみと開発がこれ1冊でしっかりわかる教科書

ブロックチェーン イーサリアムへの入り口 第二版 (ブロックチェーン技術書籍)

本書は、ブロックチェーン技術に興味を持ったエンジニアや、その仕組みを学び、自分の仕事に活かしたいビジネスパーソンを対象にして、ブロックチェーンのコア技術とネットワーク維持の仕組みを平易な言葉で解説しています。この本を読んだうえで、実際にコードを書くような専門書、ブロックチェーンビジネスの解説書を読むことで、理解度が飛躍的に高まるでしょう。(はじめにより)

リブラ(Libra)カテゴリの最新記事