Docs

ans_queries

Lookup Aptos Naming Service entries

Coming soon: Need support for this? Email support@dwellir.com and we will enable it for you.

Aptos Name Service (ANS) provides human-readable names for Aptos addresses, similar to DNS for the internet. The GraphQL API enables efficient querying of ANS registrations, allowing applications to resolve names to addresses, lookup reverse mappings, check expiration dates, and manage domain portfolios programmatically.

Overview

ANS transforms complex hexadecimal addresses like 0x1a2b3c... into memorable names like alice.apt, significantly improving user experience. The GraphQL indexer provides indexed access to ANS data, enabling fast lookups for wallet displays, payment systems, social features, and any application needing human-readable identifiers.

Core Query Patterns

Resolve Name to Address

graphql
query ResolveName($name: String!) {
  ans_lookup(where: { name: { _eq: $name } }) {
    name
    address
    expiration_timestamp
    registered_at
    owner
  }
}

Reverse Lookup (Address to Names)

graphql
query AddressToNames($address: String!) {
  ans_lookup(
    where: { address: { _eq: $address } },
    order_by: { registered_at: desc }
  ) {
    name
    expiration_timestamp
    is_primary
  }
}

Check Name Availability

graphql
query CheckAvailability($name: String!) {
  ans_lookup(
    where: {
      name: { _eq: $name },
      expiration_timestamp: { _gt: "now()" }
    }
  ) {
    name
    owner
  }
}

Get Primary Name

graphql
query GetPrimaryName($address: String!) {
  ans_lookup(
    where: {
      address: { _eq: $address },
      is_primary: { _eq: true }
    },
    limit: 1
  ) {
    name
    expiration_timestamp
  }
}

Search Names by Pattern

graphql
query SearchNames($pattern: String!, $limit: Int!) {
  ans_lookup(
    where: { name: { _like: $pattern } },
    order_by: { registered_at: desc },
    limit: $limit
  ) {
    name
    address
    owner
    registered_at
  }
}

Expiring Names

graphql
query ExpiringNames($days: Int!) {
  ans_lookup(
    where: {
      expiration_timestamp: {
        _gte: "now()",
        _lte: "now() + ${days} days"
      }
    },
    order_by: { expiration_timestamp: asc }
  ) {
    name
    address
    expiration_timestamp
  }
}

Real-World Use Cases

  1. Wallet Applications: Display user-friendly names instead of addresses in transaction histories, contact lists, and payment interfaces for improved UX.

  2. Payment Systems: Allow users to send payments to names like "alice.apt" instead of copying long addresses, reducing errors and improving accessibility.

  3. Social Platforms: Enable username-based social features where users can follow, message, or interact with others using memorable names.

  4. Domain Marketplaces: Build platforms for buying, selling, and trading ANS domains with search, filtering, and expiration monitoring.

  5. Portfolio Management: Track domain portfolios, monitor expiration dates, and manage renewal workflows for users with multiple names.

  6. Identity Verification: Use ANS as a lightweight identity system where verified names provide reputation and trust signals.

Best Practices

Cache Resolved Names: ANS data changes infrequently - implement caching with appropriate TTLs to reduce API calls.

Handle Non-Existent Names: Always check for null/empty results when resolving names and provide clear user feedback.

Validate Name Format: Implement client-side name validation (format, length, allowed characters) before querying.

Check Expiration: Always verify expiration_timestamp to ensure names are still active before relying on them.

Support Both Directions: Implement both name-to-address and address-to-name lookups for complete functionality.

Prioritize Primary Names: When an address owns multiple names, prefer displaying the primary name for consistency.

Batch Lookups: When resolving multiple names, batch them into single GraphQL queries for efficiency.

TypeScript Integration

TypeScript
import { ApolloClient, gql } from "@apollo/client";

const client = new ApolloClient({
  uri: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/graphql"
});

async function resolveName(name: string): Promise<string | null> {
  const { data } = await client.query({
    query: gql`
      query ResolveName($name: String!) {
        ans_lookup(where: { name: { _eq: $name } }) {
          address
          expiration_timestamp
        }
      }
    `,
    variables: { name }
  });

  const result = data.ans_lookup[0];
  if (!result) return null;

  const now = Date.now();
  const expiration = new Date(result.expiration_timestamp).getTime();

  return expiration > now ? result.address : null;
}

async function getPrimaryName(address: string): Promise<string | null> {
  const { data } = await client.query({
    query: gql`
      query GetPrimaryName($address: String!) {
        ans_lookup(
          where: {
            address: { _eq: $address },
            is_primary: { _eq: true }
          },
          limit: 1
        ) {
          name
          expiration_timestamp
        }
      }
    `,
    variables: { address }
  });

  const result = data.ans_lookup[0];
  if (!result) return null;

  const now = Date.now();
  const expiration = new Date(result.expiration_timestamp).getTime();

  return expiration > now ? result.name : null;
}

Advanced Queries

Domain Portfolio Analysis

graphql
query PortfolioStats($owner: String!) {
  active: ans_lookup_aggregate(
    where: {
      owner: { _eq: $owner },
      expiration_timestamp: { _gt: "now()" }
    }
  ) {
    aggregate { count }
  }

  expiring_soon: ans_lookup_aggregate(
    where: {
      owner: { _eq: $owner },
      expiration_timestamp: {
        _gt: "now()",
        _lte: "now() + 30 days"
      }
    }
  ) {
    aggregate { count }
  }

  domains: ans_lookup(
    where: { owner: { _eq: $owner } },
    order_by: { expiration_timestamp: asc }
  ) {
    name
    address
    expiration_timestamp
    registered_at
  }
}
graphql
query TrendingNames($hours: Int!) {
  ans_lookup(
    where: {
      registered_at: { _gte: "now() - ${hours} hours" }
    },
    order_by: { registered_at: desc },
    limit: 50
  ) {
    name
    address
    owner
    registered_at
  }
}

Common Patterns

TypeScript
// Display name with fallback to address
function displayName(address: string, ansName?: string | null): string {
  if (ansName) return ansName;
  return `${address.substring(0, 6)}...${address.substring(address.length - 4)}`;
}

// Validate name format
function isValidANSName(name: string): boolean {
  return /^[a-z0-9-]{1,63}\.apt$/.test(name);
}

// Check if name is expired
function isExpired(expirationTimestamp: string): boolean {
  return new Date(expirationTimestamp).getTime() < Date.now();
}