@kaspacom/mpp-storage-postgres
v0.1.2
Published
Postgres storage adapter for Kaspa MPP provider channels, receipts, and settlement candidates.
Readme
@kaspacom/mpp-storage-postgres
Postgres storage adapter for provider-side MPP API payments.
This package is the durable storage piece for @kaspacom/mpp-provider.
Providers can use it to persist channels, accepted voucher receipts, payer
close requests, selected route policies, settlement authorizations, and
settlement worker candidates.
Setup
import { createPostgresMppStorage, POSTGRES_MPP_SCHEMA_SQL } from "@kaspacom/mpp-storage-postgres";
import pg from "pg";
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
await pool.query(POSTGRES_MPP_SCHEMA_SQL);
const storage = createPostgresMppStorage({ db: pool });The db object only needs the usual query(sql, values) method and may expose
connect() for transaction clients, matching the shape of pg.Pool.
Channels
Record an opened channel, or renew provider-local state after a same-channel top-up:
await storage.upsertChannel({
channelId,
networkId: "testnet-10",
payerPubkey,
providerPubkey,
maxTotalSpendSompi: 150_000_000,
refundAfterMs: Date.now() + 86_400_000,
currentTxid,
currentVout: 0,
});channelId stays stable across top-ups. The on-chain current outpoint changes,
so payer wallets should refresh currentTxid/currentVout from the indexer or
provider before building settlement, refund, or another top-up. The storage
schema includes idempotent ALTER TABLE ... ADD COLUMN IF NOT EXISTS statements
so existing provider DBs can be upgraded without deleting channel rows.
Provider Guard
const policies = await storage.listActiveRoutePolicies("testnet-10");
const decision = await authorizeProviderRequest(request, {
policy: policies[0],
storage,
});acceptVoucher() runs in a transaction, locks the channel row, re-checks
sequence and spend, writes a receipt, and then updates the channel state.
Route Policies
await storage.upsertRoutePolicy({
policyId: "expensive-report",
enabled: true,
networkId: "testnet-10",
method: "GET",
path: "/api/expensive-report",
pricingId: "api.expensive-report.v1",
amountSompi: 300_000,
providerPubkey,
});
const activePolicies = await storage.listActiveRoutePolicies("testnet-10");The route policy table lets providers turn selected API paths on or off without
monetizing every endpoint. listActiveRoutePolicies() returns
@kaspacom/mpp-provider compatible policies that can be passed directly to the
catalog guard/middleware.
Close / Finalize
await storage.recordCloseRequest(closeRequest);This verifies the payer-signed close request against the channel, stores the
request, and marks the channel close_requested so the settlement worker
prioritizes it.
Settlement Authorization
await storage.recordSettlementAuthorization(authorization, expectation);
await storage.recordSettlementArtifact(artifact, expectation);The current channel covenant needs a payer signature over the actual settlement
transaction/PSKT before the provider can force settlement. This method validates
the authorization shape through @kaspacom/mpp-core, stores the normalized
authorization, and dedupes by channel sequence, metadata digest, and settlement
txid. recordSettlementArtifact() additionally stores the unsigned settlement
template and contract material needed by @kaspacom/mpp-kaspa-redeemer.
Settlement Worker
startSettlementWorker({
candidates: storage,
redeemer,
policy: { minUnsettledSompi: 50_000_000 },
});listSettlementCandidates() only returns channels with a stored available
settlement artifact whose sequence matches the latest accepted voucher, so the
worker does not try to redeem a channel it cannot enforce on-chain.
After a worker attempt, call recordSettlementResult(). Submitted settlements
mark the authorization submitted and the channel settlement_pending;
rejected settlements mark the authorization rejected and the channel
settlement_rejected. This keeps the next interval from retrying the same
artifact.
inspect() is the read-only operator surface for dashboards and support tools.
It returns recent channels, route policies, settlement authorization rows, and
current settlement candidates without exposing raw private keys or payment
credentials.
This package does not submit Kaspa transactions. The provider still supplies a redeemer that owns wallet access and settlement transaction submission.
