Skip to main content
The Namespace SDK is a TypeScript library that allows developers to interact with the Namespace API and smart contracts. It abstracts the complexity of different blockchain networks and enables you to mint subnames under activated ENS names.

Prerequisites

  • ENS Name Activation: Your ENS name must be activated on the Namespace platform
  • Node.js: Version 16 or higher
  • TypeScript: Basic understanding of TypeScript
  • Web3 Knowledge: Familiarity with Ethereum and blockchain concepts

Getting Started

1

Activate Your ENS Name

Before you can mint subnames, your parent ENS name must be activated on the Namespace platform. This is a prerequisite for all subname minting operations.

How-to Activate ENS Name

See the step-by-step guide on how to activate an ENS Name.
2

Install Dependencies

Install the required packages in your TypeScript project. The SDK uses Viem under the hood for blockchain interactions.
npm install @thenamespace/mint-manager@latest viem
3

Configure Mint Client

Create and configure an instance of the MintClient with your custom RPC URLs and mint source.
mint-client.ts
import {
  createMintClient,
} from "@thenamespace/mint-manager";
import { base } from "viem/chains";

export const MY_ENS_NAME = "namespace.eth";
const TOKEN = process.env.ALCHEMY_TOKEN;

export const mintClient = createMintClient({
  customRpcUrls: { [base.id]: `https://base-mainnet.g.alchemy.com/v2/${TOKEN}` },
});
Configuration Options:
  • customRpcUrls: Custom RPC endpoints for different networks
  • mintSource: Identifier for your application (used for analytics)
4

Set Up Viem Clients

Create Viem public and wallet clients for blockchain interactions. These will handle reading blockchain state and sending transactions.
web3-client.ts
import { createPublicClient, createWalletClient, http } from "viem";
import { base } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";

const TOKEN = process.env.ALCHEMY_TOKEN;
const WALLET_KEY = process.env.WALLET_PRIVATE_KEY;
const ALCHEMY_RPC = `https://base-mainnet.g.alchemy.com/v2/${TOKEN}`;

export const account = privateKeyToAccount(WALLET_KEY);

export const BASE_ID = base.id;
export const WALLET_ADDRESS = account.address;

export const publicClient = createPublicClient({
  transport: http(ALCHEMY_RPC),
  chain: base,
});

export const walletClient = createWalletClient({
  transport: http(ALCHEMY_RPC),
  chain: base,
  account,
});
Key Components:
  • publicClient: For reading blockchain state and simulating transactions
  • walletClient: For signing and sending transactions
  • wallet: Your account instance for transaction signing
5

Check Subname Availability

Before minting, verify that your desired subname is available on the target network.
check-availability.ts
import { mintClient, BASE_ID } from "./mint-client";

const checkAvailability = async (subnameLabel: string, parentName: string) => {
  const fullName = `${subnameLabel}.${parentName}`;
  const isAvailable = await mintClient.isL2SubnameAvailable(fullName, BASE_ID);
  
  if (!isAvailable) {
    throw new Error(`${fullName} is already taken!`);
  }
  return true;
};
6

Get Mint Details and Pricing

Retrieve detailed information about the minting process, including costs and validation checks.
get-mint-details.ts
import { mintClient, WALLET_ADDRESS, MY_ENS_NAME } from "./mint-client";

const getMintDetails = async (subnameLabel: string) => {
  const mintDetails = await mintClient.getMintDetails({
    minterAddress: WALLET_ADDRESS,
    parentName: MY_ENS_NAME,
    label: subnameLabel,
  });

  if (!mintDetails.canMint) {
    const errorMessage = mintDetails.validationErrors[0] || "Unknown reason";
    throw new Error(`Subname cannot be minted: ${errorMessage}`);
  }

  return mintDetails;
};
What This Provides:
  • Validation that the subname can be minted
  • Estimated costs (base price + network fees)
  • Any validation errors or restrictions
7

Generate Transaction Parameters

Create the transaction parameters needed to mint the subname, including any custom records you want to set.
generate-transaction.ts
import { mintClient, MY_ENS_NAME } from "./mint-client";
import { WALLET_ADDRESS } from "./web3-client";
import { ChainName } from "@thenamespace/mint-manager";

const generateTransaction = async (subnameLabel: string) => {
  const txParameters = await mintClient.getMintTransactionParameters({
    parentName: MY_ENS_NAME,
    label: subnameLabel,
    minterAddress: WALLET_ADDRESS,
    records: {
      texts: [
        { key: "description", value: "My awesome subname" },
        { key: "url", value: "https://example.com" },
      ],
      addresses: [
        { value: WALLET_ADDRESS, chain: ChainName.Base },
        { value: WALLET_ADDRESS, chain: ChainName.Base }
      ],
    },
  });

  return txParameters;
};
Available Record Types:
  • Address Records: Set wallet addresses for different chains
  • Text Records: Add custom metadata like descriptions, websites, social links
8

