cond_members_threshold.gno
1.82 Kb ยท 71 lines
1package daocond
2
3import (
4 "errors"
5 "math"
6
7 "gno.land/p/nt/ufmt"
8)
9
10type membersThresholdCond struct {
11 isMemberFn func(memberId string) bool
12 membersCountFn func() uint64
13 threshold float64
14}
15
16func MembersThreshold(threshold float64, isMemberFn func(memberId string) bool, membersCountFn func() uint64) Condition {
17 if threshold <= 0 || threshold > 1 {
18 panic(errors.New("invalid threshold"))
19 }
20 if isMemberFn == nil {
21 panic(errors.New("nil isMemberFn"))
22 }
23 if membersCountFn == nil {
24 panic(errors.New("nil membersCountFn"))
25 }
26 return &membersThresholdCond{
27 threshold: threshold,
28 isMemberFn: isMemberFn,
29 membersCountFn: membersCountFn,
30 }
31}
32
33// Eval implements Condition.
34func (c *membersThresholdCond) Eval(ballot Ballot) bool {
35 return c.yesRatio(ballot) >= c.threshold
36}
37
38// Signal implements Condition.
39func (c *membersThresholdCond) Signal(ballot Ballot) float64 {
40 return math.Min(c.yesRatio(ballot)/c.threshold, 1)
41}
42
43// Render implements Condition.
44func (c *membersThresholdCond) Render() string {
45 return ufmt.Sprintf("%g%% of members", c.threshold*100)
46}
47
48// RenderWithVotes implements Condition.
49func (c *membersThresholdCond) RenderWithVotes(ballot Ballot) string {
50 s := ""
51 s += ufmt.Sprintf("to meet the condition, %g%% of members must vote yes\n\n", c.threshold*100)
52 s += ufmt.Sprintf("Yes: %d/%d = %g%%\n\n", c.totalYes(ballot), c.membersCountFn(), c.yesRatio(ballot)*100)
53 return s
54}
55
56var _ Condition = (*membersThresholdCond)(nil)
57
58func (c *membersThresholdCond) yesRatio(ballot Ballot) float64 {
59 return float64(c.totalYes(ballot)) / float64(c.membersCountFn())
60}
61
62func (c *membersThresholdCond) totalYes(ballot Ballot) uint64 {
63 totalYes := uint64(0)
64 ballot.Iterate(func(voter string, vote Vote) bool {
65 if vote == VoteYes && c.isMemberFn(voter) {
66 totalYes += 1
67 }
68 return false
69 })
70 return totalYes
71}