Movement Labs LogoMovement Docs

Movement Name Service

Integrate the Movement Name Service (MNS) into your dApp for .move domain registration, resolution, and management.

Movement Name Service

The Movement Name Service is currently live on testnet only. The URL and contract addresses will change when it launches on mainnet. The current testnet app is available at movement-name-service-website-git-redesign-movement-labs.vercel.app.

The Movement Name Service (MNS) allows users to register .move domain names as NFTs that serve as a universal identity across the Movement ecosystem. Each .move name resolves to a blockchain address and can be set as a primary name for reverse lookups.

SDK Integration

MNS functionality is built into the Movement TypeScript SDK. All name service methods are accessible through the movement client instance.

Installation

npm install @moveindustries/ts-sdk

Setup

import { Movement, MovementConfig, Network } from "@moveindustries/ts-sdk";

const config = new MovementConfig({
  network: Network.TESTNET,
});
const movement = new Movement(config);

Domain Registration

Check Price and Availability

const name = "mydomain";

const price = await movement.getDomainPrice({ name, years: 1 });
console.log(`Registration cost: ${Number(price) / 1e8} MOVE`);

const available = await movement.canRegister({ name });
console.log(`Available: ${available}`);

Register a Domain

const txn = await movement.registerName({
  name: "mydomain.move",
  sender: account,
  expiration: { policy: "domain" },
});

Renew a Domain

await movement.renewDomain({
  name: "mydomain.move",
  sender: account,
  years: 1,
});

Name Resolution

Resolve Name to Address

const address = await movement.getTargetAddress({ name: "mydomain.move" });
console.log(`Address: ${address}`);

Reverse Lookup (Address to Primary Name)

const name = await movement.getPrimaryName({
  address: "0x123...",
});
console.log(`Primary name: ${name}`);

Get All Names for an Address

const names = await movement.getAccountNames({
  accountAddress: "0x123...",
});
console.log(names);

Name Management

Set Target Address

Configure which address a name resolves to:

await movement.setTargetAddress({
  sender: account,
  name: "mydomain.move",
  address: targetAddress,
});

Clear Target Address

await movement.clearTargetAddress({
  sender: account,
  name: "mydomain.move",
});

Set Primary Name

Designate a name as the primary identity for your account:

await movement.setPrimaryName({
  sender: account,
  name: "mydomain.move",
});

Check Ownership

const isOwner = await movement.isNameOwner({
  name: "mydomain.move",
  address: account.accountAddress,
});

Additional Methods

MethodDescription
getNameFetch metadata for a specific name
getOwnerAddressGet the owner of a domain
getExpirationGet the expiration timestamp for a domain
getAccountDomainsList all domains owned by an address
getTokenAddressGet the NFT token address for a domain

Indexer Queries

You can query MNS data directly using the Movement indexer GraphQL API. The testnet endpoint is:

https://indexer.testnet.movementnetwork.xyz/v1/graphql

You can explore and test queries interactively using the GraphiQL explorer.

Schema

The current_aptos_names table contains all MNS name records with the following fields:

FieldTypeDescription
domainStringThe domain name (without suffix)
domain_with_suffixStringFull domain name (e.g. mydomain.move)
owner_addressStringAddress that owns the name NFT
registered_addressStringAddress the name resolves to
is_primaryBooleanWhether this is the primary name for the address
is_activeBooleanWhether the name is currently active
expiration_timestamptimestampWhen the domain registration expires
subdomainStringSubdomain portion if applicable
token_standardStringToken standard (v2)
last_transaction_versionbigintLast transaction that modified this record

Lookup a Domain by Name

{
  current_aptos_names(
    where: { domain: { _eq: "mydomain" }, is_active: { _eq: true } }
  ) {
    domain
    domain_with_suffix
    owner_address
    registered_address
    is_primary
    expiration_timestamp
  }
}

Get All Names Owned by an Address

{
  current_aptos_names(
    where: {
      owner_address: { _eq: "0x..." }
      is_active: { _eq: true }
    }
  ) {
    domain
    domain_with_suffix
    is_primary
    registered_address
    expiration_timestamp
  }
}

Get Primary Name for an Address

{
  current_aptos_names(
    where: {
      registered_address: { _eq: "0x..." }
      is_primary: { _eq: true }
      is_active: { _eq: true }
    }
  ) {
    domain
    domain_with_suffix
    owner_address
  }
}

Count All Active Names

{
  current_aptos_names_aggregate(
    where: { is_active: { _eq: true } }
  ) {
    aggregate {
      count
    }
  }
}

Using the Indexer in TypeScript

const INDEXER_URL = "https://indexer.testnet.movementnetwork.xyz/v1/graphql";

async function getNamesByOwner(ownerAddress: string) {
  const query = `
    query GetNamesByOwner($owner: String!) {
      current_aptos_names(
        where: {
          owner_address: { _eq: $owner }
          is_active: { _eq: true }
        }
      ) {
        domain
        domain_with_suffix
        is_primary
        registered_address
        expiration_timestamp
      }
    }
  `;

  const response = await fetch(INDEXER_URL, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      query,
      variables: { owner: ownerAddress },
    }),
  });

  const { data } = await response.json();
  return data.current_aptos_names;
}