Skip to content

ChainSafe/canton-x402-facilitator

Repository files navigation

Canton x402 Facilitator

A payment facilitator for the x402 protocol on Canton Network. This facilitator enables everyday payment transactions on banking-grade infrastructure, bringing retail payment volume to Canton's institutional-grade distributed ledger.

Overview

This facilitator implements the x402 payment protocol for Canton Network, allowing:

  • Everyday payments: Person-to-person FIAT transfers
  • API monetization: Pay-per-use for services
  • Micropayments: Low-value, high-volume transactions
  • Banking integration: Regulated, compliant payment infrastructure

Key Features

  • βœ… Canton Ledger API integration via gRPC
  • βœ… Daml smart contract for payments
  • βœ… x402 protocol compliance
  • βœ… Local development with Canton sandbox
  • βœ… Simple HTTP API (verify and settle endpoints)

Prerequisites

Before you begin, ensure you have:

  • Node.js v20+ (install via nvm)
  • Java 21 (required for Canton and Daml SDK)
  • Daml SDK 3.4.0+ (installation instructions)
  • Canton SDK (automatically downloaded by setup script)
  • curl or wget (for downloading Canton)

Quick Start

1. Clone and Install

git clone <repository-url>
cd canton-x402-facilitator
npm install

2. Setup Canton

Download and extract Canton SDK:

chmod +x scripts/setup-canton.sh
./scripts/setup-canton.sh

This will download Canton SDK v3.4.0 and extract it to canton-release/.

3. Build Daml Contract

cd daml
daml build
cd ..

This creates the Payment.dar file in daml/.daml/dist/.

4. Start Canton Sandbox

In a separate terminal, start Canton with the Payment contract:

./canton-release/bin/canton sandbox \
  --ledger-api-port 6865 \
  --json-api-port 7575 \
  --dar daml/.daml/dist/canton-x402-payment-1.0.0.dar

Canton will start and load the Payment contract. You should see:

INFO  c.d.c.p.s.SandboxServer - Listening on 0.0.0.0:6865
INFO  c.d.c.p.s.SandboxServer - Listening on 0.0.0.0:7575 over HTTP

5. Configure Environment

Create a .env file (or copy from env.example):

cp env.example .env

Edit .env if needed:

CANTON_LEDGER_HOST=localhost
CANTON_LEDGER_PORT=6865
CANTON_JSON_API_PORT=7575
FACILITATOR_PORT=3000

6. Start Facilitator

npm run dev

You should see:

πŸš€ Canton x402 Facilitator
==========================

πŸ“‘ Initializing Canton client...
   Host: localhost:6865
   JSON API: localhost:7575

βœ… Connected to Canton Ledger API at localhost:6865

βœ… Facilitator server running on http://localhost:3000

Endpoints:
  GET  /health     - Health check
  GET  /supported  - Supported payment kinds
  POST /verify     - Verify payment
  POST /settle     - Settle payment

API Reference

GET /health

Check facilitator and Canton connection status.

Response:

{
  "status": "healthy",
  "facilitator": "ok",
  "canton": "connected",
  "version": "0.1.0"
}

GET /supported

Returns the payment kinds supported by this facilitator.

Response:

{
  "kinds": [
    {
      "x402Version": 1,
      "scheme": "exact-canton",
      "network": "canton-local",
      "extra": {
        "facilitatorVersion": "0.1.0",
        "features": ["verify", "settle"]
      }
    }
  ]
}

POST /verify

Verifies an x402 payment payload without settling it.

Request:

{
  "paymentPayload": {
    "x402Version": 1,
    "scheme": "exact-canton",
    "network": "canton-local",
    "payload": {
      "command": {
        "payer": "Alice::12207...abc",
        "payee": "Bob::12207...def",
        "amount": "10.00",
        "currency": "USD",
        "resourceId": "https://api.example.com/resource/123",
        "nonce": "550e8400-e29b-41d4-a716-446655440000"
      }
    }
  },
  "paymentRequirements": {
    "scheme": "exact-canton",
    "network": "canton-local",
    "maxAmountRequired": "10.00",
    "resource": "https://api.example.com/resource/123",
    "payTo": "Bob::12207...def",
    "asset": "USD"
  }
}

Response (Success):

{
  "isValid": true,
  "payer": "Alice::12207...abc"
}

Response (Failure):

{
  "isValid": false,
  "invalidReason": "insufficient_amount",
  "payer": "Alice::12207...abc"
}

POST /settle

Settles an x402 payment by submitting it to Canton.

Request: Same format as /verify

Response (Success):

{
  "success": true,
  "transaction": "12207d6f70656e2d736f757263652d6c6564676572",
  "network": "canton-local",
  "payer": "Alice::12207...abc"
}

