Mostro specification for clients

Overview

In order to have a shared order's book, Mostro daemon send Parameterized Replaceable Events with 38383 as event kind, you can find more details about that specific event here

Communication between users and Mostro

All messages from/to Mostro should be Gift wrap Nostr events, the content of the rumor event should be a nip44 encrypted JSON-serialized string (with no white space or line breaks) of the following structure:

  • version: Version of the protocol, currently 1
  • action: Action to be performed by Mostro daemon
  • content (optional): Content of the message, this field is optional and depends on the action

These fields are relative to the wrapper, here an example of a fiat-sent Order message, in this case id is the Order Id:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "fiat-sent",
    "content": null
  }
}

Keys

For all examples the participants will use this keys:

  • Mostro's pubkey dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a
  • Seller's ephemeral pubkey 00000ba40c5795451705bb9c165b3af93c846894d3062a9cd7fcba090eb3bf78
  • Buyer's ephemeral pubkey 0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427

Ephemeral keys

Mostro clients should implement nip59 which creates newly fresh keys on each message to Mostro, the client will also creates newly keys for each order and is used to sign the seal, this pubkey will be linked to the order and discarded after the trade is done, this pubkey also will be used in case of a dispute.

Creating a new sell order

To create a new sell order the user should send a Gift wrap Nostr event to Mostro, the rumor event should have the following rumor's content:

{
  "order": {
    "version": 1,
    "action": "new-order",
    "content": {
      "order": {
        "kind": "sell",
        "status": "pending",
        "amount": 0,
        "fiat_code": "VES",
        "min_amount": null,
        "max_amount": null,
        "fiat_amount": 100,
        "payment_method": "face to face",
        "premium": 1,
        "created_at": 0
      }
    }
  }
}

Let's explain some of the fields:

  • kind: sell or buy
  • status: Is always pending when creating a new order
  • amount: 0 for when we want to sell with at market price, otherwise the amount in satoshis
  • created_at: No need to send the correct unix timestamp, Mostro will replace it with the current time

The event to send to Mostro would look like this:

{
  "id": "cade205b849a872d74ba4d2a978135dbc05b4e5f483bb4403c42627dfd24f67d",
  "kind": 1059,
  "pubkey": "1f5bb148a25bca31506594722e746b10acf2641a12725b12072dcbc46ade544d", // Seller's ephemeral pubkey
  "content": "sealed-rumor-content",
  "tags": [
    ["p", "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a"] // Mostro's pubkey
  ],
  "created_at": 1234567890,
  "sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}

Confirmation message

Mostro will send back a nip59 event as a confirmation message to the user like the following (unencrypted rumor's content example):

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "new-order",
    "content": {
      "order": {
        "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
        "kind": "sell",
        "status": "pending",
        "amount": 0,
        "fiat_code": "VES",
        "fiat_amount": 100,
        "payment_method": "face to face",
        "premium": 1,
        "created_at": 1698870173
      }
    }
  }
}

Mostro publishes this order as an event kind 38383 with status pending:

[
  "EVENT",
  "RAND",
  {
    "id": "84fad0d29cb3529d789faeff2033e88fe157a48e071c6a5d1619928289420e31",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702548701,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "pending"],
      ["amt", "0"],
      ["fa", "100"],
      ["pm", "face to face", "bank transfer"],
      ["premium", "1"],
      ["network", "mainnet"],
      ["layer", "lightning"],
      ["expiration", "1719391096"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "7e8fe1eb644f33ff51d8805c02a0e1a6d034e6234eac50ef7a7e0dac68a0414f7910366204fa8217086f90eddaa37ded71e61f736d1838e37c0b73f6a16c4af2"
  }
]

Creating a new sell range order

To create a new range order the user should send a Gift wrap Nostr event to Mostro with the following rumor's content:

{
  "order": {
    "version": 1,
    "action": "new-order",
    "content": {
      "order": {
        "kind": "sell",
        "status": "pending",
        "amount": 0,
        "fiat_code": "VES",
        "min_amount": 10,
        "max_amount": 20,
        "fiat_amount": 0,
        "payment_method": "face to face",
        "premium": 1,
        "created_at": 0
      }
    }
  }
}

Here we have two new fields, min_amount and max_amount, to define the range of the order. The fiat_amount field is set to 0 to indicate that the order is for a range of amounts.

When a taker takes the order, the amount will be set on the message.

Confirmation message

Mostro will send back a nip59 event as a confirmation message to the user like the following:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "new-order",
    "content": {
      "order": {
        "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
        "kind": "sell",
        "status": "pending",
        "amount": 0,
        "fiat_code": "VES",
        "min_amount": 10,
        "max_amount": 20,
        "fiat_amount": 0,
        "payment_method": "face to face",
        "premium": 1,
        "created_at": 1698870173
      }
    }
  }
}

Mostro publishes this order as an event kind 38383 with status pending:

[
  "EVENT",
  "RAND",
  {
    "id": "84fad0d29cb3529d789faeff2033e88fe157a48e071c6a5d1619928289420e31",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702548701,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "pending"],
      ["amt", "0"],
      ["fa", "10", "20"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["network", "mainnet"],
      ["layer", "lightning"],
      ["expiration", "1719391096"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "7e8fe1eb644f33ff51d8805c02a0e1a6d034e6234eac50ef7a7e0dac68a0414f7910366204fa8217086f90eddaa37ded71e61f736d1838e37c0b73f6a16c4af2"
  }
]

Creating a new buy order

To create a new buy order the user should send a Gift wrap Nostr event to Mostro with the following rumor's content:

{
  "order": {
    "version": 1,
    "action": "new-order",
    "content": {
      "order": {
        "kind": "buy",
        "status": "pending",
        "amount": 0,
        "fiat_code": "VES",
        "fiat_amount": 100,
        "payment_method": "face to face",
        "premium": 1,
        "created_at": 0
      }
    }
  }
}

The nostr event will look like this:

{
  "id": "cade205b849a872d74ba4d2a978135dbc05b4e5f483bb4403c42627dfd24f67d",
  "kind": 1059,
  "pubkey": "9a42ac72d6466a6dbe5b4b07a8717ee13e55abb6bdd810ea9c321c9a32ee837b", // Buyer's ephemeral pubkey
  "content": "sealed-rumor-content",
  "tags": [
    ["p", "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a"] // Mostro's pubkey
  ],
  "created_at": 1234567890,
  "sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}

Confirmation message

Mostro will send back a nip59 event as a confirmation message to the user like the following:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "new-order",
    "content": {
      "order": {
        "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
        "kind": "buy",
        "status": "pending",
        "amount": 0,
        "fiat_code": "VES",
        "fiat_amount": 100,
        "payment_method": "face to face",
        "premium": 1,
        "master_buyer_pubkey": null,
        "master_seller_pubkey": null,
        "buyer_invoice": null,
        "created_at": 1698870173
      }
    }
  }
}

Mostro publishes this order as an event kind 38383 with status pending:

