svm

package
v0.0.0-...-0e07cd4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 9, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

README

SVM Mechanisms

This directory contains payment mechanism implementations for SVM (Solana Virtual Machine) networks.

What This Exports

This package provides scheme implementations for Solana-based blockchains that can be used by clients, servers, and facilitators.

Exact Payment Scheme

The exact scheme implementation enables fixed-amount payments using Solana token transfers for USDC SPL tokens.

Export Paths

The exact scheme is organized by role:

For Clients

Import Path:

github.com/coinbase/x402/go/mechanisms/svm/exact/client

Exports:

  • NewExactSvmScheme(signer) - Creates client-side SVM exact payment mechanism
  • Used for creating payment payloads with partial transaction signatures
For Servers

Import Path:

github.com/coinbase/x402/go/mechanisms/svm/exact/server

Exports:

  • NewExactSvmScheme() - Creates server-side SVM exact payment mechanism
  • Used for building payment requirements and parsing prices
  • Supports custom money parsers via RegisterMoneyParser()
For Facilitators

Import Path:

github.com/coinbase/x402/go/mechanisms/svm/exact/facilitator

Exports:

  • NewExactSvmScheme(signer) - Creates facilitator-side SVM exact payment mechanism
  • Used for verifying transaction signatures and settling payments on-chain
  • Requires facilitator signer with Solana RPC integration

Supported Networks

All Solana networks using CAIP-2 network identifiers:

  • Solana Mainnet: solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp
  • Solana Devnet: solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1
  • Solana Testnet: solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z

Use solana:* wildcard to support all Solana networks.

Scheme Implementation

The exact scheme implements fixed-amount payments:

  • Method: Solana token transfers
  • Token: USDC SPL token
  • Signing: Partial transaction signing (client + facilitator)
  • Fees: Rent and transaction fees paid by facilitator
  • Confirmation: On-chain settlement with transaction signature

Duplicate Settlement Protection

This package includes a built-in SettlementCache that prevents a known race condition on Solana where the same payment transaction could be settled multiple times before on-chain confirmation. The NewExactSvmScheme facilitator constructor accepts an optional *SettlementCache parameter — when the same cache instance is passed to both V1 and V2 facilitator schemes, cross-version duplicate detection is enabled.

The cache rejects concurrent /settle calls that carry the same transaction payload, returning a duplicate_settlement error for the second and subsequent attempts. Entries are automatically evicted after 120 seconds (approximately twice the Solana blockhash lifetime).

import svm "github.com/coinbase/x402/go/mechanisms/svm"

cache := svm.NewSettlementCache()

// Share the same cache across V1 and V2 schemes
v2Scheme := facilitator.NewExactSvmScheme(signer, cache)
v1Scheme := v1facilitator.NewExactSvmSchemeV1(signer, cache)

For full details on the race condition and mitigation strategy, see the Exact SVM Scheme Specification.

Future Schemes

This directory currently contains only the exact scheme implementation. As new payment schemes are developed for Solana networks, they will be added here alongside the exact implementation:

svm/
├── exact/          - Fixed amount payments (current)
├── upto/           - Variable amount up to a limit (planned)
├── subscription/   - Recurring payments (planned)
└── batch/          - Batched payments (planned)

Each new scheme will follow the same three-role structure (client, server, facilitator).

Contributing New Schemes

We welcome contributions of new payment scheme implementations for Solana networks!

To contribute a new scheme:

  1. Create directory structure: svm/{scheme_name}/client/, svm/{scheme_name}/server/, svm/{scheme_name}/facilitator/
  2. Implement the required interfaces for each role
  3. Add comprehensive tests
  4. Document the scheme specification
  5. Provide usage examples

See CONTRIBUTING.md for more details.

Documentation

Index

Constants

