Skip to content

Sending Unowned Currencies (Tokens) | JavaScript XRPL Development Level 3

Next, we will explain the process of sending unowned currencies (tokens) as an additional topic to cross-currency payments.

We will continue to handle the issuer A’s A.USD.

Prerequisites

Daniel does not hold A.USD but needs to pay Alice in A.USD.

The amount of A.USD to send to Alice should be about 5 XRP.

In cross-currency payments between different currencies, liquidity is always required, and the following process is necessary.

  1. Bob creates an offer to exchange A.USD for XRP, providing liquidity.
  2. Daniel, who does not hold A.USD, will pay Alice using up to 5 XRP (assuming there is liquidity; otherwise, the payment will fail).
  3. The process is successful if Alice receives 100 A.USD.

1. Create Offer from Bob (Provide Liquidity)

For cross-currency payments to occur, liquidity must exist.

Bob creates an offer to exchange his A.USD for XRP, providing liquidity.

  1. Modify the previously created createOffers.js as follows (comment out unnecessary parts).

    import { Client, xrpToDrops } from 'xrpl';
    import { wallets } from './wallets.js';
    import { createOffer } from './utils/createOffer.js';
    const client = new Client('wss://s.altnet.rippletest.net:51233'); // Use the testnet
    async function main() {
    try {
    await client.connect();
    const { issuerA, issuerB, alice, bob, charlie, daniel } = wallets;
    // Bob
    await createOffer(
    client,
    bob,
    { currency: 'USD', issuer: issuerA.address, value: '100' }, // TokenGets: offering 100 A.USD
    xrpToDrops(5); // TakerPays: Bob wants to receive 5 XRP
    );
    } catch (error) {
    console.error(`Error in offer creation: ${error}`);
    } finally {
    await client.disconnect();
    }
    }
    main();
  2. Run the script.

    Terminal window
    node createOffers.js

    This completes the creation of Bob’s offer to sell his A.USD and buy XRP.

2. Daniel Sends A.USD to Alice

Daniel will send A.USD to Alice.

Daniel wants to pay using XRP, but he does not want to spend more than necessary, so he wants to set a maximum limit for the payment.

In such cases, you can specify the amount using sendMax. In XRPL, the sendMax field allows you to set a maximum amount for the payment. (A minimum can also be specified.)

The route is quite simple; here, it will be Daniel → Bob → Alice. Of course, if the token is highly liquid, the optimal route will be selected automatically.

  1. Modify the previously created crossCurrencyPayment.js as follows (comment out unnecessary parts).

    import xrpl from 'xrpl';
    import { wallets } from './wallets.js';
    import { sendPayment } from './utils/payment.js';
    const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233');
    const main = async () => {
    await client.connect();
    const { issuerA, issuerB, alice, bob, charlie, daniel } = wallets;
    await sendPayment(
    client,
    daniel,
    { currency: 'USD', issuer: issuerA.address, value: '100' }, // Currency Alice wants to receive: A.USD
    alice.address,
    {
    sendMax: xrpToDrops(5), // Set the maximum payment limit to 5 XRP
    }
    );
    await client.disconnect();
    };
    main().catch(console.error);
  2. Run the script.

    Terminal window
    node crossCurrencyPayment.js

    If the following log is displayed, the transaction is successful.

    Please check it using the Explorer for Testnet.

    Terminal window
    Payment sent from rf6R7pFgytT9JKjMVjKqeTv6MeDTrbNw3 to r3KQdHtUHUouGkLBFLZRxRYiugbW8cNwyJ: {
    id: 14,
    result: {
    Account: 'rf6R7pFgytT9JKjMVjKqeTv6MeDTrbNw3', // Daniel
    Amount: {
    currency: 'USD',
    issuer: 'rfkJ7Uz6NrNV1FdbmKB5wepoim51KFpYQp', // Issuer A
    value: '100'
    },
    DeliverMax: {
    currency: 'USD',
    issuer: 'rfkJ7Uz6NrNV1FdbmKB5wepoim51KFpYQp',
    value: '100'
    },
    Destination: 'r3KQdHtUHUouGkLBFLZRxRYiugbW8cNwyJ', // Alice
    Fee: '12',
    Flags: 0,
    LastLedgerSequence: 1371126,
    SendMax: '5000000', // 5 XRP
    Sequence: 1046459,
    SigningPubKey: 'EDEC83B1B5D761F21A9625E88C70EE68CE5D5496B513DC6295CEDA7905065DD51A',
    TransactionType: 'Payment',
    TxnSignature: '939CD057964FCEEA621E358B65D780B50EBC50C6D80D83F5E93B463B9365F553261E27B7420E18CFBD9524A7E57C8EF20694C39B6B677F1EDBAD0ECA88F8260F',
    ctid: 'C014EBE500000001',
    date: 771245761,
    hash: '49C8ABCA168351936BE825B27F97836E68D4C49818F9664BD08447B6E4044A2A',
    inLedger: 1371109,
    ledger_index: 1371109,
    meta: {
    AffectedNodes: [Array],
    TransactionIndex: 0,
    TransactionResult: 'tesSUCCESS', // Success
    delivered_amount: [Object]
    },
    validated: true
    },
    type: 'response'
    }

    This completes the transfer of A.USD to Alice.

    To recap, Daniel sent A.USD to Alice, staying within the limit of 5 XRP. Bob had placed an order to exchange 100 A.USD for 5 XRP, so ultimately, Bob received 5 XRP and Alice received the A.USD that Bob held.

Summary

As demonstrated in this guide, with XRPL, you can send currency that you do not hold as long as there is liquidity. The fact that such functionality is provided natively is a strength of XRPL and the reason why XRPL is originally called a blockchain for payments.

Recently, powerful features like AMM have been incorporated, and it continues to evolve. However, I believe that understanding these basic concepts is essential before attempting to master more complex features. Please continue to work on mastering them.

The simple transfer mechanism itself may be difficult to visualize based solely on documentation, so I hope this knowledge will be helpful in your future development and projects.