🧐

XRP LedgerのMulti-Purpose Tokensとは?

2023/12/22に公開

はじめに

この記事はXLS-33dとして提案されているMulti-Purpose Tokens (MPT)を紹介するものです。

元々はCompact Fungible Token(CFT)として提案されていましたが、その後MPTと変更されています。

原文

この提案はまだ確定しているものではないため、今後変更される可能性があります。

1. Multi-Purpose Tokens (MPTs)

1.1. 概要

トラストラインは、CBDCフィアット担保ステーブルコインを含む、多くのXRP Ledgerのトークン化機能の基本的な構成要素です。しかし、より多くのトークン発行者がXRP Ledgerを採用するにつれて、各トラストラインの現在のサイズは、レジャーの安定性とスケーラビリティの障害となるでしょう。

本提案では、より多目的なトークン(MPT)をサポートするために、XRP Ledgerの拡張と、そのようなトークンの列挙、購入、売却、保持のための操作を導入します。

トラストラインとは異なり、MPTは双方向の債務関係を表すものではありません。その代わり、MPTは残高が1つしかない一方向のトラストラインのように機能します。そのため、一般的なトークン化の要件をサポートしやすくなり、オンライン・ゲームでの評価ポイントの追跡のような非貨幣的なユースケースもサポートできます。

しかし、おそらく同じくらい重要なのは、MPTはトラストラインよりもかなり少ないスペースしか必要としないということです。トラストラインは1つにつき 少なくとも 234バイトですが、MPTは1つにつき最大52バイトです。(詳細な比較は付録1をご覧ください)

1.1.1. メリットとデメリット

メリット

  • 浮動小数点表現の代わりに固定小数点での残高表現を使用しているため、次のような利点があります。
    • MPT 残高金額は、エスクロー、小切手、支払いチャネル、AMMなどの他のレジャーオブジェクトに簡単に追加できます。
    • 信頼性が高く、簡単に不変チェックを実施し、手数料を簡単に追跡できます。
    • 期待される等式条件に違反する非常に少額の浮動小数点演算のエッジケースを排除(例えば、MPTは、非ゼロのBに対してA+B=Aや、(A+B)+C != A+(B+C)のようなケースを扱う必要がありません)。
  • よりシンプルな概念モデル(トラストラインとリップリングは開発者がシステムを推論することを難しくし、エラーや価値損失のリスクを高めます)。
  • より少ないコストでより多くのトークンを保持するためのより多くのアカウントを可能にするトラストラインのストレージ要件を削減します。
  • ノードオペレータの長期的なインフラとストレージの負担を軽減し、ネットワークの回復力を高めます。
  • 大量のMPTトランザクションを処理する際のノードパフォーマンスの向上。

デメリット

  • MPTはXRPとIOUに続く第三の資産タイプをレジャーに導入することになり、ペイメントエンジンの実装が複雑になります。
  • 新しい取引やデータ型は、クライアントライブラリやウォレットが読み取り、表示、取引するための新しい実装コードを必要とします。
  • MPTは、トラストライン(トラストラインは、およそ10^-96から10^-80の間の膨大な範囲を表すことができます)と比較して、全体的な残高額が小さくなります。

1.1.2. 前提

この提案では、データを最もコンパクトに表現するために、既存のトラストラインの使用状況の観測に基づき、さまざまな前提を置いています。これらの仮定には以下が含まれます。

  1. 単方向のみ: ほとんどのトークン発行者は、トラストラインの上限をデフォルトの0に設定している(つまり、発行者はデフォルトでトークン保有者との債務関係を許可していない)ことを前提として、本提案では双方向のトラストライン構築をサポートしません。従って、MPTには、トラストラインに見られるような「残高相殺」の機能はありません。なぜなら、トラストラインでは2つの残高があるのに対し、MPTでは1つの残高しかないからです。
  2. 発行体ごとの発行数が少ない: 最も一般的なトークンの例では、規制のオーバーヘッドを伴うため、一般的なケースでは、発行者が多くのトークンを発行することはあまりありません。さらに、既存のxrpl.orgに関するガイダンスでは、グローバルフリーズの行動に対応するため、トークン発行者はトークン発行ごとに異なるアドレスを使用するようアドバイスしています。このため、個々の発行者が同じアドレスを使用して多くの異なるトークンを発行することはないと想定しています。特に、この仕様では、1つの発行アカウントにつき、ユニークなMPTの発行数を32個に制限しています。発行者がこの数以上のMPTをサポートしたい場合、追加のアドレスを使用することができます。
  3. トラスト上限なし: 現在のトラストラインの機能では、どちらか一方の当事者によってトラスト量の上限を設定することができますが、この提案では、トークン保有者が最初にオフレジャーのトラスト決定を行わずにMPTを取得することはないという前提の下、この機能を排除します。例えば、MPT の一般的なユースケースは、法定通貨を裏付けとするステーブルコインであり、トークン保有者は、自分が安心して保有できる以上のステーブルコインを購入することはないでしょう。
  4. リップリングなし: 既存のレジャーのいくつかの機能とは異なり、MPTはリップリングの対象ではないため、その機能に関する設定もありません。

1.1.3 リリーススケジュールと範囲

XLS-33では、MPTの新しいデータ構造の追加、ユーザがMPTからMPTへの支払いを行えるようにするための Payment トランザクションとの統合(つまり、異なる種類の通貨をまたいだ支払いはできません)、アカウント削除に関する新しい要件(後述)のような他のいくつかの付随的な追加のみをカバーする予定です。今後のAmendmentでは、MPTをDEXなどXRPLの他の機能と統合する予定です。

1.2. Multi-Purpose Tokenの作成

1.2.1. オンレジャーのデータ構造

2つの新しいオブジェクトと1つの新しいレジャー構造を提案します。

  1. MPTokenIssuance は、発行者が作成したトークンを定義する新しいオブジェクトです。
  2. MPToken は、ひとつのアカウントが保有するトークンを表す新しいオブジェクトです。

1.2.1.1. MPTokenIssuance オブジェクト

MPTokenIssuance オブジェクトはMPTの発行を表し、発行そのものに関連するデータを保持します。トークンは MPTokenIssuanceCreate トランザクションで作成され、オプションで MPTokenIssuanceDestroy トランザクションで破棄することができます。

1.2.1.1.1. MPTokenIssuance のレジャー識別子

MPTokenIssuanceオブジェクトのキーは、以下の値のSHA512-Halfを順番に連結したものです。

  • MPTokenIssuanceスペースキー(0x007E)。
  • トランザクションのシーケンス番号。
  • 発行者のAccountID。

MPTokenIssuanceオブジェクトのID(別名MPTokenIssuanceID)は192ビットの整数で、順番に連結されます。

  • トランザクションのシーケンス番号。
  • 発行者のAccountID。
┌──────────────────────────┐┌──────────────────────────┐
│                          ││                          │
│      シーケンス            ││     発行者のAccountID     │
│      (32 bits)           ││        (160 bits)        │
│                          ││                          │
└──────────────────────────┘└──────────────────────────┘

注記: MPTokenIssuanceIDは、ユーザーがインターフェイスに入力するものです。内部的には、レジャーはMPTokenIssuanceIDsequenceissuerアドレスの2つの要素に分割します。

1.2.1.1.2. フィールド

MPTokenIssuance オブジェクトはレジャーに保存され、発行者が所有するオーナーディレクトリで追跡されます。発行には、以下の必須フィールドとオプショナルフィールドがあります。

