新着:HeliusがLight Protocolを買収
Solana Web3.js 2.0 SDKで開発を始める方法
ブログ/開発

Solana Web3.js 2.0 SDKで開発を始める方法

Developer ExperienceエンジニアXのAnam AnsariLinkedInのAnam Ansari
開発者教育XのMike MacCanaLinkedInのMike MacCana
読了時間:10分

本題に入る前に、この記事をレビューしてくださったEvanとNickに感謝します。貴重なフィードバックと知見をいただき、ありがとうございました。

はじめに

Solana Web3.js SDKは、Node.js、Web、React Nativeの各プラットフォームでSolanaアプリケーションを構築するための強力なTypeScriptおよびJavaScriptライブラリです。2024年11月7日、Anzaは待望の2.0 SDKアップデートを発表し、多数の最新JavaScript機能と改善を導入しました。主な特長には、bigintと暗号処理での標準JS型の採用やバンドルサイズの削減があり、開発者にとって重要なアップグレードとなっています。 

@solana/web3.jsを使用している場合は、ソフトウェアを新しいv2.0パッケージへ移行するか、バージョンを明示的に指定してv1.xに固定する必要があります。 

この記事では、Web3.js 2.0 SDKの最新アップデートを解説し、移行プロセスを案内するとともに、開発を始めるための例を紹介します。 

この記事では、トランザクションの送信、Solanaのアカウントモデル、ブロックハッシュ、優先手数料など、Solanaの基本概念を十分に理解し、TypeScriptまたはJavaScriptの経験があることを前提としています。以前のバージョンのWeb3.js SDKに慣れていることが望ましいですが、必須ではありません。それでは始めましょう!

Web3.js 2.0の新機能

新しいWeb3.js 2.0 SDKで利用できる機能を簡単に見ていきましょう。 

1. パフォーマンスの向上

暗号処理が高速化されました。キーペア生成、トランザクション署名、メッセージ検証は、Node.jsや最新ブラウザなどのモダンなJavaScript環境に組み込まれた暗号APIを活用することで、最大10倍高速になります。

2. より小さく効率的なアプリケーション

Web3.js 2.0は完全にtree-shaking可能なため、ライブラリで使用する部分だけを含め、バンドルサイズを最小限に抑えられます。さらに、新しいSDKには外部依存関係がなく、軽量で安全なビルドを実現できます。

3. 柔軟性の向上

開発者は、次の方法でカスタムソリューションを作成できるようになりました。

  • カスタムメソッドを備えたRPCインスタンスの定義  
  • 専用のネットワークトランスポートやトランザクション署名者の使用  
  • ネットワーク、トランザクション確認、コーデック向けカスタムプリミティブの組み合わせ  

‍オンチェーンプログラム向けの新しいTypeScriptクライアントは、@solana-program GitHub organizationでホストされています。これらのクライアントはCodamaを使用して自動生成されるため、開発者はカスタムプログラム用のクライアントをすばやく生成できます。 

Web3.js v2へ今すぐ移行すべきですか?

2025年2月時点では、次のように判断できます。

  • JS/TSで新しいSolanaアプリを作成し、システムプログラム、トークンプログラム、関連トークンプログラムなどの一般的な既存プログラムを使用する場合は、今すぐweb3.js v2を使用できます。
  • Anchorを使用してカスタムのオンチェーンアプリを作成する場合は、待つことをおすすめします。Anchorはまだweb3.js v2を標準ではサポートしていません。今後のAnchorアップデートを待つのがよいでしょう。または、少し作業は増えますが、Codamaを使用してオンチェーンアプリ用のTypeScriptクライアントを作成できます。

web3.jsバージョン1からの移行

‍web3.js v1を使用したことがある方向けに、重要な違いを簡単にまとめます。

キーペア

これまで**Keypairを使用していたすべての箇所で、今後はKeyPairSignerを使用します。Keypair.generate()はgenerateKeyPairSigner()**になりました。また、キーペアは通常のJS/TSのキャメルケースと同様に、すべての箇所でkeyPairと表記されるようになりました。

