Research preview — The SDK is under active development.
Compute module
The ComputeModule provides verifiable geospatial operations that run in a trusted execution environment. Each operation returns a signed delegated attestation that can be submitted to EAS.
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 ();
All compute methods accept flexible input types:
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
// 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
);
Raw GeoJSON is not verified for authenticity. The inputRefs will contain a keccak256 hash of the geometry rather than a UID.
Compute options
All spatial methods require options:
interface ComputeOptions {
schema : string ; // Required: EAS schema UID for the result
recipient ?: string ; // Optional: recipient address (defaults to zero address)
}
Schema requirements
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.
Operation Required schema type distance, area, lengthNumericPolicyAttestation contains, within, intersectsBooleanPolicyAttestation
// 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 for schema definitions and default UIDs.
Numeric operations
distance()
Calculate the geodesic distance between two geometries.
astral . compute . distance (
from : Input ,
to : Input ,
options : ComputeOptions
): Promise < NumericComputeResult >
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.
astral . compute . area (
geometry : Input ,
options : ComputeOptions
): Promise < NumericComputeResult >
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.
astral . compute . length (
geometry : Input ,
options : ComputeOptions
): Promise < NumericComputeResult >
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.
astral . compute . contains (
container : Input ,
containee : Input ,
options : ComputeOptions
): Promise < BooleanComputeResult >
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.
astral . compute . within (
geometry : Input ,
target : Input ,
radius : number , // meters
options : ComputeOptions
): Promise < BooleanComputeResult >
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.
astral . compute . intersects (
a : Input ,
b : Input ,
options : ComputeOptions
): Promise < BooleanComputeResult >
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:
// 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 >
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.
astral . compute . estimate (
attestation : DelegatedAttestation
): Promise < bigint >
const gas = await astral . compute . estimate ( result . delegatedAttestation );
console . log ( 'Estimated gas:' , gas . toString ());
if ( gas < 200000 n ) {
await astral . compute . submit ( result . delegatedAttestation );
}
health()
Check the compute service health status.
astral . compute . health (): Promise < HealthStatus >
const status = await astral . compute . health ();
console . log ( 'Service status:' , status . status );
console . log ( 'Database status:' , status . database );
Return types
NumericComputeResult
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
interface BooleanComputeResult {
result : boolean ;
operation : string ; // 'contains', 'within', or 'intersects'
timestamp : number ;
inputRefs : string [];
attestation : AttestationObject ;
delegatedAttestation : DelegatedAttestationObject ;
proofInputs ?: ProofInputContext [];
}
DelegatedAttestation
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:
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
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 );
}
Next: EAS integration Learn how the SDK integrates with EAS