最速でXRPLのクロスカレンシー送金をJavaScriptで試す方法
私が作成している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)
};
汎用的なメソッドを定義する
こちらの記事を参考にしていただき、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();
通貨(トークン)の発行
- アリスにA.USDとB.EURを発行します。
- ボブにA.USDを発行します。
- チャーリーに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.EUR
をA.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