[
  "EVENT",
  "RAND",
  {
    "id": "84fad0d29cb3529d789faeff2033e88fe157a48e071c6a5d1619928289420e31",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702548701,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "buy"],
      ["f", "VES"],
      ["s", "pending"],
      ["amt", "0"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["network", "mainnet"],
      ["layer", "lightning"],
      ["expiration", "1719391096"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "7e8fe1eb644f33ff51d8805c02a0e1a6d034e6234eac50ef7a7e0dac68a0414f7910366204fa8217086f90eddaa37ded71e61f736d1838e37c0b73f6a16c4af2"
  }
]

After a seller takes this order Mostro will request an invoice from the buyer, Mostro will pay the buyer's invoice when the seller releases the funds.

Creating the order with a lightning invoice

There are two ways where the buyer can create the order adding the invoice:

  1. If the buyer already knows the amount, e.g. buyer wants to buy 15000 sats with 10 euros, in this case the buyer knows from the beginning that the invoice should have amount 15000 - Mostro's fee, instead of the user doing the calculation, the client must do it and in some cases create the invoice with the right amount.

  2. If the buyer don't know the amount, e.g. buyer wants to buy sats with 10 euros, in this case the buyer can add an amountless invoice and Mostro will pay it with the market price amount - Mostro's fee automatically.

Creating a new order

Creating buy order with a lightning address would make the process way faster and easy going, to acomplish the buyer should send a Gift wrap Nostr event to Mostro with the following rumor's content:

{
  "order": {
    "version": 1,
    "action": "new-order",
    "content": {
      "order": {
        "kind": "buy",
        "status": "pending",
        "amount": 0,
        "fiat_code": "VES",
        "fiat_amount": 100,
        "payment_method": "face to face",
        "premium": 1,
        "buyer_invoice": "mostro_p2p@ln.tips",
        "created_at": 0
      }
    }
  }
}

The nostr event will look like this:

{
  "id": "cade205b849a872d74ba4d2a978135dbc05b4e5f483bb4403c42627dfd24f67d",
  "kind": 1059,
  "pubkey": "9a42ac72d6466a6dbe5b4b07a8717ee13e55abb6bdd810ea9c321c9a32ee837b", // Buyer's ephemeral pubkey
  "content": "sealed-rumor-content",
  "tags": [
    ["p", "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a"] // Mostro's pubkey
  ],
  "created_at": 1234567890,
  "sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}

Confirmation message

Mostro will send back a nip59 event as a confirmation message to the user like the following:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "new-order",
    "content": {
      "order": {
        "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
        "kind": "buy",
        "status": "pending",
        "amount": 0,
        "fiat_code": "VES",
        "fiat_amount": 100,
        "payment_method": "face to face",
        "premium": 1,
        "master_buyer_pubkey": null,
        "master_seller_pubkey": null,
        "buyer_invoice": "mostro_p2p@ln.tips",
        "created_at": 1698870173
      }
    }
  }
}

Mostro publishes this order as an event kind 38383 with status pending:

[
  "EVENT",
  "RAND",
  {
    "id": "84fad0d29cb3529d789faeff2033e88fe157a48e071c6a5d1619928289420e31",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702548701,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "buy"],
      ["f", "VES"],
      ["s", "pending"],
      ["amt", "0"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["network", "mainnet"],
      ["layer", "lightning"],
      ["expiration", "1719391096"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "7e8fe1eb644f33ff51d8805c02a0e1a6d034e6234eac50ef7a7e0dac68a0414f7910366204fa8217086f90eddaa37ded71e61f736d1838e37c0b73f6a16c4af2"
  }
]

After a seller takes this order Mostro will not ask for an invoice to the buyer, Mostro will get the buyer's invoice and paid it when the seller releases the funds.

Listing Orders

Mostro publishes new orders with event kind 38383 and status pending:

[
  "EVENT",
  "RAND",
  {
    "id": "84fad0d29cb3529d789faeff2033e88fe157a48e071c6a5d1619928289420e31",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702548701,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "pending"],
      ["amt", "0"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["network", "mainnet"],
      ["layer", "lightning"],
      ["expiration", "1719391096"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "7e8fe1eb644f33ff51d8805c02a0e1a6d034e6234eac50ef7a7e0dac68a0414f7910366204fa8217086f90eddaa37ded71e61f736d1838e37c0b73f6a16c4af2"
  }
]

Clients can query this events by nostr event kind 38383, nostr event author, order status (s), order kind (k), order currency (f), type (z)

Taking a sell order

If the order amount is 0 the buyer don't know the exact amount to create the invoice, buyer will send a message in a Gift wrap Nostr event to Mostro with the following rumor's content:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "take-sell",
    "content": null
  }
}

The event to send to Mostro would look like this:

{
  "id": "cade205b849a872d74ba4d2a978135dbc05b4e5f483bb4403c42627dfd24f67d",
  "kind": 1059,
  "pubkey": "9a42ac72d6466a6dbe5b4b07a8717ee13e55abb6bdd810ea9c321c9a32ee837b",
  "content": "sealed-rumor-content",
  "tags": [
    ["p", "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a"]
  ],
  "created_at": 1234567890,
  "sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}

Mostro response

In order to continue the buyer needs to send a lightning network invoice to Mostro, in this case the amount of the order is 0, so Mostro will need to calculate the amount of sats for this order, then Mostro will send back a message asking for a LN invoice indicating the correct amount of sats that the invoice should have, here the rumor's content of the message:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "add-invoice",
    "content": {
      "order": {
        "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
        "amount": 7851,
        "fiat_code": "VES",
        "fiat_amount": 100,
        "payment_method": "face to face",
        "premium": 1,
        "buyer_pubkey": null,
        "seller_pubkey": null
      }
    }
  }
}

Mostro updates the parameterized replaceable event with d tag ede61c96-4c13-4519-bf3a-dcf7f1e9d842 to change the status to waiting-buyer-invoice:

[
  "EVENT",
  "RAND",
  {
    "id": "eb0582360ebd3836c90711f774fbecb27e600f4a5fedf4fc2d16fc852f8380b1",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702549437,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "waiting-buyer-invoice"],
      ["amt", "7851"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["network", "mainnet"],
      ["layer", "lightning"],
      ["expiration", "1719391096"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "a835f8620db3ebdd9fa142ae99c599a61da86321c60f7c9fed0cc57169950f4121757ff64a5e998baccf6b68272aa51819c3e688d8ad586c0177b3cd1ab09c0f"
  }
]

Buyer sends LN invoice

The buyer sends a Gift wrap Nostr event to Mostro with the lightning invoice, the action should be the same the buyer just received in the last message from Mostro (add-invoice), here the rumor's content of the event for an invoice with no amount:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "add-invoice",
    "content": {
      "payment_request": [
        null,
        "lnbcrt1pn9dvx0pp5935mskms2uf8wx90m8dlr60ytwn5vxy0e65ls42h7y7exweyvekqdqqcqzzsxqyz5vqsp5xjmllv4ta7jkuc5nfgqp8qjc3amzfewmlycpkkggr7q2y5mjfldq9qyyssqncpf3vm8hwujutqc99f0vy45zh8es54mn6u99q9t6rwm0q80dxszskzrp24y46lxqkc7ly9p80t6lalc8x8xhsn49yhy70a7wqyygugpv7chqs",
        3922
      ]
    }
  }
}

If the invoice includes an amount, the last element of the payment_request array should be set to null.

Mostro response

