Compare commits

..

2 Commits

Author SHA1 Message Date
Maria Shodunke
a078f09f21 Update example to show requesting historical data 2026-04-23 10:46:51 +01:00
Maria Shodunke
7e934fe44d Fix amm_info missing request fields 2026-04-22 16:12:57 +01:00
18 changed files with 328 additions and 579 deletions

View File

@@ -1,66 +1,56 @@
import xrpl from 'xrpl'
import { execSync } from 'child_process'
import fs from 'fs'
'use strict'
const xrpl = require('xrpl')
// Looks for setup data required to run the checks tutorials.
// If missing, checks-setup.js will generate the data.
// Define parameters. Edit this snippet with your values before running it.
const secret = "s████████████████████████████" // Replace with your secret
const check_id = "" // Replace with your Check ID
if (!fs.existsSync('checks-setup.json')) {
console.log(`\n=== Checks tutorial data doesn't exist. Running setup script... ===\n`)
execSync('node checks-setup.js', { stdio: 'inherit' })
async function main() {
try {
// Connect ----------------------------------------------------------------
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233');
await client.connect();
// Instantiate wallet from secret. ----------------------------------------
const wallet = await xrpl.Wallet.fromSeed(secret)
console.log("Wallet address: ", wallet.address)
// Check if the check ID is provided --------------------------------------
if (check_id.length === 0) {
console.log("Please edit this snippet to provide a check ID. You can get a check ID by running create-check.js.");
return;
}
// Prepare the transaction ------------------------------------------------
const checkcancel = {
"TransactionType": "CheckCancel",
"Account": wallet.address,
"CheckID": check_id
};
// Submit the transaction -------------------------------------------------
const tx = await client.submitAndWait(
checkcancel,
{ autofill: true,
wallet: wallet }
)
// Confirm results --------------------------------------------------------
console.log(`Transaction result: ${JSON.stringify(tx, null, 2)}`)
if (tx.result.meta.TransactionResult === "tesSUCCESS") {
// submitAndWait() only returns when the transaction's outcome is final,
// so you don't also have to check for validated: true.
console.log("Transaction was successful.")
}
// Disconnect -------------------------------------------------------------
await client.disconnect()
} catch (error) {
console.error(`Error: ${error}`)
}
}
// Load setup data --------------------------------------------------------
const setupData = JSON.parse(fs.readFileSync('checks-setup.json', 'utf8'))
const wallet = xrpl.Wallet.fromSeed(setupData.sender.seed)
const checkID = setupData.checkIDs.cancel
console.log(`Wallet address: ${wallet.address}`)
console.log(`Check ID to cancel: ${checkID}`)
// Connect to Testnet -----------------------------------------------------
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
await client.connect()
// Prepare the transaction ------------------------------------------------
console.log(`\n=== Preparing CheckCancel transaction ===\n`)
const checkCancel = {
TransactionType: 'CheckCancel',
Account: wallet.address,
CheckID: checkID
}
// Validate the transaction before submitting -----------------------------
xrpl.validate(checkCancel)
console.log(JSON.stringify(checkCancel, null, 2))
// Submit the transaction -------------------------------------------------
console.log(`\n=== Submitting CheckCancel transaction ===\n`)
const tx = await client.submitAndWait(
checkCancel,
{ autofill: true,
wallet }
)
// Confirm transaction result ---------------------------------------------
const resultCode = tx.result.meta.TransactionResult
if (resultCode !== 'tesSUCCESS') {
console.error('Unable to cancel check:', resultCode)
await client.disconnect()
process.exit(1)
}
const deletedCheck = tx.result.meta.AffectedNodes.find(node =>
node.DeletedNode?.LedgerEntryType === 'Check')
console.log(`Check canceled successfully.`)
console.log(`Deleted check:\n`, JSON.stringify(deletedCheck.DeletedNode.FinalFields, null, 2))
// Disconnect -------------------------------------------------------------
await client.disconnect()
main()

View File

@@ -1,68 +1,62 @@
import xrpl from 'xrpl'
import { execSync } from 'child_process'
import fs from 'fs'
'use strict'
const xrpl = require('xrpl')
// Looks for setup data required to run the checks tutorials.
// If missing, checks-setup.js will generate the data.
// Define parameters. Edit this code with your values before running it.
const secret = "s████████████████████████████" // Replace with your secret
const check_id = "49D339B76FAB3FE3C9DFAD32EB7DB9269FD07B07E165DD7BAFDF68D14CE6CAB8"
const amount = "30000000" // Replace with the amount you want to cash
// String for XRP in drops
// {currency, issuer, value} object for token amount
if (!fs.existsSync('checks-setup.json')) {
console.log(`\n=== Checks tutorial data doesn't exist. Running setup script... ===\n`)
execSync('node checks-setup.js', { stdio: 'inherit' })
async function main() {
try {
// Connect to Testnet
const client = new xrpl.Client("wss://s.altnet.rippletest.net:51233")
await client.connect()
// Instantiate a wallet -----------------------------------------------
const wallet = xrpl.Wallet.fromSeed(secret)
console.log("Wallet address: ", wallet.address)
// Check if the check ID is provided ----------------------------------
if (check_id == "49D339B76FAB3FE3C9DFAD32EB7DB9269FD07B07E165DD7BAFDF68D14CE6CAB8") {
console.log("Please edit this snippet to provide your own check ID. You can get a check ID by running create-check.js.")
return
}
// Prepare the transaction ------------------------------------------------
const checkcash = {
TransactionType: "CheckCash",
Account: wallet.address,
CheckID: check_id,
Amount: amount
}
// Submit the transaction -------------------------------------------------
const tx = await client.submitAndWait(
checkcash,
{ autofill: true,
wallet: wallet }
)
// Confirm transaction results --------------------------------------------
console.log(`Transaction result: ${JSON.stringify(tx, null, 2)}`)
if (tx.result.meta.TransactionResult === "tesSUCCESS") {
// submitAndWait() only returns when the transaction's outcome is final,
// so you don't also have to check for validated: true.
console.log("Transaction was successful.")
console.log("Balance changes:",
JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2)
)
}
// Disconnect -------------------------------------------------------------
await client.disconnect()
} catch (error) {
console.log("Error: ", error)
}
}
// Load setup data --------------------------------------------------------
const setupData = JSON.parse(fs.readFileSync('checks-setup.json', 'utf8'))
const wallet = xrpl.Wallet.fromSeed(setupData.recipient.seed)
const checkID = setupData.checkIDs.exact
const amount = xrpl.xrpToDrops(30)
console.log(`Wallet address: ${wallet.address}`)
console.log(`Check ID to cash: ${checkID}`)
console.log(`Amount to cash: ${amount}`)
// Connect to Testnet -----------------------------------------------------
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
await client.connect()
// Prepare the transaction ------------------------------------------------
const checkCash = {
TransactionType: "CheckCash",
Account: wallet.address,
CheckID: checkID,
Amount: amount
}
// Validate the transaction before submitting -----------------------------
xrpl.validate(checkCash)
console.log(JSON.stringify(checkCash, null, 2))
// Submit the transaction -------------------------------------------------
console.log(`\n=== Submitting CheckCash transaction ===\n`)
const tx = await client.submitAndWait(
checkCash,
{ autofill: true,
wallet }
)
// Confirm transaction result ---------------------------------------------
const resultCode = tx.result.meta.TransactionResult
if (resultCode !== 'tesSUCCESS') {
console.error('Unable to cash check:', resultCode)
await client.disconnect()
process.exit(1)
}
console.log('Check cashed successfully.')
console.log('Balance changes:',
JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2)
)
// Disconnect ------------------------------------------------------------
await client.disconnect()
main()

