zenith-docs/docs/api/azimuth-watcher.md
2025-11-28 15:34:21 -05:00

8.9 KiB

Azimuth Watcher API

The Azimuth Watcher monitors Urbit's Azimuth identity registry on Ethereum, providing access to point ownership, sponsorship relationships, and identity state changes.

GraphQL Endpoint: https://azimuth-watcher.zenith-test.tlon.systems/graphql

Querying Urbit Point Information

The azimuth-watcher is the primary service for querying Urbit identity data. Here are the most common operations:

1. Get Point Owner and Basic Info

Check who owns a specific Urbit point:

# Example:
curl 'https://azimuth.dev.vdb.to/graphql' \
  -H 'Content-Type: application/json' \
  --data-raw '{"query":"{ azimuthGetOwner(blockHash: \"latest\", contractAddress: \"0x223c067F8CF28ae173EE5CafEa60cA44C335fecB\", _point: 1234) { value } }"}' \
  | jq

Response:

{
  "data": {
    "azimuthGetOwner": {
      "value": "0x4b22764F2Db640aB4d0Ecfd0F84344F3CB5C3715"
    }
  }
}

2. Get Cryptographic Keys for a Point

Get encryption and authentication keys for networking:

# Example:
curl 'https://azimuth.dev.vdb.to/graphql' \
  -H 'Content-Type: application/json' \
  --data-raw '{"query":"{ azimuthGetKeys(blockHash: \"latest\", contractAddress: \"0x223c067F8CF28ae173EE5CafEa60cA44C335fecB\", _point: 58213) { value { encryptionKey: value0 authenticationKey: value1 cryptoSuiteVersion: value2 keyRevisionNumber: value3 } } }"}' \
  | jq

Response:

{
  "data": {
    "azimuthGetKeys": {
      "value": {
        "encryptionKey": "0xc248f759474b16192bd8bdca0bff1b8bff555cd3d118022095331d6d98690c6d",
        "authenticationKey": "0x21188bac08542730e1c4697636d6fa25968f404470ccf917756f05e28c69045a",
        "cryptoSuiteVersion": "1",
        "keyRevisionNumber": "1"
      }
    }
  }
}

3. Check Point Status

Check if a point is active (booted) and has a sponsor:

# Example:
curl 'https://azimuth.dev.vdb.to/graphql' \
  -H 'Content-Type: application/json' \
  --data-raw '{"query":"{ azimuthIsActive(blockHash: \"latest\", contractAddress: \"0x223c067F8CF28ae173EE5CafEa60cA44C335fecB\", _point: 1234) { value } azimuthHasSponsor(blockHash: \"latest\", contractAddress: \"0x223c067F8CF28ae173EE5CafEa60cA44C335fecB\", _point: 1234) { value } azimuthGetSponsor(blockHash: \"latest\", contractAddress: \"0x223c067F8CF28ae173EE5CafEa60cA44C335fecB\", _point: 1234) { value } }"}' \
  | jq

Response:

{
  "data": {
    "azimuthIsActive": {
      "value": true
    },
    "azimuthHasSponsor": {
      "value": true
    },
    "azimuthGetSponsor": {
      "value": "210"
    }
  }
}

4. Get All Points Owned by an Address

Find all Urbit points owned by an Ethereum address:

# Example:
curl 'https://azimuth.dev.vdb.to/graphql' \
  -H 'Content-Type: application/json' \
  --data-raw '{"query":"{ azimuthGetOwnedPoints(blockHash: \"latest\", contractAddress: \"0x223c067F8CF28ae173EE5CafEa60cA44C335fecB\", _whose: \"0x1234567890123456789012345678901234567890\") { value } }"}' \
  | jq

Response:

{
  "data": {
    "azimuthGetOwnedPoints": {
      "value": [
        "57965",
        "1234"
      ]
    }
  }
}

5. Multi-Watcher Queries

The gateway server allows querying multiple watchers in a single request:

