9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

本記事では、React Native(Expo環境)でSymbol-SDK(nemnesia版)を利用し、ニーモニック生成・アカウント生成・トランザクション生成までを一通り体験できるサンプル構成を紹介します。

Expo環境のセットアップ

まずは新規プロジェクトを作成します。

npx create-expo-app@latest symbol-expo-sample --template blank-typescript
cd symbol-expo-sample

Web対応も追加しておきましょう。

npx expo install react-dom react-native-web @expo/metro-runtime

プロジェクトの起動・動作確認は以下のコマンドで行います。

npx expo start --tunnel

スマートフォンやブラウザで表示できることを確認してください。

Android:

iOS:

Symbol-SDK(nemnesia版)のインストール

Symbol-SDKをピュアJS化した @nemnesia/symbol-sdk を利用します。
また、crypto.getRandomValuesのネイティブ対応のため react-native-get-random-values もインストールします。

npm i @nemnesia/symbol-sdk
npx expo install react-native-get-random-values

初期化コードの追加

index.tsreact-native-get-random-values のインポートを追加してください。

index.ts
import 'react-native-get-random-values';
import { registerRootComponent } from 'expo';

import App from './App';

// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in Expo Go or in a native build,
// the environment is set up appropriately
registerRootComponent(App);

サンプルコード(App.tsx)

以下のサンプルでは、ニーモニック生成・アカウント生成・トランザクション生成を行い、画面にアドレス・公開鍵・トランザクションペイロードを表示します。

App.tsx
import { StatusBar } from "expo-status-bar";
import { useEffect, useState } from "react";
import { StyleSheet, Text, View } from "react-native";
import { Bip32 } from "@nemnesia/symbol-sdk";
import {
  descriptors,
  generateMosaicAliasId,
  models,
  Network,
  SymbolAccount,
  SymbolFacade,
  SymbolTransactionFactory,
} from "@nemnesia/symbol-sdk/symbol";

export default function App() {
  const [address, setAddress] = useState("");
  const [publicKey, setPublicKey] = useState("");
  const [txPayload, setTxPayload] = useState("");

  useEffect(() => {
    // facade生成
    const facade = new SymbolFacade(Network.TESTNET);

    const genAccount = (id: number): SymbolAccount => {
      const bip32Path = facade.bip32Path(id); // Bip32Path生成
      const childBip32Node = bip32Node.derivePath(bip32Path); // Bip32Pathから子Bip32Path生成
      const keyPair = SymbolFacade.bip32NodeToKeyPair(childBip32Node); // 子Bip32Pathからキーペア生成
      const account = new SymbolAccount(facade, keyPair); // キーペアからアカウント生成
      console.log(`Account PrivateKey: ${account.keyPair.privateKey.toString()}`);
      console.log(`Account PublicKey : ${account.publicKey.toString()}`);
      console.log(`Account Address   : ${account.address.toString()}`);
      return account;
    };

    // ニーモニック生成
    const bip32 = new Bip32();
    const mnemonic = bip32.random();
    console.log("Mnemonic:", mnemonic);
    // Bip32Node生成
    const passwd = "";
    const bip32Node = bip32.fromMnemonic(mnemonic, passwd);
    // アカウントを生成する
    const account = genAccount(0);
    setAddress(account.address.toString());
    setPublicKey(account.publicKey.toString());

    // _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    // _/ トランザクション生成
    // _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

    // 受信者アカウント生成
    const recipientAccount = genAccount(1);

    // 転送モザイク設定(ネームスペースからモザイクIDを解決)
    const mosaicId = generateMosaicAliasId("symbol.xym");
    const mosaics = [
      new descriptors.UnresolvedMosaicDescriptor(
        new models.UnresolvedMosaicId(mosaicId),
        new models.Amount(10_000000n)
      ),
    ];
    // 平文メッセージ
    const message = new TextEncoder().encode("\0Hello, Symbol!!");
    // 転送トランザクションディスクリプタ生成
    const transferTxDescriptor =
      new descriptors.TransferTransactionV1Descriptor(
        recipientAccount.address, // 受信者アドレス
        mosaics, // 転送モザイク
        message // メッセージ
      );
    // 転送トランザクション生成
    const transferTx = facade.createTransactionFromTypedDescriptor(
      transferTxDescriptor, // トランザクションディスクリプタ
      account.publicKey, // 送信者公開鍵
      100, // 手数料係数
      60 * 60 * 2 // 有効期限(秒)
    );
    // 署名
    const sig = account.signTransaction(transferTx);
    const payloadJsonString = SymbolTransactionFactory.attachSignature(
      transferTx,
      sig
    );
    setTxPayload(JSON.parse(payloadJsonString).payload);
    console.log("TxPayload:", JSON.stringify(transferTx.toJson(), null, 2));
  }, []);

  return (
    <View style={styles.container}>
      <Text style={styles.label}>Address:</Text>
      <Text style={styles.value}>{address}</Text>
      <Text style={styles.label}>PublicKey:</Text>
      <Text style={styles.value}>{publicKey}</Text>
      <Text style={styles.label}>TxPayload:</Text>
      <Text style={styles.value}>{txPayload}</Text>
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "flex-start",
    justifyContent: "flex-start",
    padding: 16,
  },
  label: {
    fontWeight: "bold",
    marginTop: 8,
  },
  value: {
    width: "100%",
    flexWrap: "wrap",
    color: "#333",
    marginBottom: 4,
  },
});

実行・確認

npx expo start --tunnel

アプリ画面に「アドレス」「公開鍵」「TxPayload(トランザクションペイロード)」が表示されていれば成功です。

まとめ

本記事では、Expo環境でSymbol-SDK(nemnesia版)を使用する方法を紹介しました。ピュアJS版のSDKを使用することで、React Nativeアプリでも問題なくSymbolブロックチェーンの機能を利用できます。

ご不明点や追加の解説が必要な場合は、コメントでお気軽にご質問ください。

9
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?