Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
7 changes: 7 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"permissions": {
"allow": [
"mcp__context7__query-docs"
]
}
}
2 changes: 2 additions & 0 deletions _code-samples/cross-currency-payment/js/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
crossCurrencySetup.json
48 changes: 48 additions & 0 deletions _code-samples/cross-currency-payment/js/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Cross-Currency Payment Examples (JavaScript)

Sends a cross-currency payment where the source spends XRP and the destination is credited in USD, converted through the DEX order book.

## Setup

```sh
npm i
```

## Send a Cross-Currency Payment

```sh
node sendCrossCurrency.js
```

Delivers 100 USD to the receiver, spending up to 30 XRP from the source, and prints the `delivered_amount` from the transaction metadata. If `crossCurrencySetup.json` is missing, the script runs `crossCurrencySetup.js` first to create the issuer, market maker, sender, and receiver accounts and to post the XRP/USD liquidity.

```sh
Sender address: rSENDER...
Receiver address: rRECEIVER...

=== Preparing cross-currency Payment ===

{
"TransactionType": "Payment",
"Account": "rSENDER...",
"Destination": "rRECEIVER...",
"Amount": {
"currency": "USD",
"issuer": "rISSUER...",
"value": "100"
},
"SendMax": "30000000",
"DeliverMin": {
"currency": "USD",
"issuer": "rISSUER...",
"value": "95"
},
"Flags": 131072
}

=== Submitting cross-currency Payment ===

=== Payment delivered ===

delivered_amount: { currency: 'USD', issuer: 'rISSUER...', value: '100' }
```
75 changes: 75 additions & 0 deletions _code-samples/cross-currency-payment/js/crossCurrencySetup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Setup script for cross-currency payment tutorial
import xrpl from 'xrpl'
import fs from 'fs'

const WSS_URL = 'wss://s.altnet.rippletest.net:51233'
const CURRENCY = 'USD'

const client = new xrpl.Client(WSS_URL)
await client.connect()

// Fund the four wallets the tutorial needs
process.stdout.write('Setting up tutorial: 1/5\r')
const [
{ wallet: issuer },
{ wallet: marketMaker },
{ wallet: sender },
{ wallet: receiver }
] = await Promise.all([
client.fundWallet(),
client.fundWallet(),
client.fundWallet(),
client.fundWallet()
])

// Enable rippling so the issuer's USD can move between holders
process.stdout.write('Setting up tutorial: 2/5\r')
await client.submitAndWait({
TransactionType: 'AccountSet',
Account: issuer.address,
SetFlag: 8 // asfDefaultRipple
}, { wallet: issuer, autofill: true })

// Market maker and receiver trust the issuer's USD
process.stdout.write('Setting up tutorial: 3/5\r')
await Promise.all([
client.submitAndWait({
TransactionType: 'TrustSet',
Account: marketMaker.address,
LimitAmount: { currency: CURRENCY, issuer: issuer.address, value: '1000000' }
}, { wallet: marketMaker, autofill: true }),
client.submitAndWait({
TransactionType: 'TrustSet',
Account: receiver.address,
LimitAmount: { currency: CURRENCY, issuer: issuer.address, value: '1000000' }
}, { wallet: receiver, autofill: true })
])

// Issue USD to the market maker so it has inventory to sell
process.stdout.write('Setting up tutorial: 4/5\r')
await client.submitAndWait({
TransactionType: 'Payment',
Account: issuer.address,
Destination: marketMaker.address,
Amount: { currency: CURRENCY, issuer: issuer.address, value: '100000' }
}, { wallet: issuer, autofill: true })

// Post an offer providing XRP -> USD liquidity (4 USD per XRP)
process.stdout.write('Setting up tutorial: 5/5\r')
await client.submitAndWait({
TransactionType: 'OfferCreate',
Account: marketMaker.address,
TakerGets: { currency: CURRENCY, issuer: issuer.address, value: '10000' },
TakerPays: xrpl.xrpToDrops('2500')
}, { wallet: marketMaker, autofill: true })

