Introducing Pontmore: a Nostr-native protocol for agent discovery, escrow, and swaps

Hi Open Bitcoin Africa community,

I would like to introduce Pontmore, a Nostr-native protocol family for agent identity, capability discovery, escrow declaration, and swap lifecycle coordination.

Pontmore is designed for a world where services, market makers, operators, and automated participants can publish what they do publicly, discover each other through Nostr, and coordinate swaps without making a single application account the root of identity.

The core idea is simple:

An Agent is a protocol participant that publishes capabilities and can conduct swaps. A Swap is the exchange from fiat to Bitcoin, or Bitcoin to fiat. A Nostr pubkey is the root agent identity, allowing for portability of agents in an open network.

Pontmore does not require the Agent to be a human

It’s easiest to think of an Agent here as the very familiar “Mobile Money Agents”. Such human agents are key participants how money move in the global south through networks like M-Pesa, MTN MoMo, Airtel Money, bKash and GCash.

Applications, dashboards, indexes, compliance tools, and operator systems can wrap that identity, but the public protocol surface remains portable and verifiable.

Protocol Definitions

Pontmore currently defines four required protocol documents:

Defines how an Agent publishes its public profile, supported capabilities, payment channels, regions, limits, pricing policy references, and default escrow descriptor.

Defines how escrow mechanisms are declared publicly, including supported networks such as Bitcoin or Lightning, funding rules, release rules, refund rules, and dispute assumptions.

Defines the event lifecycle for swaps: request, transitions, evidence, disputes, notes, and snapshots. The swap history is append-only, while private data can move through encrypted Nostr messages.

Defines dispute classes, timeout classes, evidence boundaries, and resolution modes. The swap state machine is public, but sensitive evidence stays private by default.

## Why this matters

Many Bitcoin services today depend on platform-specific accounts, internal databases, and private trust assumptions. That can work inside one app, but it makes interoperability difficult.

Pontmore tries to separate public protocol facts from private operator systems.

Public protocol facts include:

  • who an Agent is

  • what capabilities they publish

  • which escrow model they reference

  • what swap was requested

  • how the public lifecycle advanced

  • whether a dispute was opened or resolved

Private operator data can still exist, but it does not become the canonical protocol state.

That means different clients, indexes, operators, and automation systems can coordinate around the same public event model while keeping sensitive details out of the public feed.

Possible Use Cases

Pontmore can support:

  • peer-to-peer Bitcoin and fiat swaps

  • Lightning-based escrow flows

  • agent discovery for local liquidity providers

  • public capability directories

  • interoperable swap clients

  • escrow operators that publish their rules clearly

  • dispute-aware swap coordination

  • regional Bitcoin markets where multiple frontends can discover the same agents

  • automation that helps coordinate swaps without owning user identity

For example, an Agent could publish that it supports Kenyan shilling swaps, Lightning settlement, specific payment channels, certain limits, and a particular escrow descriptor. A client can discover that Agent over Nostr, start a swap, track public state transitions, and keep sensitive payment details in encrypted messages.

Privacy Model

Pontmore does not assume that everything belongs on the public timeline.

The public state machine records the minimum shared facts needed for coordination and auditability. Sensitive payloads such as invoices, bank details, payout instructions, screenshots, internal notes, and private documents should stay in encrypted/private channels unless a dispute policy requires limited disclosure.

The goal is interoperability without unnecessary exposure.

Current Status

Pontmore is still in draft form.

The current repository contains only the minimum interoperable core PIPs, so the protocol remains small and reviewable.

The core repository is open source:

With a proof of concept hosted at:

This draft has been adopted by Minmo - the proposer[1][2].

How to Contribute

The most useful contributions right now are:

  • protocol-focused review

  • proof of concept implementations

  • general protocol discussion

  • feedback on whether the event model is clear enough for independent implementations

  • challenges to unclear terminology or missing protocol rules

  • suggestions for better boundaries between public protocol state and private operator data

  • concrete improvements as issues or pull requests

The repository is intentionally focused on protocol text.

Application UX, database schemas, deployment details, and SDK plans should live elsewhere unless they are needed to clarify the protocol itself. You can [read the source code]( GitHub - pontmore/nextjs-poc · GitHub ) for the publicly hosted proof of concept app.

Feedback from builders working on Bitcoin, Lightning, Nostr, escrow, and local liquidity markets would be especially valuable.


  1. Minmo implements the Pontmore Protocol, and is one of many possible operator in the resulting network of Pontmore Agents. As an operator, Minmo provides tools which help in operating a subset of the emergent Open network of Agents compatible with the specifications defined in this protocol. It does not and will not have unilateral ownership of Agents in the network. Generally, no single operator should be able to delete, censor, or prevent Agents from participating in the network proposed. ↩︎

  2. Minmo proposes the original shape of Pontmore Protocol, and commits to working collaboratively in the open with other individual or organizational contributors who want to further the ideas proposed. ↩︎

1 Like

Hi everyone,

I’ve been working on a way for Pontmore escrows to advertise their full service capabilities directly on Nostr. The goal here is simple: anyone building an app should be able to just discover, parse, and invoke a published escrow service without needing out-of-band coordination.

Right now, PIP-01 is great for discovery and matching within standard swap flows. But if you want to build a standalone, non-swap application (like a two-party dice game) using a Pontmore escrow, the current descriptor doesn’t tell your app how to actually talk to the service. It’s missing the API endpoints, the auth model, and the expected payload formats.
To fix this Issue #11, I’ve opened PR #12

The PR extends PIP-01 with an optional service block. This allows an escrow to publicly advertise its HTTPS endpoints, require Nostr-native NIP-98 authentication, and specify exactly which operations and release-decision formats it supports—all without leaking the operator’s private custody or routing details.

1 Like

To prove this actually works in practice, I’ve built out two working repositories:

1. The Escrow Backend: pontmore-lightning-escrow

A standalone, PIP-01 conformant custodial escrow service over HTTPS.

  • Uses Blink for Lightning custody and Supabase (Postgres RPCs) for atomic state transitions.
  • Implements the six canonical operations proposed in the PR (create, funding_instructions, fund_status, release, refund, cancel).
  • Fully relies on NIP-98 HTTP Auth—every mutating request requires a signed kind 27235 event, meaning the Nostr pubkey is the participant identity.

2. The Validation Toolkit: descriptor-POC

A Rust workspace to parse, validate, and test these new standalone descriptors.

  • Core Library: Parses the JSON against PIP-01 rules, classifies if it is DiscoveryOnly or StandaloneSufficient, and verifies the wrapping Nostr event signatures.
  • Tooling: Includes a CLI to quickly validate local descriptor files, and a lightweight axum mock web server to simulate the escrow service for frontend testing.

I’d love for builders here to tear into the PR and the code and share there findings/feedback.

1 Like

This is really cool. I listed the proof of concepts under pontmore.xyz projects

I am working on an a simple dice-roller app which can just connect to advertised pontmore escrows and carry out it’s functions. The idea is to test the escrow invocation spec proposed by Define escrow service invocation by mk-Denver · Pull Request #12 · pontmore/protocol · GitHub

I appriciate the idea of building a a simple dice-roller client to test the proposed idea ,feedback on your findings will be highly appriciated

