Coordinator Contract
Account: coordinator.agents-coordinator.testnet
The Coordinator contract manages proposal lifecycle, worker submission recording, and on-chain result settlement using NEAR's yield/resume pattern. Individual votes remain private off-chain -- only aggregate tallies are settled on-chain.
Proposal Lifecycle
Created ──> WorkersCompleted ──> Finalized
│
└──────> TimedOut| State | Description |
|---|---|
| Created | Yield promise created, waiting for worker submissions |
| WorkersCompleted | All expected worker submissions recorded on-chain |
| Finalized | Aggregated result settled on-chain via yield resume |
| TimedOut | Yield timed out (~200 blocks / ~100s on testnet) before resolution |
Yield/Resume Pattern
The contract uses NEAR's promise_yield_create to create an async coordination point:
start_coordinationcreates a yielded promise and stores theyield_idin the proposal- The coordinator agent orchestrates off-chain deliberation (workers vote via Ensue)
record_worker_submissionsrecords nullifier hashes on-chain (no vote data)coordinator_resumecallspromise_yield_resumewith the aggregated result- The
return_coordination_resultcallback finalizes the proposal state
If the yield times out before resume, the proposal transitions to TimedOut and the contract panics with a timeout error.
Data Structures
Proposal
pub struct Proposal {
pub yield_id: CryptoHash,
pub task_config: String,
pub config_hash: String,
pub timestamp: u64,
pub requester: AccountId,
pub state: ProposalState,
pub expected_worker_count: u8,
pub quorum: u8,
pub worker_submissions: Vec<WorkerSubmission>,
pub finalized_result: Option<String>,
}WorkerSubmission
pub struct WorkerSubmission {
pub worker_id: String,
pub result_hash: String, // nullifier -- no vote data on-chain
pub timestamp: u64,
}Manifesto
pub struct Manifesto {
pub text: String, // up to 10,000 characters
pub hash: String, // SHA-256 hex
}Call Methods
coordinator.agents-coordinator.testnetStart a new proposal. Creates a yielded promise and returns the proposal ID. Requires a manifesto to be set first.
Parameters:
| Param | Type | Description |
|---|---|---|
| task_config | String | JSON task configuration (max 10,000 chars) |
| expected_worker_count | u8 | Number of workers expected to participate |
| quorum | u8 | Minimum votes needed for valid result |
Returns: u64 (proposal ID)
near call coordinator.agents-coordinator.testnet start_coordination \
'{"task_config":"{\"type\":\"vote\",\"parameters\":{\"proposal\":\"Fund dev education\"}}","expected_worker_count":3,"quorum":2}' \
--accountId agents-coordinator.testnet \
--gas 300000000000000The yield times out after ~200 blocks (~100 seconds on testnet). The coordinator agent must complete the full flow (worker polling, submission recording, and resume) within this window.
coordinator.agents-coordinator.testnetRecord worker participation on-chain using the nullifier pattern. Each worker can submit only once per proposal (double-submission panics). The submission count must exactly match expected_worker_count.
Only callable by a registered coordinator with an approved codehash.
Parameters:
| Param | Type | Description |
|---|---|---|
| proposal_id | u64 | Proposal to record submissions for |
| submissions | Vec<WorkerSubmissionInput> | Array of { worker_id, result_hash } |
{
"proposal_id": 1,
"submissions": [
{ "worker_id": "did:key:z6Mk...", "result_hash": "a1b2c3..." },
{ "worker_id": "did:key:z6Mk...", "result_hash": "d4e5f6..." }
]
}Transitions proposal state from Created to WorkersCompleted.
coordinator.agents-coordinator.testnetResume the yielded promise with the aggregated result. Only callable by a registered coordinator with an approved codehash. The proposal must be in WorkersCompleted state.
Parameters:
| Param | Type | Description |
|---|---|---|
| proposal_id | u64 | Proposal to resume |
| aggregated_result | String | JSON result (e.g., {"approved":2,"rejected":1,"decision":"Approved"}) |
| config_hash | String | SHA-256 of original task config (integrity check) |
| result_hash | String | SHA-256 of aggregated_result (integrity check) |
The contract verifies both hashes: config_hash must match the stored config hash, and result_hash must match the SHA-256 of the provided aggregated_result. This prevents tampering between submission recording and result settlement.
coordinator.agents-coordinator.testnetSet the DAO manifesto that guides agent voting decisions. Owner only. Max 10,000 characters. The manifesto text and its SHA-256 hash are stored on-chain.
Parameters:
| Param | Type | Description |
|---|---|---|
| manifesto_text | String | Manifesto content (max 10,000 chars) |
coordinator.agents-coordinator.testnetApprove a TEE codehash for coordinator registration. Owner only. Coordinators must have an approved codehash to call record_worker_submissions and coordinator_resume.
Parameters:
| Param | Type | Description |
|---|---|---|
| codehash | String | TEE codehash to approve |
coordinator.agents-coordinator.testnetRegister a coordinator agent with a TEE checksum and codehash. Owner only. The codehash must be pre-approved via approve_codehash.
Parameters:
| Param | Type | Description |
|---|---|---|
| checksum | String | TEE deployment checksum |
| codehash | String | Pre-approved TEE codehash |
coordinator.agents-coordinator.testnetRegister a worker on the Coordinator contract. Only callable by the owner or a registered coordinator.
Parameters:
| Param | Type | Description |
|---|---|---|
| worker_id | String | Worker identifier (typically a DID) |
| account_id | Option<AccountId> | Optional NEAR account ID |
This is a separate registration from the Registry contract. The Registry handles permissionless discovery; this method registers workers directly on the Coordinator for on-chain validation.
coordinator.agents-coordinator.testnetDeactivate a worker on the Coordinator contract. Owner only. The worker record is preserved but marked inactive.
Parameters:
| Param | Type | Description |
|---|---|---|
| worker_id | String | Worker ID to deactivate |
coordinator.agents-coordinator.testnetRemove a proposal from storage. Owner only. Used for cleanup of stale or test proposals.
Parameters:
| Param | Type | Description |
|---|---|---|
| proposal_id | u64 | Proposal to remove |
View Methods
coordinator.agents-coordinator.testnetGet a single proposal by ID.
Parameters:
| Param | Type | Description |
|---|---|---|
| proposal_id | u64 | Proposal ID |
Returns: Option<Proposal>
near view coordinator.agents-coordinator.testnet get_proposal '{"proposal_id":1}'coordinator.agents-coordinator.testnetGet all proposals with optional pagination.
Parameters:
| Param | Type | Description |
|---|---|---|
| from_index | Option<u64> | Start from this proposal ID (default: 0) |
| limit | Option<u64> | Max results to return |
Returns: Vec<(u64, Proposal)>
coordinator.agents-coordinator.testnetFilter proposals by lifecycle state.
Parameters:
| Param | Type | Description |
|---|---|---|
| state | ProposalState | "Created", "WorkersCompleted", "Finalized", or "TimedOut" |
| from_index | Option<u64> | Start index |
| limit | Option<u64> | Max results |
Returns: Vec<(u64, Proposal)>
coordinator.agents-coordinator.testnetShortcut for get_proposals_by_state("Created", ...). Returns proposals awaiting worker submissions.
Parameters:
| Param | Type | Description |
|---|---|---|
| from_index | Option<u64> | Start index |
| limit | Option<u64> | Max results |
Returns: Vec<(u64, Proposal)>
coordinator.agents-coordinator.testnetGet the finalized result string for a specific proposal. Returns None if the proposal is not finalized.
Parameters:
| Param | Type | Description |
|---|---|---|
| proposal_id | u64 | Proposal ID |
Returns: Option<String>
coordinator.agents-coordinator.testnetGet all finalized proposal results with pagination.
Parameters:
| Param | Type | Description |
|---|---|---|
| from_index | Option<u64> | Start index |
| limit | Option<u64> | Max results |
Returns: Vec<(u64, String)>
coordinator.agents-coordinator.testnetGet all worker submissions (nullifier hashes) for a proposal.
Parameters:
| Param | Type | Description |
|---|---|---|
| proposal_id | u64 | Proposal ID |
Returns: Vec<WorkerSubmission>
coordinator.agents-coordinator.testnetGet the current DAO manifesto.
Returns: Option<Manifesto>
near view coordinator.agents-coordinator.testnet get_manifesto '{}'coordinator.agents-coordinator.testnetList all registered workers (active and inactive).
Returns: Vec<RegisteredWorker>
coordinator.agents-coordinator.testnetList only active registered workers.
Returns: Vec<RegisteredWorker>
coordinator.agents-coordinator.testnetCheck if a worker is registered and active.
Parameters:
| Param | Type | Description |
|---|---|---|
| worker_id | String | Worker ID to check |
Returns: bool
coordinator.agents-coordinator.testnetGet the count of active registered workers.
Returns: u32
coordinator.agents-coordinator.testnetGet the latest proposal ID (auto-incrementing counter).
Returns: u64
coordinator.agents-coordinator.testnetGet the contract owner account.
Returns: AccountId