Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NIP-15 Nostr marketplace #330

Merged
merged 32 commits into from
Apr 13, 2023
Merged

NIP-15 Nostr marketplace #330

merged 32 commits into from
Apr 13, 2023

Conversation

arcbtc
Copy link
Contributor

@arcbtc arcbtc commented Mar 6, 2023

Based on Diagon Alley https://github.com/lnbits/Diagon-Alley

Adds a marketplace NIP. Clients being built here on @lnbits https://github.com/lnbits/nostrmarket

@nicolasburtey
Copy link

one use for marketplace that would be useful is peer to peer trading. the reputation that is inherently build on nostr is what it a very good fit (how reputation should be built/managed should probably be handled in another NIP)

for this use case to work on this piece, the first missing from this PR that I can think of right now are:

  • need to get a range for quantity. ie: a seller is willing to buy or sell X sats per transfer
  • an escrow service is (typically) needed. the escrow service itself should be another PR but there should be a way to reference the id of the escrows that are accepted

maybe the use case is specific enough that it could be a dedicated nip

@cj-chua
Copy link

cj-chua commented Mar 22, 2023

Step 2: merchant request payment (event)

This seems to be a new payment standard (in relation to Zaps), should it be made into a NIP?

Personally I prefer this over zaps, since the receiver need not implement a lnurl server

When building payments related stuff on top of nostr it's unclear if one should build on top of zaps, or define a payment standard for the feature one is building (like this nip), or define a list of payment standard nips (what i'm kinda proposing). Curious to know what people think

@ibz
Copy link
Contributor

ibz commented Mar 22, 2023

Since the sale is conducted via DM - which although encrypted, is still visible to others - can't outside observers guess who bought what items by simply correlating the times the DMs were send to the times the object inventory was decremented by the seller?

