Skip to content

quiknode-labs/x402-payments

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

X402::Payments

Now supporting x402 v2!

Coverage

Ruby gem for generating signed payment HTTP headers and links using the x402 protocol.

Supports USDC and other token payments on Base, Avalanche, Solana, and other EVM networks with EIP-712 signing.

Installation

System Requirements

This gem depends on the eth gem which requires native extensions for cryptographic operations. You'll need to install system dependencies first:

macOS

brew install automake openssl libtool pkg-config gmp libffi

Ubuntu/Debian

sudo apt-get install build-essential libgmp-dev libssl-dev

Alpine Linux

apk add build-base gmp-dev openssl-dev autoconf automake libtool

Installing the Gem

Add this line to your application's Gemfile:

gem 'x402-payments'

And then execute:

bundle install

Or install it yourself as:

gem install x402-payments

Configuration

Configure the gem using environment variables. See examples/.env.example for a template.

Environment Variables

Variable Required Description
X402_PRIVATE_KEY Yes (EVM) EVM private key for signing
X402_PAY_TO Yes (EVM) EVM recipient wallet address
X402_SOL_PRIVATE_KEY Yes (Solana) Solana private key (base58 or JSON array)
X402_SOL_PAY_TO Yes (Solana) Solana recipient wallet address
X402_CHAIN No Network to use (default: base-sepolia)
X402_CURRENCY No Token symbol (default: USDC)
X402_PROTOCOL_VERSION No Protocol version 1 or 2 (default: 2)
X402_MAX_TIMEOUT_SECONDS No Payment validity timeout (default: 600)
X402_SOLANA_FEE_PAYER No Solana fee payer (default: x402.org facilitator)
X402_SOLANA_COMPUTE_UNIT_LIMIT No Solana compute unit limit (default: 200000)
X402_SOLANA_COMPUTE_UNIT_PRICE No Priority fee in micro-lamports (default: 1000)
X402_SOLANA_RPC_URL No Custom Solana mainnet RPC URL
X402_SOLANA_DEVNET_RPC_URL No Custom Solana devnet RPC URL
X402_BASE_RPC_URL No Custom Base mainnet RPC URL
X402_BASE_SEPOLIA_RPC_URL No Custom Base Sepolia RPC URL
X402_AVALANCHE_RPC_URL No Custom Avalanche mainnet RPC URL
X402_AVALANCHE_FUJI_RPC_URL No Custom Avalanche Fuji RPC URL

Supported Networks

EVM Networks:

  • base-sepolia (testnet) - Default
  • base (mainnet)
  • avalanche-fuji (testnet)
  • avalanche (mainnet)

Solana Networks:

  • solana-devnet (testnet)
  • solana (mainnet)

Custom Chains and Tokens

You can register custom EVM chains and tokens beyond the built-in options.

Register a Custom Chain

X402::Payments.configure do |config|
  config.default_pay_to = ENV['X402_PAY_TO']
  config.private_key = ENV['X402_PRIVATE_KEY']

  # Register Polygon Amoy testnet
  config.register_chain(
    name: "polygon-amoy",
    chain_id: 80002,
    standard: "eip155"
  )

  # Register the token for that chain
  config.register_token(
    chain: "polygon-amoy",
    symbol: "USDC",
    address: "0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582",
    decimals: 6,
    name: "USD Coin",
    version: "2"
  )

  # Set the RPC URL for the custom chain
  config.rpc_urls["polygon-amoy"] = "https://bitter-attentive-pool.matic-amoy.quiknode.pro"

  config.chain = "polygon-amoy"
  config.currency = "USDC"
end

You can also set RPC URLs via environment variables using the pattern X402_<CHAIN>_RPC_URL:

export X402_POLYGON_AMOY_RPC_URL="https://bitter-attentive-pool.matic-amoy.quiknode.pro"

Register a Custom Token on a Built-in Chain

X402::Payments.configure do |config|
  config.default_pay_to = ENV['X402_PAY_TO']
  config.private_key = ENV['X402_PRIVATE_KEY']

  # Accept WETH on Base instead of USDC
  config.register_token(
    chain: "base",
    symbol: "WETH",
    address: "0x4200000000000000000000000000000000000006",
    decimals: 18,
    name: "Wrapped Ether",
    version: "1"
  )

  config.chain = "base"
  config.currency = "WETH"
end

Token Registration Parameters

Parameter Required Description
chain Yes Chain name (built-in or custom registered)
symbol Yes Token symbol (e.g., "USDC", "WETH")
address Yes Token contract address
decimals Yes Token decimals (e.g., 6 for USDC, 18 for WETH)
name Yes Token name for EIP-712 domain
version No EIP-712 version (default: "1")

Solana Configuration

For Solana payments, ensure you've set the Solana-specific environment variables (see Configuration section above), then set your chain:

export X402_CHAIN="solana-devnet"  # or "solana" for mainnet

You can also override the fee payer per-request:

X402::Payments.generate_header(
  amount: 0.001,
  resource: "http://example.com/api",
  network: "solana-devnet",
  fee_payer: "CustomFacilitatorFeePayer"  # use different facilitator
)

Note: Both sender and receiver must have a USDC Associated Token Account (ATA). The sender must have USDC in their wallet (receiving USDC creates the ATA automatically).

Protocol Versions

x402-payments supports both v1 and v2 of the x402 protocol. v2 is the default.

v2 (Default)

X402::Payments.configure do |config|
  config.private_key = ENV['X402_PRIVATE_KEY']
  config.default_pay_to = ENV['X402_PAY_TO']
  config.protocol_version = 2  # Default, can be omitted
end

v2 uses CAIP-2 network identifiers (eip155:84532) and the PAYMENT-SIGNATURE header.

v1 (Legacy)

X402::Payments.configure do |config|
  config.private_key = ENV['X402_PRIVATE_KEY']
  config.default_pay_to = ENV['X402_PAY_TO']
  config.protocol_version = 1
end

v1 uses simple network names (base-sepolia) and the X-PAYMENT header.

Usage

Basic Usage

require 'x402/payments'

# Generate a signed payment header
header = X402::Payments.generate_header(
  amount: 0.001,                                    # Amount in USD
  resource: "http://localhost:3000/api/weather",   # Protected resource URL
  description: "Payment for weather API access",   # Optional description
  pay_to: "0xRecipientAddress"                     # Optional: override recipient (defaults to config)
)

# Use the header in an HTTP request (v2 uses PAYMENT-SIGNATURE, v1 uses X-PAYMENT)
# curl -H "PAYMENT-SIGNATURE: #{header}" http://localhost:3000/api/weather

Note: The pay_to parameter allows you to specify a different recipient wallet address per payment. If not provided, it uses the configured default_pay_to.

Using in Rails

The gem works seamlessly in Rails applications:

# config/initializers/x402.rb
X402::Payments.configure do |config|
  config.default_pay_to = ENV['X402_PAY_TO']
  config.private_key = ENV['X402_PRIVATE_KEY']
  config.chain = Rails.env.production? ? 'base' : 'base-sepolia'

  # Optional: Override RPC URLs programmatically
  # config.rpc_urls = {
  #   'base' => 'https://your-custom-base-rpc.com',
  #   'base-sepolia' => 'https://your-sepolia-rpc.com'
  # }
end

# In your controller or service
class PaymentService
  def self.generate_payment_for(resource_url, amount)
    X402::Payments.generate_header(
      amount: amount,
      resource: resource_url,
      description: "Payment for #{resource_url}"
    )
  end
end

Using Standalone (Non-Rails)

#!/usr/bin/env ruby
require 'x402/payments'

# Set environment variables or configure directly
X402::Payments.configure do |config|
  config.default_pay_to = "0xYourDefaultRecipient"
  config.private_key = "0xYourPrivateKeyHere"
  config.chain = "base-sepolia"
  # config.rpc_urls = { 'base-sepolia' => 'https://your-custom-rpc.com' }
end

# Generate payment
header = X402::Payments.generate_header(
  amount: 0.001,
  resource: "http://localhost:3000/api/data",
  # version: 1,                              # Override configured protocol version (1 or 2)
  # network: "avalanche",                    # Override default network
  # private_key: "0xDifferentKey",           # Override default key
  # pay_to: "0xRecipientWalletAddress",      # Override recipient address
)

puts "Payment Header:"
puts header

# v2 (default) uses PAYMENT-SIGNATURE, v1 uses X-PAYMENT
HTTParty.get("http://localhost:3000/api/data", headers: { "PAYMENT-SIGNATURE" => header })

How It Works

  1. Payment Requirements: The gem creates a payment requirement specifying the amount (in USDC atomic units), network, and resource
  2. Transaction Signing:
    • EVM: Uses EIP-3009 TransferWithAuthorization to create a signature that authorizes the payment
    • Solana: Creates a partially-signed TransferChecked transaction (facilitator adds fee payer signature)
  3. Header Encoding: Encodes the signed payment data as a base64 string for the HTTP header (PAYMENT-SIGNATURE for v2, X-PAYMENT for v1)
  4. Server Validation: The server validates the signature/transaction and settles the payment on-chain via the facilitator

Example Script

A complete example script is provided in examples/generate_payment.rb:

# Create your .env file in examples directory
cd examples
cp .env.example .env
# Edit .env with your credentials

# Run the example
cd ..
export $(cat examples/.env | xargs)
ruby examples/generate_payment.rb

This will generate a signed payment header and provide a ready-to-use curl command for testing. See examples/README.md for more details.

Development

After checking out the repo, run:

bin/setup        # Install dependencies
bundle exec rake spec   # Run tests
bin/console      # Interactive prompt for experimentation

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/yourusername/x402-payments.

Requirements

  • Ruby 3.0+

Resources

License

MIT License. See LICENSE.txt.

About

Ruby gem for generating signed payment HTTP headers and links using the x402 protocol.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •