⚠️

XRPLで独自トークンを発行・取り扱う際の注意点

2024/05/08に公開

L1のブロックチェーンであるXRP Ledger(XRPL)では、独自にトークンを発行する機能が備わっていますが、いくつか気がついた注意点があるので、その内容を紹介したいと思います。

https://xrpl.org/ja/docs/concepts/tokens/

その1:Rippling機能について

基本的には、XRPLで発行したトークン(IOU)は発行者以外のユーザー間ではやり取りすることができない仕様となっていますが、発行者アカウントのRippling機能を有効化することで、ユーザー間でトークンの送付の許可が可能な仕様となっています。

もちろん、トラストラインで繋がったユーザーと発行者とのみでトークンをやり取りできれば良いケースでは何も調整する必要はありません。

Ripplingについては、以下の記事などが参考になると思います。

https://zenn.dev/tequ/articles/xrpl-rippling

以下は、有効にするコードサンプルです。

const xrpl = require('xrpl'); // moduleを用いる場合は適宜調整ください

// リップリングを有効にする関数
async function enableRippling(walletSecret) {
    // Testnetへ接続
    const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233');
    await client.connect();

    try {
        // ウォレット情報をシークレットキーから作成する
        const issuerWallet = xrpl.Wallet.fromSecret(walletSecret);

        // リップリングを有効にするトランザクションを送信
        const response = await client.submitAndWait(
            {
                TransactionType: 'AccountSet', // AccountSetはアカウント情報を修正するトランザクションです
                Account: issuerWallet.address,
                SetFlag: xrpl.AccountSetAsfFlags.asfDefaultRipple, // Ripplingを許可する
                // ClearFlag: xrpl.AccountSetAsfFlags.asfDefaultRipple, // クリアする場合
            },
            {
                wallet: issuerWallet,
            }
        );

        // コンソールに結果を出力
        console.log('Transaction result:', response);
    } catch (error) {
        console.error('An error occurred:', error);
    }

    // 接続を閉じる
    await client.disconnect();
}

const walletSecret = 'wallet_secret_here'; // 発行者のアドレス
enableRippling(walletSecret);

wallet_secret_hereには、テストネットのアカウントシークレットキーを入力してください。

ポイントとしては、このRippling機能というのはアカウントに対していつでも変更が可能ということです。

この記事で伝えたいことのひとつとして、発行者アカウントのRippling機能を有効化する前に、ユーザーからトラストラインをセットされてしまった場合は、発行者視点からみたときに、NoRippleフラグが強制的にtrueになってしまうということがあります。

発行者のRippling機能が無効化されていたとしても、有効化時にトラストラインをセットしたユーザーは基本的にはトークンを送付する権限を持ってしまうため、発行者のRippling機能の設定についてはトークンを発行する前に決めておくべきだと思いました。

こういったことを踏まえると、発行者のアドレスをブラックホール化する必要が出てくる、ということにも繋がります。(供給量を固定にする必要がある場合は必須です)

https://xrpl.org/ja/docs/use-cases/tokenization/stablecoin-issuer/#バーン

その2:NoRippleフラグには気をつけよう

前述のとおり、発行者アカウントのRippling機能を有効化する前に、ユーザーからトラストラインをセットされてしまった場合は、NoRippleフラグが強制的にtrueになってしまい、Rippling機能を有効化したとしてもそのユーザーはトークンの送付が不可となったままです。

つまり、発行者からNoRippleフラグが有効化されているユーザーはトークンの送付ができません。

以下は、発行者視点でのトラストライン一覧を確認するコードサンプルです。

const xrpl = require('xrpl'); // moduleを用いる場合は適宜調整ください

async function checkAccountLines(accountAddress) {
    // Testnetに接続
    const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233');
    await client.connect();

    try {
        // account_lines コマンドを用いて確認
        const response = await client.request({
            command: 'account_lines', // コマンド
            account: accountAddress, // 確認したいアドレス
            ledger_index: 'validated', // 確実に検証済みのレジャーから取得する
        });

        // コンソールに結果を出力
        console.log('Account Lines:', response.result.lines);
    } catch (error) {
        console.error('Error retrieving account lines:', error);
    }

    // 接続を閉じる
    client.disconnect();
}

// 関数に引数としてアカウントアドレスを渡す
const issuerAddress = 'wallet_address_here'; // 発行者のアドレス
checkAccountLines(issuerAddress);

wallet_address_hereには、テストネットのアカウントアドレスを入力してください。

NoRippleフラグの状態を確認することができます。

Account Lines: [
    { // ユーザーA
        account: 'rQr8KfkCQcpqvFwmRspDoaL36reZhcdaeA',
        balance: '-1000', // ユーザーAに対しての債務
        currency: 'HOG',
        limit: '0',
        limit_peer: '10000',
        no_ripple: true, // No Rippleフラグ
        no_ripple_peer: false,
        quality_in: 0,
        quality_out: 0
    }
]

一度セットされてしまったNoRippleフラグは、あとから発行者のアカウントのRipplingを有効化しても自動的に変更されないので、もし必要であれば明示的に無効化する必要があります。

これは発行者のアカウントで紐づいている、ユーザーのNoRippleフラグを無効化するコードサンプルです。

const xrpl = require('xrpl');

async function disableNoRipple(
    wallet,
    trustLineCurrency,
    trustLineIssuer,
    trustLineLimit
) {
    // Testnetに接続
    const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233');
    await client.connect();

    try {
        // TrustSetトランザクションの作成
        const trustSetTx = {
            TransactionType: 'TrustSet',
            Account: wallet.address, // アリスまたはボブのアドレスが入ります
            LimitAmount: {
                currency: trustLineCurrency, // 通貨コード
                issuer: trustLineIssuer, // 発行者のアドレス(チャーリー)
                value: trustLineLimit, // 限度額(ここでは変更しない)
            },
            // NoRippleフラグを無効化
            Flags: xrpl.TrustSetFlags.tfClearNoRipple,
        };

        // トランザクションを送信し、結果を待つ
        const response = await client.submitAndWait(trustSetTx, { wallet });
        console.log('Transaction result:', response);
    } catch (error) {
        console.error('An error occurred:', error);
    }

    // 接続を閉じる
    await client.disconnect();
}

// 関数の実行
const currency = 'HOG'; // 通貨コード
const trustLineIssuer = 'user_wallet_address_here'; // ユーザーのアドレス
const limit = '0'; // 限度額(ここでは変更しない)

const issuerWallet = xrpl.Wallet.fromSecret('issuer_wallet_secret_here'); // 発行者のシークレットキー
disableNoRipple(issuerWallet, currency, trustLineIssuer, limit); // トラストライン情報を変更する
  1. user_wallet_address_hereには、テストネットのアドレスを入力してください。(ユーザーA)
  2. wallet_secret_hereには、テストネットのトークン発行者のシークレットキーを入力してください。

まとめ

XRPLのトークン機能の細かな注意点について紹介させていただきました。

執筆した背景としては、実際に開発していく中で、コンソールに表示されたフィールドフラグなどをひとつひとつ理解していく重要性を感じており、実際の運用上ではこういった細かい仕様を知っている必要があると思うからです。

また、この記事の内容は、XRPL道場初段編でも詳しく紹介しています!興味のある方は是非挑戦してみてください。

Discussion