types.gno

5.19 Kb ยท 227 lines
  1package dao
  2
  3import (
  4	"errors"
  5	"std"
  6
  7	"gno.land/p/demo/avl"
  8	"gno.land/p/demo/seqid"
  9	"gno.land/p/demo/ufmt"
 10)
 11
 12type ProposalID int64
 13
 14func (pid ProposalID) String() string {
 15	return ufmt.Sprintf("%v", int64(pid))
 16}
 17
 18// VoteOption is the limited voting option for a DAO proposal
 19// New govDAOs can create their own VoteOptions if needed in the
 20// future.
 21type VoteOption string
 22
 23const (
 24	AbstainVote VoteOption = "ABSTAIN" // Side is not chosen
 25	YesVote     VoteOption = "YES"     // Proposal should be accepted
 26	NoVote      VoteOption = "NO"      // Proposal should be rejected
 27)
 28
 29type VoteRequest struct {
 30	Option     VoteOption
 31	ProposalID ProposalID
 32	Metadata   interface{}
 33}
 34
 35func NewProposalRequest(title string, description string, executor Executor) ProposalRequest {
 36	return ProposalRequest{
 37		title:       title,
 38		description: description,
 39		executor:    executor,
 40	}
 41}
 42
 43func NewProposalRequestWithFilter(title string, description string, executor Executor, filter Filter) ProposalRequest {
 44	return ProposalRequest{
 45		title:       title,
 46		description: description,
 47		executor:    executor,
 48		filter:      filter,
 49	}
 50}
 51
 52type Filter interface{}
 53
 54type ProposalRequest struct {
 55	title       string
 56	description string
 57	executor    Executor
 58	filter      Filter
 59}
 60
 61func (p *ProposalRequest) Title() string {
 62	return p.title
 63}
 64
 65func (p *ProposalRequest) Description() string {
 66	return p.description
 67}
 68
 69func (p *ProposalRequest) Filter() Filter {
 70	return p.filter
 71}
 72
 73type Proposal struct {
 74	author std.Address
 75
 76	title       string
 77	description string
 78
 79	executor    Executor
 80	allowedDAOs []string
 81}
 82
 83func (p *Proposal) Author() std.Address {
 84	return p.author
 85}
 86
 87func (p *Proposal) Title() string {
 88	return p.title
 89}
 90
 91func (p *Proposal) Description() string {
 92	return p.description
 93}
 94
 95func (p *Proposal) ExecutorString() string {
 96	if p.executor != nil {
 97		return p.executor.String()
 98	}
 99
100	return ""
101}
102
103func (p *Proposal) AllowedDAOs() []string {
104	return p.allowedDAOs
105}
106
107type Proposals struct {
108	seq       seqid.ID
109	*avl.Tree // *avl.Tree[ProposalID]*Proposal
110}
111
112func NewProposals() *Proposals {
113	return &Proposals{Tree: avl.NewTree()}
114}
115
116func (ps *Proposals) SetProposal(p *Proposal) ProposalID {
117	pid := ProposalID(int64(ps.seq))
118	updated := ps.Set(pid.String(), p)
119	if updated {
120		panic("fatal error: Override proposals is not allowed")
121	}
122
123	ps.seq = ps.seq.Next()
124
125	return pid
126}
127
128func (ps *Proposals) GetProposal(pid ProposalID) *Proposal {
129	pv, ok := ps.Get(pid.String())
130	if !ok {
131		return nil
132	}
133
134	return pv.(*Proposal)
135}
136
137type Executor interface {
138	Execute() error
139	String() string
140}
141
142func NewSimpleExecutor(callback func() error, description string) *SimpleExecutor {
143	return &SimpleExecutor{
144		callback: callback,
145		desc:     description,
146	}
147}
148
149// SimpleExecutor implements the Executor interface using
150// a callback function and a description string.
151type SimpleExecutor struct {
152	callback func() error
153	desc     string
154}
155
156func (e *SimpleExecutor) Execute() error {
157	return e.callback()
158}
159
160func (e *SimpleExecutor) String() string {
161	return e.desc
162}
163
164func NewSafeExecutor(e Executor) *SafeExecutor {
165	return &SafeExecutor{
166		e: e,
167	}
168}
169
170// SafeExecutor wraps an Executor to only allow its execution
171// by allowed govDAOs.
172type SafeExecutor struct {
173	e Executor
174}
175
176func (e *SafeExecutor) Execute() error {
177	// Verify the caller is an adequate Realm
178	if !InAllowedDAOs(std.CurrentRealm().PkgPath()) {
179		return errors.New("execution only allowed by validated govDAOs")
180	}
181
182	return e.e.Execute()
183}
184
185func (e *SafeExecutor) String() string {
186	return e.e.String()
187}
188
189type DAO interface {
190	// PreCreateProposal is called just before creating a new Proposal
191	// It is intended to be used to get the std.Address of the proposal, that
192	// may vary depending on the DAO implementation, and to validate that
193	// the requester is allowed to do a proposal
194	PreCreateProposal(r ProposalRequest) (std.Address, error)
195
196	// PostCreateProposal is called after creating the Proposal. It is
197	// intended to be used as a way to store a new proposal status, that
198	// depends on the actuall govDAO implementation
199	PostCreateProposal(r ProposalRequest, pid ProposalID)
200
201	// VoteOnProposal will send a petition to vote for a specific proposal
202	// to the actual govDAO implementation
203	VoteOnProposal(r VoteRequest) error
204
205	// PreGetProposal is called when someone is trying to get a proposal by ID.
206	// Is intended to be used to validate who can query proposals, just in case
207	// the actual govDAO implementation wants to limit the access.
208	PreGetProposal(pid ProposalID) error
209
210	// PostGetProposal is called after the proposal has been obtained. Intended to be
211	// used by govDAO implementations if they need to check Proposal data to know if
212	// the caller is allowed to get that kind of Proposal or not.
213	PostGetProposal(pid ProposalID, p *Proposal) error
214
215	// PreExecuteProposal is called when someone is trying to execute a proposal by ID.
216	// Is intended to be used to validate who can trigger the proposal execution.
217	PreExecuteProposal(pid ProposalID) (bool, error)
218
219	// Render will return a human-readable string in markdown format that
220	// will be used to show new data through the dao proxy entrypoint.
221	Render(pkgpath string, path string) string
222}
223
224type UpdateRequest struct {
225	DAO         DAO
226	AllowedDAOs []string
227}