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 a Nostr event kind 4, the content
field of the event should be a base64-encoded, aes-256-cbc encrypted JSON-serialized string (with no white space or line breaks) of the following structure:
version
: Version of the protocol, currently1
pubkey
(optional): Real pubkey of the user, if present the message is signed with the real pubkey, this is used when users are sending messages from ephemeral keys- 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",
"pubkey": "0001be6bd50247846a28cce439a10470a39b1b6c81d5c3be2475156a413e1e3a",
"action": "fiat-sent",
"content": null
}
}
Keys
For all examples the participants will use this keys:
- Mostro's pubkey
dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a
- Seller's real pubkey
00000ba40c5795451705bb9c165b3af93c846894d3062a9cd7fcba090eb3bf78
- Seller's ephemeral pubkey
1f5bb148a25bca31506594722e746b10acf2641a12725b12072dcbc46ade544d
- Buyer's real pubkey
0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427
- Buyer's ephemeral pubkey
9a42ac72d6466a6dbe5b4b07a8717ee13e55abb6bdd810ea9c321c9a32ee837b
Ephemeral keys
Mostro clients should use newly fresh keys to communicate with Mostro, indicating the pubkey where they want to be contacted by the counterpart in the pubkey
field of the message, this way orders and users can't be easily linked, buyer_pubkey
and seller_pubkey
fields are each party real pubkeys.
Creating a new sell order
To create a new sell order the user should send a Nostr event kind 4 (an encrypted message) to Mostro with the following content:
{
"order": {
"version": 1,
"pubkey": "00000ba40c5795451705bb9c165b3af93c846894d3062a9cd7fcba090eb3bf78", // Seller's real pubkey
"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
orbuy
- 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
- pubkey: Real user's npub, we use this when the message was sent from an ephemeral key
- 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": 4,
"pubkey": "1f5bb148a25bca31506594722e746b10acf2641a12725b12072dcbc46ade544d", // Seller's ephemeral pubkey
"content": "base64-encoded-aes-256-cbc-encrypted-JSON-serialized-string",
"tags": [
["p", "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a"] // Mostro's pubkey
],
"created_at": 1234567890,
"sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}
Confirmation message
Mostro will send back a nip04 event as a confirmation message to the user like the following:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": "00000ba40c5795451705bb9c165b3af93c846894d3062a9cd7fcba090eb3bf78",
"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 Nostr event kind 4 (an encrypted message) to Mostro with the following content:
{
"order": {
"version": 1,
"pubkey": "00000ba40c5795451705bb9c165b3af93c846894d3062a9cd7fcba090eb3bf78", // Seller's real pubkey
"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
}
}
}
}
We 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 nip04 event as a confirmation message to the user like the following:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": "00000ba40c5795451705bb9c165b3af93c846894d3062a9cd7fcba090eb3bf78",
"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 Nostr event kind 4 (an encrypted message) to Mostro with the following content:
{
"order": {
"version": 1,
"pubkey": "0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427", // Buyer's real pubkey
"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": 4,
"pubkey": "9a42ac72d6466a6dbe5b4b07a8717ee13e55abb6bdd810ea9c321c9a32ee837b", // Buyer's ephemeral pubkey
"content": "base64-encoded-aes-256-cbc-encrypted-JSON-serialized-string",
"tags": [
["p", "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a"] // Mostro's pubkey
],
"created_at": 1234567890,
"sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}
Confirmation message
Mostro will send back a nip04 event as a confirmation message to the user like the following:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": "0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427",
"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,
"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", "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"
}
]
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:
-
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.
-
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 Nostr event kind 4 (an encrypted message) to Mostro with the following content:
{
"order": {
"version": 1,
"pubkey": "0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427", // Buyer's real pubkey
"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": 4,
"pubkey": "9a42ac72d6466a6dbe5b4b07a8717ee13e55abb6bdd810ea9c321c9a32ee837b", // Buyer's ephemeral pubkey
"content": "base64-encoded-aes-256-cbc-encrypted-JSON-serialized-string",
"tags": [
["p", "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a"] // Mostro's pubkey
],
"created_at": 1234567890,
"sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}
Confirmation message
Mostro will send back a nip04 event as a confirmation message to the user like the following:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": "0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427",
"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,
"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", "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"
}
]
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 Nostr event kind 4 to Mostro with the following content:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": "0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427",
"action": "take-sell",
"content": null
}
}
The event to send to Mostro would look like this:
{
"id": "cade205b849a872d74ba4d2a978135dbc05b4e5f483bb4403c42627dfd24f67d",
"kind": 4,
"pubkey": "9a42ac72d6466a6dbe5b4b07a8717ee13e55abb6bdd810ea9c321c9a32ee837b",
"content": "base64-encoded-aes-256-cbc-encrypted-JSON-serialized-string",
"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 unencrypted content of the message:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": null,
"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 nip 04 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 unencrypted content of the event for an invoice with no amount:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": null,
"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 nip 04 event to the buyer with a wrapped order
in the content, it would look like this:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": null,
"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 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"],
["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 create and send lightning invoices on each trade, to acomplish this the buyer will send a message in a Nostr event kind 4 to Mostro with the following content:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": "0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427",
"action": "take-sell",
"content": {
"payment_request": [null, "mostro_p2p@ln.tips"]
}
}
}
The event to send to Mostro would look like this:
{
"id": "cade205b849a872d74ba4d2a978135dbc05b4e5f483bb4403c42627dfd24f67d",
"kind": 4,
"pubkey": "9a42ac72d6466a6dbe5b4b07a8717ee13e55abb6bdd810ea9c321c9a32ee837b",
"content": "base64-encoded-aes-256-cbc-encrypted-JSON-serialized-string",
"tags": [
["p", "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a"]
],
"created_at": 1234567890,
"sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}
Mostro response
Mostro send a nip 04 event to the buyer with a wrapped order
in the content, it would look like this:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": null,
"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 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"
}
]
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 Nostr event kind 4 to Mostro with the following content:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": "0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427",
"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 unencrypted content of the message:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": null,
"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 Nostr event kind 4 to Mostro with the following content:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": "0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427",
"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 content:
{
"order": {
"version": 1,
"pubkey": "00000ba40c5795451705bb9c165b3af93c846894d3062a9cd7fcba090eb3bf78",
"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": "base64-encoded-aes-256-cbc-encrypted-JSON-serialized-string",
"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 Nostr event kind 4 to Mostro with the following content:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": "0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427",
"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 content of the message will look like this:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": null,
"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 content:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": null,
"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",
"pubkey": "0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427",
"action": "waiting-buyer-invoice",
"content": null
}
}
And this message to the buyer:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": null,
"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 to Mostro indicating that the fiat money was sent, the message will look like this:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": "0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427",
"action": "fiat-sent",
"content": null
}
}
The event to send to Mostro would look like this:
{
"id": "cade205b849a872d74ba4d2a978135dbc05b4e5f483bb4403c42627dfd24f67d",
"kind": 4,
"pubkey": "9a42ac72d6466a6dbe5b4b07a8717ee13e55abb6bdd810ea9c321c9a32ee837b",
"content": "base64-encoded-aes-256-cbc-encrypted-JSON-serialized-string",
"tags": [
["p", "dbe0b1be7aafd3cfba92d7463edbd4e33b2969f61bd554d37ac56f032e13355a"]
],
"created_at": 1234567890,
"sig": "a21eb195fe418613aa9a3a8a78039b090e50dc3f9fb06b0f3fe41c63221adc073a9317a1f28d9db843a43c28d860ba173b70132ca85b0e706f6487d43a57ee82"
}
Mostro response
Mostro send a 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",
"pubkey": "0000147e939bef2b81c27af4c1b702c90c3843f7212a34934bff1e049b7f1427",
"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 message will look like this:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": "00000ba40c5795451705bb9c165b3af93c846894d3062a9cd7fcba090eb3bf78",
"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",
"pubkey": null,
"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",
"pubkey": null,
"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",
"pubkey": null,
"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"
}
]
Seconds later Mostro will try to pay the buyer's invoice, if the payment is successful 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 nip04 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",
"pubkey": null,
"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 nip04 event to send to Mostro with this content:
{
"order": {
"version": 1,
"id": "7e44aa5d-855a-4b17-865e-8ca3834a91a3",
"pubkey": null,
"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 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 message content will look like this:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": "00000ba40c5795451705bb9c165b3af93c846894d3062a9cd7fcba090eb3bf78",
"action": "cancel",
"content": null
}
}
Mostro response
Mostro will send a message with action cancel
confirming the order was canceled, here an example of the message:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": null,
"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",
"pubkey": null,
"action": "cancel",
"content": null
}
}
Mostro will send this message to the seller:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": null,
"action": "cooperative-cancel-initiated-by-you",
"content": null
}
}
And this message to the buyer:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": null,
"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",
"pubkey": null,
"action": "cancel",
"content": null
}
}
And Mostro will send this message to both parties:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": null,
"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",
"pubkey": "00000ba40c5795451705bb9c165b3af93c846894d3062a9cd7fcba090eb3bf78",
"action": "dispute",
"content": null
}
}
Mostro response
Mostro will send this message to the seller:
{
"order": {
"version": 1,
"id": "ede61c96-4c13-4519-bf3a-dcf7f1e9d842",
"pubkey": null,
"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",
"pubkey": null,
"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",
"pubkey": null,
"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",
"pubkey": null,
"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",
"pubkey": null,
"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",
"pubkey": null,
"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",
"pubkey": null,
"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",
"pubkey": null,
"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,
"pubkey": null,
"action": "admin-add-solver",
"content": {
"text_message": "npub1qqq884wtp2jn96lqhqlnarl4kk3rmvrc9z2nmrvqujx3m4l2ea5qd5d0fq"
}
}
}
Mostro response
Mostro will send this message to the admin:
{
"order": {
"version": 1,
"pubkey": null,
"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
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
orbuy
.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, if0
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 bemainnet
,testnet
,signet
, etc.layer
< Layer >: The layer used for the trade, it can beonchain
,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: