mirror of
https://github.com/nostr-protocol/nips.git
synced 2024-12-23 00:45:53 -05:00
Reinstate NIP 88
This commit is contained in:
parent
b83b0c1602
commit
802d7ab132
73
88.md
73
88.md
|
@ -6,11 +6,6 @@
|
||||||
|
|
||||||
This NIP defines the event scheme that describe Polls on nostr.
|
This NIP defines the event scheme that describe Polls on nostr.
|
||||||
|
|
||||||
The NIP makes the following tradeoffs.
|
|
||||||
|
|
||||||
1. All votes are public.
|
|
||||||
2. All votes are editable (latest response by timestamp considered last vote)
|
|
||||||
|
|
||||||
## Events
|
## Events
|
||||||
|
|
||||||
### Poll Event
|
### Poll Event
|
||||||
|
@ -24,34 +19,37 @@ Major tags in the poll event are:
|
||||||
- **option**: The option tags contain an OptionId(any alphanumeric) field, followed by an option label field.
|
- **option**: The option tags contain an OptionId(any alphanumeric) field, followed by an option label field.
|
||||||
- **relay**: One or multiple tags that the poll is expecting respondents to respond on.
|
- **relay**: One or multiple tags that the poll is expecting respondents to respond on.
|
||||||
- **polltype**: can be "singlechoice", "multiplechoice", or "rankedchoice". Polls that do not have a polltype should be considered a "singlechoice" poll.
|
- **polltype**: can be "singlechoice", "multiplechoice", or "rankedchoice". Polls that do not have a polltype should be considered a "singlechoice" poll.
|
||||||
|
- **endsAt**: signifying at which unix timestamp the poll is meant to end.
|
||||||
|
|
||||||
Example Event
|
Example Event
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"content": "",
|
"content": "Pineapple on pizza",
|
||||||
"created_at": 1719888496,
|
"created_at": 1719888496,
|
||||||
"id": "9d1b6b9562e66f2ecf35eb0a3c2decc736c47fddb13d6fb8f87185a153ea3634",
|
"id": "9d1b6b9562e66f2ecf35eb0a3c2decc736c47fddb13d6fb8f87185a153ea3634",
|
||||||
"kind": 1068,
|
"kind": 1068,
|
||||||
"pubkey": "dee45a23c4f1d93f3a2043650c5081e4ac14a778e0acbef03de3768e4f81ac7b",
|
"pubkey": "dee45a23c4f1d93f3a2043650c5081e4ac14a778e0acbef03de3768e4f81ac7b",
|
||||||
"sig": "7fa93bf3c430eaef784b0dacc217d3cd5eff1c520e7ef5d961381bc0f014dde6286618048d924808e54d1be03f2f2c2f0f8b5c9c2082a4480caf45a565ca9797",
|
"sig": "7fa93bf3c430eaef784b0dacc217d3cd5eff1c520e7ef5d961381bc0f014dde6286618048d924808e54d1be03f2f2c2f0f8b5c9c2082a4480caf45a565ca9797",
|
||||||
"tags": [
|
"tags": [
|
||||||
["label", "Pineapple on Pizza"],
|
|
||||||
["option", "qj518h583", "Yay"],
|
["option", "qj518h583", "Yay"],
|
||||||
["option", "gga6cdnqj", "Nay"],
|
["option", "gga6cdnqj", "Nay"],
|
||||||
["relay", "<relay url1>"],
|
["relay", "<relay url1>"],
|
||||||
["relay", "<relay url2>"],
|
["relay", "<relay url2>"],
|
||||||
["polltype", "singlechoice"]
|
["polltype", "singlechoice"],
|
||||||
|
["endsAt", "<unix timestamp in seconds>"]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Responses
|
### Responses
|
||||||
|
|
||||||
The response event is a `kind:30068` event. It contains a d tag with the poll event it is referencing, followed by one or more response tags.
|
The response event is a `kind:1018` event. It contains an e tag with the poll event it is referencing, followed by one or more response tags.
|
||||||
|
|
||||||
- **response** : The tag contains "response" as it's first positional argument followed by the option Id selected.
|
- **response** : The tag contains "response" as it's first positional argument followed by the option Id selected.
|
||||||
|
|
||||||
|
The responses are meant to be published to the relays specified in the poll event.
|
||||||
|
|
||||||
Example Response Event
|
Example Response Event
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
@ -63,7 +61,7 @@ Example Response Event
|
||||||
"pubkey": "1bc70a0148b3f316da33fe7e89f23e3e71ac4ff998027ec712b905cd24f6a411",
|
"pubkey": "1bc70a0148b3f316da33fe7e89f23e3e71ac4ff998027ec712b905cd24f6a411",
|
||||||
"sig": "30071a633c65db8f3a075c7a8de757fbd8ce65e3607f4ba287fe6d7fbf839a380f94ff4e826fbba593f6faaa13683b7ea9114ade140720ecf4927010ebf3e44f",
|
"sig": "30071a633c65db8f3a075c7a8de757fbd8ce65e3607f4ba287fe6d7fbf839a380f94ff4e826fbba593f6faaa13683b7ea9114ade140720ecf4927010ebf3e44f",
|
||||||
"tags": [
|
"tags": [
|
||||||
["d", "1fc80cf813f1af33d5a435862b7ef7fb96b47e68a48f1abcadf8081f5a545550"],
|
["e", "1fc80cf813f1af33d5a435862b7ef7fb96b47e68a48f1abcadf8081f5a545550"],
|
||||||
["response", "gga6cdnqj"],
|
["response", "gga6cdnqj"],
|
||||||
["response", "m3agjsdq1"]
|
["response", "m3agjsdq1"]
|
||||||
]
|
]
|
||||||
|
@ -72,17 +70,60 @@ Example Response Event
|
||||||
|
|
||||||
### Poll Types
|
### Poll Types
|
||||||
|
|
||||||
Poll Types can be configured in the settings object of the poll, the setting dictates how multiple response tags are handled in the `kind:30068` event.
|
The polltype setting dictates how multiple response tags are handled in the `kind:1018` event.
|
||||||
|
|
||||||
- **PollType: singlechoice**: The first response tag is to be considered the actual response.
|
- **polltype: singlechoice**: The first response tag is to be considered the actual response.
|
||||||
- **PollType: multiplechoice**: The first response tag pointing to each id is considered the actual response, without considering the order of the response tags.
|
- **polltype: multiplechoice**: The first response tag pointing to each id is considered the actual response, without considering the order of the response tags.
|
||||||
- **PollType: rankedchoice**: The first response tag pointing to each id is the considered the actual response, while also taking into account the order of the response tags.
|
- **polltype: rankedchoice**: The first response tag pointing to each id is the considered the actual response, while also taking into account the order of the response tags.
|
||||||
|
|
||||||
### Counting Results
|
### Counting Results
|
||||||
|
|
||||||
Results can be queried by fetching `kind:30068` events from the relays specified in the poll.
|
Results can be queried by fetching `kind:1018` events from the relays specified in the poll.
|
||||||
The results displayed should only be 1 vote event per pubkey.
|
The results displayed should only be 1 vote event per pubkey.
|
||||||
In case of multiple events for a pubkey, the event with the largest timestamp should be considered.
|
In case of multiple events for a pubkey, the event with the largest timestamp within the poll limits should be considered.
|
||||||
|
|
||||||
|
Example for querying polls.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const fetchVoteEvents = (filterPubkeys: string[]) => {
|
||||||
|
let resultFilter: Filter = {
|
||||||
|
"#e": [pollEvent.id],
|
||||||
|
kinds: [1070, 1018],
|
||||||
|
};
|
||||||
|
if (filterPubkeys?.length) {
|
||||||
|
resultFilter.authors = filterPubkeys;
|
||||||
|
}
|
||||||
|
if (pollExpiration) {
|
||||||
|
resultFilter.until = Number(pollExpiration);
|
||||||
|
}
|
||||||
|
poolRef.current.subscribeMany(relays, [resultFilter], {
|
||||||
|
onevent: handleResultEvent,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Example for maintaining OneVotePerPubkey
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const oneVotePerPubkey = (events: Event[]) => {
|
||||||
|
const eventMap = new Map<string, Event>();
|
||||||
|
|
||||||
|
events.forEach((event) => {
|
||||||
|
if (
|
||||||
|
!eventMap.has(event.pubkey) ||
|
||||||
|
event.created_at > eventMap.get(event.pubkey)!.created_at
|
||||||
|
) {
|
||||||
|
eventMap.set(event.pubkey, event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Array.from(eventMap.values());
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Relays
|
||||||
|
|
||||||
|
It is advisable for the users to use relays that do not allow back dated events i.e. events with timestamp not matching the current time, to achieve authenticity in the poll results.
|
||||||
|
|
||||||
### Curation
|
### Curation
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||||
- [NIP-75: Zap Goals](75.md)
|
- [NIP-75: Zap Goals](75.md)
|
||||||
- [NIP-78: Application-specific data](78.md)
|
- [NIP-78: Application-specific data](78.md)
|
||||||
- [NIP-84: Highlights](84.md)
|
- [NIP-84: Highlights](84.md)
|
||||||
|
- [NIP-88: Polls](88.md)
|
||||||
- [NIP-89: Recommended Application Handlers](89.md)
|
- [NIP-89: Recommended Application Handlers](89.md)
|
||||||
- [NIP-90: Data Vending Machines](90.md)
|
- [NIP-90: Data Vending Machines](90.md)
|
||||||
- [NIP-92: Media Attachments](92.md)
|
- [NIP-92: Media Attachments](92.md)
|
||||||
|
@ -118,11 +119,13 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||||
| `44` | Channel Mute User | [28](28.md) |
|
| `44` | Channel Mute User | [28](28.md) |
|
||||||
| `64` | Chess (PGN) | [64](64.md) |
|
| `64` | Chess (PGN) | [64](64.md) |
|
||||||
| `818` | Merge Requests | [54](54.md) |
|
| `818` | Merge Requests | [54](54.md) |
|
||||||
|
| `1018` | Poll Response | [88](88.md) |
|
||||||
| `1021` | Bid | [15](15.md) |
|
| `1021` | Bid | [15](15.md) |
|
||||||
| `1022` | Bid confirmation | [15](15.md) |
|
| `1022` | Bid confirmation | [15](15.md) |
|
||||||
| `1040` | OpenTimestamps | [03](03.md) |
|
| `1040` | OpenTimestamps | [03](03.md) |
|
||||||
| `1059` | Gift Wrap | [59](59.md) |
|
| `1059` | Gift Wrap | [59](59.md) |
|
||||||
| `1063` | File Metadata | [94](94.md) |
|
| `1063` | File Metadata | [94](94.md) |
|
||||||
|
| `1068` | Poll | [88](88.md) |
|
||||||
| `1311` | Live Chat Message | [53](53.md) |
|
| `1311` | Live Chat Message | [53](53.md) |
|
||||||
| `1617` | Patches | [34](34.md) |
|
| `1617` | Patches | [34](34.md) |
|
||||||
| `1621` | Issues | [34](34.md) |
|
| `1621` | Issues | [34](34.md) |
|
||||||
|
|
Loading…
Reference in New Issue
Block a user