getter.gno
10.74 Kb · 339 lines
1package governance
2
3import (
4 "errors"
5 "time"
6
7 ufmt "gno.land/p/nt/ufmt/v0"
8
9 "gno.land/r/gnoswap/gov/governance"
10)
11
12// GetLatestConfigVersion returns the current config version.
13func (gv *governanceV1) GetLatestConfigVersion() int64 {
14 return gv.getCurrentConfigVersion()
15}
16
17// GetCurrentProposalID returns the current proposal ID counter.
18func (gv *governanceV1) GetCurrentProposalID() int64 {
19 return gv.getCurrentProposalID()
20}
21
22// GetMaxSmoothingPeriod returns the maximum smoothing period for delegation history cleanup.
23func (gv *governanceV1) GetMaxSmoothingPeriod() int64 {
24 return maxSmoothingPeriod
25}
26
27// GetLatestConfig returns the latest governance configuration.
28func (gv *governanceV1) GetLatestConfig() governance.Config {
29 currentVersion := gv.getCurrentConfigVersion()
30 config, ok := gv.getConfig(currentVersion)
31 if !ok {
32 panic(errors.New(errDataNotFound))
33 }
34
35 return config
36}
37
38// GetConfig returns a specific governance configuration by version.
39func (gv *governanceV1) GetConfig(configVersion int64) (governance.Config, error) {
40 config, ok := gv.getConfig(configVersion)
41 if !ok {
42 // Construct the zero Config via the domain constructor so it is
43 // allocated inside the governance domain realm (realm allocation check).
44 return governance.NewConfig(0, 0, 0, 0, 0, 0, 0), ufmt.Errorf("config version %d not found", configVersion)
45 }
46
47 return config, nil
48}
49
50// GetProposalCount returns the total number of proposals.
51func (gv *governanceV1) GetProposalCount() int {
52 return gv.store.GetProposals().Size()
53}
54
55// GetProposalIDs returns a paginated list of proposal IDs.
56func (gv *governanceV1) GetProposalIDs(offset, count int) []int64 {
57 proposals := gv.store.GetProposals()
58 size := proposals.Size()
59
60 if offset >= size {
61 return []int64{}
62 }
63
64 end := offset + count
65 if end > size {
66 end = size
67 }
68
69 ids := make([]int64, 0, end-offset)
70 proposals.IterateByOffset(offset, end-offset, func(key string, value any) bool {
71 proposal := value.(*governance.Proposal)
72 ids = append(ids, proposal.ID())
73 return false
74 })
75
76 return ids
77}
78
79// ExistsProposal checks if a proposal exists.
80func (gv *governanceV1) ExistsProposal(proposalID int64) bool {
81 _, exists := gv.store.GetProposal(proposalID)
82 return exists
83}
84
85// GetProposal returns a proposal by ID.
86func (gv *governanceV1) GetProposal(proposalID int64) (*governance.Proposal, error) {
87 proposal, exists := gv.store.GetProposal(proposalID)
88 if !exists {
89 return nil, ufmt.Errorf("proposal %d not found", proposalID)
90 }
91 return proposal, nil
92}
93
94// GetProposerByProposalId returns the proposer address of a proposal.
95func (gv *governanceV1) GetProposerByProposalId(proposalId int64) (address, error) {
96 proposal, exists := gv.store.GetProposal(proposalId)
97 if !exists {
98 return "", ufmt.Errorf("proposal %d not found", proposalId)
99 }
100 return proposal.Proposer(), nil
101}
102
103// GetProposalTypeByProposalId returns the type of a proposal.
104func (gv *governanceV1) GetProposalTypeByProposalId(proposalId int64) (governance.ProposalType, error) {
105 proposal, exists := gv.store.GetProposal(proposalId)
106 if !exists {
107 return governance.ProposalType(0), ufmt.Errorf("proposal %d not found", proposalId)
108 }
109 return proposal.Type(), nil
110}
111
112// GetYeaByProposalId returns the yes vote weight of a proposal.
113func (gv *governanceV1) GetYeaByProposalId(proposalId int64) (int64, error) {
114 proposal, exists := gv.store.GetProposal(proposalId)
115 if !exists {
116 return 0, ufmt.Errorf("proposal %d not found", proposalId)
117 }
118 return proposal.Status().YesWeight(), nil
119}
120
121// GetNayByProposalId returns the no vote weight of a proposal.
122func (gv *governanceV1) GetNayByProposalId(proposalId int64) (int64, error) {
123 proposal, exists := gv.store.GetProposal(proposalId)
124 if !exists {
125 return 0, ufmt.Errorf("proposal %d not found", proposalId)
126 }
127 return proposal.Status().NoWeight(), nil
128}
129
130// GetConfigVersionByProposalId returns the config version used by a proposal.
131func (gv *governanceV1) GetConfigVersionByProposalId(proposalId int64) (int64, error) {
132 proposal, exists := gv.store.GetProposal(proposalId)
133 if !exists {
134 return 0, ufmt.Errorf("proposal %d not found", proposalId)
135 }
136 return proposal.ConfigVersion(), nil
137}
138
139// GetQuorumAmountByProposalId returns the quorum requirement for a proposal.
140func (gv *governanceV1) GetQuorumAmountByProposalId(proposalId int64) (int64, error) {
141 proposal, exists := gv.store.GetProposal(proposalId)
142 if !exists {
143 return 0, ufmt.Errorf("proposal %d not found", proposalId)
144 }
145 return proposal.Status().VoteStatus().QuorumAmount(), nil
146}
147
148// GetTitleByProposalId returns the title of a proposal.
149func (gv *governanceV1) GetTitleByProposalId(proposalId int64) (string, error) {
150 proposal, exists := gv.store.GetProposal(proposalId)
151 if !exists {
152 return "", ufmt.Errorf("proposal %d not found", proposalId)
153 }
154 return proposal.Metadata().Title(), nil
155}
156
157// GetDescriptionByProposalId returns the description of a proposal.
158func (gv *governanceV1) GetDescriptionByProposalId(proposalId int64) (string, error) {
159 proposal, exists := gv.store.GetProposal(proposalId)
160 if !exists {
161 return "", ufmt.Errorf("proposal %d not found", proposalId)
162 }
163 return proposal.Metadata().Description(), nil
164}
165
166// GetProposalStatusByProposalId returns the current status of a proposal.
167func (gv *governanceV1) GetProposalStatusByProposalId(proposalId int64) (string, error) {
168 proposal, exists := gv.store.GetProposal(proposalId)
169 if !exists {
170 return "", ufmt.Errorf("proposal %d not found", proposalId)
171 }
172 proposalResolver := NewProposalResolver(proposal)
173 return proposalResolver.Status(time.Now().Unix()), nil
174}
175
176// GetVoteStatus returns the vote status of a proposal.
177//
178// Returns:
179// - quorum: minimum vote weight required for proposal to pass
180// - maxVotingWeight: maximum possible voting weight
181// - yesWeight: total weight of "yes" votes
182// - noWeight: total weight of "no" votes
183func (gv *governanceV1) GetVoteStatus(proposalId int64) (quorum, maxVotingWeight, yesWeight, noWeight int64, err error) {
184 proposal, exists := gv.store.GetProposal(proposalId)
185 if !exists {
186 return 0, 0, 0, 0, ufmt.Errorf("proposal %d not found", proposalId)
187 }
188 voting := proposal.Status().VoteStatus()
189 return voting.QuorumAmount(), voting.MaxVotingWeight(), voting.YesWeight(), voting.NoWeight(), nil
190}
191
192// GetVotingInfoCount returns the number of voters for a proposal.
193func (gv *governanceV1) GetVotingInfoCount(proposalID int64) int {
194 votingInfos, exists := gv.getProposalUserVotingInfos(proposalID)
195 if !exists {
196 return 0
197 }
198 return votingInfos.Size()
199}
200
201// GetVotingInfoAddresses returns a paginated list of voter addresses for a proposal.
202func (gv *governanceV1) GetVotingInfoAddresses(proposalID int64, offset, count int) []address {
203 votingInfos, exists := gv.getProposalUserVotingInfos(proposalID)
204 if !exists {
205 return []address{}
206 }
207
208 size := votingInfos.Size()
209 if offset >= size {
210 return []address{}
211 }
212
213 end := offset + count
214 if end > size {
215 end = size
216 }
217
218 addrs := make([]address, 0, end-offset)
219 votingInfos.IterateByOffset(offset, end-offset, func(key string, value any) bool {
220 addrs = append(addrs, address(key))
221 return false
222 })
223
224 return addrs
225}
226
227// ExistsVotingInfo checks if a voting info exists for a user on a proposal.
228func (gv *governanceV1) ExistsVotingInfo(proposalID int64, addr address) bool {
229 _, exists := gv.getProposalUserVotingInfo(proposalID, addr)
230 return exists
231}
232
233// GetVotingInfo returns the voting info for a user on a proposal.
234func (gv *governanceV1) GetVotingInfo(proposalID int64, addr address) (*governance.VotingInfo, error) {
235 votingInfo, exists := gv.getProposalUserVotingInfo(proposalID, addr)
236 if !exists {
237 return nil, ufmt.Errorf("voting info not found for proposal %d and address %s", proposalID, addr.String())
238 }
239 return votingInfo, nil
240}
241
242// GetVoteWeight returns the voting weight of an address for a proposal.
243func (gv *governanceV1) GetVoteWeight(proposalID int64, addr address) (int64, error) {
244 votingInfo, exists := gv.getProposalUserVotingInfo(proposalID, addr)
245 if !exists {
246 return 0, ufmt.Errorf("voting info not found for proposal %d and address %s", proposalID, addr.String())
247 }
248 return votingInfo.VotedWeight(), nil
249}
250
251// GetVotedHeight returns the block height when an address voted on a proposal.
252func (gv *governanceV1) GetVotedHeight(proposalID int64, addr address) (int64, error) {
253 votingInfo, exists := gv.getProposalUserVotingInfo(proposalID, addr)
254 if !exists {
255 return 0, ufmt.Errorf("voting info not found for proposal %d and address %s", proposalID, addr.String())
256 }
257 return votingInfo.VotedHeight(), nil
258}
259
260// GetVotedAt returns the timestamp when an address voted on a proposal.
261func (gv *governanceV1) GetVotedAt(proposalID int64, addr address) (int64, error) {
262 votingInfo, exists := gv.getProposalUserVotingInfo(proposalID, addr)
263 if !exists {
264 return 0, ufmt.Errorf("voting info not found for proposal %d and address %s", proposalID, addr.String())
265 }
266 return votingInfo.VotedAt(), nil
267}
268
269// GetUserProposalCount returns the number of proposals created by a user.
270func (gv *governanceV1) GetUserProposalCount(user address) int {
271 proposalIDs, exists := gv.store.GetUserProposalIDs(user.String())
272 if !exists {
273 return 0
274 }
275 return len(proposalIDs)
276}
277
278// GetUserProposalIDs returns a paginated list of proposal IDs created by a user.
279func (gv *governanceV1) GetUserProposalIDs(user address, offset, count int) []int64 {
280 proposalIDs, exists := gv.store.GetUserProposalIDs(user.String())
281 if !exists {
282 return []int64{}
283 }
284
285 size := len(proposalIDs)
286 if offset >= size {
287 return []int64{}
288 }
289
290 end := offset + count
291 if end > size {
292 end = size
293 }
294
295 return proposalIDs[offset:end]
296}
297
298// GetOldestActiveProposalSnapshotTime returns the oldest snapshot time among active proposals.
299// This is used by gov/staker to prevent cleanup of delegation history that is still needed
300// by active proposals for voting weight calculation.
301func (gv *governanceV1) GetOldestActiveProposalSnapshotTime() (int64, bool) {
302 currentTime := time.Now().Unix()
303 currentProposalID := gv.getCurrentProposalID()
304
305 var (
306 oldestSnapshotTime int64
307 hasActiveProposal bool
308 )
309
310 for id := int64(1); id <= currentProposalID; id++ {
311 proposal, exists := gv.getProposal(id)
312 if !exists {
313 continue
314 }
315
316 proposalResolver := NewProposalResolver(proposal)
317
318 if proposalResolver.IsActive(currentTime) {
319 snapshotTime := proposal.SnapshotTime()
320 if !hasActiveProposal || snapshotTime < oldestSnapshotTime {
321 oldestSnapshotTime = snapshotTime
322 hasActiveProposal = true
323 }
324 }
325 }
326
327 return oldestSnapshotTime, hasActiveProposal
328}
329
330// GetCurrentVotingWeightSnapshot returns the current voting weight snapshot.
331func (gv *governanceV1) GetCurrentVotingWeightSnapshot() (int64, int64, error) {
332 current := time.Now().Unix()
333 config, ok := gv.getCurrentConfig()
334 if !ok {
335 return 0, 0, ufmt.Errorf("current config not found")
336 }
337
338 return gv.getVotingWeightSnapshot(current, config.VotingWeightSmoothingDuration)
339}