Insights

xrpl.js — JavaScript SDK Guide

xrpl.js is the JavaScript and TypeScript library for the XRP Ledger: it connects to a server, signs with your keys on your machine, and submits. Version 5.3.0, 208,637 downloads from npm last week. Every example below runs as written.

How a transaction goes through

  1. 1. Buildyou

    A plain object: type, account, amount.

  2. 2. Autofillxrpl.js

    The library adds the fee, the next sequence number and a last ledger to land in.

  3. 3. Signxrpl.js

    On your machine. The seed never leaves it.

  4. 4. Submitserver

    Sent to a server, which shares it with the network.

  5. 5. Validatedledger

    In a ledger 3–5 seconds later, with a final result code.

Steps 2–4 are one call, client.submitAndWait(tx, { wallet }), when you do not need them apart.

Install and connect

Terminal
npm install xrpl
app.mjs (an ES module, so await works at the top level)
import { Client } from 'xrpl'

const client = new Client('wss://xrplcluster.com')
await client.connect()

// ... the examples below go here ...

await client.disconnect()

Public servers: wss://xrplcluster.com, wss://s1.ripple.com and wss://s2.ripple.com. For testing use Testnet, wss://s.altnet.rippletest.net:51233, where XRP is free: xrpl.to’s Testnet sandbox funds an account and shows every transaction type.

Read balances and an order book

// XRP and every token an account holds (this is the ledger's very first account)
const balances = await client.getBalances('rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh')
console.log(balances)   // [{ currency: 'XRP', value }, { currency, issuer, value }, ...]

// The two sides of the RLUSD/XRP market
const XRP = { currency: 'XRP' }
const RLUSD = { currency: '524C555344000000000000000000000000000000', issuer: 'rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De' }
const asks = await client.request({ command: 'book_offers', taker_gets: RLUSD, taker_pays: XRP, limit: 10 })
const bids = await client.request({ command: 'book_offers', taker_gets: XRP, taker_pays: RLUSD, limit: 10 })
console.log(asks.result.offers.length, 'offers selling RLUSD,', bids.result.offers.length, 'buying it')
  • The XRP balance includes the reserve, 1 XRP for the account plus 0.2 XRP for each trust line, offer or other object it owns, which it cannot spend (xrpl.org: reserves).
  • getBalances reads every trust line, so on an issuer with thousands of holders it makes thousands of requests and public servers refuse it. Ask account_info for the XRP alone.
  • The library’s getOrderbook returns buy and sell, but it sorts offers by a flag their creator chose, not by side of the market (source). For bids and asks, ask book_offers once in each direction, as above.
  • A currency code longer than three characters is written as 40 hex characters: RLUSD is 524C5553440….

Send XRP

import { Wallet, xrpToDrops } from 'xrpl'

const wallet = Wallet.fromSeed(process.env.XRPL_SEED)   // never in the source file

const tx = await client.autofill({
  TransactionType: 'Payment',
  Account: wallet.address,
  Destination: 'rDestination...',
  Amount: xrpToDrops('10'),          // amounts in drops: 1 XRP = 1,000,000
  // DestinationTag: 12345,          // when an exchange gives you one
})
const signed = wallet.sign(tx)
const res = await client.submitAndWait(signed.tx_blob)
console.log(res.result.meta.TransactionResult)   // 'tesSUCCESS'

submitAndWait resolves once the transaction is in a validated ledger, so the result it prints is final. To tell your app’s transactions apart on the ledger, add a SourceTag of your own choosing.

Open a trust line, with NoRipple

import { TrustSetFlags } from 'xrpl'

const res = await client.submitAndWait({
  TransactionType: 'TrustSet',
  Account: wallet.address,
  LimitAmount: {
    currency: '524C555344000000000000000000000000000000',   // RLUSD
    issuer: 'rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De',
    value: '1000000',                                        // the most you will hold
  },
  Flags: TrustSetFlags.tfSetNoRipple,
}, { wallet })

Always set NoRipple. Without it, someone holding two tokens with the same name from different issuers can route a payment through your account and swap your valuable one for their worthless one, with no signature from you. The line holds 0.2 XRP of your balance until you remove it.

Follow new ledgers

await client.request({ command: 'subscribe', streams: ['ledger'] })

client.on('ledgerClosed', (ledger) => {
  console.log(ledger.ledger_index, ledger.txn_count, 'transactions')
})

A new ledger closes every 3–5 seconds. Subscribe to accounts instead to get only the transactions that touch your addresses.

Reading the result

A result starting with tec is final and costs the fee; one starting with tef or tem never reached a ledger. The ones you will meet first:

CodeThe server saysWhat it means
tesSUCCESS—It worked.
tecUNFUNDED_PAYMENTInsufficient XRP balance to send.More than you can spend: the reserve stays locked.
tecNO_DST_INSUF_XRPDestination does not exist. Too little XRP sent to create it.A new account needs at least 1 XRP to exist.
tecDST_TAG_NEEDEDA destination tag is required.Exchanges need the tag they gave you.
tecPATH_DRYPath could not send partial amount.No liquidity between the two currencies.
tecPATH_PARTIALPath could not send full amount.Not enough liquidity at your price limit.
tecINSUF_RESERVE_LINEInsufficient reserve to add trust line.Each trust line holds 0.2 XRP; you are short.
tefPAST_SEQThis sequence number has already passed.Sent twice, or another program used the same account.
Messages from rippled’s TER.cpp.

Prices, history and holders

The ledger holds current state; prices over time, candles, holder lists and 24-hour volumes come from an index. xrpl.to’s API serves them over plain HTTPS, so an app can read them with fetch and keep xrpl.js for signing. Full reference: js.xrpl.org; source: XRPLF/xrpl.js.

Questions

What is xrpl.js?
The JavaScript and TypeScript library for the XRP Ledger, published on npm as "xrpl" and maintained in the XRPLF/xrpl.js repository. It connects to XRP Ledger servers, signs transactions with your keys and submits them. The current version is 5.3.0.
Does xrpl.js work in the browser?
Yes. It runs in Node.js and in browsers; in Node it needs version 20.19 or newer.
Do I need to tell xrpl.js which key algorithm my seed uses?
Not in version 5: Wallet.fromSeed reads it from the seed itself (sEd… is ed25519, other s… seeds are secp256k1). Versions 3 and 4 assumed ed25519 unless told otherwise, so a secp256k1 seed gave the wrong address there; pass { algorithm: 'ecdsa-secp256k1' } if you are on one of them.