Search Apps Documentation Source Content File Folder Download Copy Actions Download

types.gno

4.67 Kb ยท 222 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	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("### Stats\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 is open for votes**\n")
151	}
152
153	sb.WriteString("- Tiers eligible to vote: ")
154	sb.WriteString(strings.Join(ps.TiersAllowedToVote, ", "))
155	sb.WriteString("\n")
156
157	sb.WriteString(ufmt.Sprintf("- YES PERCENT: %v%%\n", ps.YesPercent()))
158	sb.WriteString(ufmt.Sprintf("- NO PERCENT: %v%%\n", ps.NoPercent()))
159
160	return sb.String()
161}
162
163func StringifyVotes(ps *proposalStatus) string {
164	var sb strings.Builder
165
166	writeVotes(&sb, ps.YesVotes, "YES")
167	writeVotes(&sb, ps.NoVotes, "NO")
168
169	if sb.String() == "" {
170		return "No one voted yet."
171	}
172
173	return sb.String()
174}
175
176func writeVotes(sb *strings.Builder, t memberstore.MembersByTier, title string) {
177	if t.Size() == 0 {
178		return
179	}
180	t.Iterate("", "", func(tn string, value interface{}) bool {
181		tier, ok := memberstore.Tiers.GetTier(tn)
182		if !ok {
183			panic("tier not found")
184		}
185
186		power := tier.PowerHandler(getMembers(cross), memberstore.Tiers)
187
188		sb.WriteString(ufmt.Sprintf("%v from %v (VPPM %v):\n\n", title, tn, power))
189		ms, _ := value.(*avl.Tree)
190		ms.Iterate("", "", func(addr string, _ interface{}) bool {
191			sb.WriteString("\n")
192			sb.WriteString("- " + tryResolveAddr(address(addr)) + "\n")
193
194			return false
195		})
196
197		sb.WriteString("\n")
198
199		return false
200	})
201}
202
203func StringifyProposal(p *dao.Proposal) string {
204	out := ufmt.Sprintf(`
205### Title: %s
206
207### Proposed by: %s
208
209%s
210`, p.Title(), p.Author(), p.Description())
211
212	if p.ExecutorString() != "" {
213		out += ufmt.Sprintf(`
214This proposal contains the following metadata:
215
216%s	
217`, p.ExecutorString())
218	}
219
220	return out
221
222}