> ## Documentation Index
> Fetch the complete documentation index at: https://astral-6ef288be-docs-policy-evaluation-framing.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Compute Module

> Verifiable geospatial computation methods

<Warning>
  **Research Preview** — The SDK is under active development.
</Warning>

# Compute module

The `ComputeModule` provides geospatial operations designed to run in a trusted execution environment, so the computation can be verified independently. Each operation returns a signed result (a delegated attestation that can be submitted to EAS). Note that the TEE makes the *computation* verifiable, not the input locations truthful, and continuous attested operation is not yet funded — see the [trust model](/trust-model/what-you-are-trusting).

```typescript theme={null}
import { AstralSDK } from '@decentralized-geo/astral-sdk';

const astral = new AstralSDK({
  chainId: 84532,
  signer: wallet,
  apiUrl: 'https://staging-api.astral.global'
});

// Access via astral.compute
astral.compute.distance(from, to, options);
astral.compute.area(geometry, options);
astral.compute.length(geometry, options);
astral.compute.contains(container, containee, options);
astral.compute.within(geometry, target, radius, options);
astral.compute.intersects(a, b, options);
astral.compute.submit(input);
astral.compute.estimate(attestation);
astral.compute.health();
```

***

## Input types

All compute methods accept flexible input types:

```typescript theme={null}
type Input =
  | string                         // Onchain attestation UID
  | GeoJSON.Geometry               // Raw GeoJSON geometry
  | { uid: string }                // Onchain reference
  | { uid: string; uri: string }   // Offchain reference
  | { verifiedProof: VerifiedLocationProof }  // Verified proof input
```

### Examples

```typescript theme={null}
// Using attestation UID
const result = await astral.compute.distance(
  '0x1234...abcd',
  '0x5678...efgh',
  options
);

// Using raw GeoJSON
const result = await astral.compute.distance(
  { type: 'Point', coordinates: [2.2945, 48.8584] },
  { type: 'Point', coordinates: [-0.1276, 51.5074] },
  options
);

// Mixing UIDs and GeoJSON
const result = await astral.compute.contains(
  boundaryUID,
  { type: 'Point', coordinates: [lon, lat] },
  options
);
```

<Note>
  Raw GeoJSON is not verified for authenticity. The `inputRefs` will contain a keccak256 hash of the geometry rather than a UID.
</Note>

***

## Compute options

All spatial methods **require** options:

```typescript theme={null}
interface ComputeOptions {
  schema: string;       // Required: EAS schema UID for the result
  recipient?: string;   // Optional: recipient address (defaults to zero address)
}
```

### Schema requirements

<Warning>
  **Use the correct schema type** — Compute operations encode data differently than location attestations. Using the wrong schema UID causes a data/schema mismatch where the attestation is stored but cannot be decoded correctly.
</Warning>

| Operation                          | Required schema type     |
| ---------------------------------- | ------------------------ |
| `distance`, `area`, `length`       | NumericPolicyAttestation |
| `contains`, `within`, `intersects` | BooleanPolicyAttestation |

```typescript theme={null}
// CORRECT: Boolean operation with boolean schema
await compute.within(point, target, 500, {
  schema: BOOLEAN_POLICY_SCHEMA_UID
});

// WRONG: Boolean operation with location schema
await compute.within(point, target, 500, {
  schema: LOCATION_SCHEMA_UID
});
// The attestation is created but data is unreadable!
```

See [Schemas](/resources/schemas) for schema definitions and default UIDs.

***

## Numeric operations

### distance()

Calculate the geodesic distance between two geometries.

```typescript theme={null}
astral.compute.distance(
  from: Input,
  to: Input,
  options: ComputeOptions
): Promise<NumericComputeResult>
```

```typescript theme={null}
const result = await astral.compute.distance(
  userLocationUID,
  landmarkUID,
  { schema: SCHEMA_UID }
);

console.log(result.result);     // 523.45
console.log(result.units);      // 'meters'
console.log(result.operation);  // 'distance'
```

### area()

Calculate the area of a polygon.

```typescript theme={null}
astral.compute.area(
  geometry: Input,
  options: ComputeOptions
): Promise<NumericComputeResult>
```

```typescript theme={null}
const result = await astral.compute.area(
  propertyBoundaryUID,
  { schema: SCHEMA_UID }
);

console.log(result.result);  // 5432.10
console.log(result.units);   // 'square_meters'
```

### length()

Calculate the length of a LineString.

```typescript theme={null}
astral.compute.length(
  geometry: Input,
  options: ComputeOptions
): Promise<NumericComputeResult>
```

```typescript theme={null}
const result = await astral.compute.length(
  routeUID,
  { schema: SCHEMA_UID }
);

console.log(result.result);  // 2345.67
console.log(result.units);   // 'meters'
```

***

## Boolean operations

### contains()

Check if a container geometry contains another geometry.

```typescript theme={null}
astral.compute.contains(
  container: Input,
  containee: Input,
  options: ComputeOptions
): Promise<BooleanComputeResult>
```

```typescript theme={null}
const result = await astral.compute.contains(
  geofencePolygonUID,
  userLocationUID,
  { schema: SCHEMA_UID }
);

if (result.result) {
  console.log('User is inside the geofence!');
  await astral.compute.submit(result.delegatedAttestation);
}
```

### within()

Check if a geometry is within a specified radius of a target.

```typescript theme={null}
astral.compute.within(
  geometry: Input,
  target: Input,
  radius: number,           // meters
  options: ComputeOptions
): Promise<BooleanComputeResult>
```

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