View Source
const (
	// SchemeExact is the scheme identifier for exact payments
	SchemeExact = "exact"

	// DefaultDecimals is the default token decimals for USDC
	DefaultDecimals = 6

	// DefaultComputeUnitPriceMicrolamports is the default compute unit price in microlamports
	DefaultComputeUnitPriceMicrolamports = 1

	// MaxComputeUnitPriceMicrolamports is the maximum compute unit price in microlamports (facilitator validation limit)
	// 5 lamports = 5,000,000 microlamports
	MaxComputeUnitPriceMicrolamports = 5_000_000

	// DefaultComputeUnitLimit is the default compute unit limit for transactions
	// Set to 20000 to accommodate: transfer (~6200 CUs) + memo (~8500 CUs without signer) + budget instructions (~300 CUs) + headroom
	DefaultComputeUnitLimit uint32 = 20000

	// LighthouseProgramAddress is the Phantom/Solflare Lighthouse program address
	// Phantom and Solflare wallets inject Lighthouse instructions for user protection on mainnet transactions.
	// - Phantom adds 1 Lighthouse instruction (4th instruction)
	// - Solflare adds 2 Lighthouse instructions (4th and 5th instructions)
	// We allow these as optional instructions to support these wallets.
	// See: https://github.com/coinbase/x402/issues/828
	LighthouseProgramAddress = "L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95"

	// MemoProgramAddress is the SPL Memo program address
	MemoProgramAddress = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"

	// DefaultCommitment is the default commitment level for transactions
	DefaultCommitment = rpc.CommitmentConfirmed

	// MaxConfirmAttempts is the maximum number of confirmation attempts
	MaxConfirmAttempts = 30

	// ConfirmRetryDelay is the base delay between confirmation attempts
	ConfirmRetryDelay = 1 * time.Second

	// SettlementTTL is how long a transaction is held in the duplicate settlement cache.
	// Covers the Solana blockhash lifetime (~60-90s) with margin.
	SettlementTTL = 120 * time.Second

	// CAIP-2 network identifiers (V2)
	SolanaMainnetCAIP2 = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
	SolanaDevnetCAIP2  = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"
	SolanaTestnetCAIP2 = "solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z"

	// V1 network names
	SolanaMainnetV1 = "solana"
	SolanaDevnetV1  = "solana-devnet"
	SolanaTestnetV1 = "solana-testnet"

	// USDC mint addresses
	USDCMainnetAddress = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
	USDCDevnetAddress  = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"
	USDCTestnetAddress = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" // Same as devnet
)

Variables

View Source
var (
	// NetworkConfigs maps CAIP-2 identifiers to network configurations
	// See DEFAULT_ASSET.md for guidelines on adding new networks
	NetworkConfigs = map[string]NetworkConfig{
		SolanaMainnetCAIP2: {
			Name:   "Solana Mainnet",
			CAIP2:  SolanaMainnetCAIP2,
			RPCURL: "https://api.mainnet-beta.solana.com",
			DefaultAsset: AssetInfo{
				Address:  USDCMainnetAddress,
				Symbol:   "USDC",
				Decimals: DefaultDecimals,
			},
		},
		SolanaDevnetCAIP2: {
			Name:   "Solana Devnet",
			CAIP2:  SolanaDevnetCAIP2,
			RPCURL: "https://api.devnet.solana.com",
			DefaultAsset: AssetInfo{
				Address:  USDCDevnetAddress,
				Symbol:   "USDC",
				Decimals: DefaultDecimals,
			},
		},
		SolanaTestnetCAIP2: {
			Name:   "Solana Testnet",
			CAIP2:  SolanaTestnetCAIP2,
			RPCURL: "https://api.testnet.solana.com",
			DefaultAsset: AssetInfo{
				Address:  USDCTestnetAddress,
				Symbol:   "USDC",
				Decimals: DefaultDecimals,
			},
		},
	}

	// V1ToV2NetworkMap maps V1 network names to CAIP-2 identifiers
	V1ToV2NetworkMap = map[string]string{
		SolanaMainnetV1: SolanaMainnetCAIP2,
		SolanaDevnetV1:  SolanaDevnetCAIP2,
		SolanaTestnetV1: SolanaTestnetCAIP2,
	}
)

Functions

func DecodeTransaction

func DecodeTransaction(base64Tx string) (*solana.Transaction, error)

DecodeTransaction decodes a base64 encoded Solana transaction

func EncodeTransaction

func EncodeTransaction(tx *solana.Transaction) (string, error)

EncodeTransaction encodes a Solana transaction to base64

func FormatAmount

func FormatAmount(amount uint64, decimals int) string

FormatAmount converts an amount in smallest units to a decimal string

func GetTokenPayerFromTransaction

func GetTokenPayerFromTransaction(tx *solana.Transaction) (string, error)

GetTokenPayerFromTransaction extracts the token payer (owner) address from a transaction This looks for the TransferChecked instruction and returns the owner/authority address

func IsValidNetwork

func IsValidNetwork(network string) bool

IsValidNetwork checks if the network is supported for Solana

func NormalizeNetwork

func NormalizeNetwork(network string) (string, error)

NormalizeNetwork converts V1 network names to CAIP-2 format

func ParseAmount

func ParseAmount(amount string, decimals int) (uint64, error)

ParseAmount converts a decimal string amount to token smallest units

func ValidateSolanaAddress

func ValidateSolanaAddress(address string) bool

