XRP API

XrpApp クラスは、XRP Ledger のアドレス取得とトランザクション署名を提供します。Ed25519(デフォルト)と secp256k1 の両方の楕円曲線をサポートしています。

XrpApp が提供するのは、この 2 つのメソッドだけです。トランザクションの組み立て(Payment や TrustSet などの種類ごとのシリアライズ)は含まれません。組み立てには xrpl.js などを使い、できあがった署名前のトランザクションをデバイスに渡します。

Ethereum との主な違い

項目 Ethereum XRP
アドレス形式 0x... (hex) r... (Base58Check)
デフォルト曲線 secp256k1 Ed25519
Ed25519 公開鍵 — 0xED プレフィックス付き
署名フォーマット v/r/s raw bytes (Ed25519: 64B, secp256k1: DER)
BIP44 パス 44'/60'/... 44'/144'/...(Ed25519: 全ハードニング)

インポート

import {
  XrpApp,
  DEFAULT_XRP_PATH,
  type XrpSignatureResult,
  type XrpCurve,
} from '@openloop/sdk-core'

初期化

const xrp = new XrpApp(transport)

どちらのメソッドも、実行中は transport.lock() でデバイスを占有し、終わると(失敗したときも)transport.unlock() で解放します。

メソッド一覧

メソッド 説明
getAddress(path, curve?) XRP アドレスと公開鍵を取得
signTransaction(path, txBlob, curve?) シリアライズ済みトランザクションに署名

getAddress

デバイスから XRP Ledger アドレスを取得します。

async getAddress(
  path: string,
  curve?: XrpCurve
): Promise<{
  publicKey: string  // 公開鍵 (hex, Ed25519: 33B with 0xED prefix, secp256k1: 33B compressed)
  address: string    // XRP アドレス ("r...")
}>

パラメータ

名前 型 デフォルト 説明
path string — BIP44 パス
curve XrpCurve 'ed25519' 'ed25519' or 'secp256k1'

XrpCurve 型

type XrpCurve = 'ed25519' | 'secp256k1'

デフォルトパス

DEFAULT_XRP_PATH = "44'/144'/0'/0'/0'"(Ed25519: 全要素ハードニング)

使用例

// Ed25519(デフォルト)
const { address, publicKey } = await xrp.getAddress(DEFAULT_XRP_PATH)
// address: "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"
// publicKey: "ed01a2b3c4..." (0xED prefix)

// secp256k1
const { address: addr2, publicKey: pub2 } = await xrp.getAddress(
  "44'/144'/0'/0/0",  // secp256k1 は非ハードニングパスも可
  'secp256k1'
)

曲線選択と P2 値

曲線 P2 値 説明
'ed25519' 0x80 Ed25519(デフォルト、推奨)
'secp256k1' 0x40 secp256k1(Ethereum 互換)

APDU は CLA 0xE0 / INS 0x02 / P1 0x00 で、データ部は BIP32 パスです。応答は 公開鍵の長さ(1B) + 公開鍵 + アドレスの長さ(1B) + アドレス(ASCII) の形で、SDK がこれを分解して返します。


signTransaction

シリアライズ済みの XRP トランザクションに署名します。

async signTransaction(
  path: string,
  txBlob: string,
  curve?: XrpCurve
): Promise<XrpSignatureResult>

パラメータ

名前 型 説明
path string BIP44 パス
txBlob string シリアライズ済みトランザクション (hex, 0x あり/なし)
curve XrpCurve 曲線(省略時は 'ed25519')。Ledger 互換仕様に従い P2 に curveMask(secp256k1=0x40 / ed25519=0x80)として送出。getAddress で取得した曲線と一致させる

txBlob に渡すもの

blob は 255 バイトを超えても渡せます。SDK が自動で複数の APDU に分割します(先頭は P1 0x80、途中は P1 0x81、最後は P1 0x01。1 つに収まるときは P1 0x00)。

返り値: XrpSignatureResult

フィールド 型 説明
signature string 署名の hex(Ed25519: 64 bytes, secp256k1: DER エンコード可変長)

使用例

// Ed25519 (省略時のデフォルト)
const { signature } = await xrp.signTransaction(
  DEFAULT_XRP_PATH,
  '120000228...' // 署名前のトランザクション blob(SigningPubKey を含む)
)

// secp256k1(getAddress で 'secp256k1' を取った場合は同じ値を渡す)
const { signature: sig2 } = await xrp.signTransaction(
  "44'/144'/0'/0/0",
  '120000228...',
  'secp256k1'
)

エラー

署名の拒否や使用中は ApduError(0x6985)、通信の失敗は TransportError で届きます。詳細はエラー処理を参照してください。署名を伴う呼び出しなので、timeout や disconnected のあとで自動的に送り直さないでください。

XrpApp は WalletConnect では使えません(XRP は WalletConnect 非対応です)。


署名の検証

デバイスが返した署名は、@openloop/sdk-core/verify の verifyXrpTransaction で、デバイスの外から検証できます。

import { verifyXrpTransaction } from '@openloop/sdk-core/verify'

const { publicKey } = await xrp.getAddress(DEFAULT_XRP_PATH)
const result = await xrp.signTransaction(DEFAULT_XRP_PATH, txBlob)

// txBlob は signTransaction に渡したものと同じ(前置きなし)
const check = verifyXrpTransaction(txBlob, 'ed25519', result, publicKey)
console.log(check.ok) // true なら署名は publicKey のもの

verifyXrpTransaction(txBlobHex, curve, result, pubkeyHex) は { recovered: string; expected?: string; ok: boolean } を返します。署名済みのトランザクション全体から検証するときは verifyXrpSignedTx(signedTxHex) を使います(SigningPubKey と TxnSignature を取り出すので、公開鍵の指定は要りません)。


xrpl.js 連携

import { Client, encode } from 'xrpl'
import { XrpApp, DEFAULT_XRP_PATH } from '@openloop/sdk-core'
import { WebHidTransport } from '@openloop/transport-webhid'

const transport = await WebHidTransport.connect()
const xrp = new XrpApp(transport)

// アドレス取得
const { address, publicKey } = await xrp.getAddress(DEFAULT_XRP_PATH)

// XRP Ledger に接続
const client = new Client('wss://xrplcluster.com/')
await client.connect()

// トランザクション作成
const prepared = await client.autofill({
  TransactionType: 'Payment',
  Account: address,
  Amount: '1000000', // 1 XRP = 1,000,000 drops
  Destination: 'rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe',
})

// SigningPubKey を入れてシリアライズし、デバイスで署名
const unsigned = { ...prepared, SigningPubKey: publicKey.toUpperCase() }
const txBlob = encode(unsigned)
const { signature } = await xrp.signTransaction(DEFAULT_XRP_PATH, txBlob)

// 署名をトランザクションに追加
const signedTx = {
  ...unsigned,
  TxnSignature: signature.toUpperCase(),
}

// ブロードキャスト
const result = await client.submitAndWait(encode(signedTx))
console.log('TX Result:', result.result.meta)

await client.disconnect()

次のステップ