PathrockNetwork Gno Explorer
HomeBlocksTransactionsRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/r/gov/dao

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
dao
Namespace
gov
Files
5 (gnomod.toml)
Exported functions
21
Module
gno.land/r/gov/dao
gno
0.9

Files (5)

  • gnomod.tomltoml
  • proxy.gnogno
  • types.gnogno
  • allowlist_test.gnogno
  • proxy_test.gnogno
proxy.gnogno
1package dao23import (4	"chain"5	"errors"6	"strconv"7	"strings"89	"gno.land/p/nt/ufmt/v0"10)1112// dao is the actual govDAO implementation, having all the needed business logic13var dao DAO1415// allowedDAOs contains realms that can be used to update the actual govDAO implementation,16// and validate Proposals.17// This is like that to be able to rollback using a previous govDAO implementation in case18// the latest implementation has a breaking bug. After a test period, a proposal can be19// executed to remove all previous govDAOs implementations and leave the last one.20var allowedDAOs []string2122// proposals contains all the proposals in history.23var proposals *Proposals = NewProposals()2425// Render calls directly to Render's DAO implementation.26// This allows to have this realm as the main entry point for everything.27func Render(cur realm, p string) string {28	if dao == nil {29		return "DAO not initialized"30	}31	return dao.Render(cross(cur), cur.PkgPath(), p)32}3334// MustCreateProposal is an utility method that does the same as CreateProposal,35// but instead of erroing if something happens, it panics.36func MustCreateProposal(cur realm, r ProposalRequest) ProposalID {37	pid, err := CreateProposal(cur, r)38	if err != nil {39		panic(err.Error())40	}4142	return pid43}4445// ExecuteProposal will try to execute the proposal with the provided ProposalID.46// If the proposal was denied, it will return false. If the proposal is correctly47// executed, it will return true. If something happens this function will panic.48func ExecuteProposal(cur realm, pid ProposalID) bool {49	return executeProposal(cur, pid, false)50}5152// ExecuteOrRejectProposal executes the proposal with the provided ProposalID or rejects53// it when there is an execution error.54// If the proposal was denied, it will return false. If the proposal is correctly55// executed, it will return true, unless execution fails with an error, in which case56// proposal is rejected with the error as the reason.57// This function allows to finish proposals by rejecting them when there is a state58// change or an error in the proposal parameters that makes execution fail, potentially59// leaving the proposal active forever because it can't be successfully executed.60func ExecuteOrRejectProposal(cur realm, pid ProposalID) bool {61	return executeProposal(cur, pid, true)62}6364// CreateProposal will try to create a new proposal, that will be validated by the actual65// govDAO implementation. If the proposal cannot be created, an error will be returned.66func CreateProposal(cur realm, r ProposalRequest) (ProposalID, error) {67	if dao == nil {68		return -1, errors.New("DAO not initialized")69	}70	author, err := dao.PreCreateProposal(0, cur, r)71	if err != nil {72		return -1, err73	}7475	p := &Proposal{76		author:      author,77		title:       r.title,78		description: r.description,79		executor:    r.executor,80		allowedDAOs: allowedDAOs[:],81	}8283	pid := proposals.SetProposal(p)84	dao.PostCreateProposal(0, cur, r, pid)8586	chain.Emit("ProposalCreated",87		"id", strconv.FormatInt(int64(pid), 10),88	)8990	return pid, nil91}9293func MustVoteOnProposal(cur realm, r VoteRequest) {94	if err := VoteOnProposal(cur, r); err != nil {95		panic(err.Error())96	}97}9899// VoteOnProposal sends a vote to the actual govDAO implementation.100// If the voter cannot vote the specified proposal, this method will return an error101// with the explanation of why.102func VoteOnProposal(cur realm, r VoteRequest) error {103	if dao == nil {104		return errors.New("DAO not initialized")105	}106	return dao.VoteOnProposal(0, cur, r)107}108109// MustVoteOnProposalSimple is like MustVoteOnProposal but intended to be used through gnokey with basic types.110func MustVoteOnProposalSimple(cur realm, pid int64, option string) {111	MustVoteOnProposal(cur, VoteRequest{112		Option:     VoteOption(option),113		ProposalID: ProposalID(pid),114	})115}116117func MustGetProposal(pid ProposalID) *Proposal {118	p, err := GetProposal(pid)119	if err != nil {120		panic(err.Error())121	}122123	return p124}125126// GetProposal gets created proposal by its ID. Non-crossing pure read:127// looks up the proposal in this realm's package var. Callable directly128// from any realm without cross-call syntax.129func GetProposal(pid ProposalID) (*Proposal, error) {130	if dao == nil {131		return nil, errors.New("DAO not initialized")132	}133	prop := proposals.GetProposal(pid)134	if prop == nil {135		return nil, errors.New(ufmt.Sprintf("Proposal %v does not exist.", int64(pid)))136	}137	return prop, nil138}139140// UpdateImpl is a method intended to be used on a proposal.141// This method will update the current govDAO implementation142// to a new one. AllowedDAOs are a list of realms that can143// call this method, in case the new DAO implementation had144// a breaking bug. A nil DAO is ignored.145// If AllowedDAOs field is not set correctly, the actual DAO146// implementation wont be able to execute new Proposals!147//148// An empty AllowedDAOs is ignored rather than stored. An empty list makes149// InAllowedDAOs() return true for every caller — the bootstrap-only state that150// lets the genesis MsgRun seed the member set. Since this is the only site that151// assigns allowedDAOs, ignoring empty here makes the transition152// empty -> non-empty one-way: once locked down the DAO cannot be reopened,153// whether the empty value arrives as a literal []string{} or from154// NewUpdateRequest(d, nil), which copies nil into a non-nil empty slice.155// Individual entries must be non-blank realm paths; an empty entry would match156// a user realm's empty PkgPath() and is rejected.157func UpdateImpl(cur realm, r UpdateRequest) {158	// AGENTS.md: in a crossing function, always check IsCurrent() before159	// deriving caller identity from cur.Previous(). Redundant under the160	// crossing-frame guarantee, but mandated, and this is the single most161	// powerful entrypoint (it rewrites the allowlist and swaps the impl).162	if !cur.IsCurrent() {163		panic("UpdateImpl: realm value is not the caller's live cur")164	}165	gRealm := cur.Previous().PkgPath()166167	if !InAllowedDAOs(gRealm) {168		panic("permission denied for prev realm: " + gRealm)169	}170171	if len(r.AllowedDAOs) != 0 {172		// Every entry must be a real realm path. len() != 0 alone is the wrong173		// invariant: InAllowedDAOs compares by exact string, and a user realm's174		// PkgPath() is "", so a single "" entry admits any caller whose previous175		// frame is a user realm -- the same fail-open outcome this guard exists176		// to prevent, just spelled differently. An empty entry can only be a177		// drafting mistake, so reject the whole request rather than silently178		// dropping it and storing a list the proposal did not describe.179		for i, d := range r.AllowedDAOs {180			trimmed := strings.TrimSpace(d)181			if trimmed == "" {182				panic("AllowedDAOs entries must be realm paths; got an empty one")183			}184			// Entries are stored exactly as given, and InAllowedDAOs compares185			// whole strings, so an entry with surrounding spaces matches no186			// caller at all. A non-empty list also closes the bootstrap187			// window, so a list of only padded entries is locked shut against188			// everyone, the DAO included, with no way to reopen it.189			//190			// This does not make the list typo-proof, and is not meant to be:191			// any wrong path locks the DAO out exactly the same way, and no192			// check here can tell a typo from a realm that does not exist yet.193			// Whitespace is worth rejecting because it is the one spelling a194			// human reviewing the proposal cannot see. Rejected rather than195			// trimmed, so what gets stored is what the proposal said.196			// Reported by position, not by value. A panic message becomes the197			// proposal's DeniedReason, which is stored, and the entry is198			// caller-supplied and unbounded — echoing it would put an199			// arbitrary amount of someone else's text into this realm's200			// storage. The index is enough to find it in a list the proposal201			// author wrote.202			if d != trimmed {203				panic("AllowedDAOs entries must not have leading or trailing spaces; entry " + strconv.Itoa(i))204			}205		}206		// Stored as given. A defensive copy here looks prudent but would207		// guard a write no outside realm can perform, which was checked from208		// a separate realm rather than assumed:209		//210		//   - Building this request as a literal fails outright, with211		//     "cannot allocate gno.land/r/gov/dao.UpdateRequest in realm ...".212		//   - Writing through a request obtained from NewUpdateRequest fails213		//     with "cannot directly modify readonly tainted object".214		//215		// So the only way in is NewUpdateRequest, which copies already. Both216		// checks are language guarantees, not conventions.217		allowedDAOs = r.AllowedDAOs218	}219220	if r.DAO != nil {221		dao = r.DAO222	}223}224225func AllowedDAOs() []string {226	dup := make([]string, len(allowedDAOs))227	copy(dup, allowedDAOs)228	return dup229}230231func InAllowedDAOs(pkg string) bool {232	if len(allowedDAOs) == 0 {233		return true // corner case for initialization234	}235	for _, d := range allowedDAOs {236		if pkg == d {237			return true238		}239	}240	return false241}242243func executeProposal(cur realm, pid ProposalID, execErrorRejects bool) bool {244	if dao == nil {245		return false246	}247	execute, err := dao.PreExecuteProposal(0, cur, pid)248	if err != nil {249		panic(err.Error())250	}251252	if !execute {253		return false254	}255	prop, err := GetProposal(pid)256	if err != nil {257		panic(err.Error())258	}259260	err = dao.ExecuteProposal(0, cur, pid, prop.executor)261	if err != nil {262		if execErrorRejects {263			return false264		}265266		panic(err.Error())267	}268	return true269}270