フィールド名 必須? JSONの型 内部の型
LedgerEntryType number UINT16
Flags number UINT32
Issuer string ACCOUNTID
AssetScale (default) number UINT8
MaximumAmount string UINT64
OutstandingAmount string UINT64
LockedAmount ️(default) string UINT64
TransferFee ️(default) number UINT16
MPTokenMetadata string BLOB
PreviousTxnID string HASH256
PreviousTxnLgrSeq ️✅ number UINT32
OwnerNode (default) number UINT64
Sequence number UINT32
1.2.1.1.2.1. LedgerEntryType

0x007Eは文字列MPTokenIssuanceにマッピングされ、このオブジェクトが多目的トークン(MPT)であることを示します。

1.2.1.1.2.2. Flags

この MPTokenIssuance オブジェクトに関連付けられたプロパティやその他のオプションを示すフラグのセットです。型特有のフラグを指定します。

フラグ名 フラグ値 説明
lsfMPTLocked 0x0001 設定されている場合、すべての残高がロックされていることを示します。
lsfMPTCanLock 0x0002 設定されている場合、発行者がこのMPTの個々の残高またはすべての残高をロックできることを示します。設定されていない場合、MPTはいかなる方法でもロックできません。
lsfMPTRequireAuth 0x0004 設定されている場合、_ 個々の_ 保有者が認可されなければならないことを示します。これにより、発行者は資産を保有できる人を制限することができます。
lsfMPTCanEscrow 0x0008 設定されている場合、個々の保有者が残高をエスクローに預けることができることを示します。
lsfMPTCanTrade 0x0010 設定されている場合、XRP LedgerのDEXまたはAMMを使用して、 個々の 保有者が残高を取引できることを示します。
lsfMPTCanTransfer 0x0020 設定されている場合、発行者以外が保有するトークンを他のアカウントに転送できることを示します。設定されていない場合、発行者以外が保有するトークンは発行者に返却する以外には転送できないことを示します。
lsfMPTCanClawback 0x0040 設定されている場合、発行者がClawbackトランザクションを使用して、個々の 保有者から価値を取り戻すことができることを示します。

MPTokenIssuanceSetトランザクションで変更できるlsfMPTLockedを除き、これらのフラグは変更不可です。MPTokenIssuanceCreateトランザクションでのみ設定でき、後で変更することはできません。

1.2.1.1.2.3. Issuer

特定のトークンの発行量と性質を管理するアカウントのアドレス。

1.2.1.1.2.4. AssetScale

資産スケールとは、標準単位と対応する分数単位との間の桁数の差のことです。より正式には、資産スケールは、1つの標準単位が対応する端数単位の10^(-スケール)に等しくなるような非負整数(0, 1, 2, ...)です。端数単位が標準単位に等しい場合、資産スケールは0です。

1.2.1.1.2.5. MaximumAmount

この値はMPTを発行していないアカウント(つまりminted)に配布できる最大数を指定する符号なし数値です。最大数を持たない発行の場合、この値は0xFFFFFFFFFFFFFFに設定されます。

1.2.1.1.2.6. OutstandingAmount

すべてのトークン保有者に発行されたすべてのトークンの金額の合計を指定します。この値はdefault型としてレジャーに保存することができます。この値は、発行者が非発行者アカウントにMPTを支払うたびに増加し、非発行者が発行者アカウントにMPTを支払うたびに減少します。

1.2.1.1.2.7. TransferFee

この値は、トークンの二次売買が許可されている場合に、発行者がその二次売買に課す手数料を、basis pointの10分の1で指定します。このフィールドの有効な値は0から50,000です。1の値は1/10 basis pointまたは0.001%に相当し、0%から50%の間の送金手数料を設定することができます。50,000のTransferFeeは50%に相当します。送金手数料の小数点以下は切り捨てられるため、支払いが少額の場合は手数料をゼロに切り捨てることができます。発行者はMPTのAssetScaleが十分大きいことを確認してください。

1.2.1.1.2.8. PreviousTxnID

このオブジェクトを最も最近変更したトランザクションのトランザクションIDを表します。

1.2.1.1.2.9. PreviousTxnLgrSeq

このオブジェクトを最近変更したトランザクションを含むレジャーのシーケンス番号を表します。

1.2.1.1.2.10. OwnerNode

このアイテムが参照されているオーナーディレクトリのページを表します。

1.2.1.1.2.11. Sequence

MPTokenIssuanceの識別子で、MPTokenIssuanceIDを作成するために使用します。

1.2.1.1.3. Example MPTokenIssuance JSON
{
    "LedgerEntryType": "MPTokenIssuance",
    "Flags": 131072,
    "Issuer": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
    "AssetScale": "2",
    "MaximumAmount": "100000000",
    "OutstandingAmount": "5",
    "TransferFee": 50000,
    "MPTokenMetadata": "",
    "OwnerNode": "74"
}
1.2.1.1.4. MPTokenIssuance オブジェクトはどのように機能しますか?

どのアカウントでも、任意の数の多目的トークンを発行できます。

1.2.1.1.4.1. MPTokenIssuance オブジェクトの検索

MPTokenIssuanceオブジェクトは、タイプ固有の接頭辞、発行者アドレス、およびトランザクションシーケンス番号の組み合わせによって一意に識別されます。特定の MPTokenIssuance を見つけるには、まず発行者のオーナーディレクトリを検索します。次にMPTokenIssuanceのレジャーオブジェクトを保持しているディレクトリを見つけ、各エントリを繰り返し検索して目的のキーを持つインスタンスを見つけます。そのエントリが存在しない場合、 MPTokenIssuance は指定されたアカウントに存在しません。

1.2.1.1.4.2. MPTokenIssuance オブジェクトの追加

MPTokenIssuance オブジェクトを追加するには、同じ方法で MPTokenIssuance を見つけ、そのディレクトリに追加します。追加後、ディレクトリ内のMPTの数が32を超えるようであれば、その操作は失敗しなければなりません。

1.2.1.1.4.3. MPTokenIssuance オブジェクトの削除

MPTokenIssuance も同じ方法で削除することができますが、 OutstandingAmount が0に等しい場合に限ります。

1.2.1.1.4.4. MPTokenIssuance オブジェクトの準備金

それぞれの MPTokenIssuance には、オーナーアカウントへの準備金の増分がかかります。

1.2.1.2. MPToken オブジェクト

MPToken オブジェクトはトークン発行者ではないアカウントが保有するトークンの量を表します。MPTは通常のPaymentまたはDEXトランザクションによって得られるもので、任意でこれらの同じタイプのトランザクションを使用して償還または交換することができます。MPTokenのオブジェクトキーは、スペースキー、保有者のアドレス、およびMPTokenIssuanceIDをハッシュして生成されます。

1.2.1.2.1. MPToken のレジャー識別子

MPTokenオブジェクトのID(別名MPTokenID)は、以下の値のSHA512-Halfを順番に連結したものです。

  • MPTokenスペースキー(0x0074)。
  • 保有するトークンのMPTokenIssuanceID
  • トークン保有者のAccountID
1.2.1.2.2. フィールド

MPToken オブジェクトは以下のフィールドを持つことができます。各MPTokenのキーはMPTokenを保持するアカウントのオーナーディレクトリに格納されます。

