basedao.gno
4.04 Kb ยท 164 lines
1package basedao
2
3import (
4 "chain"
5 "chain/runtime"
6 "errors"
7
8 "gno.land/p/nt/mux"
9 "gno.land/p/samcrew/daocond"
10 "gno.land/p/samcrew/daokit"
11)
12
13type daoPublic struct {
14 impl *DAOPrivate
15}
16
17func (d *daoPublic) Propose(req daokit.ProposalRequest) uint64 {
18 return d.impl.Propose(req)
19}
20
21func (d *daoPublic) Execute(id uint64) {
22 d.impl.Execute(id)
23}
24
25func (d *daoPublic) Vote(id uint64, vote daocond.Vote) {
26 d.impl.Vote(id, vote)
27}
28
29// DAOPrivate is meant for internal realm usage and should not be exposed
30type DAOPrivate struct {
31 Core *daokit.Core
32 Members *MembersStore
33 RenderRouter *mux.Router
34 GetProfileString ProfileStringGetter
35 Realm runtime.Realm
36}
37
38type Config struct {
39 Name string
40 Description string
41 ImageURI string
42 Members *MembersStore
43 NoDefaultHandlers bool
44 NoDefaultRendering bool
45 InitialCondition daocond.Condition
46 SetProfileString ProfileStringSetter
47 GetProfileString ProfileStringGetter
48 NoCreationEvent bool
49}
50
51type ProfileStringSetter func(cur realm, field string, value string) bool
52type ProfileStringGetter func(addr address, field string, def string) string
53
54const EventBaseDAOCreated = "BaseDAOCreated"
55
56func New(conf *Config) (daokit.DAO, *DAOPrivate) {
57 // XXX: emit events from memberstore
58
59 members := conf.Members
60 if members == nil {
61 members = NewMembersStore(nil, nil)
62 }
63
64 if conf.GetProfileString == nil {
65 panic(errors.New("GetProfileString is required"))
66 }
67
68 core := daokit.NewCore()
69 dao := &DAOPrivate{
70 Core: core,
71 Members: members,
72 GetProfileString: conf.GetProfileString,
73 Realm: runtime.CurrentRealm(),
74 }
75 dao.initRenderingRouter()
76
77 if !conf.NoDefaultRendering {
78 dao.InitDefaultRendering()
79 }
80
81 if conf.SetProfileString != nil {
82 conf.SetProfileString(cross, "DisplayName", conf.Name)
83 conf.SetProfileString(cross, "Bio", conf.Description)
84 conf.SetProfileString(cross, "Avatar", conf.ImageURI)
85 }
86
87 if !conf.NoDefaultHandlers {
88 if conf.InitialCondition == nil {
89 conf.InitialCondition = daocond.MembersThreshold(0.6, members.IsMember, members.MembersCount)
90 }
91
92 if conf.SetProfileString != nil {
93 dao.Core.Resources.Set(&daokit.Resource{
94 Handler: NewEditProfileHandler(conf.SetProfileString, []string{"DisplayName", "Bio", "Avatar"}),
95 Condition: conf.InitialCondition,
96 })
97 }
98
99 defaultResources := []daokit.Resource{
100 {
101 Handler: NewAddMemberHandler(dao),
102 Condition: conf.InitialCondition,
103 DisplayName: "Add Member",
104 Description: "This proposal allows you to add a new member to the DAO.",
105 },
106 {
107 Handler: NewRemoveMemberHandler(dao),
108 Condition: conf.InitialCondition,
109 DisplayName: "Remove Member",
110 Description: "This proposal allows you to remove a member from the DAO.",
111 },
112 {
113 Handler: NewAssignRoleHandler(dao),
114 Condition: conf.InitialCondition,
115 DisplayName: "Assign Role",
116 Description: "This proposal allows you to assign a role to a member.",
117 },
118 {
119 Handler: NewUnassignRoleHandler(dao),
120 Condition: conf.InitialCondition,
121 DisplayName: "Unassign Role",
122 Description: "This proposal allows you to unassign a role from a member.",
123 },
124 }
125 // register management handlers
126 for _, resource := range defaultResources {
127 dao.Core.Resources.Set(&resource)
128 }
129
130 }
131
132 if !conf.NoCreationEvent {
133 chain.Emit(EventBaseDAOCreated)
134 }
135
136 return &daoPublic{impl: dao}, dao
137}
138
139func (d *DAOPrivate) Vote(proposalID uint64, vote daocond.Vote) {
140 if len(vote) > 16 {
141 panic("invalid vote")
142 }
143
144 voterID := d.assertCallerIsMember()
145 d.Core.Vote(voterID, proposalID, vote)
146}
147
148func (d *DAOPrivate) Execute(proposalID uint64) {
149 _ = d.assertCallerIsMember()
150 d.Core.Execute(proposalID)
151}
152
153func (d *DAOPrivate) Propose(req daokit.ProposalRequest) uint64 {
154 proposerID := d.assertCallerIsMember()
155 return d.Core.Propose(proposerID, req)
156}
157
158func (d *DAOPrivate) assertCallerIsMember() string {
159 id := runtime.PreviousRealm().Address().String()
160 if !d.Members.IsMember(id) {
161 panic(errors.New("caller is not a member"))
162 }
163 return id
164}