Skip to content

Instantly share code, notes, and snippets.

@crypt0miester
Created May 17, 2025 12:45
Show Gist options
  • Save crypt0miester/20305f7ec99b3dc9e7a9af581fc4de65 to your computer and use it in GitHub Desktop.
Save crypt0miester/20305f7ec99b3dc9e7a9af581fc4de65 to your computer and use it in GitHub Desktop.
Get AllDomains main domains

AllDomains Main Domain API

This README documents the API endpoints for querying main domains by Solana pubkey, both individually and in batch.

Website: https://alldomains.id


Endpoints

1. Get Main Domain for a Single Pubkey

Endpoint:

GET /api/main-domain/[pubkey]

Description: Retrieve the main domain associated with a single Solana pubkey.

Example Request:

curl https://alldomains.id/api/main-domain/2EGGxj2qbNAJNgLCPKca8sxYetyTjnoRspTPjzN2D67

Example Response:

{
  "status": "success",
  "error": null,
  "msg": null,
  "mainDomain": "miester.bonk"
}

Error Response:

{
  "status": "error",
  "error": "Main Domain does not exist",
  "msg": null,
  "mainDomain": null
}

2. Get Main Domains for Multiple Pubkeys (Batch)

Endpoint:

POST /api/main-domain/batch

Description: Retrieve main domains for up to 100 Solana pubkeys in a single request.

Example Request:

curl -X POST https://alldomains.id/api/main-domain/batch \
  -H "Content-Type: application/json" \
  -d '{"pubkeys": ["2EGGxj2qbNAJNgLCPKca8sxYetyTjnoRspTPjzN2D67", "7pYxSDRV6qwSSHAxxJ3MtGUycEenz85rSdmnQTJD73wY"]}'

Example Response:

{
  "status": "success",
  "error": null,
  "msg": null,
  "mainDomains": [
    {
      "pubkey": "2EGGxj2qbNAJNgLCPKca8sxYetyTjnoRspTPjzN2D67",
      "mainDomain": "miester.bonk",
      "nameAccount": "<base58_pubkey>"
    },
    {
      "pubkey": "7pYxSDRV6qwSSHAxxJ3MtGUycEenz85rSdmnQTJD73wY",
      "mainDomain": null,
      "nameAccount": null
    }
  ]
}

Error Response (missing pubkeys):

{
  "status": "error",
  "error": "pubkeys are missing",
  "msg": "Please specify pubkeys. i.e. /api/main-domain/batch",
  "owner": null
}

Error Response (too many pubkeys):

{
  "status": "error",
  "error": "pubkeys length should be less than 100",
  "msg": "Please specify pubkeys. i.e. /api/main-domain/batch",
  "owner": null
}

API Implementation

Single Pubkey Endpoint ([pubkey]/route.ts)

// /app/api/main-domain/[pubkey]/route.ts
import {
  findMainDomain,
  findNameHouse,
  findNftRecord,
  findTldHouse,
  getMintOwner,
  MainDomain,
  NameRecordHeader,
} from "@onsol/tldparser";
import { Connection, PublicKey } from "@solana/web3.js";

export const getMainDomainV2 = async (
  connection: Connection,
  pubkey: string
): Promise<{
  pubkey: string;
  mainDomain: string | undefined;
  nameAccount: PublicKey | undefined;
}> => {
  const mainDomainKey = findMainDomain(new PublicKey(pubkey))[0];
  const mainDomainAccount = await connection.getAccountInfo(mainDomainKey);

  if (!mainDomainAccount?.data) {
    return { pubkey, nameAccount: undefined, mainDomain: undefined };
  }

  const mainDomainData = MainDomain.fromAccountInfo(mainDomainAccount)[0];
  const nameAccount = mainDomainData.nameAccount;

  const nameAccountInfo = await connection.getAccountInfo(nameAccount);
  if (!nameAccountInfo) {
    return { pubkey, nameAccount, mainDomain: undefined };
  }

  const nameAccountData = NameRecordHeader.fromAccountInfo(nameAccountInfo);
  const tld = mainDomainData.tld;
  const [tldHouseKey] = findTldHouse(tld);
  const [nameHouseKey] = findNameHouse(tldHouseKey);
  const [nftRecordKey] = findNftRecord(nameAccount, nameHouseKey);

  // NFT owner check
  if (nameAccountData.owner?.toString() === nftRecordKey.toString()) {
    const mintOwner = await getMintOwner(connection, nftRecordKey);
    if (mintOwner?.toString() !== pubkey) {
      return { pubkey, nameAccount, mainDomain: undefined };
    }
    return {
      pubkey,
      nameAccount,
      mainDomain: mainDomainData.domain + mainDomainData.tld,
    };
  }

  // Name record owner check
  if (nameAccountData.owner?.toString() !== pubkey) {
    return { pubkey, nameAccount, mainDomain: undefined };
  }

  // Expiry check
  const expiresAtIsValid = nameAccountData.expiresAt.getTime() !== 0;
  if (expiresAtIsValid && nameAccountData.expiresAt.getTime() < Date.now()) {
    return { pubkey, nameAccount, mainDomain: undefined };
  }

  return {
    pubkey,
    nameAccount,
    mainDomain: mainDomainData.domain + mainDomainData.tld,
  };
};

