Search Apps Documentation Source Content File Folder Download Copy Actions Download

cond_role_treshold.gno

2.65 Kb ยท 81 lines
 1package daocond
 2
 3import (
 4	"errors"
 5	"math"
 6
 7	"gno.land/p/nt/ufmt"
 8)
 9
10type roleThresholdCond struct {
11	hasRoleFn        func(memberId string, role string) bool
12	usersRoleCountFn func(role string) uint32
13	threshold        float64
14	role             string
15}
16
17// Creates a condition requiring a percentage of role holders to vote yes.
18//
19// Example: RoleThreshold(0.6, "admin", hasRoleFn, countFn)
20// Requires 60% of admins.
21func RoleThreshold(threshold float64, role string, hasRoleFn func(memberId string, role string) bool, usersRoleCountFn func(role string) uint32) Condition {
22	if threshold <= 0 || threshold > 1 {
23		panic(errors.New("invalid threshold"))
24	}
25	if hasRoleFn == nil {
26		panic(errors.New("nil hasRoleFn"))
27	}
28	if usersRoleCountFn == nil {
29		panic(errors.New("nil usersRoleCountFn"))
30	}
31	return &roleThresholdCond{
32		threshold:        threshold,
33		hasRoleFn:        hasRoleFn,
34		usersRoleCountFn: usersRoleCountFn,
35		role:             role,
36	}
37}
38
39// Checks if enough role holders voted yes to meet the threshold.
40func (c *roleThresholdCond) Eval(ballot Ballot) bool {
41	return c.voteRatio(ballot, VoteYes) >= c.threshold
42}
43
44// Returns progress toward meeting the threshold between 0.0 and 1.0.
45func (c *roleThresholdCond) Signal(ballot Ballot) float64 {
46	return math.Min(c.voteRatio(ballot, VoteYes)/c.threshold, 1)
47}
48
49// Displays the condition as text.
50// Example output: "60% of admin members"
51func (c *roleThresholdCond) Render() string {
52	return ufmt.Sprintf("%g%% of %s members", c.threshold*100, c.role)
53}
54
55// Displays the condition with current vote counts.
56// Example output: "60% of admin members with role admin must vote yes\n\nYes: 1/2 = 50%"
57func (c *roleThresholdCond) RenderWithVotes(ballot Ballot) string {
58	s := ""
59	s += ufmt.Sprintf("%g%% of %s members with role %s must vote yes\n\n", c.threshold*100, c.role)
60	s += ufmt.Sprintf("Yes: %d/%d = %g%%\n\n", c.totalVote(ballot, VoteYes), c.usersRoleCountFn(c.role), c.voteRatio(ballot, VoteYes)*100)
61	s += ufmt.Sprintf("No: %d/%d = %g%%\n\n", c.totalVote(ballot, VoteNo), c.usersRoleCountFn(c.role), c.voteRatio(ballot, VoteNo)*100)
62	s += ufmt.Sprintf("Abstain: %d/%d = %g%%\n\n", c.totalVote(ballot, VoteAbstain), c.usersRoleCountFn(c.role), c.voteRatio(ballot, VoteAbstain)*100)
63	return s
64}
65
66var _ Condition = (*roleThresholdCond)(nil)
67
68func (c *roleThresholdCond) voteRatio(ballot Ballot, vote Vote) float64 {
69	return float64(c.totalVote(ballot, vote)) / float64(c.usersRoleCountFn(c.role))
70}
71
72func (c *roleThresholdCond) totalVote(ballot Ballot, vote Vote) uint32 {
73	total := uint32(0)
74	ballot.Iterate(func(voter string, v Vote) bool {
75		if v == vote && c.hasRoleFn(voter, c.role) {
76			total += 1
77		}
78		return false
79	})
80	return total
81}