8.3 KiB
Poll event
draft
optional
author:toadlyBroodle
A poll note is a nostr event (kind 6969
) for conducting paid polls. A poll presents two or more voting options, which participants my vote on by sending regular zap events which include an additional poll_option
vote tag. Polls may include multiple recipients which participants may choose from when zapping their votes. Poll results should be blinded, until after users have voted. Polls should specify a closed_at
time, after which results be unblinded, closed to new votes, and the tally considered final. Polls may specify either value_maximum
or value_minimum
satoshi valuations for determining which zaps are included in the tally. Polls may also specify a consensus_threshold
for assessing the state of consensus.
Purpose
The purpose of poll notes is to conduct quantitative public opinion polls over nostr by requiring voters pay to participate. By tying results to real satoshi valuations, nostr polls intend to provide superior signal compared to other free polling models. Imposing real monetary costs for participation should also discourage undesired attempts to sway results.
Pollers may specify multiple p
keys, to allow participants to choose which recipient they zap, regardless of their vote choice. The option for such distribution of funds should also incentivize participation by increasing voter optionality, poller authenticity, and legitimacy of results by mitigating certain unauthentic attack vectors.
By including a value_maximum
limit, polls can stop single 'whale' votes discounting many smaller 'shrimp' votes. Likewise, by including a value_minimum
limit, polls can make automated low-value vote flooding attacks prohibitively expensive. However, both limits remain optional to allow for freedom in poll design.
By setting value_maximum
and value_minimum
equal, a more traditional style poll may be designed, which weights each vote equal and limits each participant to a single vote.
The optional consensus_threshold
is intended as a simple 'measuring bar', defined as the minimum percentage for any single poll_option
's percentage of the total tally to attain poll consensus status.
A careful balancing of all poll attributes should enable pollers to conduct tailored polls that deliver meaningful and valuable outcomes.
Poll format
A poll event:
- MUST specify an
e
tag that includes a primary hosting relay URL - MUST specify 1 or more
p
tags, each including the same primary hosting relay specified in thee
tag - MUST contain a primary description string, specified in the
content
field - MUST contain at least 2
poll_option
tags, each specifying an index and a unique description string, formatted as below - SHOULD specify a
closed_at
time:- when specified, MUST include a valid
ots
tag, proving original poll publishing time - a
closed_at
value of null or less than or equal to thecreated_at
field indicates a poll SHOULD NOT be closed.
- when specified, MUST include a valid
- MAY specify a
value_maximum
satoshi value for zapped votes to be included in the tally - MAY specify a
value_minimum
satoshi value for zapped votes to be included in the tallyvalue_minimum
MUST be less than or equal tovalue_maximum
, when both are specified
- MAY include a
consensus_threshold
(0-100), representing a percentage threshold for any single vote option to achieve poll consensus- a
consensus_threshold
of '0' indicates no threshold is specified.
- a
{
"id": <32-bytes lowercase hex-encoded sha256 of the serialized event data>
"pubkey": <32-bytes lowercase hex-encoded public key of the event creator>,
"created_at": <unix timestamp in seconds>,
"kind": 6969,
"tags": [
["e", <32-bytes hex of the id of the poll event>, <primary poll host relay URL>],
["p", <32-bytes hex of the key>, <primary poll host relay URL>],
["poll_option", "0", "poll option 0 description string"],
["poll_option", "1", "poll option 1 description string"],
["poll_option", "n", "poll option <n> description string"],
["value_maximum", "maximum satoshi value for inclusion in tally"],
["value_minimum", "minimum satoshi value for inclusion in tally"],
["consensus_threshold", "required percentage to attain consensus <0..100>"],
["closed_at", "unix timestamp in seconds"],
],
"ots": <base64-encoded OTS file data>
"content": <primary poll description string>,
"sig": <64-bytes hex of the signature of the sha256 hash of the serialized event data, which is the same as the "id" field>
}
Zap voting
Poll options are voted on by sending zap events (referencing the original poll event's e
and p
values) that indicate their chosen vote option in a poll_option
tag. To ensure all eligible votes are included in the tally, all e
and p
tags must specify the same primary hosting relay.
A voting client:
- SHOULD NOT allow submission of zap events with amounts greater than
value_maximum
(when specified) - SHOULD NOT allow submission of zap events with amounts less than
value_minimum
(when specified) - SHOULD NOT allow submission of zap events after
closed_at
time (when specified) - SHOULD hide tally results, until after a user has zapped the note
Zap vote format
The zap request event (kind 9734
):
- MUST specify an
e
tag that references the original poll event- MUST include a primary hosting relay URL in the
e
tag
- MUST include a primary hosting relay URL in the
- MUST include at least 1
p
tag specifying the recipient's key, chosen from the original poll event's list of keys- MUST include the same primary hosting relay URL in all
p
tags as is specified in thee
tag
- MUST include the same primary hosting relay URL in all
- MUST include exactly 1
poll_option
tag which references the chosen vote option by its corresponding indexn
- MUST include a valid
ots
tag, if the original poll event specifies aclosed_at
time
...
"tags": [
["e", <32-bytes hex of the id of the original poll event>, <primary poll host relay URL>],
["p", <32-bytes hex of the recipient's key>, <primary poll host relay URL>],
["poll_option", "n"],
...
],
"ots": <base64-encoded OTS file data>
...
Poll outcome
Polls results are tallied by summing the exact satoshi values from all eligible zaps for each poll_option
. The total tally is the sum of all individual poll_option
tallies, and poll_option
results are calculated by their percentage of the total tally value.
To avoid ambiguity of results, strict adherence to the following rules is vital when tallying and rendering poll outcomes.
A tallying client:
- MUST ONLY include full satoshi value amounts in option tallies from ALL eligible zaps that meet ALL following criteria:
- MUST ONLY tally zaps that reference the original poll event by its
e
tag value - MUST ONLY tally zaps sent to a
p
key specified in the original poll event - MUST ONLY include zap amounts less than or equal to
value_maximum
, if specified - MUST ONLY include zap amounts greater than or equal to
value_minimum
, if specified - if both
value_maximum
andvalue_minimum
are specified AND are equal:- MUST ONLY count 1 zap (the most recent) per participant (to allow for changes to vote choice, while enforcing 1 vote per participant)
- if a
closed_at
time is specified, clients:- MUST ONLY tally zaps including a valid
ots
tag indicating a sent time greater than or equal to the original poll event'sots
time - MUST ONLY tally zaps including a valid
ots
tag indicating a sent time less than or equal toclosed_at
time
- MUST ONLY tally zaps including a valid
Additionally, a tallying client:
- MUST display the distribution percentages, from the tally total, for each vote option tally
- MUST display the
consensus_threshold
(if specified) relative to the winning vote percentage - SHOULD show tally results to all note zappers, even if they haven't voted on an option
- SHOULD publicly show results after the
closed_at
time has passed (if specified) - MAY display the counts of zap events received for each option, along with other poll statistics
Strict adherence to these requirements should enable a standardized means of quantitatively assessing the distribution of opinion regarding a poll's content amongst poll participants, determining a winning outcome, and possibly achieving consensus. However, until this protocol is further tested, refined, and proven robust, polls should probably not be considered authoritative nor binding.
TODO
- refine NIP#69 based RFC feedback
- implement polls in 2 clients
- merge with nostr-protocol/NIPs