Batch Endpoint (batch/route.ts)

// /app/api/main-domain/batch/route.ts
import {
  findMainDomain,
  findNameHouse,
  findNftRecord,
  findTldHouse,
  getMintOwner,
  MainDomain,
  NameRecordHeader,
} from "@onsol/tldparser";
import { AccountInfo, Connection, PublicKey } from "@solana/web3.js";

const getMultipleMainDomains = async (
  connection: Connection,
  pubkeys: string[],
): Promise<{
  pubkey: string;
  mainDomain: string | undefined;
  nameAccount: PublicKey | undefined;
}[]> => {
  const mainDomainKeys = pubkeys.map(
    (pubkey) => findMainDomain(new PublicKey(pubkey))[0],
  );
  const mainDomainAccounts =
    await connection.getMultipleAccountsInfo(mainDomainKeys);
  const mainDomainWithNameAccounts = pubkeys.map((pubkey, index) => {
    const mainDomainAccount = mainDomainAccounts[index];
    if (!!mainDomainAccount?.data) {
      const mainDomainData = MainDomain.fromAccountInfo(mainDomainAccount)[0];
      const nameAccount = mainDomainData.nameAccount;
      return {
        pubkey: pubkey.toString(),
        nameAccount,
        mainDomain: mainDomainData.domain + mainDomainData.tld,
      };
    }
    return {
      pubkey: pubkey.toString(),
      nameAccount: undefined,
      mainDomain: undefined,
    };
  });
  const nameAccounts = mainDomainWithNameAccounts.map(
    (item) => item.nameAccount,
  );
  const filteredNameAccountsWithIndex = nameAccounts
    .map((pk, idx) => (pk ? { pk, idx } : undefined))
    .filter((x): x is { pk: PublicKey; idx: number } => !!x);
  const filteredNameAccounts = filteredNameAccountsWithIndex.map((x) => x.pk);
  const nameAccountsInfo =
    await connection.getMultipleAccountsInfo(filteredNameAccounts);
  const infoByOriginalIdx = new Array<AccountInfo<Buffer> | null>(
    nameAccounts.length,
  ).fill(null);
  filteredNameAccountsWithIndex.forEach((entry, i) => {
    infoByOriginalIdx[entry.idx] = nameAccountsInfo[i];
  });
  const result = await Promise.all(
    mainDomainWithNameAccounts.map(async (item, index) => {
      const nameAccount = item.nameAccount;
      const info = infoByOriginalIdx[index];
      if (!nameAccount || !info) {
        return { ...item };
      }
      const nameAccountData = NameRecordHeader.fromAccountInfo(info);
      const tld = item.mainDomain?.split(".")[1];
      const [tldHouseKey] = findTldHouse(tld);
      const [nameHouseKey] = findNameHouse(tldHouseKey);
      const [nftRecordKey] = findNftRecord(nameAccount, nameHouseKey);
      const isNftRecordOwner =
        nameAccountData.owner?.toString() === nftRecordKey.toString();
      if (isNftRecordOwner) {
        const mintOwner = await getMintOwner(connection, nftRecordKey);
        if (mintOwner?.toString() != pubkeys[index]) {
          return {
            pubkey: pubkeys[index].toString(),
            nameAccount,
            mainDomain: undefined,
          };
        }
        return { ...item };
      }
      if (nameAccountData.owner?.toString() != pubkeys[index]) {
        return {
          pubkey: pubkeys[index].toString(),
          nameAccount,
          mainDomain: undefined,
        };
      }
      const expiresAtIsValid = nameAccountData.expiresAt.getTime() != 0;
      if (
        expiresAtIsValid &&
        nameAccountData.expiresAt.getTime() < Date.now()
      ) {
        return {
          pubkey: pubkeys[index].toString(),
          nameAccount,
          mainDomain: undefined,
        };
      }
      return { ...item };
    }),
  );
  return result;
};

Example Client Code

JavaScript (fetch, single pubkey)

const pubkey = "2EGGxj2qbNAJNgLCPKca8sxYetyTjnoRspTPjzN2D67";
fetch(`https://alldomains.id/api/main-domain/${pubkey}`)
  .then(res => res.json())
  .then(data => {
    if (data.status === "success") {
      console.log("Main domain:", data.mainDomain);
    } else {
      console.error("Error:", data.error);
    }
  });

JavaScript (fetch, batch)

const pubkeys = [
  "2EGGxj2qbNAJNgLCPKca8sxYetyTjnoRspTPjzN2D67",
  "7pYxSDRV6qwSSHAxxJ3MtGUycEenz85rSdmnQTJD73wY"
];
fetch("https://alldomains.id/api/main-domain/batch", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ pubkeys })
})
  .then(res => res.json())
  .then(data => {
    if (data.status === "success") {
      data.mainDomains.forEach(item => {
        console.log(item.pubkey, "=>", item.mainDomain);
      });
    } else {
      console.error("Error:", data.error);
    }
  });

Notes

  • The batch endpoint is limited to 100 pubkeys per request.
  • All endpoints use the same Solana RPC endpoint as configured in the code.

© alldomains.id

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment