Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/_snippets/simplexrpl-response-fields.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Every simpleXRPL write resolves to a `SubmissionResult<T>` — a union tagged by `source`, with the backend's raw response preserved verbatim. Its common fields are:

| Field | Type | Description |
| --- | --- | --- |
| `intent` | `T` | The method-specific output. See the method's response values below. |
| `source` | `'rippled' \| 'custody' \| 'palisade'` | Which backend produced the result; discriminates `response`. |
| `response` | `TxResponse` \| custody record \| Palisade record | The backend's raw response, preserved verbatim. |
| `txHash` | `string` _(optional)_ | The XRPL transaction hash, once the transaction is on-ledger. |
| `intentId` | `string` _(optional)_ | The custodian intent id, when the path produced one. |
| `idempotencyKey` | `string` _(optional)_ | The UUIDv7 this submission carried. Pass it back as a later call's `idempotencyKey` to retry to the same intent. |
7 changes: 7 additions & 0 deletions docs/_snippets/simplexrpl-write-options.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
`options` is an optional second argument that sets the source account and overrides the fee.

| Option | Type | Required | Description |
| --- | --- | --- | --- |
| `from` | `AccountSelector` | No | The account to act as. Defaults to the primary signer's primary account. (For IOU verbs, this is the issuer.) |
| `fee` | `FeeIntent` | No | Fee override. |
| `idempotencyKey` | `string` | No | A prior submission's `idempotencyKey`, to retry to the same intent instead of creating a duplicate. Auto-generated when omitted. |
130 changes: 130 additions & 0 deletions docs/simpleXRPL/get-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
---
seo:
description: Install simpleXRPL, initialize the client, connect a custodian, and run your first XRP Ledger operation.
labels:
- simpleXRPL
- SDK
---

# Get Started

This guide takes you from install to your first on-ledger operation in three steps: **initialize the client**, **set up a custodian**, and **run a vertical operation**. The examples target the XRPL Testnet with a local signer so you can run them as-is, then swap in a production custodian when you're ready.

## Prerequisites

- **Node.js >= 20.19.** simpleXRPL is Node-targeted and not intended to run in the browser.
- Install the package:

```sh
npm install simplexrpl
```

## 1. Initialize the client

`SimpleXRPL.init(...)` is the single entry point — you never construct the client with `new`. It binds one or more already-authenticated signing backends (the **connectors**) to a network and builds the account index.
Comment thread
oeggert marked this conversation as resolved.
Outdated

```ts
import { LocalSigner, SimpleXRPL } from 'simplexrpl'

const client = await SimpleXRPL.init({
// Point at a rippled endpoint. `faucetUrl` is only used on test networks
// (by `client.account.fund`).
rippledUrl: 'wss://s.altnet.rippletest.net:51233',
faucetUrl: 'https://faucet.altnet.rippletest.net/accounts',

// Bind one or more connectors. Here, a single local-signing backend that
// reads its seeds from the environment (`XRPL_*_SEED`).
signers: [LocalSigner.fromEnv()],
})

// ... use the client ...

await client.disconnect()
```

- **`primarySigner`** is the default backend for verbs called without an explicit account. It defaults to `signers[0]`, so you only set it when you bind more than one connector.
- With **no `signers`**, the client is read-only: reads work, but write verbs throw `NoSignerError` until a signer is added.
- Bind an account at runtime (for example, a freshly created wallet) with `client.registerLocalAccount(seed)`.

