const ActionExecuteLambdaKind
////////////////////////////////////////////////////////// ActionExecuteLambdaKind
Built-in action type for executing lambda functions.
////////////////////////////////////////////////////////// ActionExecuteLambdaKind
Built-in action type for executing lambda functions.
////////////////////////////////////////////////////////// ActionInstantExecuteKind
Built-in action type for instantly executing sub-proposals.
Creates, votes yes, and immediately executes a proposal in one operation. Useful when you have enough permission to execute an action directly. Examples: migrations, adding members.
SAME REALM ONLY. Every step threads rlm, and each entry point requires it to be the receiving DAO's own — so d must be a DAO hosted by the realm calling this. Handing it a DAO belonging to another realm is refused.
That refusal is the point. Driving a foreign DAO by passing it your realm is the donation shape: it makes the DAO act under YOUR identity, and it is what a caller holding the handle could previously do to any DAO. It appeared to work only because nothing checked.
A parent DAO can still drive a child. Reach the child through the child REALM's own crossing function — child.Propose(cross(cur), req) — so the child mints its own realm and sees the parent as its caller. Make the parent a member of the child; the child then authorises it like any other member.
SAME REALM ONLY, for the reason on InstantExecute: the handler forwards the EXECUTING DAO's realm, so dao must be hosted by the same realm. A child DAO in another realm is refused — reach it through that realm's crossing function instead.
SECURITY: the executor MUST type-assert the payload to a CONCRETE type, never to an interface.
The concrete assertion is what makes the action's own rendering safe to show a voter: a hostile proposer can submit any payload, but one of the wrong type is rejected before the executor sees it, and one of the right type renders through that type's own String(). Assert to an interface instead and any conforming type passes — including one whose String() understates what its data does, so the proposal reads as something milder than it executes.
Stronger still, and what the destructive built-ins do: make the payload type UNEXPORTED and expose only a constructor, so a proposer cannot build one at all. basedao's ChangeDAOImplementation and daokit's InstantExecute both do.
Moving rendering onto the handler would remove this footgun rather than document it, since the handler is registered by the DAO and the payload is not — gnodaokit#13. That changes ActionHandler, so it belongs to a version boundary rather than a patch.
Creates a new DAO core with empty stores.
Interface storing Action's data.
SECURITY: String() is what a member reads before voting, and for an action built with NewAction it is the PAYLOAD's own rendering — supplied by whoever created the proposal. It is not trustworthy on its own.
Two things keep it honest. Type() must be truthful or the wrong handler is looked up and its type assertion fails, so the action's KIND cannot be disguised; and the proposal view renders the Resource's registered DisplayName, Description and Condition beside it, which come from the DAO's own registry keyed by Type(), not from the proposal. A member therefore always sees what KIND of action this is from a trusted source.
What String() can still misrepresent is the payload's DETAIL — and only if the handler lets a hostile payload through. See NewActionHandler.
Interface storing executable function that processes Action's data.
Manages the essential components of a DAO: resources, proposals, and extensions.
1type DAO interface {
2 // Creates a new proposal and returns its ID.
3 Propose(req ProposalRequest, rlm realm) uint64
4 // Casts a vote on a specific proposal.
5 Vote(id uint64, vote daocond.Vote, rlm realm)
6 // Executes a proposal if it meets the required conditions.
7 Execute(id uint64, rlm realm)
8
9 // Generates a web interface representation for the given path.
10 Render(path string) string
11
12 // Gets an extension by path, returns nil if not found. A PRIVATE extension
13 // additionally requires the DAO realm's own live realm, on the same terms
14 // as the entry points above; a public one ignores it.
15 Extension(path string, rlm realm) Extension
16 // Lists all available extensions.
17 ExtensionsList() ExtensionsList
18}Every entry point threads the DAO realm's own realm value.
It serves two purposes. Execute forwards it to the action handlers, which cross out under it, so the implementation must refuse any realm that is not its own — otherwise a caller holding this handle could make the DAO act under the CALLER's identity. And because the realm is then known to be the DAO's, rlm.Previous() names the DAO's immediate caller, which a stack walk cannot do: reached through this handle there is no DAO realm frame on the stack at all, so a walk reports the signing account instead.
An implementation must require the realm to be BOTH its own by pkgpath and current: every realm the DAO crosses out into receives the DAO's own realm as its cur.Previous() and can hand it back within the same transaction, and only IsCurrent() tells that apart from the live one.
The realm is deliberately never the first parameter: a function whose first parameter is a realm is read as crossing, which /p/ packages may not declare.
Interface must be implemented by any object that wants to be registered as a DAO extension. Extensions expose functionality through well-defined interfaces while maintaining encapsulation.
1type ExtensionInfo struct {
2 Path string // Unique extension identifier (e.g., "gno.land/p/samcrew/basedao.MembersView")
3 Version string // Extension version (e.g., "1", "2.0", etc.)
4 QueryPath string // Path for external queries to access this extension's data
5 // If true, only the registering realm can obtain the extension VALUE
6 // through DAO.Extension — which is a capability, not a secret. Realm state
7 // on a public chain is world-readable over ABCI regardless, and this
8 // ExtensionInfo (including QueryPath) is listed by ExtensionsList without a
9 // check. Private restricts who can call the extension's methods under the
10 // DAO's authority; it does not hide anything.
11 Private bool
12} 1type ExtensionsList interface {
2 // Returns the total number of registered extensions.
3 Len() int
4 // Returns extension info at the specified index, or nil if index is out of bounds.
5 Get(index int) *ExtensionInfo
6 // Returns a slice of ExtensionInfo from startIndex to endIndex.
7 Slice(startIndex, endIndex int) []ExtensionInfo
8 // Iterates over all extensions, calling fn for each one.
9 // Iteration stops if fn returns true.
10 ForEach(fn func(index int, value ExtensionInfo) bool)
11}Returns an ExtensionsList interface for iterating over all registered extensions. This provides read-only access to the extensions registry.
Remove unregisters an extension by its path. Returns the removed extension and true if found, nil and false otherwise.
Registers a new extension using its path as the key. Returns true if the extension was successfully registered. If an extension with the same path already exists, it will be replaced.
1type Proposal struct {
2 ID seqid.ID
3 Title string
4 Description string
5 CreatedAt time.Time
6 CreatedHeight int64
7 ProposerID string
8
9 Action Action // What to execute if passed
10 Condition daocond.Condition // Voting conditions for this proposal
11 Status ProposalStatus
12 ExecutedAt time.Time
13
14 Ballot daocond.Ballot // All votes cast on this proposal
15}Reports the status a proposal should be displayed as, without writing it.
Reading must never move a proposal. Render is on the cross-realm DAO interface, so anything it touches is reachable by any realm holding the handle: every read path used to call UpdateStatus on each proposal it walked, and a single Render flipped every condition-met proposal from Open to Passed — which, back when Execute demanded Open, bricked it permanently.
Persists the status implied by the current votes: Open becomes Passed once the condition is met.
Nothing in this package calls it. Execute evaluates the condition itself and the read paths use DisplayStatus, so a proposal that is never passed through here stays Open until it is Executed. It exists for a realm that wants the passed state on-chain rather than computed.
SAFE ONLY BECAUSE Vote and Execute both key on Executed alone. When they demanded Open, calling this was destructive twice over: it froze the ballot, so support could not be withdrawn, and it made the proposal permanently unexecutable. Do not narrow either of those checks without removing this.
It is also a READ path hazard — do not call it while rendering. And once persisted the status no longer tracks the votes: withdraw support afterwards and this still reads Passed, though Execute re-evaluates the condition and will refuse.
Data needed to create a new proposal.
Returns all proposals that match the given filter function.
Returns all proposals as a JSON string.
Function type for updating DAO implementation during governance upgrades.