フィールド名 必須? JSONの型 内部の型
LedgerEntryType number UINT16
Account string ACCOUNTID
MPTokenIssuanceID string UINT192
MPTAmount string UINT64
LockedAmount default string UINT64
Flags default number UINT32
PreviousTxnID string HASH256
PreviousTxnLgrSeq number UINT32
OwnerNode default number UINT64
MPTokenNode default number UINT64
1.2.1.2.2.1. LedgerEntryType

0x007Fは文字列MPTokenにマップされ、このオブジェクトが個々のアカウントがMPTを保有を表します。

1.2.1.2.2.2. Account

MPTokenの所有者を表します。

1.2.1.2.2.3. MPTokenIssuanceID

MPTokenIssuance`の識別子を表します。

1.2.1.2.2.4. MPTAmount

この値は、オーナーが現在保持しているトークンの正の量を指定します。このフィールドの有効な値は、0x0から0xFFFFFFFFFFFFの間です。

1.2.1.2.2.5. LockedAmount

この値は、トークン保有者のアカウントに現在保有されているが、トークン保有者が使用することができないトークンの量を指定します。ロックされたトークンは、例えば、現在エスクローで保持されている値や、トークン保持者がアクセスできない値を表します。

この値は、空のMPTを保持するためのレジャーのスペースを節約するために、デフォルト値として0が格納されます。

1.2.1.2.2.6. Flags

この MPTokenIssuance オブジェクトに関連付けられたプロパティやその他のオプションを示すフラグのセットです。型固有のフラグを表します。

フラグ名 フラグ値 説明
lsfMPTLocked 0x0001 このフラグがセットされている場合、このアカウントが所有するMPTは現在ロックされており、発行者に値を送り返す以外のXRPトランザクションでは使用できないことを示します。このフラグがセットされている場合、LockedAmountMPTAmount と等しくなければなりません。
lsfMPTAuthorized 0x0002 (許可されている場合にのみ適用可能)セットされていれば、発行者がMPTの所持者を認可したことを示します。このフラグはMPTokenAuthorizeトランザクションを使用して設定することができ、tfMPTUnauthorizeフラグを指定したMPTokenAuthorizeトランザクションを使用して「設定解除」することもできます。
1.2.1.2.2.7. PreviousTxnID

このオブジェクトを最も最近変更したトランザクションのトランザクションIDを表します。

1.2.1.2.2.8. PreviousTxnLgrSeq

このオブジェクトを最近変更したトランザクションを含むレジャーのシーケンス番号を表します。

1.2.1.2.2.9. OwnerNode

このアイテムが参照されているオーナーディレクトリのページを表します。

1.2.1.2.2.10. MPTokenNode

MPTディレクトリはOwner Directoryとまったく同じ構造をしていますが、1つのMPTokenIssuanceに対してMPTokensだけをインデックスする新しいタイプのディレクトリです。このディレクトリの所有権については、MPTokenNodeディレクトリで引き続き議論されます。

1.2.1.2.3. MPTokenのJSON例
{
    "LedgerEntryType": "MPToken",
    "Account": "rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG",
    "MPTokenIssuanceID": "00070C4495F14B0E44F78A264E41713C64B5F89242540EE255534400000000000000",
    "Flags": 0,
    "MPTAmount": "100000000",
    "LockedAmount": "0",
    "OwnerNode": 1,
    "MPTokenNode": 1
}
1.2.1.2.4. MPToken オブジェクトの準備金

それぞれの MPToken は、所有者アカウントに増分準備金を必要とします。

1.3 トランザクション

本提案では、MPT発行の作成と削除を可能にするために、いくつかの新しいトランザクションを導入します。同様に、本提案では、MPTの個別のインスタンスを作成および償還するための新しいトランザクションをいくつか導入します。本提案で導入されるすべてのトランザクションは、すべてのトランザクションで共有される共通トランザクションフィールドを組み込んでいます。共通フィールドは、本提案がそのようなフィールドに新しい可能な値を導入するため、必要でない限り、本提案では文書化されません。

1.3.1 XRPLにおける多目的トークンの作成と破棄のためのトランザクション

MPT発行に関連する3つのトランザクションを定義します。
MPTokenIssuanceCreateMPTokenIssuanceDestroyMPTokenIssuanceSet で、それぞれXRPL上でMPT Issuance を作成、破棄、更新します。

1.3.1.1 MPTokenIssuanceCreate トランザクション

MPTokenIssuanceCreate トランザクションは MPTokenIssuance オブジェクトを作成し、作成者アカウントの関連するディレクトリノードに追加します。このトランザクションはissuerが不変と定義されているトークンのフィールド(MPTフラグなど)を指定する唯一の手段です。

トランザクションが成功すると、新しく作成されたトークンはトランザクションを実行したアカウント(作成者アカウント)が所有することになります。

1.3.1.1.1 トランザクションのフィールド
フィールド名 必須? JSONの型 内部の型
TransactionType ️ ✅ object UINT16

新しいトランザクションタイプ MPTokenIssuanceCreate を表します。

フィールド名 必須? JSONの型 内部の型
AssetScale number UINT8

アセットスケールとは、標準単位と対応する分数単位との間の桁数の差のことです。より正式には、資産スケールは非負の整数(0, 1, 2, ...)で、1つの標準単位が対応する端数単位の10^(-1*スケール)に相当します。端数単位が標準単位と等しい場合、資産スケールは0となります。この値はオプションであり、指定しなかった場合のデフォルトは0となることに注意してください。

フィールド名 必須? JSONの型 内部の型
Flags number UINT16

このトランザクションのフラグを指定します。すべてのトランザクションに適用される共通のトランザクションフラグ(tfullyCanonicalSigなど)に加えて、以下のトランザクション固有のフラグが定義され、トークンの適切なフィールドを設定するために使用されます。

フラグ名 フラグ値 説明
lsfMPTLocked 0x0001 設定されている場合、すべての残高がロックされていることを示します。
lsfMPTCanLock 0x0002 設定されている場合、発行者がこのMPTの個々の残高またはすべての残高をロックできることを示します。設定されていない場合、MPTはいかなる方法でもロックできません。
lsfMPTRequireAuth 0x0004 設定されている場合、_ 個々の_ 保有者が認可されなければならないことを示します。これにより、発行者は資産を保有できる人を制限することができます。
lsfMPTCanEscrow 0x0008 設定されている場合、個々の保有者が残高をエスクローに預けることができることを示します。
lsfMPTCanTrade 0x0010 設定されている場合、XRP LedgerのDEXまたはAMMを使用して、 個々の 保有者が残高を取引できることを示します。
lsfMPTCanTransfer 0x0020 設定されている場合、発行者以外が保有するトークンを他のアカウントに転送できることを示します。設定されていない場合、発行者以外が保有するトークンは発行者に返却する以外には転送できないことを示します。
lsfMPTCanClawback 0x0040 設定されている場合、発行者がClawbackトランザクションを使用して、個々の 保有者から価値を取り戻すことができることを示します。
フィールド名 必須? JSONの型 内部の型
TransferFee number UINT16

この値は、トークンの二次売買が許可されている場合に、発行者が請求する手数料を指定します。このフィールドの有効な値は0から50,000の間で、0.001刻みで0.000%から50.000%の転送レートを許容します。

tfMPTCanTransferフラグが設定されていない場合、このフィールドは存在してはなりません(MUST NOT)。もし設定されていれば、そのトランザクションは失敗します。

フィールド名 必須? JSONの型 内部の型
MaximumAmount string UINT64

このトークンの発行可能な最大資産額。

フィールド名 必須? JSONの型 内部の型
MPTokenMetadata string BLOB

このトークンに関する任意のメタデータ。このフィールドの上限は1024バイトです。

1.3.1.1.2 MPTokenIssuanceCreate トランザクションの例
{
  "TransactionType": "MPTokenIssuanceCreate",
  "Account": "rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG",
  "AssetScale": "2",
  "TransferFee": 314,
  "MaxAmount": "50000000",
  "Flags": 83659,
  "MPTokenMetadata": "FOO",
  "Fee": 10
}

このトランザクションは、トークンの発行者がトランザクションの署名者であることを前提としています。

1.3.2 MPTokenIssuanceDestroy トランザクション

MPTokenIssuanceDestroy トランザクションは、 MPTokenIssuance オブジェクトを保持しているディレクトリノードから削除するために使用されます。

この操作が成功すると、対応する MPTokenIssuance が削除され、所有者の準備金が1つ減ります。該当するMPTの所有者がいる場合、この操作は失敗しなければなりません。

1.3.2.1 トランザクションのフィールド

フィールド名 必須? JSONの型 内部の型
TransactionType string UINT16

新しいトランザクション・タイプ MPTokenIssuanceDestroy を表します。

フィールド名 必須? JSONの型 内部の型
MPTokenIssuanceID string UINT192

トランザクションによって削除される MPTokenIssuance オブジェクトを表します。

1.3.2.2 MPTokenIssuanceDestroy のJSON例

{
      "TransactionType": "MPTokenIssuanceDestroy",
      "Fee": 10,
      "MPTokenIssuanceID": "00070C4495F14B0E44F78A264E41713C64B5F89242540EE255534400000000000000"
}

1.3.3 MPTokenIssuanceSet トランザクション

1.3.3.1 MPTokenIssuanceSet

フィールド名 必須? JSONの型 内部の型
TransactionType ️ ✅ object UINT16

新しいトランザクション・タイプ MPTokenIssuanceSet を表します。

フィールド名 必須? JSONの型 内部の型
MPTokenIssuanceID string UINT192

MPTokenIssuanceの識別子を表します。

フィールド名 必須? JSONの型 内部の型
MPTokenHolder string ACCOUNTID

ロック/アンロックする個々のトークン保有者の残高のオプションのXRPLアドレス。省略された場合、このトランザクションはMPTを保持するすべてのアカウントに適用されます。

フィールド名 必須? JSONの型 内部の型
Flag string UINT64

1.3.3.2 MPTokenIssuanceSet のJSON例

{
      "TransactionType": "MPTokenIssuanceSet",
      "Fee": 10,
      "MPTokenIssuanceID": "00070C4495F14B0E44F78A264E41713C64B5F89242540EE255534400000000000000",
      "Flags": 1
}

1.3.3.1.1 MPTokenIssuanceSetのフラグ

MPTokenLock のトランザクションでは、以下のようにFlagsフィールドに追加の値を指定することができます。

フラグ名 フラグ値 説明
tfMPTLock 0x0001 設定されている場合、この資産のすべてのMPT残高をロックすることを表します。
tfMPTUnlock 0x0002 設定されている場合、この資産のすべてのMPT残高をアンロックすることを表します。

1.3.4 Payment トランザクション

既存のPaymentトランザクションには新しいトップレベルフィールドやフラグは追加されません。しかし、既存のamountフィールドをMPTの金額に対応するように拡張します。

1.3.4.1 amountフィールド

現在、金額フィールドは2つの形式のいずれかをとります。下記は1ドロップのXRPを表しています。

"amount": "1"

以下は、1米ドルの金額を表しています。

"amount": {
  "issuer": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
  "currency": "USD",
  "value": "1"
}

MPTの金額については、以下のフォーマットを使用することを提案します。

"amount": {
  "mpt_issuance_id": "00070C4495F14B0E44F78A264E41713C64B5F89242540EE255534400000000000000",
  "value": "1"
}

注: MPTokenIssuanceIDは、支払いトランザクション中にMPTを一意に識別するために使用されます。

1.3.5 MPTokenAuthorize トランザクション

このトランザクションにより、アカウントは特定のMPT額を保持できるようになります。このトランザクションが正常に適用されると、初期残高がゼロのMPTokenオブジェクトが作成されます。

発行者がMPTokenIssuancelsfMPTRequireAuth(許可リスト)を設定している場合、発行者はホルダーに許可を与えるためにMPTokenAuthorizeトランザクションも送信する必要があります。lsfMPTRequireAuthが設定されておらず、発行者がこのトランザクションを送信しようとすると失敗します。

1.3.5.1 MPTokenAuthorize

フィールド名 必須? JSONの型 内部の型
Account string ACCOUNTID

このアドレスは、MPTの発行者または潜在的な保有者のいずれかを表します。

フィールド名 必須? JSONの型 内部の型
TransactionType ️ ✅ object UINT16

新しいトランザクションタイプ MPTokenAuthorize` を表します。

