types.gno
4.67 Kb ยท 223 lines
1package impl
2
3import (
4 "strings"
5
6 "gno.land/p/demo/avl"
7 "gno.land/p/demo/ufmt"
8 "gno.land/r/gov/dao"
9 "gno.land/r/gov/dao/v3/memberstore"
10)
11
12type Law struct {
13 Supermajority float64
14}
15
16func (l *Law) String() string {
17 return ufmt.Sprintf("This law contains the following data:\n\n- Supermajority: %v%%", l.Supermajority)
18}
19
20// ProposalsStatuses contains the status of all the proposals indexed by the proposal ID.
21type ProposalsStatuses struct {
22 *avl.Tree // map[int]*proposalStatus
23}
24
25func NewProposalsStatuses() ProposalsStatuses {
26 return ProposalsStatuses{avl.NewTree()}
27}
28
29func (pss ProposalsStatuses) GetStatus(id dao.ProposalID) *proposalStatus {
30 pids := id.String()
31 psv, ok := pss.Get(pids)
32 if !ok {
33 return nil
34 }
35
36 ps, ok := psv.(*proposalStatus)
37 if !ok {
38 panic("ProposalsStatuses must contains only proposalStatus types")
39 }
40
41 return ps
42}
43
44type proposalStatus struct {
45 YesVotes memberstore.MembersByTier
46 NoVotes memberstore.MembersByTier
47 AllVotes memberstore.MembersByTier
48
49 Accepted bool
50 Denied bool
51
52 DeniedReason string
53
54 TiersAllowedToVote []string
55
56 TotalPower float64 // TotalPower is the power of all the members existing when this proposal was created.
57}
58
59func getMembers(cur realm) memberstore.MembersByTier {
60 return memberstore.Get()
61}
62
63func newProposalStatus(allowedToVote []string) *proposalStatus {
64 yv := memberstore.NewMembersByTier()
65 yv.SetTier(memberstore.T1)
66 yv.SetTier(memberstore.T2)
67 yv.SetTier(memberstore.T3)
68 nv := memberstore.NewMembersByTier()
69 nv.SetTier(memberstore.T1)
70 nv.SetTier(memberstore.T2)
71 nv.SetTier(memberstore.T3)
72 av := memberstore.NewMembersByTier()
73 av.SetTier(memberstore.T1)
74 av.SetTier(memberstore.T2)
75 av.SetTier(memberstore.T3)
76
77 return &proposalStatus{
78 YesVotes: yv,
79 NoVotes: nv,
80 AllVotes: av,
81
82 TiersAllowedToVote: allowedToVote,
83
84 TotalPower: getMembers(cross).GetTotalPower(),
85 }
86}
87
88func (ps *proposalStatus) YesPercent() float64 {
89 var yp float64
90
91 memberstore.Tiers.Iterate("", "", func(tn string, ti interface{}) bool {
92 tier, ok := ti.(memberstore.Tier)
93 if !ok {
94 panic("type must be memberstore.Tier")
95 }
96
97 power := tier.PowerHandler(getMembers(cross), memberstore.Tiers)
98 ts := ps.YesVotes.GetTierSize(tn)
99
100 yp = yp + (power * float64(ts))
101
102 return false
103 })
104
105 return (yp / ps.TotalPower) * 100
106}
107
108func (ps *proposalStatus) NoPercent() float64 {
109 var np float64
110
111 memberstore.Tiers.Iterate("", "", func(tn string, ti interface{}) bool {
112 tier, ok := ti.(memberstore.Tier)
113 if !ok {
114 panic("type must be memberstore.Tier")
115 }
116
117 power := tier.PowerHandler(getMembers(cross), memberstore.Tiers)
118 ts := ps.NoVotes.GetTierSize(tn)
119 np = np + (power * float64(ts))
120
121 return false
122 })
123
124 return (np / ps.TotalPower) * 100
125}
126
127func (ps *proposalStatus) IsAllowed(tier string) bool {
128 for _, ta := range ps.TiersAllowedToVote {
129 if ta == tier {
130 return true
131 }
132 }
133
134 return false
135}
136
137func (ps *proposalStatus) String() string {
138 var sb strings.Builder
139 sb.WriteString("### Proposal Status:\n\n")
140
141 if ps.Accepted {
142 sb.WriteString("- **PROPOSAL HAS BEEN ACCEPTED**\n")
143 } else if ps.Denied {
144 sb.WriteString("- **PROPOSAL HAS BEEN DENIED**\n")
145 if ps.DeniedReason != "" {
146 sb.WriteString("REASON: ")
147 sb.WriteString(ps.DeniedReason)
148 }
149 } else {
150 sb.WriteString("- **Proposal open for votes**\n")
151 }
152
153 sb.WriteString("- Allowed tiers to vote: ")
154 for _, t := range ps.TiersAllowedToVote {
155 sb.WriteString(t)
156 sb.WriteString(" ")
157 }
158 sb.WriteString("\n")
159
160 sb.WriteString(ufmt.Sprintf("- YES PERCENT: %v%%\n", ps.YesPercent()))
161 sb.WriteString(ufmt.Sprintf("- NO PERCENT: %v%%\n", ps.NoPercent()))
162
163 return sb.String()
164}
165
166func StringifyVotes(ps *proposalStatus) string {
167 var sb strings.Builder
168
169 writeVotes(&sb, ps.YesVotes, "YES")
170 writeVotes(&sb, ps.NoVotes, "NO")
171
172 if sb.String() == "" {
173 return "No one voted yet."
174 }
175
176 return sb.String()
177}
178
179func writeVotes(sb *strings.Builder, t memberstore.MembersByTier, title string) {
180 if t.Size() == 0 {
181 return
182 }
183 t.Iterate("", "", func(tn string, value interface{}) bool {
184 tier, ok := memberstore.Tiers.GetTier(tn)
185 if !ok {
186 panic("tier not found")
187 }
188
189 power := tier.PowerHandler(getMembers(cross), memberstore.Tiers)
190
191 sb.WriteString(ufmt.Sprintf("### %v from %v (VPPM %v):\n", title, tn, power))
192 ms, _ := value.(*avl.Tree)
193 ms.Iterate("", "", func(addr string, _ interface{}) bool {
194 sb.WriteString("\n")
195 sb.WriteString("- " + string(addr) + "\n")
196
197 return false
198 })
199
200 return false
201 })
202}
203
204func StringifyProposal(p *dao.Proposal) string {
205 out := ufmt.Sprintf(`
206### Title: %s
207
208### Proposed by: %s
209
210%s
211`, p.Title(), p.Author(), p.Description())
212
213 if p.ExecutorString() != "" {
214 out += ufmt.Sprintf(`
215This proposal contains the following metadata:
216
217%s
218`, p.ExecutorString())
219 }
220
221 return out
222
223}