https://github.com/solana-foundation/mpp-sdk
Solana payment method for the Machine Payments Protocol.
https://github.com/solana-foundation/mpp-sdk
mpp solana tempo
Last synced: 3 months ago
JSON representation
Solana payment method for the Machine Payments Protocol.
- Host: GitHub
- URL: https://github.com/solana-foundation/mpp-sdk
- Owner: solana-foundation
- License: mit
- Created: 2026-03-18T14:52:28.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-03-29T05:55:56.000Z (3 months ago)
- Last Synced: 2026-03-29T05:56:19.908Z (3 months ago)
- Topics: mpp, solana, tempo
- Language: Rust
- Homepage: http://paymentauth.org/draft-solana-charge-00
- Size: 1.61 MB
- Stars: 48
- Watchers: 0
- Forks: 8
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# @solana/mpp
Solana payment method for the [Machine Payments Protocol](https://mpp.dev).
**MPP** is [an open protocol proposal](https://paymentauth.org) that lets any HTTP API accept payments using the `402 Payment Required` flow.
> [!IMPORTANT]
> This repository is under active development. The [Solana MPP spec](https://github.com/tempoxyz/mpp-specs/pull/188) is not yet finalized — APIs and wire formats are subject to change.
## Install
```bash
pnpm add @solana/mpp
```
## 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
- Split payments: send one charge to multiple recipients in a single transaction
- Replay protection via consumed transaction signatures
**General**
- Works with [ConnectorKit](https://www.connectorkit.dev), `@solana/kit` keypair signers, and [Solana Keychain](https://github.com/solana-foundation/solana-keychain) remote signers
- Server pre-fetches `recentBlockhash` to save client an RPC round-trip
- Transaction simulation before broadcast to prevent wasted fees
- Optional `tokenProgram` hint; clients resolve the mint owner and fail closed if discovery fails
## Architecture
```
mpp-sdk/
├── typescript/ # TypeScript SDK
│ └── packages/mpp/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
├── rust/ # Rust SDK (coming soon)
│ └── src/lib.rs
└── demo/ # Interactive playground
```
**Exports:**
- `@solana/mpp` — shared schemas, session types, and authorizers only
- `@solana/mpp/server` — server-side charge + session, `Mppx`, `Store`
- `@solana/mpp/client` — client-side charge + session, `Mppx`
## Quick Start
### Charge (one-time payment)
**Server:**
```ts
import { Mppx, solana } from '@solana/mpp/server'
const mppx = Mppx.create({
secretKey: process.env.MPP_SECRET_KEY,
methods: [
solana.charge({
recipient: 'RecipientPubkey...',
currency: '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:**
```ts
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')
```
### Fee Sponsorship (charge)
The server can pay transaction fees on behalf of clients:
```ts
// 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`, optional `tokenProgram`, optional `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.
### Splits (charge)
Use `splits` when one charge should pay multiple recipients in the same asset.
The top-level `amount` is the total paid. The primary `recipient` receives
`amount - sum(splits)`, and each split recipient receives its own `amount`.
```ts
import { Mppx, solana } from '@solana/mpp/server'
const mppx = Mppx.create({
secretKey: process.env.MPP_SECRET_KEY,
methods: [
solana.charge({
recipient: 'SellerPubkey...',
currency: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
decimals: 6,
splits: [
{ recipient: 'PlatformPubkey...', amount: '50000', memo: 'platform fee' },
{ recipient: 'ReferrerPubkey...', amount: '20000', memo: 'referral fee' },
],
}),
],
})
const result = await mppx.charge({
amount: '1000000', // total: 1.00 USDC
currency: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
})(request)
```
In this example:
- seller receives `930000`
- platform receives `50000`
- referrer receives `20000`
The same `splits` shape works for native SOL charges.
## Demo
An interactive playground with a React frontend and Express backend, running against [Surfpool](https://surfpool.run).
- Charge flow demo: `http://localhost:5173/charges`
- Session flow demo: `http://localhost:5173/sessions`
```bash
surfpool start
pnpm demo:install
pnpm demo:server
pnpm demo:app
```
See [demo/README.md](demo/README.md) for full details.
## Development
```bash
# TypeScript
cd typescript && pnpm install
just ts-fmt # Format and lint
just ts-build # Build
just ts-test # Unit tests (charge + session, no network)
just ts-test-integration # Integration tests (requires Surfpool)
# Rust
cd rust && cargo build
# Everything
just build # Build both
just test # Test both
just pre-commit # Full pre-commit checks
```
## Spec
This SDK implements the [Solana Charge Intent](https://github.com/tempoxyz/mpp-specs/pull/188) for the [HTTP Payment Authentication Scheme](https://paymentauth.org).
Session method docs and implementation notes are intentionally kept out of this
README for now. See [docs/methods/sessions.md](docs/methods/sessions.md).
## License
MIT