Develop with pleasure!

福岡でCloudとかBlockchainとか。

Open Assets Payment Method Protocolの仕様(訳)

ちょっと時間が経ったけど、Open Assets Extensions to Payment Requestsにおけるアセットの交渉に関するプロトコルを定義したドキュメントが公開されてたのでざっと訳してみる。

github.com

ざっくり言うと、支払い方法(どんなアセットでどんな量の支払いができのか)についてクライアントと売り手の間で支払いの前に事前に調整するプロトコル

動機

Payment requestsは、クライアントへ正確なトランザクション要件を伝えるのに役立つ。支払いの結果であるpayment responseは支払いに失敗するか、Payment Requestの要件を完全に満たすトランザクションのいずれかになる。

この仕様では、売り手と買い手の間で、これから行おうとしている取引でどんな種類のアセットが利用できるのかといった、支払いの事前の問題を解決する。BIP70ではBitcoinという1つのアセットしかサポートしていないのでこの問題を解決できない。

ここでは3つの新しいタイプのメッセージを紹介する。(BIP70と同様Protocol Bufferによるエンコーディングを採用)

  • Payment Method Request
    Payment Method Requestには受け入れ可能な支払いオプションに関する情報が含まれ、売り手が顧客にこのメッセージを送る。
  • Payment Method
    Payment Methodには支払いに使われる正確な支払い情報(種類や、アセットの量など)が含まれ、Payment Method Requestへの応答として顧客が売り手に送信する。その後、売り手は最終的にPayment RequestかPayment Method Rejectionのどちらかのメッセージを送る。
  • Payment Method Rejection
    Payment Method Rejectionには支払い方法が許容できない理由に関する情報が含まれる。

以下ユースケース

チェックアウト(買い物をカートに入れて決済手段を確定する購入のプロセス)の処理の中で、売り手は顧客にQRコードを表示する。顧客はPayment Method Requestのメッセージを受け取れるクライアントウォレットを使ってQRコードをスキャンする。このメッセージにはこの支払いで、売り手のギフトカード(商品券みたいなものか)とポイントが使えると記載されている。また売り手がチップを受け付けているという情報も含まれている。

クライアントのウォレットは、顧客が利用可能なギフトカードとポイント両方持っていること認識し、顧客にどちらを支払いに使うかもしくは両方使うかの選択をせまる。ここで顧客はギフトカードを選択する。続いてウォレットは顧客にチップを入力するよう求める。顧客はチップを入力し支払いの確認をする。クライアントウォレットはその後Payment Methodを作成し、売り手の端末に返信する。

売り手の端末は受け取ったPayment Methodを使ってPayment Requestメッセージを作成し、クライアントのウォレットに返信する。続いてクライアントのウォレットはトランザクションを生成し、Paymentメッセージに入れ、売り手の端末に送信する。すると売り手の端末に顧客への支払い確認が表示される。

仕様

Payment Method Request

Payment Requestと同様、Payment Method Requestも必要に応じて、売り手のIDと紐付き、X.509証明書で署名される。

message PaymentMethodRequest {
    optional uint32 payment_details_version           = 1 [default = 1];
    optional string pki_type                          = 2 [default = "none"];
    optional bytes  pki_data                          = 3;
    required bytes  serialized_payment_method_details = 4;
    optional bytes  signature                         = 5;
}

PaymentMethodRequestの意図と署名の検証ルールはBIP70と同様。

