proposal.gno
4.40 Kb ยท 202 lines
1package gnopendao7
2
3import (
4 "time"
5 "gno.land/p/nt/commondao"
6 "gno.land/p/nt/ufmt"
7)
8
9const (
10 PROPOSAL_TYPE_APPROVE_COLLECTION = "approve_collection"
11 PROPOSAL_TYPE_REMOVE_COLLECTION = "remove_collection"
12 PROPOSAL_TYPE_UPDATE_FEES = "update_fees"
13
14 VOTING_PERIOD = 5 * time.Minute//7 * 24 * time.Hour // 7 days
15 QUORUM = 0 // 0% of members must vote
16)
17
18// CollectionProposal - Proposal to approve or remove a collection
19type CollectionProposal struct {
20 proposalType string
21 collectionAddr address
22 collectionName string
23 reason string
24 approved bool
25 executed bool
26}
27
28func newCollectionProposal(propType string, addr address, name string, reason string) *CollectionProposal {
29 return &CollectionProposal{
30 proposalType: propType,
31 collectionAddr: addr,
32 collectionName: name,
33 reason: reason,
34 approved: false,
35 executed: false,
36 }
37}
38
39func (p *CollectionProposal) Title() string {
40 if p.proposalType == PROPOSAL_TYPE_APPROVE_COLLECTION {
41 return "Approve Collection: " + p.collectionName
42 }
43 return "Remove Collection: " + p.collectionName
44}
45
46func (p *CollectionProposal) Body() string {
47 return ufmt.Sprintf(
48 "Type: %s\nCollection: %s\nAddress: %s\nReason: %s\n\nVote YES to approve, NO to reject",
49 p.proposalType,
50 p.collectionName,
51 p.collectionAddr.String(),
52 p.reason,
53 )
54}
55
56func (p *CollectionProposal) VotingPeriod() time.Duration {
57 return VOTING_PERIOD
58}
59
60func (p *CollectionProposal) Tally(
61 votes commondao.ReadonlyVotingRecord,
62 members commondao.MemberSet,
63) (bool, error) {
64 yesVotes := 0
65 noVotes := 0
66 totalVotes := 0
67
68 votes.Iterate(0, votes.Size(), false, func(v commondao.Vote) bool {
69 if string(v.Choice) == "yes" {
70 yesVotes++
71 } else if string(v.Choice) == "no" {
72 noVotes++
73 }
74 totalVotes++
75 return false
76 })
77
78 // Check quorum
79 totalMembers := members.Size()
80 quorumRequired := (totalMembers * QUORUM) / 100
81
82 if totalVotes < quorumRequired {
83 p.approved = false
84 return false, nil
85 }
86
87 // Simple majority
88 p.approved = yesVotes > noVotes
89 return p.approved, nil
90}
91
92func (p *CollectionProposal) IsApproved() bool {
93 return p.approved
94}
95
96func (p *CollectionProposal) IsExecuted() bool {
97 return p.executed
98}
99
100func (p *CollectionProposal) Execute(realm) error {
101 // Do the actual action
102 if p.proposalType == PROPOSAL_TYPE_APPROVE_COLLECTION {
103 approvedCollections.Set(p.collectionAddr.String(), true)
104 } else if p.proposalType == PROPOSAL_TYPE_REMOVE_COLLECTION {
105 approvedCollections.Remove(p.collectionAddr.String())
106 }
107
108 p.executed = true
109 return nil
110}
111
112func (p *CollectionProposal) GetCollectionAddr() address {
113 return p.collectionAddr
114}
115
116// FeesProposal - Proposal to update marketplace fees
117type FeesProposal struct {
118 newFee int64
119 reason string
120 approved bool
121 executed bool
122}
123
124func newFeesProposal(newFee int64, reason string) *FeesProposal {
125 return &FeesProposal{
126 newFee: newFee,
127 reason: reason,
128 approved: false,
129 executed: false,
130 }
131}
132
133func (p *FeesProposal) Title() string {
134 return ufmt.Sprintf("Update Marketplace Fee to %d basis points", p.newFee)
135}
136
137func (p *FeesProposal) Body() string {
138 currentFeePercent := float64(marketplaceFee) / 100.0
139 newFeePercent := float64(p.newFee) / 100.0
140
141 return ufmt.Sprintf(
142 "Current Fee: %.2f%%\nProposed Fee: %.2f%%\nReason: %s\n\nVote YES to approve, NO to reject",
143 currentFeePercent,
144 newFeePercent,
145 p.reason,
146 )
147}
148
149func (p *FeesProposal) VotingPeriod() time.Duration {
150 return VOTING_PERIOD
151}
152
153func (p *FeesProposal) Tally(
154 votes commondao.ReadonlyVotingRecord,
155 members commondao.MemberSet,
156) (bool, error) {
157 yesVotes := 0
158 noVotes := 0
159 totalVotes := 0
160
161 votes.Iterate(0, votes.Size(), false, func(v commondao.Vote) bool {
162 if string(v.Choice) == "yes" {
163 yesVotes++
164 } else if string(v.Choice) == "no" {
165 noVotes++
166 }
167 totalVotes++
168 return false
169 })
170
171 // Check quorum
172 totalMembers := members.Size()
173 quorumRequired := (totalMembers * QUORUM) / 100
174
175 if totalVotes < quorumRequired {
176 p.approved = false
177 return false, nil
178 }
179
180 // Simple majority
181 p.approved = yesVotes > noVotes
182 return p.approved, nil
183}
184
185func (p *FeesProposal) IsApproved() bool {
186 return p.approved
187}
188
189func (p *FeesProposal) IsExecuted() bool {
190 return p.executed
191}
192
193func (p *FeesProposal) Execute(realm) error {
194 // Do the actual action
195 marketplaceFee = p.newFee
196
197 p.executed = true
198 return nil
199}
200
201func (p *FeesProposal) GetNewFee() int64 {
202 return p.newFee
203}