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}