proposal_status.gno
7.79 Kb · 252 lines
1package governance
2
3import (
4 gnsmath "gno.land/p/gnoswap/gnsmath/v1"
5
6 "gno.land/r/gnoswap/gov/governance"
7)
8
9type ProposalStatusResolver struct {
10 *governance.ProposalStatus
11 scheduleResolver *ProposalScheduleStatusResolver
12 actionStatusResolver *ProposalActionStatusResolver
13 voteStatusResolver *ProposalVoteStatusResolver
14}
15
16// NewProposalStatusResolver wraps proposal status components for lifecycle and vote queries.
17//
18// Parameters:
19// - status: proposal status containing schedule, action, and vote state
20//
21// Returns:
22// - *ProposalStatusResolver: resolver backed by status
23func NewProposalStatusResolver(status *governance.ProposalStatus) *ProposalStatusResolver {
24 return &ProposalStatusResolver{
25 ProposalStatus: status,
26 scheduleResolver: NewProposalScheduleStatusResolver(status.Schedule()),
27 actionStatusResolver: NewProposalActionStatusResolver(status.ActionStatus()),
28 voteStatusResolver: NewProposalVoteStatusResolver(status.VoteStatus()),
29 }
30}
31
32// TotalVoteWeight returns the total weight of all votes cast.
33//
34// Returns:
35// - int64: total vote weight
36func (p *ProposalStatusResolver) TotalVoteWeight() int64 {
37 return p.voteStatusResolver.TotalVoteWeight()
38}
39
40// StatusType determines the current status of the proposal based on timing, voting, and actions.
41// This is the main status calculation method that considers all factors.
42//
43// Parameters:
44// - current: current timestamp to evaluate status at
45//
46// Returns:
47// - ProposalStatusType: current status of the proposal
48func (p *ProposalStatusResolver) StatusType(current int64) governance.ProposalStatusType {
49 actionStatus := p.ActionStatus()
50
51 // Check action-based statuses first (these override time-based statuses)
52 if actionStatus.IsExecuted() {
53 return governance.StatusExecuted
54 }
55
56 if actionStatus.Canceled() {
57 return governance.StatusCanceled
58 }
59
60 // Check time-based statuses
61 if !p.scheduleResolver.IsPassedActiveAt(current) {
62 return governance.StatusUpcoming
63 }
64
65 if !p.scheduleResolver.IsPassedVotingEndedAt(current) {
66 return governance.StatusActive
67 }
68
69 // Check voting outcome after voting period ends
70 if !p.voteStatusResolver.IsPassed() {
71 return governance.StatusRejected
72 }
73
74 // For passed proposals, check execution status
75 if !p.ActionStatus().IsExecutable() || !p.scheduleResolver.IsPassedExecutableAt(current) {
76 return governance.StatusPassed
77 }
78
79 if !p.scheduleResolver.IsPassedExpiredAt(current) {
80 return governance.StatusExecutable
81 }
82
83 return governance.StatusExpired
84}
85
86// IsUpcoming checks if the proposal is in upcoming status.
87//
88// Parameters:
89// - current: timestamp to check status at
90//
91// Returns:
92// - bool: true if proposal is upcoming
93func (p *ProposalStatusResolver) IsUpcoming(current int64) bool {
94 return p.StatusType(current) == governance.StatusUpcoming
95}
96
97// IsActive checks if the proposal is in active voting status.
98//
99// Parameters:
100// - current: timestamp to check status at
101//
102// Returns:
103// - bool: true if proposal is active (voting period)
104func (p *ProposalStatusResolver) IsActive(current int64) bool {
105 return p.StatusType(current) == governance.StatusActive
106}
107
108// IsPassed checks if the proposal has passed voting.
109//
110// Parameters:
111// - current: timestamp to check status at
112//
113// Returns:
114// - bool: true if proposal has passed
115func (p *ProposalStatusResolver) IsPassed(current int64) bool {
116 return p.StatusType(current) == governance.StatusPassed
117}
118
119// IsRejected checks if the proposal has been rejected by voting.
120//
121// Parameters:
122// - current: timestamp to check status at
123//
124// Returns:
125// - bool: true if proposal was rejected
126func (p *ProposalStatusResolver) IsRejected(current int64) bool {
127 return p.StatusType(current) == governance.StatusRejected
128}
129
130// IsExecutable checks if the proposal is in executable status.
131//
132// Parameters:
133// - current: timestamp to check status at
134//
135// Returns:
136// - bool: true if proposal can be executed
137func (p *ProposalStatusResolver) IsExecutable(current int64) bool {
138 return p.StatusType(current) == governance.StatusExecutable
139}
140
141// IsExpired checks if the proposal execution window has expired.
142//
143// Parameters:
144// - current: timestamp to check status at
145//
146// Returns:
147// - bool: true if proposal has expired
148func (p *ProposalStatusResolver) IsExpired(current int64) bool {
149 return p.StatusType(current) == governance.StatusExpired
150}
151
152// IsExecuted checks if the proposal has been executed.
153//
154// Parameters:
155// - current: timestamp to check status at
156//
157// Returns:
158// - bool: true if proposal has been executed
159func (p *ProposalStatusResolver) IsExecuted(current int64) bool {
160 return p.StatusType(current) == governance.StatusExecuted
161}
162
163// IsCanceled checks if the proposal has been canceled.
164//
165// Parameters:
166// - current: timestamp to check status at
167//
168// Returns:
169// - bool: true if proposal has been canceled
170func (p *ProposalStatusResolver) IsCanceled(current int64) bool {
171 return p.StatusType(current) == governance.StatusCanceled
172}
173
174// cancel marks the proposal as canceled with the provided details.
175// This delegates to the action status for actual cancellation logic.
176//
177// Parameters:
178// - canceledAt: timestamp when proposal was canceled
179// - canceledHeight: block height when proposal was canceled
180// - canceledBy: address that canceled the proposal
181//
182// Returns:
183// - error: cancellation error if operation fails
184func (p *ProposalStatusResolver) cancel(canceledAt int64, canceledHeight int64, canceledBy address) error {
185 return p.actionStatusResolver.cancel(canceledAt, canceledHeight, canceledBy)
186}
187
188// execute marks the proposal as executed with the provided details.
189// This delegates to the action status for actual execution logic.
190//
191// Parameters:
192// - executedAt: timestamp when proposal was executed
193// - executedHeight: block height when proposal was executed
194// - executedBy: address that executed the proposal
195//
196// Returns:
197// - error: execution error if operation fails
198func (p *ProposalStatusResolver) execute(executedAt int64, executedHeight int64, executedBy address) error {
199 return p.actionStatusResolver.Execute(executedAt, executedHeight, executedBy)
200}
201
202// vote records a vote on the proposal and updates vote tallies.
203// This delegates to the vote status for actual vote recording.
204//
205// Parameters:
206// - votedYes: true for "yes" vote, false for "no" vote
207// - weight: voting weight to apply
208//
209// Returns:
210// - error: voting error if operation fails
211func (p *ProposalStatusResolver) vote(votedYes bool, weight int64) error {
212 if votedYes {
213 return p.voteStatusResolver.AddYesVoteWeight(weight)
214 }
215
216 return p.voteStatusResolver.AddNoVoteWeight(weight)
217}
218
219// NewProposalStatus creates a new proposal status with the specified configuration.
220// This initializes all status components with the governance configuration and timing.
221//
222// Parameters:
223// - config: governance configuration to use
224// - maxVotingWeight: maximum voting weight for this proposal
225// - executable: whether this proposal type can be executed
226// - createdAt: timestamp when proposal was created
227// - quorumWeight: total xGNS supply at proposal creation, used as the quorum base
228//
229// Returns:
230// - *ProposalStatus: new proposal status instance
231func NewProposalStatus(
232 config governance.Config,
233 maxVotingWeight int64,
234 executable bool,
235 createdAt int64,
236 quorumWeight int64,
237) *governance.ProposalStatus {
238 schedule := NewProposalScheduleStatus(
239 config.VotingStartDelay,
240 config.VotingPeriod,
241 config.ExecutionDelay,
242 config.ExecutionWindow,
243 createdAt,
244 )
245 actionStatus := governance.NewProposalActionStatus(executable)
246
247 // Calculate the quorum amount from the current xGNS supply, not the smoothed voting weight.
248 quorumAmount := gnsmath.SafeMulDivInt64(quorumWeight, config.Quorum, 100)
249 voteStatus := governance.NewProposalVoteStatus(maxVotingWeight, quorumAmount)
250
251 return governance.NewProposalStatusBy(schedule, actionStatus, voteStatus)
252}