Search Apps Documentation Source Content File Folder Download Copy Actions Download

daokit.gno

3.07 Kb · 107 lines
  1package daokit
  2
  3import (
  4	"time"
  5
  6	"gno.land/p/samcrew/daocond"
  7)
  8
  9type DAO interface {
 10	// Creates a new proposal and returns its ID.
 11	Propose(req ProposalRequest) uint64
 12	// Casts a vote on a specific proposal.
 13	Vote(id uint64, vote daocond.Vote)
 14	// Executes a proposal if it meets the required conditions.
 15	// The rlm realm is threaded so action handlers can perform
 16	// cross-realm calls (e.g. editing the DAO profile).
 17	Execute(id uint64, rlm realm)
 18
 19	// Generates a web interface representation for the given path.
 20	Render(path string) string
 21
 22	// Gets an extension by path, returns nil if not found.
 23	Extension(path string) Extension
 24	// Lists all available extensions.
 25	ExtensionsList() ExtensionsList
 26}
 27
 28// Function type for updating DAO implementation during governance upgrades.
 29type SetImplemFn = func(implem DAO)
 30
 31// Creates, votes yes, and immediately executes a proposal in one operation.
 32// Useful when you have enough permission to execute an action directly.
 33// Examples: migrations, adding members
 34func InstantExecute(d DAO, req ProposalRequest, rlm realm) uint64 {
 35	id := d.Propose(req)
 36	d.Vote(id, daocond.VoteYes)
 37	d.Execute(id, rlm)
 38	return id
 39}
 40
 41// Manages the essential components of a DAO: resources, proposals, and extensions.
 42type Core struct {
 43	Resources  *ResourcesStore  // Available actions and their conditions
 44	Proposals  *ProposalsStore  // All proposals and their voting state
 45	Extensions *ExtensionsStore // Pluggable functionality modules
 46}
 47
 48// Creates a new DAO core with empty stores.
 49func NewCore() *Core {
 50	return &Core{
 51		Resources:  NewResourcesStore(),
 52		Proposals:  NewProposalsStore(),
 53		Extensions: &ExtensionsStore{},
 54	}
 55}
 56
 57// Records a vote for a specific proposal from a voter.
 58func (d *Core) Vote(voterID string, proposalID uint64, vote daocond.Vote) {
 59	proposal := d.Proposals.GetProposal(proposalID)
 60	if proposal == nil {
 61		panic("proposal not found")
 62	}
 63
 64	if proposal.Status != ProposalStatusOpen {
 65		panic("proposal is not open")
 66	}
 67
 68	proposal.Ballot.Vote(voterID, daocond.Vote(vote))
 69}
 70
 71// Executes a proposal if it meets the required voting conditions.
 72func (d *Core) Execute(proposalID uint64, rlm realm) {
 73	proposal := d.Proposals.GetProposal(proposalID)
 74	if proposal == nil {
 75		panic("proposal not found")
 76	}
 77
 78	if proposal.Status != ProposalStatusOpen {
 79		panic("proposal is not open")
 80	}
 81
 82	if !proposal.Condition.Eval(proposal.Ballot) {
 83		panic("proposal condition is not met")
 84	}
 85
 86	proposal.UpdateStatus()
 87	if proposal.Status != ProposalStatusPassed {
 88		panic("proposal does not meet the condition(s) or is already closed/executed")
 89	}
 90
 91	d.Resources.Get(proposal.Action.Type()).Handler.Execute(proposal.Action, rlm)
 92	proposal.Status = ProposalStatusExecuted
 93	proposal.ExecutedAt = time.Now()
 94}
 95
 96// Creates a new proposal for voting and returns its ID.
 97func (d *Core) Propose(proposerID string, req ProposalRequest) uint64 {
 98	actionType := req.Action.Type()
 99
100	resource := d.Resources.Get(actionType)
101	if resource == nil {
102		panic("action type is not registered as a resource")
103	}
104
105	prop := d.Proposals.newProposal(proposerID, req, resource.Condition)
106	return uint64(prop.ID)
107}