Skip to content

Ledger Adapter ​

Ledger connects to the hardware device through WebHID or WebUSB. Transaction approval happens on the device; private keys do not leave it.

IntegrationValue
Package@xrpl-wallet-kit/adapter-ledger
Adapter IDledger
Wallet typeHardware wallet
Client registrationIncluded on XRPL; explicit opt-in on Xahau

Installation ​

sh
npm install @xrpl-wallet-kit/core @xrpl-wallet-kit/adapter-ledger xrpl@^4

For the Client tab below, install @xrpl-wallet-kit/client instead. Use a browser with WebHID or WebUSB, connect/unlock the device and install the chain's device app.

Connect ​

ts
import { createWalletKit } from "@xrpl-wallet-kit/client";

const kit = createWalletKit({ network: "mainnet", wallets: ["ledger"] });
const { manager } = kit;
const { account } = await kit.connect("ledger");
ts
import { WalletManager } from "@xrpl-wallet-kit/core";
import { createLedgerAdapter } from "@xrpl-wallet-kit/adapter-ledger";

const manager = new WalletManager({
  network: "mainnet",
  adapters: [createLedgerAdapter({ accountIndex: 0 })],
});
const { account } = await manager.connect("ledger");

Start connection from a user action and select the device in the browser picker. With autoOpenApp, Kit requests the chain's app on the hardware and reads the address/public key once it is ready. It does not launch Ledger Live desktop or approve transactions for the user.

Networks ​

XRPL uses the XRP device app. Xahau uses the XAH device app and is opt-in: configure network: "xahau-mainnet" or "xahau-testnet", include "ledger" explicitly in wallets, and set a positive preflight.maxFeeDrops with the full client. Core/selective integrations must register the protocol and chain filter. See Xahau Configuration.

Connection success does not establish support for every transaction type or field. Keep the device app up to date and do not enable blind signing to bypass unsupported fields.

Capabilities ​

Operations below depend on the connected device app supporting the transaction being signed.

OperationSupport
ConnectYes
DisconnectYes; closes device/session resources
Session restoreNo; fresh device connection required
signTransaction()Yes
signAndSubmit()Yes
signMessage()Not exposed
signIn()Not exposed by the direct Ledger adapter
switchNetwork()Not exposed; reconnect for the selected network
Payment / NFT transactionsGeneric txJson; device app/version dependent
QR / deep linkNo

Options ​

These options apply to createLedgerAdapter(). Pass a configured adapter through the client's adapters option for custom device/account handling.

OptionTypeDefaultDescription
accountIndexnumber0Account in 44'/144'/<index>'/0/0
derivationPathstring44'/144'/0'/0/0Full path; overrides accountIndex
preferWebHIDbooleantruePrefer WebHID, fall back to WebUSB
timeoutnumber60000Device operation timeout in milliseconds
autoOpenAppbooleantrueRequest the selected chain's app on the device
deviceApp"XRP" or "XAH"Selected chain's appExplicit device app override; must be compatible with the selected chain
onDeviceState(state: LedgerDeviceState) => voidNot setObserve device states such as OPENING_APP and READY
connectLedger() => Promise<LedgerSession>Built-in connectionCustom device/account connection flow
supportedChainsWalletChainFilterXRPL integrationRestrict chains in a protocol-aware integration
iconstringEmbedded Ledger iconCustom icon URL or data URI

Transactions ​

These XRPL examples use manager and account from either Connect tab. Run each request separately from a user action. Replace recipient addresses and 64-character NFT/offer IDs before signing. Amounts are in drops: "1000000" is 1 XRP. Include DestinationTag when the recipient requires it.

maxFeeDrops is an application-selected ceiling, not the expected fee. Adjust the example limit for your application.

A returned hash or submitted status is not validated ledger confirmation. Check the transaction result before treating a payment or NFT transfer as complete. See WalletManager Events.

Payment ​