Simulate and Execute Transaction

Simulate the transaction first to ensure it will succeed, then execute it on the blockchain.
execute-mint.ts
import { publicClient, walletClient, account } from "./web3-client";
import { base } from "viem/chains";
import { generateTransaction } from "./generate-transaction";
import { MY_ENS_NAME } from "./mint-client";

const executeMint = async (subnameLabel: string) => {
  try {
    // Generate transaction parameters
    const txParameters = await generateTransaction(subnameLabel);
    
    // Simulate the transaction
    const { request } = await publicClient.simulateContract({
      address: txParameters.contractAddress,
      args: txParameters.args,
      value: txParameters.value,
      account,
      functionName: txParameters.functionName,
      abi: txParameters.abi,
      chain: base,
    });

    // Execute the transaction
    const transactionHash = await walletClient.writeContract(request);
    return transactionHash;
  } catch (error) {
    console.error("Minting failed:", error);
    throw error;
  }
};
Transaction Flow:
  1. Simulation: Ensures the transaction will succeed before execution
  2. Execution: Sends the transaction to the blockchain
  3. Confirmation: Returns the transaction hash for tracking

Complete Example

Here’s a complete implementation that combines all the steps:
complete-mint-example.ts
import "dotenv/config";
import { createPublicClient, createWalletClient, http } from "viem";
import { base } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";
import { createMintClient, ChainName } from "@thenamespace/mint-manager";

// Parent ENS name to mint subnames under
const MY_ENS_NAME = "namespace.eth";

// Env vars (set these before running)
const ALCHEMY_TOKEN = process.env.ALCHEMY_TOKEN;
const WALLET_PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY as `0x${string}`;

if (!ALCHEMY_TOKEN) {
  throw new Error("Missing ALCHEMY_TOKEN env var");
}
if (!WALLET_PRIVATE_KEY) {
  throw new Error("Missing WALLET_PRIVATE_KEY env var");
}

const ALCHEMY_RPC = `https://base-mainnet.g.alchemy.com/v2/${ALCHEMY_TOKEN}`;

const mintClient = createMintClient({
  customRpcUrls: { [base.id]: ALCHEMY_RPC },
});

// Configure viem clients
const account = privateKeyToAccount(WALLET_PRIVATE_KEY);
const publicClient = createPublicClient({ transport: http(ALCHEMY_RPC), chain: base });
const walletClient = createWalletClient({ transport: http(ALCHEMY_RPC), chain: base, account });

async function mintSubnameOnBaseMainnet(subnameLabel: string) {
  const fullName = `${subnameLabel}.${MY_ENS_NAME}`;

  // 1) Availability check (L2 on Base)
  const isAvailable = await mintClient.isL2SubnameAvailable(fullName, base.id);
  if (!isAvailable) {
    throw new Error(`${fullName} is already taken!`);
  }

  // 2) Get mint details & pricing
  const mintDetails = await mintClient.getMintDetails({
    minterAddress: account.address,
    parentName: MY_ENS_NAME,
    label: subnameLabel,
  });
  if (!mintDetails.canMint) {
    const errorMessage = mintDetails.validationErrors?.[0] || "Unknown reason";
    throw new Error(`Subname cannot be minted: ${errorMessage}`);
  }
  
  // 3) Build transaction parameters (add example records)
  const txParameters = await mintClient.getMintTransactionParameters({
    parentName: MY_ENS_NAME,
    label: subnameLabel,
    minterAddress: account.address,
    records: {
      texts: [
        { key: "description", value: "Minted with Namespace SDK" },
        { key: "url", value: "https://namespace.ninja" },
      ],
      addresses: [
        { value: account.address, chain: ChainName.Base },
      ],
    },
  });

  // 4) Simulate
  const { request } = await publicClient.simulateContract({
    address: txParameters.contractAddress,
    args: txParameters.args,
    value: txParameters.value,
    account,
    functionName: txParameters.functionName,
    abi: txParameters.abi,
    chain: base,
  });

  // 5) Execute
  const txHash = await walletClient.writeContract(request);
  console.log(`✅ Subname ${fullName} minted on Base mainnet`);
  console.log(`🔗 Tx hash: ${txHash}`);
  return { fullName, txHash };
}

async function main() {
  const labelArg = "happy"
  await mintSubnameOnBaseMainnet(labelArg);
}

main().catch((err) => {
  console.error("Minting failed:", err);
  process.exit(1);
});

Environment Variables

Create a .env file with your configuration:
ALCHEMY_TOKEN=your_alchemy_api_token_here
WALLET_PRIVATE_KEY=your_wallet_private_key_here

Error Handling

The SDK provides comprehensive error handling for common scenarios:
  • Subname already taken: Check availability before minting
  • Insufficient funds: Ensure wallet has enough ETH for minting costs
  • Invalid parameters: Validate input parameters before calling SDK methods
  • Network issues: Handle RPC connection failures gracefully

Next Steps