See [Initialize the client](tutorials/inititialize-clients.md) for the full walkthrough, and [Client and initialization](references/index.md#client-and-initialization) for the configuration reference.

## 2. Set up a custodian

The **connector** determines how operations run and who holds the keys. simpleXRPL ships three, each constructed and authenticated on its own, then handed to `init`:

- **`LocalSigner`** — self-custody; keys held in-process. For development and testing.
- **`RippleCustody`** — routes through Ripple Custody. For production.
- **`PalisadeCustody`** — routes through Palisade. For production.

The local signer in Step 1 is enough for development. For production, construct a custodian connector and bind it instead of (or alongside) the local one:

```ts
import {
LocalSigner,
PalisadeCustody,
RippleCustody,
SimpleXRPL,
} from 'simplexrpl'

// Ripple Custody — authenticates with an intent-author key and operates within
// one Custody domain. `fromEnv` reads the `RIPPLE_CUSTODY_*` variables.
const rippleCustody = await RippleCustody.fromEnv({
primary: process.env.RIPPLE_CUSTODY_PRIMARY ?? '',
})

// Palisade — authenticates via OAuth client credentials and acts on a
// specific vault/wallet.
const palisade = await PalisadeCustody.create({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just confirming that it's correct that we have no url for ripple custody but we do for palisade? @pdp2121

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that's correct afaik. Cant tag Cybele here to confirm

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just added her to review team, tagging @cybele-ripple

baseUrl: 'https://api.sandbox.palisade.co',
clientId: process.env.PALISADE_CLIENT_ID ?? '',
clientSecret: process.env.PALISADE_CLIENT_SECRET ?? '',
primary: {
vaultId: process.env.PALISADE_VAULT_ID ?? '',
walletId: process.env.PALISADE_WALLET_ID ?? '',
},
// Enable the raw sign-only fallback for transactors the custodian has no
// native operation for. Off by default.
allowRawSigning: false,
})

const client = await SimpleXRPL.init({
rippledUrl: 'wss://s.altnet.rippletest.net:51233',
signers: [rippleCustody, palisade, LocalSigner.fromEnv()],
primarySigner: rippleCustody,
})
```

Read credentials from your environment or secrets manager — never hard-code keys. Once bound, every vertical verb works the same regardless of which connector owns the account: the SDK routes each write to the custodian that holds it.
Comment thread
oeggert marked this conversation as resolved.
Outdated

{% admonition type="info" name="Note" %}
Whether an operation runs through a custodian's **native** path or the **raw-signing fallback** is decided per operation; the fallback is off by default and enabled per connector via `allowRawSigning`. See [Operation Execution](index.md#operation-execution) and the [Connector Routing](references/connector-routing.md) table.
{% /admonition %}

See [Connect to custodians](tutorials/connect-custodians.md) for the full per-connector setup.

## 3. Run a vertical operation

Operations are grouped into domain-specific **verticals** — `xrp`, `token`, `iou`, `credential`, `domain`, and `account` — reached off the client. Each verb reads as business intent rather than protocol mechanics. Here's the simplest one, a native XRP payment:
Comment thread
oeggert marked this conversation as resolved.
Outdated

```ts
const result = await client.xrp.transfer({
to: 'rDestination...',
amount: '10',
})

console.log(result.txHash)
```

- A write verb uses the **primary account** by default; target a different bound account by passing `from` in the options.
- Every write resolves to a `SubmissionResult` carrying the transaction hash, the backend's response, and a typed `intent` output. See [Results and handles](references/index.md#results-and-handles).
- **Reads** (such as `client.account.retrieve()`) need no signer and submit nothing.

{% admonition type="success" name="Tip" %}
On a test network, create and fund an account first with [`account.create()`](references/verticals/account/create.md) and [`account.fund()`](references/verticals/account/fund.md), then use its address as the source or destination.
{% /admonition %}

## Next steps

- **Tutorials** — end-to-end workflows: [Issue an RWA as an MPT](tutorials/issue-rwa-as-mpt.md), [Issue and distribute an IOU](tutorials/issue-and-distribute-iou.md), [Place a DEX order](tutorials/place-dex-order.md), and more.
- **Reference** — every vertical, method, connector, and type: [Reference](references/index.md).
- **Concepts** — what simpleXRPL is and why: [What is simpleXRPL](index.md).
47 changes: 47 additions & 0 deletions docs/simpleXRPL/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
seo:
description: simpleXRPL is an opinionated TypeScript SDK that lets institutional developers express XRP Ledger operations as business intent and route them through the custodians they already use.
labels:
- simpleXRPL
- SDK
---

# simpleXRPL
[Source](https://github.com/ripple/simpleXRPL)

The `simpleXRPL` is an opinionated TypeScript SDK for the XRP Ledger, built for institutional developers who interact with the ledger through a custodian. It raises the level of your code from XRPL protocol mechanics to business operations that the SDK routes through your institutional custodians. Concretely, this means:
Comment thread
oeggert marked this conversation as resolved.
Outdated

- `simpleXRPL` defines the shape of business operations, handling the underlying XRPL transactions and custodian API calls.
- Your code doesn't change even if you switch custodians or operate across several at once.

{% admonition type="warning" name="Caution" %}
`simpleXRPL` is pre-1.0. The public API may change between releases and no sandbox exists yet to test native custodian operations.
{% /admonition %}


## How It Works

`simpleXRPL` is built around four concepts:

- **Clients**: Establishes the network connection and the connector configuration. Both are immutable for the client's lifetime; to change either, you create a new client.
- **Connectors**: The execution model that determines *how* operations run and *who* holds account keys. Each connector exposes a uniform interface to the rest of the SDK, so the same code runs across all of them.
- **Accounts**: An XRPL [account](https://xrpl.org/docs/concepts/accounts) paired with the connector that signs for it.
Comment thread
oeggert marked this conversation as resolved.
Outdated
- **Verticals**: Domain-specific classes and methods that group related business operations.


## Operation Execution

For every operation, on every connector, `simpleXRPL` has a statically defined routing decision that it reports at initialization:

- **Native**: Maps onto an endpoint a custodian exposes and natively handles.
- **Raw Signing**: For an operation the custodian exposes no native support for, the SDK builds the underlying XRPL transactions, the custodian signs the raw bytes, then the SDK submits them to the XRPL directly. Raw signing is off by default and enabled per connector; once on, it covers every operation that connector can't handle natively.
- **Unavailable**: The custodian doesn't expose a native endpoint and raw signing isn't enabled on the connector, so this operation is rejected.

{% admonition type="info" name="Note" %}
For a complete list of supported operations by connector, see [Connector Routing](./references/connector-routing.md)
{% /admonition %}


## See Also

- [Get Started](./get-started.md)
61 changes: 61 additions & 0 deletions docs/simpleXRPL/references/connector-routing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
seo:
description: The connector routing table — per XRPL transactor and per custodian, whether an operation routes native, requires the raw-signing fallback, or is unavailable.
labels:
- simpleXRPL
- SDK
---

# Connector Routing

[Source](https://github.com/ripple/simpleXRPL/blob/50619258cf753008e8a185eaeb3ceca489e5998a/docs/connector-routing.md)

How simpleXRPL dispatches each XRPL transactor per connector. Derived directly from each custodian's native-operation set and the transactors the verticals build, so it always matches the code.

{% admonition type="info" name="Note" %}
This page is generated from the SDK source by `scripts/gen-connector-routing.mjs` — do not edit by hand. Regenerate with `npm run docgen:routing`.
{% /admonition %}

## Transactor → connector path

The pipeline routes by transactor type: **Local** signs everything in-process; a custodian uses its **native** operation when the transactor is in its capability set, otherwise the **raw** sign-only fallback, otherwise the write is rejected.

| Transactor | Local | Ripple Custody | Palisade |
| --- | --- | --- | --- |
| `AccountSet` | signs locally | **native** | **native** |
| `Clawback` | signs locally | **native** | **native** |
| `CredentialAccept` | signs locally | raw fallback¹ | raw fallback¹ |
| `CredentialCreate` | signs locally | raw fallback¹ | raw fallback¹ |
| `CredentialDelete` | signs locally | raw fallback¹ | raw fallback¹ |
| `DepositPreauth` | signs locally | **native** | raw fallback¹ |
| `EscrowFinish` | signs locally | **native** | raw fallback¹ |
| `MPTokenAuthorize` | signs locally | **native** | raw fallback¹ |
| `MPTokenIssuanceCreate` | signs locally | **native** | raw fallback¹ |
| `MPTokenIssuanceDestroy` | signs locally | **native** | raw fallback¹ |
| `MPTokenIssuanceSet` | signs locally | **native** | raw fallback¹ |
| `OfferCancel` | signs locally | raw fallback¹ | **native** |
| `OfferCreate` | signs locally | **native** | **native** |
| `Payment` | signs locally | **native** | **native** |
| `PermissionedDomainDelete` | signs locally | raw fallback¹ | raw fallback¹ |
| `PermissionedDomainSet` | signs locally | raw fallback¹ | raw fallback¹ |
| `SetRegularKey` | signs locally | raw fallback¹ | raw fallback¹ |
| `TrustSet` | signs locally | **native** | **native** |

¹ **raw fallback** applies only when raw signing is enabled on that custodian (`allowRawSigning`). With raw signing disabled, a non-native transactor is rejected with `SignerCapabilityError` — use a Local account or a custodian that natively supports it. The raw path signs the encoded transaction and submits it through the shared XRPL connection.

## Vertical → transactors

Which XRPL transactors each vertical builds. Cross-reference with the table above to see how a given method routes on each connector.

| Vertical | Transactors emitted |
| --- | --- |
| `account` | `AccountSet`, `DepositPreauth`, `Payment`, `SetRegularKey` |
| `credential` | `CredentialAccept`, `CredentialCreate`, `CredentialDelete` |
| `domain` | `PermissionedDomainDelete`, `PermissionedDomainSet` |
| `iou` | `AccountSet`, `Clawback`, `OfferCancel`, `OfferCreate`, `Payment`, `TrustSet` |
| `token` | `MPTokenAuthorize`, `MPTokenIssuanceCreate`, `MPTokenIssuanceDestroy`, `MPTokenIssuanceSet`, `OfferCancel`, `OfferCreate`, `Payment` |
| `xrp` | `Payment` |

---

_Native-ops sets: `NATIVE_XRPL_TRANSACTORS` (Ripple Custody), `PALISADE_NATIVE_TRANSACTORS` (Palisade). Local signs all transactors._
94 changes: 94 additions & 0 deletions docs/simpleXRPL/references/index.md
Comment thread
oeggert marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
---
seo:
description: Reference index for the simpleXRPL SDK — its verticals, connectors, the amount and asset model, submission results, and the error hierarchy.
labels:
- simpleXRPL
- SDK
---

# Reference

This section is the map of simpleXRPL's public API surface: the client entry point, the business-intent verticals, the custodian connectors, the amount and asset model, submission results, and the error hierarchy. Complete type-level signatures for every symbol are generated from the source with TypeDoc; the tables below are the curated index of what you actually build against.

New to simpleXRPL? Start with [What is simpleXRPL](../index.md) for the concepts, then [Get Started](../get-started.md) to install and connect a custodian.

{% admonition type="info" name="Note" %}
This index covers the public surface only. Internal and testing seams (the dispatch pipeline, injected I/O ports, and the production ledger port) are intentionally omitted — you don't call them directly.
{% /admonition %}

## Client and initialization

The client owns the network connection and the connector configuration, both immutable for its lifetime.

| Symbol | Description |
| --- | --- |
| `SimpleXRPL` | The entry point. `SimpleXRPL.init(...)` establishes the network, connector, and account bindings. |
| `SimpleXRPLClient` | The runtime client returned by `init`; exposes the verticals. |
| `SimpleXRPLConfig` | The initialization configuration shape (network, connector, accounts). |
| `NetworkInfo` | Resolved network details for the connected client. |

## Verticals

Operations are grouped into domain-specific **verticals**, one per area of XRPL functionality and reached off the client. See [Verticals](verticals/index.md) for what a vertical is and the full list of verticals and their methods.

## Connectors

The connector is the execution model — it determines how operations run and who holds the keys. See [Operation Execution](../index.md#operation-execution) for how each operation routes.

| Connector | Use | Key configuration types |
| --- | --- | --- |
| `LocalSigner` | Development and testing; holds `xrpl` wallets in-process. | `LocalSignerCreateOptions`, `LocalSignerFromEnvOptions` |
| `RippleCustody` | Production; routes through Ripple Custody. | `RippleCustodyOptions`, `RippleCustodyAuthOptions`, `RippleCustodyFromEnvOptions` |
| `PalisadeCustody` | Production; routes through Palisade. | `PalisadeCustodyConfig`, `PalisadeWalletRef` |

## Amounts and assets

The amount model represents XRP, IOU, and MPT values and handles decimal/scale conversion.

| Symbol | Description |
| --- | --- |
| `Amount` | A value paired with the asset it denominates. |
Comment thread
oeggert marked this conversation as resolved.
Outdated
| `Asset` | The asset an amount is in (XRP, IOU, or MPT). |
| `XRP_ASSET` | The canonical XRP asset constant. |
| `iou(currency, issuer)` | Construct an issued-currency asset. |
| `mpt(mptIssuanceId, scale?)` | Construct an MPT asset; `scale` is the decimal places between display value and on-ledger base units. |
| `toLedgerAmount` / `fromLedgerAmount` | Convert between display amounts and on-ledger base units. |
| `LedgerAmount` | The on-ledger (base-unit) amount representation. |

## Results and handles

| Symbol | Description |
| --- | --- |
| `SubmissionResult<T>` | The terminal result of an operation; carries the discriminated `source`/`response` pairing and the vertical's typed `intent` output. |
| `SubmissionResultFields` | The common fields present on every submission result. |
| `SubmissionPath` | Which path the operation took (native vs. raw-signing). |
| `SubmissionHandle` | Handle over an asynchronously-submitted operation, for flows that resolve later. |
| `CustodyTransactionResult` / `PalisadeTransactionResult` | The connector-specific transaction record inside the result. |

The `*Intent` types (`XrpTransferIntent`, `MptIssueIntent`, `IOUIssueIntent`, `DomainIntent`, and the rest) are the typed `intent` payloads attached to each result.

## Errors

All errors extend `SimpleXRPLError`, so you can catch the base class or narrow to a specific type.

| Error | Raised when |
| --- | --- |
| `SimpleXRPLError` | Base class for every SDK error. |
| `NoSignerError` | No signer/connector owns the target account. |
| `SignerCapabilityError` | The operation can't be signed on this connector (native path missing, or raw signing not enabled). |
| `AccountNotFoundError` | The referenced account is not bound to the client. |
| `AmbiguousAccountError` | The account reference matches more than one bound account. |
| `RippledSubmitError` | The transaction reached a terminal on-ledger failure (non-`tesSUCCESS`). |
| `IntentPendingError` | A custodian intent is still awaiting approval when a terminal result was expected. |
| `IntentValidationError` | A custodian rejected the intent as invalid. |
| `MultiStepFailureError` | A multi-step operation failed partway through. |
| `CustodyApiError` / `CustodyAuthError` | Ripple Custody API or authentication failure. |
| `PalisadeApiError` / `PalisadeAuthError` | Palisade API or authentication failure. |

## Related reference

Companion reference pages that live alongside this index:

- **Function-to-transactor mapping** — the underlying XRPL transactor(s) each method expands into (also shown inline on each method page).
- [**Connector routing table**](connector-routing.md) — per operation and per connector, whether it routes native, requires raw-signing fallback, or is unavailable.
- **Institutional defaults** — the full set of defaults the SDK applies unless overridden.
Loading