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

proposal.gno

4.60 Kb · 147 lines
  1package governance
  2
  3import (
  4	"errors"
  5	"gno.land/r/gnoswap/gov/governance"
  6)
  7
  8type ProposalResolver struct {
  9	*governance.Proposal
 10	statusResolver   *ProposalStatusResolver
 11	dataResolver     *ProposalDataResolver
 12	metadataResolver *ProposalMetadataResolver
 13}
 14
 15func NewProposalResolver(proposal *governance.Proposal) *ProposalResolver {
 16	statusResolver := NewProposalStatusResolver(proposal.Status())
 17	dataResolver := NewProposalDataResolver(proposal.Data())
 18	metadataResolver := NewProposalMetadataResolver(proposal.Metadata())
 19	return &ProposalResolver{
 20		Proposal:         proposal,
 21		statusResolver:   statusResolver,
 22		dataResolver:     dataResolver,
 23		metadataResolver: metadataResolver,
 24	}
 25}
 26
 27// VotingTotalWeight returns total weight of all votes cast.
 28func (r *ProposalResolver) VotingTotalWeight() int64 {
 29	return r.statusResolver.TotalVoteWeight()
 30}
 31
 32// IsActive determines if the proposal is currently active (can be voted on or executed).
 33// A proposal is considered active if it's not rejected, expired, executed, or canceled.
 34func (r *ProposalResolver) IsActive(current int64) bool {
 35	// Calculate status once and reuse to avoid redundant computations
 36	status := r.statusResolver.StatusType(current)
 37
 38	switch status {
 39	case governance.StatusRejected,
 40		governance.StatusExpired,
 41		governance.StatusExecuted,
 42		governance.StatusCanceled:
 43		return false
 44	case governance.StatusPassed:
 45		// Text proposals become inactive once they pass (no execution needed)
 46		return !r.IsTextType()
 47	default:
 48		// StatusUpcoming, StatusActive, StatusExecutable are considered active
 49		return true
 50	}
 51}
 52
 53// Validate performs comprehensive validation of the proposal data and metadata.
 54// This ensures all proposal components meet requirements before storage.
 55func (r *ProposalResolver) Validate() error {
 56	// Validate type-specific proposal data
 57	if err := r.dataResolver.Validate(); err != nil {
 58		return err
 59	}
 60
 61	// Validate proposal metadata (title and description)
 62	if err := r.metadataResolver.Validate(); err != nil {
 63		return err
 64	}
 65
 66	return nil
 67}
 68
 69// Status returns the current status string of the proposal at the given time.
 70func (r *ProposalResolver) Status(current int64) string {
 71	return r.statusResolver.StatusType(current).String()
 72}
 73
 74// StatusType returns the current status type of the proposal at the given time.
 75func (r *ProposalResolver) StatusType(current int64) governance.ProposalStatusType {
 76	return r.statusResolver.StatusType(current)
 77}
 78
 79// IsVotingPeriod checks if the proposal is currently in its voting period.
 80func (r *ProposalResolver) IsVotingPeriod(votedAt int64) bool {
 81	return r.StatusType(votedAt) == governance.StatusActive
 82}
 83
 84// IsExecutable determines if the proposal can be executed at the given time.
 85// Only executable proposal types that have passed voting can be executed.
 86func (r *ProposalResolver) IsExecutable(current int64) bool {
 87	// Only certain proposal types can be executed
 88	if !r.dataResolver.ProposalType().IsExecutable() {
 89		return false
 90	}
 91
 92	return r.statusResolver.IsExecutable(current)
 93}
 94
 95// CommunityPoolSpendTokenPath returns the token path for community pool spend proposals.
 96// Returns empty string for other proposal types.
 97func (r *ProposalResolver) CommunityPoolSpendTokenPath() string {
 98	if r.Data() == nil {
 99		return ""
100	}
101
102	communityPoolSpend := r.dataResolver.CommunityPoolSpend()
103	if communityPoolSpend == nil {
104		return ""
105	}
106
107	return communityPoolSpend.TokenPath()
108}
109
110// vote records a vote for this proposal and updates vote tallies.
111// This is an internal method called during voting process.
112func (r *ProposalResolver) Vote(votedYes bool, weight int64) error {
113	return r.statusResolver.vote(votedYes, weight)
114}
115
116// execute marks the proposal as executed and records execution details.
117// This method validates execution conditions before proceeding.
118func (r *ProposalResolver) execute(
119	executedAt, executedHeight int64,
120	executedBy address,
121) error {
122	// Verify proposal is in executable state
123	if !r.IsExecutable(executedAt) {
124		return errors.New(errProposalNotExecutable)
125	}
126
127	// Mark proposal as executed
128	return r.statusResolver.execute(executedAt, executedHeight, executedBy)
129}
130
131// cancel marks the proposal as canceled and records cancellation details.
132// This method validates cancellation conditions before proceeding.
133func (r *ProposalResolver) cancel(
134	canceledAt, canceledHeight int64,
135	canceledBy address,
136) error {
137	if r.statusResolver.IsCanceled(canceledAt) {
138		return errors.New(errAlreadyCanceledProposal)
139	}
140
141	if !r.statusResolver.IsUpcoming(canceledAt) {
142		return errors.New(errUnableToCancelVotingProposal)
143	}
144
145	// Mark proposal as canceled
146	return r.statusResolver.cancel(canceledAt, canceledHeight, canceledBy)
147}