MegaETH Charge
March 28, 2026 ยท View on GitHub
Use charge when each protected request should settle independently.
This is the best fit when you want:
- one Permit2-backed payment per request
- a simple server-broadcast flow with fee sponsorship
- a client-broadcast fallback that returns a transaction hash instead of a server-submitted settlement
For the end-to-end walkthrough, start with ../getting-started.md.
Explicit Server Shape
Keep chainId and recipient explicit in server configuration. When the
settlement wallet is also the payee, opt in visibly with
recipient: settlementAccount.address.
import { Mppx, megaeth } from "@moldy/mega-mpp-sdk/server";
import { megaethMainnet } from "@moldy/mega-mpp-sdk/chains";
import { privateKeyToAccount } from "viem/accounts";
const settlementAccount = privateKeyToAccount(
process.env.MEGAETH_SETTLEMENT_PRIVATE_KEY!,
);
const recipient = settlementAccount.address;
const mppx = Mppx.create({
account: settlementAccount,
chainId: megaethMainnet.id,
methods: [megaeth.charge()],
recipient,
secretKey: process.env.MPP_SECRET_KEY!,
});
Then issue a charge from the route handler with only the price:
const result = await mppx.megaeth.charge({
amount: "100000",
description: "Premium API response",
})(request);
Once chainId and recipient are explicit, the charge server still defaults:
currency: mainnet USDmpermit2Address: the canonical Permit2 contract
Use explicit overrides when you are:
- running on testnet
- charging a token other than mainnet USDm
- using a non-default recipient
- forcing a specific submission mode
Modes
Permit2 Credential (Server Broadcast)
- Client signs Permit2 typed data.
- Server verifies the challenge, signature, token, amount, splits, and source DID.
- Server broadcasts the Permit2 transaction from the settlement wallet.
- This is the fee-sponsored path.
Transaction Hash Credential (Client Broadcast)
- Client signs Permit2 typed data.
- Client broadcasts the Permit2 transaction directly.
- Client returns the transaction hash as the credential payload.
- Server verifies the on-chain transaction against the challenge and rejects replays.
Request Shape
type ChargeRequest = {
amount: string
currency: `0x${string}`
recipient: `0x${string}`
description?: string
externalId?: string
methodDetails: {
chainId?: number
feePayer?: boolean
permit2Address?: `0x${string}`
splits?: Array<{
recipient: `0x${string}`
amount: string
memo?: string
}>
}
}
methodDetails.chainId is the only public network selector. The old testnet
flag is gone. Provide chainId either through explicit create-level defaults
or on each request.
Client Credential Mode
The client charge factory accepts an optional credentialMode parameter:
permit2: return a signed Permit2 credential for server-side verification and broadcasthash: broadcast the Permit2 transaction from the payer wallet and return a transaction-hash credential
Submission Mode
Client and server charge factories both accept an optional submissionMode parameter:
sync: requireeth_sendRawTransactionSyncrealtime: requirerealtime_sendRawTransactionsendAndWait: send the raw transaction through the standard path and wait for the receipt by hash
When the flow needs to broadcast a transaction, omitting submissionMode
defaults to realtime. Set it explicitly when you need sync or
sendAndWait. The SDK does not probe submission capabilities automatically.
Receipt Behavior
mppx currently serializes a generic payment receipt header. The SDK keeps the MegaETH request and credential wire format aligned to the draft spec, while the receipt remains compatible with the shared mppx receipt serializer.
type ChargeReceipt = {
method: "megaeth"
reference: string
status: "success"
timestamp: string
externalId?: string
}
challengeId remains available in server verification context and problem details, but it is not part of the serialized Payment-Receipt header.
Client Progress Lifecycle
Both credentialMode: "permit2" and credentialMode: "hash" emit the same user-facing lifecycle stages:
challengesigningsignedpayingconfirmingpaid
Error Style
All server failures are intentionally instructive. The caller should learn what to do next, for example:
- approve Permit2 before retrying
- request a fresh challenge before retrying
- use the configured chain ID and recipient before retrying
- switch back to
credentialMode: "permit2"when the server sponsors gas
The verification layer maps those failures onto mppx.Errors.* problem-details classes so callers can inspect both the human-readable detail and the RFC 9457 type URI.