フィールド名 必須? JSONの型 内部の型
MPTokenIssuanceID string UINT192

当該 MPT の ID を表します。

フィールド名 必須? JSONの型 内部の型
MPTokenHolder string ACCOUNTID

発行者が認可したい保有者のアドレスを指定します。認可/許可リストにのみ使用されます。保有者から送信された場合は空でなければなりません。

フィールド名 必須? JSONの型 内部の型
Flag string UINT64

1.3.3.5.12 MPTokenAuthorizeのフラグ

MPTokenAuthorizeのトランザクションでは、次のようにFlagsフィールドに追加の値を指定できます。

フラグ名 フラグ値 説明
tfMPTUnauthorize 0x0001 このフラグが設定され、ホルダーからトランザクションが送信された場合、そのホルダーはMPTokenを保持したくないことを示し、結果としてMPTokenは削除されます。このフラグをセットしようとしているときに、保有者のMPTokenの残高がゼロでない場合、トランザクションは失敗します。一方、このフラグが設定された状態でトランザクションが発行者から送信された場合、発行者は保有者の承認を解除したいことを意味します(保有許可にのみ適用されます)。

1.3.6 AccountDelete トランザクション

AccountDeleteトランザクションの構造に変更はありません。ただし、MPTokenIssuanceを持つアカウントは削除できません。これらのアカウントは、アカウントを削除する前に、まずMPTokenIssuanceDestroyを使用してMPTokenIssuanceを破棄する必要があります。この制限(または同様の制限)がないと、発行者はMPTの残高をどの保有者にとっても無意味/不安定なものにしてしまう可能性があります。

1.4.0 MPTのロックの詳細

1.4.0.1 個々の残高のロック

個々のMPTの個々の残高をロックするには、発行者はMPTokenIssuanceSetトランザクションを送信し、ロックしたいMPTと保有者のアカウントを示し、tfMPTLockフラグを設定します。以下の場合、この操作は失敗します。

  • MPTにlsfMPTCanLockフラグが設定されていない場合。

発行者はtfMPTUnlockフラグをセットした別のMPTokenIssuanceSetトランザクションを送信することで、残高のロックを解除できます。

1.4.0.2 全てのMPTをロック

この操作は、ロックまたはアンロック時にMPTokenIssuanceSetトランザクションで所有者アカウントが指定されないことを除いて、上記と同じように動作します。以下の場合、この操作は失敗します。

  • MPTの発行者のアカウントにlsfMPTCanLockフラグが設定されていない場合。

発行者が発行した他の資産をロックせずにMPT全体をロックすることは、MPTの新しい機能です。

