<aside> 📜 TABLE OF CONTENTS
1. 📘 Introduction to XRP Ledger
3. 💻 Interacting with XRP Ledger
4. 🏗️ Building dApps on XRPL with React
5. 🔗 EVM Sidechain Integration for XRPL
</aside>
Transactions are the core of the XRP Ledger. They represent actions that can change the ledger state.
🔑 Key Concepts:
Here's an example of how to send XRP using the xrpl
library:
const xrpl = require("xrpl")
async function sendXRP() {
const client = new xrpl.Client("wss://s.altnet.rippletest.net:51233")
await client.connect()
// Create test account
const fund_result = await client.fundWallet()
const test_wallet = fund_result.wallet
const prepared = await client.autofill({
"TransactionType": "Payment",
"Account": test_wallet.address,
"Amount": xrpl.xrpToDrops("22"),
"Destination": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"
})
const signed = test_wallet.sign(prepared)
console.log("Sending XRP...")
const tx = await client.submitAndWait(signed.tx_blob)
console.log("Transaction result:", tx.result.meta.TransactionResult)
console.log("Balance changes:", JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2))
await client.disconnect()
}
sendXRP().catch(console.error)
💡 This script connects to the testnet, funds a wallet, prepares a payment transaction, signs it, and submits it to the network.
Understanding transaction metadata is crucial for interpreting the results of your transactions.
📝 Key aspects:
The XRP Ledger allows the issuance of custom tokens, known as "issued currencies".
🔑 Key Concepts:
Here's an example of how to issue a token on the XRP Ledger:
const xrpl = require("xrpl")
async function issueToken() {
const client = new xrpl.Client("wss://s.altnet.rippletest.net:51233")
await client.connect()
// Create issuer and customer accounts
const issuer_wallet = (await client.fundWallet()).wallet
const customer_wallet = (await client.fundWallet()).wallet
// Create trust line from customer to issuer
const trust_set_tx = {
"TransactionType": "TrustSet",
"Account": customer_wallet.address,
"LimitAmount": {
"currency": "FOO",
"issuer": issuer_wallet.address,
"value": "10000000000" // Large limit, arbitrarily chosen
}
}
const ts_prepared = await client.autofill(trust_set_tx)
const ts_signed = customer_wallet.sign(ts_prepared)
const ts_result = await client.submitAndWait(ts_signed.tx_blob)
console.log("TrustSet transaction result:", ts_result.result.meta.TransactionResult)
// Issue token from issuer to customer
const issue_tx = {
"TransactionType": "Payment",
"Account": issuer_wallet.address,
"Amount": {
"currency": "FOO",
"value": "1000",
"issuer": issuer_wallet.address
},
"Destination": customer_wallet.address
}
const issue_prepared = await client.autofill(issue_tx)
const issue_signed = issuer_wallet.sign(issue_prepared)
const issue_result = await client.submitAndWait(issue_signed.tx_blob)
console.log("Issue transaction result:", issue_result.result.meta.TransactionResult)
await client.disconnect()
}
issueToken().catch(console.error)
🚀 This script creates two accounts, establishes a trust line, and then issues tokens from the issuer to the customer.
The XRP Ledger includes a built-in decentralized exchange for trading tokens.
🔑 Key Concepts:
Here's how to create an offer on the DEX:
const xrpl = require('xrpl')
async function createOffer() {
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
await client.connect()
// Create and fund a test wallet
const wallet = xrpl.Wallet.generate()
const fund_result = await client.fundWallet(wallet)
// Prepare the offer
const offer = {
"TransactionType": "OfferCreate",
"Account": wallet.address,
"TakerGets": {
"currency": "XRP",
"value": "100000000" // 100 XRP in drops
},
"TakerPays": {
"currency": "USD",
"issuer": "rN6KtYz9S76VatuyVLpzJJEkKAdyVaXMUw",
"value": "50"
}
}
// Submit the transaction
const prepared = await client.autofill(offer)
const signed = wallet.sign(prepared)
const result = await client.submitAndWait(signed.tx_blob)
console.log("Offer Create result:", result.result.meta.TransactionResult)
console.log("Offer ID:", result.result.OfferID)
await client.disconnect()
}
createOffer().catch(console.error)
💡 This example creates an offer to sell 100 XRP for 50 USD.
To cancel an existing offer:
async function cancelOffer() {
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
await client.connect()
const wallet = xrpl.Wallet.generate() // Use the wallet that created the offer
const cancelTx = {
"TransactionType": "OfferCancel",
"Account": wallet.address,
"OfferSequence": 12345 // The sequence number of the OfferCreate transaction
}
const prepared = await client.autofill(cancelTx)
const signed = wallet.sign(prepared)
const result = await client.submitAndWait(signed.tx_blob)
console.log("Offer Cancel result:", result.result.meta.TransactionResult)
await client.disconnect()
}
cancelOffer().catch(console.error)
Before trading, you might want to check the current state of the order book:
async function checkOrderBook() {
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
await client.connect()
const request = {
command: "book_offers",
taker_gets: {
currency: "XRP"
},
taker_pays: {
currency: "USD",
issuer: "rN6KtYz9S76VatuyVLpzJJEkKAdyVaXMUw"
},
limit: 10
}
const response = await client.request(request)
console.log("Order Book:", JSON.stringify(response.result.offers, null, 2))
await client.disconnect()
}
checkOrderBook().catch(console.error)
🔍 This will show you the top 10 offers for the XRP/USD pair.
To execute a trade, you create an OfferCreate transaction that crosses an existing offer:
async function executeTrade() {
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
await client.connect()
const wallet = xrpl.Wallet.generate()
await client.fundWallet(wallet)
const trade = {
"TransactionType": "OfferCreate",
"Account": wallet.address,
"TakerGets": {
"currency": "USD",
"issuer": "rN6KtYz9S76VatuyVLpzJJEkKAdyVaXMUw",
"value": "50"
},
"TakerPays": "100000000" // 100 XRP in drops
}
const prepared = await client.autofill(trade)
const signed = wallet.sign(prepared)
const result = await client.submitAndWait(signed.tx_blob)
console.log("Trade execution result:", result.result.meta.TransactionResult)
console.log("Balances changed:", JSON.stringify(xrpl.getBalanceChanges(result.result.meta), null, 2))
await client.disconnect()
}
executeTrade().catch(console.error)
🚀 This creates an offer that should immediately be matched with an existing offer, effectively executing a trade.
Partial payments allow the amount delivered to be less than the amount specified:
async function partialPayment() {
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
await client.connect()
const wallet = xrpl.Wallet.generate()
await client.fundWallet(wallet)
const payment = {
"TransactionType": "Payment",
"Account": wallet.address,
"Amount": {
"currency": "USD",
"issuer": "rN6KtYz9S76VatuyVLpzJJEkKAdyVaXMUw",
"value": "100"
},
"Destination": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe",
"SendMax": "200000000", // 200 XRP in drops
"Flags": xrpl.PaymentFlags.tfPartialPayment
}
const prepared = await client.autofill(payment)
const signed = wallet.sign(prepared)
const result = await client.submitAndWait(signed.tx_blob)
console.log("Partial payment result:", result.result.meta.TransactionResult)
console.log("Delivered amount:", result.result.meta.delivered_amount)
await client.disconnect()
}
partialPayment().catch(console.error)
💡 This attempts to deliver 100 USD, but will deliver less if the full amount can't be exchanged for 200 XRP or less.
Autobridging happens automatically when it provides a better rate. Here's how you might set up a trade that could use autobridging:
async function autobridgedTrade() {
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
await client.connect()
const wallet = xrpl.Wallet.generate()
await client.fundWallet(wallet)
const trade = {
"TransactionType": "OfferCreate",
"Account": wallet.address,
"TakerGets": {
"currency": "EUR",
"issuer": "rN6KtYz9S76VatuyVLpzJJEkKAdyVaXMUw",
"value": "50"
},
"TakerPays": {
"currency": "USD",
"issuer": "rN6KtYz9S76VatuyVLpzJJEkKAdyVaXMUw",
"value": "60"
}
}
const prepared = await client.autofill(trade)
const signed = wallet.sign(prepared)
const result = await client.submitAndWait(signed.tx_blob)
console.log("Autobridged trade result:", result.result.meta.TransactionResult)
console.log("Balances changed:", JSON.stringify(xrpl.getBalanceChanges(result.result.meta), null, 2))
await client.disconnect()
}
autobridgedTrade().catch(console.error)
Escrow is a feature that allows you to send conditional XRP payments. The XRP can be held in escrow and then either be released to the recipient or returned to the sender when certain conditions are met.
To create an escrow, you use the EscrowCreate transaction:
const xrpl = require('xrpl')
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
async function createEscrow() {
await client.connect()
// Create a wallet for testing
const wallet = xrpl.Wallet.generate()
// Fund the wallet using testnet faucet
const fund_result = await client.fundWallet(wallet)
// Prepare the transaction
const prepared = await client.autofill({
"TransactionType": "EscrowCreate",
"Account": wallet.address,
"Amount": xrpl.xrpToDrops("100"), // Amount of XRP to escrow
"Destination": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe", // Recipient's address
"FinishAfter": xrpl.isoTimeToRippleTime('2023-01-01T00:00:00Z'), // When the escrow can be finished
"CancelAfter": xrpl.isoTimeToRippleTime('2023-06-01T00:00:00Z'), // When the escrow can be cancelled
"Condition": "A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100" // Optional crypto-condition
})
// Sign the transaction
const signed = wallet.sign(prepared)
// Submit the transaction
const result = await client.submitAndWait(signed.tx_blob)
console.log("Escrow created. Transaction result:", result.result.meta.TransactionResult)
console.log("Escrow sequence number:", result.result.Sequence)
await client.disconnect()
}
createEscrow().catch(console.error)
🔒 This script creates an escrow that can be finished after January 1, 2023, and cancelled after June 1, 2023.
To finish (execute) an escrow, you use the EscrowFinish transaction:
async function finishEscrow() {
await client.connect()
const wallet = xrpl.Wallet.generate() // The wallet finishing the escrow
const prepared = await client.autofill({
"TransactionType": "EscrowFinish",
"Account": wallet.address,
"Owner": "rN7n7otQDd6FczFgLdSqtcsAUxDkw6fzRH", // Address of escrow creator
"OfferSequence": 7, // Sequence number of EscrowCreate transaction
"Condition": "A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100",
"Fulfillment": "A0028000" // Fulfillment that satisfies the condition
})
const signed = wallet.sign(prepared)
const result = await client.submitAndWait(signed.tx_blob)
console.log("Escrow finished. Transaction result:", result.result.meta.TransactionResult)
await client.disconnect()
}
finishEscrow().catch(console.error)
🔓 This script finishes an escrow, releasing the escrowed XRP to the intended recipient.
Multi-signing allows multiple parties to authorize a transaction. This is useful for shared accounts or increased security.
First, you need to set up a signer list for an account:
async function setupMultisigning() {
await client.connect()
const wallet = xrpl.Wallet.generate() // The account to set up for multi-signing
await client.fundWallet(wallet)
const prepared = await client.autofill({
"TransactionType": "SignerListSet",
"Account": wallet.address,
"SignerQuorum": 3, // Number of signers required
"SignerEntries": [
{
"SignerEntry": {
"Account": "rUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v",
"SignerWeight": 2
}
},
{
"SignerEntry": {
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
"SignerWeight": 1
}
},
{
"SignerEntry": {
"Account": "rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf",
"SignerWeight": 1
}
}
]
})
const signed = wallet.sign(prepared)
const result = await client.submitAndWait(signed.tx_blob)
console.log("Multi-signing setup. Transaction result:", result.result.meta.TransactionResult)
await client.disconnect()
}
setupMultisigning().catch(console.error)
🔐 This script sets up a signer list requiring 3 weights worth of signatures, with one signer having a weight of 2 and two signers having a weight of 1 each.
Here's how to create and submit a multi-signed transaction:
async function createMultisignedTx() {
await client.connect()
const wallet1 = xrpl.Wallet.fromSeed("sn3nxiW7v8KXzPzAqzyHXbSSKNuN9") // Example seed, don't use in production
const wallet2 = xrpl.Wallet.fromSeed("sswoqc5X8puRLqMv1racial3FMvNP") // Example seed, don't use in production
const prepared = await client.autofill({
"TransactionType": "Payment",
"Account": "rEuLyBCvcw4CFmzv8RepSiAoNgF8tTGJQC",
"Destination": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"Amount": "20000000" // 20 XRP
})
const signed1 = wallet1.sign(prepared, true) // true for multi-signing
const signed2 = wallet2.sign(prepared, true)
const multisigned = {
...prepared,
SigningPubKey: "",
Signers: [
{
Signer: {
Account: wallet1.address,
SigningPubKey: wallet1.publicKey,
TxnSignature: signed1.signature
}
},
{
Signer: {
Account: wallet2.address,
SigningPubKey: wallet2.publicKey,
TxnSignature: signed2.signature
}
}
]
}
const result = await client.submitAndWait(multisigned)
console.log("Multi-signed transaction result:", result.result.meta.TransactionResult)
await client.disconnect()
}
createMultisignedTx().catch(console.error)
🖋️ This script creates a payment transaction and signs it with two different wallets, demonstrating how a multi-signed transaction is constructed and submitted.
Payment channels allow for fast, off-ledger payments that can be later reconciled on the XRP Ledger.
To open a payment channel:
async function openPaymentChannel() {
await client.connect()
const wallet = xrpl.Wallet.generate()
await client.fundWallet(wallet)
const prepared = await client.autofill({
"TransactionType": "PaymentChannelCreate",
"Account": wallet.address,
"Amount": xrpl.xrpToDrops("100"),
"Destination": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe",
"SettleDelay": 86400,
"PublicKey": wallet.publicKey
})
const signed = wallet.sign(prepared)
const result = await client.submitAndWait(signed.tx_blob)
console.log("Payment channel opened. Transaction result:", result.result.meta.TransactionResult)
console.log("Payment Channel ID:", result.result.ChannelID)
await client.disconnect()
}
openPaymentChannel().catch(console.error)
🔓 This script opens a payment channel, allowing for off-ledger transactions between two parties.
To claim XRP from a payment channel:
async function claimFromPaymentChannel() {
await client.connect()
const wallet = xrpl.Wallet.generate() // The recipient's wallet
// The payment channel ID
const channelId = "5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3"
// The amount to claim, in drops of XRP
const amount = "1000000"
// The channel owner's public key
const channelPublicKey = "aB44YfzW24VDEJQ2UuLPV2PvqcPCSoLnL7y5M1EzhdW4LnK5xMS3"
// Sign the claim with the channel owner's key
const claim = {
channelId: channelId,
amount: amount
}
const signature = xrpl.authorizeChannel(claim, channelPublicKey)
// Prepare the transaction
const prepared = await client.autofill({
"TransactionType": "PaymentChannelClaim",
"Account": wallet.address,
"Channel": channelId,
"Amount": amount,
"Signature": signature,
"PublicKey": channelPublicKey
})
const signed = wallet.sign(prepared)
const result = await client.submitAndWait(signed.tx_blob)
console.log("Claim from payment channel. Transaction result:", result.result.meta.TransactionResult)
await client.disconnect()
}
claimFromPaymentChannel().catch(console.error)
💰 This script demonstrates how to claim XRP from an open payment channel, finalizing off-ledger transactions on the XRP Ledger.
This guide has covered a wide range of non-EVM development topics on the XRP Ledger, including:
Remember to always test your code thoroughly on the testnet before deploying to the mainnet. Happy coding on the XRP Ledger! 🚀