payment_method_details versioning/upgradingの議論については以下参照。
pki_type 売り手を識別するのにPKIが使用される。全ての実装は"none"、"x509+sha256"、"x509+sha1"の全てをサポートする必要がある。
pki_data 売り手を識別しデジタル署名を作成するのに使われるPKIシステムデータ。X.509証明書の場合、pki_dataには1つ以上のX.509証明書が含まれる。
serialized_payment_method_details Protocol BufferでシリアライズされたPaymentMethodDetailsのメッセージ。
signature PaymentMethodRequestメッセージをProtocol Bufferでシリアライズしたハッシュのデジタル署名。全てのフィールドを番号順にシリアライズpki_data内の公開鍵に対応する秘密鍵で署名されている。オプションフィールドはシリアライズされない。(ただ、デフォルト値が設定されているフィールドについてはシリアライズされ、署名にも影響する。)またシリアライズする前に、signatureフィールドは必ず空にしておく必要がある。(PaymentMethodRequestの署名時にそのフィールドも含まれてしまうため)
Payment Method Details
message PaymentMethodDetails {
    optional string        network            = 1 [default = "main"];
    required string        payment_method_url = 2;
    repeated PaymentItem   items              = 3;
    required uint64        time               = 4;
    optional uint64        expires            = 5;
    optional string        memo               = 6;
    optional bytes         merchant_data      = 7;
}
network Bitcoinのプロダクション環境である"main"かテスト環境である"test"のいずれかを指定。クライアントがネットワークからPaymentRequestを受信した場合、そのサポートしていない場合はリクエストをリジェクトする必要がある。
payment_method_url PaymentRequestを取得するためのPaymentMethodメッセージのセキュアな送信先(通常httpsを使用)。
items 異なる支払いの部分(インボイスやチップや寄付とか)を説明するためのPaymentItemオブジェクトのリスト。
time PaymentRequestが作成された時刻(UNIXタイムスタンプ)
expires PaymentRequestが無効になる時間(UNIXタイムスタンプ)
memo このPaymentMethodRequestについて説明するメモで顧客に表示される。UTF-8エンコードされたプレーンテキストで特にフォーマットなどは定義されていない。
merchant_data PaymentRequestを識別するために売り手によって使用される任意のデータ。売り手が支払いとPaymentRequestを関連付ける必要がなかったり、PaymentRequestを別々のpayment addressに関連付けたりしている場合は省略可能。
Payment Item

各アイテムはタイプを持っており、デフォルトのタイプは"default"。異なるタイプを様々な用途で利用できる。例えば、”tip”というタイプは、チップの追加を顧客に促すために使われ、"donation"というタイプは慈善団体への寄付を顧客に促すのに使われる。しかし"default"以外のタイプは本仕様のスコープ外。

message PaymentItem {
    optional string type                   = 1 [default = "default"];
    optional bool   optional               = 2 [default = false];
    optional bytes  item_identifier        = 3;
    optional uint64 amount                 = 4 [default = 0];
    repeated AcceptedAsset accepted_assets = 5;
    optional string memo                   = 6;
}
type アイテムのタイプの標準識別子。クライアントは特定のタイプに関してどう反応すればいいか分からない場合はPaymentItemを無視すべき。
optional このアイテムがオプションかどうかを決定するフラグ。省略した場合、そのアイテムはオプションではなく必須アイテム。
item_identifier 売り手がPaymentMethodのレスポンス内でこのアイテムを識別するために売り手によって使われる任意のデータ。
amount 支払われるユニットの数。利用可能なアセットと交換比率はAcceptedAssetメッセージでカバーされる。量がゼロだったり欠落している場合、クライアントは任意の量を出してもOK。
accepted_assets このアイテムに関する1つ以上のassets acceptable。assets acceptable については↓のAcceptedAsset を参照。
memo インボイスの要約やチャリティの名前などアイテムの説明を人間が読める形式で記載したデータ
Accepted Asset
message AcceptedAsset {
    optional string asset_id = 1 [default = "default"];
    optional string asset_group = 2;
    optional double multiplier = 3 [default = 1.0];
    optional uint64 min_amount = 4 [default = 0];
    optional uint64 max_amount = 5;
}
asset_id アセットのOpen Assets ID。"default" は特殊な値で現在のネットワークのネイティブ通貨を指す。(BitcoinのmainnetであればBTC)
asset_group アセットのグループを記述した任意の文字列。クライアントはグループと一致するアセット(Asset Definition Fileやその他の方法によって定義される)を選択することができる。asset_idもasset_groupも未定義の場合はBitcoinを使うものと判断される。
multiplier 支払い金額を満たすために必要な特定のアセットの量を計算するのに使われるコンバージョン率。正確な量は売り手によって計算されPaymentRequest内にセットされるので、この数字は正確な値である必要はなく、UIで表示する目的で使われる。
min_amount 売り手に受け入れられるこのアセットの最小量。
max_amount 売り手に受け入れられるこのアセットの最大量。
Payment Method

