@solana/mpp 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +212 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://github.com/solana-foundation/mpp-sdk/raw/main/assets/banner.png" alt="MPP" width="100%" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# @solana/mpp
|
|
6
|
+
|
|
7
|
+
Solana payment method for the [Machine Payments Protocol](https://mpp.dev).
|
|
8
|
+
|
|
9
|
+
**MPP** is [an open protocol proposal](https://paymentauth.org) that lets any HTTP API accept payments using the `402 Payment Required` flow.
|
|
10
|
+
|
|
11
|
+
> [!IMPORTANT]
|
|
12
|
+
> 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.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm add @solana/mpp
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Features
|
|
21
|
+
|
|
22
|
+
**Charge** (one-time payments)
|
|
23
|
+
- Native SOL and SPL token transfers (USDC, PYUSD, Token-2022, etc.)
|
|
24
|
+
- Two settlement modes: pull (`type="transaction"`, default) and push (`type="signature"`)
|
|
25
|
+
- Fee sponsorship: server pays transaction fees on behalf of clients
|
|
26
|
+
- Split payments: send one charge to multiple recipients in a single transaction
|
|
27
|
+
- Replay protection via consumed transaction signatures
|
|
28
|
+
|
|
29
|
+
**General**
|
|
30
|
+
- Works with [ConnectorKit](https://www.connectorkit.dev), `@solana/kit` keypair signers, and [Solana Keychain](https://github.com/solana-foundation/solana-keychain) remote signers
|
|
31
|
+
- Server pre-fetches `recentBlockhash` to save client an RPC round-trip
|
|
32
|
+
- Transaction simulation before broadcast to prevent wasted fees
|
|
33
|
+
- Optional `tokenProgram` hint; clients resolve the mint owner and fail closed if discovery fails
|
|
34
|
+
|
|
35
|
+
## Architecture
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
mpp-sdk/
|
|
39
|
+
├── typescript/ # TypeScript SDK
|
|
40
|
+
│ └── packages/mpp/src/
|
|
41
|
+
│ ├── Methods.ts # Shared charge + session schemas
|
|
42
|
+
│ ├── constants.ts # Token programs, USDC mints, RPC URLs
|
|
43
|
+
│ ├── server/
|
|
44
|
+
│ │ ├── Charge.ts # Server: challenge, verify, broadcast
|
|
45
|
+
│ │ └── Session.ts # Server: session channel management
|
|
46
|
+
│ ├── client/
|
|
47
|
+
│ │ ├── Charge.ts # Client: build tx, sign, send
|
|
48
|
+
│ │ └── Session.ts # Client: session lifecycle
|
|
49
|
+
│ └── session/
|
|
50
|
+
│ ├── Types.ts # Session types and interfaces
|
|
51
|
+
│ ├── Voucher.ts # Voucher signing and verification
|
|
52
|
+
│ ├── ChannelStore.ts # Persistent channel state
|
|
53
|
+
│ └── authorizers/ # Pluggable authorization strategies
|
|
54
|
+
├── rust/ # Rust SDK (coming soon)
|
|
55
|
+
│ └── src/lib.rs
|
|
56
|
+
└── demo/ # Interactive playground
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Exports:**
|
|
60
|
+
- `@solana/mpp` — shared schemas, session types, and authorizers only
|
|
61
|
+
- `@solana/mpp/server` — server-side charge + session, `Mppx`, `Store`
|
|
62
|
+
- `@solana/mpp/client` — client-side charge + session, `Mppx`
|
|
63
|
+
|
|
64
|
+
## Quick Start
|
|
65
|
+
|
|
66
|
+
### Charge (one-time payment)
|
|
67
|
+
|
|
68
|
+
**Server:**
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { Mppx, solana } from '@solana/mpp/server'
|
|
72
|
+
|
|
73
|
+
const mppx = Mppx.create({
|
|
74
|
+
secretKey: process.env.MPP_SECRET_KEY,
|
|
75
|
+
methods: [
|
|
76
|
+
solana.charge({
|
|
77
|
+
recipient: 'RecipientPubkey...',
|
|
78
|
+
currency: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
79
|
+
decimals: 6,
|
|
80
|
+
}),
|
|
81
|
+
],
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
const result = await mppx.charge({
|
|
85
|
+
amount: '1000000', // 1 USDC
|
|
86
|
+
currency: 'USDC',
|
|
87
|
+
})(request)
|
|
88
|
+
|
|
89
|
+
if (result.status === 402) return result.challenge
|
|
90
|
+
return result.withReceipt(Response.json({ data: '...' }))
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Client:**
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { Mppx, solana } from '@solana/mpp/client'
|
|
97
|
+
|
|
98
|
+
const mppx = Mppx.create({
|
|
99
|
+
methods: [solana.charge({ signer })], // any TransactionSigner
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
const response = await mppx.fetch('https://api.example.com/paid-endpoint')
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Fee Sponsorship (charge)
|
|
106
|
+
|
|
107
|
+
The server can pay transaction fees on behalf of clients:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
// Server — pass a TransactionPartialSigner to cover fees
|
|
111
|
+
solana.charge({
|
|
112
|
+
recipient: '...',
|
|
113
|
+
signer: feePayerSigner, // KeyPairSigner, Keychain SolanaSigner, etc.
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
// Client — no changes needed, fee payer is handled automatically
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## How It Works
|
|
120
|
+
|
|
121
|
+
### Charge Flow
|
|
122
|
+
|
|
123
|
+
1. Client requests a resource
|
|
124
|
+
2. Server returns **402 Payment Required** with a challenge (`recipient`, `amount`, `currency`, optional `tokenProgram`, optional `recentBlockhash`)
|
|
125
|
+
3. Client builds and signs a Solana transfer transaction
|
|
126
|
+
4. Server simulates, broadcasts, confirms on-chain, and verifies the transfer
|
|
127
|
+
5. Server returns the resource with a `Payment-Receipt` header
|
|
128
|
+
|
|
129
|
+
With fee sponsorship, the client partially signs (transfer authority only) and the server co-signs as fee payer before broadcasting.
|
|
130
|
+
|
|
131
|
+
### Splits (charge)
|
|
132
|
+
|
|
133
|
+
Use `splits` when one charge should pay multiple recipients in the same asset.
|
|
134
|
+
The top-level `amount` is the total paid. The primary `recipient` receives
|
|
135
|
+
`amount - sum(splits)`, and each split recipient receives its own `amount`.
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import { Mppx, solana } from '@solana/mpp/server'
|
|
139
|
+
|
|
140
|
+
const mppx = Mppx.create({
|
|
141
|
+
secretKey: process.env.MPP_SECRET_KEY,
|
|
142
|
+
methods: [
|
|
143
|
+
solana.charge({
|
|
144
|
+
recipient: 'SellerPubkey...',
|
|
145
|
+
currency: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
146
|
+
decimals: 6,
|
|
147
|
+
splits: [
|
|
148
|
+
{ recipient: 'PlatformPubkey...', amount: '50000', memo: 'platform fee' },
|
|
149
|
+
{ recipient: 'ReferrerPubkey...', amount: '20000', memo: 'referral fee' },
|
|
150
|
+
],
|
|
151
|
+
}),
|
|
152
|
+
],
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
const result = await mppx.charge({
|
|
156
|
+
amount: '1000000', // total: 1.00 USDC
|
|
157
|
+
currency: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
158
|
+
})(request)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
In this example:
|
|
162
|
+
- seller receives `930000`
|
|
163
|
+
- platform receives `50000`
|
|
164
|
+
- referrer receives `20000`
|
|
165
|
+
|
|
166
|
+
The same `splits` shape works for native SOL charges.
|
|
167
|
+
|
|
168
|
+
## Demo
|
|
169
|
+
|
|
170
|
+
An interactive playground with a React frontend and Express backend, running against [Surfpool](https://surfpool.run).
|
|
171
|
+
|
|
172
|
+
- Charge flow demo: `http://localhost:5173/charges`
|
|
173
|
+
- Session flow demo: `http://localhost:5173/sessions`
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
surfpool start
|
|
177
|
+
pnpm demo:install
|
|
178
|
+
pnpm demo:server
|
|
179
|
+
pnpm demo:app
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
See [demo/README.md](demo/README.md) for full details.
|
|
183
|
+
|
|
184
|
+
## Development
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
# TypeScript
|
|
188
|
+
cd typescript && pnpm install
|
|
189
|
+
|
|
190
|
+
just ts-fmt # Format and lint
|
|
191
|
+
just ts-build # Build
|
|
192
|
+
just ts-test # Unit tests (charge + session, no network)
|
|
193
|
+
just ts-test-integration # Integration tests (requires Surfpool)
|
|
194
|
+
# Rust
|
|
195
|
+
cd rust && cargo build
|
|
196
|
+
|
|
197
|
+
# Everything
|
|
198
|
+
just build # Build both
|
|
199
|
+
just test # Test both
|
|
200
|
+
just pre-commit # Full pre-commit checks
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Spec
|
|
204
|
+
|
|
205
|
+
This SDK implements the [Solana Charge Intent](https://github.com/tempoxyz/mpp-specs/pull/188) for the [HTTP Payment Authentication Scheme](https://paymentauth.org).
|
|
206
|
+
|
|
207
|
+
Session method docs and implementation notes are intentionally kept out of this
|
|
208
|
+
README for now. See [docs/methods/sessions.md](docs/methods/sessions.md).
|
|
209
|
+
|
|
210
|
+
## License
|
|
211
|
+
|
|
212
|
+
MIT
|