nips icon indicating copy to clipboard operation
nips copied to clipboard

docs: add nip-58 badge event and profile badges

Open cameri opened this issue 2 years ago • 18 comments

Adds event kind 8 meaning Badge and event kind 30008 parameterized replaceable event meaning Profile Badge.

cameri avatar Feb 07 '23 04:02 cameri

Looks good.

fiatjaf avatar Feb 07 '23 08:02 fiatjaf

For image and thumbs that are used to display images from a URL, should the minted badge include the SHA-256 hash of the image as well? I'm guessing we don't want the image host or badge issuer to be able to change the badge images based on time-of-day, or client IP without the client being able to notice something has changed.

gkbrk avatar Feb 07 '23 10:02 gkbrk

Oh, another thing related to the URLs in this NIP. Are the image and thumbnail URLs supposed to be HTTP or HTTPS only? Or are other schemes valid as well? Like data URLs, ipfs:// URLs, Bittorrent magnet URLs etc.

gkbrk avatar Feb 07 '23 10:02 gkbrk

Oh, another thing related to the URLs in this NIP. Are the image and thumbnail URLs supposed to be HTTP or HTTPS only? Or are other schemes valid as well? Like data URLs, ipfs:// URLs, Bittorrent magnet URLs etc.

URL so it can be located anywhere.

cameri avatar Feb 07 '23 11:02 cameri

I like this idea, just one question: What is the purpose of having ["d", "profile_badges"] in the tags? Is this not already known through the kind 30008?

sondreb avatar Feb 07 '23 11:02 sondreb

I like this idea, just one question: What is the purpose of having ["d", "profile_badges"] in the tags? Is this not already known through the kind 30008?

This prevents another kind 30008 event from replacing it unless that event is also for the key profile_badges.

These are parameterized replaceable events, so the kind isn't super important. You could use kind 30008 for another purpose, and if you used a different d tag things wouldn't overwrite each other.

gkbrk avatar Feb 07 '23 12:02 gkbrk

This prevents another kind 30008 event from replacing it unless that event is also for the key profile_badges. These are parameterized replaceable events, so the kind isn't super important. You could use kind 30008 for another purpose, and if you used a different d tag things wouldn't overwrite each other.

I am not happy with this answer. This feels like introducing two ways of doing the same thing.

Why not just define kind 10003 as meaning "profile badges" and put all badges there?

The answer above says "the kind isn't super important". To me if it isn't important it shouldn't be defined or used.

Do you also think kind 0 events should be a parameterized replaceable event and have a d tag that says "metadata"?

fiatjaf avatar Feb 08 '23 11:02 fiatjaf

I am not happy with this answer. This feels like introducing two ways of doing the same thing.

To clarify, I didn't write this NIP so my answer might not reflect that of the author.

Why not just define kind 10003 as meaning "profile badges" and put all badges there?

Makes sense to me.

The answer above says "the kind isn't super important". To me if it isn't important it shouldn't be defined or used.

Kind isn't an optional field, so it needs to be used.

You can't query filter by d tags unless the relay implements the generic tag query NIP, but you can fall back to a kind query to find this event.

Do you also think kind 0 events should be a parameterized replaceable event and have a d tag that says "metadata"?

Yes.

I also think setting aside arbitrary ranges for replaceable/ephemeral/parameterized replaceable was dumb, should have been tags or another field that determines that. Why should a relay hardcode that kind=0 is a replaceable event, instead of the event specifying that in can be replaced.

The person sending the event already knows if it should be replaced or not, or ephemeral or not, or if it should be replaced with pubkey + kind, or pubkey + kind + replacement key, there is no need to use ranges for this.

gkbrk avatar Feb 08 '23 11:02 gkbrk

you can fall back to a kind

This is not good. If the kind is enough we should use just the kind.

Yes.

Has that been working bad so far such that it would be improved by having a d tag? The best you'll achieve with that is to just replace the entire concept of kinds with that of d tags, which essentially become named kinds.

Why should a relay hardcode that kind=0 is a replaceable event

The event specifies that by being in a kind range that is replaceable. No need to transfer an additional useless property called "replaceable", no need to parse that every single time. Ideally we wouldn't have these ranges and everything would be hardcoded, but that's not feasible, so the ranges are a nice solution.

I know programmers like to parse things at runtime and have the program dynamically handle everything, but that's not a good idea for open protocols. Some things must always be hardcoded. And the more things you can manage to hardcode the better.

Or maybe you wanted, for example, that each event had a JSON schema attached to itself specifying what fields it contains. It would also have to specify a hashing algorithm in itself, hashing function, curve and signature algorithm, because it would be dumb to have these things hardcoded! Not to mention the hardcoding of the JSON spec, why not allow events to have any encoding they want, they just specify that in their leading byte, we don't want to be dumb and hardcode the JSON format! And then you also need relays to advertise what protocols they accept for connections, because it would be dumb to hardcode that they all use websockets!

fiatjaf avatar Feb 08 '23 12:02 fiatjaf

I think all these properties should be moved to tags and content should be an optional human-readable string describing the context of that specific badge award.

"tags": [
  ["p", "deadbeef"],
  ["r", "bravery"], // this is so one can query how many of any given tags a public key has issued
  ["name", "Bravery"], // optional
  ["description", "Given to people who shows signs of bravery"], // optional
  ["image", "https://..."], // optional
  ["thumb", "https://..."], // optional
  ["image_sha256sum", "..."] // optional
],
"content": "bob won this badge because his actions on field"

fiatjaf avatar Feb 08 '23 13:02 fiatjaf

This prevents another kind 30008 event from replacing it unless that event is also for the key profile_badges.

These are parameterized replaceable events, so the kind isn't super important. You could use kind 30008 for another purpose, and if you used a different d tag things wouldn't overwrite each other.

I am not happy with this answer. This feels like introducing two ways of doing the same thing.

Why not just define kind 10003 as meaning "profile badges" and put all badges there?

The answer above says "the kind isn't super important". To me if it isn't important it shouldn't be defined or used.

Do you also think kind 0 events should be a parameterized replaceable event and have a d tag that says "metadata"?

I was hoping to introduce more badge lists like on NIP-51 Lists: archived, awards, etc. If we make it a kind 10008 we won't be able to do this.

cameri avatar Feb 08 '23 13:02 cameri

I am not happy with this answer. This feels like introducing two ways of doing the same thing.

To clarify, I didn't write this NIP so my answer might not reflect that of the author.

Why not just define kind 10003 as meaning "profile badges" and put all badges there?

Makes sense to me.

The answer above says "the kind isn't super important". To me if it isn't important it shouldn't be defined or used.

Kind isn't an optional field, so it needs to be used.

You can't query filter by d tags unless the relay implements the generic tag query NIP, but you can fall back to a kind query to find this event.

Do you also think kind 0 events should be a parameterized replaceable event and have a d tag that says "metadata"?

Yes.

I also think setting aside arbitrary ranges for replaceable/ephemeral/parameterized replaceable was dumb, should have been tags or another field that determines that. Why should a relay hardcode that kind=0 is a replaceable event, instead of the event specifying that in can be replaced.

The person sending the event already knows if it should be replaced or not, or ephemeral or not, or if it should be replaced with pubkey + kind, or pubkey + kind + replacement key, there is no need to use ranges for this.

It wasn't dumb, Nostream recognizes these ranges and uses indexes to maintain the uniqueness of replaceable events. But yeah maybe we could have done the same without the ranges? The good thing about ranges is that the relays already support many kinds as special events without the need to make changes to the relay.

cameri avatar Feb 08 '23 13:02 cameri

I was hoping to introduce more badge lists like on NIP-51 Lists: archived, awards, etc. If we make it a kind 10008 we won't be able to do this.

With this in mind I think is worth allowing for future extensibility with kind 30008.

Also think is better to put badge data in tags intead of a JSON string in the content as @fiatjaf suggests, and image + thumbnail should be enough to display these in clients, no need to overcomplicate with lots of resolutions.

verbiricha avatar Feb 10 '23 19:02 verbiricha

May argue for the need of a time-to-live (TTL) attribute for badge events?

