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