🎁

Aleph Zero Signer と React で dApp を開発&操作する方法

2024/12/11に公開

この記事の概要

Aleph Zero Signer という AZERO 用 Chrome 拡張アプリと連携し、アカウント情報の表示やトランザクションの実行ができる React アプリの開発方法を紹介します。

フロントエンド側の開発ではなく、Aleph Zero でのスマコンの開発方法をお探しの方はこちらの記事をご覧ください。
https://zenn.dev/taka101/articles/ccf84f96735130

Aleph Zero とは

https://alephzero.org/
Aleph Zero は、高スケーラビリティとプライバシー保護を重視した分散型ブロックチェーンプロジェクトです。略して AZERO とも呼びます。独自のコンセンサスアルゴリズム「AlephBFT」を使用した高速で効率的なトランザクション処理や、ゼロ知識証明技術を活用したプライバシー保護機能が特徴です。ネイティブトークンは $AZERO です。

環境構築

React プロジェクトの作成

今回は Vite を使って TypeScript, React のプロジェクトを立ち上げます。プロジェクト名は任意ですがここでは signer-integration とします。

npm create vite@latest signer-integration -- --template react-ts

また、ローカル環境の node のバージョンは14以降を推奨します。

ライブラリのインストール

以下のライブラリを使用します。

npm install @polkadot/extension-dapp @polkadot/util @polkadot/api

@polkadot/extension-dapp

ブラウザ拡張機能(Polkadot.js Extension や Aleph Zero Signer など)と dApp を接続するためのライブラリです。このライブラリを使用することで簡単にユーザーのウォレット情報にアクセスしたり、トランザクションを送信したりできます。

@polkadot/api

Substrate ベースのブロックチェーンへのアクセスに利用するライブラリです。RPC 呼び出しやストレージアクセス、トランザクション送信を簡単に実現できます。

@polkadot/util

Polkadot エコシステムに特化したユーティリティ関数を提供するライブラリです。数値変換、エンコード/デコード、チェックサム計算などを簡単に行えます。

Aleph Zero Signer のインストール

Aleph Zero のアカウント管理ができる Chrome 拡張アプリです。MetaMask の AZERO 版です。以下の URL からインストールできます。
https://alephzero.org/signer

実装

src/App.tsx のみを編集します。以下のように書き換えてみましょう。

import { useState, useEffect } from "react";
import { web3Enable, web3Accounts } from "@polkadot/extension-dapp";
import { ApiPromise, WsProvider } from "@polkadot/api";
import { web3FromAddress } from "@polkadot/extension-dapp";
import { BN } from "@polkadot/util";
import "./App.css";

type InjectedExtension = Awaited<ReturnType<typeof web3Enable>>[number];
type InjectedAccountWithMeta = Awaited<ReturnType<typeof web3Accounts>>[number];

const ALEPH_ZERO_TESTNET_WS_PROVIDER = new WsProvider(
  "wss://ws.test.azero.dev"
);

function App() {
  const [accounts, setAccounts] = useState<InjectedAccountWithMeta[]>([]);
  const [extensions, setExtensions] = useState<InjectedExtension[]>([]);

  useEffect(() => {
    const fetchAccounts = async () => {
      try {
        const accounts = await web3Accounts({
          extensions: ["aleph-zero-signer"],
        });
        setAccounts(accounts);
      } catch (error) {
        console.error("アカウントの取得に失敗しました:", error);
      }
    };

    fetchAccounts();
  }, [extensions]);

  const loadAccountsFromExtensions = async () => {
    // extension-dapp API: connect to extensions; returns list of injected extensions
    const injectedExtensions = await web3Enable("my cool dapp");

    setExtensions(injectedExtensions);
  };

  const makeTransfer = async () => {
    const api = await ApiPromise.create({
      provider: ALEPH_ZERO_TESTNET_WS_PROVIDER,
    });

    const [first, second] = accounts;

    const firstAddressInjector = await web3FromAddress(first.address);

    const transferAmount = new BN(50);
    const unitAdjustment = new BN(10).pow(
      new BN(api.registry.chainDecimals[0])
    );
    const finalAmount = transferAmount.mul(unitAdjustment);

    await api.tx.balances
      .transferAllowDeath(second.address, finalAmount)
      .signAndSend(first.address, { signer: firstAddressInjector.signer });
  };

  return (
    <>
      <button onClick={loadAccountsFromExtensions}>
        Connect to extensions
      </button>
      <h2>Signer accounts</h2>
      <ul>
        {accounts.map(({ address, meta: { name } }) => (
          <li key={address}>
            <strong>{name || "<unknown>"}</strong> {address}
          </li>
        ))}
      </ul>
      <hr />
      <button onClick={makeTransfer}>Make transfer</button>
    </>
  );
}

export default App;

編集後 npm run dev でアプリを起動し、以下のように表示されれば App.ts の変更が反映されています。

実装の解説