Response (Failure):

{
  "success": false,
  "errorReason": "settlement_failed",
  "network": "canton-local",
  "payer": "Alice::12207...abc"
}

Payment Flow

  1. Client requests a resource from a resource server
  2. Server responds with 402 Payment Required and payment requirements
  3. Client creates a payment payload with Canton command
  4. Client submits request with X-PAYMENT header containing the payload
  5. Server calls facilitator /verify to check payment validity
  6. Server delivers the resource if payment is valid
  7. Server calls facilitator /settle to execute the payment on Canton
  8. Canton creates Payment contract on the ledger
  9. Server returns X-PAYMENT-RESPONSE header with settlement confirmation

Development

Project Structure

canton-x402-facilitator/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ index.ts              # Express server
β”‚   β”œβ”€β”€ canton/
β”‚   β”‚   β”œβ”€β”€ client.ts         # Canton gRPC client
β”‚   β”‚   β”œβ”€β”€ verify.ts         # Payment verification
β”‚   β”‚   └── settle.ts         # Payment settlement
β”‚   └── types/
β”‚       └── index.ts          # TypeScript types
β”œβ”€β”€ daml/
β”‚   β”œβ”€β”€ Payment.daml          # Payment smart contract
β”‚   └── daml.yaml             # Daml project config
β”œβ”€β”€ scripts/
β”‚   └── setup-canton.sh       # Canton setup script
└── README.md

Building

Compile TypeScript to JavaScript:

npm run build

Run the compiled version:

npm start

Testing

To test the facilitator, you'll need:

  1. Canton running with the Payment contract deployed
  2. Canton parties created (Alice, Bob, etc.)
  3. Test payloads that match the Payment contract structure

You can use curl to test endpoints:

# Check health
curl http://localhost:3000/health

# Check supported kinds
curl http://localhost:3000/supported

# Verify a payment (with test payload)
curl -X POST http://localhost:3000/verify \
  -H "Content-Type: application/json" \
  -d @test-payload.json

Canton Integration

How It Works

The facilitator connects to Canton via its gRPC Ledger API:

  1. gRPC Connection: Connects to Canton's CommandService on port 6865
  2. Command Submission: Submits Daml commands to create Payment contracts
  3. Transaction Confirmation: Waits for Canton to confirm the transaction
  4. Event Streaming: Can optionally stream transaction events

Payment Contract

The Daml Payment contract has these fields:

template Payment
  with
    payer: Party        -- Who is paying
    payee: Party        -- Who receives payment
    amount: Decimal     -- Amount (e.g., 10.50)
    currency: Text      -- Currency (USD, EUR, etc.)
    resourceId: Text    -- What is being paid for
    nonce: Text         -- Unique ID (prevents replay)

When settled, the Payment can be converted to a Settlement contract (immutable record).

Canton Networks

The facilitator supports:

  • canton-local: Local Canton sandbox for development
  • canton-testnet: Canton testnet (when available)
  • canton-mainnet: Canton mainnet (production)

Troubleshooting

Canton Not Starting

If Canton fails to start:

# Check Java version (need 21)
java -version

# Try starting Canton directly
./canton-release/bin/canton --version

gRPC Connection Errors

If the facilitator can't connect to Canton:

  1. Ensure Canton is running: curl http://localhost:7575/livez
  2. Check ports: lsof -i :6865 and lsof -i :7575
  3. Check PROTO_PATH in .env points to Canton proto files

Proto Loading Errors

If you see proto loading errors, set the CANTON_PROTO_PATH:

export CANTON_PROTO_PATH=/path/to/canton/community/ledger-api/src/main/protobuf

Or in .env:

CANTON_PROTO_PATH=/path/to/canton/community/ledger-api/src/main/protobuf

Daml Build Errors

If daml build fails:

# Ensure Daml SDK is installed
daml version

# Reinstall if needed
curl -sSL https://get.daml.com/ | sh

Production Deployment

For production use:

  1. Use production Canton network (not sandbox)
  2. Enable TLS for gRPC connections
  3. Add authentication (JWT tokens)
  4. Implement rate limiting on API endpoints
  5. Add monitoring (Prometheus, DataDog, etc.)
  6. Configure proper logging (structured logs)
  7. Set up database for tracking payment state
  8. Implement idempotency for settlement requests

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Submit a pull request

License

Apache 2.0 - See LICENSE file

Resources

Support

For issues and questions:

  • Open an issue on GitHub
  • Join the x402 Discord
  • Contact the maintainers

Built with ❀️ for the future of banking-grade micropayments

About

No description, website, or topics provided.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published