UNPKG

run402-mcp

Version:

MCP server for Run402 — full-stack backend infrastructure for AI agents: Postgres, auth, storage, serverless functions and atomic deploys. Paid with x402/MPP. Includes $0.03 image generation.

108 lines • 4.62 kB
import { sha256 } from "@noble/hashes/sha2.js"; import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js"; import { bindingsEqual } from "../../binding.js"; import { DEFAULT_CLOCK_SKEW_SECONDS, Errors, HTTP_PROFILE, LNBTC_NETWORKS, LnbtcError, SCHEME, } from "../../constants.js"; import { checkExpiry, reject, unixNow, validateInvoice, validateRequirements, validateSkew, } from "../../validation.js"; /** * Client for `exact` on `lnbtc`: validates the request-bound invoice, pays it, * and returns the verified preimage. */ export class ExactLnbtcScheme { scheme = SCHEME; schemeHooks; options; skew; clock; networks; /** * Creates the client scheme. * * @param options - Payer adapter, request binding provider, clock, and skew */ constructor(options) { const skew = options.clockSkewSeconds ?? DEFAULT_CLOCK_SKEW_SECONDS; validateSkew(skew); this.options = options; this.skew = skew; this.clock = options.clock ?? unixNow; this.networks = options.networks ?? LNBTC_NETWORKS; this.schemeHooks = { onBeforePaymentCreation: ctx => this.checkResource(ctx) }; } /** * Validates the challenge against the intended request, pays the invoice, * and verifies the returned preimage. * * @param x402Version - Protocol version * @param requirements - Selected payment requirements * @param context - Spend cap from the client's spend controls, if any * @returns The payload carrying the preimage */ async createPaymentPayload(x402Version, requirements, context) { const advertised = validateRequirements(requirements, this.networks); assertWithinCap(requirements.amount, context?.maxAmountPerPayment); const intended = await this.options.requestBinding(); if (!bindingsEqual(intended, advertised)) reject(Errors.requestMismatch); const invoiceText = requirements.extra.invoice; const options = { now: this.clock(), skew: this.skew }; const invoice = validateInvoice(invoiceText, requirements, intended.requestHash, this.networks, options); checkExpiry(invoice, options, "unexpired"); const payment = await this.options.payer.payInvoice(invoiceText, requirements.network); if (payment.invoice !== invoiceText) reject(Errors.payerInvoiceMismatch); if (payment.paymentHash !== invoice.paymentHash) reject(Errors.payerPaymentHashMismatch); if (payment.amountMsat !== invoice.amountMsat) reject(Errors.payerAmountMismatch); if (payment.status === "in_flight") reject(Errors.paymentInFlight); if (payment.status !== "paid") reject(Errors.paymentNotPaid); const preimage = payment.preimage; if (preimage === undefined || preimage === null) reject(Errors.payerPreimageRequired); if (typeof preimage !== "string" || !/^[0-9a-f]{64}$/.test(preimage)) { reject(Errors.payerPreimageMalformed); } if (bytesToHex(sha256(hexToBytes(preimage))) !== invoice.paymentHash) { reject(Errors.payerPreimageHashMismatch); } return { x402Version, payload: { preimage } }; } /** * For `http:1`, requires `PaymentRequired.resource.url` to equal the * intended request URL before any payment. * * @param ctx - Payment creation context * @returns An abort result on mismatch */ async checkResource(ctx) { try { const intended = await this.options.requestBinding(); if (intended.requestBindingProfile === HTTP_PROFILE && ctx.paymentRequired.resource?.url !== intended.resourceUrl) { return { abort: true, reason: Errors.requestMismatch }; } } catch (error) { if (error instanceof LnbtcError) return { abort: true, reason: error.reason }; throw error; } } } /** * Refuses an amount above the client's atomic spend cap. Core spend controls * already filter requirements; this keeps the scheme safe on its own. * * @param amount - Required millisatoshis (validated positive integer) * @param cap - Atomic cap from spend controls, if any */ function assertWithinCap(amount, cap) { if (cap === undefined) return; if (!/^[0-9]+$/.test(cap) || BigInt(amount) > BigInt(cap)) { throw new Error(`lnbtc amount ${amount} msat exceeds maxAmountPerPayment ${cap}`); } } //# sourceMappingURL=scheme.js.map