はじめに
初めまして。 「DApps開発入門」という本や色々記事を書いているかるでねです。
以下でも情報発信しているので、興味ある記事があればぜひ読んでみてください!
今回は「Commerce Payments Protocol」についてまとめていきます。
この記事は以下の方法でベースを作成しています。
従来の決済フローとAuth & Capture
クレジットカード決済を利用したことがある方なら、「Authorization」と「Capture」という用語を聞いたことがあるかもしれません。 これは従来の金融システムで確立された2フェーズの決済パターンです。
まず、本記事で使用する主要な用語を整理します。
| 用語 | 説明 |
|---|---|
| Authorization | 与信枠の確保。顧客の支払い能力を確認し、指定金額を「ホールド(保留)」する処理。実際の資金移動は発生しない |
| Capture | 売上確定。Authorizationでホールドされた金額を実際にMerchantへ移動させる処理 |
| Escrow | 第三者預託。取引の安全性を確保するため、信頼できる第三者が資金を一時的に保管する仕組み |
| Payer | 支払者。決済において資金を支払う側の当事者 |
| Receiver/Merchant | 受取人。決済において資金を受け取る側の当事者(売り手) |
| Operator | 決済フローを管理・実行する主体。ガス代を負担し、トランザクションを送信する |
sequenceDiagram
participant Customer as Customer
participant Merchant as Merchant
participant Acquirer as Acquirer
participant Issuer as Issuer
Customer->>Merchant: 購入リクエスト
Merchant->>Acquirer: Authorization要求
Acquirer->>Issuer: 与信枠確認
Issuer-->>Acquirer: 承認(与信枠確保)
Acquirer-->>Merchant: Authorization完了
Note over Merchant: 商品発送・サービス提供
Merchant->>Acquirer: Capture要求
Acquirer->>Issuer: 売上確定
Issuer-->>Acquirer: 決済完了
Acquirer-->>Merchant: 入金従来のクレジットカード決済におけるAuth & Captureフロー
この2フェーズが必要な理由は、実際のコマースでは即時決済だけでは対応できない様々なケースが存在するためです。
| シナリオ | 説明 |
|---|---|
| 在庫切れ | 注文後に在庫がないことが判明し、キャンセルが必要になる |
| 返金リクエスト | 顧客が商品に不満を持ち、返金を要求する |
| 分割配送 | 複数の商品を別々に発送し、発送ごとに請求する |
| 税金計算の確定 | 配送先が確定するまで正確な税額が計算できない |
| 価格調整 | プロモーション適用や価格変更による金額修正 |
Authorizationでは、顧客の支払い能力を確認し、その金額を「ホールド(保留)」します。 この時点では実際の資金移動は発生しませんが、Merchantは支払いが確実に行われることを保証されます。
Captureでは、ホールドされた金額の一部または全部を実際にMerchantへ移動させ、決済を確定します。
この「支払い保証の中間状態」が、スケーラブルなコマース決済の基盤となっています。
オンチェーン決済の課題
ブロックチェーン上の決済は、P2P(ピアツーピア)取引には非常に適しています。 AさんからBさんへトークンを送るという単純な取引は、スマートコントラクトで即座に実行できます。
しかし、ECサイトのような複雑なコマース決済では、従来のオンチェーン決済には以下の課題がありました。
graph TB
subgraph Problem["従来の課題"]
P1[即時・最終的な送金のみ]
P2[資金のホールド機能なし]
P3[返金は別トランザクション]
P4[部分Capture不可]
end
subgraph Impact["ビジネス影響"]
I1[在庫切れ時の対応困難]
I2[Merchantのリスク増大]
I3[複雑なオーダー管理]
I4[顧客体験の低下]
end
P1 --> I1
P2 --> I2
P3 --> I3
P4 --> I4
style Problem fill:#ffcccc
style Impact fill:#ffffcc従来のオンチェーン決済がコマースに不向きだった理由
つまり、オンチェーンには「今すぐ支払うわけではないが、将来の支払いを保証する」という中間状態が存在しなかったのです。
Commerce Payments Protocolの概要
Commerce Payments Protocolは、Baseチェーン上で従来の金融システムと同等のAuth & Captureパターンを実現するプロトコルです。
このプロトコルは以下の設計思想に基づいています。
Permissionless 誰でもOperatorとしてプロトコルを利用でき、特定の管理者による承認は不要です。 Merchant自身がOperatorになることも、サードパーティの決済プロバイダーを利用することもできます。
Immutable デプロイ後にプロトコルのコードを変更することはできません。 これにより、参加者は将来にわたってルールが変わらないことを信頼できます。
Trust-Minimized Operatorは決済フローを管理しますが、プロトコルの暗号学的制約により資金を盗むことはできません。 最悪のケースでも、Operatorができることは限定されています。
graph LR
subgraph Traditional["従来型"]
T1[Payer] -->|即時送金| T2[Receiver]
end
subgraph CPP["CPP"]
C1[Payer] -->|Authorize| C2[Escrow]
C2 -->|Capture| C3[Receiver]
C2 -.->|Void/Reclaim| C1
end
style Traditional fill:#ffcccc
style CPP fill:#ccffcc従来のオンチェーン決済とCommerce Payments Protocolの比較
プロトコルの核心は「Escrow方式」です。 Authorizeの時、資金はPayerからEscrowコントラクトに移動します。 Captureの時、資金はEscrowからReceiverに移動します。 この2ステップにより、従来の金融システムと同等の「支払い保証の中間状態」をオンチェーンで実現しています。
アーキテクチャと主要コンポーネント
Commerce Payments Protocolは、3つの主要コンポーネントで構成されています。
graph TB
subgraph External["外部参加者"]
Operator[Operator]
Payer[Payer]
Receiver[Receiver/Merchant]
end
subgraph Protocol["CPP Core"]
ACE[AuthCaptureEscrow]
TC[Token Collectors]
TS[TokenStore]
end
Operator -->|決済フロー管理| ACE
Payer -->|署名| TC
TC -->|トークン収集| ACE
ACE -->|資金保管| TS
ACE -->|支払い| Receiver
style ACE fill:#4169E1,color:#fff
style TC fill:#32CD32,color:#fff
style TS fill:#FF8C00,color:#fffCommerce Payments Protocolのアーキテクチャ
AuthCaptureEscrow
メインのEscrowコントラクトで、決済のライフサイクル全体を管理します。
このコントラクトは以下の責務を持ちます。
- 決済パラメータとタイミング制約の検証
- 決済状態の管理(authorized、captured、refunded)
- 手数料の分配
- リエントランシー攻撃からの保護
すべての決済は PaymentInfo 構造体で定義され、この構造体のハッシュが決済を一意に識別します。
struct PaymentInfo {
address operator; // 決済フローを管理するエンティティ
address payer; // 支払者のウォレットアドレス
address receiver; // Merchantの受取アドレス
address token; // 支払いトークンのコントラクトアドレス
uint120 maxAmount; // Authorization可能な最大金額
uint48 preApprovalExpiry; // 署名の有効期限
uint48 authorizationExpiry; // Authorizationの有効期限(この後はCapture不可)
uint48 refundExpiry; // 返金の有効期限
uint16 minFeeBps; // 最小手数料(基準点)
uint16 maxFeeBps; // 最大手数料(基準点)
address feeReceiver; // 手数料受取人(0なら動的に指定可能)
uint256 salt; // 一意性を保証するためのエントロピー
}TokenStore
Operatorごとに作成される資金保管庫です。
このコンポーネントの重要な特徴は「流動性の分離」です。 すべてのEscrow資金を単一のコントラクトに保管すると、万が一の脆弱性発見時に全資金が危険にさらされます。 TokenStoreはOperatorごとに独立して作成されるため、あるOperatorの資金が他のOperatorの資金に影響を与えることはありません。
graph TB
ACE[AuthCaptureEscrow]
subgraph Stores["Operator別TokenStore"]
TS1[TokenStore A]
TS2[TokenStore B]
TS3[TokenStore C]
end
ACE --> TS1
ACE --> TS2
ACE --> TS3
style ACE fill:#4169E1,color:#fff
style TS1 fill:#FF8C00,color:#fff
style TS2 fill:#FF8C00,color:#fff
style TS3 fill:#FF8C00,color:#fffOperatorごとに分離されたTokenStore
TokenStoreは以下の特徴を持ちます。
- CREATE2を使用した決定論的デプロイ(Operatorアドレスから一意に導出)
- Minimal Proxyパターンによるガス効率の最適化
- AuthCaptureEscrowからのみ呼び出し可能
Token Collector
トークンの承認方法を抽象化するモジュラーなコンポーネントです。
ブロックチェーンには複数のトークン承認標準が存在し、それぞれに特徴があります。 Token Collectorはこれらの違いを吸収し、プロトコルのコア部分を変更することなく様々な承認方法に対応できるようにします。
詳細は後述の「Token Collectorによる承認方法の抽象化」セクションで説明します。
6つの決済オペレーション
Commerce Payments Protocolは、決済ライフサイクル全体をカバーする6つのオペレーションを提供します。
stateDiagram-v2
[*] --> Pending: 決済作成
Pending --> Authorized: authorize()
Pending --> Captured: charge()
Authorized --> Captured: capture()
Authorized --> Voided: void()
Authorized --> Reclaimed: reclaim()
Captured --> Refunded: refund()
Captured --> [*]: 決済完了
Voided --> [*]: キャンセル完了
Reclaimed --> [*]: 回収完了
Refunded --> [*]: 返金完了決済状態の遷移図
Authorize
Payerの資金をEscrowにホールドし、将来のCaptureを保証します。
function authorize(
PaymentInfo calldata paymentInfo,
uint256 amount,
address tokenCollector,
bytes calldata collectorData
) externalこの関数が実行されると、指定された金額がPayerからTokenStoreに移動します。 Merchantはこの時点で、支払いが確実に行われることを保証されます。
主な検証項目
- 金額が
maxAmountを超えていないこと - 現在時刻が
preApprovalExpiryより前であること - 同じ決済がまだAuthorizeされていないこと
Capture
Authorizeされた資金をEscrowからMerchantに移動し、決済を確定します。
function capture(
PaymentInfo calldata paymentInfo,
uint256 amount,
uint16 feeBps,
address feeReceiver
) externalCaptureは複数回に分けて実行できます(部分Capture)。 例えば、1,000 USDCのAuthorizationに対して、最初に600 USDC、次に400 USDCをCaptureすることが可能です。
部分Captureの例
初期状態: capturableAmount = 1000 USDC
1回目のCapture(600 USDC):
→ capturableAmount = 400 USDC
→ refundableAmount = 600 USDC
2回目のCapture(400 USDC):
→ capturableAmount = 0 USDC
→ refundableAmount = 1000 USDCCharge
AuthorizationとCaptureを1つのトランザクションで実行します。
function charge(
PaymentInfo calldata paymentInfo,
uint256 amount,
address tokenCollector,
bytes calldata collectorData,
uint16 feeBps,
address feeReceiver
) external即時決済が適切なユースケース(デジタルコンテンツの購入など)では、2つのトランザクションを分ける必要がありません。 Chargeを使用することで、ガスコストを削減し、シンプルな決済フローを実現できます。
Void
オペレーターがAuthorizationをキャンセルし、Escrow資金をPayerに返還します。
function void(PaymentInfo calldata paymentInfo) externalVoidはOperatorのみが実行でき、いつでも呼び出し可能です。 在庫切れや注文キャンセルなど、Merchant側の理由で決済を中止する時に使用します。
Reclaim
Authorization有効期限後に、Payerが自分の資金を回収します。
function reclaim(PaymentInfo calldata paymentInfo) externalReclaimは authorizationExpiry を過ぎた後にのみ、Payer自身が実行できます。
これは重要な安全メカニズムで、Operatorが非アクティブになったり、何らかの理由でCaptureもVoidも行われなかった場合に、Payerが資金を取り戻せることを保証します。
Refund
Capture済みの資金をPayerに返還します。
function refund(
PaymentInfo calldata paymentInfo,
uint256 amount,
address tokenCollector,
bytes calldata collectorData
) external返金には別途、返金用の流動性を調達する必要があります。
これは OperatorRefundCollector などのRefund Collectorを通じて行われます。
返金可能期間
返金は refundExpiry までしか実行できません。
これにより、決済に最終的な確定性が生まれ、Merchantは一定期間後に資金が確定することを保証されます。
OperatorモデルとSecurity
Commerce Payments Protocolの特徴的な設計の1つが「Operatorモデル」です。
Operatorの役割
Operatorは決済フローを管理する主体です。 具体的には、以下の責務を持ちます。
- オンチェーントランザクションの送信(ガス代の負担)
- 決済の状態遷移のトリガー(authorize、capture、void、refund)
- PayerやMerchantとブロックチェーンの間の技術的な橋渡し
Operatorになれるのは、決済プロセッサー(Shopifyなど)、独立したサービスプロバイダー、Merchant自身、あるいはカスタムビジネスロジックを実装したスマートコントラクトなど、誰でも可能です。
暗号学的制約
Operatorは強力な役割を持ちますが、プロトコルの暗号学的制約により、その能力は厳しく制限されています。
graph TB
subgraph Can["Operatorができること"]
C1[決済フローのトリガー]
C2[手数料の設定(範囲内)]
C3[決済の無効化]
end
subgraph Cannot["Operatorができないこと"]
N1[資金の窃取]
N2[決済条件の変更]
N3[署名の再利用]
N4[他Operatorの決済操作]
end
style Can fill:#ccffcc
style Cannot fill:#ffccccOperatorの能力と制約
Payerが決済を承認する時、以下の情報すべてに暗号学的署名を行います。
- 正確な金額と受取人
- 手数料の範囲
- 各種有効期限
- 指定されたOperator
この署名により、Operatorが条件を変更したり、署名を別の決済に再利用することは不可能になります。
Operator妥協時のリスク
万が一Operatorが悪意を持った場合や、秘密鍵が漏洩した場合でも、被害は限定的です。
| リスク | 説明 |
|---|---|
| 検閲 | 決済のCaptureを拒否したり、不当にVoidすることが可能 |
| 手数料の最大化 | maxFeeBps までの手数料を徴収可能 |
| 手数料受取人の変更 | feeReceiver が未設定の場合、任意のアドレスを指定可能 |
重要なのは、Operatorは資金を盗むことができないという点です。 資金は常にPayerかReceiverのいずれかに移動し、それ以外の場所には送れません。
時間ベースの保護
プロトコルは3つの有効期限を使用して、決済が「スタック」状態になることを防ぎます。
preApprovalExpiry 署名の有効期限です。 この時刻を過ぎると、Payerの署名は無効になり、新たなAuthorizationはできなくなります。
authorizationExpiry Authorizationの有効期限です。 この時刻を過ぎると、OperatorはCaptureできなくなり、代わりにPayerがReclaimで資金を回収できるようになります。
refundExpiry 返金の有効期限です。 この時刻を過ぎると、返金はできなくなり、決済が最終確定します。
gantt
title 決済の時間制約
dateFormat X
axisFormat %s
section 期間
署名有効期間 :active, 0, 100
Authorization有効期間 :active, 0, 200
返金可能期間 :active, 0, 300
section イベント
preApprovalExpiry :milestone, 100, 100
authorizationExpiry :milestone, 200, 200
refundExpiry :milestone, 300, 3003つの有効期限の関係
Token Collectorによる承認方法の抽象化
ブロックチェーンには複数のトークン承認標準が存在し、それぞれに長所と短所があります。
| 標準 | 特徴 | 課題 |
|---|---|---|
| ERC-3009 | シングル署名UX、USDCなどが対応 | 対応トークンが限定的 |
| Permit2 | 任意のERC-20に対応 | 初回セットアップが必要 |
| ERC-20 Approval | 全トークンで利用可能 | 別トランザクションが必要 |
| Spend Permissions | 最高のUX(Coinbase Smart Wallet) | 対応ウォレットが限定的 |
Commerce Payments Protocolは、「Token Collector」という抽象化レイヤーを導入することで、この断片化問題を解決しています。
graph TB
ACE[AuthCaptureEscrow]
subgraph Collectors["Token Collectors"]
ERC3009[ERC3009]
Permit2[Permit2]
PreApproval[PreApproval]
SpendPerm[SpendPermission]
OpRefund[OperatorRefund]
end
ACE --> ERC3009
ACE --> Permit2
ACE --> PreApproval
ACE --> SpendPerm
ACE --> OpRefund
ERC3009 --> |USDC等| Payer1[Payer]
Permit2 --> |任意のERC-20| Payer2[Payer]
PreApproval --> |従来型承認| Payer3[Payer]
SpendPerm --> |Coinbase SW| Payer4[Payer]
OpRefund --> |返金用| Operator[Operator]
style ACE fill:#4169E1,color:#fffToken Collectorのアーキテクチャ
Token Collectorの仕組み
AuthCaptureEscrowは、トークンの収集方法を知りません。 代わりに、Token Collectorに対して「この金額をこのTokenStoreに移動してください」と依頼し、結果として残高が正しく増加したかを検証します。
abstract contract TokenCollector {
enum CollectorType { Payment, Refund }
function collectTokens(
AuthCaptureEscrow.PaymentInfo calldata paymentInfo,
address tokenStore,
uint256 amount,
bytes calldata collectorData
) external;
function collectorType() external view virtual returns (CollectorType);
}この設計により、以下のメリットが生まれます。
- 新しい承認標準が登場しても、新しいCollectorを追加するだけでコアプロトコルの変更は不要
- オペレーターはPayerのウォレットとトークンの組み合わせに最適なCollectorを選択できる
- Payment CollectorとRefund Collectorを分離することで、残存する承認を返金に流用することを防止
実装されているCollector
プロトコルには以下のCollectorが実装されています。
ERC3009PaymentCollector
USDCなどERC-3009対応トークン用です。
receiveWithAuthorization を使用したガスレス署名転送に対応しています。
ERC-6492によるスマートコントラクトウォレット署名もサポートしています。
Permit2PaymentCollector 任意のERC-20トークンに対応します。 Permit2による署名ベースの転送を使用しますが、ユーザーは事前にPermit2コントラクトへのApproveが必要です。
PreApprovalPaymentCollector
従来型のERC-20 Approvalフローに対応します。
Payerが事前にCollectorにApproveし、その後 transferFrom で転送します。
SpendPermissionPaymentCollector Coinbase Smart Wallet専用の最適化されたCollectorです。 サブスクリプションのような定期的な支払いにも対応可能です。
OperatorRefundCollector Operatorの資金から返金を行うCollectorです。 OperatorがCollectorにApproveし、返金時にOperatorの残高から資金を調達します。
手数料システム
Commerce Payments Protocolは、柔軟な手数料システムを実装しています。 手数料は「基準点(Basis Points, bps)」で指定され、10,000 bps = 100% となります。
手数料パラメータ
PaymentInfo 構造体には3つの手数料関連フィールドがあります。
| フィールド | 説明 |
|---|---|
minFeeBps |
最小手数料率 |
maxFeeBps |
最大手数料率 |
feeReceiver |
手数料受取人(0なら動的に指定可能) |
手数料の設定パターン
固定レート
minFeeBps と maxFeeBps を同じ値に設定します。
例えば、両方を250(2.5%)に設定すると、Operatorは必ず2.5%の手数料を徴収します。
可変レート
minFeeBps を100(1%)、maxFeeBps を500(5%)に設定すると、Operatorは1%〜5%の範囲で手数料を設定できます。
マーケットプレイスで取引量に応じた階層型手数料を実現する時などに有用です。
ゼロ手数料 両方を0に設定すると、手数料を徴収できません。
手数料受取人の設定
固定受取人
feeReceiver に特定のアドレスを設定すると、手数料は必ずそのアドレスに送られます。
動的受取人
feeReceiver を address(0) に設定すると、OperatorがCapture時に任意の受取人を指定できます。
これはUSDCのデニーリスト問題への対策としても有用で、指定した受取人がブロックされた場合に別のアドレスを指定できます。
デプロイ情報とセキュリティ監査
Commerce Payments ProtocolはBase MainnetとBase Sepoliaにデプロイされています。
| コントラクト | アドレス |
|---|---|
| AuthCaptureEscrow | 0xBdEA0D1bcC5966192B070Fdf62aB4EF5b4420cff |
| ERC3009PaymentCollector | 0x0E3dF9510de65469C4518D7843919c0b8C7A7757 |
| Permit2PaymentCollector | 0x992476B9Ee81d52a5BdA0622C333938D0Af0aB26 |
| PreApprovalPaymentCollector | 0x1b77ABd71FCD21fbe2398AE821Aa27D1E6B94bC6 |
| SpendPermissionPaymentCollector | 0x8d9F34934dc9619e5DC3Df27D0A40b4A744E7eAa |
| OperatorRefundCollector | 0x934907bffd0901b6A21e398B9C53A4A38F02fa5d |
セキュリティ監査
プロトコルはSpearbitとCoinbase Protocol Securityによる複数回の監査を受けています。
| 監査 | 日付 |
|---|---|
| Coinbase Protocol Security audit 1 | 2025年3月19日 |
| Coinbase Protocol Security audit 2 | 2025年3月26日 |
| Spearbit audit 1 | 2025年4月1日 |
| Coinbase Protocol Security audit 3 | 2025年4月15日 |
| Spearbit audit 2 | 2025年4月22日 |
監査レポートはGitHubリポジトリの audits/ ディレクトリで公開されています。
最後に
今回は「Commerce Payments Protocol」についてまとめてきました。
このプロトコルは、従来の金融システムで確立されたAuth & Captureパターンをオンチェーンで実現することで、ブロックチェーン決済をコマーススケールに拡張します。 パーミッションレスで不変のプロトコル設計、暗号学的に制約されたオペレーターモデル、モジュラー式Token Collectorによる柔軟な承認方法のサポートにより、マーチャントとPayerの両方に安全で使いやすい決済インフラを提供しています。


