voting.gno
4.88 Kb ยท 202 lines
1package gnopendao8
2
3import (
4 "chain/runtime"
5
6 "gno.land/p/nt/commondao"
7 "gno.land/p/nt/ufmt"
8)
9
10// ProposeApproveCollection - Create a proposal to approve a new collection
11func ProposeApproveCollection(_ realm, collectionAddr address, collectionName string, reason string) uint64 {
12 caller := runtime.PreviousRealm().Address()
13
14 if !IsDAOMember(caller) {
15 panic("only DAO members can create proposals")
16 }
17
18 propDef := newCollectionProposal(PROPOSAL_TYPE_APPROVE_COLLECTION, collectionAddr, collectionName, reason)
19
20 proposal, err := marketplaceDAO.Propose(caller, propDef)
21 if err != nil {
22 panic("failed to create proposal: " + err.Error())
23 }
24
25 return proposal.ID()
26}
27
28// ProposeRemoveCollection - Create a proposal to remove a collection
29func ProposeRemoveCollection(_ realm, collectionAddr address, collectionName string, reason string) uint64 {
30 caller := runtime.PreviousRealm().Address()
31
32 if !IsDAOMember(caller) {
33 panic("only DAO members can create proposals")
34 }
35
36 propDef := newCollectionProposal(PROPOSAL_TYPE_REMOVE_COLLECTION, collectionAddr, collectionName, reason)
37
38 proposal, err := marketplaceDAO.Propose(caller, propDef)
39 if err != nil {
40 panic("failed to create proposal: " + err.Error())
41 }
42
43 return proposal.ID()
44}
45
46// ProposeUpdateFees - Create a proposal to update marketplace fees
47func ProposeUpdateFees(_ realm, newFeeBasisPoints int64, reason string) uint64 {
48 caller := runtime.PreviousRealm().Address()
49
50 if !IsDAOMember(caller) {
51 panic("only DAO members can create proposals")
52 }
53
54 if newFeeBasisPoints < 0 || newFeeBasisPoints > 1000 {
55 panic("fees must be between 0 and 1000 basis points (0-10%)")
56 }
57
58 propDef := newFeesProposal(newFeeBasisPoints, reason)
59
60 proposal, err := marketplaceDAO.Propose(caller, propDef)
61 if err != nil {
62 panic("failed to create proposal: " + err.Error())
63 }
64
65 return proposal.ID()
66}
67
68// Vote - Vote on a proposal (yes or no)
69func Vote(_ realm, proposalID uint64, choice string) string {
70 caller := runtime.PreviousRealm().Address()
71
72 if !IsDAOMember(caller) {
73 panic("only DAO members can vote")
74 }
75
76 if choice != "yes" && choice != "no" {
77 panic("choice must be 'yes' or 'no'")
78 }
79
80 proposal := marketplaceDAO.ActiveProposals().Get(proposalID)
81 if proposal == nil {
82 panic("proposal not found")
83 }
84
85 if proposal.HasVotingDeadlinePassed() {
86 panic("voting period has ended")
87 }
88
89 vote := commondao.Vote{
90 Address: caller,
91 Choice: commondao.VoteChoice(choice),
92 Reason: "",
93 Context: nil,
94 }
95
96 proposal.VotingRecord().AddVote(vote)
97
98 return "Vote recorded: " + choice
99}
100
101func TallyProposal(_ realm, proposalID uint64) string {
102 caller := runtime.PreviousRealm().Address()
103
104 if caller != daoAdmin {
105 panic("only admin can execute proposals")
106 }
107
108 err := marketplaceDAO.Execute(proposalID)
109 if err != nil {
110 panic("execution failed: " + err.Error())
111 }
112
113 return ufmt.Sprintf("Proposal %d executed successfully", proposalID)
114}
115
116// GetProposalInfo - Get information about a proposal
117func GetProposalInfo(proposalID uint64) string {
118 proposal := marketplaceDAO.ActiveProposals().Get(proposalID)
119 if proposal == nil {
120 return "Proposal not found"
121 }
122
123 yesVotes := 0
124 noVotes := 0
125
126 proposal.VotingRecord().Iterate(0, proposal.VotingRecord().Size(), false, func(v commondao.Vote) bool {
127 if string(v.Choice) == "yes" {
128 yesVotes++
129 } else if string(v.Choice) == "no" {
130 noVotes++
131 }
132 return false
133 })
134
135 output := ufmt.Sprintf(`Proposal #%d
136Title: %s
137Body: %s
138Yes Votes: %d
139No Votes: %d
140Total Votes: %d
141Voting Ended: %t`,
142 proposalID,
143 proposal.Definition().Title(),
144 proposal.Definition().Body(),
145 yesVotes,
146 noVotes,
147 yesVotes+noVotes,
148 proposal.HasVotingDeadlinePassed(),
149 )
150
151 return output
152}
153
154// GetAllActiveProposals - Get all active proposals
155func GetAllActiveProposals() string {
156 proposals := marketplaceDAO.ActiveProposals()
157
158 if proposals.Size() == 0 {
159 return "No active proposals"
160 }
161
162 output := "=== Active Proposals ===\n\n"
163
164 // Fix: use *commondao.Proposal instead of commondao.Proposal
165 proposals.Iterate(0, proposals.Size(), false, func(p *commondao.Proposal) bool {
166 output += ufmt.Sprintf("ID: %d | %s\n", p.ID(), p.Definition().Title())
167 return false
168 })
169
170 return output
171}
172
173// ProposeWithdrawTreasury - Create a proposal to withdraw funds from treasury
174func ProposeWithdrawTreasury(_ realm, amount int64, recipient address, reason string) uint64 {
175 caller := runtime.PreviousRealm().Address()
176
177 if !IsDAOMember(caller) {
178 panic("only DAO members can create proposals")
179 }
180
181 if amount <= 0 {
182 panic("amount must be positive")
183 }
184
185 if !recipient.IsValid() {
186 panic("invalid recipient address")
187 }
188
189 currentBalance := GetBalance()
190 if amount > currentBalance {
191 panic(ufmt.Sprintf("insufficient treasury balance (available: %d ugnot)", currentBalance))
192 }
193
194 propDef := NewTreasuryProposal(amount, recipient, reason)
195
196 proposal, err := marketplaceDAO.Propose(caller, propDef)
197 if err != nil {
198 panic("failed to create proposal: " + err.Error())
199 }
200
201 return proposal.ID()
202}