ValidateSolanaAddress checks if a string is a valid Solana address

Types

type AssetInfo

type AssetInfo struct {
	Address  string // Mint address
	Symbol   string // Token symbol (e.g., "USDC")
	Decimals int    // Token decimals
}

AssetInfo contains information about a SPL token

func GetAssetInfo

func GetAssetInfo(network string, assetSymbolOrAddress string) (*AssetInfo, error)

GetAssetInfo returns information about an asset on a network

type ClientConfig

type ClientConfig struct {
	RPCURL string // Custom RPC URL
}

ClientConfig contains optional client configuration

type ClientSvmSigner

type ClientSvmSigner interface {
	// Address returns the signer's Solana address (base58)
	Address() solana.PublicKey

	// SignTransaction signs a Solana transaction
	SignTransaction(ctx context.Context, tx *solana.Transaction) error
}

ClientSvmSigner defines client-side operations

type ExactSvmPayload

type ExactSvmPayload struct {
	Transaction string `json:"transaction"` // Base64 encoded Solana transaction
}

ExactSvmPayload represents a SVM (Solana) payment payload

func PayloadFromMap

func PayloadFromMap(data map[string]interface{}) (*ExactSvmPayload, error)

PayloadFromMap creates an ExactSvmPayload from a map

func (*ExactSvmPayload) ToMap

func (p *ExactSvmPayload) ToMap() map[string]interface{}

ToMap converts an ExactSvmPayload to a map for JSON marshaling

type ExactSvmPayloadV1

type ExactSvmPayloadV1 = ExactSvmPayload

ExactSvmPayloadV1 - alias for v1 compatibility

type ExactSvmPayloadV2

type ExactSvmPayloadV2 = ExactSvmPayload

ExactSvmPayloadV2 - alias for v2 (currently identical, reserved for future)

type FacilitatorSvmSigner

type FacilitatorSvmSigner interface {
	// GetAddresses returns all addresses this facilitator can use as fee payers for a network
	// Enables dynamic address selection for load balancing and key rotation
	GetAddresses(ctx context.Context, network string) []solana.PublicKey

	// SignTransaction signs a transaction with the signer matching feePayer
	// Transaction is modified in-place to add the facilitator's signature
	// Returns error if no signer exists for feePayer or signing fails
	SignTransaction(ctx context.Context, tx *solana.Transaction, feePayer solana.PublicKey, network string) error

	// SimulateTransaction simulates a signed transaction to verify it would succeed
	// Returns error if simulation fails
	SimulateTransaction(ctx context.Context, tx *solana.Transaction, network string) error

	// SendTransaction sends a signed transaction to the network
	// Returns transaction signature or error if send fails
	SendTransaction(ctx context.Context, tx *solana.Transaction, network string) (solana.Signature, error)

	// ConfirmTransaction waits for transaction confirmation
	// Returns error if confirmation fails or times out
	ConfirmTransaction(ctx context.Context, signature solana.Signature, network string) error
}

FacilitatorSvmSigner defines facilitator operations for SVM Supports multiple signers for load balancing, key rotation, and high availability All implementation details (RPC clients, key management) are hidden

type NetworkConfig

type NetworkConfig struct {
	Name         string    // Network name
	CAIP2        string    // CAIP-2 identifier
	RPCURL       string    // Default RPC URL
	DefaultAsset AssetInfo // Default stablecoin
}

NetworkConfig contains network-specific configuration See DEFAULT_ASSET.md for guidelines on adding new chains

func GetNetworkConfig

func GetNetworkConfig(network string) (*NetworkConfig, error)

GetNetworkConfig returns the configuration for a network

type SettlementCache

type SettlementCache struct {
	// contains filtered or unexported fields
}

SettlementCache is a thread-safe in-memory cache for deduplicating concurrent settlement requests. A single instance should be shared across V1 and V2 facilitator scheme instances so that a transaction submitted through one protocol version is also blocked on the other.

func NewSettlementCache

func NewSettlementCache() *SettlementCache

NewSettlementCache creates a new, empty SettlementCache.

func (*SettlementCache) Entries

func (c *SettlementCache) Entries() map[string]time.Time

Entries returns a snapshot of the underlying map — use only in tests.

func (*SettlementCache) IsDuplicate

func (c *SettlementCache) IsDuplicate(key string) bool

IsDuplicate returns true if key is already pending settlement (duplicate). Otherwise it records the key as newly pending and returns false. Callers should reject the settlement when this returns true.

func (*SettlementCache) Mu

func (c *SettlementCache) Mu() *sync.Mutex

Mu returns the mutex — use only in tests.

Directories

Path Synopsis
exact

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL