Development started

Due to the growing need to be able to operate with Bitcoin without giving up personal data, last year I started a project to allows people to buy and sell Bitcoin through Lightning Network without funds custody and of course without KYC, this project is a telegram bot called @lnp2pbot.

@lnp2pBot is growing steadily and organically, it's being use in the whole world but is having a bigger impact in Latin-America, a place where there is no need to explain to people that money is broken, it's being used more and more in dictatorial regimes like Cuba and Venezuela, where people keep resisting tyranny and protesting using less the local currency and more Bitcoin.

Although the bot works excellent, it's running on top of Telegram, a great platform but we do not know if one day it will be reached by the tentacles of a powerful government asking for political dissidents or simply awkward public person.

This is where enter nostr as a platform where the bot can live without the possibility of being censored by a powerful entity, a month ago I started to research about nostr to see if we can create a new bot version, a censorship resistant version that makes it unstoppable, a new Monster version.

Recently I started a first version that runs a nostr bot and only returns a lightning invoice when a user send a event kind 1, this is coded on Rust and will be developed in the next weeks.

If you are a Rust developer and want to participate on this project let me know, we are just starting and you can be since the beginning. happy hacking!

Mostro

_ Updated: 2022-12-14 _

Overview

Due to the growing need to be able to operate with Bitcoin without giving up personal data, in 2021 I started a project to allows people to buy and sell Bitcoin through Lightning Network without funds custody and without KYC, this project is a telegram bot called @lnp2pbot.

@lnp2pBot is growing steadily and organically, it's being use in the whole world and is having a bigger impact in Latin-America, a place where there is no need to explain to people that money is broken, it's being used more and more in dictatorial regimes like Cuba and Venezuela, where people keep resisting tyranny and protesting using less the local currency and more Bitcoin.

Although the bot works excellent, it's running on top of Telegram, a great platform but we do not know if one day it will be reached by the tentacles of a powerful government asking for political dissidents or simply awkward public person.

At this point Nostr appears as a platform where a system like this can live without the possibility of being censored by a powerful entity. This document explains how we can create a censorship-resistant and non custodial lightning network peer-to-peer exchange without a single point of failure like a telegram bot.

How it works?

Mostro works with a p2p communication on top of Nostr, Mostro will be the escrow that will allow buyer and seller operate reducing the risk for both parties.

Mostro will handle Bitcoin using a Lightning Network node, the node will create the hold invoices for sellers and pay the buyers lightning regular invoices.

Mostro will need a private key to be able to create, sign and send events throught Nostr network.

In the next graphic we can see a very summarized version of how Mostro, the seller and the lightning node interact, a more detailed explanation can be found here:

Client-server-ln

Client

Buyers and sellers will need Mostro's clients in order to buy/sell Bitcoin and a Lightning Wallet, for this we need to build at least a web client to start, we plan to build mobile and desktop clients in the future.

Removing the single point of failure

For this idea to work we need to make it as easy as possible for anyone to be a Mostro, we don't need dozens of Mostros but we do need the ones that are running to be reliable, that's why with this implementation we encourage to create your own Mostro and give more options to users.

To handle a Mostro is not going to be that easy, a Mostro admin needs to have a lightning node up and running, it will need to have enough liquidity for users to operate lightning fast, the node MUST have uptime closer to 99.9%, all this requires resources that can be obtained by the fee that sellers pay on each successful order, this is a percentage that can vary between Mostros.

Mostro's reputation

Users will be able to rate Mostros and Mostros will compete to obtain more users in order to survive. Bad Mostros should be rejected by users and will lose incentives to keep existing.

Order flow

_ Updated: 2023-04-07 _

Overview

All mostro messages are Parameterized Replaceable Events and use 30000 as event kind, a list of standard event kinds can be found here

Keys

For this example the participants will use this keys:

  • Mostro's pubkey 7590450f6b4d2c6793cacc8c0894e2c6bd2e8a83894912e79335f8f98436d2d8
  • Seller's pubkey 1f5bb148a25bca31506594722e746b10acf2641a12725b12072dcbc46ade544d
  • Buyer's pubkey f6c63403def1642b0980c42221f1649cdc33d01ce4156c93f6e1607f3e854c92

Communication between users and Mostro