秘密鍵は**privateKeyと呼ばれるようになり、keyPairSigner.privateKeyからアクセスできます。通常、web3.js v1でsecretKeyを使用していた箇所では、web3.js v2のKeyPairSigner**を使用します。

アドレス/公開鍵

web3.js v1でPublicKeyを使用していた箇所では、web3.js v2では単にアドレスを使用します。たとえば、**KeyPairSignerには、公開鍵を表すkeypairSigner.addressプロパティがあります。文字列形式の公開鍵は、address**関数を使用してアドレスに変換できます。

SOLとトークンの数量

数量には、JSネイティブの**BigInt型を使用します。そのため、数値の末尾にnを追加し、1は1ではなく1n**と記述します。 

ファクトリ

多くの機能を設定できるため、事前定義された実装(例:doThing())の代わりに、独自の**doThing()関数を作成できるファクトリ(doThingFactory()**)が用意されています。たとえば、次のように使用します。

  • トランザクションを送信して確認するには、希望するオプションで**sendAndConfirmTransactionFactory()を一度実行し、カスタムのsendAndConfirmTransaction()関数を取得します。その後、トランザクションを送信して確認する必要があるときは、いつでもsendAndConfirmTransaction()**を使用できます。 
  • devnetまたはlocalnetでエアドロップを取得するには、**airdropFactory()を一度実行し、エアドロップが必要なときにいつでも使用できるカスタムのairdrop()**関数を取得します。

Web3.js 2.0でトランザクションを送信する方法

Web3.js 2.0を使用して、別のウォレットへlamportを転送するクライアントサイドプログラムを構築します。このプログラムでは、トランザクションの成功率を高め、確認時間を短縮する手法を紹介します。 

トランザクションの送信では、次のベストプラクティスに従います。 

  1. confirmedコミットメントレベルで最新のブロックハッシュを取得する  
  2. HeliusのPriority Fee APIが推奨する優先手数料を設定する
  3. コンピュートユニットを最適化する  
  4. maxRetriesを0、skipPreflightをtrueに設定してトランザクションを送信する  

この方法により、ネットワーク混雑時でも最適なパフォーマンスと信頼性を確保できます。 

前提条件

  • Node.jsをインストールする  
  • 対応するIDE(例:VS CodeまたはCursor)  

インストール

まず、アプリケーションの構成に使用する基本的なNode.jsプロジェクトを作成します。

次のコマンドを実行し、依存関係とプロジェクトのメタデータを管理するpackage.jsonファイルを作成します。

Shell commands
npm init -y

srcディレクトリを作成し、その中にメインコードを配置するindex.tsファイルを追加します。

Shell commands
mkdir src  
touch src/index.ts

次に、npmを使用して、SolanaのWeb3.js 2.0 SDKを操作するために必要な依存関係をインストールします。

Shell commands
npm install @solana/web3.js@2 @solana-program/system @solana-program/compute-budget esrun

各パッケージの説明は次のとおりです。

  • @solana/web3.js:Solanaトランザクションの構築と管理に不可欠なSolana Web3.js 2.0 SDKです
  • @solana-program/system:Solana System Programへのアクセスを提供し、lamport転送などの操作を可能にします
  • @solana-program/compute-budget:トランザクションの優先手数料の設定とコンピュートユニットの最適化に使用します
  • esrunは、設定やラッパー関数を使わずにコマンドラインからTypeScriptアプリを実行できるシンプルな方法です。

転送元と転送先のアドレスを定義する

index.tsで、lamportを転送するための送信元と送信先のアドレスを定義します。指定された文字列から送信先の公開鍵を生成するために、**address()**関数を使用します。

送信元については、その**secretKeyを使用してKeyPair**を導出します。

send-transaction.ts
import { address, createKeyPairSignerFromBytes, getBase58Encoder } from "@solana/web3.js";