Here's my use case: Personhood-based sybil resitance. The Encointer protocol (as does IDENA and others) requires persons to attend regular concurrent key signing gatherings. In order to get a unique personhood proof, such a proof of attendance has to be ephemeral and reputation is only valid for 10days after which badges need renewal.

Motivation for nostr: Persons can only maintain one nostr profile with high reputation (because they can not be in more than one place at the same time of the gatherings), which can be useful for a variety of use cases

Our badges would mean sth like "has attended 4 of the past 5 Encointer personhood cycles"

brenzi avatar Feb 16 '23 20:02 brenzi

@brenzi you could just say "this person attended a meeting on day x" and then people browsing that knew what Encointer was would realize that the last meeting they attended was 5 years ago so that doesn't mean anything.

fiatjaf avatar Feb 17 '23 14:02 fiatjaf

This NIP works better if badges don't have metadata in them.

If I am issuing the same badge to a bunch of people it doesn't make sense for me to write the description and image in all these badges. And worse: as time passes I may want to change the description and images of badges I've given in the past, which is desirable.

I think this works better if I do

  • kind:30009: "define badge", an event with description, images, can be replaced to be updated
  • kind:8: "badge award", an event in which I give a badge to people, contains an a tag (see https://nips.be/33) referencing the badge
  • kind:30008: "profile badges", event users can use to decide what badges they "accept" and want to display, contains multiple a and e tags referencing the pairs of kind:8 and kind:30009 above

fiatjaf avatar Feb 17 '23 14:02 fiatjaf

@brenzi you could just say "this person attended a meeting on day x" and then people browsing that knew what Encointer was would realize that the last meeting they attended was 5 years ago so that doesn't mean anything.

Agreed, this can be solved client side. My preference would still be that the badge somehow can be marked as perishable with a TTL because the cycle period could change and clients would have to look up the lifetime of those badges dynamically, which I think is unnecessary overhead. No doubt we can find a workaround for our use case though.

brenzi avatar Feb 18 '23 18:02 brenzi

@brenzi there is a NIP for generalized event expiration already. That can be used for badges too.

fiatjaf avatar Feb 19 '23 15:02 fiatjaf

I assume there's no way to revoke an awarded badge, like with a replaceable event, since the awarding is kind:8?

The use-case I'm thinking of is badges for membership levels, like Premium Supporter, Platinum Member, etc. These can be contingent on regular payment (badge re-issued every month), or on good behavior in a community (badge issued once, but may be revoked at any point in the future if necessary).

there is a NIP for generalized event expiration already. That can be used for badges too.

General event TTL expiration wouldn't work for that, you'd have to decide in advance how long this badge will live. Even so, it's impractical because each time it's renewed (re-awarded), the recipient has to update or re-issue the kind:3008 Profile Badge event to point to the new award.

Or am I missing something? Is there a simpler, more robust way to revoke badges?

ok300 avatar May 20 '23 10:05 ok300

I assume there's no way to revoke an awarded badge, like with a replaceable event, since the awarding is kind:8?

The use-case I'm thinking of is badges for membership levels, like Premium Supporter, Platinum Member, etc. These can be contingent on regular payment (badge re-issued every month), or on good behavior in a community (badge issued once, but may be revoked at any point in the future if necessary).

there is a NIP for generalized event expiration already. That can be used for badges too.

General event TTL expiration wouldn't work for that, you'd have to decide in advance how long this badge will live. Even so, it's impractical because each time it's renewed (re-awarded), the recipient has to update or re-issue the kind:3008 Profile Badge event to point to the new award.

Or am I missing something? Is there a simpler, more robust way to revoke badges?

Deletion events. Ask clients to honor them because none of them care. (except Snort)

Semisol avatar May 20 '23 10:05 Semisol

Do not bother about expiration time, just make badges with dates in them and write in them that they are valid only for a month. Then issue a new badge every month.

fiatjaf avatar May 20 '23 11:05 fiatjaf

@ok300 If you feel this is still a problem, perhaps it's best to create a new issue to discuss since this PR is already merged.

weex avatar May 20 '23 15:05 weex