All messages to Mostro should be a Nostr event kind 4, and should have this fields:

  • version
  • action (https://docs.rs/mostro-core/latest/mostro_core/enum.Action.html)
  • content (optional https://docs.rs/mostro-core/latest/mostro_core/enum.Content.html)

Message definition can be found here

Example of a message from a buyer sending a lightning network invoice, the content of this message should be a JSON-serialized string (with no white space or line breaks) of the following structure:

{
  "version": 0,
  "order_id": "6ceda69d-99e4-4263-84cd-157a673aa307",
  "action": "TakeSell",
  "content": {
    "PaymentRequest": [
      null,
      "lnbcrt500u1p3e0xwkpp585pza8m5klgy3zn4dw7ej32jh0hz5mrucc04aezcjx2uulr4tf2sdqqcqzpgxqyz5vqsp52m65dwsqkq5n630pareeswal9e2xxx0ldykuhhcfc0ed2znwzmfq9qyyssqz422f9qtwcleykknzq29yhyytufddhnml4hqdtu3mtpw37kvltqkp7z4y6ntkhy7vpy2eyy53qzjsa0u7mmmx8ee5td64c8x4vm2vcsq786ewz"
    ]
  }
}

Order

To publish an order a user needs to send an encrypted message to Mostro with the order details, then Mostro will create a new Parameterized Replaceable Event that could be taken by another user that wants to trade.

The order wrapped on the encrypted message have this properties:

  • kind (Buy/Sell)
  • status (this will be handle by Mostro, user should send Pending to publish)
  • amount
  • fiat_code
  • fiat_amount
  • payment_method
  • prime
  • buyer_invoice (optional, to be used only on Buy orders)

This format is subject to change!

Example of message from a buyer to create a buy order:

{
  "version": 0,
  "action": "Order",
  "content": {
    "Order": {
      "kind": "Buy",
      "status": "Pending",
      "amount": 6000,
      "fiat_code": "EUR",
      "fiat_amount": 1,
      "payment_method": "bank transfer",
      "prime": 0,
      "buyer_invoice": "lnbcrt500u1p3e0xwkpp585pza8m5klgy3zn4dw7ej32jh0hz5mrucc04aezcjx2uulr4tf2sdqqcqzpgxqyz5vqsp52m65dwsqkq5n630pareeswal9e2xxx0ldykuhhcfc0ed2znwzmfq9qyyssqz422f9qtwcleykknzq29yhyytufddhnml4hqdtu3mtpw37kvltqkp7z4y6ntkhy7vpy2eyy53qzjsa0u7mmmx8ee5td64c8x4vm2vcsq786ewz"
    }
  }
}

Seller creates an order

The seller wants to exchange 100 sats and get 1000 of XXX currency, to publish an offer the seller send an encrypted event to Mostro's pubkey, the content of this event should be a JSON-serialized string (with no white space or line breaks) of the following structure:

{
  "version": 0,
  "action": "Order",
  "content": {
    "Order": {
      "kind": "Sell",
      "status": "Pending",
      "amount": 100,
      "fiat_code": "XXX",
      "fiat_amount": 1000,
      "payment_method": "bank transfer",
      "prime": 0
    }
  }
}

Event example:

{
  "id": "cade205b849a872d74ba4d2a978135dbc05b4e5f483bb4403c42627dfd24f67d",
  "kind": 4,
  "pubkey": "1f5bb148a25bca31506594722e746b10acf2641a12725b12072dcbc46ade544d",
  "content": "base64encoded-encrypted-order",
  "tags": [
    ["p", "7590450f6b4d2c6793cacc8c0894e2c6bd2e8a83894912e79335f8f98436d2d8"]
  ],
  "created_at": 1234567890,
  "sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}

Mostro publishes this order as an event kind 30000 with status Pending:

{
  "id": "74a1ce6e428ba3b4d7c99a5f582b04afdb645aa5f0c661cf83ed3c4e547c04ad",
  "kind": 30000,
  "pubkey": "7590450f6b4d2c6793cacc8c0894e2c6bd2e8a83894912e79335f8f98436d2d8",
  "content": "{\"id\":\"6ceda69d-99e4-4263-84cd-157a673aa307\",\"kind\":\"Sell\",\"status\":\"Pending\",\"amount\":100,\"fiat_code\":\"XXX\",\"fiat_amount\":1000,\"payment_method\":\"bank transfer\",\"prime\":0}",
  "tags": [["d", "6ceda69d-99e4-4263-84cd-157a673aa307"]],
  "created_at": 1234567890,
  "sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}

Buyer takes an order

The buyer wants to buy sats and take the order:

Buyer send a regular invoice

Buyer sends an encrypted message to mostro's pubkey with a lightning invoice, this invoice can have an amount of 100 sats or be amountless, this is linked to :

Unencrypted content:

{
  "version": 0,
  "order_id": "6ceda69d-99e4-4263-84cd-157a673aa307",
  "action": "TakeSell",
  "content": {
    "PaymentRequest": [
      null,
      "lnbcrt1u1p3e0geapp5u3nfpcmc4llggqq6upp85p32kvph6uh8caqkruph5xh0lgl4764qdqqcqzpgxqyz5vqsp59ul6delmlj35rk0k5hcfxz9q0xfcgdsflkzpf673g08dhkm6gtjq9qyyssqe6daccezwpjxxm7n7nqh3zw5ykjl42wmneaukhedaz037t0tarmjnfay3j3xddwz6eg7q98zxct32trfq3h2tr72xyhrkls255q4wfspn84a2e"
    ]
  }
}

Nostr event:

{
  "id": "8af95e0ae6dcf65505474ea8885b3f2eb46c1f094f06339f76c711af43a2242d",
  "kind": 4,
  "pubkey": "f6c63403def1642b0980c42221f1649cdc33d01ce4156c93f6e1607f3e854c92",
  "content": "base64encoded-encrypted-invoice",
  "tags": [
    ["p", "7590450f6b4d2c6793cacc8c0894e2c6bd2e8a83894912e79335f8f98436d2d8"]
  ],
  "created_at": 1234567890,
  "sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}

Mostro put them in touch

Mostro sends an encrypted event to seller with a hold invoice:

Unencrypted message from Mostro to user:

{
  "version": 0,
  "action": "PayInvoice",
  "order_id": "6ceda69d-99e4-4263-84cd-157a673aa307",
  "content": {
    "PaymentRequest": [
      {
        "id": "6ceda69d-99e4-4263-84cd-157a673aa307",
        "kind": "Sell",
        "status": "WaitingPayment",
        "amount": 100,
        "fiat_code": "XXX",
        "fiat_amount": 10000,
        "payment_method": "bank transfer",
        "prime": 0,
        "buyer_invoice": "",
        "created_at": 1680895588
      },
      "lnbcrt1u1p3e0geapp5u3nfpcmc4llggqq6upp85p32kvph6uh8caqkruph5xh0lgl4764qdqqcqzpgxqyz5vqsp59ul6delmlj35rk0k5hcfxz9q0xfcgdsflkzpf673g08dhkm6gtjq9qyyssqe6daccezwpjxxm7n7nqh3zw5ykjl42wmneaukhedaz037t0tarmjnfay3j3xddwz6eg7q98zxct32trfq3h2tr72xyhrkls255q4wfspn84a2e"
    ]
  }
}

After the seller pays the invoice mostro put the parties in touch and update the order sending a replaceable event kind 30000 with the same id, a newer timestamp and status Active:

{
  "id": "74a1ce6e428ba3b4d7c99a5f582b04afdb645aa5f0c661cf83ed3c4e547c04ad",
  "kind": 30000,
  "pubkey": "7590450f6b4d2c6793cacc8c0894e2c6bd2e8a83894912e79335f8f98436d2d8",
  "content": "{\"id\":\"6ceda69d-99e4-4263-84cd-157a673aa307\",\"kind\":\"Sell\",\"status\":\"Active\",\"amount\":100,\"fiat_code\":\"XXX\",\"fiat_amount\":1000,\"payment_method\":\"bank transfer\",\"prime\":0}",
  "tags": [["d", "6ceda69d-99e4-4263-84cd-157a673aa307"]],
  "created_at": 1234567890,
  "sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}

Mostro talks to seller

The buyer sends the seller fiat money, after that, the buyer sends an encrypted message to Mostro indicating that the fiat was sent, example:

Unencrypted fiat sent message:

{
  "version": 0,
  "order_id": "6ceda69d-99e4-4263-84cd-157a673aa307",
  "action": "FiatSent"
}

Encrypted content event example:

{
  "id": "581c0f6f7f8561737506d4484e0e28e18852d8543a9bbcea34ff0dfe68961046",
  "kind": 4,
  "pubkey": "f6c63403def1642b0980c42221f1649cdc33d01ce4156c93f6e1607f3e854c92",
  "content": "base64encoded-encrypted-fiatsent",
  "tags": [
    ["p", "7590450f6b4d2c6793cacc8c0894e2c6bd2e8a83894912e79335f8f98436d2d8"]
  ],
  "created_at": 1234567890,
  "sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}

Now Mostro send a replaceable event kind 30000 with the same id, a newer timestamp and status FiatSent:

{
  "id": "74a1ce6e428ba3b4d7c99a5f582b04afdb645aa5f0c661cf83ed3c4e547c04ad",
  "kind": 30000,
  "pubkey": "7590450f6b4d2c6793cacc8c0894e2c6bd2e8a83894912e79335f8f98436d2d8",
  "content": "{\"id\":\"6ceda69d-99e4-4263-84cd-157a673aa307\",\"kind\":\"Sell\",\"status\":\"FiatSent\",\"amount\":100,\"fiat_code\":\"XXX\",\"fiat_amount\":1000,\"payment_method\":\"bank transfer\",\"prime\":0}",
  "tags": [["d", "6ceda69d-99e4-4263-84cd-157a673aa307"]],
  "created_at": 1234567890,
  "sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}

Mostro request release of funds

Mostro send an encrypted message to seller indicating that buyer confirmed that fiat was sent and request to release funds, if everything went well, seller respond with a new encrypted message to Mostro with this content to release funds:

Unencrypted release message:

{
  "version": 0,
  "order_id": "6ceda69d-99e4-4263-84cd-157a673aa307",
  "action": "Release"
}

Settle seller's invoice

Mostro settle the invoice and send a replaceable event kind 30000 with the same id, a newer timestamp and status SettledHoldInvoice, right after tries to pay the buyer's invoice, after the invoice is paid Mostro send a replaceable event kind 30000 with status Success.