1.5.0 MPTのClawbackの詳細

MPT保有者から資金をクローバックするには、発行者はMPTokenIssuanceCreateトランザクションを使用してMPTを作成するときにtfMPTCanClawbackフラグを設定することで、MPTがクローバックを許可していることを指定する必要があります。このフラグが設定されたMPTが作成されたと仮定すると、クローバックはClawbackトランザクションを使用して許可されます(このトランザクションが新しい値に対応するためにどのように変更されるかについての詳細は後述します)。

1.6.0 API

この機能のためにいくつかの新しいAPIを提案します。すべての新しいAPIはclioでのみ利用可能です。

1.6.0.1 mpts_by_issuer

指定されたアカウントとレジャーに対して、削除されたMPTokenIssuancesを含め、そのアカウントが作成したすべてのMPTokenIssuanceが表示されます。削除されたMPTokenIssuanceは、新しいMPTokenIssuanceと同じIDを持つ可能性があります。

1.6.0.1.1 リクエストのフィールド
{
  "command": "mpts_by_isssuer",
  "issuer": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
  "ledger_index": "validated",
  "include_deleted": true
}
フィールド名 必須? JSONの型
issuer string

MPTを照会したいMPT発行者を示します。

フィールド名 必須? JSONの型
ledger_index string または number (正の整数)

使用する最大のレジャーインデックス、またはレジャーを自動的に選択するためのショートカット文字列。ledger_indexまたはledger_hashのどちらかを指定する必要があります。

フィールド名 必須? JSONの型
ledger_hash string

使用する最大レジャーバージョンを表す20バイトの16進文字列。ledger_indexまたはledger_hashのどちらかを指定する必要があります。

フィールド名 必須? JSONの型
include_deleted boolean

デフォルトはfalseです。もしtrueなら、削除されたMPTも含まれます。

フィールド名 必須? JSONの型
marker string

ページ分割の際に、前回終了したところからクエリを続行するために使用します。

フィールド名 必須? JSONの型
limit number (正の整数)

返される MPT の数の上限を指定します。

1.6.0.1.2 レスポンスのフィールド
{
    "id": 5,
    "status": "success",
    "type": "response",
    "result": {
        "mpt_issuances": [
           {
             "MPTokenIssuanceID": "00070C4495F14B0E44F78A264E41713C64B5F89242540EE255534400000000000000",
             "Flags": 83659,
             "Issuer": ......,
             "AssetScale": .....,
             "MaximumAmount": .....,
             "OutstandingAmount": ....,
             "LockedAmount": .....,
             "TransferFee": .....,
             "MPTokenMetadata": ....,
             "ledger_index": 11231
           }
        ],
        "validated": true
    }
}
フィールド名 JSONの型
mpt_issuances array

指定したアカウントが作成したMPTokenIssuanceオブジェクトの配列。既存の基本オブジェクトのすべてのフィールド、このMPTが最後に変更されたインデックスのledger_indexを含みます。削除されたオブジェクトの場合は、このMPTが削除されたインデックスのMPTokenIssuanceIDdeleted_ledger_indexだけが表示されます。

フィールド名 JSONの型
marker string

ページ分割の際に、中断したところからクエリを続行するために使用されます。この結果の後に項目がない場合は省略されます。

1.6.0.2 account_mpts

指定されたアカウントとレジャーに対して、account_mptsはそのアカウントが保持しているすべてのMPTの残高を返します。

1.6.0.2.1 リクエストのフィールド
{
  "command": "account_mpts",
  "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
  "ledger_index": "validated"
}
フィールド名 必須? JSONの型
account string

MPT 残高を照会するアカウントを表します。

フィールド名 必須? JSONの型
ledger_index string または number (正の整数)

使用する最大のレジャーインデックス、またはレジャーを自動的に選択するためのショートカット文字列。ledger_indexまたはledger_hashのどちらかを指定する必要があります。

フィールド名 必須? JSONの型
ledger_hash string

デフォルトはfalseです。もしtrueなら、削除されたMPTも含まれます。

フィールド名 必須? JSONの型
marker string

ページ分割の際に、前回終了したところからクエリを続行するために使用します。

フィールド名 必須? JSONの型
limit number (正の整数)

返されるMPTの数の上限を指定します。

1.6.0.2.2 レスポンスのフィールド
{
    "id": 5,
    "status": "success",
    "type": "response",
    "result": {
        "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
        "mpts": [
           {
             "MPTokenIssuanceID": "00070C4495F14B0E44F78A264E41713C64B5F89242540EE255534400000000000000",
             "Flags": 83659,
             "MPTAmount": "1000",
             "LockedAmount": "0"
           }
        ],
        "validated": true
    }
}
フィールド名 JSONの型
mpts array

指定したアカウントが所有するMPTokenオブジェクトの配列。基礎となるオブジェクトのすべてのフィールドを含みます。

フィールド名 JSONの型
marker string

ページ分割の際に、中断したところからクエリを続行するために使用されます。この結果の後に項目がない場合は省略されます。

1.6.0.3 mpt_holders

与えられたMPTokenIssuanceIDとレジャーシーケンスに対して、mpt_holdersはそのMPTのすべての保有者とその残高を返します。このAPIは非常に大きなデータセットを返すので、ユーザはmarkerフィールドを使用してページングを実装する必要があります。

1.6.0.3.1 リクエストのフィールド
{
  "command": "mpt_holders",
  "mpt_id": "00070C4495F14B0E44F78A264E41713C64B5F89242540EE255534400000000000000",
  "ledger_index": "validated"
}
フィールド名 必須? JSONの型
mpt_id string

照会したい MPTokenIssuance を表します。

フィールド名 必須? JSONの型
ledger_index stringまたはnumber(正の整数)

使用する最大のレジャーインデックス、またはレジャーを自動的に選択するためのショートカット文字列。ledger_indexまたはledger_hashのどちらかを指定する必要があります。

フィールド名 必須? JSONの型
ledger_hash string

デフォルトは false です。もし true なら、削除された MPT も含まれます。

フィールド名 必須? JSONの型
marker string

ページ分割の際に、前回終了したところからクエリを続行するために使用します。

フィールド名 必須? JSONの型
limit number (正の整数)

返されるMPTの数の上限を指定します。

1.6.0.3.2 レスポンスのフィールド
{
    "id": 5,
    "status": "success",
    "type": "response",
    "result": {
        "mpt_id": "00070C4495F14B0E44F78A264E41713C64B5F89242540EE255534400000000000000",
        "mpt_holders": {
          "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn": {
             "MPTokenIssuanceID": "00070C4495F14B0E44F78A264E41713C64B5F89242540EE255534400000000000000",
             "Flags": 83659,
             "MPTAmount": "1000",
             "LockedAmount": "0"
          }
        },
        "validated": true
    }
}
フィールド名 JSONの型
mpt_id string

照会した MPTokenIssuance を表します。

フィールド名 JSONの型
mpt_holders object

MPTokenオブジェクトのアカウントの辞書を表すJSONオブジェクト。基礎となるMPTokenオブジェクトのすべてのフィールドを含みます。

フィールド名 JSONの型
marker string

ページ分割の際に、中断したところからクエリを続行するために使用されます。この結果の後に項目がない場合は省略されます。

2. 付録

2.1 付録: FAQs

2.1.1. MPTはトラストラインとは違うのですか?

はい、MPTはトラストラインとは異なります。詳しくは1.1.2節をご覧ください。

