Payment on Lightning, dispute on Bitcoin. A server-side adapter that lets any Rootstock-hosted API accept HTTP L402 payments (Lightning Network sats) and records each payment on Rootstock via Predge's ERC-8004 validator — so the same slashable-bond machinery Predge already ships can adjudicate a "you didn't deliver what I paid for" dispute against it, even though the payment itself lived on Lightning.
RDMoutlaw/pay402is a great client-side SDK for the L402 ↔ x402 world — but no server-side glue for Rootstock exists.- L402 (Lightning Labs) gives you cheap, private, native-Bitcoin agent payments.
- ERC-8004 + a slashable rBTC bond on Rootstock gives you on-chain dispute resolution.
- Bridging them means an agent can pay in sats and still have a Bitcoin-collateralized way to slash a dishonest seller. Nothing else in the x402 / L402 ecosystem does this today.
npm install @predgeai/rsk-l402-adapterimport express from "express";
import { l402Rootstock, connect } from "@predgeai/rsk-l402-adapter";
const { wallet } = await connect({ privateKey: process.env.PRIVATE_KEY });
const app = express();
app.get("/whales/latest",
l402Rootstock({
priceSats: 500,
expectedSha256Of: (req) => precomputeShaFor(req), // your deterministic acceptance test
issueChallenge: () => lnd.issueL402(500), // your LND / LNbits issuer
validatorAddress: process.env.PREDGE_VALIDATOR_ADDRESS,
rskWallet: wallet,
}),
(req, res) => res.json({ /* your data */ })
);The middleware:
- Returns
402 Payment Requiredwith a realWWW-Authenticate: L402 …on first hit. - On retry, verifies
sha256(preimage) == committed_hash_in_macaroonoffline (no LND round-trip). - Calls
PredgeAgentValidator.validationRequeston Rootstock and attaches the tx hash toreq.l402.rsk.txHashso your handler can return it as a header. That on-chain record is what makes the payment disputable later.
# Deployer key funded with a bit of tRBTC (faucet.rootstock.io)
export PRIVATE_KEY=0x...
export PREDGE_VALIDATOR_ADDRESS=0x7041Ed7B6D33F6A8D2605b120194645765d67a85
# Terminal A — the paid API
npm run example:server
# Terminal B — a paying client that walks the full L402 flow
npm run example:clientSample run (14 Aug 2026):
[1] GET http://localhost:8080/whales/latest → 402
challenge · macaroon bW9jay1sNDAyLWxvYzoAAIwc… · invoice lnbc500n1MOCK_8c1c8fd0…
[2] "paid" invoice → preimage 2121c05a8e630e48…
[3] retry with credential → 200
[4] delivered bytes mock-whale-response for /whales/latest
sha256(bytes) 0x502cec4d69f9985fef6cfd3be0b9e13153331fa0b2849600e442b3e583a628b3
on-chain requestHash 0x04367a07e543af0dcebeb3a5aec6a13216d1a74a7d39a4905545c01f33d5d7ca
on-chain tx https://explorer.testnet.rootstock.io/tx/0x0f8906eb846e9e04f9de221653df666a7e2ff11a65af1fa82821915f78fabb56
The demo uses a mock LN issuer so you don't need to run LND to see the end-to-end work. The Rootstock leg is real — that transaction above is on the testnet explorer.
src/
l402.mjs header parsing, macaroon → payment_hash, preimage verification (dep-free)
on-chain.mjs Rootstock signer (legacy type:0, EIP-1559-off) + PredgeAgentValidator calls
express.mjs l402Rootstock() middleware — the three-liner
index.mjs public surface
test/
l402.test.mjs 10 tests, no keys, no network
example/
server.mjs the demo API
client.mjs the demo client
RSK does not support EIP-1559 — every tx is sent as legacy type: 0 with an explicit
gasPrice (wrapped once in on-chain.mjs). Cancun opcodes (PUSH0, MCOPY, TLOAD/TSTORE,
BASEFEE) and the sha256 precompile 0x02 are bit-identical to Ethereum, so nothing else
changes. See the tutorial: "Portable EVM: Deploying an ERC-8004 Validator from Ethereum L2 to
Rootstock" (companion Hacktivator submission).
Server-side only. No macaroon signatures ever leave the LN issuer; no wallet keys ever leave the server. The Rootstock write costs a few hundred sats of tRBTC per payment — negligible on testnet, worth budgeting on mainnet for high-QPS APIs.
MIT. Predge · hello@predge.io · @predgeAI · https://predge.io.
Companion repos:
- predgeAI/predge-rootstock — the ERC-8004 validator + slashable rBTC bond
- predgeAI/predge-arc — the same primitive on Circle Arc