Skip to main content

venice_ai.auth.x402_solana

x402 Solana ("exact" scheme, SVM) settlement for Venice's /x402/top-up endpoint.

Venice's live 402 challenge (x402Version 2) advertises a Solana payment requirement whose network is the bare string "solana" (NOT a CAIP-2 id). The settlement envelope mirrors the EVM one in :mod:venice_ai.auth.x402 but carries a base64-encoded, partially-signed Solana :class:~solders.transaction.VersionedTransaction instead of an EIP-712 authorization:

{ "x402Version": 2, "scheme": "exact", "network": "solana",
"payload": { "transaction": "<base64 serialized VersionedTransaction>" } }

The transaction implements the upstream x402 "exact" scheme for SVM:

* message ``payer`` = the requirement's ``extra.feePayer`` (the facilitator
pays gas; the client only signs the SPL transfer it authorizes), and
* exactly four instructions: ComputeBudget set-unit-limit, ComputeBudget
set-unit-price, SPL ``TransferChecked``, SPL Memo.

The client signs only its own slot; the feePayer slot (index 0) is left as a
64-zero-byte placeholder for the facilitator to fill in before submission.

Usage:

from venice_ai.auth.x402_solana import SolanaX402Auth

auth = SolanaX402Auth(private_key="<base58 secret>")
# auth.wallet_address — base58 pubkey derived from the key
header = auth.build_payment_header(
requirement=req, # the network=="solana" accepts entry
recent_blockhash=blockhash,
mint_decimals=6,
token_program="Tokenkeg...",
)

This module is optional and requires ``pip install venice-ai[x402-solana]``.

SolanaX402Auth Objects

class SolanaX402Auth()

Builds base64 X-402-Payment envelopes for Venice's Solana x402 flow.

Arguments:

  • private_key: A base58-encoded Solana secret key (the 64-byte keypair, as produced by solana-keygen / wallet exports). Never share or commit this.

SolanaX402Auth.wallet_address

@property
def wallet_address() -> str

Base58 public key (wallet address) derived from the secret key.

SolanaX402Auth.build_header

def build_header(*,
nonce: str | None = None,
now: datetime | None = None) -> str

Build the base64-encoded X-Sign-In-With-X (SIGN-IN-WITH-X) header value.

Signs a Solana SIWX (Sign-In-With-X) message with the wallet's Ed25519 key so wallet-authenticated reads (client.x402.balance / transactions) work for Solana, mirroring

Arguments:

  • nonce: Optional 16-character hex nonce; a random one is generated if omitted.
  • now: Override the issuedAt timestamp (UTC), for testing.

SolanaX402Auth.build_payment_header

def build_payment_header(*,
requirement: dict[str, Any],
recent_blockhash: str,
mint_decimals: int,
token_program: str,
max_amount_units: int | None = None) -> str

Build the base64 X-402-Payment v2 envelope (PURE, no I/O).

Constructs the four-instruction Solana VersionedTransaction for the x402 "exact" SVM scheme, partial-signs the client's slot, and base64 encodes the v2 payment envelope. Performs no network I/O — the caller supplies recent_blockhash, mint_decimals and token_program (fetched live via :func:fetch_solana_tx_context).

Validates network/asset/amount BEFORE signing — refuses to sign payloads that deviate from expectations. This is a security control: a misbehaving server could otherwise ask you to authorize a transfer to an attacker-controlled address.

Arguments:

  • requirement: A single accepts entry with network == "solana" (bare string, echoed back exactly). Expected keys: asset (mint), amount (string base units), payTo (recipient owner), and extra.feePayer (the facilitator). Optional extra.memo (UTF-8, <=256 bytes) — a random 16-byte hex memo is generated when absent. Optional scheme (defaults "exact").
  • recent_blockhash: Base58 recent blockhash for the message.
  • mint_decimals: The mint's decimals (byte 44 of the mint account data), encoded into the TransferChecked instruction.
  • token_program: The mint's owning token program id (base58).
  • max_amount_units: Optional cap in token base units; refuses to sign if int(requirement["amount"]) exceeds it. None disables the cap (not recommended in production).

Raises:

  • ValueError: On validation mismatch (network/asset/amount) or a malformed requirement.

Returns:

Base64-encoded v2 X-402-Payment envelope string.

fetch_solana_tx_context

async def fetch_solana_tx_context(rpc_url: str, mint: str, *,
http: Any) -> tuple[str, int, str]

Fetch the live transaction context needed to build a Solana payment.

Performs two raw JSON-RPC calls over the supplied aiohttp session:

  1. getLatestBlockhash → recent blockhash (base58 str) for the message.
  2. getAccountInfo(mint, {encoding:"base64"}) → the mint account's owner (the token program id) and data; decimals is byte 44 of the base64-decoded mint account data.

Arguments:

  • rpc_url: Solana JSON-RPC endpoint.
  • mint: The mint (asset) base58 address from the 402 requirement.
  • http: An aiohttp.ClientSession to issue the POSTs with.

Raises:

  • RuntimeError: If the RPC returns an error or unexpected shape.

Returns:

(recent_blockhash, mint_decimals, token_program).