💭

Flutter で web3モバイルアプリ

2023/08/14に公開

概要

Flutterを使って、web3のモバイルアプリを作れないかなと思い作成してみました.
現状はDappはwebのフロントエンドが主流だと思いますが、モバイルアプリでかつFlutterでiOS/Android向けにどんな感じで開発できるのかを検証することがモチベーションとなります.
一旦のゴールはスマートコントラクトの実行(トランザクションの送信)を目標として取り組みました.

現状の成果物

コード一式はGithubで公開しております.
https://github.com/tarosuzuki/web3-mobile

下記の動画に示すような、wallet連携 と トランザクションの送信(ERC-20トークンのtransferの実行)までを実施しております.
動画はiOSになりますが、Androidでも同じような挙動になることは確認できています.

主なポイントとしては下記になります.

  • WalletConnectを利用してmetamaskと連携して、walletのアドレス等の取得, トランザクションの送信などを実施
  • トランザクションの送信時には、walletアプリを起動してユーザに許諾してもらう
  • トランザクションの送信後に元アプリに戻るところができていない...

https://www.youtube.com/watch?v=HUAAnpmbXuE

利用したパッケージ

当初は下記のパッケージ関連を利用しようと考えていたのですが、WalletConnectのプロトコルのバージョンアップに伴い利用できなそうでした.

https://pub.dev/packages/wallet_connect

WalletConnectが公式で開発しているパッケージがあったので、下記2つを主に利用しています.
https://pub.dev/packages/walletconnect_flutter_v2
https://pub.dev/packages/walletconnect_modal_flutter
walletconnect_modal_flutterの方はWalletConnectを利用したwallet連携において、接続用のURL生成だけでなく、View(UI)を含めた連携機能を提供してくれています.

実装におけるポイント

WalletConnectの利用

WalletConnectの利用においては、事前にWalletConnect(https://walletconnect.com/)でプロジェクトを作成し、ProjectIDを取得する必要があります.

また、WalletConnectでは利用できるチェーンが決まっているので所望のチェーンが対応しているかの確認が必要になります(https://docs.walletconnect.com/2.0/advanced/multichain/chain-list).

私はテストネットワークのSepoliaを利用したかったのですが当時は対応しておりませんでした.
ちょうどGithubのissueでリクエストが上がっていたので、対応されるのを待ちました.
(チェーンの対応リクエストはissueであげるように記載があります)

WalletConnectの設定に関するコードとしては下記のような形で、プロジェクトIDやチェーンを設定する必要があります.

https://github.com/tarosuzuki/web3-mobile/blob/main/lib/data/wallet_connect/wallet_connect_service_impl.dart#L21

_walletConnectModalService = WalletConnectModalService(
      projectId: _ethereumConfig.walletConnectProjectId,
      requiredNamespaces: {
        'eip155': RequiredNamespace(
          methods: [
            'eth_sendTransaction',
            'personal_sign',
            'eth_sign',
            'eth_signTypedData',
          ],
          chains: ['eip155:11155111'],
          events: [
            'chainChanged',
            'accountsChanged',
          ],
        ),
      },
      metadata: PairingMetadata(
        name: _ethereumConfig.walletConnectParingMetadataName,
        description: _ethereumConfig.walletConnectParingMetadataDescription,
        url: _ethereumConfig.walletConnectParingMetadataUrl,
        icons: [_ethereumConfig.walletConnectParingMetadataIconUrl],
        redirect: Redirect(
          native: _ethereumConfig.walletConnectParingMetadataRedirectAppSchema,
        ),
      ),
    );

トランザクションの送信

特定のスマートコントラクトのコードを呼び出す場合の、トランザクションのdataフィールドの生成方法を少し悩みましたが、下記ように実施できました.

  • abiファイルからコントラクトの定義を生成して
    ( _contractInner = DeployedContract() あたり)
  • 所望のメソッドを指定するようなイメージになります
    (final transaction = Transaction.callContract() あたり)

https://github.com/tarosuzuki/web3-mobile/blob/main/lib/data/coin/cloud_coin_service.dart#L32

Future<DeployedContract> get _contract async {
    if (_contractInner == null) {
      final abiCode =
          await rootBundle.loadString('assets/abi/TaroCoin.abi.json');
      _contractInner = DeployedContract(
        ContractAbi.fromJson(abiCode, 'TaroCoin'),
        _contractAddress,
      );
    }
    return _contractInner!;
  }
   ....

  
  Future<bool> transfer({
    required String toAddress,
    required BigInt value,
  }) async {
    try {
      final contract = await _contract;
      final to = EthereumAddress.fromHex(toAddress);
      final amount = EtherAmount.fromBigInt(EtherUnit.ether, value).getInWei;
      final transaction = Transaction.callContract(
        contract: contract,
        function: contract.function('transfer'),
        parameters: [to, amount],
      );
      final hexEncodedData = hex.encode(transaction.data!);
      final response = _walletConnectService.sendTransaction(
        to: _contractAddress.toString(),
        data: hexEncodedData,
      );
      return true;
    } catch (e) {
      _logger?.e('error - ${e.toString()}');
      return false;
    }
  }
}

課題

  • トランザクションの送信後に元アプリへ自動で戻れない
    WalletConnectの設定としては、redirect先(アプリのdeep link)の設定など、設定できる項目は実施しているのですが、自動で戻れていません.
    iOSやAndroidの場合の戻り方に関しては公式のドキュメントに記載があるのですが、Flutterには記載がなく、現状では術がないのかが気になっております.

  • Ethereumのイベントの受信
    トークンの転送などのイベントのハンドリングはできると思うのですが、未着手です.

  • NFT関連
    未着手です...

Discussion