
Solana Dev 101 - Solanaでのアカウントデータのデシリアライズ
はじめに
Solana上のデータを扱うのは簡単ではありません。アカウントやトランザクションのデータは、多くの場合エンコードされています。これは効率面では優れていますが、開発者にとっては扱いにくいものです。
Solanaはデータのシリアライズに、シリアライズとデシリアライズの両方の処理を含むBorsh(Binary Object Representation Serializer for Hashing)を使用します。Borshの主な利点の1つは決定性です。同じ入力に対して一貫したシリアライズ結果を保証します。
このチュートリアルでは、トークンアカウントのデータをデシリアライズし、利用可能な読みやすいデータとして返す方法を解説します。Token Programライブラリを使用し、NFTのmint addressから生のアカウント情報を分解する簡単な例を扱います。
以下は、生のアカウントデータをより読みやすい形式に変換する例です。
このチュートリアルの完全なコードは、deserialize-accountリポジトリをこちらからクローンして確認できます。
前提条件
このチュートリアルの前提条件は次のとおりです。
環境のセットアップ
サンプルリポジトリをクローンします。
git clone https://github.com/helius-labs/deserialize-base.gitプロジェクトディレクトリに移動します。
cd deserialize-basenpmをインストールします。
npm installこれでプロジェクトのセットアップは完了です。
ここから、指定したmint addressのアカウントデータをデシリアライズする処理を実装していきます。
実装手順
以下の手順に従ってください。
1. アカウントデータを取得する
/src/deserialize.tsファイルで、必要なモジュールをインポートします。
import { Connection, PublicKey } from "@solana/web3.js";これは後ほどSolanaへの接続と、データをデシリアライズするmintのPublicKeyを定義するために使用します。
この下にメイン関数を設定します。
Helius RPC URLを使用してSolanaへの接続を設定し、このチュートリアルでデシリアライズするmintを指定します。
async function deserializeMint() {
// CONNECTION TO SOLANA USING HELIUS
const rpc = 'https://rpc.helius.xyz/?api-key=';
const connection = new Connection(rpc);
// MINT THAT WE ARE DESERIALIZING
const mint = new PublicKey('6MWfAt3S9Xu4ybxxgPm6e4LSwuXfyAwGXd5yfUqpox9K');
}
deserializeMint()上記のapi-keyを、ご自身のHelius APIキーに置き換えてください。また、このチュートリアルで使用するmintを任意の例に置き換えることもできます。
次に、try/catchを設定し、このmintの生のアカウントデータを取得します。
try {
let { data } = (await connection.getAccountInfo(mint)) || {};
if (!data) {
return;
}
console.log(data);
} catch {
return null;
}上記の手順では、接続を使用してSolana上でgetAccountInfoへのRPC呼び出しを行っています。これにより、さらに分解するために必要な初期データが返されます。
データが見つからない場合はnullが返されます。それ以外の場合は、検索結果がターミナルに出力されます。
ts-node deserializeを実行して結果を確認できます。
次のような結果が表示されます。
ここでデシリアライズする目的は、このデータを読みやすい形式に変換することです。
そのためには、このデータを作成したプログラムが想定するレイアウトをソースコードで確認する必要があります。
2. アカウントの型を設定する
この例では、SPL mint 6MWfAt3S9Xu4ybxxgPm6e4LSwuXfyAwGXd5yfUqpox9KのAccountInfoを取得します。
そのためには、Solana Program Libraryに記載されている生のmintデータの型とバッファレイアウトを分解する必要があります。データの構造を理解することは、Solana上のあらゆるデータをデシリアライズするうえで重要な手順です。
上の画像には、プログラムで定義されたRawMint構造体とMintLayoutが示されています。これらを型ファイルにコピーして使用できます。
次に、./src/typesディレクトリに移動します。
/src/types.tsファイルで、型のインポートを設定します。
import { PublicKey } from "@solana/web3.js";
import { u32, u8, struct } from "@solana/buffer-layout";
import { publicKey, u64, bool } from "@solana/buffer-layout-utils";これにより、この例のNFTのアカウントデータをデシリアライズするために必要な、生のmintの形式とレイアウトが定義されます。
次に、上記と同様にインターフェースとレイアウトを設定します。
インポートしたPublicKey、u32、u8、publicKey、u64、boolを使用します。
// Defining RawMint from https://github.com/solana-labs/solana-program-library/blob/48fbb5b7c49ea35848442bba470b89331dea2b2b/token/js/src/state/mint.ts#L31 //
export interface RawMint {
mintAuthorityOption: 1 | 0;
mintAuthority: PublicKey;
supply: bigint;
decimals: number;
isInitialized: boolean;
freezeAuthorityOption: 1 | 0;
freezeAuthority: PublicKey;
}
// Defining Buffer Layout from https://github.com/solana-labs/solana-program-library/blob/48fbb5b7c49ea35848442bba470b89331dea2b2b/token/js/src/state/mint.ts#L31 //
/** Buffer layout for de/serializing a mint */
export const MintLayout = struct([
u32('mintAuthorityOption'),
publicKey('mintAuthority'),
u64('supply'),
u8('decimals'),
bool('isInitialized'),
u32('freezeAuthorityOption'),
publicKey('freezeAuthority'),
]);これで、生のアカウント情報の型を設定できました。これをメインのdeserialize.tsファイルにインポートし、先ほど返されたデータのデシリアライズに使用できます。
MintLayoutでは、RawMintが構造体として定義されています。これは基本的に、設定したインターフェースにGitHubのソースで定義されたレイアウトの型を付けるものです。
3. 返されたデータをデシリアライズする
想定されるデータの構造を理解できたので、わずか1行のコードでdecode関数を設定できます。src/deserialize.tsファイルに戻って設定します。
まず、メインのdeserialize.tsファイルで、types.tsファイルからMintLayoutをインポートします。
import { MintLayout } from "./types";次に、アカウントデータを取得している箇所のすぐ下に、デシリアライズ関数のコードを1行追加します。
const deserialize = MintLayout.decode(data)
console.log(deserialize)ここではMintLayoutを使用して、deserializeMint関数から返されたデータをデコードしています。
./srcフォルダからts-node deserializeを実行すると、次のような結果が得られます。
{
mintAuthorityOption: 1,
mintAuthority: PublicKey [PublicKey(5WQAPQ8i8wqHcSWSEkBQ9kqfwRJxxgyZqAtKiwJSW5zT)] {
_bn:
},
supply: 1n,
decimals: 0,
isInitialized: true,
freezeAuthorityOption: 1,
freezeAuthority: PublicKey [PublicKey(5WQAPQ8i8wqHcSWSEkBQ9kqfwRJxxgyZqAtKiwJSW5zT)] {
_bn:
}
}かなり読みやすくなりました。次の手順でレスポンスを型ごとに分解すると、さらに整理できます。
最後に、レスポンスを上記の形式に調整して、データをさらに整えることができます。次のように実装します。
// Breaking down the response //
console.log(deserialize.mintAuthorityOption)
console.log(deserialize.mintAuthority.toString())
console.log(deserialize.decimals)
console.log(deserialize.isInitialized)
console.log(deserialize.freezeAuthorityOption)
console.log(deserialize.freezeAuthority.toString())上記のコードでは、返されたPublicKeysをtoString形式に変換するだけです。それ以外のデータは、受け取った形式のまま返せます。データ形式はあらかじめ分かっているため、事前に設定することもできます。その場合、次の結果が返されます。
1
5WQAPQ8i8wqHcSWSEkBQ9kqfwRJxxgyZqAtKiwJSW5zT
0
true
1このデータは必要に応じて自由に調整できます。
これは単に、結果を読みやすい形式に分解しているだけです。
完全なコード:
deserialize.tsの完全なコードを以下に示します。
import { Connection, PublicKey } from "@solana/web3.js";
import { RawMint, MintLayout } from "./types";
async function deserializeMint() {
const rpc =
"https://rpc.helius.xyz/?api-key=";
const connection = new Connection(rpc);
const mint = new PublicKey("6MWfAt3S9Xu4ybxxgPm6e4LSwuXfyAwGXd5yfUqpox9K");
try {
let { data } = (await connection.getAccountInfo(mint)) || {};
if (!data) {
return;
}
// Data returned.
console.log(data);
// Deserialize Data.
const deserialize = MintLayout.decode(data)
// Breaking down the response //
console.log(deserialize.mintAuthorityOption)
console.log(deserialize.mintAuthority.toString())
console.log(deserialize.decimals)
console.log(deserialize.isInitialized)
console.log(deserialize.freezeAuthorityOption)
console.log(deserialize.freezeAuthority.toString)
} catch {
return null;
}
}
deserializeMint();まとめ
これで、Solana上のNFTアカウントデータをデシリアライズできました。同じ手法をほかのユースケースにも適用できます。また、同様の調査方法を使用して、対象データを扱うプログラムの構造を特定できます。
デシリアライズするデータを生成したプログラムのソースを必ず確認し、ここで紹介した手法を応用して実装してみてください。
リソース
関連記事
Heliusを購読
Solana開発の最新情報や新しい記事の公開通知を受け取れます