Mostro send a Gift wrap Nostr event to the buyer with a wrapped order in the rumor's content, it would look like this:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "waiting-seller-to-pay",
    "content": null
  }
}

Mostro updates the parameterized replaceable event with d tag ede61c96-4c13-4519-bf3a-dcf7f1e9d842 to change the status to waiting-payment:

[
  "EVENT",
  "RAND",
  {
    "id": "eb0582360ebd3836c90711f774fbecb27e600f4a5fedf4fc2d16fc852f8380b1",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702549437,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "waiting-payment"],
      ["amt", "7851"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "a835f8620db3ebdd9fa142ae99c599a61da86321c60f7c9fed0cc57169950f4121757ff64a5e998baccf6b68272aa51819c3e688d8ad586c0177b3cd1ab09c0f"
  }
]

Taking a sell order with a lightning address

The buyer can use a lightning address to receive funds and avoid to manually create and send lightning invoices on each trade, to acomplish this the buyer will send a message in a Gift wrap Nostr event to Mostro with the following rumor's content:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "take-sell",
    "content": {
      "payment_request": [null, "mostro_p2p@ln.tips"]
    }
  }
}

The event to send to Mostro would look like this:

{
  "id": "cade205b849a872d74ba4d2a978135dbc05b4e5f483bb4403c42627dfd24f67d",
  "kind": 1059,
  "pubkey": "9a42ac72d6466a6dbe5b4b07a8717ee13e55abb6bdd810ea9c321c9a32ee837b",
  "content": "sealed-rumor-content",
  "tags": [
    ["p", "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a"]
  ],
  "created_at": 1234567890,
  "sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}

Mostro response

Mostro send a Gift wrap Nostr event to the buyer with a wrapped order in the rumor's content, it would look like this:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "waiting-seller-to-pay",
    "content": null
  }
}

Mostro updates the parameterized replaceable event with d tag ede61c96-4c13-4519-bf3a-dcf7f1e9d842 to change the status to waiting-payment:

[
  "EVENT",
  "RAND",
  {
    "id": "eb0582360ebd3836c90711f774fbecb27e600f4a5fedf4fc2d16fc852f8380b1",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702549437,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "waiting-payment"],
      ["amt", "7851"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["network", "mainnet"],
      ["layer", "lightning"],
      ["expiration", "1719391096"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "a835f8620db3ebdd9fa142ae99c599a61da86321c60f7c9fed0cc57169950f4121757ff64a5e998baccf6b68272aa51819c3e688d8ad586c0177b3cd1ab09c0f"
  }
]

Taking a sell range order

If the order fiat amount is a range like 10-20 the buyer must indicate a fiat amount to take the order, buyer will send a message in a Gift wrap Nostr event to Mostro with the following rumor's content:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "take-sell",
    "content": {
      "amount": 15
    }
  }
}

Mostro response

In order to continue the buyer needs to send a lightning network invoice to Mostro, in this case the amount of the order is 0, so Mostro will need to calculate the amount of sats for this order, then Mostro will send back a message asking for a LN invoice indicating the correct amount of sats that the invoice should have, here the rumor's content of the message:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "add-invoice",
    "content": {
      "order": {
        "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
        "amount": 7851,
        "fiat_code": "VES",
        "min_amount": 10,
        "max_amount": 20,
        "fiat_amount": 15,
        "payment_method": "face to face",
        "premium": 1,
        "master_buyer_pubkey": null,
        "master_seller_pubkey": null,
        "buyer_invoice": null,
        "created_at": null,
        "expires_at": null
      }
    }
  }
}

Mostro updates the parameterized replaceable event with d tag ede61c96-4c13-4519-bf3a-dcf7f1e9d842 to change the status to waiting-buyer-invoice:

[
  "EVENT",
  "RAND",
  {
    "id": "eb0582360ebd3836c90711f774fbecb27e600f4a5fedf4fc2d16fc852f8380b1",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702549437,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "waiting-buyer-invoice"],
      ["amt", "7851"],
      ["fa", "15"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["network", "mainnet"],
      ["layer", "lightning"],
      ["expiration", "1719391096"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "a835f8620db3ebdd9fa142ae99c599a61da86321c60f7c9fed0cc57169950f4121757ff64a5e998baccf6b68272aa51819c3e688d8ad586c0177b3cd1ab09c0f"
  }
]

Using a lightning address

The buyer can use a lightning address to receive funds and avoid to create and send lightning invoices on each trade, with a range order we set the fiat amount as the third element of the payment_request array, to acomplish this the buyer will send a message in a Gift wrap Nostr event to Mostro with the following rumor's content:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "take-sell",
    "content": {
      "payment_request": [null, "mostro_p2p@ln.tips", 15]
    }
  }
}

Taking a buy order

To take an order the seller will send to Mostro a message with the following rumor's content:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "take-buy",
    "content": null
  }
}

The event to send to Mostro would look like this:

{
  "id": "cade205b849a872d74ba4d2a978135dbc05b4e5f483bb4403c42627dfd24f67d",
  "kind": 4,
  "pubkey": "1f5bb148a25bca31506594722e746b10acf2641a12725b12072dcbc46ade544d", // Seller's ephemeral pubkey
  "content": "sealed-rumor-content",
  "tags": [
    ["p", "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a"] // Mostro's pubkey
  ],
  "created_at": 1234567890,
  "sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}

Mostro response

Mostro respond to the seller with a message with the following content:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "pubkey": null,
    "action": "pay-invoice",
    "content": {
      "payment_request": [
        {
          "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
          "kind": "buy",
          "status": "waiting-payment",
          "amount": 7851,
          "fiat_code": "VES",
          "fiat_amount": 100,
          "payment_method": "face to face",
          "premium": 1,
          "created_at": 1698957793
        },
        "lnbcrt78510n1pj59wmepp50677g8tffdqa2p8882y0x6newny5vtz0hjuyngdwv226nanv4uzsdqqcqzzsxqyz5vqsp5skn973360gp4yhlpmefwvul5hs58lkkl3u3ujvt57elmp4zugp4q9qyyssqw4nzlr72w28k4waycf27qvgzc9sp79sqlw83j56txltz4va44j7jda23ydcujj9y5k6k0rn5ms84w8wmcmcyk5g3mhpqepf7envhdccp72nz6e"
      ]
    }
  }
}

Mostro updates the event with d tag ede61c96-4c13-4519-bf3a-dcf7f1e9d842 to change the status to WaitingPayment:

[
  "EVENT",
  "RAND",
  {
    "id": "eb0582360ebd3836c90711f774fbecb27e600f4a5fedf4fc2d16fc852f8380b1",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702549437,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "waiting-payment"],
      ["amt", "7851"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["network", "mainnet"],
      ["layer", "lightning"],
      ["expiration", "1719391096"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "a835f8620db3ebdd9fa142ae99c599a61da86321c60f7c9fed0cc57169950f4121757ff64a5e998baccf6b68272aa51819c3e688d8ad586c0177b3cd1ab09c0f"
  }
]

And send a message to the buyer with the following content:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "pubkey": null,
    "action": "waiting-seller-to-pay",
    "content": null
  }
}

Seller pays LN invoice