Functions

  • AllowedDAOs() []string

  • CreateProposal(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, r struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}) (int64, interface {Error func() string})

  • ExecuteOrRejectProposal(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, pid int64) bool

  • ExecuteProposal(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, pid int64) bool

  • GetProposal(pid int64) (*gno.land/r/gov/dao.Proposal, interface {Error func() string})

  • InAllowedDAOs(pkg string) bool

  • MustCreateProposal(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, r struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}) int64

  • MustGetProposal(pid int64) *gno.land/r/gov/dao.Proposal

  • MustVoteOnProposal(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, r struct{Option gno.land/r/gov/dao.VoteOption; ProposalID gno.land/r/gov/dao.ProposalID; Metadata interface {}})

  • MustVoteOnProposalSimple(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, pid int64, option string)

  • NewProposalRequest(title string, description string, executor interface {CreationRealm func() string; Execute func(.uverse.realm) .uverse.error; String func() string}) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

  • NewProposalRequestWithFilter(title string, description string, executor interface {CreationRealm func() string; Execute func(.uverse.realm) .uverse.error; String func() string}, filter interface {}) struct{title string; description string; executor gno.land/r/gov/dao.Executor; filter gno.land/r/gov/dao.Filter}

  • NewProposals() *gno.land/r/gov/dao.Proposals

  • NewSafeExecutor(e interface {CreationRealm func() string; Execute func(.uverse.realm) .uverse.error; String func() string}) *gno.land/r/gov/dao.SafeExecutor

  • NewSimpleExecutor(int, rlm interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, callback func(.uverse.realm) .uverse.error, description string) *gno.land/r/gov/dao.SimpleExecutor

  • NewUpdateRequest(d interface {ExecuteProposal func(int, .uverse.realm, gno.land/r/gov/dao.ProposalID, gno.land/r/gov/dao.Executor) .uverse.error; PostCreateProposal func(int, .uverse.realm, gno.land/r/gov/dao.ProposalRequest, gno.land/r/gov/dao.ProposalID); PreCreateProposal func(int, .uverse.realm, gno.land/r/gov/dao.ProposalRequest) (.uverse.address, .uverse.error); PreExecuteProposal func(int, .uverse.realm, gno.land/r/gov/dao.ProposalID) (bool, .uverse.error); Render func(.uverse.realm, string, string) string; VoteOnProposal func(int, .uverse.realm, gno.land/r/gov/dao.VoteRequest) .uverse.error}, allowedDAOs []string) struct{DAO gno.land/r/gov/dao.DAO; AllowedDAOs []string}

  • NewVoteRequest(option string, proposalID int64) struct{Option gno.land/r/gov/dao.VoteOption; ProposalID gno.land/r/gov/dao.ProposalID; Metadata interface {}}

  • NewVoteRequestWithMetadata(option string, proposalID int64, metadata interface {}) struct{Option gno.land/r/gov/dao.VoteOption; ProposalID gno.land/r/gov/dao.ProposalID; Metadata interface {}}

  • Render(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, p string) string

  • UpdateImpl(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, r struct{DAO gno.land/r/gov/dao.DAO; AllowedDAOs []string})

  • VoteOnProposal(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, r struct{Option gno.land/r/gov/dao.VoteOption; ProposalID gno.land/r/gov/dao.ProposalID; Metadata interface {}}) interface {Error func() string}

Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

Rendered

RenderedRawgnoweb ↗

vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.