Search Apps Documentation Source Content File Folder Download Copy Actions Download

proposal.gno

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