Search Apps Documentation Source Content File Folder Download Copy Actions Download

types.gno

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