const setupData = {
description: 'Auto-generated by crossCurrencySetup.js. Stores XRPL account info for the cross-currency payment tutorial.',
issuerAddress: issuer.address,
currency: CURRENCY,
sender: { address: sender.address, seed: sender.seed },
receiver: { address: receiver.address, seed: receiver.seed }
}
fs.writeFileSync('crossCurrencySetup.json', JSON.stringify(setupData, null, 2))

await client.disconnect()
8 changes: 8 additions & 0 deletions _code-samples/cross-currency-payment/js/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "cross-currency-payment-examples",
"description": "Example code for sending a cross-currency payment on the XRP Ledger.",
"dependencies": {
"xrpl": "^4.6.0"
},
"type": "module"
}
63 changes: 63 additions & 0 deletions _code-samples/cross-currency-payment/js/sendCrossCurrency.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// IMPORTANT: This script sends a cross-currency payment. The sender spends XRP
// and the receiver is credited in USD, converted through the DEX order book.
// It requires the accounts and liquidity created by crossCurrencySetup.js; if
// the setup data is missing, this script runs the setup script first.
import xrpl from 'xrpl'
import fs from 'fs'
import { execSync } from 'child_process'

// Connect to the network ----------------------
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
await client.connect()

// Ensure the tutorial's accounts and liquidity exist ----------------------
if (!fs.existsSync('crossCurrencySetup.json')) {
console.log(`\n=== Setup data doesn't exist. Running setup script... ===\n`)
execSync('node crossCurrencySetup.js', { stdio: 'inherit' })
}

const setupData = JSON.parse(fs.readFileSync('crossCurrencySetup.json', 'utf8'))
const sender = xrpl.Wallet.fromSeed(setupData.sender.seed)
const receiverAddress = setupData.receiver.address
const issuerAddress = setupData.issuerAddress
const currency = setupData.currency

console.log(`\nSender address: ${sender.address}`)
console.log(`Receiver address: ${receiverAddress}`)

// Prepare cross-currency Payment ----------------------
// Deliver 100 USD to the receiver while spending no more than 30 XRP from the
// source. The ledger routes XRP -> USD through the DEX automatically, so there
// is no router to integrate. SendMax caps what the source spends. DeliverMin,
// together with the tfPartialPayment flag, floors what the destination receives.
console.log(`\n=== Preparing cross-currency Payment ===\n`)
const paymentTx = {
TransactionType: 'Payment',
Account: sender.address,
Destination: receiverAddress,
Amount: { currency, issuer: issuerAddress, value: '100' },
SendMax: xrpl.xrpToDrops('30'),
DeliverMin: { currency, issuer: issuerAddress, value: '95' },
Flags: 131072 // tfPartialPayment
}

xrpl.validate(paymentTx)
console.log(JSON.stringify(paymentTx, null, 2))

// Submit, sign, and wait for validation ----------------------
console.log(`\n=== Submitting cross-currency Payment ===\n`)
const response = await client.submitAndWait(paymentTx, { wallet: sender, autofill: true })

const resultCode = response.result.meta.TransactionResult
if (resultCode !== 'tesSUCCESS') {
console.error('Error: payment failed with', resultCode)
await client.disconnect()
process.exit(1)
}

// Credit the amount that ACTUALLY arrived, from metadata, never the Amount field
console.log(`\n=== Payment delivered ===\n`)
console.log('delivered_amount:', response.result.meta.delivered_amount)
// End cross-currency payment

await client.disconnect()
3 changes: 3 additions & 0 deletions _code-samples/cross-currency-payment/py/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.venv/
__pycache__/
cross_currency_setup.json
50 changes: 50 additions & 0 deletions _code-samples/cross-currency-payment/py/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Cross-Currency Payment Examples (Python)

Sends a cross-currency payment where the source spends XRP and the destination is credited in USD, converted through the DEX order book.

## Setup

```sh
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```

## Send a Cross-Currency Payment

```sh
python3 send_cross_currency.py
```

Delivers 100 USD to the receiver, spending up to 30 XRP from the source, and prints the `delivered_amount` from the transaction metadata. If `cross_currency_setup.json` is missing, the script runs `cross_currency_setup.py` first to create the issuer, market maker, sender, and receiver accounts and to post the XRP/USD liquidity.

