Hi magicians,
I’ve opened a new topic for l402 (x402 wrapped BTC) over layer 2.
I am working on it (with LLM yes as i am not a monkey!).
I’d like to share a small project and get feedback from people who know payment channels, EIP-712 and account abstraction much better than I do.
Why
I run LightPhon, an LLM provider aimed at agent orchestrators, with per-use pricing well below the usual subscription/API competitors. On Bitcoin, agents already pay for it machine-to-machine over Lightning, using the L402 pattern: HTTP 402 challenge → pay → retry with a macaroon + proof of payment.
I needed the same thing on Ethereum. Many agent builders live in the EVM world and if somebody don’t want to run a Lightning node it has got another option.
The constraint is the same as on Lightning, though. An agent that calls a tool thousands of times a day can’t send a transaction per call: gas would cost more than the service, and it would add ~1–2 s of latency to every request.
How
L402-EL2 keeps the L402 wire format (so existing parsers still work) but replaces the Lightning invoice/preimage with a unidirectional payment channel on an L2:
- Escrow contract (
L402Escrow.sol): the agent opens a prefunded channel toward a provider (1 L2 tx).channelId = keccak256(abi.encode(payer, provider, token)), so it can be computed offline. - Cumulative EIP-712 vouchers as the proof of payment:
Voucher(channelId, cumulativeAmount, nonce, validUntil). Each call signs a new total, so there’s no replay, the server keeps one row per channel, and verification is an in-memory signature check (~ms, no RPC). - Macaroons for the HTTP credential: caveats (
tool,max_cumulative,expires_at, …), fail-closed evaluation, and attenuation, so an agent can hand a narrower token to a sub-agent. - On-chain session keys:
authorizeSigner(key, maxCumulative, validUntil)puts the spending cap in the contract, not in the client. Revocations/tightening respect the same 24h challenge period as channel closes, so they can’t be used to void vouchers already served. - Batch settlement: a settler collects the latest voucher of many channels in one
settleBatch(). - Works with EOAs and ERC-4337 accounts (ERC-1271 verification), plus ERC-2612/ERC-3009 single-signature deposits.
- MCP integration:
initialize/tools/liststay free for discovery; onlytools/call,resources/readandprompts/getare billed.
Net effect: 2 on-chain transactions per channel lifecycle (open + settle) instead of one per call, and < 10 ms of payment overhead per request. The token is any ERC-20; I’m using wrapped BTC (cbBTC/WBTC/tBTC) to stay denominated like the Lightning side.
The repo includes the contract (node + Foundry tests, including fuzzing), TypeScript server/client/settler packages, a protocol spec, and an end-to-end example that runs on an in-process EVM with no configuration.
Not audited — please don’t use it with real funds yet.
Feedback are welcome. More trouble you found more i learn…
Thanks for reading. Happy to answer questions.
Disclosure: I’m the founder of LightPhon, which is the reason I built this and i will use it future.
PS i am a newbie here the site: https://www.l402-over-eth-l2.com/