Skip to content

Documentation improvements for Location-Gated NFT guide and compute API #7

@johnx25bd

Description

@johnx25bd

Context

While implementing a Location-Gated NFT using the compute system, I encountered several undocumented behaviors that required significant debugging. This issue captures documentation improvements that would help both humans and LLMs implement Astral integrations more easily.

1. Missing Documentation

Topic What's Missing Impact
Operation string format Compute operations return within:RADIUS (e.g., within:100000), not just within Resolver contracts that check operation == "within" will fail
inputRefs format When using raw GeoJSON, inputRefs are content-addressed hashes. When using attestation UIDs, they're the actual UIDs Resolver contracts checking inputRefs[1] == landmarkUID fail when using raw GeoJSON
Schema revocable flag Astral signs delegated attestations with revocable: true. Schemas must be registered with revocable: true to match EAS rejects with Irrevocable() or InvalidSignature() errors
Rate limits 100 requests/hour per IP on the compute API Developers get blocked during testing
Astral signer addresses The TEE signer address per chain (e.g., 0x2376192D7F1B50130f1aC3995Ad610251a06067C on Base Sepolia) Required for resolver contracts to verify attestations

2. Location-Gated NFT Guide Improvements

The guide should include:

Complete Solidity Contract

The current guide's contract needs a helper for operation prefix matching:

// Operation comes as "within:RADIUS", not just "within"
function _startsWith(string memory str, string memory prefix) internal pure returns (bool) {
    bytes memory strBytes = bytes(str);
    bytes memory prefixBytes = bytes(prefix);
    if (strBytes.length < prefixBytes.length) return false;
    for (uint256 i = 0; i < prefixBytes.length; i++) {
        if (strBytes[i] != prefixBytes[i]) return false;
    }
    return true;
}

// Then use: if (!_startsWith(operation, "within")) revert WrongOperation();

Schema Registration Note

// IMPORTANT: Must use revocable: true to match Astral's signing
const tx = await schemaRegistry.register({
  schema: "bool result,bytes32[] inputRefs,uint64 timestamp,string operation",
  resolverAddress: nftContract,
  revocable: true,  // Required - Astral signs with revocable=true
});

inputRefs Explanation

When using raw GeoJSON:
  inputRefs[0] = keccak256(abi.encode(userGeoJSON))  // content hash
  inputRefs[1] = keccak256(abi.encode(targetGeoJSON)) // content hash

When using attestation UIDs:
  inputRefs[0] = userLocationAttestationUID
  inputRefs[1] = targetLocationAttestationUID

Common Errors Section

Error Selector Cause Fix
InvalidSignature() 0x8baa579f revocable mismatch between signed data and submission Use revocable: true in submit
Irrevocable() 0x157bd4c3 Schema registered with revocable: false but attestation has revocable: true Register schema with revocable: true
WrongOperation() Custom Checking operation == "within" but API returns within:100000 Use prefix matching

3. API Reference Improvements

Full Response Examples

Document complete JSON responses for each compute endpoint, including:

  • All fields in the delegatedAttestation object
  • The nonce field and how it relates to EAS
  • The exact format of operation strings

Chain Configuration

A table of per-chain addresses:

| Chain | Chain ID | EAS | Schema Registry | Astral Signer |
|-------|----------|-----|-----------------|---------------|
| Base Sepolia | 84532 | 0x4200...0021 | 0x4200...0020 | 0x2376...067C |

4. LLM-Friendly Improvements

  • Explicit error selectors: List all custom errors with their 4-byte selectors
  • Copy-pasteable code: Complete, runnable scripts rather than fragments
  • Schema UIDs: Pre-registered schema UIDs for common use cases on each chain

This feedback comes from a complete implementation attempt. See the working code at the end of this debugging session for reference.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions