XRP API

The XrpApp class provides XRP Ledger address retrieval and transaction signing. It supports both the Ed25519 (default) and secp256k1 elliptic curves.

Key Differences from Ethereum

Aspect Ethereum XRP
Address format 0x... (hex) r... (Base58Check)
Default curve secp256k1 Ed25519
Ed25519 public key Carries a 0xED prefix
Signature format v/r/s raw bytes (Ed25519: 64B, secp256k1: DER)
BIP44 path 44'/60'/... 44'/144'/... (Ed25519: fully hardened)

Import

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

Initialization

const xrp = new XrpApp(transport)

Methods

Method Description
getAddress(path, curve?) Get the XRP address and the public key
signTransaction(path, txBlob, curve?) Sign a serialized transaction

getAddress

Get the XRP Ledger address from the device.

async getAddress(
  path: string,
  curve?: XrpCurve
): Promise<{
  publicKey: string  // Public key (hex, Ed25519: 33B with 0xED prefix, secp256k1: 33B compressed)
  address: string    // XRP address ("r...")
}>

Parameters

Name Type Default Description
path string BIP44 path
curve XrpCurve 'ed25519' 'ed25519' or 'secp256k1'

XrpCurve Type

type XrpCurve = 'ed25519' | 'secp256k1'

Default Path

DEFAULT_XRP_PATH = "44'/144'/0'/0'/0'" (Ed25519: every element hardened)

Example

// Ed25519 (the default)
const { address, publicKey } = await xrp.getAddress(DEFAULT_XRP_PATH)
// address: "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"
// publicKey: "ed01a2b3c4..." (0xED prefix)

// secp256k1
const { address, publicKey } = await xrp.getAddress(
  "44'/144'/0'/0/0",  // secp256k1 also accepts a non-hardened path
  'secp256k1'
)

Curve Selection and P2 Values

Curve P2 value Description
'ed25519' 0x80 Ed25519 (default, recommended)
'secp256k1' 0x40 secp256k1 (Ethereum-compatible)

signTransaction

Sign a serialized XRP transaction.

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

Parameters

Name Type Description
path string BIP44 path
txBlob string Serialized transaction (hex, with or without 0x)
curve XrpCurve Curve (defaults to 'ed25519'). Following the Ledger-compatible specification, it is sent in P2 as a curveMask (secp256k1=0x40 / ed25519=0x80). Match the curve you used with getAddress

Returns: XrpSignatureResult

Field Type Description
signature string Signature as hex (Ed25519: 64 bytes, secp256k1: variable-length DER encoding)

Example

// Ed25519 (the default when omitted)
const { signature } = await xrp.signTransaction(
  DEFAULT_XRP_PATH,
  '120000228...' // serialized transaction blob
)

// secp256k1 (pass the same value you used with getAddress if you chose 'secp256k1')
const { signature: sig2 } = await xrp.signTransaction(
  DEFAULT_XRP_PATH,
  '120000228...',
  'secp256k1'
)

xrpl.js Integration

import { Client, Wallet, encode, decode } 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)

// Get the address
const { address, publicKey } = await xrp.getAddress(DEFAULT_XRP_PATH)

// Connect to the XRP Ledger
const client = new Client('wss://xrplcluster.com/')
await client.connect()

// Build the transaction
const prepared = await client.autofill({
  TransactionType: 'Payment',
  Account: address,
  Amount: '1000000', // 1 XRP = 1,000,000 drops
  Destination: 'rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe',
})

// Serialize and sign on the device
const txBlob = encode(prepared)
const { signature } = await xrp.signTransaction(DEFAULT_XRP_PATH, txBlob)

// Add the signature to the transaction
const signedTx = {
  ...prepared,
  TxnSignature: signature.toUpperCase(),
  SigningPubKey: publicKey.toUpperCase(),
}

// Broadcast
const result = await client.submitAndWait(encode(signedTx))
console.log('TX Result:', result.result.meta.TransactionResult)

await client.disconnect()

Next Steps