const destinationAddress = address("public-key-to-send-lamports-to");
const secretKey = "add-your-private-key";
const sourceKeypair = await createKeyPairSignerFromBytes(getBase58Encoder().encode(secretKey));

RPC接続を設定する

次に、必要なRPC接続を設定します。**createSolanaRpc**関数は、デフォルトのHTTPトランスポートを使用してRPCサーバーとの通信を確立します。これはほとんどのユースケースで十分です。

同様に、**createSolanaRpcSubscriptionsを使用してWebSocket接続を確立します。rpc_urlとwss_url**はHelius Dashboardにあります。登録またはログインして、「Endpoints」セクションに移動するだけです。

**sendAndConfirmTransactionFactory**関数は、再利用可能なトランザクション送信機能を構築します。この送信機能には、トランザクションを送信するためのRPC接続と、トランザクションのステータスを監視するためのRPCサブスクリプションが必要です。

send-transaction.ts
import {
  // ...
  createSolanaRpcSubscriptions,
  createSolanaRpc,
  sendAndConfirmTransactionFactory,
} from "@solana/web3.js";

const rpc_url = "https://mainnet.helius-rpc.com/?api-key=<your-key>";
const wss_url = "wss://mainnet.helius-rpc.com/?api-key=<your-key>";

const rpc = createSolanaRpc(rpc_url);
const rpcSubscriptions = createSolanaRpcSubscriptions(wss_url);

const sendAndConfirmTransaction = sendAndConfirmTransactionFactory({
  rpc,
  rpcSubscriptions,
});

転送命令を作成する

直近のブロックハッシュを含めることで重複を防ぎ、トランザクションに有効期間を設定できます。すべてのトランザクションは、実行対象として受け入れられるために有効なブロックハッシュを含める必要があります。このトランザクションでは、confirmedコミットメントレベルを使用して最新のブロックハッシュを取得します。

次に、**getTransferSolInstruction()**を使用して、System Programが提供する事前定義済みの転送命令を作成します。これには、数量、送信元

、送信先の指定が必要です。送信元は常に署名者である必要があり、送信先には公開アドレスを指定します。

send-transaction.ts
import {
  // ...
  lamports,
} from "@solana/web3.js";
import { getTransferSolInstruction } from "@solana-program/system";

/**
 * STEP 1: CREATE THE TRANSFER TRANSACTION
 */
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();

const instruction = getTransferSolInstruction({
  amount: lamports(1n),
  destination: destinationAddress,
  source: sourceKeypair,
});

トランザクションメッセージを作成する

次に、トランザクションメッセージを作成します。すべてのトランザクションメッセージがバージョンを認識するようになったため、異なる型(例:TransactionとVersionedTransaction)を個別に扱う必要はありません。 

送信元を手数料支払者として設定し、ブロックハッシュを含め、lamportを転送する命令を追加します。

send-transaction.ts
import {
  // ...
  pipe,
  createTransactionMessage,
  setTransactionMessageFeePayer,
  setTransactionMessageLifetimeUsingBlockhash,
  appendTransactionMessageInstruction,
} from "@solana/web3.js";

// ...

const transactionMessage = pipe(
  createTransactionMessage({ version: 0 }),
  (message) => setTransactionMessageFeePayer(sourceKeypair.address, message),
  (message) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, message),
  (message) => appendTransactionMessageInstruction(instruction, message),
);

console.log("Transaction message created");

関数型プログラミングでよく使用されるpipe関数は、ある関数の出力を次の関数の入力にする一連の処理を作成します。ここでは、手数料支払者と有効期間の設定、命令の追加といった変換を適用し、トランザクションメッセージを段階的に構築します。

トランザクションメッセージを初期化する:

**createTransactionMessage({ version: 0 })**は、基本的なトランザクションメッセージから処理を開始します。

手数料支払者を設定する:

**message => setTransactionMessageFeePayer(fromKeypair.address, message)**は、手数料支払者のアドレスを追加します。

ブロックハッシュを使用して有効期間を設定する

