DAO Agent Contract
On this page, you'll look at the DAO smart contract that uses the yield and resume pattern to enable the Shade Agent to vote on proposals within a single transaction
flow.
The AI DAO contract is a fork of the default agent contract, modified to remove the request_signature
function and implement DAO-specific functionality. This page focuses on the DAO-specific code, as agent registration follows the default contract.
Contract Structure
The DAO agent contract extends the default contract with additional state:
- The DAO's manifesto
- A map of pending proposals
- A map of finalized proposals
- The current proposal ID
Loading...
Manifesto
The manifesto consists of two components: the manifesto text
that defines the DAO's decision-making principles and a hash
of the manifesto for verifying that the agent uses the correct manifesto when voting.
Loading...
The manifesto and its hash are initialized as empty strings.
Pending Proposals
This stores all proposals that are awaiting a vote from the agent. Each proposal request includes the proposal text
and yield ID
- a unique identifier for each yielded promise (each active pending proposal request).
Loading...
The map is initialized as empty.
Finalized Proposals
This stores all proposals that the agent has voted on. Each finalized proposal contains the proposal text
, proposal result
(enum of Approved
or Rejected
), and reasoning
for the vote. The result and reasoning are provided by the agent.
- FinalizedProposal
- ProposalResult
Loading...
Loading...
The map is initialized as empty.
Current Proposal ID
The current proposal ID is an integer identifier that increments with each proposal request and is used to identify different proposals. If a proposal is not voted on by the agent, then the proposal ID will still increment, leading to non-consecutive proposal IDs
within the finalized proposals map. Note that the proposal ID is different to the yield ID.
Setting the Manifesto
The contract provides a function to set the manifesto, which only the contract owner
can call. The owner provides the manifesto text, which is hashed
and stored along with the text in the contract's state. In production, the owner would typically be a multisig
contract.
Loading...
Creating a Proposal
When a user calls create_proposal
with the proposal text, the function creates a yielded promise
. The promise will call the specified function,return_external_response
, with the arguments of proposal_id
and proposal_text
when the promise resolves. The promise resolves when the agent produces a valid response or the promise times out - after 200 blocks (~2 minutes).
Loading...
The function then reads the yield ID
from the register
for the created promise. The yield ID
is a unique hash identifier that ensures responses are matched to the correct pending proposal. The yield ID is generated by the register
, which takes an integer identifier that specifies which register is being used, since there is just one yield-resume register here, it's set to zero.
Loading...
A new proposal request is created and inserted into the pending proposals map, allowing the agent to fetch proposals that it needs to respond to.
Loading...
Lastly, the function returns the yielded promise
making it ready to be resumed.
Loading...
Agent Response and Validation
Once the agent makes its decision, it calls the agent_vote
function. This function checks whether the response is valid and resumes the yielded promise if so.
The agent responds with the yield ID
for the promise it intends to resume, the proposal ID
it's voting on, the hash of the proposal
, the hash of the manifesto
, the vote
, and the reasoning
behind the vote.
- Args
- AiResponse
Loading...
Loading...
Most importantly, the function checks if the caller is a valid registered agent
, ensuring the DAO only makes decisions through the expected process (that's defined by the verifiable agent).
Loading...
The function verifies that the manifesto hash
and proposal hash
submitted by the agent match those stored in the contract. This verification ensures the agent used the correct manifesto and proposal when voting, removing trust in the RPC
used to fetch proposals and manifesto data. Otherwise, there could be a bug in the RPC causing it to fetch the wrong details and the RPC or a malicious intermediary could intentionally provide the wrong details to try to corrupt the vote.
Loading...
If any of these checks fail then the function panics and the promise is not be resumed (it could be resumed later with valid arguments before timeout). If all checks pass, then the function resumes the promise with the specified yield ID and the agent's response as an argument.
Loading...
Proposal Finalization
When the yielded promise resolves (either resumed or timed out), the return_external_response
function is called. This function is private and can only be called by the yielded promise, not by external accounts.
The function receives arguments from both when the promise was created and when it was resumed.
Loading...
The function first removes the proposal being responded to from the pending proposals map, regardless of whether the promise was resumed or timed out.
Loading...
If the response is valid, i.e. the yielded promise was successfully resumed, the proposal and the result are added to the map of finalized proposals, and a response is returned to the caller within the same transaction that the proposal was submitted in.
Loading...
If the response is invalid, i.e. the yielded promise timed out, the function returns a promise to call fail_on_timeout
, which panics and produces a failed receipt in a separate block to provide a clear error to the user (the return_external_response receipt is still successful).
- Promise
- Panic function
Loading...
Loading...
Visit the yield and resume section of the docs for a deeper look into this pattern.
View Functions
The contract exposes view functions to retrieve the manifesto text, pending proposals, and finalized proposals.
Next steps
Now that you understand the DAO agent contract implementation, continue to the agent page to learn about the verifiable agent that queries the contract for pending requests and casts a vote using an LLM.