Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}