Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

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}