XRPLで独自トークンを発行・取り扱う際の注意点
L1のブロックチェーンであるXRP Ledger(XRPL)では、独自にトークンを発行する機能が備わっていますが、いくつか気がついた注意点があるので、その内容を紹介したいと思います。
その1:Rippling機能について
基本的には、XRPLで発行したトークン(IOU)は発行者以外のユーザー間ではやり取りすることができない仕様となっていますが、発行者アカウントのRippling
機能を有効化することで、ユーザー間でトークンの送付の許可が可能な仕様となっています。
もちろん、トラストラインで繋がったユーザーと発行者とのみでトークンをやり取りできれば良いケースでは何も調整する必要はありません。
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機能の設定についてはトークンを発行する前に決めておくべきだと思いました。
こういったことを踏まえると、発行者のアドレスをブラックホール化する必要が出てくる、ということにも繋がります。(供給量を固定にする必要がある場合は必須です)
その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); // トラストライン情報を変更する
-
user_wallet_address_here
には、テストネットのアドレスを入力してください。(ユーザーA) -
wallet_secret_here
には、テストネットのトークン発行者のシークレットキーを入力してください。
まとめ
XRPLのトークン機能の細かな注意点について紹介させていただきました。
執筆した背景としては、実際に開発していく中で、コンソールに表示されたフィールド
やフラグ
などをひとつひとつ理解していく重要性を感じており、実際の運用上ではこういった細かい仕様を知っている必要があると思うからです。
Discussion