azimuth-watcher-ts/README.md

9.3 KiB

azimuth-watcher-ts

A comprehensive blockchain indexing and querying system for Azimuth, Urbit's identity layer on Ethereum. This system monitors multiple Ethereum smart contracts that make up the Azimuth PKI and provides a unified GraphQL API for querying Urbit identity information.

What is Azimuth?

Azimuth is Urbit's public key infrastructure (PKI) that lives on Ethereum. It's a set of smart contracts that manage Urbit identities called "points" (similar to usernames), their ownership, cryptographic keys, and hierarchical relationships. Each Urbit identity is represented as an NFT on Ethereum, making it decentralized and censorship-resistant.

What are Blockchain Watchers?

Blockchain watchers are services that continuously monitor smart contracts on Ethereum, index their events and state changes, and provide efficient APIs for querying blockchain data. Instead of directly querying the Ethereum blockchain (which is slow and expensive), applications can query watchers for fast, indexed access to current and historical blockchain state.

System Architecture

This system consists of 8 specialized watchers that each monitor different Azimuth smart contracts:

  • azimuth-watcher - Core identity operations (ownership, keys, sponsorship)
  • censures-watcher - Reputation and censure system
  • claims-watcher - On-chain claims and metadata
  • ecliptic-watcher - Galaxy operations and governance
  • polls-watcher - Voting and governance proposals
  • conditional-star-release-watcher - Conditional star distribution
  • linear-star-release-watcher - Linear star distribution
  • delegated-sending-watcher - Delegated operations

Plus a gateway server that provides a unified GraphQL endpoint routing queries to the appropriate watcher.

Hosted Service

A public instance is available at: https://azimuth.dev.vdb.to/graphql

You can also run the system locally using Stack Orchestrator.

Common Use Cases

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

2. Get Cryptographic Keys for a Point

# Get encryption and authentication keys for networking
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

# Example 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
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

4. Get All Points Owned by an Address

# Find all Urbit points owned by an Ethereum address
curl 'https://azimuth.dev.vdb.to/graphql' \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "query": "{
      azimuthGetOwnedPoints(
        blockHash: \"latest\",
        contractAddress: \"0x223c067F8CF28ae173EE5CafEa60cA44C335fecB\",
        _whose: \"0x1234567890123456789012345678901234567890\"
      ) {
        value
      }
    }"
  }' | jq

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

Available Query Types

Azimuth Watcher (Core Identity Operations)

Point Ownership & Information:

  • azimuthGetOwner - Get point owner address
  • azimuthGetOwnedPoints - Get all points owned by an address
  • azimuthIsActive - Check if point is activated
  • azimuthIsLive - Check if point is online

Cryptographic Keys:

  • azimuthGetKeys - Get encryption/authentication keys
  • azimuthGetKeyRevisionNumber - Get key version number

Sponsorship Hierarchy:

  • azimuthGetSponsor - Get point's sponsor
  • azimuthGetSponsoring - Get points sponsored by a point
  • azimuthHasSponsor - Check if point has sponsor

Proxies & Permissions:

  • azimuthGetManagementProxy - Get management proxy address
  • azimuthCanManage - Check management permissions
  • azimuthGetSpawnProxy - Get spawn proxy address
  • azimuthCanSpawnAs - Check spawn permissions

Other Watchers

Censures - Reputation system queries with prefix censures Claims - Metadata and claims queries with prefix claims Ecliptic - Galaxy operations queries with prefix ecliptic Polls - Governance voting queries with prefix polls Star Release - Token distribution queries with prefixes linearStarRelease and conditionalStarRelease Delegated Sending - Delegation queries with prefix delegatedSending

Multi-Watcher Query Example

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

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

  # Find a claim (claims-watcher)
  claimsFindClaim(blockHash: "latest", contractAddress: "0xe7e7f69b34D7d9Bd8d61Fb22C33b22708947971A", _whose: 1234, _protocol: "text", _claim: "hello world") {
    value
  }
}

## Real-time Updates

Subscribe to blockchain events in real-time:

```graphql
subscription {
  onEvent {
    event {
      __typename
      ... on OwnerChangedEvent {
        point
        owner
      }
      ... on ActivatedEvent {
        point
      }
      ... on ChangedKeysEvent {
        point
        encryptionKey
        authenticationKey
      }
    }
    block {
      hash
      number
      timestamp
    }
  }
}

Development Setup

Prerequisites

  • Node.js 16+
  • PostgreSQL database
  • Ethereum RPC endpoint (or ipld-eth-server)

Quick Start

  1. Clone and install dependencies:

    git clone https://github.com/cerc-io/azimuth-watcher-ts.git
    cd azimuth-watcher-ts
    yarn install
    
  2. Build all packages:

    yarn build
    
  3. Configure environment:

    • Copy packages/azimuth-watcher/environments/local.toml and update database/RPC settings
    • Set up PostgreSQL databases for each watcher
  4. Start the azimuth-watcher:

    cd packages/azimuth-watcher
    yarn server:dev  # GraphQL server
    yarn job-runner:dev  # Blockchain indexer (separate terminal)
    
  5. Start the gateway server (optional):

    cd packages/gateway-server
    yarn server:dev
    

Commands

Build and lint:

yarn build      # Build all packages
yarn lint       # Lint with zero warnings tolerance

Individual watcher operations:

yarn server:dev     # Development GraphQL server
yarn job-runner:dev # Event processing worker
yarn fill          # Backfill historical data
yarn reset         # Reset watcher state
yarn checkpoint    # Create state checkpoint

Architecture Details

Data Flow

  1. Indexing: Job runners continuously fetch Ethereum events and blocks
  2. Processing: Events are processed and state changes stored in PostgreSQL
  3. Querying: GraphQL servers provide indexed data with historical query support
  4. Gateway: Unified endpoint routes queries to appropriate specialized watchers

Storage

  • Each watcher maintains its own PostgreSQL database
  • State is checkpointed periodically for recovery
  • IPLD (Content-addressed storage) support for cryptographic proofs

Generate Watchers

Follow instructions to generate Azimuth watchers using the code generator (@cerc-io/codegen)