After seller pays the hold invoice Mostro send a message to the seller with the following content:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "pubkey": null,
    "action": "waiting-buyer-invoice",
    "content": null
  }
}

Mostro updates the parameterized replaceable event with d tag ede61c96-4c13-4519-bf3a-dcf7f1e9d842 to change the status to waiting-buyer-invoice:

[
  "EVENT",
  "RAND",
  {
    "id": "eb0582360ebd3836c90711f774fbecb27e600f4a5fedf4fc2d16fc852f8380b1",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702549437,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "waiting-buyer-invoice"],
      ["amt", "7851"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["network", "mainnet"],
      ["layer", "lightning"],
      ["expiration", "1719391096"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "a835f8620db3ebdd9fa142ae99c599a61da86321c60f7c9fed0cc57169950f4121757ff64a5e998baccf6b68272aa51819c3e688d8ad586c0177b3cd1ab09c0f"
  }
]

And sends a message to the buyer with the following content:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "pubkey": null,
    "action": "add-invoice",
    "content": {
      "order": {
        "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
        "status": "waiting-buyer-invoice",
        "amount": 7851,
        "fiat_code": "VES",
        "fiat_amount": 100,
        "payment_method": "face to face",
        "premium": 1,
        "created_at": null
      }
    }
  }
}

Buyer sends LN invoice

Buyer sends the LN invoice to Mostro.

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "pubkey": null,
    "action": "add-invoice",
    "content": {
      "payment_request": [
        null,
        "lnbcrt78510n1pj59wmepp50677g8tffdqa2p8882y0x6newny5vtz0hjuyngdwv226nanv4uzsdqqcqzzsxqyz5vqsp5skn973360gp4yhlpmefwvul5hs58lkkl3u3ujvt57elmp4zugp4q9qyyssqw4nzlr72w28k4waycf27qvgzc9sp79sqlw83j56txltz4va44j7jda23ydcujj9y5k6k0rn5ms84w8wmcmcyk5g3mhpqepf7envhdccp72nz6e"
      ]
    }
  }
}

Now both parties have an active order and they can keep going with the trade.

Finally Mostro updates the parameterized replaceable event with d tag ede61c96-4c13-4519-bf3a-dcf7f1e9d842 to change the status to active:

[
  "EVENT",
  "RAND",
  {
    "id": "eb0582360ebd3836c90711f774fbecb27e600f4a5fedf4fc2d16fc852f8380b1",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702549437,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "active"],
      ["amt", "7851"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["network", "mainnet"],
      ["layer", "lightning"],
      ["expiration", "1719391096"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "a835f8620db3ebdd9fa142ae99c599a61da86321c60f7c9fed0cc57169950f4121757ff64a5e998baccf6b68272aa51819c3e688d8ad586c0177b3cd1ab09c0f"
  }
]

Taking a buy range order

If the order fiat amount is a range like 10-20 the seller must indicate a fiat amount to take the order, seller will send a message in a Gift wrap Nostr event to Mostro with the following rumor's content:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "take-buy",
    "content": {
      "amount": 15
    }
  }
}

Mostro response

Response is the same as we explained in the Taking a buy order section.

Seller pays hold invoice

When the seller is the maker and the order was taken by a buyer, Mostro will send to the seller a message asking to pay the hold invoice, the rumor's content of the message will look like this:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "pay-invoice",
    "content": {
      "payment_request": [
        {
          "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
          "kind": "sell",
          "status": "waiting-payment",
          "amount": 7851,
          "fiat_code": "VES",
          "fiat_amount": 100,
          "payment_method": "face to face",
          "premium": 1,
          "created_at": 1698937797
        },
        "lnbcrt78510n1pj59wmepp50677g8tffdqa2p8882y0x6newny5vtz0hjuyngdwv226nanv4uzsdqqcqzzsxqyz5vqsp5skn973360gp4yhlpmefwvul5hs58lkkl3u3ujvt57elmp4zugp4q9qyyssqw4nzlr72w28k4waycf27qvgzc9sp79sqlw83j56txltz4va44j7jda23ydcujj9y5k6k0rn5ms84w8wmcmcyk5g3mhpqepf7envhdccp72nz6e"
      ]
    }
  }
}

After the hold invoice is paid and the buyer already sent the invoice to receive the sats, Mostro will send a new message to seller with the following rumor's content:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "buyer-took-order",
    "content": {
      "order": {
        "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
        "kind": "sell",
        "status": "active",
        "amount": 7851,
        "fiat_code": "VES",
        "fiat_amount": 100,
        "payment_method": "face to face",
        "premium": 1,
        "master_buyer_pubkey": "0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427",
        "master_seller_pubkey": "00000ba40c5795451705bb9c165b3af93c846894d3062a9cd7fcba090eb3bf78",
        "buyer_invoice": null,
        "created_at": 1698937797
      }
    }
  }
}

Mostro also send a message to the buyer, this way they can both write to each other in private, this message would look like this:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "pubkey": null,
    "action": "hold-invoice-payment-accepted",
    "content": {
      "order": {
        "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
        "kind": "sell",
        "status": "active",
        "amount": 7851,
        "fiat_code": "VES",
        "fiat_amount": 100,
        "payment_method": "face to face",
        "premium": 1,
        "master_buyer_pubkey": "0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427",
        "master_seller_pubkey": "00000ba40c5795451705bb9c165b3af93c846894d3062a9cd7fcba090eb3bf78",
        "buyer_invoice": null,
        "created_at": 1698937797
      }
    }
  }
}

Mostro updates the parameterized replaceable event with d tag ede61c96-4c13-4519-bf3a-dcf7f1e9d842 to change the status to active:

[
  "EVENT",
  "RAND",
  {
    "id": "eb0582360ebd3836c90711f774fbecb27e600f4a5fedf4fc2d16fc852f8380b1",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702549437,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "active"],
      ["amt", "7851"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "a835f8620db3ebdd9fa142ae99c599a61da86321c60f7c9fed0cc57169950f4121757ff64a5e998baccf6b68272aa51819c3e688d8ad586c0177b3cd1ab09c0f"
  }
]

If the buyer didn't sent the invoice yet

Mostro send this message to the seller:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "waiting-buyer-invoice",
    "content": null
  }
}

And this message to the buyer:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "add-invoice",
    "content": {
      "order": {
        "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
        "kind": "sell",
        "status": "waiting-buyer-invoice",
        "amount": 7851,
        "fiat_code": "VES",
        "fiat_amount": 100,
        "payment_method": "face to face",
        "premium": 1,
        "created_at": 1698937797
      }
    }
  }
}

And updates the parameterized replaceable event with d tag ede61c96-4c13-4519-bf3a-dcf7f1e9d842 to change the status to waiting-buyer-invoice:

