mppx-arc

April 5, 2026 · View on GitHub

MPP (Machine Payments Protocol) payment method for Arc chain. USDC-native charge + session support.

Note: This is an experimental integration. Both x402 and MPP are actively evolving protocols — features, capabilities, and architecture can change rapidly. What's described here reflects the state of both protocols at the time of writing. MPP may or may not become officially supported on Arc — this project demonstrates that it's technically feasible and the code is fully open source.

Why MPP on Arc?

Arc already supports x402 for machine payments. MPP complements it — they solve different problems:

x402 (V2)MPP
Best forSimple per-request paymentsHigh-frequency agent workflows
Payment modelPer-request on-chain txSession channels (1 tx → 100s of off-chain requests)
SessionsWallet-based identity (re-access paid resources)Payment channels with off-chain vouchers
StreamingNoSSE pay-per-token
VerificationFacilitator server requiredNo facilitator (server verifies via ecrecover)
SDKPlugin-based, multi-chainPlugin-based (mppx), multi-chain
Standards bodyOpen specIETF Internet-Draft
Backed byCoinbaseStripe, Tempo, Paradigm

Both use USDC. Both use HTTP 402. Both are actively evolving — features listed here reflect the current state and may change as each protocol develops.

When does MPP matter?

  • AI agent making 500 API calls/minute — x402: 500 on-chain tx. MPP: 1 tx + 499 off-chain vouchers.
  • LLM service charging per token — Pay $0.0001 per word as it streams. x402 can't do per-token billing.
  • Data feed with continuous polling — Agent polls every second for an hour. x402: 3,600 tx. MPP: 1 tx + 3,599 vouchers at ~3ms each.

What is this?

MPP is the open standard for machine-to-machine payments via HTTP 402, co-developed by Tempo and Stripe. This package brings MPP to Arc, Circle's sovereign L1 blockchain where USDC is the native gas token.

Payment modes:

  • Charge — One-time USDC payments. Push mode (client broadcasts) or pull mode (client signs ERC-3009, server broadcasts — gasless for client).
  • Session — Streaming micropayments via payment channels. Client deposits USDC into escrow, then signs off-chain vouchers for each request. Sub-ms verification, $0.0001 per request possible.
  • SSE Streaming — Pay-per-token streaming for LLM responses. Real server-side SSE with voucher budget gating.
  • HTML Payment Page — Browser-friendly 402 page for non-agent clients.

USDC only — no bridged tokens, no extra gas tokens. Arc's native currency.

Demo

Architecture

Agent (Client)                          Server
  |                                       |
  |-- GET /api/resource ----------------->|
  |<-- 402 + WWW-Authenticate: Payment --|
  |   method="arc", intent="charge"       |
  |                                       |
  |-- Sign ERC-3009 authorization         |
  |                                       |
  |-- Authorization: Payment <cred> ----->|
  |                                       |
  |   Verify signature (ecrecover)        |
  |   Broadcast transferWithAuth          |
  |                                       |
  |<-- 200 OK + Payment-Receipt ----------|

For sessions, the first request opens a channel (1 on-chain tx), then all subsequent requests use off-chain vouchers (CPU-only verification):

Agent                                   Server
  |                                       |
  |-- Open channel (1 on-chain tx) ------>|
  |-- Voucher #1 (off-chain, ~1ms) ----->|  ← no blockchain
  |-- Voucher #2 (off-chain, ~1ms) ----->|  ← no blockchain
  |-- Voucher #3 (off-chain, ~1ms) ----->|  ← no blockchain
  |-- ... hundreds of requests ...        |
  |                                       |
  |   Server auto-settles at threshold    |
  |   (batch on-chain settlement)         |

mppx Plugin Interface

Implements the official mppx plugin API (Method.from / Method.toClient / Method.toServer):

import { arcChargeServer, arcSessionServer } from "@mppx-arc/mpp";

const chargeMethod = arcChargeServer({ recipient: SERVER_ADDRESS, walletClient });
const sessionMethod = arcSessionServer({
  payee: SERVER_ADDRESS,
  escrow: ESCROW,
  amountPerRequest: 10000n,
});

Also exports standalone functions for direct use without the mppx framework.

Deployed Contracts

NetworkContractAddress
Arc TestnetArcStreamChannel0x805aCAD6064CBfABac71a021c3ab432920925533
Arc TestnetUSDC0x3600000000000000000000000000000000000000

Quick Start

Install

npm install @mppx-arc/mpp viem mppx

Server (Hono)

import { Hono } from "hono";
import { verifyCharge, arcTestnet, ARC_USDC } from "@mppx-arc/mpp";

const app = new Hono();

app.get("/api/data", async (c) => {
  const auth = c.req.header("Authorization");

  if (!auth?.startsWith("Payment ")) {
    return c.json({
      method: "arc",
      intent: "charge",
      recipient: SERVER_ADDRESS,
      amount: "100000", // \$0.10 USDC
      chainId: arcTestnet.id,
      currency: ARC_USDC,
    }, 402);
  }

  const credential = JSON.parse(
    Buffer.from(auth.slice(8), "base64").toString()
  );

  const receipt = await verifyCharge({
    credential,
    expectedRecipient: SERVER_ADDRESS,
    expectedAmount: 100000n,
    publicClient,
    walletClient,
  });

  return c.json({ data: "paid content", receipt });
});

Client (Agent)

import { createChargeCredential, arcTestnet } from "@mppx-arc/mpp";

const res = await fetch("https://api.example.com/data");
const challenge = await res.json();

const credential = await createChargeCredential({
  challenge,
  walletClient,
  publicClient,
  mode: "pull", // gasless for client
});

const paid = await fetch("https://api.example.com/data", {
  headers: {
    Authorization: `Payment ${btoa(JSON.stringify(credential))}`,
  },
});

Project Structure

mppx-arc/
├── packages/
│   ├── contracts/          # Solidity (Foundry)
│   │   ├── src/ArcStreamChannel.sol
│   │   ├── test/           # 32 tests (incl. fuzz + ERC-1271)
│   │   └── script/Deploy.s.sol
│   └── mpp/                # TypeScript plugin
│       ├── src/
│       │   ├── client/     # Charge + Session client
│       │   ├── server/     # Charge + Session + SSE + HTML
│       │   ├── methods.ts  # mppx Method.from definitions
│       │   └── ...
│       └── test/           # 78 tests (5 suites)
├── examples/
│   ├── server/             # Hono server with charge + session
│   └── agent/              # Autonomous agent client
├── spec/                   # IETF-style formal specification
├── ARCHITECTURE.md         # Security review guide
└── README.md

Tests

# Solidity (32 tests including fuzz)
cd packages/contracts && forge test -vvv

# TypeScript (78 tests including Arc Testnet integration)
cd packages/mpp && npm test

110 total tests, 0 failures.

Arc Chain Details

PropertyValue
Chain ID5042002
RPChttps://rpc.testnet.arc.network
Explorerhttps://testnet.arcscan.app
USDC0x3600000000000000000000000000000000000000
Gas TokenUSDC (native)
Faucethttps://faucet.circle.com

License

MIT