View File

@@ -1,68 +1,62 @@
import xrpl from 'xrpl'
import { execSync } from 'child_process'
import fs from 'fs'
'use strict'
const xrpl = require('xrpl')
// Looks for setup data required to run the checks tutorials.
// If missing, checks-setup.js will generate the data.
// Define parameters. Edit this code with your values before running it.
const secret = "s████████████████████████████" // Replace with your secret
const check_id = "5C5E9F39A92908BBA7B85AECD9457E9616AD36DF1895074723253B767A380D14"
const deliver_min = "20000000" // Replace with the minimum amount to receive
// String for XRP in drops
// {currency, issuer, value} object for token amount
if (!fs.existsSync('checks-setup.json')) {
console.log(`\n=== Checks tutorial data doesn't exist. Running setup script... ===\n`)
execSync('node checks-setup.js', { stdio: 'inherit' })
async function main() {
try {
// Connect to Testnet
const client = new xrpl.Client("wss://s.altnet.rippletest.net:51233")
await client.connect()
// Instantiate a wallet -----------------------------------------------
const wallet = xrpl.Wallet.fromSeed(secret)
console.log("Wallet address: ", wallet.address)
// Check if the check ID is provided ----------------------------------
if (check_id.length === 0) {
console.log("Please edit this snippet to provide a check ID. You can get a check ID by running create-check.js.")
return
}
// Prepare the transaction ------------------------------------------------
const checkcash = {
TransactionType: "CheckCash",
Account: wallet.address,
CheckID: check_id,
DeliverMin: deliver_min
}
// Submit the transaction -------------------------------------------------
const tx = await client.submitAndWait(
checkcash,
{ autofill: true,
wallet: wallet }
)
// Confirm transaction results --------------------------------------------
console.log(`Transaction result: ${JSON.stringify(tx, null, 2)}`)
if (tx.result.meta.TransactionResult === "tesSUCCESS") {
// submitAndWait() only returns when the transaction's outcome is final,
// so you don't also have to check for validated: true.
console.log("Transaction was successful.")
console.log("Balance changes:",
JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2)
)
}
// Disconnect -------------------------------------------------------------
await client.disconnect()
} catch (error) {
console.log("Error: ", error)
}
}
// Load setup data --------------------------------------------------------
const setupData = JSON.parse(fs.readFileSync('checks-setup.json', 'utf8'))
const wallet = xrpl.Wallet.fromSeed(setupData.recipient.seed)
const checkID = setupData.checkIDs.flexible
const deliverMin = xrpl.xrpToDrops(20)
console.log(`Wallet address: ${wallet.address}`)
console.log(`Check ID to cash: ${checkID}`)
console.log(`Deliver minimum: ${deliverMin}`)
// Connect to Testnet -----------------------------------------------------
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
await client.connect()
// Prepare the transaction ------------------------------------------------
const checkCash = {
TransactionType: "CheckCash",
Account: wallet.address,
CheckID: checkID,
DeliverMin: deliverMin
}
// Validate the transaction before submitting -----------------------------
xrpl.validate(checkCash)
console.log(JSON.stringify(checkCash, null, 2))
// Submit the transaction -------------------------------------------------
console.log(`\n=== Submitting CheckCash transaction ===\n`)
const tx = await client.submitAndWait(
checkCash,
{ autofill: true,
wallet }
)
// Confirm transaction result ---------------------------------------------
const resultCode = tx.result.meta.TransactionResult
if (resultCode !== 'tesSUCCESS') {
console.error('Unable to cash check:', resultCode)
await client.disconnect()
process.exit(1)
}
console.log('Check cashed successfully.')
console.log('Balance changes:',
JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2)
)
// Disconnect -------------------------------------------------------------
await client.disconnect()
main()

View File