```sh
Sender address: rSENDER...
Receiver address: rRECEIVER...

=== Preparing cross-currency Payment ===

{
"Account": "rSENDER...",
"TransactionType": "Payment",
"Amount": {
"currency": "USD",
"issuer": "rISSUER...",
"value": "100"
},
"Destination": "rRECEIVER...",
"SendMax": "30000000",
"DeliverMin": {
"currency": "USD",
"issuer": "rISSUER...",
"value": "95"
},
"Flags": 131072
}

=== Submitting cross-currency Payment ===

=== Payment delivered ===

delivered_amount: {'currency': 'USD', 'issuer': 'rISSUER...', 'value': '100'}
```
119 changes: 119 additions & 0 deletions _code-samples/cross-currency-payment/py/cross_currency_setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Setup script for cross-currency payment tutorial
import asyncio
import json

from xrpl.asyncio.clients import AsyncWebsocketClient
from xrpl.asyncio.transaction import submit_and_wait
from xrpl.asyncio.wallet import generate_faucet_wallet
from xrpl.models.amounts import IssuedCurrencyAmount
from xrpl.models.transactions import (
AccountSet,
AccountSetAsfFlag,
OfferCreate,
Payment,
TrustSet,
)
from xrpl.utils import xrp_to_drops

WSS_URL = "wss://s.altnet.rippletest.net:51233"
CURRENCY = "USD"


async def main():
async with AsyncWebsocketClient(WSS_URL) as client:
# Fund the four wallets the tutorial needs
print("Setting up tutorial: 1/5", end="\r")
issuer, market_maker, sender, receiver = await asyncio.gather(
generate_faucet_wallet(client),
generate_faucet_wallet(client),
generate_faucet_wallet(client),
generate_faucet_wallet(client),
)

# Enable rippling so the issuer's USD can move between holders
print("Setting up tutorial: 2/5", end="\r")
await submit_and_wait(
AccountSet(
account=issuer.address,
set_flag=AccountSetAsfFlag.ASF_DEFAULT_RIPPLE,
),
client,
issuer,
)

# Market maker and receiver trust the issuer's USD
print("Setting up tutorial: 3/5", end="\r")
await asyncio.gather(
submit_and_wait(
TrustSet(
account=market_maker.address,
limit_amount=IssuedCurrencyAmount(
currency=CURRENCY,
issuer=issuer.address,
value="1000000",
),
),
client,
market_maker,
),
submit_and_wait(
TrustSet(
account=receiver.address,
limit_amount=IssuedCurrencyAmount(
currency=CURRENCY,
issuer=issuer.address,
value="1000000",
),
),
client,
receiver,
),
)

# Issue USD to the market maker so it has inventory to sell
print("Setting up tutorial: 4/5", end="\r")
await submit_and_wait(
Payment(
account=issuer.address,
destination=market_maker.address,
amount=IssuedCurrencyAmount(
currency=CURRENCY,
issuer=issuer.address,
value="100000",
),
),
client,
issuer,
)

# Post an offer providing XRP -> USD liquidity (4 USD per XRP)
print("Setting up tutorial: 5/5", end="\r")
await submit_and_wait(
OfferCreate(
account=market_maker.address,
taker_gets=IssuedCurrencyAmount(
currency=CURRENCY,
issuer=issuer.address,
value="10000",
),
taker_pays=xrp_to_drops(2500),
),
client,
market_maker,
)

setup_data = {
"description": (
"Auto-generated by cross_currency_setup.py. Stores XRPL account "
"info for the cross-currency payment tutorial."
),
"issuer_address": issuer.address,
"currency": CURRENCY,
"sender": {"address": sender.address, "seed": sender.seed},
"receiver": {"address": receiver.address, "seed": receiver.seed},
}
with open("cross_currency_setup.json", "w") as f:
json.dump(setup_data, f, indent=2)


asyncio.run(main())
1 change: 1 addition & 0 deletions _code-samples/cross-currency-payment/py/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
xrpl-py>=4.5.0
Loading