Aleph Zero Signer との接続とアカウントの取得

「Connect to extensions」ボタンをクリックすると、Aleph Zero Signer のポップアップが立ち上がり、このアプリと接続するアカウントを選択する画面が開きます。

接続するアカウントにチェックをつけて「Connect」ボタンをクリックすると、アプリの画面に戻り、選択したアカウントの名前とアドレスが表示されます。

アプリと Aleph Zero Signer の切断や、アプリに接続するアカウントの変更は、Aleph Zero Signer の Chrome 拡張アプリから Settings > Trusted Apps から行えます。

Aleph Zero Signer との接続とアカウントの読み込みは上記のコードのうち以下の部分で行っています。本質的な部分は「アカウント情報の取得」「ボタンクリック時の実装」の部分のみで、@polkadot/extension-dappweb3Enable() 関数を呼び出すだけで Aleph Zero Signer との接続が、web3Accounts({extensions: ["aleph-zero-signer"]}) 関数を呼び出すだけでアカウントを読み込むことができます。とても簡単です。
web3Enable() に渡す dApp 名には任意の文字列を指定できます。

import { web3Enable, web3Accounts, web3FromAddress } from "@polkadot/extension-dapp";
〜〜中略〜〜
type InjectedExtension = Awaited<ReturnType<typeof web3Enable>>[number];
type InjectedAccountWithMeta = Awaited<ReturnType<typeof web3Accounts>>[number];
〜〜中略〜〜
const [accounts, setAccounts] = useState<InjectedAccountWithMeta[]>([]);
const [extensions, setExtensions] = useState<InjectedExtension[]>([]);

// アカウント情報の取得
useEffect(() => {
const fetchAccounts = async () => {
  try {
    const accounts = await web3Accounts({
      extensions: ["aleph-zero-signer"],
    });
    setAccounts(accounts);
  } catch (error) {
    console.error("アカウントの取得に失敗しました:", error);
  }
};

fetchAccounts();
}, [extensions]);

// ボタンクリック時の実装
const loadAccountsFromExtensions = async () => {
  // extension-dapp API: connect to extensions; returns list of injected extensions
  const injectedExtensions = await web3Enable(my cool dapp);

  setExtensions(injectedExtensions);
};
〜〜中略〜〜
// ボタンの実装
<button onClick={loadAccountsFromExtensions}>
    Connect to extensions
</button>
// 接続中のアカウントの表示
<h2>Signer accounts</h2>
<ul>
    {accounts.map(({ address, meta: { name } }) => (
      <li key={address}>
        <strong>{name || "<unknown>"}</strong> {address}
      </li>
    ))}
</ul>

トランザクションの実行

1つ目のアカウント(赤い方)から2つ目のアカウント(青い方)に50TZERO を送るトランザクションを発行してみます。
(※もしアカウントが1つしか表示されていない場合は、Aleph Zero Signer アプリ上でもう一つアカウントを作り、設定からこのアプリへの接続を許可して、アカウントが二つ以上表示される状態にしてから以降の手順に進んでください。)

「Make transfer」ボタンをクリックすると、以下のようなポップアップが表示され、パスワードを入力して「Sign」ボタンをクリックするとトランザクションを実行することができます。

発行したトランザクションの詳細は Subscan で確認可能です。上記で実行したトランザクションはこちらになります。
https://alephzero-testnet.subscan.io/extrinsic/80266343-1

トランザクションの発行は以下の部分で行なっています。まず ApiPromise.create() で TZERO ネットワークと接続し、トランザクションの処理内容を作成後、signAndSend() でトランザクションを実行しています。

import { ApiPromise, WsProvider } from "@polkadot/api";
import { BN } from "@polkadot/util";
〜〜中略〜〜
const ALEPH_ZERO_TESTNET_WS_PROVIDER = new WsProvider(
  "wss://ws.test.azero.dev"
);
〜〜中略〜〜
const makeTransfer = async () => {
    const api = await ApiPromise.create({
      provider: ALEPH_ZERO_TESTNET_WS_PROVIDER,
    });
    
    const [first, second] = accounts;
    
    const firstAddressInjector = await web3FromAddress(first.address);
    
    const transferAmount = new BN(50);
    const unitAdjustment = new BN(10).pow(
      new BN(api.registry.chainDecimals[0])
    );
    const finalAmount = transferAmount.mul(unitAdjustment);
    
    await api.tx.balances
      .transferAllowDeath(second.address, finalAmount)
      .signAndSend(first.address, { signer: firstAddressInjector.signer });
};
〜〜中略〜〜
<button onClick={makeTransfer}>Make transfer</button>

Aleph Zero に対応した React アプリの開発方法をご紹介しました。EVM 系とは若干の違いはありつつも、polkadot のライブラリを使用することでとても手軽にアプリ開発ができることが確認できたと思います。皆様の今後の AZERO dApp 開発の一助になれば幸いです!

Discussion