{
  # Check point status (azimuth-watcher)
  azimuthIsActive(
    blockHash: "0x2461e78f075e618173c524b5ab4309111001517bb50cfd1b3505aed5433cf5f9"
    contractAddress: "0x223c067F8CF28ae173EE5CafEa60cA44C335fecB"
    _point: 1
  ) {
    value
  }

  # Check censure count (censures-watcher)
  censuresGetCensuredByCount(
    blockHash: "0x2461e78f075e618173c524b5ab4309111001517bb50cfd1b3505aed5433cf5f9"
    contractAddress: "0x325f68d32BdEe6Ed86E7235ff2480e2A433D6189"
    _who: 6054
  ) {
    value
  }

  # Find a claim (claims-watcher)
  claimsFindClaim(
    blockHash: "0x2461e78f075e618173c524b5ab4309111001517bb50cfd1b3505aed5433cf5f9"
    contractAddress: "0xe7e7f69b34D7d9Bd8d61Fb22C33b22708947971A"
    _whose: 1967913144
    _protocol: "text"
    _claim: "Shrek is NOT Drek!"
  ) {
    value
  }

  # Check star release balance (linear-star-release-watcher)
  linearStarReleaseVerifyBalance(
    blockHash: "0x2461e78f075e618173c524b5ab4309111001517bb50cfd1b3505aed5433cf5f9"
    contractAddress: "0x86cd9cd0992F04231751E3761De45cEceA5d1801"
    _participant: "0xbD396c580d868FBbE4a115DD667E756079880801"
  ) {
    value
  }

  # Check conditional star release (conditional-star-release-watcher)
  conditionalStarReleaseWithdrawLimit(
    blockHash: "0x2461e78f075e618173c524b5ab4309111001517bb50cfd1b3505aed5433cf5f9"
    contractAddress: "0x8C241098C3D3498Fe1261421633FD57986D74AeA"
    _participant: "0x7F0584938E649061e80e45cF88E6d8dDDb22f2aB"
    _batch: 2
  ) {
    value
  }

  # Check governance proposals (polls-watcher)
  pollsGetUpgradeProposalCount(
    blockHash: "0xeaf611fabbe604932d36b97c89955c091e9582e292b741ebf144962b9ff5c271"
    contractAddress: "0x7fEcaB617c868Bb5996d99D95200D2Fa708218e4"
  ) {
    value
  }

  # Check NFT balance (ecliptic-watcher)
  eclipticBalanceOf(
    blockHash: "0x5e82abbe6474caf7b5325022db1d1287ce352488b303685493289770484f54f4"
    contractAddress: "0x33EeCbf908478C10614626A9D304bfe18B78DD73"
    _owner: "0x4b5E239C1bbb98d44ea23BC9f8eC7584F54096E8"
  ) {
    value
  }

  # Check delegation permissions (delegated-sending-watcher)
  delegatedSendingCanSend(
    blockHash: "0x2461e78f075e618173c524b5ab4309111001517bb50cfd1b3505aed5433cf5f9"
    contractAddress: "0xf6b461fE1aD4bd2ce25B23Fe0aff2ac19B3dFA76"
    _as: 1
    _point: 1
  ) {
    value
  }
}

Understanding Query Parameters

All queries require these standard parameters:

  • blockHash: Use "latest" for current state, or a specific block hash for historical queries
  • contractAddress: Azimuth contract address (0x223c067F8CF28ae173EE5CafEa60cA44C335fecB)
  • _point: The Urbit point number you're querying
  • _whose: Ethereum address when querying by owner

How It Works

Data Source

The watchers continuously monitor Ethereum smart contracts by connecting to Ethereum RPC endpoint(s), indexing blockchain events and state changes.

Data Flow

  1. Indexing: Job runners fetch Ethereum events and blocks from RPC endpoint(s)
  2. Processing: Events are processed and state changes stored in PostgreSQL databases
  3. Querying: GraphQL servers provide fast, indexed access to current and historical blockchain state
  4. Gateway: Unified endpoint routes queries to appropriate specialized watchers

Storage

Each watcher maintains its own PostgreSQL database for efficient querying and data isolation.

Additional Query Examples

Query Point Information

query GetPoint($point: String!) {
  point(id: $point) {
    id
    owner
    sponsor
    keyRevisionNumber
    managementProxy
    spawnProxy
    votingProxy
    transferProxy
    active
    escapeRequested
    escapeRequestedTo
  }
}

Query Point History

query GetPointHistory($point: String!) {
  point(id: $point) {
    id
    transfers {
      timestamp
      from
      to
      blockNumber
    }
    spawns {
      timestamp
      child
      blockNumber
    }
  }
}

Query Multiple Points

query GetPoints($owner: String!) {
  points(where: { owner: $owner }) {
    id
    owner
    sponsor
    active
  }
}

Using the GraphQL API

With curl

# Query Azimuth Watcher
curl -X POST https://azimuth-watcher.zenith-test.tlon.systems/graphql \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { point(id: \"~sampel-palnet\") { owner sponsor } }"
  }'

With JavaScript/TypeScript

const query = `
  query GetPoint($point: String!) {
    point(id: $point) {
      owner
      sponsor
      active
    }
  }
`;

const variables = { point: "~sampel-palnet" };

const response = await fetch('https://azimuth-watcher.zenith-test.tlon.systems/graphql', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ query, variables })
});

const data = await response.json();

With GraphQL Client Libraries

import { GraphQLClient } from 'graphql-request';

const client = new GraphQLClient(
  'https://azimuth-watcher.zenith-test.tlon.systems/graphql'
);

const query = `
  query GetPoint($point: String!) {
    point(id: $point) {
      owner sponsor active
    }
  }
`;

const data = await client.request(query, { point: '~sampel-palnet' });

Rate Limiting and Best Practices

  • Rate Limits: Public watcher endpoints have rate limiting in place. For production applications, consider running your own watcher instances.
  • Pagination: Use pagination parameters for queries that return large result sets.
  • Caching: Cache frequently accessed data to reduce API load.
  • Error Handling: Implement proper error handling and retry logic for network failures.

!!! note "Watcher Documentation" For more information about the watcher architecture and deployment, see the Watchers documentation.