Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}