polls.gno
1.37 Kb · 59 lines
1// Package polls implements a single fixed-choice poll where each address
2// may cast one vote.
3package polls
4
5import (
6 "strconv"
7
8 "gno.land/p/nt/avl/v0"
9)
10
11type option struct {
12 text string
13 votes int
14}
15
16var (
17 question string
18 options []*option
19 voters avl.Tree // address string -> struct{}
20)
21
22func init() {
23 question = "What's your favorite gno.land feature?"
24 for _, text := range []string{
25 "Realms (on-chain smart contracts in Go-like Gno)",
26 "GRC20 tokens",
27 "Render() — realms rendering their own web pages",
28 "The gnokey CLI",
29 } {
30 options = append(options, &option{text: text})
31 }
32}
33
34// Vote casts a vote for the option at index i. Each address may vote once.
35// EOA-only — MsgRun callers are rejected.
36func Vote(cur realm, i int) {
37 if !cur.Previous().IsUserCall() {
38 panic("only a direct EOA call may vote")
39 }
40 if i < 0 || i >= len(options) {
41 panic("invalid option index")
42 }
43 addr := cur.Previous().Address().String()
44 if voters.Has(addr) {
45 panic("this address already voted")
46 }
47 options[i].votes++
48 voters.Set(addr, struct{}{})
49}
50
51// Render shows the poll question, options, and current vote tally.
52func Render(path string) string {
53 out := "# " + question + "\n\n"
54 for i, o := range options {
55 out += strconv.Itoa(i) + ". " + o.text + " — " + strconv.Itoa(o.votes) + " votes\n"
56 }
57 out += "\nCall Vote(i) with your option's index to vote.\n"
58 return out
59}