> ## Documentation Index
> Fetch the complete documentation index at: https://astral-6ef288be-claude-ascii-globe-mouse-interaction-bupya.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Policy Attestations

> Signed computation results for offchain and onchain use

<Warning>
  **Research Preview** — Under active development.
</Warning>

# Policy Attestations

Policy Attestations are the **signed outputs** of geospatial operations. They are signed by the Astral signing key, which is held exclusively inside the TEE (trusted execution environment). This is how you know the computation was performed correctly — only code running inside the TEE can produce valid signatures.

<Info>
  When submitted onchain via EAS resolvers, policy attestations can trigger any smart contract logic on EVM-compatible chains.
</Info>

## What is a Policy Attestation?

When you call a compute operation, Astral returns a Policy Attestation:

<Note>
  **Code snippets need testing** — Verify against actual implementation before use.
</Note>

```typescript theme={null}
const result = await astral.compute.within({
  geometry: userLocationUID,
  target: landmarkUID,
  radius: 500,
  chainId: 84532,
  schema: SCHEMA_UID,
  recipient: userAddress
});

// result is a PolicyAttestationResult
console.log(result.result);      // true
console.log(result.operation);   // "within"
console.log(result.attestation); // { uid, schema, signature, ... }
```

The attestation proves:

* The computation was performed by the Astral signing key
* The inputs were exactly as specified
* The result is accurate

## Schema Types

Policy Attestations use per-result-type schemas. The SDK auto-selects based on the operation.

### BooleanPolicyAttestation

For predicates (`contains`, `within`, `intersects`):

```solidity theme={null}
// Schema: "bool result, bytes32[] inputRefs, uint64 timestamp, string operation"
struct BooleanPolicyAttestation {
    bool result;              // The boolean result
    bytes32[] inputRefs;      // Input references (UIDs or hashes)
    uint64 timestamp;         // When computation was performed
    string operation;         // "contains", "within", "intersects"
}
```

### NumericPolicyAttestation

For measurements (`distance`, `length`, `area`):

```solidity theme={null}
// Schema: "uint256 result, string units, bytes32[] inputRefs, uint64 timestamp, string operation"
struct NumericPolicyAttestation {
    uint256 result;           // Scaled integer (centimeters)
    string units;             // "meters" or "square_meters"
    bytes32[] inputRefs;      // Input references
    uint64 timestamp;         // When computation was performed
    string operation;         // "distance", "length", "area"
}
```

### GeometryPolicyAttestation (Future)

For transformations (`buffer`, `centroid`, `union`):

```solidity theme={null}
// Schema: "bytes geometry, string geometryType, bytes32[] inputRefs, uint64 timestamp, string operation"
struct GeometryPolicyAttestation {
    bytes geometry;           // Encoded geometry result
    string geometryType;      // "Point", "Polygon", etc.
    bytes32[] inputRefs;      // Input references
    uint64 timestamp;         // When computation was performed
    string operation;         // "buffer", "centroid", "union"
}
```

## Input References

The `inputRefs` array contains a `bytes32` reference for each input:

| Input Type               | Reference Value                  |
| ------------------------ | -------------------------------- |
| Location Attestation UID | The UID itself                   |
| Offchain Attestation     | The attestation UID              |
| Raw GeoJSON              | `keccak256(abi.encode(geojson))` |

This enables verification that specific inputs were used:

```solidity theme={null}
// In your resolver
(bool result, bytes32[] memory inputRefs, , ) = abi.decode(...);

// Verify the expected location was checked
require(inputRefs[1] == EXPECTED_LANDMARK_UID, "Wrong location checked");
```

<Note>
  For raw GeoJSON, the hash allows verification if the original geometry is known, but does not reveal the geometry itself.
</Note>

## SDK Return Object

```typescript theme={null}
interface PolicyAttestationResult<T> {
  // Decoded result (convenience)
  result: T;                          // boolean | number | GeoJSON.Geometry
  units?: string;                     // For measurements
  operation: string;                  // Operation name
  timestamp: number;                  // Unix timestamp
  inputRefs: string[];                // Input references

  // Full attestation data
  attestation: {
    uid: string;                      // EAS UID (if submitted onchain)
    schema: string;                   // Schema UID
    attester: string;                 // Astral signer address
    recipient: string;                // Developer-specified recipient
    data: string;                     // ABI-encoded attestation data
    signature: string;                // EIP-712 signature
  };

  // For delegated onchain submission
  delegatedAttestation: {
    signature: string;                // Astral's signature
    attester: string;                 // Astral's address
    deadline: number;                 // Signature expiry
  };
}
```

## Using Policy Attestations

### Offchain

Use the result directly in your application:

```typescript theme={null}
const result = await astral.compute.within({
  geometry: uid1,
  target: uid2,
  radius: 500,
  chainId: 84532,
  schema: SCHEMA_UID
});

if (result.result) {
  // User is nearby — enable feature
  enableFeature();
}
```

### Onchain

Submit using [delegated attestation](/sdk/eas):

```typescript theme={null}
const result = await astral.compute.within({
  geometry: uid1,
  target: uid2,
  radius: 500,
  chainId: 84532,
  schema: RESOLVER_SCHEMA_UID,
  recipient: userAddress
});

// Submit to EAS — triggers your resolver
const tx = await astral.eas.submitDelegated(result.delegatedAttestation);
await tx.wait();
```

<Info>
  To connect policy attestations to smart contract logic, you need to [register an EAS resolver](/concepts/eas-resolvers) with your schema first.
</Info>

## Result Scaling

Numeric results are stored as scaled integers for determinism:

| Original      | Stored   | To Recover      |
| ------------- | -------- | --------------- |
| 523.45 meters | 52345    | divide by 100   |
| 1234.5678 m²  | 12345678 | divide by 10000 |

```solidity theme={null}
// In your resolver
(uint256 resultCm, , , , ) = abi.decode(...);
uint256 meters = resultCm / 100;
```

## Attestation Expiry

The `delegatedAttestation.deadline` indicates when the signature expires. Submissions after the deadline will fail.

```typescript theme={null}
if (Date.now() / 1000 < result.delegatedAttestation.deadline) {
  await astral.eas.submitDelegated(result.delegatedAttestation);
}
```

<Card title="Next: EAS Resolvers" icon="gavel" href="/concepts/eas-resolvers">
  Learn how to gate smart contracts with Policy Attestations
</Card>