クライアントが支払い方法を選択すると、payment_method_urlで定義されたURLにPaymentMethodメッセージを返す。

売り手はtypeかitem_identifierのいずれかのフィールドを使って、PaymentItemオブジェクトとPaymentMethodItemを一致させることができる。例えばtypeが"default"の場合は、それだけで識別できるのでitem_identifierを定義する必要は無い。クライアントは必ず対応するPaymentMethodItemオブジェクトにtypeとitem_identifierの両方をコピーする必要がある。

message PaymentMethod {
    optional bytes             merchant_data    = 1;
    repeated PaymentMethodItem items            = 2;
}
    
message PaymentMethodItem {
    optional string             type                = 1 [default = "default"];
    optional bytes              item_identifier     = 2;
    repeated PaymentMethodAsset payment_item_assets = 3;
}
    
message PaymentMethodAsset {
    optional string            asset_id = 1 [default = "default"];
    optional uint64            amount   = 2;
}
merchant_data PaymentMethodDetails.merchant_dataからコピーされる。売り手がPaymentsとPaymentRequestsを一致させるのに利用するインボイスNoやその他のデータ。悪意のあるクライアントがmerchant_dataを改竄する可能性があるので、売り手だけが持つ秘密鍵等で署名する等、なんらかの認証の仕組みが必要。
items PaymentMethodItemオブジェクトのリストで、対応するPaymentItemの支払いに使われるアセットとその量を記述する。
item_identifier PaymentItem.item_identifierからコピーされる。対応するPaymentItemとPaymentItemMethod を一致させるのに使われる。
payment_item_assets 各payment itemで使われる1つ以上のアセットの説明。
payment_item_type PaymentItem メッセージ内で定義されたpayment itemのタイプ。
asset_id アセットのOpen Assets ID。"default" は特殊な値で現在のネットワークのネイティブ通貨を指す。
amount 支払われる量(オプション)。この値が定義されていた場合は、Payment Requestに必ずamountが定義されている必要があり、定義されていない場合Payment Request にはpayment itemが完全に支払われいることを確認するために任意の量を含めることができる。
Payment Method Rejection

もしクライアントがサポートしていないアセットや無効な金額を指定された場合、売り手は支払い方法に関する調整が失敗したことを返信することができる。リジェクションメッセージには指定されたアセットを拒否する理由を含めることができる。

message PaymentMethodRejection {
    optional string memo = 1;
    optional uint64 code = 2;
    repeated PaymentMethodRejectedAsset rejected_assets = 3;
}
message PaymentMethodRejectedAsset {
    required string asset_id = 1;
    optional uint64 code     = 2;
    optional string reason   = 3;
}
memo 人間が読める形のリジェクト理由。任意の資産に固有のものではない。
rejected_assets (オプション)アセット毎のリジェクト理由のリスト
code (オプション)売り手が定義したエラーコード。クライアントはデバッグやUIに表示するために使用する。
asset_id リジェクトの原因となったアセットのID
reason 人間が読める形のアセットをリジェクトした理由
MIME types

Payment Methodの調整はPayment Requestsと同じURLで始まる。

Payment Methodを採用するには、クライアントがPayment Request URIにアクセスする際Accept:ヘッダにapplication/oa-paymentmethodrequestを追加する。互換性がある売り手は、Payment Method Requestメッセージに対しContent-type: application/oa-paymentmethodrequestをセットしたレスポンスを返す。
クライアントがOpen AssetsかBitcoinのPayment Requestをサポートしている場合、適切なMIME typesをAccept: listに追加し対応するメッセージが予想される。

クライアントはPayment Method メッセージへの返信に、payment_method_urlに記載されているURLにapplication/oa-paymentrequestを使用する。この時、クライアントは再度Payment Methodが帰ってくるPayment Method Request の受信を避けるため、application/oa-paymentmethodrequestを使ってはいけない。Payment Method のContent-Typeは(リクエスト、レスポンス両方とも)application/oa-paymentmethod。

Payment Method RejectionメッセージのContent−Typeはapplication/oa-paymentmethodrejectionを使う。