Search Apps Documentation Source Content File Folder Download Copy Actions Download

definition.gno

3.58 Kb · 132 lines
  1package definition
  2
  3import (
  4	"errors"
  5	"strings"
  6	"time"
  7
  8	"gno.land/p/nt/commondao/v0"
  9)
 10
 11// DefaultVotingPeriod defines the default voting period for proposals.
 12const DefaultVotingPeriod = time.Hour * 24 * 7
 13
 14var (
 15	ErrBodyIsRequired  = errors.New("proposal body is required")
 16	ErrTitleIsRequired = errors.New("proposal title is required")
 17)
 18
 19var defaultVoteChoices = []commondao.VoteChoice{
 20	commondao.ChoiceYes,
 21	commondao.ChoiceNo,
 22	commondao.ChoiceAbstain,
 23}
 24
 25// TallyFunc defines a function to handle proposal votes tallying.
 26type TallyFunc func(commondao.VotingContext) (passes bool, _ error)
 27
 28// New creates a new proposal definition.
 29//
 30// By default, new definitions have a voting period of 7 days, allowing YES, NO and
 31// ABSTAIN votes, tallying those votes using an absolute majority of more than 50% of
 32// member votes, considering that a proposal passes when the majority of the votes are YES.
 33//
 34// Default definition behavior can be configured by setting custom options.
 35func New(title, body string, options ...Option) (Definition, error) {
 36	title = strings.TrimSpace(title)
 37	if title == "" {
 38		return Definition{}, ErrTitleIsRequired
 39	}
 40
 41	body = strings.TrimSpace(body)
 42	if body == "" {
 43		return Definition{}, ErrBodyIsRequired
 44	}
 45
 46	def := Definition{
 47		title:        title,
 48		body:         body,
 49		votingPeriod: DefaultVotingPeriod,
 50		voteChoices:  defaultVoteChoices,
 51		tallyCb:      TallyByAbsoluteMajority,
 52	}
 53	for _, apply := range options {
 54		apply(&def)
 55	}
 56	return def, nil
 57}
 58
 59// MustNew creates a new proposal definition or panics on error.
 60func MustNew(title, body string, options ...Option) Definition {
 61	def, err := New(title, body, options...)
 62	if err != nil {
 63		panic(err)
 64	}
 65	return def
 66}
 67
 68// Definition defines CommonDAO proposal types.
 69type Definition struct {
 70	title        string
 71	body         string
 72	votingPeriod time.Duration
 73	voteChoices  []commondao.VoteChoice
 74	tallyCb      TallyFunc
 75	validateCb   func() error
 76	executeCb    commondao.ExecFunc
 77}
 78
 79// Title returns the proposal title.
 80func (d Definition) Title() string {
 81	return d.title
 82}
 83
 84// Body returns proposal's body.
 85func (d Definition) Body() string {
 86	return d.body
 87}
 88
 89// VotingPeriod returns the period where votes are allowed after proposal creation.
 90func (d Definition) VotingPeriod() time.Duration {
 91	return d.votingPeriod
 92}
 93
 94// CustomVoteChoices returns a list of valid voting choices.
 95func (d Definition) CustomVoteChoices() []commondao.VoteChoice {
 96	return d.voteChoices
 97}
 98
 99// Tally counts the number of votes and verifies if proposal passes.
100func (d Definition) Tally(ctx commondao.VotingContext) (passes bool, _ error) {
101	return d.tallyCb(ctx)
102}
103
104// Validate validates that the proposal is valid for the current state.
105func (d Definition) Validate() error {
106	if d.validateCb != nil {
107		return d.validateCb()
108	}
109	return nil
110}
111
112// Executor returns a function to execute the proposal.
113func (d Definition) Executor() commondao.ExecFunc {
114	return d.executeCb
115}
116
117// TallyByAbsoluteMajority tallies votes by absolute majority.
118// A quorum of 51% of member votes is required to tally votes.
119// Tally considers that proposals passes when more than half of members votes YES.
120func TallyByAbsoluteMajority(ctx commondao.VotingContext) (bool, error) {
121	// Check if a quorum of 51% has been met
122	if !commondao.IsQuorumReached(commondao.QuorumMoreThanHalf, ctx.VotingRecord, ctx.Members) {
123		return false, commondao.ErrNoQuorum
124	}
125
126	// Tally votes by absolute majority, which requires 51% votes
127	c, success := commondao.SelectChoiceByAbsoluteMajority(ctx.VotingRecord, ctx.Members.Size())
128	if success {
129		return c == commondao.ChoiceYes, nil
130	}
131	return false, nil
132}