[
  "EVENT",
  "RAND",
  {
    "id": "eb0582360ebd3836c90711f774fbecb27e600f4a5fedf4fc2d16fc852f8380b1",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702549437,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "waiting-buyer-invoice"],
      ["amt", "7851"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["network", "mainnet"],
      ["layer", "lightning"],
      ["expiration", "1719391096"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "a835f8620db3ebdd9fa142ae99c599a61da86321c60f7c9fed0cc57169950f4121757ff64a5e998baccf6b68272aa51819c3e688d8ad586c0177b3cd1ab09c0f"
  }
]

Now buyer sends the invoice to Mostro:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "pubkey": null,
    "action": "add-invoice",
    "content": {
      "payment_request": [
        null,
        "lnbcrt78510n1pj59wmepp50677g8tffdqa2p8882y0x6newny5vtz0hjuyngdwv226nanv4uzsdqqcqzzsxqyz5vqsp5skn973360gp4yhlpmefwvul5hs58lkkl3u3ujvt57elmp4zugp4q9qyyssqw4nzlr72w28k4waycf27qvgzc9sp79sqlw83j56txltz4va44j7jda23ydcujj9y5k6k0rn5ms84w8wmcmcyk5g3mhpqepf7envhdccp72nz6e"
      ]
    }
  }
}

And both parties receives each other pubkeys to start a direct conversation

Fiat sent

After the buyer sends the fiat money to the seller, the buyer should send a message in a Gift wrap Nostr event to Mostro indicating that the fiat money was sent, the rumor's content would look like this:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "fiat-sent",
    "content": null
  }
}

The event to send to Mostro would look like this:

{
  "id": "cade205b849a872d74ba4d2a978135dbc05b4e5f483bb4403c42627dfd24f67d",
  "kind": 1059,
  "pubkey": "9a42ac72d6466a6dbe5b4b07a8717ee13e55abb6bdd810ea9c321c9a32ee837b",
  "content": "sealed-rumor-content",
  "tags": [
    ["p", "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a"]
  ],
  "created_at": 1234567890,
  "sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}

Mostro response

Mostro send messages to both parties confirming fiat-sent action and sending again the counterpart pubkey, here an example of the message to the buyer:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "fiat-sent-ok",
    "content": {
      "Peer": {
        "pubkey": "00000ba40c5795451705bb9c165b3af93c846894d3062a9cd7fcba090eb3bf78"
      }
    }
  }
}

And here an example of the message from Mostro to the seller:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "pubkey": "00000ba40c5795451705bb9c165b3af93c846894d3062a9cd7fcba090eb3bf78",
    "action": "fiat-sent-ok",
    "content": {
      "Peer": {
        "pubkey": "0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427"
      }
    }
  }
}

Mostro updates the parameterized replaceable event with d tag ede61c96-4c13-4519-bf3a-dcf7f1e9d842 to change the status to fiat-sent:

[
  "EVENT",
  "RAND",
  {
    "id": "eb0582360ebd3836c90711f774fbecb27e600f4a5fedf4fc2d16fc852f8380b1",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702549437,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "fiat-sent"],
      ["amt", "7851"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["network", "mainnet"],
      ["layer", "lightning"],
      ["expiration", "1719391096"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "a835f8620db3ebdd9fa142ae99c599a61da86321c60f7c9fed0cc57169950f4121757ff64a5e998baccf6b68272aa51819c3e688d8ad586c0177b3cd1ab09c0f"
  }
]

release

After confirming the buyer sent the fiat money, the seller should send a message to Mostro indicating that sats should be delivered to the buyer, the rumor's content of the message will look like this:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "release",
    "content": null
  }
}

Mostro response

Here an example of the Mostro response to the seller:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "hold-invoice-payment-settled",
    "content": null
  }
}

And a message to the buyer to let him know that the sats were released:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "released",
    "content": null
  }
}

Buyer receives sats

Right after seller release sats Mostro will try to pay the buyer's lightning invoice, if the payment is successful Mostro will send a message to the buyer indicating that the purchase was completed:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "purchase-completed",
    "content": null
  }
}

Mostro updates the parameterized replaceable event with d tag ede61c96-4c13-4519-bf3a-dcf7f1e9d842 to change the status to settled-hold-invoice:

[
  "EVENT",
  "RAND",
  {
    "id": "eb0582360ebd3836c90711f774fbecb27e600f4a5fedf4fc2d16fc852f8380b1",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702549437,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "settled-hold-invoice"],
      ["amt", "7851"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "a835f8620db3ebdd9fa142ae99c599a61da86321c60f7c9fed0cc57169950f4121757ff64a5e998baccf6b68272aa51819c3e688d8ad586c0177b3cd1ab09c0f"
  }
]

Mostro will then attempt to pay the buyer's invoice, if the payment successds Mostro updates the parameterized replaceable event with d tag ede61c96-4c13-4519-bf3a-dcf7f1e9d842 to change the status to success:

[
  "EVENT",
  "RAND",
  {
    "id": "eb0582360ebd3836c90711f774fbecb27e600f4a5fedf4fc2d16fc852f8380b1",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702549437,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "success"],
      ["amt", "7851"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["network", "mainnet"],
      ["layer", "lightning"],
      ["expiration", "1719391096"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "a835f8620db3ebdd9fa142ae99c599a61da86321c60f7c9fed0cc57169950f4121757ff64a5e998baccf6b68272aa51819c3e688d8ad586c0177b3cd1ab09c0f"
  }
]

User rating

After a successful trade Mostro send a Gift wrap Nostr event to both parties to let them know they can rate each other, here an example how the message look like:

{
  "order": {
    "version": 1,
    "id": "7e44aa5d-855a-4b17-865e-8ca3834a91a3",
    "action": "rate",
    "content": null
  }
}

After a Mostro client receive this message, the user can rate the other party, the rating is a number between 1 and 5, to rate the client must receive user's input and create a new Gift wrap Nostr event to send to Mostro with this content:

{
  "order": {
    "version": 1,
    "id": "7e44aa5d-855a-4b17-865e-8ca3834a91a3",
    "action": "rate-user",
    "content": {
      "rating_user": 5 // User input
    }
  }
}

Confirmation message

If Mostro received the correct message, it will send back a confirmation message to the user with the action rate-received:

{
  "order": {
    "version": 1,
    "id": "7e44aa5d-855a-4b17-865e-8ca3834a91a3",
    "pubkey": null,
    "action": "rate-received",
    "content": {
      "rating_user": 5
    }
  }
}

Mostro updates the parameterized replaceable rating event, in this event the d tag will be the user pubkey 00000ba40c5795451705bb9c165b3af93c846894d3062a9cd7fcba090eb3bf78 and looks like this:

[
  "EVENT",
  "RAND",
  {
    "id": "80909a120d17632f99995f92caff4801f25e9e523d7643bf8acb0166bd0932a6",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702637077,
    "kind": 38383,
    "tags": [
      ["d", "00000ba40c5795451705bb9c165b3af93c846894d3062a9cd7fcba090eb3bf78"],
      ["total_reviews", "1"],
      ["total_rating", "2"],
      ["last_rating", "1"],
      ["max_rate", "2"],
      ["min_rate", "5"],
      ["data_label", "rating"]
    ],
    "content": "",
    "sig": "456fdc0589a5ffe1b55d5474cef2826bf01f458d63cf409490def9c5af31052e0461d38aed4f386f5dcea999e9fe6001d27d592dbba54a0420687dce0652322f"
  }
]

Cancel Order

A user can cancel an order created by himself and with status pending sending action cancel, the rumor's content of the message will look like this:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "cancel",
    "content": null
  }
}

Mostro response