ts
const result = await manager.signAndSubmit({
  txJson: {
    TransactionType: "Payment",
    Account: account.address,
    Destination: "<recipient_address>",
    Amount: "1000000",
  },
  maxFeeDrops: "50000",
});
console.log(result.hash);
ts
const result = await manager.signTransaction({
  txJson: {
    TransactionType: "Payment",
    Account: account.address,
    Destination: "<recipient_address>",
    Amount: "1000000",
  },
  maxFeeDrops: "50000",
});
console.log(result.txBlob); // Signed, not broadcast

The default path fills required transaction fields using the selected network, requests device approval and verifies the returned signature. XRPL single-sign requests include the canonical-signature flag for compatibility with the XRP app.

NFT Transactions ​

Each tab signs and submits one transaction. Wallet display and supported transaction types depend on the wallet/provider; generic signing is not a promise of support for every amendment.

ts
await manager.signAndSubmit({
  txJson: {
    TransactionType: "NFTokenMint",
    Account: account.address,
    NFTokenTaxon: 0,
    Flags: 8, // tfTransferable
  },
  maxFeeDrops: "50000",
});
ts
await manager.signAndSubmit({
  txJson: {
    TransactionType: "NFTokenCreateOffer",
    Account: account.address,
    NFTokenID: "<nft_id>",
    Amount: "1000000",
    Flags: 1, // tfSellNFToken
  },
  maxFeeDrops: "50000",
});
ts
await manager.signAndSubmit({
  txJson: {
    TransactionType: "NFTokenAcceptOffer",
    Account: account.address, // Buyer's account
    NFTokenSellOffer: "<sell_offer_id>",
  },
  maxFeeDrops: "50000",
});
ts
await manager.signAndSubmit({
  txJson: {
    TransactionType: "NFTokenCancelOffer",
    Account: account.address, // Offer creator's account
    NFTokenOffers: ["<offer_id>"],
  },
  maxFeeDrops: "50000",
});
ts
await manager.signAndSubmit({
  txJson: {
    TransactionType: "NFTokenBurn",
    Account: account.address,
    NFTokenID: "<nft_id>",
  },
  maxFeeDrops: "50000",
});

Burning permanently destroys the NFT. For buy offers, brokered acceptance and additional fields, see NFT Marketplace. Xahau uses different transaction examples; see the Xahau guide.

Use a current device app that can display the requested NFT transaction. For sign-only NFT requests, pass the same txJson to manager.signTransaction().

Authentication ​

The direct Ledger adapter does not expose arbitrary signMessage() or native signIn(). Joey Wallet's Ledger-backed sign-in challenge belongs to the Joey Wallet adapter, not this adapter. Do not submit a Payment as a substitute login proof.

Sessions and Disconnect ​

Passive restore returns no session. After reload, reconnect and select the device again. manager.disconnect() closes the active transport and clears local session state.

Integration Notes ​

Device App Selection ​

autoOpenApp: false keeps manual app selection. If switching apps resets USB or requires browser permission again, open the requested XRP/XAH app on the hardware and select the device again. A custom connectLedger implementation owns its device-opening behavior. Only one transport should use the device at a time.

Multiple Accounts ​

ts
import { LedgerAdapter } from "@xrpl-wallet-kit/adapter-ledger";

const ledger = new LedgerAdapter();
const accounts = await ledger.getAccounts(5);
console.log(accounts); // address, publicKey, path, index

Use accountIndex or derivationPath when creating the adapter for the selected account.

Multisigning ​

Sign-only multisign requests require a fully prepared source Account, Sequence/ticket, Fee, LastLedgerSequence and network fields, with SigningPubKey: "" and no Signers/TxnSignature. The default multisign path preserves those exact fields without autofill. Custom sessions must implement signMultisignTransaction. Use Core Multisign Coordination for submission; the adapter does not expose multisign submission. Generic signing does not imply Batch compatibility.

Troubleshooting ​

SymptomAction
Device is not detectedCheck USB connection, unlock the device and use a browser with WebHID/WebUSB
Requested app does not openOpen XRP for XRPL or XAH for Xahau on the device, then reconnect
Device is busyClose other applications or transports using it
Transaction fields/type are unsupportedUpdate the device app and confirm support; do not bypass with blind signing
Device approval times outApprove on the device or configure a suitable timeout

Released under the MIT License.