Search Apps Documentation Source Content File Folder Download Copy Actions Download

cond_members_threshold.gno

2.45 Kb ยท 79 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
16// Creates a condition requiring a percentage of members to vote yes.
17//
18// Example: MembersThreshold(0.6, isMemberFn, countFn)
19// Requires 60% member approval.
20func MembersThreshold(threshold float64, isMemberFn func(memberId string) bool, membersCountFn func() uint64) Condition {
21	if threshold <= 0 || threshold > 1 {
22		panic(errors.New("invalid threshold"))
23	}
24	if isMemberFn == nil {
25		panic(errors.New("nil isMemberFn"))
26	}
27	if membersCountFn == nil {
28		panic(errors.New("nil membersCountFn"))
29	}
30	return &membersThresholdCond{
31		threshold:      threshold,
32		isMemberFn:     isMemberFn,
33		membersCountFn: membersCountFn,
34	}
35}
36
37// Checks if enough members voted yes to meet the threshold.
38func (c *membersThresholdCond) Eval(ballot Ballot) bool {
39	return c.voteRatio(ballot, VoteYes) >= c.threshold
40}
41
42// Returns progress toward meeting the threshold between 0.0 and 1.0.
43func (c *membersThresholdCond) Signal(ballot Ballot) float64 {
44	return math.Min(c.voteRatio(ballot, VoteYes)/c.threshold, 1)
45}
46
47// Displays the condition as text.
48// Example output: "60% of members"
49func (c *membersThresholdCond) Render() string {
50	return ufmt.Sprintf("%g%% of members", c.threshold*100)
51}
52
53// Displays the condition with current vote counts.
54// Example output: "60% of members must vote yes\n\nYes: 3/5 = 60%"
55func (c *membersThresholdCond) RenderWithVotes(ballot Ballot) string {
56	s := ""
57	s += ufmt.Sprintf("%g%% of members must vote yes\n\n", c.threshold*100)
58	s += ufmt.Sprintf("Yes: %d/%d = %g%%\n\n", c.totalVote(ballot, VoteYes), c.membersCountFn(), c.voteRatio(ballot, VoteYes)*100)
59	s += ufmt.Sprintf("No: %d/%d = %g%%\n\n", c.totalVote(ballot, VoteNo), c.membersCountFn(), c.voteRatio(ballot, VoteNo)*100)
60	s += ufmt.Sprintf("Abstain: %d/%d = %g%%\n\n", c.totalVote(ballot, VoteAbstain), c.membersCountFn(), c.voteRatio(ballot, VoteAbstain)*100)
61	return s
62}
63
64var _ Condition = (*membersThresholdCond)(nil)
65
66func (c *membersThresholdCond) voteRatio(ballot Ballot, vote Vote) float64 {
67	return float64(c.totalVote(ballot, vote)) / float64(c.membersCountFn())
68}
69
70func (c *membersThresholdCond) totalVote(ballot Ballot, vote Vote) uint64 {
71	total := uint64(0)
72	ballot.Iterate(func(voter string, v Vote) bool {
73		if v == vote && c.isMemberFn(voter) {
74			total += 1
75		}
76		return false
77	})
78	return total
79}