Mostro will send a message with action cancel confirming the order was canceled, here an example of rumor's content of the message:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "canceled",
    "content": null
  }
}

Mostro updates the parameterized replaceable event with d tag ede61c96-4c13-4519-bf3a-dcf7f1e9d842 to change the status to canceled:

[
  "EVENT",
  "RAND",
  {
    "id": "eb0582360ebd3836c90711f774fbecb27e600f4a5fedf4fc2d16fc852f8380b1",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702549437,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "canceled"],
      ["amt", "7851"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["network", "mainnet"],
      ["layer", "lightning"],
      ["expiration", "1719391096"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "a835f8620db3ebdd9fa142ae99c599a61da86321c60f7c9fed0cc57169950f4121757ff64a5e998baccf6b68272aa51819c3e688d8ad586c0177b3cd1ab09c0f"
  }
]

Cancel cooperatively

A user can cancel an active order, but will need the counterparty to agree, let's look at an example where the seller initiates a cooperative cancellation:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "cancel",
    "content": null
  }
}

Mostro will send this message to the seller:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "cooperative-cancel-initiated-by-you",
    "content": null
  }
}

And this message to the buyer:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "cooperative-cancel-initiated-by-peer",
    "content": null
  }
}

Mostro updates the parameterized replaceable event with d tag ede61c96-4c13-4519-bf3a-dcf7f1e9d842 to change the status to cooperatively-canceled:

[
  "EVENT",
  "RAND",
  {
    "id": "eb0582360ebd3836c90711f774fbecb27e600f4a5fedf4fc2d16fc852f8380b1",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702549437,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "cooperatively-canceled"],
      ["amt", "7851"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "a835f8620db3ebdd9fa142ae99c599a61da86321c60f7c9fed0cc57169950f4121757ff64a5e998baccf6b68272aa51819c3e688d8ad586c0177b3cd1ab09c0f"
  }
]

The buyer can accept the cooperative cancellation sending this message:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "cancel",
    "content": null
  }
}

And Mostro will send this message to both parties:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "cooperative-cancel-accepted",
    "content": null
  }
}

Dispute

A use can start a dispute in an order with status active or fiat-sent sending action dispute, here is an example where the seller initiates a dispute:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "dispute",
    "content": null
  }
}

Mostro response

Mostro will send this message to the seller:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "dispute-initiated-by-you",
    "content": {
      "dispute": "efc75871-2568-40b9-a6ee-c382d4d6de01"
    }
  }
}

And here is the message to the buyer:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "dispute-initiated-by-peer",
    "content": {
      "dispute": "efc75871-2568-40b9-a6ee-c382d4d6de01"
    }
  }
}

Mostro will not update the parameterized replaceable event with d tag ede61c96-4c13-4519-bf3a-dcf7f1e9d842 to change the status to dispute, this is because the order is still active, the dispute is just a way to let the admins and the other party know that there is a problem with the order.

Mostro send a parameterized replaceable event to show the dispute

Here is an example of the event sent by Mostro:

[
  "EVENT",
  "RAND",
  {
    "id": "4a4d63698f8a27d7d44e5669224acf6af2516a9350ae5f07d3cb91e5601f7302",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1703016565,
    "kind": 38383,
    "tags": [
      ["d", "efc75871-2568-40b9-a6ee-c382d4d6de01"],
      ["s", "initiated"],
      ["y", "mostrop2p"],
      ["z", "dispute"]
    ],
    "content": "",
    "sig": "00a1da45c00684c5af18cf292ca11697c9e70f2a691e6cd397211e717d2f54362dd401d7567da8184a5c596f48a09693479e67214c23e773523a63d0b1c3f537"
  }
]

Mostro admin will see the dispute and can take it using the dispute Id from d tag, in this case efc75871-2568-40b9-a6ee-c382d4d6de01.

{
  "dispute": {
    "version": 1,
    "id": "efc75871-2568-40b9-a6ee-c382d4d6de01",
    "action": "admin-take-dispute",
    "content": null
  }
}

Mostro will send a confirmation message to the admin with the order details:

{
  "dispute": {
    "version": 1,
    "id": "efc75871-2568-40b9-a6ee-c382d4d6de01",
    "action": "admin-took-dispute",
    "content": {
      "order": {
        "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
        "kind": "sell",
        "status": "active",
        "amount": 7851,
        "fiat_code": "VES",
        "fiat_amount": 100,
        "payment_method": "face to face",
        "premium": 1,
        "master_buyer_pubkey": "0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427",
        "master_seller_pubkey": "00000ba40c5795451705bb9c165b3af93c846894d3062a9cd7fcba090eb3bf78",
        "buyer_invoice": "lnbcrt11020n1pjcypj3pp58m3d9gcu4cc8l3jgkpfn7zhqv2jfw7p3t6z3tq2nmk9cjqam2c3sdqqcqzzsxqyz5vqsp5mew44wzjs0a58d9sfpkrdpyrytswna6gftlfrv8xghkc6fexu6sq9qyyssqnwfkqdxm66lxjv8z68ysaf0fmm50ztvv773jzuyf8a5tat3lnhks6468ngpv3lk5m7yr7vsg97jh6artva5qhd95vafqhxupyuawmrcqnthl9y",
        "created_at": 1698870173
      }
    }
  }
}

Also Mostro will broadcast a new parameterized replaceable dispute event to update the dispute status to in-progress:

[
  "EVENT",
  "RAND",
  {
    "id": "2bb3f5a045bcc1eb057fd1e22c0cece7c58428a6ab5153299ef4e1e89633fde9",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1703020540,
    "kind": 38383,
    "tags": [
      ["d", "efc75871-2568-40b9-a6ee-c382d4d6de01"],
      ["s", "in-progress"],
      ["y", "mostrop2p"],
      ["z", "dispute"]
    ],
    "content": "",
    "sig": "20d454a0704cfac1d4a6660d234ce407deb56db8f08598741af5d38c0698a96234fd326a34e7efb2ac20c1c0ed0a921fd50513aab8f5c4b83e2509f2d32794d2"
  }
]

Listing Disputes

Mostro publishes new disputes with event kind 38383 and status initiated:

[
  "EVENT",
  "RAND",
  {
    "id": "4a4d63698f8a27d7d44e5669224acf6af2516a9350ae5f07d3cb91e5601f7302",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1703016565,
    "kind": 38383,
    "tags": [
      ["d", "efc75871-2568-40b9-a6ee-c382d4d6de01"],
      ["s", "initiated"],
      ["y", "mostrop2p"],
      ["z", "dispute"]
    ],
    "content": "",
    "sig": "00a1da45c00684c5af18cf292ca11697c9e70f2a691e6cd397211e717d2f54362dd401d7567da8184a5c596f48a09693479e67214c23e773523a63d0b1c3f537"
  }
]

Clients can query this events by nostr event kind `38383`, nostr event author, dispute status (`s`), type (`z`)

Settle order

An admin can settle an order, most of the time this is done when admin is solving a dispute, for this the admin will need to send an order message to Mostro with action admin-settle with the id of the order like this:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "admin-settle",
    "content": null
  }
}

Mostro response

Mostro will send this message to the both parties buyer/seller and to the admin:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "admin-settled",
    "content": null
  }
}

