JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 2551
  • Score
    100M100P100Q100117F

Solana payment method for the MPP protocol

Package Exports

  • @solana/mpp
  • @solana/mpp/client
  • @solana/mpp/server

Readme

MPP

@solana/mpp

Solana payment method for the Machine Payments Protocol.

MPP is an open protocol proposal that lets any HTTP API accept payments using the 402 Payment Required flow.

[!IMPORTANT] This repository is under active development. The Solana MPP spec is not yet finalized — APIs and wire formats are subject to change.

Install

pnpm add @solana/mpp

Peer dependencies:

pnpm add @solana/kit mppx
# Optional — for Swig session authorization:
pnpm add @swig-wallet/kit

Features

Charge (one-time payments)

  • Native SOL and SPL token transfers (USDC, PYUSD, Token-2022, etc.)
  • Two settlement modes: pull (type="transaction", default) and push (type="signature")
  • Fee sponsorship: server pays transaction fees on behalf of clients
  • Replay protection via consumed transaction signatures

Session (metered / streaming payments)

  • Voucher-based payment channels with monotonic cumulative amounts
  • Multiple authorization modes: unbounded, regular_budget, swig_session
  • Auto-open, auto-topup, and close lifecycle
  • Swig smart wallet integration for on-chain spend limits

General

  • Works with ConnectorKit, @solana/kit keypair signers, and Solana Keychain remote signers
  • Server pre-fetches recentBlockhash to save client an RPC round-trip
  • Transaction simulation before broadcast to prevent wasted fees

Architecture

sdk/src/
├── Methods.ts              # Shared charge + session schemas
├── constants.ts            # Token programs, USDC mints, RPC URLs
├── server/
│   ├── Charge.ts           # Server: challenge, verify, broadcast
│   └── Session.ts          # Server: session channel management
├── client/
│   ├── Charge.ts           # Client: build tx, sign, send
│   └── Session.ts          # Client: session lifecycle
└── session/
    ├── Types.ts            # Session types and interfaces
    ├── Voucher.ts          # Voucher signing and verification
    ├── ChannelStore.ts     # Persistent channel state
    └── authorizers/        # Pluggable authorization strategies
        ├── UnboundedAuthorizer.ts
        ├── BudgetAuthorizer.ts
        └── SwigSessionAuthorizer.ts

Exports:

  • @solana/mpp — shared schemas, session types, and authorizers
  • @solana/mpp/server — server-side charge + session, Mppx, Store
  • @solana/mpp/client — client-side charge + session, Mppx

Quick Start

Charge (one-time payment)

Server:

import { Mppx, solana } from '@solana/mpp/server'

const mppx = Mppx.create({
  secretKey: process.env.MPP_SECRET_KEY,
  methods: [
    solana.charge({
      recipient: 'RecipientPubkey...',
      splToken: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
      decimals: 6,
    }),
  ],
})

const result = await mppx.charge({
  amount: '1000000', // 1 USDC
  currency: 'USDC',
})(request)

if (result.status === 402) return result.challenge
return result.withReceipt(Response.json({ data: '...' }))

Client:

import { Mppx, solana } from '@solana/mpp/client'

const mppx = Mppx.create({
  methods: [solana.charge({ signer })], // any TransactionSigner
})

const response = await mppx.fetch('https://api.example.com/paid-endpoint')

Session (metered payments)

Server:

import { Mppx, solana } from '@solana/mpp/server'

const mppx = Mppx.create({
  secretKey: process.env.MPP_SECRET_KEY,
  methods: [
    solana.session({
      recipient: 'RecipientPubkey...',
      asset: { kind: 'sol', decimals: 9 },
      channelProgram: 'ChannelProgramId...',
      pricing: { unit: 'request', amountPerUnit: '10', meter: 'api_calls' },
      sessionDefaults: { suggestedDeposit: '1000', ttlSeconds: 60 },
    }),
  ],
})

Client:

import { Mppx, solana } from '@solana/mpp/client'
import { UnboundedAuthorizer } from '@solana/mpp'

const mppx = Mppx.create({
  methods: [
    solana.session({
      signer,
      authorizer: new UnboundedAuthorizer({ signer, buildOpenTx, buildTopupTx }),
    }),
  ],
})

const response = await mppx.fetch('https://api.example.com/metered-endpoint')

Fee Sponsorship (charge)

The server can pay transaction fees on behalf of clients:

// Server — pass a TransactionPartialSigner to cover fees
solana.charge({
  recipient: '...',
  signer: feePayerSigner, // KeyPairSigner, Keychain SolanaSigner, etc.
})

// Client — no changes needed, fee payer is handled automatically

How It Works

Charge Flow

  1. Client requests a resource
  2. Server returns 402 Payment Required with a challenge (recipient, amount, currency, recentBlockhash)
  3. Client builds and signs a Solana transfer transaction
  4. Server simulates, broadcasts, confirms on-chain, and verifies the transfer
  5. Server returns the resource with a Payment-Receipt header

With fee sponsorship, the client partially signs (transfer authority only) and the server co-signs as fee payer before broadcasting.

Session Flow

  1. First request: server returns 402, client opens a channel (deposit + voucher)
  2. Subsequent requests: client sends updated vouchers with monotonic cumulative amounts
  3. Server deducts from the channel balance per its pricing config
  4. When balance runs low: client tops up the channel
  5. On close: final voucher settles the channel

Demo

An interactive playground with a React frontend and Express backend, running against Surfpool.

  • Charge flow demo: http://localhost:5173/charges
  • Session flow demo: http://localhost:5173/sessions
surfpool start
pnpm demo:install
pnpm demo:server
pnpm demo:app

See demo/README.md for full details.

Development

pnpm install

just fmt              # Format and lint
just build            # Typecheck
just test             # Unit tests (charge + session, no network)
just test-integration # Integration tests (requires Surfpool)
just test-all         # All tests
just pre-commit       # fmt + typecheck + unit tests

Spec

This SDK implements the Solana Charge Intent for the HTTP Payment Authentication Scheme.

Session method docs and implementation notes:

License

MIT