@@ -1,121 +0,0 @@
import xrpl from 'xrpl'
import fs from 'fs'
// Helper to extract ticket sequences from TicketCreate result
function getTicketSequences(ticketCreateResult) {
return ticketCreateResult.result.meta.AffectedNodes
.filter(node => node.CreatedNode?.LedgerEntryType === 'Ticket')
.map(node => node.CreatedNode.NewFields.TicketSequence)
}
// Helper to extract check ID from CheckCreate result
function getCheckId(checkCreateResult) {
const checkNode = checkCreateResult.result.meta.AffectedNodes.find(
node => node.CreatedNode?.LedgerEntryType === 'Check'
)
return checkNode.CreatedNode.LedgerIndex
}
// Connect ----------------------
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
await client.connect()
// Fund sender and recipient wallets ----------------------
process.stdout.write('Setting up tutorial: 0/3\r')
const [{ wallet: sender }, { wallet: recipient }] = await Promise.all([
client.fundWallet(),
client.fundWallet()
])
// Create tickets for sender to submit checks in parallel ----------------------
process.stdout.write('Setting up tutorial: 1/3\r')
const ticketCreateResult = await client.submitAndWait(
{
TransactionType: 'TicketCreate',
Account: sender.address,
TicketCount: 4
},
{ wallet: sender, autofill: true }
)
const ticketSequences = getTicketSequences(ticketCreateResult)
// Create four checks in parallel ----------------------
process.stdout.write('Setting up tutorial: 2/3\r')
const [exactResult, flexibleResult, cancelResult, sampleResult] = await Promise.all([
client.submitAndWait(
{
TransactionType: 'CheckCreate',
Account: sender.address,
Destination: recipient.address,
SendMax: xrpl.xrpToDrops(30),
TicketSequence: ticketSequences[0],
Sequence: 0
},
{ wallet: sender, autofill: true }
),
client.submitAndWait(
{
TransactionType: 'CheckCreate',
Account: sender.address,
Destination: recipient.address,
SendMax: xrpl.xrpToDrops(100),
TicketSequence: ticketSequences[1],
Sequence: 0
},
{ wallet: sender, autofill: true }
),
client.submitAndWait(
{
TransactionType: 'CheckCreate',
Account: sender.address,
Destination: recipient.address,
SendMax: xrpl.xrpToDrops(30),
TicketSequence: ticketSequences[2],
Sequence: 0
},
{ wallet: sender, autofill: true }
),
client.submitAndWait(
{
TransactionType: 'CheckCreate',
Account: sender.address,
Destination: recipient.address,
SendMax: xrpl.xrpToDrops(50),
TicketSequence: ticketSequences[3],
Sequence: 0
},
{ wallet: sender, autofill: true }
)
])
// Save setup data to file ----------------------
process.stdout.write('Setting up tutorial: 3/3\r')
const setupData = {
sender: {
address: sender.address,
seed: sender.seed
},
recipient: {
address: recipient.address,
seed: recipient.seed
},
checkIDs: {
exact: getCheckId(exactResult),
flexible: getCheckId(flexibleResult),
cancel: getCheckId(cancelResult),
sample: getCheckId(sampleResult)
}
}
fs.writeFileSync('checks-setup.json', JSON.stringify(setupData, null, 2))
process.stdout.write('Setting up tutorial: Complete!\n')
// Disconnect ----------------------
await client.disconnect()

View File