Mostro updates parameterized replaceable events

Mostro will publish two parameterized replaceable messages, one for the order to update the status to settled-by-admin, this means that the hold invoice paid by the seller was settled:

[
  "EVENT",
  "RAND",
  {
    "id": "3d74ce3f10096d163603aa82beb5778bd1686226fdfcfba5d4c3a2c3137929ea",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1703260182,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "settled-by-admin"],
      ["amt", "7851"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "76bfc5e9ce089757dd4074472e1df421da700ce133c874f40b1136607121eca8acfdd2b8b4b374adaa83fa0c7d99672eb21a1068b6b6b774742d5de5bfc932ba"
  }
]

And updates parameterized replaceable dispute event with status settled:

[
  "EVENT",
  "RAND",
  {
    "id": "098e8622eae022a79bc793984fccbc5ea3f6641bdcdffaa031c00d3bd33ca5a0",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1703274022,
    "kind": 38383,
    "tags": [
      ["d", "efc75871-2568-40b9-a6ee-c382d4d6de01"],
      ["s", "settled"],
      ["y", "mostrop2p"],
      ["z", "dispute"]
    ],
    "content": "",
    "sig": "6d7ca7bef7b696f1f6f8cfc33b3fe1beb2fdc6b7647efc93be669c6c1a9d4bafc770d9b0d25432c204dd487d48b39e589dfd7b03bf0e808483921b8937bd5367"
  }
]

Payment of the buyer's invoice

At this point Mostro is trying to pay the buyer's invoice, right after complete the payment Mostro will update the status of the order parameterized replaceable event to success:

[
  "EVENT",
  "RAND",
  {
    "id": "6170892aca6a73906142e58a9c29734d49b399a3811f6216ce553b4a77a8a11e",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1703274032,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "success"],
      ["amt", "7851"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "1670a9e61f7bc99f7121a95a2d479456970fbd9bc84d663160e35d1a95d71a006c7986db050ea584d5040927879fd9dcc85dc0ab5c6367f679c9fd5fd33a3cfb"
  }
]

Cancel order

An admin can cancel an order, most of the time this is done when admin is solving a dispute, for this the admin will need to send an order message to Mostro with action admin-cancel with the id of the order like this:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "admin-cancel",
    "content": null
  }
}

Mostro response

Mostro will send this message to the both parties buyer/seller and to the admin:

{
  "order": {
    "version": 1,
    "id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
    "action": "admin-canceled",
    "content": null
  }
}

Mostro updates parameterized replaceable events

Mostro will publish two parameterized replaceable events, one for the order to update the status to canceled-by-admin, this means that the hold invoice was canceled and the seller's funds were returned:

[
  "EVENT",
  "RAND",
  {
    "id": "3d74ce3f10096d163603aa82beb5778bd1686226fdfcfba5d4c3a2c3137929ea",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1703260182,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "canceled-by-admin"],
      ["amt", "7851"],
      ["fa", "100"],
      ["pm", "face to face"],
      ["premium", "1"],
      ["y", "mostrop2p"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "76bfc5e9ce089757dd4074472e1df421da700ce133c874f40b1136607121eca8acfdd2b8b4b374adaa83fa0c7d99672eb21a1068b6b6b774742d5de5bfc932ba"
  }
]

And updates parameterized replaceable dispute event with status seller-refunded:

[
  "EVENT",
  "RAND",
  {
    "id": "098e8622eae022a79bc793984fccbc5ea3f6641bdcdffaa031c00d3bd33ca5a0",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1703274022,
    "kind": 38383,
    "tags": [
      ["d", "efc75871-2568-40b9-a6ee-c382d4d6de01"],
      ["s", "seller-refunded"],
      ["y", "mostrop2p"],
      ["z", "dispute"]
    ],
    "content": "",
    "sig": "6d7ca7bef7b696f1f6f8cfc33b3fe1beb2fdc6b7647efc93be669c6c1a9d4bafc770d9b0d25432c204dd487d48b39e589dfd7b03bf0e808483921b8937bd5367"
  }
]

Admin add solver

Solvers are users appointed by the Mostro administrator and are responsible for resolving disputes.

The administrator can add or remove them at any time.

The administrator can also solve disputes.

To add a solver the admin will need to send an order message to Mostro with action admin-add-solver:

{
  "order": {
    "version": 1,
    "action": "admin-add-solver",
    "content": {
      "text_message": "npub1qqq884wtp2jn96lqhqlnarl4kk3rmvrc9z2nmrvqujx3m4l2ea5qd5d0fq"
    }
  }
}

Mostro response

Mostro will send this message to the admin:

{
  "order": {
    "version": 1,
    "action": "admin-add-solver",
    "content": null
  }
}

Actions

mostro_core::Action

Action is used to identify each message between Mostro and users

You can see details in mostro core documentation

Message suggestions for some actions

