Your first location proof and verified spatial computation in 5 minutes
Research Preview — Astral is under active development and not yet production-ready. APIs may change. We’re building in public and welcome feedback.
This guide walks through both of Astral’s core capabilities: creating and verifying a location proof, then running a verified spatial computation with it.
A location proof starts on the device. You collect signals from proof-of-location systems, process them into stamps, sign them, and compose the proof.
import { AstralSDK, MockPlugin } from '@decentralized-geo/astral-sdk';const astral = new AstralSDK({ chainId: 84532, signer: wallet, apiUrl: 'https://staging-api.astral.global'});// 1. Register a proof-of-location plugin. The SDK ships MockPlugin for local// development; on a real device, evidence comes from a source like the// ProofMode app (GPS, sensors, hardware-backed signatures).astral.plugins.register(new MockPlugin({ name: 'mock-1', lat: 37.7749, lon: -122.4194 }));// 2. Collect raw signals (returns an array), then create an unsigned stampconst signals = await astral.stamps.collect({ plugins: ['mock-1'] });const unsigned = await astral.stamps.create({ plugin: 'mock-1' }, signals[0]);// 3. Sign the stamp with the device keyconst stamp = await astral.stamps.sign({ plugin: 'mock-1' }, unsigned, deviceSigner);// 4. Compose a location proof: a claim ("I was here") bundled with signed stampsconst claim = { lpVersion: '0.2', locationType: 'geojson-point', location: { type: 'Point', coordinates: [-122.4194, 37.7749] }, srs: 'http://www.opengis.net/def/crs/OGC/1.3/CRS84', subject: { scheme: 'eth-address', value: '0x1234...' }, radius: 100, time: { start: Date.now() / 1000 - 60, end: Date.now() / 1000 },};const proof = astral.proofs.create(claim, [stamp]);
Each step adds a layer. The signals are raw sensor data. The stamp processes them into a structured artifact. The signature binds the stamp to a specific identity. The proof bundles the claim with the evidence.
Submit the location proof to Astral’s Verify endpoint. Verification runs inside a TEE — each stamp is checked for signature validity, structural integrity, and consistency with the claim. Multiple stamps from independent systems are cross-correlated to strengthen confidence.
// `mode: 'tee'` routes verification to the hosted service and returns a// VerifiedLocationProof; the default 'local' mode returns the vector directly.const verified = await astral.proofs.verify(proof, { mode: 'tee', chainId: 84532 });console.log(verified.credibility); // a multidimensional credibility vectorconst locationUID = verified.attestation.uid;
The result is a credibility vector — not a binary yes/no, and not a single score, but a structured assessment of how strongly the evidence supports the claim across several dimensions (its exact structure is still an open research question). It tells you how well the evidence backs the claim — not, by itself, that the entity was definitely there. How much that’s worth, and what threshold to require, is your application’s call.
Now use the verified location in a spatial operation. The computation runs inside the same TEE — PostGIS computes the spatial relationship and the TEE signs the result.
// Arguments are positional: (container, containee, options).// `schema` is the EAS schema UID the signed result is encoded against.const inside = await astral.compute.contains( geofencePolygon, // container locationUID, // containee — the verified location { schema: SCHEMA_UID });console.log(`Inside geofence: ${inside.result}`); // true
The signed result proves the computation was performed correctly on the stated inputs. Because the input was a verified location proof, the full chain of trust is preserved: who claimed to be where, the evidence supporting that claim, and the spatial relationship the system computed.Raw GeoJSON also works — useful for reference geometries like official boundaries or known landmarks. But raw coordinates carry no proof of origin. The computation is still verified, but the inputs are unverified.
The signed result is portable. Use it directly in your application:
// Agent workflow — branch on the verified spatial answerif (inside.result) { confirmDelivery(inside); // the signed result is the audit trail}// Backend — store as evidenceawait db.insert({ delivery_id, proof: inside });
Or submit it onchain. EAS (the Ethereum Attestation Service) is an open protocol for structured, signed attestations, plus a smart contract to register attestations onchain.Astral’s signed results can be packaged as EAS attestations. EAS supports resolver contracts — smart contracts that execute arbitrary logic when an attestation is created onchain. A verified spatial result can then trigger token transfers, access grants, escrow releases, or any other onchain action. (This is one path among several — most applications use signed results offchain, as in Step 4 above.)
import { ethers } from 'ethers';const wallet = new ethers.Wallet(PRIVATE_KEY, provider);const astral = new AstralSDK({ chainId: 84532, signer: wallet, apiUrl: 'https://staging-api.astral.global'});// Arguments are positional: (geometry, target, radius, options).const result = await astral.compute.within( locationUID, // geometry — the verified location landmarkUID, // target 500, // radius in meters { schema: RESOLVER_SCHEMA_UID, recipient: wallet.address });// Submit to EAS — triggers your resolver contract onchainconst { uid } = await astral.compute.submit({ attestation: result.attestation, delegatedAttestation: result.delegatedAttestation,});console.log('Onchain attestation:', uid);
For the full blockchain flow — writing resolver contracts, registering schemas, chain configuration — see Blockchain Integration.