Search Apps Documentation Source Content File Folder Download Copy Actions Download

proposal_subdao.gno

4.13 Kb · 164 lines
  1package commondao
  2
  3import (
  4	"errors"
  5	"strings"
  6	"time"
  7
  8	"gno.land/p/moul/addrset"
  9	"gno.land/p/moul/md"
 10	"gno.land/p/nt/commondao/v0"
 11)
 12
 13// newSubDAOPropDefinition creates a new proposal definition for adding a SubDAO.
 14func newSubDAOPropDefinition(parent *commondao.CommonDAO, name string, members *addrset.Set) subDAOPropDefinition {
 15	if parent == nil {
 16		panic("parent DAO is required")
 17	}
 18
 19	name = strings.TrimSpace(name)
 20	assertDAONameIsValid(name)
 21
 22	return subDAOPropDefinition{
 23		parent:  parent,
 24		name:    name,
 25		members: members,
 26	}
 27}
 28
 29// subDAOPropDefinition defines a proposal type for adding a SubDAO.
 30type subDAOPropDefinition struct {
 31	parent  *commondao.CommonDAO
 32	name    string
 33	members *addrset.Set
 34}
 35
 36func (p subDAOPropDefinition) Title() string             { return "New SubDAO: " + p.name }
 37func (subDAOPropDefinition) VotingPeriod() time.Duration { return time.Hour * 24 * 7 }
 38
 39func (p subDAOPropDefinition) Body() string {
 40	var b strings.Builder
 41
 42	b.WriteString(md.Paragraph(
 43		md.Bold("Parent DAO:") + "\n" + md.Link(p.parent.Name(), daoURL(p.parent.ID())),
 44	))
 45
 46	b.WriteString(md.Paragraph(
 47		md.Bold("SubDAO Name:") + "\n" + p.name,
 48	))
 49
 50	if p.members != nil && p.members.Size() > 0 {
 51		items := make([]string, 0, p.members.Size())
 52		p.members.IterateByOffset(0, p.members.Size(), func(addr address) bool {
 53			items = append(items, addr.String())
 54			return false
 55		})
 56
 57		b.WriteString(md.Paragraph(
 58			md.Bold("Members:") + "\n" + md.BulletList(items),
 59		))
 60	}
 61
 62	return b.String()
 63}
 64
 65func (p subDAOPropDefinition) Validate() (err error) {
 66	options := getOptions(p.parent.ID())
 67	if !(options.AllowSubDAOProposals && options.AllowChildren) {
 68		return errors.New("SubDAO support is not enabled")
 69	}
 70
 71	p.parent.Children().ForEach(func(_ int, v any) bool {
 72		subDAO := v.(*commondao.CommonDAO)
 73		if subDAO.Name() == p.name {
 74			err = errors.New("a SubDAO with the same name already exists")
 75			return true
 76		}
 77		return false
 78	})
 79	return err
 80}
 81
 82func (subDAOPropDefinition) Tally(ctx commondao.VotingContext) (bool, error) {
 83	if !commondao.IsQuorumReached(commondao.QuorumFull, ctx.VotingRecord, ctx.Members) {
 84		return false, commondao.ErrNoQuorum
 85	}
 86
 87	c, success := commondao.SelectChoiceBySuperMajority(ctx.VotingRecord, ctx.Members.Size())
 88	if success {
 89		return c == commondao.ChoiceYes, nil
 90	}
 91	return false, nil
 92}
 93
 94func (p subDAOPropDefinition) Executor() commondao.ExecFunc {
 95	return p.execute
 96}
 97
 98func (p subDAOPropDefinition) execute(realm) error {
 99	subDAO := createSubDAO(p.parent, p.name, nil)
100
101	if p.members != nil {
102		p.members.IterateByOffset(0, p.members.Size(), func(addr address) bool {
103			subDAO.Members().Add(addr)
104			return false
105		})
106	}
107
108	p.parent.Children().Append(subDAO)
109	return nil
110}
111
112// newDissolvePropDefinition creates a new proposal definition for dissolving a SubDAO.
113func newDissolvePropDefinition(dao *commondao.CommonDAO) dissolvePropDefinition {
114	if dao == nil {
115		panic("SubDAO is required")
116	}
117
118	return dissolvePropDefinition{dao}
119}
120
121// dissolvePropDefinition defines a proposal type for dissolving a SubDAO.
122type dissolvePropDefinition struct {
123	dao *commondao.CommonDAO
124}
125
126func (p dissolvePropDefinition) Title() string             { return "Dissolve DAO: " + p.dao.Name() }
127func (dissolvePropDefinition) VotingPeriod() time.Duration { return time.Hour * 24 * 7 }
128
129func (p dissolvePropDefinition) Body() string {
130	var b strings.Builder
131
132	b.WriteString(md.Bold("DAO:") + "\n")
133	b.WriteString(md.Link(p.dao.Name(), daoURL(p.dao.ID())))
134
135	return b.String()
136}
137
138func (p dissolvePropDefinition) Validate() (err error) {
139	if p.dao.IsDeleted() {
140		return errors.New("DAO has been already dissolveed")
141	}
142	return nil
143}
144
145func (dissolvePropDefinition) Tally(ctx commondao.VotingContext) (bool, error) {
146	if !commondao.IsQuorumReached(commondao.QuorumFull, ctx.VotingRecord, ctx.Members) {
147		return false, commondao.ErrNoQuorum
148	}
149
150	c, success := commondao.SelectChoiceBySuperMajority(ctx.VotingRecord, ctx.Members.Size())
151	if success {
152		return c == commondao.ChoiceYes, nil
153	}
154	return false, nil
155}
156
157func (p dissolvePropDefinition) Executor() commondao.ExecFunc {
158	return p.execute
159}
160
161func (p dissolvePropDefinition) execute(realm) error {
162	p.dao.SetDeleted(true)
163	return nil
164}