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