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}