🚄

XRP Ledgerのペイメントチャネルを触ってみる

2023/09/14に公開

XRP Ledger とは

XRP LedgerはBitcoinやEthereumなどと同じ分散型のパブリックブロックチェーンです。PoWやPoSとは異なる独自のコンセンサスアルゴリズム(Proof of Association)が用いられています。
EVMによるスマートコントラクトは搭載しておらず、スマートトランザクタ(プロトコルネイティブで提供されている機能)を拡張することで進化し続けています。

DEXやNFTなどの機能だけでなく、エスくローやペイメントチャネル等の決済向けの高度な機能も備わっています。

ペイメントチャネル機能

ペイメントチャネルとは、送金の一部をオフチェーンにおいて処理し、後にオンレジャーでまとめて処理することで、オンレジャーでの処理コストを削減できる機能です。
XRP Ledgerの3~5秒のファイナリティを待つことなく、秒間数千~数万件の送金処理を可能とします。

XRP Ledgerメインネットではペイメントチャネル機能は2017年3月に有効化され利用可能となりました。

https://xrpscan.com/amendment/08DE7D96082187F6E6578530258C77FAABABE4C20474BDB82F04B021F1A68647

https://xrpl.org/ja/known-amendments.html#paychan

ペイメントチャネルに関するレジャーオブジェクト

次のPayChannelオブジェクトを使いペイメントチャネルの情報が表現されます。

https://xrpl.org/ja/paychannel.html

例えばペイメントチャネルの送信元と送信先、ペイメントチャネルで利用可能なXRP残高、送信済みのXRP残高、署名に利用する公開鍵などの情報があります。

ペイメントチャネルに関するトランザクションの種類

以下のようなトランザクションを利用することでペイメントチャネルが利用可能となっています。

PaymentChannelCreate

ペイメントチャネルを作成し、チャネルに資金を提供するトランザクションです。

https://xrpl.org/ja/paymentchannelcreate.html

PaymentChannelFund

送信者がチャネルに追加の資金を提供するトランザクションです。

https://xrpl.org/ja/paymentchannelfund.html

PaymentChannelClaim

受信者がチャネルから資金を請求するトランザクションです。送信者からオフチェーンで送信された署名情報を利用して請求を行います。
また、いくつかの条件に応じて送信者、受信者またはそれ以外の第三者によりペイメントチャネルを閉じることができます。

https://xrpl.org/ja/paymentchannelclaim.html

1. ペイメントチャネルを作成する

ペイメントチャネルを作成します。

import { Wallet, Client, xrpToDrops, signPaymentChannelClaim, verifyPaymentChannelClaim, PaymentChannelClaimFlags } from 'xrpl'

const client = new Client("wss://testnet.xrpl-labs.com")

const alice = Wallet.fromSeed('sEdVSH8WdY2na2kGWhytNbEti8ZEMkB') // testnet account
const bob = Wallet.fromSeed('sEdVh9tvzFuhxEc8uXhyyMdopG3sNtt') // testnet account 
const signature = Wallet.generate()


await client.connect()

// create channel
await client.submitAndWait({
  TransactionType: "PaymentChannelCreate",
  Account: alice.address,
  Destination: bob.address,
  Amount: xrpToDrops(1), // ペイメントチャネルの利用資金として1XRPを設定
  SettleDelay: 86400, // 24 * 60 * 60  チャネルに資金がある場合でも86400秒(=1日)後にチャネルを閉じることが可能になる
  PublicKey: signature.publicKey, // オフレジャーでの署名に利用する公開鍵
}, { wallet: alice })

2. ペイメントチャネルのIDを取得

account_channelsメソッドを使ってペイメントチャネルのIDを取得します。

const response = await client.request({
  command: 'account_channels',
  account: alice.address,
})
console.log(response.result.channels[0].channel_id)
const channel_id = response.result.channels[0].channel_id

PaymentChannelCreateトランザクションのメタデータ(PayChannelオブジェクトのLedgerIndexフィールド)から取得する方法もあります。

3. オフレジャーで署名を作成する。

ペイメントチャネルで利用する送金の署名を作成します。

