Search Apps Documentation Source Content File Folder Download Copy Actions Download

types.gno

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