Here are suggestions for messages that clients could show to users when they receive certain actions. Clients can customize these messages to their convenience, as well as translate them, add emojis or any other modifications they consider necessary to provide a good user experience. Clients must complete the information that is in monospace format.

  • new-order: Your offer has been published! Please wait until another user picks your order. It will be available for expiration_hours hours. You can cancel this order before another user picks it up by executing: cancel.

  • canceled: You have cancelled the order ID: id!

  • pay-invoice: Please pay this hold invoice of amount Sats for fiat_code fiat_amount to start the operation. If you do not pay it within expiration_seconds the trade will be cancelled.

  • add-invoice: Please send me an invoice for amount satoshis equivalent to fiat_code fiat_amount. This is where I’ll send the funds upon completion of the trade. If you don't provide the invoice within expiration_seconds this trade will be cancelled.

  • waiting-seller-to-pay: Please wait a bit. I've sent a payment request to the seller to sends the Sats for the order ID id. Once the payment is made, I'll connect you both. If the seller doesn’t complete the payment within expiration_seconds minutes the trade will be cancelled.

  • waiting-buyer-invoice: Payment received! Your Sats are now "held" in your own wallet. Please wait a bit. I've requested the buyer to provide an invoice. Once they do, I 'll connect you both. If they does not do so within expiration_seconds your Sats will be available at your wallet again and the trade will be cancelled.

  • buyer-invoice-accepted: Invoice has been successfully saved!

  • hold-invoice-payment-accepted: Get in touch with the seller, this is their npub seller-npub to get the details on how to send the fiat money for the order id, you must send fiat_code fiat_amount using payment_method. Once you send the fiat money, please let me know with fiat-sent.

  • buyer-took-order: Get in touch with the buyer, this is their npub buyer-npub to inform them how to send you fiat_code fiat_amount through payment_method. I will notify you once the buyer indicates the fiat money has been sent. Afterward, you should verify if it has arrived. If the buyer does not respond, you can initiate a cancellation or a dispute. Remember, an administrator will NEVER contact you to resolve your order unless you open a dispute first.

  • fiat-sent-ok:

    • To the buyer: I have informed to seller-npub that you have sent the fiat money. When the seller confirms they have received your fiat money, they should release the funds. If they refuse, you can open a dispute.
    • To the seller: buyer-npub has informed that they have sent you the fiat money. Once you confirm receipt, please release the funds. After releasing, the money will go to the buyer and there will be no turning back, so only proceed if you are sure. If you want to release the Sats to the buyer, send me release-order-message.
  • released: seller-npub has already released the Sats! Expect your invoice to be paid any time. Remember your wallet needs to be online to receive through the Lightning Network.

  • purchase-completed: Your satoshis purchase has been completed successfully. I have paid your invoice, enjoy sound money!

  • hold-invoice-payment-settled: Your Sats sale has been completed after confirming the payment from buyer-npub.

  • rate: Please qualify your counterparty

  • rate-received: Rating successfully saved!

  • cooperative-cancel-initiated-by-you: You have initiated the cancellation of the order ID: id. Your counterparty must agree to the cancellation too. If they do not respond, you can open a dispute. Note that no administrator will contact you regarding this cancellation unless you open a dispute first.

  • cooperative-cancel-initiated-by-peer: Your counterparty wants to cancel order ID: id. Note that no administrator will contact you regarding this cancellation unless you open a dispute first. If you agree on such cancellation, please send me cancel-order-message.

  • cooperative-cancel-accepted: Order id has been successfully cancelled!

  • dispute-initiated-by-you: You have initiated a dispute for order Id: id. A solver will be assigned to your dispute soon. Once assigned, I will share their npub with you, and only they will be able to assist you. You may contact the solver directly, but if they reach out first, please ask them to provide the token for your dispute. Your dispute token is: user-token.

  • dispute-initiated-by-peer: Your counterparty has initiated a dispute for order Id: ${orderId}. A solver will be assigned to your dispute soon. Once assigned, I will share their npub with you, and only they will be able to assist you. You may contact the solver directly, but if they reach out first, please ask them to provide the token for your dispute. Your dispute token is: user-token.

  • admin-took-dispute:

    • To the admin: Here are the details of the dispute order you have taken: details. You need to determine which user is correct and decide whether to cancel or complete the order. Please note that your decision will be final and cannot be reversed.
    • To the users: The solver admin-npub will handle your dispute. You can contact them directly, but if they reach out to you first, make sure to ask them for your dispute token.
  • admin-canceled:

    • To the admin: You have cancelled the order ID: id!
    • To the users: Admin has cancelled the order ID: id!
  • admin-settled:

    • To the admin: You have completed the order ID: id!
    • To the users: Admin has completed the order ID: id!
  • is-not-your-dispute: This dispute was not assigned to you!

  • not-found: Dispute not found.

  • payment-failed: I tried to send you the Sats but the payment of your invoice failed, I will try payment_attempts more times in payment_retries_interval minutes window. Please ensure your node/wallet is online.

  • invoice-updated: Invoice has been successfully updated!

  • hold-invoice-payment-canceled: The invoice was cancelled, your Sats will be available at your wallet again.

  • cant-do: You are not allowed to action for this order!

  • admin-add-solver: You have successfully added to the solver npub.

  • is-not-your-order: You did not create this order and are not authorized to action it.

  • not-allowed-by-status: You are not allowed to action because order Id id status is order-status.

  • out-of-range-fiat-amount: The requested amount is incorrect and may be outside the acceptable range. The minimum is min_amount and the maximum is max_amount.

  • incorrect-invoice-amount:

    • If the buyer previously had sent the new-order action:
      An invoice with non-zero amount was receive for the new order. Please send an invoice with a zero amount or no invoice at all.
    • If the buyer previously sent the add-invoice action:
      The amount stated in the invoice is incorrect. Please send an invoice with an amount of amount satoshis, an invoice without an amount, or a lightning address.
  • invalid-sats-amount: That specified Sats amount is invalid.

  • out-of-range-sats-amount: The allowed Sats amount for this Mostro is between min min_order_amount and max max_order_amount. Please enter an amount within this range.

Peer-to-peer Order events

Abstract

Peer-to-peer (P2P) platforms have seen an upturn in recent years, while having more and more options is positive, in the specific case of p2p, having several options contributes to the liquidity split, meaning sometimes there's not enough assets available for trading. If we combine all these individual solutions into one big pool of orders, it will make them much more competitive compared to centralized systems, where a single authority controls the liquidity.

This NIP defines a simple standard for peer-to-peer order events, which enables the creation of a big liquidity pool for all p2p platforms participating.

The event

Events are Parameterized Replaceable Events and use 38383 as event kind, a p2p event look like this:

[
  "EVENT",
  "RAND",
  {
    "id": "84fad0d29cb3529d789faeff2033e88fe157a48e071c6a5d1619928289420e31",
    "pubkey": "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a",
    "created_at": 1702548701,
    "kind": 38383,
    "tags": [
      ["d", "ede61c96-4c13-4519-bf3a-dcf7f1e9d842"],
      ["k", "sell"],
      ["f", "VES"],
      ["s", "pending"],
      ["amt", "0"],
      ["fa", "100"],
      ["pm", "face to face", "bank transfer"],
      ["premium", "1"],
      [
        "rating",
        "{\"total_reviews\":1,\"total_rating\":3.0,\"last_rating\":3,\"max_rate\":5,\"min_rate\":1}"
      ],
      ["source", "https://t.me/p2plightning/xxxxxxx"],
      ["network", "mainnet"],
      ["layer", "lightning"],
      ["name", "Satoshi"],
      ["g", "<geohash>"],
      ["bond", "0"],
      ["expiration", "1719391096"],
      ["y", "lnp2pbot"],
      ["z", "order"]
    ],
    "content": "",
    "sig": "7e8fe1eb644f33ff51d8805c02a0e1a6d034e6234eac50ef7a7e0dac68a0414f7910366204fa8217086f90eddaa37ded71e61f736d1838e37c0b73f6a16c4af2"
  }
]

Tags

  • d < Order ID >: A unique identifier for the order.
  • k < Order type >: sell or buy.
  • f < Currency >: The asset being traded, using the ISO 4217 standard.
  • s < Status >: pending, canceled, in-progress, success.
  • amt < Amount >: The amount of Bitcoin to be traded, the amount is defined in satoshis, if 0 means that the amount of satoshis will be obtained from a public API after the taker accepts the order.
  • fa < Fiat amount >: The fiat amount being traded, for range orders two values are expected, the minimum and maximum amount.
  • pm < Payment method >: The payment method used for the trade, if the order has multiple payment methods, they should be separated by a comma.
  • premium < Premium >: The percentage of the premium the maker is willing to pay.
  • source [Source]: The source of the order, it can be a URL that redirects to the order.
  • rating [Rating]: The rating of the maker, this document does not define how the rating is calculated, it's up to the platform to define it.
  • network < Network >: The network used for the trade, it can be mainnet, testnet, signet, etc.
  • layer < Layer >: The layer used for the trade, it can be onchain, lightning, liquid, etc.
  • name [Name]: The name of the maker.
  • g [Geohash]: The geohash of the operation, it can be useful in a face to face trade.
  • bond [Bond]: The bond amount, the bond is a security deposit that both parties must pay.
  • expiration < Expiration>: The expiration date of the order (NIP-40).
  • y < Platform >: The platform that created the order.
  • z < Document >: order.

Mandatory tags are enclosed with <tag>, optional tags are enclosed with [tag].

Implementations

Currently implemented on the following platforms:

This document is inspired on