@@ -1,60 +1,65 @@
import xrpl from 'xrpl'
'use strict'
const xrpl = require('xrpl')
// Connect to the Testnet -------------------------------------------------
async function main() {
try {
// Connect to the XRP Ledger Test Net -------------------------------------
console.log("Connecting to Testnet...")
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
await client.connect()
console.log("Connected.")
console.log('Connecting to Testnet...')
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
await client.connect()
console.log('Connected.')
// Get a new wallet ---------------------------------------------------
console.log("Generating new wallet...")
const wallet = (await client.fundWallet()).wallet
console.log(" Address:", wallet.address)
console.log(" Seed:", wallet.seed)
// Get a new wallet -------------------------------------------------------
// Prepare the transaction --------------------------------------------
const checkcreate = {
"TransactionType": "CheckCreate",
"Account": wallet.address,
"Destination": "rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis",
"SendMax": xrpl.xrpToDrops(120), // Can be more than you have
"InvoiceID": "46060241FABCF692D4D934BA2A6C4427CD4279083E38C77CBE642243E43BE291"
}
console.log('Generating new wallet...')
const wallet = (await client.fundWallet()).wallet
console.log(' Address:', wallet.address)
console.log(' Seed:', wallet.seed)
// Submit the transaction ---------------------------------------------
console.log("Submitting transaction...")
const tx = await client.submitAndWait(
checkcreate,
{ autofill: true,
wallet: wallet }
)
// Prepare the transaction ------------------------------------------------
// Get transaction result and Check ID---------------------------------
console.log(`Transaction: ${JSON.stringify(tx, null, 2)}`)
const checkCreate = {
TransactionType: 'CheckCreate',
Account: wallet.address,
Destination: 'rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis',
SendMax: xrpl.xrpToDrops(120), // Can be more than you have
InvoiceID: '46060241FABCF692D4D934BA2A6C4427CD4279083E38C77CBE642243E43BE291'
if (tx.result.meta.TransactionResult === "tesSUCCESS") {
let checkID = null
for (const node of tx.result.meta.AffectedNodes) {
if (node?.CreatedNode &&
node.CreatedNode?.LedgerEntryType == "Check") {
checkID = node.CreatedNode.LedgerIndex
break
}
}
if (checkID) {
console.log(`Check ID: ${checkID}`)
} else {
console.log("Unable to find the CheckID from parsing the metadata. Look for the LedgerIndex of the 'Check' object within 'meta'.")
}
} else {
console.log("Transaction failed with result code "+
tx.result.meta.TransactionResult)
}
// Disconnect ---------------------------------------------------------
await client.disconnect()
} catch (error) {
console.error(`Error: ${error}`)
}
}
// Validate the transaction before submitting -----------------------------
xrpl.validate(checkCreate)
console.log(JSON.stringify(checkCreate, null, 2))
// Submit the transaction -------------------------------------------------
console.log('Submitting transaction...')
const tx = await client.submitAndWait(
checkCreate,
{ autofill: true,
wallet }
)
// Confirm transaction result and get check ID ------------------------------------
const resultCode = tx.result.meta.TransactionResult
if (resultCode !== 'tesSUCCESS') {
console.error('Unable to create check:', resultCode)
await client.disconnect()
process.exit(1)
}
const node = tx.result.meta.AffectedNodes.find(node =>
node.CreatedNode?.LedgerEntryType === 'Check'
).CreatedNode
console.log('Check created successfully.')
console.log(`Check details:\n`, JSON.stringify(node.NewFields, null, 2))
console.log(`Check ID: ${node.LedgerIndex}`)
// Disconnect -------------------------------------------------------------
await client.disconnect()
main()

View File

@@ -1,66 +1,57 @@
import xrpl from 'xrpl'
import { execSync } from 'child_process'
import fs from 'fs'
'use strict'
const xrpl = require('xrpl')
// Looks for setup data required to run the checks tutorials.
// If missing, checks-setup.js will generate the data.
async function main() {
try {
// Connect ----------------------------------------------------------------
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
await client.connect()
if (!fs.existsSync('checks-setup.json')) {
console.log(`\n=== Checks tutorial data doesn't exist. Running setup script... ===\n`)
execSync('node checks-setup.js', { stdio: 'inherit' })
}
// Loop through account objects until marker is undefined -----------------
let current_marker = null
let checks_found = []
do {
const request = {
"command": "account_objects",
"account": "rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis",
"ledger_index": "validated",
"type": "check"
}
// Load setup data ----------------------
if (current_marker) {
request.marker = current_marker
}
const setupData = JSON.parse(fs.readFileSync('checks-setup.json', 'utf8'))
const address = setupData.recipient.address
const response = await client.request(request)
checks_found = checks_found.concat(response.result.account_objects)
current_marker = response.result.marker
// Connect ----------------------
} while (current_marker)
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
await client.connect()
// Filter results by recipient --------------------------------------------
// To filter by sender, check Account field instead of Destination
const checks_by_recipient = []
for (const check of checks_found) {
if (check.Destination == "rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis") {
checks_by_recipient.push(check)
}
}
// Print results ----------------------------------------------------------
if (checks_by_recipient.length === 0) {
console.log("No checks found.")
} else {
console.log("Checks: \n", JSON.stringify(checks_by_recipient, null, 2))
}
// Loop through account objects until marker is undefined ----------------------
// Disconnect -------------------------------------------------------------
await client.disconnect()
let currentMarker = null
let checksFound = []
do {
const request = {
command: 'account_objects',
account: address,
ledger_index: 'validated',
type: 'check'
}
if (currentMarker) {
request.marker = currentMarker
}
const response = await client.request(request)
checksFound = checksFound.concat(response.result.account_objects)
currentMarker = response.result.marker
} while (currentMarker)
// Filter results by recipient ----------------------
// To filter by sender, check Account field instead of Destination
const checksByRecipient = []
for (const check of checksFound) {
if (check.Destination == address) {
checksByRecipient.push(check)
} catch (error) {
console.log(error)
process.exit(1)
}
}
// Print results ----------------------
if (checksByRecipient.length === 0) {
console.log('No checks found.')
} else {
console.log('Checks: \n', JSON.stringify(checksByRecipient, null, 2))
}
// Disconnect ----------------------
await client.disconnect()
main()

View File

@@ -3,8 +3,7 @@
"description": "Example code for signing and submitting Checks",
"version": "0.0.2",
"license": "MIT",
"type": "module",
"dependencies": {
"xrpl": "^4.4.0"
"xrpl": "^4.0.0"
}
}

View File

@@ -55,7 +55,7 @@ Each inner transaction:
- Must set the `tfInnerBatchTxn` flag.
- Must not have a fee. It must use a fee value of _0_.
- Must not be signed (the global transaction is already signed by all relevant parties). It should instead have an empty string (`""`) in the `SigningPubKey` field and must not include the `TxnSignature` or `Signers` fields.
- Must not be signed (the global transaction is already signed by all relevant parties). They must instead have an empty string ("") in the `SigningPubKey` and `TxnSignature` fields.
A transaction is considered a failure if it receives any result that is not `tesSUCCESS`.
@@ -130,7 +130,7 @@ Each outer transaction contains the metadata for its sequence and fee processing
Each inner transaction contains the metadata for its own processing. Only the inner transactions that are actually committed to the ledger are included. This makes it easier for legacy systems to process `Batch` transactions as if they were normal.
There is also a pointer back to the outer transaction (`ParentBatchID`).
There is also a pointer back to the parent outer transaction (`ParentBatchID`).
## Transaction Common Fields
@@ -168,40 +168,3 @@ If Alice just signs her part of the Batch transaction, Bob can modify his transa
An inner batch transaction is a special case. It doesn't include a signature or a fee (since those are both included in the outer transaction). Therefore, they must be handled carefully to ensure that someone can't somehow directly submit an inner `Batch` transaction without it being included in an outer transaction.
Inner transactions cannot be broadcast (and won't be accepted if they happen to be broadcast, for example, from a malicious node). They must be generated from the `Batch` outer transaction instead. Inner transactions cannot be directly submitted via the submit RPC.
## Integration Considerations
`Batch` transactions have some unique integration considerations:
- Since the outer transaction returns `tesSUCCESS` even when inner transactions fail (see [Metadata](#metadata)), you must check each inner transaction's metadata and result codes to determine its actual outcome.
- If inner transactions are validated, they are included in the same ledger as the outer transaction. If an inner transaction appears in a different ledger, it is likely a fraud attempt.
- Systems that don't specifically handle `Batch` transactions should be able to support them without any changes, since each inner transaction is a valid transaction on its own. All inner transactions that have a `tes` (success) or `tec` result code are accessible via standard transaction-fetching mechanisms such as [`tx`](/docs/references/http-websocket-apis/public-api-methods/transaction-methods/tx.md) and [`account_tx`](/docs/references/http-websocket-apis/public-api-methods/account-methods/account_tx.md).
- In a multi-account `Batch` transaction, only the inner transactions and batch mode flags are signed by all parties. This means the submitter of the outer transaction can adjust the sequence number and fee of the outer transaction as needed, without coordinating with the other parties.
The following sections cover additional recommendations for specific types of integrations.
### Client Libraries
Client libraries that implement `Batch` transaction support should:
- Provide a helper method to calculate the fee for a `Batch` transaction, since the fee includes the sum of all inner transaction fees. See [XRPL Batch Transaction Fees](#xrpl-batch-transaction-fees).
- Provide a helper method to construct and sign multi-account `Batch` transactions, where one party signs the outer transaction and the other parties sign the inner transactions.
- Provide an auto-fill method that sets each inner transaction's `Fee` to `"0"` and the `SigningPubKey` to an empty string (`""`), while omitting the `TxnSignature` field.
### Wallets
Wallets that display or sign `Batch` transactions should:
- Clearly display all inner transactions to users before requesting a signature, so users understand the full scope of what they are approving.
- For multi-account `Batch` transactions, provide a workflow for users to review and sign their portion of the batch, then export it for other parties to sign.
- Warn users if they are signing a `Batch` transaction that includes inner transactions from other accounts, since they are approving the entire batch.
- Display the [batch mode](#xrpl-batch-transaction-modes) and explain its implications.
- Avoid auto-incrementing sequence numbers after successes or failures, since the number of validated transactions depends on the batch mode and which inner transactions succeed. Instead, wait for the outer `Batch` transaction to be validated and check the result of each inner transaction to determine which sequences were consumed.
### Explorers and Indexers
Explorers and indexers that display `Batch` transactions should:
- Display the relationship between outer `Batch` transactions and their inner transactions using the `ParentBatchID` field in the inner transaction metadata.
- Show inner transactions in context with their outer `Batch` transaction, rather than as standalone transactions.
- Consider grouping inner transactions with their outer transaction in transaction lists for clarity.

View File

@@ -32,7 +32,8 @@ An example of the request format:
"asset2": {
"currency": "TST",
"issuer": "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"
}
},
"ledger_index": "validated"
}
```
{% /tab %}
@@ -48,7 +49,8 @@ An example of the request format:
"asset2": {
"currency": "TST",
"issuer": "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"
}
},
"ledger_index": "validated"
}]
}
```
@@ -60,12 +62,14 @@ An example of the request format:
The request includes the following parameters:
| `Field` | Type | Required? | Description |
|:--------------|:-----------------|:----------|-------------|
| `account` | String - [Address][] | No | Show only LP Tokens held by this liquidity provider. |
| `amm_account` | String - [Address][] | No | The address of the AMM's special AccountRoot. (This is the `issuer` of the AMM's LP Tokens.) |
| `asset` | Object | No | One of the assets of the AMM to look up, as an object with `currency` and `issuer` fields (omit `issuer` for XRP), like [currency amounts][Currency Amount]. |
| `asset2` | Object | No | The other of the assets of the AMM, as an object with `currency` and `issuer` fields (omit `issuer` for XRP), like [currency amounts][Currency Amount]. |
| `Field` | Type | Required? | Description |
|:---------------|:---------------------|:----------|-------------|
| `account` | String - [Address][] | No | Show only LP Tokens held by this liquidity provider. |
| `amm_account` | String - [Address][] | No | The address of the AMM's special AccountRoot. (This is the `issuer` of the AMM's LP Tokens.) |
| `asset` | Object | No | One of the assets of the AMM to look up, as an object with `currency` and `issuer` fields (omit `issuer` for XRP), like [currency amounts][Currency Amount]. |
| `asset2` | Object | No | The other of the assets of the AMM, as an object with `currency` and `issuer` fields (omit `issuer` for XRP), like [currency amounts][Currency Amount]. |
| `ledger_hash` | String | No | The unique hash of the ledger version to use. See [Specifying Ledgers][]. |
| `ledger_index` | Number or String | No | The [ledger index][] of the ledger to use, or a shortcut string to choose a ledger automatically. See [Specifying Ledgers][]. |
You must specify _either_ `amm_account` or both `asset` and `asset2`.

View File

@@ -105,26 +105,24 @@ Create or update a [price oracle](../../../../concepts/decentralized-storage/pri
| Field | JSON Type | Internal Type | Required? | Description |
|---------------------|-----------|---------------|-----------|-------------|
| `BaseAsset` | String | Currency | Yes | The primary asset in a trading pair. Any valid identifier, such as a stock symbol, bond CUSIP, or currency code is allowed. For example, in the BTC/USD pair, BTC is the base asset; in 912810RR9/BTC, 912810RR9 is the base asset. |
| `QuoteAsset` | String | Currency | Yes | The quote asset in a trading pair. The quote asset denotes the price of one unit of the base asset. For example, in the BTC/USD pair, USD is the quote asset; in 912810RR9/BTC, BTC is the quote asset. |
| `AssetPrice` | String | UInt64 | No | The asset price after applying the `Scale` precision level. It's recommended you provide this value as a hexadecimal, but [client libraries](https://xrpl.org/docs/references#client-libraries) will accept decimal numbers and convert to hexadecimal strings. |
| `Scale` | Number | UInt8 | No | The scaling factor to apply to an asset price. For example, if `Scale` is 6 and original price is 0.155, then the scaled price is 155000. Valid scale ranges are 0-10. |
| `QuoteAsset` | String | Currency | Yes | The quote asset in a trading pair. The quote asset denotes the price of one unit of the base asset. For example, in the BTC/USD pair, BTC is the base asset; in 912810RR9/BTC, 912810RR9 is the base asset. |
| `AssetPrice` | String | UInt64 | No | The asset price after applying the `Scale` precision level. It's not included if the last update transaction didn't include the `BaseAsset`/`QuoteAsset` pair. It's recommended you provide this value as a hexadecimal, but [client libraries](https://xrpl.org/docs/references#client-libraries) will accept decimal numbers and convert to hexadecimal strings. |
| `Scale` | Number | UInt8 | No | The scaling factor to apply to an asset price. For example, if `Scale` is 6 and original price is 0.155, then the scaled price is 155000. Valid scale ranges are 0-10. It's not included if the last update transaction didn't include the `BaseAsset`/`QuoteAsset` pair.|
`PriceData` is created or updated based on whether the token pair is new or already exists on the oracle entry, and which fields are included in the `OracleSet` transaction. The table below describes the possible outcomes:
`PriceData` is created or updated, following these rules:
| Token pair state and transaction fields | Outcome |
|:--------------------------------------------------------|:--------|
| New pair, including `AssetPrice` | The asset pair is added to the oracle entry with `AssetPrice`. `Scale` is set with a default value of `0` if not set. |
| New pair, excluding `AssetPrice` | `temMALFORMED` if creating a new oracle entry; `tecTOKEN_PAIR_NOT_FOUND` if updating an existing oracle entry. |
| Existing pair, including `AssetPrice` and `Scale` | `AssetPrice` and `Scale` are updated for the asset pair. |
| Existing pair, including `AssetPrice` but _not_ `Scale` | `AssetPrice` is updated. `Scale` is reset to the default value of 0. |
| Existing pair, excluding `AssetPrice` | The asset pair is deleted from the oracle entry. |
| Existing pair excluded from the transaction | The existing asset pair remains in the oracle entry, but its `AssetPrice` and `Scale` are cleared to signal the price is outdated. |
- New token pairs in the transaction are added to the object.
- Token pairs in the transaction overwrite corresponding token pairs in the object.
- Token pairs in the transaction with a missing `AssetPrice` field delete corresponding token pairs in the object.
- Token pairs that only appear in the object have `AssetPrice` and `Scale` removed to signify that the price is outdated.
The `LastUpdateTime` field applies to all entries in the `PriceDataSeries` array. Existing asset pairs not included in an `OracleSet` update transaction have their prices removed to indicate they are out of date for the given `LastUpdateTime`. To access historical price data for these entries, you can:
When updating fewer entries than the existing oracle contains, the `LastUpdateTime` applies to all entries. Entries not included in the update have their prices removed to indicate they are out of date for the given `LastUpdateTime`. To access historical price data for these entries, you can:
- Use the `ledger_entry` method with `PreviousTxnLgrSeq` to traverse previous Oracle objects
- Use the `tx` method with `PreviousTxnID` to find historical transactions
This design choice saves space by having a single `LastUpdateTime` for all entries rather than tracking update times per token pair.
{% admonition type="info" name="Note" %}
The order of token pairs in the transaction isn't important because each token pair uniquely identifies the location of the `PriceData` object in the `PriceDataSeries`.
{% /admonition %}

View File

@@ -13,6 +13,7 @@ You may want to cancel an incoming Check if you do not want it. You might cancel
## Prerequisites
- You should be familiar with the basics of using the [xrpl.js client library](../get-started/get-started-javascript.md).
- You need an XRP Ledger account including its secret key. (You can get one on Testnet for free.) See also: [XRP Faucets](/resources/dev-tools/xrp-faucets).
- You need the ID of a Check ledger entry that you are either the sender or recipient of. See also: [Send a Check](./send-a-check.md).
## Source Code
@@ -33,25 +34,21 @@ Figure out the values of the [CheckCancel transaction][] fields. The following f
| `Account` | String (Address) | The address of the sender who is canceling the Check. (In other words, your address.) |
| `CheckID` | String | The ID of the Check entry to cancel. You can get this information when you [send a check](./send-a-check.md), or by [looking up checks](./look-up-checks.md). |
This example uses a preconfigured account and check from the `checks-setup.js` script, but you can replace `wallet` and `checkID` with your own values.
For example:
{% code-snippet file="/_code-samples/checks/js/cancel-check.js" language="js" from="// Load setup data" before="// Connect to Testnet" /%}
Then, use the loaded values to fill out the transaction:
{% code-snippet file="/_code-samples/checks/js/cancel-check.js" language="js" from="// Prepare the transaction" before="// Submit the transaction" /%}
{% code-snippet file="/_code-samples/checks/js/cancel-check.js" from="// Prepare" before="// Submit" /%}
### 2. Submit the CheckCancel transaction
Submit the CheckCancel transaction in the usual way and wait for it to be validated. If the result code is `tesSUCCESS` and the transaction is in a validated ledger, the transaction is successful. For example:
{% code-snippet file="/_code-samples/checks/js/cancel-check.js" language="js" from="// Submit the transaction" before="// Confirm transaction result" /%}
{% code-snippet file="/_code-samples/checks/js/cancel-check.js" from="// Submit" before="// Confirm" /%}
### 3. Confirm transaction result
## 3. Confirm transaction result
If the transaction succeeds, the code prints the cancelled check's details. For example:
If the transaction succeeded, it should have a `"TransactionResult": "tesSUCCESS"` field in the metadata, and the field `"validated": true` in the result, indicating that this result is final. For example:
{% code-snippet file="/_code-samples/checks/js/cancel-check.js" language="js" from="// Confirm transaction result" before="// Disconnect" /%}
{% code-snippet file="/_code-samples/checks/js/cancel-check.js" from="// Confirm" before="// Disconnect" /%}
{% admonition type="success" name="Tip" %}The `submitAndWait()` method in xrpl.js only returns when the transaction's result is final, so you can assume that the transaction is validated if it returns a result code of `tesSUCCESS`.{% /admonition %}

View File

@@ -8,12 +8,13 @@ labels:
This tutorial shows how to cash a [Check](/docs/concepts/payment-types/checks.md) for a flexible amount. As long as the Check is not expired, the specified recipient can cash it to receive the maximum amount available. You would cash a Check this way if you want to receive as much as possible. When doing this, you set a minimum amount to receive in case the sender does not have enough money to pay the full amount. If the check cannot deliver at least the minimum amount, cashing the check fails but you can try again later.
You can also [cash a check for an exact amount](cash-a-check-for-an-exact-amount.md).
You can also [cash a check for an exact amount](cash-a-check-for-a-flexible-amount.md).
## Prerequisites
- You should be familiar with the basics of using the [xrpl.js client library](../get-started/get-started-javascript.md).
- You need an XRP Ledger account including its secret key. (You can get one on Testnet for free.) See also: [XRP Faucets](/resources/dev-tools/xrp-faucets).
- You need the ID of a Check ledger entry that you are the recipient of. See also: [Send a Check](./send-a-check.md) and [Look Up Checks](./look-up-checks.md).
@@ -36,11 +37,11 @@ Figure out the values of the [CheckCash transaction][] fields. To cash a check f
| `CheckID` | String | The ID of the Check to cash. You can get this information from the person who sent you the Check, or by [looking up checks](./look-up-checks.md) where your account is the destination. |
| `DeliverMin` | [Currency Amount][] | A minimum amount to receive from the Check. If you cannot receive at least this much, cashing the Check fails, leaving the Check in the ledger so you can try again. For XRP, this must be a string specifying drops of XRP. For tokens, this is an object with `currency`, `issuer`, and `value` fields. The `currency` and `issuer` fields must match the corresponding fields in the Check object, and the `value` must be less than or equal to the amount in the Check object. For more information on specifying currency amounts, see [Specifying Currency Amounts][]. |
This example uses a preconfigured account and check from the `checks-setup.js` script, but you can replace `wallet` and `checkID` with your own values.
In the sample code, these values are hard-coded, so you should edit them to match your case:
{% code-snippet file="/_code-samples/checks/js/cash-check-flexible.js" language="js" from="// Load setup data" before="// Connect to Testnet" /%}
{% code-snippet file="/_code-samples/checks/js/cash-check-flexible.js" language="js" from="// Define parameters" before="async function main()" /%}
Then, use the loaded values to fill out the transaction:
Then, you use these parameters to fill out the transaction. For example:
{% code-snippet file="/_code-samples/checks/js/cash-check-flexible.js" language="js" from="// Prepare the transaction" before="// Submit the transaction" /%}
@@ -49,10 +50,10 @@ Then, use the loaded values to fill out the transaction:
Send the transaction and wait for it to be validated by the consensus process, as normal:
{% code-snippet file="/_code-samples/checks/js/cash-check-flexible.js" language="js" from="// Submit the transaction" before="// Confirm transaction result" /%}
{% code-snippet file="/_code-samples/checks/js/cash-check-flexible.js" from="// Submit" before="// Confirm" /%}
### 3. Confirm transaction result
## 3. Confirm final result
If the transaction succeeded, it should have a `"TransactionResult": "tesSUCCESS"` field in the metadata, and the field `"validated": true` in the result, indicating that this result is final.
@@ -60,7 +61,7 @@ If the transaction succeeded, it should have a `"TransactionResult": "tesSUCCESS
If the transaction suceeded, you can assume that it delivered at least the `DeliverMin` amount of this transaction and at most the `SendMax` of the Check. To confirm the exact balance changes that occurred as a result of cashing the check, including how much was actually debited and credited, you must look at the transaction metadata. The `xrpl.getBalanceChanges()` function can help to summarize this. For example:
{% code-snippet file="/_code-samples/checks/js/cash-check-flexible.js" language="js" from="// Confirm transaction result" before="// Disconnect" /%}
{% code-snippet file="/_code-samples/checks/js/cash-check-flexible.js" from="// Confirm transaction results" before="// Disconnect" /%}
{% admonition type="info" name="Note" %}
The metadata shows the net balance changes as the result of all of the transactions effects, which may be surprising in some cases. If an account receives exactly the same amount of XRP as it burns, its balance stays the same so it does not even appear in the list of balance changes.
@@ -72,7 +73,7 @@ If you are not using `getBalanceChanges()`, the following guidelines should help
For example, the following `ModifiedNode` shows that the account `rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis`, the Check's recipient and the sender of this CheckCash transaction, had its XRP balance change from `9999999970` drops to `10099999960` drops, meaning the recipient was credited a _net_ of 99.99999 XRP as a result of processing the transaction.
```json
```
{
"ModifiedNode": {
"FinalFields": {
@@ -96,7 +97,7 @@ If you are not using `getBalanceChanges()`, the following guidelines should help
The net amount of 99.99999 XRP includes deducting the transaction cost that is destroyed to pay for sending this CheckCash transaction. The following part of the transaction instructions shows that the transaction cost (the `Fee` field) was 10 drops of XRP. By adding this to the net balance change, we conclude that the recipient, `rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis`, was credited a _gross_ amount of exactly 100 XRP for cashing the Check.
```json
```
"Account" : "rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis",
"TransactionType" : "CheckCash",
"DeliverMin" : "95000000",

View File

@@ -13,6 +13,7 @@ You can also [cash a check for a flexible amount](./cash-a-check-for-a-flexible-
## Prerequisites
- You should be familiar with the basics of using the [xrpl.js client library](../get-started/get-started-javascript.md).
- You need an XRP Ledger account including its secret key. (You can get one on Testnet for free.) See also: [XRP Faucets](/resources/dev-tools/xrp-faucets).
- You need the ID of a Check ledger entry that you are the recipient of. See also: [Send a Check](./send-a-check.md) and [Look Up Checks](./look-up-checks.md).
## Source Code
@@ -22,12 +23,9 @@ The complete source code for this tutorial is available in the source repository
{% repo-link path="_code-samples/checks/js/" %}Checks sample code{% /repo-link %}
## Steps
Before running these scripts, run `checks-setup.js` once to generate the test wallets and checks used throughout the tutorials.
### 1. Prepare the CheckCash transaction
Figure out the values of the [CheckCash transaction][] fields. To cash a check for an exact amount, the following fields are the bare minimum; everything else is either optional or can be [auto-filled](../../references/protocol/transactions/common-fields.md#auto-fillable-fields) when signing:
Figure out the values of the [CheckCash transaction][] fields. You also need to create a `Wallet` instance for your account's key pair. To cash a check for an exact amount, the following fields are the bare minimum; everything else is either optional or can be [auto-filled](../../references/protocol/transactions/common-fields.md#auto-fillable-fields) when signing:
| Field | Value | Description |
|:------------------|:---------------------|:-----------------------------|
@@ -36,19 +34,20 @@ Figure out the values of the [CheckCash transaction][] fields. To cash a check f
| `CheckID` | String | The ID of the Check to cash. You can get this information from the person who sent you the Check, or by [looking up checks](./look-up-checks.md) where your account is the destination. |
| `Amount` | [Currency Amount][] | The amount to receive. The type of currency (token or XRP) must match the Check object. The quantity in the `value` field must be less than or equal to the amount in the Check object. (For currencies with transfer fees, you must cash the Check for less than its `SendMax` so the transfer fee can be paid by the `SendMax`.) For more information on specifying currency amounts, see [Specifying Currency Amounts][]. |
This example uses a preconfigured account and check from the `checks-setup.js` script, but you can replace `wallet` and `checkID` with your own values.
In the sample code, these values are hard-coded, so you should edit them to match your case:
{% code-snippet file="/_code-samples/checks/js/cash-check-exact.js" language="js" from="// Load setup data" before="// Connect to Testnet" /%}
{% code-snippet file="/_code-samples/checks/js/cash-check-exact.js" language="js" from="// Define parameters" before="async function main()" /%}
Then, use the loaded values to fill out the transaction:
Then, you use these parameters to fill out the transaction. For example:
{% code-snippet file="/_code-samples/checks/js/cash-check-exact.js" language="js" from="// Prepare the transaction" before="// Submit the transaction" /%}
### 2. Submit the transaction
Send the transaction and wait for it to be validated by the consensus process, as normal:
{% code-snippet file="/_code-samples/checks/js/cash-check-exact.js" language="js" from="// Submit the transaction" before="// Confirm transaction result" /%}
{% code-snippet file="/_code-samples/checks/js/cash-check-exact.js" from="// Submit" before="// Confirm" /%}
### 3. Confirm transaction result
@@ -59,7 +58,7 @@ If the transaction succeeded, it should have a `"TransactionResult": "tesSUCCESS
You can look at the transaction metadata to confirm the balance changes that occurred as a result of delivering the exact amount. The `xrpl.getBalanceChanges()` function can help to summarize this. For example:
{% code-snippet file="/_code-samples/checks/js/cash-check-exact.js" language="js" from="// Confirm transaction result" before="// Disconnect" /%}
{% code-snippet file="/_code-samples/checks/js/cash-check-exact.js" from="// Confirm transaction results" before="// Disconnect" /%}
Example balance changes output:

View File

@@ -25,14 +25,14 @@ The complete source code for this tutorial is available in the source repository
To get a list of all incoming and outgoing Checks for an account, use the `account_objects` command and set the `type` field of the request to `checks`. You may need to make multiple requests if the result is [paginated](../../references/http-websocket-apis/api-conventions/markers-and-pagination.md).
{% code-snippet file="/_code-samples/checks/js/get-checks.js" language="js" from="// Loop through account objects until marker is undefined" before="// Filter results by recipient" /%}
{% code-snippet file="/_code-samples/checks/js/get-checks.js" from="// Loop through account objects" before="// Filter results" /%}
### 2. Filter the responses by recipient
The response may include Checks where the account from the request is the sender or the recipient. Each member of the `account_objects` array of the response represents one Check. For each such Check object, the address in the `Destination` is address of that Check's recipient, such as in the following code:
{% code-snippet file="/_code-samples/checks/js/get-checks.js" language="js" from="// Filter results by recipient" before="// Disconnect" /%}
{% code-snippet file="/_code-samples/checks/js/get-checks.js" from="// Filter results" before="// Disconnect" /%}
To filter by sender, check the address in the `Account` field of the Check instead.

View File

@@ -49,18 +49,16 @@ For example, imagine you were asked to pay a company named Grand Payments for so
Send the transaction and wait for it to be validated by the consensus process, as normal:
{% code-snippet file="/_code-samples/checks/js/create-check.js" language="js" from="// Submit the transaction" before="// Confirm transaction result and get check ID" /%}
{% code-snippet file="/_code-samples/checks/js/create-check.js" language="js" from="// Submit the transaction" before="// Get transaction result" /%}
### 3. Confirm transaction result
If the transaction succeeded, it should have a `"TransactionResult": "tesSUCCESS"` field in the metadata, and the field `"validated": true` in the result, indicating that this result is final.
{% code-snippet file="/_code-samples/checks/js/create-check.js" language="js" from="// Confirm transaction result and get check ID" before="// Disconnect" /%}
{% admonition type="success" name="Tip" %}The `submitAndWait()` method in xrpl.js only returns when the transaction's result is final, so you can assume that the transaction is validated if it returns a result code of `tesSUCCESS`.{% /admonition %}
To cash or cancel the Check later, you'll need the Check ID printed above.
To cash or cancel the Check later, you'll need the Check ID. You can find this in the transaction's metadata by looking for a `CreatedNode` entry with a `LedgerEntryType` of `"Check"`. This indicates that the transaction created a [Check ledger entry](../../references/protocol/ledger-data/ledger-entry-types/check.md). The `LedgerIndex` of this object is the ID of the Check. This should be a [hash][] value such as `84C61BE9B39B2C4A2267F67504404F1EC76678806C1B901EA781D1E3B4CE0CD9`.
At this point, it is up to the recipient to cash the Check.

View File

@@ -1,63 +0,0 @@
---
seo:
description: Accelerate development on the XRPL with AI tools.
---
# AI Tools
Augment your AI with additional tools to accelerate development, automate integrations, and deploy secure solutions on the XRP Ledger.
## Model Context Protocol (MCP) Servers
AI models are limited by their training data, which will always be out-of-date with the most recent XRPL features and SDK improvements. MCP servers solve this by giving your AI real-time access to current documentation through a standardized interface. Instead of relying on potentially outdated training data, your AI can query an MCP server for accurate, up-to-date context. Below is a list of available MCP servers:
### Context7
[Context7](https://context7.com/) is a searchable database of user-submitted repos and websites. Official XRPL docs are maintained on the site and include:
- [xrpl.org](https://xrpl.org/docs): The official developer portal for up-to-date XRPL docs, including use cases, concepts, tutorials, references, and code samples.
- [opensource.ripple.com](https://opensource.ripple.com/): The technical doc site for all features in development by Ripple.
- [docs.xrplevm.org](https://docs.xrplevm.org/): The technical doc site for the XRPL EVM Sidechain.
- [XRPL JavaScript SDK](https://github.com/xrplf/xrpl.js)
- [XRPL Python SDK](https://github.com/xrplf/xrpl-py)
- [XRPL Go SDK](https://github.com/xrplf/xrpl-go)
To set up Context7, see: [Installation](https://github.com/upstash/context7?tab=readme-ov-file#installation).
### xrpl.org MCP Server
The xrpl.org site hosts a standalone MCP server, which only contains documentation hosted on the site. From any doc page, you can click the **Copy** dropdown by the page title and select either **Connect to Cursor** or **Connect to VS Code**. If you are using a different code editor, you can manually configure the MCP server using the `https://xrpl.org/mcp` endpoint.
## SKILL.md
A `SKILL.md` file provides behavioral instructions for AI models working with XRPL code. It defines specific steps and rules to produce more precise outcomes, such as forming transactions, implementing security best practices, or issuing tokens. By loading a skill in your coding agent, you reduce the need for verbose or repeated queries.
### XRPL Development Skill for Claude Code
A comprehensive Claude Code skill for modern XRP Ledger development, provided by XRPL Commons. This skill uses Claude Code's progressive disclosure pattern; the main `SKILL.md` provides core guidance, and Claude reads specialized markdown files only when needed for specific tasks. For a full list of available skills, as well as installation instructions, check the [GitHub repo](https://github.com/XRPL-Commons/xrpl-dev-skills?tab=readme-ov-file#xrpl-development-skill-for-claude-code).
### Generate Release Notes
The `generate-release-notes` skill generates a draft release notes to publish to the xrpl.org blog. This skill is intended for contributors to the XRPL docs. For additional details, check the [GitHub repo](https://github.com/XRPLF/xrpl-dev-portal/blob/master/.claude/skills/generate-release-notes/SKILL.md).
## Site Optimizations
The XRPL developer portal has been updated with AI optimizations to serve both human and AI audiences.
### AI Chatbot
An AI chatbot is hosted on [xrpl.org](https://xrpl.org/docs), [opensource.ripple.com](https://opensource.ripple.com/), and [docs.xrplevm.org](https://docs.xrplevm.org/) for users who prefer a more natural-language approach to documentation. You can access the chatbots from the **Ask AI** button at the bottom right of each website, or from the **Search with AI** button embedded in the search bar.
### llms.txt
The site hosts an [llms.txt](https://xrpl.org/llms.txt) file at the root directory, providing a curated index of content for AI crawlers and tools to find relevant information quickly. If you don't want to use the MCP servers, you can provide this file to your AI as context.
### Context Optimization
Markdown is an efficient format for providing documentation context to an AI. Every documentation page on the site hosts an `.md` version, which is accessible from the **Copy** dropdown at the top of the page. The dropdown includes options to:
- Copy the contents of the `.md` file.
- View the page as an `.md` file.
- Open **Claude** or **ChatGPT** with the contents of the page automatically loaded as context.
- Set up the xrpl.org MCP server in **VS Code** or **Cursor** with one click.

View File

@@ -286,7 +286,8 @@
"asset2": {
"currency": "TST",
"issuer": "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"
}
},
"ledger_index": "validated"
}
},
{

View File

@@ -751,7 +751,6 @@
page: resources/dev-tools/index.page.tsx
expanded: false
items:
- page: resources/dev-tools/ai-tools.md
- label: RPC Tool
labelTranslationKey: sidebar.resources.dev-tools.rpc-tool
page: resources/dev-tools/rpc-tool.page.tsx