Flutter で web3モバイルアプリ
概要
Flutterを使って、web3のモバイルアプリを作れないかなと思い作成してみました.
現状はDappはwebのフロントエンドが主流だと思いますが、モバイルアプリでかつFlutterでiOS/Android向けにどんな感じで開発できるのかを検証することがモチベーションとなります.
一旦のゴールはスマートコントラクトの実行(トランザクションの送信)を目標として取り組みました.
現状の成果物
コード一式はGithubで公開しております.
下記の動画に示すような、wallet連携 と トランザクションの送信(ERC-20トークンのtransferの実行)までを実施しております.
動画はiOSになりますが、Androidでも同じような挙動になることは確認できています.
主なポイントとしては下記になります.
- WalletConnectを利用してmetamaskと連携して、walletのアドレス等の取得, トランザクションの送信などを実施
- トランザクションの送信時には、walletアプリを起動してユーザに許諾してもらう
- トランザクションの送信後に元アプリに戻るところができていない...
利用したパッケージ
当初は下記のパッケージ関連を利用しようと考えていたのですが、WalletConnectのプロトコルのバージョンアップに伴い利用できなそうでした.
WalletConnectが公式で開発しているパッケージがあったので、下記2つを主に利用しています.
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やチェーンを設定する必要があります.
_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()
あたり)
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