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