とはいえ、両者の機能には重複する部分もあります。例えば、MPTもTrustlinesもステーブルコインを発行するために使うことができます。しかし、MPTとトラストラインの背後にある本来の意図は微妙に異なり、それはそれぞれのオンレッジャー設計に影響を与えます。分かりやすく説明すると、トラストラインは主に「コミュニティクレジット」というアイデアを提供するために発明されました。一方、MPTには、トラストラインとは微妙に異なる3つの主要な設計上の意図があります。(1)レジャー上でできるだけ少ないスペース(バイト数)でトークン化を可能にすること、(2)トークン化プリミティブから浮動小数点数と浮動小数点演算を排除すること、(3)例えば、リップリングを削除し、エスクローペイメントチャンネルのような場所でMPTをより自然な方法で使用できるようにすることで、決済の実装をよりシンプルにすることです。

2.1.2. MPTはトラストラインを置き換えるものですか?

いいえ、MPTはトラストラインを置き換えるものではありません。むしろ、MPTとトラストラインは微妙に異なるユースケース(特にリップリングに関する部分)を可能にするため、共存可能であり、共存していくでしょう(FAQ 2.1.1.をご覧ください)。

2.1.3 MPTの代わりに、なぜトラストラインをより小さく/より良くしないのですか?

トラストラインをより効率的にする提案があるのは事実ですが(例えば、トラストラインのストレージの最適化、さらには(トラストラインからCustom Math)[https://github.com/XRPLF/rippled/issues/4120]を削除する)、これらはどちらもRippleStateの実装の重要な側面を変更する、ある程度大きな変更です。このような変更を行う場合、既存の機能に予期せぬ影響を与える可能性があります。MPTを構築し実装するという選択は、結局のところ、このリスクとリターンのトレードオフのバランスをとるための選択であり、既存の機能を壊さないために新しいものを導入するということです。

2.1.4. MPTの対象はメインネットですか、それともサイドチェーンですか?

これはまだ検討・議論中ですが、最終的にはバリデータが決めることです。一方では、メインネットでMPTを使用すると、トラストラインが使用された場合に問題となる可能性のある、いくつかの新しいトークン化のユースケースが可能になります(詳細についてはFAQ 2.1.7をご覧ください)。一方、MPTを追加すると、ペイメントエンジンに新しい決済タイプが導入され、rippled自体の実装とXRPLツールの両方が複雑になります。

いずれにせよ、私たちはまずMPT-DevnetでMPTをプレビューし、そこで判明したことに応じてこの問題を再検討します。

2.1.5. MPTはSTAmountにエンコードされるのでしょうか、それとも新しいC++オブジェクト型が必要なのでしょうか?

MPTはSTAmountにエンコードできるようになります。詳細はthis gistをご覧ください。

2.1.6. 1つのアカウントが保持できるMPTokenIssuanceオブジェクトやMPTokenオブジェクトの数に制限はありますか?

実用的には、制限はありません。どのアカウントでも保持できるMPTokenオブジェクトやMPTokenIssuanceオブジェクトの数は、オーナーディレクトリに格納できるオブジェクトの数によって制限されます。

2.1.7. このMPT提案の初期の草案では、MPTokenオブジェクトをNFTで使われているようなページング構造に格納していました。なぜその設計は放棄されたのですか?

元の設計は、レジャー上のスペースを節約するために最適化されていましたが、この仕様と実装の両方において、複雑さの増大というトレードオフを伴いました。もう1つの考慮点は、多くのNFT開発者がNFTの識別に使用されるメカニズムに苦慮していたというデータポイントで、その一部はNFTのページング構造に起因するものです。

(a)トラストライン、(b)MPTokenPages、(c)および単純にMPTokenオブジェクトをオーナーディレクトリに格納する場合のレジャー上の必要スペースを分析した結果、典型的なユーザー(つまり~10種類のMPTを保有するユーザー)の場合、より単純な設計で必要とされる全体的なスペースは、より複雑な設計とトラストラインの間でうまくバランスが取れていると判断しました。例えば、より単純な設計は、より複雑な設計よりも、台帳上で~3.2倍のバイトを要求します。しかし、より単純な設計は、トラストラインよりもレジャー上で必要なバイト数が約30%少なくなります。

とはいえ、この決定にはまだ議論の余地があります。例えば、Rippleチームは2024年初頭に、TrustlinesとよりシンプルなMPTデザインに関するリミットテストを実施し、両方のタイプの元帳オブジェクト数の増加が元帳パフォーマンスにどのように影響するかを確認する予定です。そのデータが完了したら、私たちはこの設計の選択を再検討し、それを検証するか変更することになるでしょう。

2.1.8. なぜMPTRedeemトランザクションがないのですか?

これは、MPTの保有者は通常の支払いトランザクションを使ってMPTを発行者に送り返すことができるため、MPTを「償還」して保有残高から取り除くことができるからです。もし発行者がそのようなことができるとすれば、送られてくるMPTの支払いがどこに行くべきかが曖昧になるからです(つまり、その支払いは償還となり発行残高の合計を減らすべきなのか、それともその支払いは発行者のMPToken量に入り、まだ"流通している"とみなされるべきなのか)。シンプルにするために、私たちは前者の設計を選択し、MPT発行者がMPTokenオブジェクトを持つことを制限しました。

2.1.9. なぜMPToken発行者はMPTokenオブジェクトにMPTの残高を保持できないのですか?

上記の質問をご覧ください。この設計は、発行アカウントを発行者の取引アカウントとしても使用してはならないというセキュリティのベストプラクティスを実施するのにも役立ちます。発行者はMPTの発行以外の活動のために別のXRPLアカウントを使うべきです。

2.1.10. なぜAuthorized MPT機能にはDepositPreauthトランザクションを使用しないのですか?

lsfMPTRequireAuthフラグが設定されているMPTokenIssuanceについては、DepositPreauthトランザクションを、事前認可されたトラストラインと事前認可されたMPTを区別するために若干の変更を加えて使用することが想定されます。あるいは、トラストラインを制限する単一の発行者が、同じ発行者アカウントから発行されるMPTについても同じ制限をしたいという前提のもとで、deposit_preauthオブジェクトが両方に適用されるかもしれないと考えるかもしれません。

とはいえ、この設計はまだ未定です。

2.1.11. 「Compact Fungible Token」という名称が「Multi-Purpose Token」に改名されたのはなぜですか?

最初の名称である「Compact Fungible Token」は、このトークン規格の柔軟性と汎用性を効果的に伝えるものではありませんでした。そのため、私たちは「多目的トークン(Multi-Purpose Token)」という新しい名称を導入しました。この名称は、ユーザーのカスタマイズに対応する能力をよりよく反映し、fungible、semi-fungible、そして潜在的にはnon-fungibleトークンのユースケースに対応するものです。この名称変更は、MPTを介して利用可能な広範な機能を強調することを目的としています。

例えば、MPTはNFTよりもセミファンジブルなユースケース(特に各トークンが1以上の数量を持つようなユースケース)に適しているかもしれません。加えて、NFTの発行者の中には、セミファンジブルにするために同じNFTを複数発行する者もいます。これは技術的にNFT仕様の趣旨に反するものであり、すべてのNFTユースケースでうまく機能するとは限りません。

とはいえ、特定のユースケースでNFTかMPTかを選択する前に、将来の要件やトレードオフを考慮する必要があります。例えば、NFTはURIフィールドを介してオフレジャーのメタデータにリンクする機能を持っており、MPTよりもオンレジャーのストレージバイト数が少なくて済む可能性があります(ただし、これは今後の研究に値します)。

2.2. 付録: 未解決の問題

このセクションでは、本提案でまだ解決されていない未解決または議論の余地のある問題について説明します。

2.2.1. MPTokenIssuanceIDの選択肢

MPTokenIssuanceIDを構成する要素にはさまざまな方法があります。このセクションでは、現在議論されている3つの方法について概説します。

2.2.1.1. 発行者アドレスと通貨コードのハッシュ

トークン保有者は発行者と使用する通貨を知った上で直接取引を行うことができます。しかし、これが実装されると、発行者がMPTokenIssuanceをすべて破棄した後(つまり、誰もそのトークンを保持しなくなった後)、発行者は同じトークンを同じ通貨で再発行できることになり、結果として同じMPTokenIssuanceIDが生成されます。このような動作は、トークン保有者にとって誤解を招きかねません。トークン保有者は、再発行されたトークンではなく、最初のトークンを保持することになります(どちらのトークンも同じMPTokenIssuanceIDを持つため)。実際のユースケース(特に金融)では、トークンを焼却した後、同じ識別子で再作成することは絶対に避けなければなりません。

2.2.1.2. オプションA: 通貨配列とMPT発行数の制限

この方法でも、発行者アドレスと通貨コードをハッシュしてMPTokenIssuanceIDを構築します。しかし、再作成可能なMPTokenIssuanceIDの問題を解決するために、発行者はこれまでに発行されたMPT通貨コードの配列を保存します。こうすることで、発行者が新しいMPTを発行するたびに、台帳はその通貨コードがすでに使われているかどうかをチェックし、もし使われていれば取引は失敗します。しかし、この方法の問題点は、口座がMPTを発行しようとするたびに、台帳が通貨配列を繰り返しチェックする必要があることです。そこで、1つのアカウントが発行できるMPTの総数に制限をかけます(提案されている制限は32MPTです)。

しかし、この方法は問題を解決する上であまりすっきりしていません。口座が発行できるMPTの数には制限があり、発行者は好きなだけMPTを発行したいので、これは理想的ではありません。

2.2.1.3. オプションB: 通貨コードなしでMPTokenIssuanceを構築する(現在のアプローチ)

私たちは、再作成可能なMPTの問題は、MPTを焼いた後に通貨を何度も再利用できるアカウント/通貨ペアに起因していることに気づきました。この問題を解決するために、MPTokenIssuanceIDは発行者アドレスとトランザクションシーケンスの2つのパラメータから構成されるようになりました。トランザクションシーケンスは増加インデックスなので、MPTokenIssuanceIDが再作成されることはありません。したがって、AssetCode/currencyは純粋にメタデータとして使用するオプションのフィールドとすることができます。

この方法を使うと、MPTの支払いトランザクションに通貨コードが含まれなくなり、ユーザーにとって不便になりますが、それでも妥協の産物です。NFTokenはランダムな識別子を持ち、APIサービスにはclioを使用しています。

2.2.2. 許可リスト

特定のユースケースにおいて、発行者は、トラストラインの認可の仕組みと同様に、特定のアカウントにのみMPTの保持を許可するオプションが欲しい場合があります。

2.2.2.1. 許可リストなし

まず、許可リストを使用しない場合のフローを見てみましょう。

  1. AliceはアセットコードUSDのMPTを保持しています。
  2. Bobはそれを保有したいので、MPTokenIssuanceIDを指定してMPTokenAuthorizeトランザクションを送信します。これにより、残高ゼロのMPTokenオブジェクトが作成され、余分な準備金が発生する可能性があります。
  3. BobはUSDを使って誰からでも/誰に対しても支払いを受送信できるようになりました。
  4. BobはもうMPTを使いたくないので、USDの全額をPaymentトランザクションを通して発行者に返す必要があります。その結果、残高ゼロのMPTokenオブジェクトが再び生成されます。
  5. Bobは次にtfMPTUnauthorizeフラグを設定したMPTokenAuthorizeトランザクションを送信し、MPTokenオブジェクトの削除に成功します。

2.2.2.2. 許可リストを使用する場合

発行者はMPTokenIssuancelsfMPTRequireAuthを設定して、MPTのリストを許可する必要があります。

許可リストでは、保有者と発行者の間に双方向の信頼関係が必要です。上記との違いを比較してみましょう。

  1. Aliceは通貨USDのMPTを持っています(上と同じ)。
  2. Bobはそれを保有したいので、MPTokenIssuanceIDを指定してMPTokenAuthorizeトランザクションを送信します。この場合、残高ゼロのMPTokenオブジェクトが作成され、余分な準備金が発生する可能性があります。(上記と同じ)
    この時点では、BobはまだUSDを使用する権限を持っていません。
  3. AliceはMPTokenHolderフィールドにBobのアドレスを指定してMPTokenAuthorizeトランザクションを送信する必要があり、成功すればBobのMPTokenオブジェクトにlsfMPTAuthorizedフラグを設定します。これでようやくBobがUSDを使えるようになります。
  4. 上のステップ4と同じです。
  5. 上記のステップ5と同じ

上記の例では、AliceがBobより先にMPTokenAuthorizeを送信した場合、ステップ2とステップ3を逆にすることはできません。

発行者は保有者の認証を解除することもできます。その場合、保有者にまだ残高があれば、その資金を回収するのは発行者の責任です。

2.2.3. MPTokenNodeディレクトリとは?

MPTokenNodeオブジェクトの本来の目的は、1つのMPTokenIssuanceに対して存在するMPTokenID値(それぞれ32バイト)のリストを格納する一種の"ディレクトリ"(つまりインデックス)になることです。これによって、rippledは与えられた発行のMPTokenオブジェクトのページングされたコレクションを返すRPCエンドポイントや、mpt_holder_balancesと呼ばれるRPCのようなものを持つことができます。理論的には、これによりrippledは、対応するMPTokenIssuanceが削除された後も台帳に残っているMPTokenを削除する(そしてレジャーの準備金をトークン保有者に戻す)"クリーンアップ"操作を行うことができます。

2.2.3.1 MPTokenNodeディレクトリを持つべきか?

MPTokenNodeの導入は特定のユースケースに対応するものですが、MPTと一般的なユースケースの両方について、そのユースケースを実際に解決したいのかどうか、さらに議論する必要があります。例えば、コミュニティの中には、多くの(ほとんどの?)RPCはrippled自体から削除されるべきであり、特に主にインデックス作成の目的で存在するものは削除されるべきであると考える人もいます。つまり、実際のトランザクタによって使われるのではなく、RPCを介して外部プロセスにサービスを提供するためだけに存在するデータをレジャーに保存することは避けるべきという意見です。例えば、これらのRPCをClioや他のサービスに移行することで、データのインデックス付けや、より高価なインデックス付けの責任をレジャー自体から取り除くことができ、特定のインフラオペレーターの負担を取り除くことができます。

ぶら下がるMPTokenObjectsを削除するというトピックについてですが、この解決策はrippledにバックグラウンドのスレッドを導入することになり、実際のノード操作に意図しない結果をもたらすかもしれません。加えて、レジャーのクリーンアップを行うための最も一般的な方法は、アカウント保有者が削除トランザクションを発行することです。

2.2.3.2 MPTokenNodeディレクトリをどのように設計すべきか?

新しい"MPTのみの"ディレクトリ構造の提案は、更に考慮されるべき新しいパターンを導入します。例えば、XRP Ledgerには現在2種類の"Directory"があります。"Owner Directory"と"Offer Directory"です。新しいタイプのMPTディレクトリの提案は、MPT専用の新しいタイプのオーナー不在のディレクトリを作成することを提案しています(NFTokenOfferNodeに似ています)。このディレクトリは、所有者がいないという意味では確かに「オファーディレクトリ」に似ていますが、DEXのオファーやNFTokenOfferNodeオブジェクトの場合のように、これらの新しいMPTディレクトリはDEXや取引所の操作を目的としていないという意味で、設計はこのコンセプトから逸脱しています。

別の設計として、(1)発行者が所有し、(2)MPTokenID値のみを保持するMPTのための新しいタイプの"Owner Directory"を検討することもできます。この新しいタイプのディレクトリは、(オーナーが存在するため)「Owner Directory」に似ていますが、MPTokenID値のみが格納されるため異なります。

どちらの提案も、現存するものとは多少アーキテクチャが異なるため、トレードオフとその意味を探るために、それぞれについてさらに議論する必要があります。

2.3. 付録: 補足情報

2.3.1 オンレジャーのストレージ要件

2.3.1.1. RippleStateオブジェクト(バイト単位)

Issue#3866で説明されているように、RippleStateオブジェクトのサイズは202バイトから218バイトで、さらにオブジェクトの所有者追跡のために最低32バイトが必要です。さらに、各トラストラインは、両方の参加者のオーナーディレクトリのエントリを必要とします。

このセクションでは、予想されるスペースの節約を予測するために、トラストラインとMPTの両方について、予想されるサイズをバイト単位でカタログ化することを試みます。

必須フィールド

フィールド名 サイズ(BITS) サイズ(BYTES) 備考
LedgerEntryType 16 2
Flags 32 4 (「任意」だが99.99%以上のケースで存在)
Balance 384 48 (160–224が無駄)
LowLimit 384 48 (160–224が無駄)
HighLimit 384 48 (160–224が無駄)
LowNode 64 8 (ほとんどの場合0)
HighNode 64 8 (ほとんどの場合0)
PreviousTxnID 256 32
PreviousTxnLgrSeq 32 4
Field+Type Codes 144 18 各フィールドにはFieldCodeTypeCodeがあり、合計で2バイトを使用します(例えばフィールドが4つあれば8バイトを使用します)。ここでは9つのフィールドがあります。
--- -- ---
小計 1760 220
--- -- ---
LowQualityIn 32 4
LowQualityOut 32 4 (「任意」だが99.99%以上のケースで存在)
HighQualityIn 32 4 (160–224が無駄)
HighQualityOut 32 4 (160–224が無駄)
Field+Type Codes 64 8 各フィールドにはFieldCodeTypeCodeがあり、合計で2バイトを使用します(例えばフィールドが4つあれば8バイトを使用します)。ここでは4つのフィールドがあります。
--- -- ---
小計 192 24
--- -- ---
合計 1952 244

2.3.1.2. MPTokenオブジェクト(バイト単位)

フィールド名 サイズ(BITS) サイズ(BYTES) 備考
LedgerEntryType 16 2
MPTokenIssuanceID 192 32
MPTAmount 64 8
LockedAmount 64 8
Flags 32 4
PreviousTxnID 256 32
PreviousTxnLgrSeq 32 4
Field+Type Codes 112 14 各フィールドにはFieldCodeTypeCodeがあり、合計で2バイトを使用します(例えば、フィールドが4つある場合は8バイトを使用します)。ここでは7つのフィールドがあります。
--- -- ---
合計 768 104

2.3.1.3. サイズの比較

以下のサイズ比較表からわかるように、トラストラインはMPTの約2.2倍(バイト)のスペースをレジャー上で占有します。

説明 # MPTディレクトリ 合計バイト(MPT) # トラストラインディレクトリ 合計バイト(トラストライン) トラストラインはn倍
Bytes for holding 1 Tokens 1 226 2 488 2.2x
Bytes for holding 10 Tokens 1 1,450 2 3,260 2.2x
Bytes for holding 32 Tokens 2 5,556 4 12,264 2.2x
Bytes for holding 64 Tokens 3 13,070 6 28,444 2.2x

2.3.2. STAmountのシリアライズ

https://gist.github.com/sappenin/2c923bb249d4e9dd153e2e5f32f96d92 を参考に一部改変。

バイナリのエンコード

このアイデアをサポートするために、まず現在のSTAmountのバイナリエンコードを活用する方法が必要です。これを実現するために、XRPの最大量(10^17ドロップ)には57ビットしか必要ないことに気づきます。しかし、現在のXRPの金額エンコーディングでは、62ビットが利用可能です。

バイナリの金額フィールドの読み取りルールは後方互換性があり、以下のようになります。

  1. フィールドIDをtype_code(STI_AMOUNT)でパースします。これは次のバイトがSTAmountであることを示します。
  2. 次のビットを検査します。もし1なら、これはMPTやXRPではありません。しかし、もし最初のビットが0なら、続行します。
  3. 2番目のビットを無視します(これは符号ビットで、XRPでもMPTでも常に1です)。
  4. 3番目のビットを調べます。もし0なら、通常通りXRPの値として解析します。もし1なら、MPTとしてパースします。

XRP値のエンコーディング(後方互換性)

┌────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ┌─────────────────┐┌────────────────────────┐┌────────────┐┌─────────────────────────────────────────────┐ │
│ │        0        ││           1            ││     0      ││                                             │ │
│ │                 ││                        ││            ││                integer drops                │ │
│ │  "Not XRP" bit  ││  Sign bit (always 1;   ││"IsMPT" bit ││                  (61 bits)                  │ │
│ │0=XRP/MPT; 1=IOU ││       positive)        ││0=XRP; 1=MPT││                                             │ │
│ └─────────────────┘└────────────────────────┘└────────────┘└─────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

MPT値のエンコーディング(後方互換性)

このエンコーディングはMPTの最初の3バイトに注目します。

┌────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ┌─────────────────┐┌────────────────────────┐┌────────────┐┌─────────────────────────────────────────────┐ │
│ │        0        ││           1            ││     1      ││                                             │ │
│ │                 ││                        ││            ││             Remaining MPT Bytes             │ │
│ │  "Not XRP" bit  ││  Sign bit (always 1;   ││"IsMPT" bit ││                 (389 bits)                  │ │
│ │0=XRP/MPT; 1=IOU ││       positive)        ││0=XRP; 1=MPT││                                             │ │
│ └─────────────────┘└────────────────────────┘└────────────┘└─────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

このエンコーディングは、MPTの残りのバイト(264ビット)に注目します。

┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ┌─────────────────┐┌──────────────────┐┌──────────────────────┐┌──────────────────────────┐┌──────────────────────────┐│
│ │    [0][1][1]    ││                  ││                      ││                          ││                          ││
│ │                 ││     Reserved     ││   MPT Amount Value   ││      Sequence            ││     Issuer AcountID      ││
│ │   IsMPT=true    ││     (5 bits)     ││      (64 bits)       ││      (32 bits)           ││        (160 bits)        ││
│ │                 ││                  ││                      ││                          ││                          ││
│ └─────────────────┘└──────────────────┘└──────────────────────┘└──────────────────────────┘└──────────────────────────┘│
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

Discussion