👻

【XRPL運用ベストプラクティス】トランザクション送信における責務分離の実装指針

に公開

はじめに

こんにちは!一般社団法人XRPL Japan 理事をしている増田(通称:ぽこ太郎)です。

XRPL を使った DApp の本番運用においては、ウォレットとトランザクション送信処理の 責務を整理 することが重要です。
この記事では、その設計ポイントをわかりやすく整理してお伝えいたします!

ウォレットSDKの責務は分けるべきか?

トランザクション送信において、ウォレットの SDK にどこまでの責務を持たせるべきかは、本番環境での運用設計において重要な論点です。
ここでは、 送信処理をウォレットSDKに集約した場合の影響 を整理しつつ、代表的なウォレットである GemWallet を例に考察していきます。

https://gemwallet.app/

トランザクション送信における責務の整理

ウォレットSDKに送信処理を一任すると、UI層にロジックが集中し、 保守や拡張、SDKのバージョン対応 などが難しくなりがちです。

No 責務 役割
1 トランザクションの作成 トランザクションに応じたパラメータ生成
2 署名処理 トランザクションへの署名
3 トランザクションの送信 ネットワークへブロードキャスト
4 結果取得と処理 成否判定やエラー時のリカバリ

責務の分け方と設計の考え方

ウォレット SDK の責務を適切に分離するには、トランザクション送信のライフサイクルを次の 3 つのレイヤーに分けて考えると整理しやすくなります。

1. トランザクションの作成レイヤ

このレイヤーでは、型定義やバリデーションの方針が重要です。
長期運用を見据え、拡張性や柔軟性とのバランスを意識しましょう。

実装方法

区分 方法 メリット 注意点
独自実装した型定義を使用 柔軟性と型安全性に優れ、長期運用に強い 初期コストは高め
xrpl.js を使用 最新の仕様に追随しやすく、広く使われている 更新や破壊的変更に注意が必要
ウォレットSDK を使用 実装が簡易で取り組みやすい 柔軟性と拡張性は限定される

💡 個人的には、保守性と拡張性のバランスが良いため 竹(xrpl.js の型定義を直接使用) を選択します。

サンプルコード

import { signTransaction, getAddress } from '@gemwallet/api'
import type { SubmittableTransaction } from 'xrpl' // ここで xrpl.js を使用

async function sendTrustSetTransaction() {
  const res = await getAddress()

  // xrpl.jsの型定義を使用
  const transaction: SubmittableTransaction = {
    TransactionType: 'TrustSet',
    Account: res.result.address,
    LimitAmount: {
      currency: 'ABC',
      issuer: 'rLQ23456789012345678901234567890123456789',
      value: '100'
    },
  }
}

2. 署名レイヤ

このレイヤーの主な役割は、ユーザーの秘密鍵を使って安全に署名を行うことです。
SDKを使いつつ、 マルチウォレット対応を見据えた構成 がポイントです。

実装方法

区分 方法 メリット 注意点
- ウォレットSDK を使用 実装は非常に簡易 マルチウォレット対応で複雑化しやすい

💡 マルチウォレットに対応する場合は、ウォレット種別ごとにファクトリーを用いて適切な SDK 実装を生成する構成を取ると、実装の切り替えや拡張がスムーズになります。

サンプルコード

import { signTransaction, getAddress } from '@gemwallet/api'  // ここで ウォレットSDK を使用
import type { SubmittableTransaction } from 'xrpl'

async function sendTrustSetTransaction() {
  const res = await getAddress()

  const transaction: SubmittableTransaction = {
    TransactionType: 'TrustSet',
    Account: res.result.address,
    LimitAmount: {
      currency: 'ABC',
      issuer: 'rLQ23456789012345678901234567890123456789',
      value: '100'
    },
  }

  // ウォレットSDKを使用して署名
  const response = await signTransaction({ transaction })
  const txBlob = response?.result?.signature

  console.log('txBlob: ', txBlob)
}

3. 送信・監視レイヤ

ここでは、署名済みトランザクションの送信と結果の取得・監視を行います。

実装方法

区分 方法 メリット 注意点
Backend API 経由で送信 セキュリティ・可観測性が高い サーバーインフラの構築と保守、実装コストが大きい
フロントエンドから WSS 経由で直接送信 レイテンシが低く、UXに優れている 接続管理やセキュリティ要件を別途設計する必要がある
ウォレットSDK を使用 実装が簡易で取り組みやすい 柔軟性と拡張性は限定される

💡 私は「松」派です。
バックエンドAPI経由の送信がセキュリティと可観測性が高く、TypeScriptベースのモノリシック構成にすることで保守性も高くなります。

サンプルコード

// バックエンド(NextJS)で、トランザクションを送信
const response = await fetch(XRPL_API_URL, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    method: 'submit',
    params: [
      {
        tx_blob: txBlob
      }
    ]
  })
})

const json = await response.json()
const result = json.result

console.log('result: ', result)

まとめ

ウォレット SDK に送信処理をすべて任せる設計は、一見シンプルですが、保守や拡張の面で課題が多くなりがちです。
そのため、本記事では処理を「リクエスト作成」「署名」「送信・監視」の3つのレイヤーに分け、それぞれの責務に応じた最適な実装方法を整理しました。

  • 責務を明確に分離することで、保守性・拡張性・セキュリティ・可観測性を高められる
  • 各レイヤーの実装方針は、開発体制やプロダクトのフェーズに応じて柔軟に選択するのが重要

最後に...

今後、Web3やブロックチェーンがチェーンの壁を越えてつながっていく世界の中で、XRPLがどんな可能性を広げていくのか、ぜひ一緒にワクワクしながら追いかけていきましょう!

最後まで読んでいただき、ありがとうございました!

GitHubで編集を提案

Discussion