Skip to main content

Agent Contract

The agent contract is the on-chain component of the Shade Agent Framework. It handles agent registration, measurement, and PPID approval, and enforces that only valid agents can call specific methods.

On this page, you'll walk through the key components of the reference agent contract and how to implement your own agent-gated functions. You may need to change other parts of the contract depending on your use case. The full source lives in the shade-agent-template repo.


Flow

High-level flow:

  • The owner deploys and initializes the contract.
  • The owner approves measurements and PPIDs.
  • Each agent calls register_agent with a valid attestation.
  • Valid agents can then call agent-gated methods.

Initialization

The new method initializes the contract and takes four arguments (the CLI can initialize the contract with defaults):

  • requires_tee: Whether the contract runs in local or TEE mode. This switches the behavior of the contract so you can move easily between local and TEE deployments.
  • attestation_expiration_time_ms: How long a registration stays valid for after an agent registers.
  • owner_id: The account ID allowed to call owner-only methods. The owner should usually be a multisig.
  • mpc_contract_id: The Chain Signatures MPC contract that the agent contract will call for multichain signing.

On initialization, the rest of the contract state is set to empty.

If your contract needs additional state, add it in the init method and extend the Contract struct accordingly.


Measurements, PPID, Whitelist, and Agent Management

The owner of the contract can manage the approved measurements, PPIDs, whitelist, and agents.

Measurements

The approved_measurements decide what code an agent is allowed to run. The CLI will approve a set of measurements for your agent when run. You can learn more about measurements here.

The owner controls which measurements are approved and can add or remove them over time. A typical agent code upgrade flow is: approve a new set of measurements, allow a transition period (e.g. a week) so operators can update agents to run the new code, then remove the old measurements.

PPID

The approved_ppids decide which physical TEE CPUs an agent may run on. The CLI will approve a list of default PPIDs when run. You can learn more about PPID here.

Agent

Agents become authorized by calling register_agent; the owner can also remove an agent at any time. Use removal to clean up invalid agents or to revoke access if a TEE were to become compromised.

note

A removed agent can re-register by calling register_agent with a valid attestation.

Whitelist

The whitelist applies only in local mode. It defines which account IDs may call agent-gated methods, since in local mode, the contract cannot verify that an agent is running approved code. Use shade whitelist in the CLI to add an account. You can learn more about whitelisting here.


Register Agent

Agents register by calling register_agent. The method checks that the agent has a valid attestation via verify_attestation; if it passes, the agent is stored with its measurements, PPID, and validity period (determined by attestation_expiration_time_ms).

An agent must attach 0.00486 NEAR to cover its own storage cost in the contract. If you change how much data is stored per agent, update the STORAGE_BYTES_TO_REGISTER constant accordingly.

By default, an agent that provides a valid attestation can register. Meaning that anyone may be able to run an agent and register. Depending on your use case, you may want to add additional restrictions to an agent, for example, an allow-list of accounts, proof of a shared secret, or a limit of one agent per contract.

Verify Attestation

verify_attestation decides if an agent is allowed to register. Its behavior depends on whether the contract is in TEE or local mode.

TEE Mode

In TEE mode (requires_tee = true), the method accepts the agent only if it supplies a valid attestation, which is checked using the verify function provided by the shade-attestation crate, which takes the list of approved measurements and PPIDs, the current timestamp (in seconds), and the expected report_data.

The attestation’s report data must contain the NEAR account ID of the agent. This binds the attestation to the same TEE where the agent’s key was created to prevent replay of valid attestations. Report data is passed as bytes.

Local Mode

In local mode (requires_tee = false), the method approves the agent if the caller is whitelisted and the mock measurements and PPID are approved in the contract. No real attestation is verified.


Require Valid Agent

You can restrict methods so only valid agents can call them using the helper require_valid_agent. An agent that registered earlier may no longer be valid. To gate a method: call require_valid_agent, and if it returns Some(promise), execute the promise.

Handle the promise

You must execute the promise returned by require_valid_agent when it is Some(promise); otherwise, the invalid agent can still call the function.

require_valid_agent first loads the agent from storage; if the caller is not registered, it panics.

It then checks whether the agent is still valid. It's valid if its registration has not expired (determined by attestation_expiration_time_ms), its measurements are still in the approved set, and its PPID is still approved.

If the agent is valid, then the function will return None. If the agent is invalid, it will be removed from the map of agents, an event will be emitted detailing the reasons for removal, and a promise will be returned from the function that will call fail_on_invalid_agent in the next block.

The promise calls fail_on_invalid_agent, which panics in the next block. Panicking in the next block (rather than the current one) ensures the agent is removed from storage; panicking in the current block would revert that removal.


Your Functions

The template includes an example request_signature function. It allows a valid agent to request a signature for a transaction payload from the MPC contract, so you can sign transactions for most chains. You can learn more about singing transactions for different chains in the chain signatures documentation.

You should implement your own agent-gated functions in this your_functions.rs file, following the same pattern: call require_valid_agent, then run your logic.

On chain guardrails

A key part of the Shade Agent Framework is the ability to implement on-chain guardrails. This gives protection against unauthorized actions - even if the TEE is compromised. It's strongly recommended that you build actions within the agent contract rather than in the agent itself, for example, using the omni-transaction-rs library.


Building the Contract

Usually, you build and deploy with the Shade Agent CLI: shade deploy. To build the contract manually, use the following command:

For Linux, you can compile the contract directly with cargo near.

cargo near build non-reproducible-wasm --no-abi
note

The --no-abi flag is used to build the contract without an ABI. This is required because the shade-attestation crate currently doesn't support ABI generation.


Calling Methods

The Shade Agent CLI calls the main contract methods when you run shade deploy, but it does not cover every method. For methods the CLI doesn’t support, use the NEAR CLI or create scripts using the NEAR API.