Search Apps Documentation Source Content File Folder Download Copy Actions Download

cond_role_treshold.gno

1.97 Kb ยท 73 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
17func RoleThreshold(threshold float64, role string, hasRoleFn func(memberId string, role string) bool, usersRoleCountFn func(role string) uint32) Condition {
18	if threshold <= 0 || threshold > 1 {
19		panic(errors.New("invalid threshold"))
20	}
21	if hasRoleFn == nil {
22		panic(errors.New("nil hasRoleFn"))
23	}
24	if usersRoleCountFn == nil {
25		panic(errors.New("nil usersRoleCountFn"))
26	}
27	return &roleThresholdCond{
28		threshold:        threshold,
29		hasRoleFn:        hasRoleFn,
30		usersRoleCountFn: usersRoleCountFn,
31		role:             role,
32	}
33}
34
35// Eval implements Condition.
36func (c *roleThresholdCond) Eval(ballot Ballot) bool {
37	return c.yesRatio(ballot) >= c.threshold
38}
39
40// Signal implements Condition.
41func (c *roleThresholdCond) Signal(ballot Ballot) float64 {
42	return math.Min(c.yesRatio(ballot)/c.threshold, 1)
43}
44
45// Render implements Condition.
46func (c *roleThresholdCond) Render() string {
47	return ufmt.Sprintf("%g%% of %s members", c.threshold*100, c.role)
48}
49
50// RenderWithVotes implements Condition.
51func (c *roleThresholdCond) RenderWithVotes(ballot Ballot) string {
52	s := ""
53	s += ufmt.Sprintf("To meet the condition, %g%% of %s members with role %s must vote yes\n\n", c.threshold*100, c.role)
54	s += ufmt.Sprintf("Yes: %d/%d = %g%%\n\n", c.totalYes(ballot), c.usersRoleCountFn(c.role), c.yesRatio(ballot)*100)
55	return s
56}
57
58var _ Condition = (*roleThresholdCond)(nil)
59
60func (c *roleThresholdCond) yesRatio(ballot Ballot) float64 {
61	return float64(c.totalYes(ballot)) / float64(c.usersRoleCountFn(c.role))
62}
63
64func (c *roleThresholdCond) totalYes(ballot Ballot) uint32 {
65	totalYes := uint32(0)
66	ballot.Iterate(func(voter string, vote Vote) bool {
67		if vote == VoteYes && c.hasRoleFn(voter, c.role) {
68			totalYes += 1
69		}
70		return false
71	})
72	return totalYes
73}