Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}