45.md Outdated
| `0 ` | `set_meta` | The merchant description (similar with any `nostr` public key). | [NIP01 ](https://github.com/nostr-protocol/nips/blob/master/01.md) |
| `30017` | `set_stall` | Create or update a stall. | [NIP33](https://github.com/nostr-protocol/nips/blob/master/33.md) (Parameterized Replaceable Event) |
| `30018` | `set_product` | Create or update a product. | [NIP33](https://github.com/nostr-protocol/nips/blob/master/33.md) (Parameterized Replaceable Event) |
| `4 ` | `direct_message` | Communicate with the customer. The messages can be plain-text or JSON. | [NIP09](https://github.com/nostr-protocol/nips/blob/master/09.md) |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use the kind 4, use another number so that it doesn't get mixed with regular DM's in clients

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • this is the only kind that its encrypted
  • it has the (privacy) advantage that it "looses in the crowd". Otherwise it would be much easier to identify orders.
  • the key (npub) that a customer uses to buy goods might be different than the one used for social media
  • some social media clients (like hamstr) have nice way of displaying JSON (in the form of tables)

Copy link
Member

@v0l v0l Mar 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Use the same encryption scheme
  • Stores and clients might use different keys anyway so this doesnt really add any noise to hide in
  • Yes
  • Most don't and won't parse json messages in DM's, nor should they ever expect JSON, normies will be extremely confused

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stores and clients might use different keys anyway so this doesnt really add any noise to hide in

The noise is network-wide not key-specific. Although since the other kinds determine the pubkey of the marketplace, you are right, it is obvious the comms are for marketplace actions.

@motorina0
The only way to make this work is to do what I did in lnurl/luds#203 and have an extra interaction round so that the stall tells the customer which pubkey to communicate with.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Kukks

@ktecho
Copy link
Contributor

ktecho commented Mar 30, 2023

@motorina0
The fields for products are not updated against what you have in models.py. I'm seeing there categories and image, but here in the spec we don't have categories and we have images and specs.

Which one will you be using? I guess the one in the code, right?

Copy link
Contributor

@Kukks Kukks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excited about this one! Although I would rather future proof it by making some components of it more flexible.

45.md Outdated
| `0 ` | `set_meta` | The merchant description (similar with any `nostr` public key). | [NIP01 ](https://github.com/nostr-protocol/nips/blob/master/01.md) |
| `30017` | `set_stall` | Create or update a stall. | [NIP33](https://github.com/nostr-protocol/nips/blob/master/33.md) (Parameterized Replaceable Event) |
| `30018` | `set_product` | Create or update a product. | [NIP33](https://github.com/nostr-protocol/nips/blob/master/33.md) (Parameterized Replaceable Event) |
| `4 ` | `direct_message` | Communicate with the customer. The messages can be plain-text or JSON. | [NIP09](https://github.com/nostr-protocol/nips/blob/master/09.md) |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stores and clients might use different keys anyway so this doesnt really add any noise to hide in

The noise is network-wide not key-specific. Although since the other kinds determine the pubkey of the marketplace, you are right, it is obvious the comms are for marketplace actions.

@motorina0
The only way to make this work is to do what I did in lnurl/luds#203 and have an extra interaction round so that the stall tells the customer which pubkey to communicate with.

45.md Outdated Show resolved Hide resolved
45.md Outdated Show resolved Hide resolved
45.md Outdated
"name": <String, stall name>,
"description": <String (optional), stall description>,
"currency": <String, currency used>,
"shipping": [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels very specific and inflexible. What if the items require a more complex shipping cost structure, such as a weight/country matrix, cart subtotal quota, etc? Realistically, the current shipping option does not work for most sellers.

I would suggest shipping be optional, a simple string value describing the shipping costs.

Then, I would add a checkoutData array similar in function to https://github.com/lnurl/luds/blob/luds/18.md
For example:

    "checkoutData": {
        "name": { mandatory: boolean, description: string },
        "address": { mandatory: boolean, description: string },
        "country": { mandatory: boolean, description: string }
    }

And then, in the customer order event, add the following to the payload:

   "checkoutData": { "name" : "Kukks", "address": "17, Chocolate Street", "country": "Russia"}

This would also omit the shipping_id and address from customer order event

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the items require a more complex shipping cost structure, such as a weight/country matrix

  • I agree it does not cover complex shipping scenarios (was not intended to)
  • the solution (as far as this NIP goes) is for the merchant to send over DM to the customer any relevant information (like extra shipping cost for higher weights)
  • use-cases for : gift cards, promotions, discounts (over a certain quantity), etc are not included in this NIP (but can be part of future NIPs)

I would suggest shipping be optional, a simple string value describing the shipping costs.

  • the shipping cost can vary depending on the shipping zone (so more costs are possible)
  • the shipping zone id is required, as the merchant cannot rely on the value (cost) sent by the client

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Realistically, the current shipping option does not work for most sellers.

  • why not?
  • left: amazon, right: alibaba

image

@mikestaub
Copy link

How can different pricing models be supported with this NIP? Subscriptions, Pay-per-use, etc? Would that logic live outside the nostr protocol in the client logic?

@Kukks
Copy link
Contributor

Kukks commented Apr 1, 2023

How can different pricing models be supported with this NIP? Subscriptions, Pay-per-use, etc? Would that logic live outside the nostr protocol in the client logic?

I don't think this nip can be that explicit in its current state? Maybe subscriptions could be that the same stall can send a payment request to the request again after to renew the subscription?

How would pay per use make sense in this flow? Maybe you just pay in advance and the product is just creditd for usage consumption?

Any other model to consider?

@mikestaub
Copy link

The value prop for these types of charging models is the "one-time-setup" of the agreement. If as a buyer, I have to keep approving requests that will be annoying. Of course, the client can just automate that for you but I want to be sure that this NIP is explicitly making that decision as there are tradeoffs.

motorina0 and others added 2 commits April 3, 2023 09:37
Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>
Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>
@Kukks
Copy link
Contributor

Kukks commented Apr 3, 2023

The value prop for these types of charging models is the "one-time-setup" of the agreement. If as a buyer, I have to keep approving requests that will be annoying. Of course, the client can just automate that for you but I want to be sure that this NIP is explicitly making that decision as there are tradeoffs.
If selling a subscription, the initial payment request could be the agreement being bound. Since the payment mechanism is out of scope for this NIP, it could handle auto payments (for example the payment method could accept a lnurlw which pull the renewal amount automatically). A payment request should still be sent out for the renewal regardless of automatic payments so that the buyer is aware of "charges" that will be made.

@motorina0
Copy link
Contributor

How can different pricing models be supported with this NIP? Subscriptions, Pay-per-use, etc? Would that logic live outside the nostr protocol in the client logic?

  • those are valid use-cases, but are not part of this NIP (it would make it too large and would require any shop to support them)
  • this NIP is for a vanilla store/stall. Think of a plain old marketplace with stalls.
  • those use-cases can later be added as NIPs (on top of this one) and can be supported or not by different marketplace clients (just like social media clients support or not some NIPs)

@motorina0
Copy link
Contributor

@motorina0 The fields for products are not updated against what you have in models.py. I'm seeing there categories and image, but here in the spec we don't have categories and we have images and specs.

Which one will you be using? I guess the one in the code, right?

  • we have decided to use images so that a product can have a gallery of images. The code has been updated.
  • categories are published as t tag values so they can be searched by

@motorina0
Copy link
Contributor

Since the sale is conducted via DM - which although encrypted, is still visible to others - can't outside observers guess who bought what items by simply correlating the times the DMs were send to the times the object inventory was decremented by the seller?

That is correct. There are these discussions for increasing the privacy of DMs in Nostr:

There might be other propsals, that I'm not aware of.

@ktecho
Copy link
Contributor

ktecho commented Apr 10, 2023

@motorina0 We don't have a way to differenciate test products from real ones, right?

@motorina0
Copy link
Contributor

@motorina0 We don't have a way to differenciate test products from real ones, right?

  • there is no such method
  • there should be test merchant public keys used for that

@arcbtc arcbtc changed the title NIP45 Nostr marketplace NIP-15 Nostr marketplace Apr 12, 2023
@fiatjaf fiatjaf merged commit bf0a0da into nostr-protocol:master Apr 13, 2023
@ktecho
Copy link
Contributor

ktecho commented Apr 13, 2023

@motorina0 We don't have a way to differenciate test products from real ones, right?

  • there is no such method
  • there should be test merchant public keys used for that

Shouldn't we have something like what we have for standard notes? Something like "report this item as testing product", because I guess right now 100% of products are test products and they will be there forever :)

@ibz
Copy link
Contributor

ibz commented Apr 13, 2023

Can we just report them using the 1984 event kind?

@ktecho
Copy link
Contributor

ktecho commented Apr 18, 2023

@motorina0 Should we have a message type so the merchant can tell the user "purchase rejected" for "this reasons... the address is not valid..." or whatever?

Or that should be made using DMs from the merchant to the buyer?

@motorina0
Copy link
Contributor

Shouldn't we have something like what we have for standard notes? Something like "report this item as testing product", because I guess right now 100% of products are test products and they will be there forever :)

  • not familiar how "standard notes" can be marked as "test data". Can you please point me tho the NIP.
  • a marketplace is a collection of merchant public keys. If a "test" merchant is added to the list then test data will be visible.
  • a marketplace should not blindly aggregate all events that have kind: 3018 (product) because it will get everything from cars to dog food

@motorina0
Copy link
Contributor

Can we just report them using the 1984 event kind?

this is scary

@motorina0
Copy link
Contributor

@motorina0 Should we have a message type so the merchant can tell the user "purchase rejected" for "this reasons... the address is not valid..." or whatever?

Or that should be made using DMs from the merchant to the buyer?

DMs should be used. It is possible that a different NIP will emerge covering the scenario you have mentioned.

@ktecho
Copy link
Contributor

ktecho commented Apr 19, 2023

  • a marketplace should not blindly aggregate all events that have kind: 3018 (product) because it will get everything from cars to dog food

Where is the information about kind: 3018? It's not in the nip-15.

@ktecho
Copy link
Contributor

ktecho commented Apr 19, 2023

@motorina0

Don't you think it would be cool to have an "error" message from the merchant to the buyer?

At least something that's going to happen a lot: the user tries to buy more stock than what is available because some other user bought some units.

@motorina0
Copy link
Contributor

Where is the information about kind: 3018? It's not in the nip-15.

Sorry, 30018 (not 3018)
https://github.com/nostr-protocol/nips/blob/master/15.md#merchant-publishingupdating-products-event

@motorina0
Copy link
Contributor

Don't you think it would be cool to have an "error" message from the merchant to the buyer?

At least something that's going to happen a lot: the user tries to buy more stock than what is available because some other user bought some units.

  • yes, it would be cool and also useful
  • this NIP takes care of the basic functionality required for a nostr market to be considered compatible and functional
  • there are many use-cases that would improve the user experience, but it would lead up to a very large NIP which fewer implementations would support

staab pushed a commit to coracle-social/nips that referenced this pull request May 13, 2023
Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>
Co-authored-by: Vlad Stan <stan.v.vlad@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants