Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}