💸

最速でXRPLのクロスカレンシー送金をJavaScriptで試す方法

2024/05/29に公開

私が作成しているXRPL道場でクロスカレンシー送金の講座を作成しましたので、合わせてこちらでも「最速でXRPLのクロスカレンシー送金をJavaScriptで試す方法」としてテストフローをご紹介したいと思います。

前提

最終的に、以下の条件をクリアできるように進めていきます。

  • チャーリーからボブに、発行者AのA.USDが届くこと
  • チャーリーが発行者BのB.EURで支払いを行えること

1.プロジェクトのセットアップ

// ディレクトリの作成・移動
mkdir xrpl-cross-currency
cd xrpl-cross-currency

// プロジェクト作成
npm init -y
npm install xrpl dotenv

package.jsonの調整

{
  "name": "xrpl-cross-currency",
  "version": "1.0.0",
  "main": "index.js",
  "type": "module", // 追加
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "xrpl": "^3.0.0"
  }
}

アカウント情報の作成

アカウント情報の効率的に管理する

プロジェクトのルートに.envというファイルを作成し、以下のように定義してください。

ISSUER_A_SEED=s████████████████████████████
ISSUER_B_SEED=s████████████████████████████
ALICE_SEED=s████████████████████████████
BOB_SEED=s████████████████████████████
CHARLIE_SEED=s████████████████████████████

wallet.jsの作成

プロジェクトのルートにwallet.jsというファイルを作成し、以下のように定義してください。

import { Wallet } from 'xrpl';
import { config } from 'dotenv';

config(); // dotenvの設定を読み込む

export const wallets = {
  issuerA: Wallet.fromSeed(process.env.ISSUER_A_SEED),
  issuerB: Wallet.fromSeed(process.env.ISSUER_B_SEED),
  alice: Wallet.fromSeed(process.env.ALICE_SEED),
  bob: Wallet.fromSeed(process.env.BOB_SEED),
  charlie: Wallet.fromSeed(process.env.CHARLIE_SEED)
};

汎用的なメソッドを定義する

https://zenn.dev/nabe3/articles/8fa914b33afce5

こちらの記事を参考にしていただき、utilsディレクトリに各jsファイル群を作成します。

※sendPaymentなど、今回不要のものもあります。

トラストラインを設定する

トラストラインを設定することで、アカウントは特定の通貨を受け取ることができるようになります。

※トラストラインの基本的な解説についてはこちらを参照ください。

// setTrustline.js
import { Client, AccountSetAsfFlags } from 'xrpl';
import { wallets } from './wallets.js';
import { setTrustLine } from './utils/trustSet.js';
import { setAccountFlags } from './utils/setAccountFlags.js';

const client = new Client('wss://s.altnet.rippletest.net:51233'); // テストネットを使用

const main = async () => {
 try {
   await client.connect();

   const { issuerA, issuerB, alice, bob, charlie } = wallets;
   const limitAmount = '10000';

   // Ripplingを許可しておく(※必須ではありません)
   await setAccountFlags(client, issuerA, AccountSetAsfFlags.asfDefaultRipple);
   await setAccountFlags(client, issuerB, AccountSetAsfFlags.asfDefaultRipple);

   // AliceがissuerAのUSDと、issuerBのEURを受け取るためのトラストラインを設定
   await setTrustLine(client, alice, 'USD', issuerA.classicAddress, limitAmount);
   await setTrustLine(client, alice, 'EUR', issuerB.classicAddress, limitAmount);

   // BobがissuerAのUSDを受け取るためのトラストラインを設定
   await setTrustLine(client, charlie, 'USD', issuerA.classicAddress, limitAmount);

   // CharlieがissuerBのEURを受け取るためのトラストラインを設定
   await setTrustLine(client, daniel, 'EUR', issuerB.classicAddress, limitAmount);
 } catch (error) {
   console.error(`Error in trust line setup: ${error}`);
 } finally {
   await client.disconnect();
 }
};

main();