**message => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, message)**は、最新のブロックハッシュを使用して、トランザクションが一定期間内で有効になるようにします。

転送命令を追加する

**message => appendTransactionMessageInstruction(instruction, message)**は、アクション(例:lamportの転送)をメッセージに追加します。

各アロー関数**message => (...)**はメッセージを変更し、更新されたメッセージを次のステップへ渡します。これにより、完全に構築された新しいトランザクションメッセージが生成されます。

トランザクションに署名する

指定した署名者である送信元の**Keypair**を使用して、トランザクションに署名します。

send-transaction.ts
import {
  // ...
  signTransactionMessageWithSigners,
} from "@solana/web3.js";
// ...

/**
 * STEP 2: SIGN THE TRANSACTION
 */
const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
console.log("Transaction signed");

優先手数料を見積もる

この段階で、トランザクションの送信と確認に進めます。ただし、優先手数料を設定し、コンピュートユニットを調整してトランザクションを最適化する必要があります。これらの最適化により、特にネットワーク混雑時にトランザクションの成功率を高め、確認時間を短縮できます。

優先手数料の設定には、HeliusのPriority Fee APIを使用します。これにはBase64形式でシリアライズされたトランザクションが必要です。APIはBase58エンコーディングにも対応していますが、現在のSDKではトランザクションをBase64形式で直接取得できるため、処理が簡単になります。

send-transaction.ts
import {
  // ...
  getBase64EncodedWireTransaction,
} from "@solana/web3.js";

/**
 * STEP 3: GET PRIORITY FEE FROM SIGNED TRANSACTION
 */

const base64EncodedWireTransaction = getBase64EncodedWireTransaction(signedTransaction);

const response = await fetch(rpc_url, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: "helius-example",
    method: "getPriorityFeeEstimate",
    params: [
      {
        transaction: base64EncodedWireTransaction,
        options: {
          transactionEncoding: "base64",
          priorityLevel: "High",
        },
      },
    ],
  }),
});
const { result } = await response.json();
const priorityFee = result.priorityFeeEstimate;
console.log("Setting priority fee to ", priorityFee);

通常は、priorityLevelをHighに設定すれば十分です。ただし、シリアライズされたトランザクションやアカウントキーを使用するような高度な優先手数料戦略を実装すると、ネットワーク混雑時のトランザクション成功率を大幅に高められます。

コンピュートユニットを最適化する

次に、トランザクションメッセージが実際に消費するコンピュートユニットを見積もります。

その後、この値に1.1を掛けて10%のバッファを追加します。このバッファは、優先手数料や、後ほど組み込む追加のコンピュートユニット命令で使用されるコンピュートユニットを考慮したものです。 

lamportの転送など、一部の命令ではコンピュートユニットの見積もりが低くなる場合があります。十分なリソースを確保するため、見積もりがこのしきい値を下回る場合は、コンピュートユニットを最低1000に設定する保護措置を追加しています。

send-transaction.ts
import {
  // ...
  getComputeUnitEstimateForTransactionMessageFactory,
} from "@solana/web3.js";

/**
 * STEP 4: OPTIMIZE COMPUTE UNITS
 */
const getComputeUnitEstimateForTransactionMessage = getComputeUnitEstimateForTransactionMessageFactory({
  rpc,
});
// Request an estimate of the actual compute units this message will consume.
let computeUnitsEstimate = await getComputeUnitEstimateForTransactionMessage(transactionMessage);
computeUnitsEstimate = computeUnitsEstimate < 1000 ? 1000 : Math.ceil(computeUnitsEstimate * 1.1);
console.log("Setting compute units to ", computeUnitsEstimate);

トランザクションを再構築して署名する

このトランザクションに必要な優先手数料とコンピュートユニットが揃いました。トランザクションにはすでに署名済みのため、新しい命令を直接追加することはできません。代わりに、新しいブロックハッシュを使用してトランザクションメッセージ全体を再構築します。 