xrpl.jsのsignPaymentChannelClaimを利用するとペイメントチャネル向けの署名が簡単に作成できます。

第二引数は送金するXRPの量です。drop建の量ではなくXRP建の量での指定が必要であることに注意してください。

const paychanSignature = signPaymentChannelClaim(channel_id, '1', signature.privateKey)
console.log(paychanSignature)

この署名情報は送信者によって作成され、PaymentChannelCreateトランザクションで設定して公開鍵に紐付く秘密鍵によって署名されなければいけません。

署名したデータはその他必要なデータとともに受信者へ送信する必要があります。

4. 署名を検証する。

送金の受取人は送信者から署名情報などを受け取った後、その署名情報が正しいかどうかを検証する必要があります。

検証には2パターンの方法があります。

パターン 1. xrpl.jsのverifyPaymentChannelClaimメソッドを利用する

対象となるチャネルID、送金されるXRPの量、署名情報、公開鍵を指定して検証を行います。
signPaymentChannelClaimと同じくXRP建の量での指定が必要です。

const verified = verifyPaymentChannelClaim(channel_id, '1', paychanSignature, signature.publicKey)

パターン 2. rippledのパブリックメソッドchannel_verifyを利用する

パターン1と指定する情報は代わりませんが、ノードとの通信が発生するため、パターン1に比べ遅延が発生します。

他のプログラム言語を使っており、検証メソッドがない場合などはこのメソッドを利用することが有効かもしれません。

const channelVerifyResponse = await client.request({
  command: 'channel_verify',
  amount: xrpToDrops(1),
  channel_id,
  public_key: signature.publicKey,
  signature: paychanSignature
})
const verified = channelVerifyResponse.result.signature_verified

5. 資金を請求する

PaymentChannelClaimトランザクションを利用してペイメントチャネルから資金を請求します。
これは送金の受取人または送金人により実行可能です。

Balanceフィールドには、このチャンネルでこれまで請求したXRPの額をdropで指定します。(今回の請求額を含む)
Amountフィールドには、このトランザクションで請求するXRPの額をdropで指定します。この額はSigunatureフィールドによって署名された額と一致している必要があります。

送金人はSigunaturePublicKeyフィールドを指定することなく資金を送金できます。

const response2 = await client.submitAndWait({
  TransactionType: "PaymentChannelClaim",
  Account: bob.address,
  Channel: channel_id,
  Balance: xrpToDrops(1),
  Amount: xrpToDrops(1),
  Signature: paychanSignature,
  PublicKey: signature.publicKey,
}, { wallet: bob })
console.log(response2.result)

6. ペイメントチャネルに資金を追加する

PaymentChannelFundトランザクションを利用してペイメントチャネルに資金を追加できます。

await client.submitAndWait({
  TransactionType: "PaymentChannelFund",
  Account: alice.address,
  Channel: channel_id,
  Amount: xrpToDrops(1),
}, { wallet: alice })

7. チャネルを閉じる

PaymentChannelClaimトランザクションはペイメントチャネルを閉じる場合にも利用できます。
FlagsフィールドにtfCloseを指定することでペイメントチャネルを閉じることができます。

const response3 = await client.submitAndWait({
  TransactionType: "PaymentChannelClaim",
  Account: bob.address,
  Channel: channel_id,
  Flags: PaymentChannelClaimFlags.tfClose,
}, { wallet: bob })
console.log(response3.result)

まとめ

XRP Ledgerではコントラクト開発を行うことなく、組み込みの機能でペイメントチャネルを利用可能です。

これによりコントラクトリスクを最小限に抑え、安く安全にペイメントチャネルを利用できます。

今回はJavaScriptライブライxrpl.jsを利用してペイメントチャネルを作成し、資金を追加し、資金を請求し、チャネルを閉じる方法を紹介しました。他にもPython向けのライブラリやJava向けのライブラリなども存在しているため、お好きな言語で試してみてください。

興味を持たれた方はXRP Ledger開発者のDiscordチャンネルへ是非お越しください!
日本語チャンネルもありますので、英語ができなくても大丈夫です!
https://xrpldevs.org

Discussion