通貨(トークン)の発行

  1. アリスにA.USDとB.EURを発行します。
  2. ボブにA.USDを発行します。
  3. チャーリーにB.EURを発行します。
import { Client } from 'xrpl';
import { wallets } from './wallets.js';
import { issueCurrency } from './utils/issueCurrency.js';

const client = new Client('wss://s.altnet.rippletest.net:51233'); // テストネットを使用

async function main() {
  try {
    await client.connect();

    const { issuerA, issuerB, alice, bob, charlie, daniel } = wallets;

    const limitAmount = '1000'; // 送金量

    // Alice
    await issueCurrency(client, issuerA, alice.address, 'USD', limitAmount);
    await issueCurrency(client, issuerB, alice.address, 'EUR', limitAmount);

    // Bob
    await issueCurrency(client, issuerA, bob.address, 'USD', limitAmount);

    // Charlie
    await issueCurrency(client, issuerB, charlie.address, 'EUR', limitAmount);
  } catch (error) {
    console.error(`Error in setup: ${error}`);
  } finally {
    await client.disconnect();
  }
}

main();

オファーの作成

アリスが「A.USDを売り、B.EURを買う」というオファー(注文)を作成します。

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'); // テストネットを使用

async function main() {
    try {
        await client.connect();

        const { issuerA, issuerB, alice, bob, charlie } = wallets;

        await createOffer(
            client,
            alice,
            { currency: 'USD', issuer: issuerA.address, value: '100' },
            { currency: 'EUR', issuer: issuerB.address, value: '100' }
        );
    } catch (error) {
        console.error(`Error in offer creation: ${error}`);
    } finally {
        await client.disconnect();
    }
}

main();

クロスカレンシー送金の実行

前提

アリスが発行者AのA.USDを売り、発行者BのB.EURを買うオファーを出し、流動性を提供済みです。

チャーリーは、ボブに支払いを行う必要がありますが、ボブはA.USDで受け取りたいそうです。しかし、現時点では、チャーリーはA.USDを保有していないため、
XRPと発行者BのB.EURしか保有していないチャーリーは、手持ちのB.EURを交換できないかと考えました。

B.EURA.USDに希望額分交換してくれる人が存在するかを検索したところ、交換してくれる人が存在することを確認できたので、B.EURをボブにA.USDとして、送付する手続きを行います。

プロジェクトディレクトリに新しいjsファイルを作成し、実行します。

// crossCurrencyPayment.js
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 () => {

    try {
        await client.connect();
    
        const { issuerA, issuerB, alice, bob, charlie } = wallets;
    
        const payment = {
            TransactionType: "Payment",
            Account: charlie.address,
            Amount: { // ボブが受け取りたい通貨:A.USD
                currency: 'USD',
                issuer: issuerA.address,
                value: '100'
            },
            Destination: bob.address,
            SendMax: { // チャーリーが支払いたい通貨:B.EUR
                currency: 'EUR',
                issuer: issuerB.address,
                value: '100' // 限度額
            }
        };

        const result = await client.submitAndWait(payment, { charlie });

        console.log(result);
    } catch (error) {
        console.error(`Error in cross-currency payment: ${error}`);
    } finally {
        await client.disconnect();
    }
};

main();

まとめ

以上のステップを進めるだけで、クロスカレンシー送金が成立します。実際には複雑なクロスカレンシー送金を行うことも可能ですが、一番シンプルなパターンで紹介しました。

クロスカレンシー送金は、ネイティブDEXが存在するXRPL特有の機能であり、最も代表的な機能のひとつです。XRPLでは、それぞれ異なる発行者の通貨(トークン)だとしても、流動性さえ存在していれば、自分が支払いたい通貨で、相手が欲しい通貨として届けることができることができます。

個人的に学習を進める中では、クロスカレンシー送金についてはあまり具体的なフローとコードが存在しなかったため、比較的難易度が高かった印象ですので、これから学習する方はぜひ参考にしてみてください。

また、こちらの内容について、もう少し詳しく丁寧に知りたい方はぜひこちらの講座をご覧ください!

Discussion