Quick update:
I’ve Just pushed some additional implementations to PR(#12). This update patches several structural loopholes and standalone limitations identified in PIP-01, with a minor alignment in PIP-03.

Key Updates (PIP-01):

  • Security Fixes: Patched the Sybil-join loophole (enrollment tokens are now strictly bound to the joining participant’s pubkey) and cross-instance replay attacks (oracle/threshold signatures MUST now commit to the stable escrow ID).
  • State Machine & Lifecycle: Added strict state transition rules (created through to terminal states) to fix ambiguous states. Resolved the “funding limbo” by adding a funding_timeout that mandates full refunds for partially funded sides.
  • Disputes & Deadlocks: Introduced the split operation and split_decision format for proportional payouts. Fixed the mutual-consent deadlock by requiring a non-consent refund_trigger fallback (this is also minimally mirrored in PIP-03 to ensure operators resolve timeouts).
  • Risk Documentation: Added a new section detailing standalone implementation risks, specifically addressing Lightning routing-node penalties, custodial counterparty risks, and Cashu mint liveness.
1 Like

I was wondering if we need state machine declarations for the escrows. A strict state machine declaration would mean the protocol has an opinion on the internal implementation of the escrow.

Question: Is escrow variant and public interface definition declared via descriptor mechanism sufficient for interoperable pontmore escrows, or does the protocol also need to define the escrow implementation details to a degree ?

The public interface definition declared via descriptor mechanism is only sufficient for an escrow to be standalone, but for it to be an interoperable pontmore escrows, the the protocol will need to define the implementation details to a degree ,example; the escrow instance state machine,of which in this case are public states

I am designing a Pontmore-compatible Lightning escrow using:

  • PIP-01 for escrow discovery and service-schema declaration
  • PIP-02 for the Nostr-native swap lifecycle
  • PIP-03 for disputes and timeout policy
  • A Lightning hold invoice as the funding lock

The main question is: who should create and control the hold invoice; the trading agent or the escrow node?

Option A: Agent-controlled hold invoice

The agent creates the hold invoice, generates the preimage, and gives the invoice to the customer.

Customer ── pays ──> Agent's hold invoice
                           |
                    Agent knows preimage
                           |
                    settle or cancel

This has a simple, direct Lightning payment path and keeps the escrow operator out of custody. However, the agent has unilateral settlement ability.

If a dispute is opened, the escrow operator can publish a signed RELEASE or REFUND decision, but it cannot enforce that decision through Lightning. A dishonest agent could settle during the dispute, ignore a refund decision, or wait for HTLC expiry.

This therefore appears to provide cooperative or reputational arbitration, rather than enforceable escrow.

Option B: Escrow-node-controlled hold invoice

The escrow node creates the hold invoice, retains the preimage, and receives the customer’s pending HTLC. The agent provides a separate payout invoice.

Customer ── pays ──> Escrow node's hold invoice
                              |
                       Escrow owns preimage
                              |
                   +----------+----------+
                   |                     |
                RELEASE                REFUND
                   |                     |
          settle incoming HTLC     cancel hold invoice
          and pay agent invoice    customer gets refund

During a dispute, an authorized solver signs a release or refund directive. The escrow node validates the directive and executes the corresponding Lightning operation. Neither the customer nor the agent can override the outcome because neither has the preimage or the node’s Lightning credentials.

This makes dispute decisions enforceable against the trading parties, but introduces important trade-offs:

  1. The escrow operator becomes a trusted settlement authority.
  2. Settling the incoming HTLC and paying the agent’s invoice are two separate Lightning operations.
  3. These operations are not atomic.
  4. If the incoming HTLC settles but the outgoing payment fails, the swap enters a PAYOUT_PENDING state.
  5. The escrow node must handle durable execution records, payout retries, replacement invoices, idempotency, and restart reconciliation.
  6. A compromised operator could settle early, refund incorrectly, withhold payout, or become unavailable.

Under PIP-01, this seems more accurately described as custodial_escrow with a Lightning backend, rather than participant-controlled lightning_hold_invoice.

Proposed state flow

REQUESTED
    |
    v
ACCEPTED
    |
    v
INVOICED
    |
    v
FUNDED
    |
    +-------------------------+
    |                         |
    v                         v
RELEASE_AUTHORIZED      REFUND_AUTHORIZED
    |                         |
    v                         v
PAYOUT_PENDING             REFUNDED
    |
    v
SETTLED

A dispute would add:

FUNDED
   |
   v
DISPUTED
   |
   +── solver authorizes release ──> PAYOUT_PENDING ──> SETTLED
   |
   └── solver authorizes refund ───> REFUNDED

PIP-02 Nostr events would coordinate and audit the lifecycle, while the escrow node’s Lightning observations would determine the actual financial state.

Architectural Question

For a practical Pontmore Lightning HTLC escrow, which trust and settlement model is preferable?

  1. Agent-controlled hold invoice, accepting that dispute decisions are cooperative and reputational;
  2. Escrow-node-controlled hold invoice, accepting operator trust and a non-atomic outgoing payout;

For the node-controlled model specifically:

  • Should the incoming HTLC be settled before attempting the agent payout, or is there a safer ordering?
  • How should PAYOUT_PENDING and failed outgoing payments be handled?
  • What evidence should be sufficient to mark SETTLED?
  • Should solver authorization and Lightning execution use separate keys and services?
  • Is custodial_escrow the correct PIP-01 classification even though funds remain in a pending Lightning HTLC until resolution?
  • Is there a deployable way to reduce operator trust using currently available Lightning primitives?

I am particularly interested in feedback on the custody classification, dispute enforceability, failure recovery, and the non-atomic boundary between settling the incoming hold invoice and paying the winning party.

Hi everyone, I just joined to follow the discussions here. Looking forward to learning from this community.

1 Like

Welcome! , looking forward for your contribution in our discussion