if (result.result) {
  console.log('User is within 500m of the landmark!');
  await astral.compute.submit(result.delegatedAttestation);
}
```

### intersects()

Check if two geometries intersect.

```typescript theme={null}
astral.compute.intersects(
  a: Input,
  b: Input,
  options: ComputeOptions
): Promise<BooleanComputeResult>
```

```typescript theme={null}
const result = await astral.compute.intersects(
  territory1UID,
  territory2UID,
  { schema: SCHEMA_UID }
);

console.log('Territories overlap:', result.result);
```

***

## Submission methods

### submit()

Submit a delegated attestation to EAS. Accepts two input formats:

```typescript theme={null}
// Format 1: DelegatedAttestation directly
astral.compute.submit(
  attestation: DelegatedAttestation
): Promise<AttestationResult>

// Format 2: Object with both attestation types
astral.compute.submit(
  input: {
    attestation: AttestationObject;
    delegatedAttestation: DelegatedAttestationObject;
  }
): Promise<AttestationResult>
```

```typescript theme={null}
const result = await astral.compute.within(
  userLocationUID, landmarkUID, 500, { schema: SCHEMA_UID }
);

if (result.result) {
  const submission = await astral.compute.submit(result.delegatedAttestation);
  console.log('Attestation UID:', submission.uid);
}
```

### estimate()

Estimate gas for attestation submission.

```typescript theme={null}
astral.compute.estimate(
  attestation: DelegatedAttestation
): Promise<bigint>
```

```typescript theme={null}
const gas = await astral.compute.estimate(result.delegatedAttestation);
console.log('Estimated gas:', gas.toString());

if (gas < 200000n) {
  await astral.compute.submit(result.delegatedAttestation);
}
```

### health()

Check the compute service health status.

```typescript theme={null}
astral.compute.health(): Promise<HealthStatus>
```

```typescript theme={null}
const status = await astral.compute.health();
console.log('Service status:', status.status);
console.log('Database status:', status.database);
```

***

## Return types

### NumericComputeResult

```typescript theme={null}
interface NumericComputeResult {
  result: number;
  units: string;               // 'meters' or 'square_meters'
  operation: string;           // 'distance', 'area', or 'length'
  timestamp: number;
  inputRefs: string[];         // UIDs or hashes of inputs
  attestation: AttestationObject;
  delegatedAttestation: DelegatedAttestationObject;
  proofInputs?: ProofInputContext[];  // When using VerifiedLocationProof inputs
}
```

### BooleanComputeResult

```typescript theme={null}
interface BooleanComputeResult {
  result: boolean;
  operation: string;           // 'contains', 'within', or 'intersects'
  timestamp: number;
  inputRefs: string[];
  attestation: AttestationObject;
  delegatedAttestation: DelegatedAttestationObject;
  proofInputs?: ProofInputContext[];
}
```

### DelegatedAttestation

```typescript theme={null}
interface DelegatedAttestation {
  message: {
    schema: string;
    recipient: string;
    expirationTime: bigint;
    revocable: boolean;
    refUID: string;
    data: string;
    value: bigint;
    nonce: bigint;
    deadline: bigint;
  };
  signature: {
    v: number;
    r: string;
    s: string;
  };
  attester: string;
}
```

***

## How delegated attestations work

| Step | Who            | Does what                                      |
| ---- | -------------- | ---------------------------------------------- |
| 1    | **Developer**  | Calls `compute.within()` or other method       |
| 2    | **Astral API** | Runs computation in TEE, signs attestation     |
| 3    | **Developer**  | Receives signed `delegatedAttestation`         |
| 4    | **Developer**  | Calls `compute.submit()` (pays gas)            |
| 5    | **EAS**        | Verifies signature, records Astral as attester |
| 6    | **Resolver**   | Checks `attestation.attester == astralSigner`  |

This pattern means:

* Astral does not need to pay gas for every computation
* Developers control when/whether to submit onchain
* Smart contracts can verify attestations came from Astral

***

## Signature expiry

Delegated attestation signatures have a deadline:

```typescript theme={null}
const result = await astral.compute.within(uid1, uid2, 500, options);

const deadline = result.delegatedAttestation.message.deadline;
const now = BigInt(Math.floor(Date.now() / 1000));

if (now < deadline) {
  await astral.compute.submit(result.delegatedAttestation);
} else {
  // Signature expired — request new computation
  const newResult = await astral.compute.within(uid1, uid2, 500, options);
  await astral.compute.submit(newResult.delegatedAttestation);
}
```

***

## Complete example

```typescript theme={null}
import { AstralSDK } from '@decentralized-geo/astral-sdk';
import { ethers } from 'ethers';

const provider = new ethers.JsonRpcProvider('https://sepolia.base.org');
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);

const astral = new AstralSDK({
  chainId: 84532,
  signer: wallet,
  apiUrl: 'https://staging-api.astral.global'
});

// Create a location attestation
const location = await astral.location.onchain.create({
  location: { type: 'Point', coordinates: [2.2951, 48.8580] },
  memo: 'Near Eiffel Tower'
});

// Check proximity to a landmark
const LANDMARK_UID = '0x...';
const SCHEMA_UID = '0x...';

const result = await astral.compute.within(
  location.uid,
  LANDMARK_UID,
  500,
  { schema: SCHEMA_UID, recipient: wallet.address }
);

console.log('Within 500m:', result.result);

// Estimate gas and submit if check passed
if (result.result) {
  const gas = await astral.compute.estimate(result.delegatedAttestation);
  console.log('Estimated gas:', gas.toString());

  const submission = await astral.compute.submit(result.delegatedAttestation);
  console.log('Attestation submitted:', submission.uid);
}
```

<Card title="Next: EAS integration" icon="arrow-right" href="/sdk/eas">
  Learn how the SDK integrates with EAS
</Card>
