> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kineticvm.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Attestations

> How a device signs what it did, how KineticAttestor verifies it, and how the result becomes a public ERC-8004 validation anyone can query.

An **attestation** is a device-signed statement that a specific action happened, with specific parameters, at a specific time. KineticVM writes each one into the ERC-8004 **Validation Registry**, the standard place where onchain agents collect verifiable claims about their work.

## The action proof

The device signs an EIP-712 `ActionProof`:

```solidity theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
struct ActionProof {
    uint256 agentId;     // the agent this device is bound to
    bytes32 action;      // keccak256 of the action name, e.g. keccak256("vend")
    bytes32 paramsHash;  // keccak256 of the exact parameter bytes
    string  requestURI;  // a URI describing the request, covered by the signature
    uint256 timestamp;   // block time when the device built the proof
    uint256 nonce;       // unique per agent
}
```

The domain is `name = "KineticAttestor"`, `version = "1"`. The `requestURI` is hashed into the signature, so it cannot be swapped after signing. As with claim tickets, the device asks the contract for the digest (`hashActionProof`) and signs that.

## What the attestor checks

Anyone can submit a signed proof to `KineticAttestor.attest(proof, signature)`. In practice the device submits its own. The attestor accepts it only if every check passes:

<Steps>
  <Step title="The signer is the active device">
    The signature must recover to `KineticRegistry.activeDevice(agentId)`. A revoked key, a rotated-out key, or a key whose NFT changed hands is rejected.
  </Step>

  <Step title="The nonce is fresh">
    `nonceUsed[agentId][nonce]` must be false. Otherwise `NonceUsed`.
  </Step>

  <Step title="The proof is recent">
    `timestamp` may be at most **10 minutes** old (`StaleProof`) and at most **2 minutes** in the future (`FutureProof`).
  </Step>

  <Step title="The attestor is an operator on the agent">
    The owner must have approved the attestor with `setApprovalForAll` or `approve`. Otherwise `NotOperator`. ERC-8004 only lets an owner or operator open a validation request, and this is how the owner consents.
  </Step>
</Steps>

## What gets written

The attestor then computes a **request hash** and writes two calls to the Validation Registry:

```solidity theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
requestHash = keccak256(abi.encode(
    agentId, action, paramsHash, keccak256(bytes(requestURI)), timestamp, nonce
));

validation.validationRequest(attestor, agentId, requestURI, requestHash);
validation.validationResponse(requestHash, 100, "", paramsHash, "kinetic-action");
```

| Field in the validation | Value |
| - | - |
| Validator | The `KineticAttestor` address. |
| Agent | `agentId`. |
| Response | `100`, meaning the device key bound to this agent signed this record. |
| Response hash | `paramsHash`, the keccak256 of the exact signed parameters. |
| Tag | `kinetic-action`. |

Finally it emits:

```solidity theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
event Attested(uint256 indexed agentId, address indexed device, bytes32 indexed requestHash, bytes32 action);
```

Anyone can later call `getValidationStatus(requestHash)` on the Validation Registry and get back the validator, agent, response, response hash, and tag. That lookup is the foundation of [buyer verification](/marketplace/verification).

## When the device attests

<Tabs>
  <Tab title="Actuator actions" icon="zap">
    When `[chain]` is enabled, the runtime wraps the actuator tools `gpio_write`, `gpio_rpi_write`, `gpio_rpi_blink`, and `set_device`. After one of them **succeeds**, the runtime attests it automatically:

    * `action` is the tool name,
    * the parameters are the tool's JSON arguments,
    * `requestURI` is `kinetic://actuator/<tool name>`.

    The tool's output gets a line appended with the transaction hash, or with the error if the attestation failed. A failed tool call is never attested.
  </Tab>

  <Tab title="Builder operations" icon="package">
    A builder records a completed business operation, such as a vend, a sale, or a soil reading, by calling the [`monad_attest`](/reference/agent-tools#monad_attest) tool with an `action`, `params`, and `request_uri`.

    When the device has an [operation record schema](/concepts/records), `params` must be a JSON object matching it. The host canonicalizes it into one line, signs those exact bytes, and appends the same line to the operations file. This is what makes records sellable.
  </Tab>
</Tabs>

<Note>
  Plugin tools are **not** wrapped automatically. If a plugin drives a motor through its own path, the SOP or the model should call `monad_attest` after the operation completes.
</Note>

## Gas and nonces

The device pays gas for its attestations. Before submitting, the runtime checks its balance and [tops up from the vault](/concepts/vault#device-gas) if it holds 1 MON or less.

The runtime picks the nonce from the latest block time and tries up to four consecutive values until it finds one the attestor has not used, so two attestations in the same second do not collide.

## Reading attestations

<CodeGroup>
  ```bash cast theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  # Every attestation for agent 2005, newest last
  cast logs --rpc-url https://testnet-rpc.monad.xyz \
    --address 0x6e46d149b7d3396b42E874765Cf5a1bb26BD5bA5 \
    "Attested(uint256 indexed,address indexed,bytes32 indexed,bytes32)" \
    $(cast to-uint256 2005)

  # One attestation's validation record
  cast call --rpc-url https://testnet-rpc.monad.xyz \
    0x8004Cb1BF31DAf7788923b405b754f57acEB4272 \
    "getValidationStatus(bytes32)(address,uint256,uint8,bytes32,string,uint256)" \
    0xREQUEST_HASH
  ```

  ```text Telegram theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  /status
  ```
</CodeGroup>

`/status` lists explorer links for the five most recent `Attested` transactions for the agent.

## What an attestation proves

<Warning>
  An attestation with response `100` proves that **the device key bound to this agent signed this exact record at this time**, and that the agent's owner had authorized the attestor. It does **not** prove that the actuator physically moved, that a sensor reading was accurate, or that the device's software was honest.
</Warning>

This is the same trust boundary as any signed log, made portable and public. What KineticVM adds is that the key is tied to an owned, revocable identity, the record cannot be edited after the fact, and anyone can check it without asking the operator. Stronger guarantees come from where the key lives (a secure element such as the SE050 makes key extraction impractical) and from correlating records across independent devices.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.