ブロックハッシュの有効期間は約1〜2分しかなく、優先手数料とコンピュートユニットの取得には時間がかかります。トランザクションの送信中にブロックハッシュが期限切れになるリスクを避けるには、トランザクションの再構築時に新しいブロックハッシュを取得する方が安全です。

再構築するトランザクションには、次の2つの命令を追加します。 

  1. 優先手数料を設定する命令
  2. コンピュートユニットを設定する命令 

最後に、更新したトランザクションに署名し、送信の準備を整えます。

send-transaction.ts
import {
  // ...
  appendTransactionMessageInstructions,
} from "@solana/web3.js";
import { getSetComputeUnitLimitInstruction, getSetComputeUnitPriceInstruction } from "@solana-program/compute-budget";

/**
 * STEP 5: REBUILD AND SIGN FINAL TRANSACTION
 */
const { value: finalLatestBlockhash } = await rpc.getLatestBlockhash().send();

const finalTransactionMessage = appendTransactionMessageInstructions(
  [
    getSetComputeUnitPriceInstruction({ microLamports: priorityFee }),
    getSetComputeUnitLimitInstruction({ units: computeUnitsEstimate }),
  ],
  transactionMessage,
);

setTransactionMessageLifetimeUsingBlockhash(finalLatestBlockhash, finalTransactionMessage);

const finalSignedTransaction = await signTransactionMessageWithSigners(finalTransactionMessage);
console.log("Rebuilt the transaction and signed it");

トランザクションを送信して確認する

次に、**sendAndConfirmTransaction**関数を使用して、署名済みトランザクションを送信し、確認します。

コミットメントレベルは、先ほど取得したブロックハッシュと同じconfirmedに設定し、**maxRetriesは0**に設定します。skipPreflightオプションはtrueに設定し、実行を高速化するためにプリフライトチェックを省略します。ただし、これはトランザクション署名が検証済みで、ほかにエラーがないと確信できる場合にのみ使用してください。

**sendAndConfirmTransaction**は、RPCとRPCサブスクリプションの両方のURLを指定して先ほど作成したものです。RPCサブスクリプションURLを使用するとトランザクションのステータスが確認されるため、手動でポーリングする必要がなくなります。

エラー処理セクションでは、プリフライトチェック中に発生したエラーをコードで確認します。**skipPreflightをtrue**に設定しているため、この確認は不要です。ただし、trueに設定しない場合には役立ちます。

send-transaction.ts
import {
  getSignatureFromTransaction,
  isSolanaError,
  SOLANA_ERROR__JSON_RPC__SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE,
} from "@solana/web3.js";
import { getSystemErrorMessage, isSystemError } from "@solana-program/system";

/**
 * STEP 6: SEND AND CONFIRM THE FINAL TRANSACTION
 */

console.log("Sending and confirming transaction");
await sendAndConfirmTransaction(finalSignedTransaction, {
  commitment: "confirmed",
  maxRetries: 0n,
  skipPreflight: true,
});
console.log("Transfer confirmed: ", getSignatureFromTransaction(finalSignedTransaction));

コードを実行する

最後に、コードを実行します。 npx esrun send-transaction.ts

まとめ

SolanaのWeb3.js 2.0 SDKのリリースは、Solana上でより高速かつ効率的で、スケーラブルなアプリケーションを開発できるようにする画期的なアップデートです。最新のJavaScript標準を採用し、ネイティブ暗号API、tree-shaking、自動生成されるTypeScriptクライアントなどの機能を導入したことで、SDKは開発者体験とアプリケーションのパフォーマンスを大幅に向上させます。

プログラミング例の完全なコードはGitHubで確認できます。

ここまでお読みいただき、ありがとうございます!下にメールアドレスを入力して、Solanaの最新情報を見逃さないようにしましょう。さらに詳しく知りたいですか?Heliusブログで最新の記事を読み、今日からSolanaの学習をさらに進めましょう。

参考資料

Heliusを購読

Solana開発の最新情報や新しい記事の公開通知を受け取れます

拡大画像