메인 콘텐츠로 건너뛰기
이 섹션에서는 Injective Name Service 컨트랙트를 쿼리하여 .inj 도메인 이름을 확인하고 역방향 조회를 수행하는 방법을 살펴봅니다.

InjNameService 클래스 구현

권장되는 접근 방식은 이름 서비스 기능을 캡슐화하는 자체 InjNameService 클래스를 만드는 것입니다. 이렇게 하면 도메인 확인 및 역방향 조회를 위한 깔끔하고 재사용 가능한 인터페이스가 제공됩니다.

InjNameService 클래스 생성

다음은 애플리케이션에서 사용할 수 있는 완전한 구현입니다:
import {
  Network,
  getNetworkEndpoints,
  getInjNameRegistryContractForNetwork,
  getInjNameReverseResolverContractForNetwork,
} from "@injectivelabs/networks";
import {
  QueryInjName,
  ChainGrpcWasmApi,
  QueryResolverAddress,
  QueryInjectiveAddress,
  InjNameServiceQueryTransformer,
} from "@injectivelabs/sdk-ts/client/wasm";
import { nameToNode, normalizeName } from "@injectivelabs/sdk-ts/utils";

export class InjNameService {
  private reverseResolverAddress: string;
  private registryAddress: string;
  private chainGrpcWasmApi: ChainGrpcWasmApi;

  constructor(network: Network = Network.Mainnet) {
    const endpoints = getNetworkEndpoints(network);
    this.chainGrpcWasmApi = new ChainGrpcWasmApi(endpoints.grpc);
    this.registryAddress = getInjNameRegistryContractForNetwork(network);
    this.reverseResolverAddress =
      getInjNameReverseResolverContractForNetwork(network);
  }

  /**
   * 주어진 Injective 주소에 대한 .inj 이름을 가져옵니다 (역방향 확인)
   * @param address - 확인할 Injective 주소
   * @returns .inj 도메인 이름
   */
  async fetchInjName(address: string): Promise<string> {
    const query = new QueryInjName({ address }).toPayload();

    const response = await this.chainGrpcWasmApi.fetchSmartContractState(
      this.reverseResolverAddress,
      query
    );

    const name =
      InjNameServiceQueryTransformer.injectiveNameResponseToInjectiveName(
        response
      );

    if (!name) {
      throw new Error(`.inj name not found for ${address}`);
    }

    // 이름이 실제로 동일한 주소로 다시 확인되는지 확인하여 역방향 확인 검증
    const addressFromName = await this.fetchInjAddress(name);

    if (addressFromName.toLowerCase() !== address.toLowerCase()) {
      throw new Error(`.inj name not found for ${address}`);
    }

    return name;
  }

  /**
   * 주어진 .inj 도메인 이름에 대한 Injective 주소를 가져옵니다 (정방향 확인)
   * @param name - 확인할 .inj 도메인 이름
   * @returns Injective 주소
   */
  async fetchInjAddress(name: string): Promise<string> {
    const normalizedName = normalizeName(name);
    const node = nameToNode(normalizedName);

    if (!node || node.length === 0) {
      throw new Error(`The ${name} can't be normalized`);
    }

    const resolverAddress = await this.fetchResolverAddress(node);

    if (!resolverAddress) {
      throw new Error(`Resolver address not found for ${name}`);
    }

    const query = new QueryInjectiveAddress({ node }).toPayload();

    const response = await this.chainGrpcWasmApi.fetchSmartContractState(
      resolverAddress,
      query
    );

    const address =
      InjNameServiceQueryTransformer.injectiveAddressResponseToInjectiveAddress(
        response
      );

    if (!address) {
      throw new Error(`Address not found for ${name}`);
    }

    return address;
  }

  /**
   * 주어진 노드에 대한 resolver 주소를 가져옵니다
   * @private
   */
  private async fetchResolverAddress(node: number[]): Promise<string> {
    const query = new QueryResolverAddress({ node }).toPayload();

    const response = await this.chainGrpcWasmApi.fetchSmartContractState(
      this.registryAddress,
      query
    );

    return InjNameServiceQueryTransformer.resolverAddressResponseToResolverAddress(
      response
    );
  }
}

InjNameService 클래스 사용

import { Network } from "@injectivelabs/networks";

// 서비스 초기화
const injNameService = new InjNameService(Network.Mainnet);

// .inj 도메인을 주소로 확인
const address = await injNameService.fetchInjAddress("ninja.inj");
console.log("Address:", address);

// 주소를 .inj 도메인으로 역방향 확인
const name = await injNameService.fetchInjName("inj1...");
console.log("Name:", name);

직접 스마트 컨트랙트 쿼리

추상화 레이어 없이 컨트랙트를 직접 쿼리해야 하거나 더 많은 제어가 필요한 경우 개별 메서드는 다음과 같습니다:

도메인 확인 (정방향 조회)

.inj 도메인 이름을 Injective 주소로 확인합니다.

1단계: Resolver 주소 가져오기

import {
  Network,
  getNetworkEndpoints,
  getInjNameRegistryContractForNetwork,
} from "@injectivelabs/networks";
import { nameToNode, normalizeName } from "@injectivelabs/sdk-ts/utils";
import {
  ChainGrpcWasmApi,
  QueryResolverAddress,
  InjNameServiceQueryTransformer,
} from "@injectivelabs/sdk-ts/client/wasm";

const endpoints = getNetworkEndpoints(Network.Mainnet);
const chainGrpcWasmApi = new ChainGrpcWasmApi(endpoints.grpc);

const registryContractAddress = getInjNameRegistryContractForNetwork(
  Network.Mainnet
);

const name = "ninja.inj";
const normalizedName = normalizeName(name);
const node = nameToNode(normalizedName);

const query = new QueryResolverAddress({ node }).toPayload();

const response = await chainGrpcWasmApi.fetchSmartContractState(
  registryContractAddress,
  query
);

const resolverAddress =
  InjNameServiceQueryTransformer.resolverAddressResponseToResolverAddress(
    response
  );

console.log("Resolver Address:", resolverAddress);

2단계: 도메인의 주소 가져오기

import { Network, getNetworkEndpoints } from "@injectivelabs/networks";
import { nameToNode, normalizeName } from "@injectivelabs/sdk-ts/utils";
import {
  ChainGrpcWasmApi,
  QueryInjectiveAddress,
  InjNameServiceQueryTransformer,
} from "@injectivelabs/sdk-ts/client/wasm";

const endpoints = getNetworkEndpoints(Network.Mainnet);
const chainGrpcWasmApi = new ChainGrpcWasmApi(endpoints.grpc);

const name = "ninja.inj";
const normalizedName = normalizeName(name);
const node = nameToNode(normalizedName);

// 1단계의 resolver 주소 사용
const resolverAddress = "...";

const query = new QueryInjectiveAddress({ node }).toPayload();

const response = await chainGrpcWasmApi.fetchSmartContractState(
  resolverAddress,
  query
);

const injectiveAddress =
  InjNameServiceQueryTransformer.injectiveAddressResponseToInjectiveAddress(
    response
  );

if (!injectiveAddress) {
  throw new Error(`Address not found for ${name}`);
}

console.log("Injective Address:", injectiveAddress);

역방향 확인 (주소에서 도메인으로)

Injective 주소를 기본 .inj 도메인 이름으로 확인합니다.
import {
  Network,
  getNetworkEndpoints,
  getInjNameReverseResolverContractForNetwork,
} from "@injectivelabs/networks";
import {
  QueryInjName,
  ChainGrpcWasmApi,
  InjNameServiceQueryTransformer,
} from "@injectivelabs/sdk-ts/client/wasm";

const endpoints = getNetworkEndpoints(Network.Mainnet);
const chainGrpcWasmApi = new ChainGrpcWasmApi(endpoints.grpc);

const reverseResolverContractAddress =
  getInjNameReverseResolverContractForNetwork(Network.Mainnet);

const injectiveAddress = "inj1...";

const query = new QueryInjName({ address: injectiveAddress }).toPayload();

const response = await chainGrpcWasmApi.fetchSmartContractState(
  reverseResolverContractAddress,
  query
);

const name =
  InjNameServiceQueryTransformer.injectiveNameResponseToInjectiveName(response);

if (!name) {
  throw new Error(`.inj name not found for ${injectiveAddress}`);
}

console.log("INS Name:", name);
중요: 이름이 실제로 원래 주소로 다시 확인되는지 정방향 조회를 수행하여 항상 역방향 확인을 검증하세요. 정방향 확인을 사용한 검증 방법은 다음과 같습니다:
import { Network, getNetworkEndpoints, getInjNameRegistryContractForNetwork } from "@injectivelabs/networks";
import { nameToNode, normalizeName } from "@injectivelabs/sdk-ts/utils";
import {
  ChainGrpcWasmApi,
  QueryResolverAddress,
  QueryInjectiveAddress,
  InjNameServiceQueryTransformer,
} from "@injectivelabs/sdk-ts/client/wasm";

// gRPC 클라이언트 초기화
const endpoints = getNetworkEndpoints(Network.Mainnet);
const chainGrpcWasmApi = new ChainGrpcWasmApi(endpoints.grpc);

// 역방향 확인에서 이름을 얻은 후 다시 확인되는지 검증
const normalizedName = normalizeName(name);
const node = nameToNode(normalizedName);

// resolver 주소 가져오기
const registryContractAddress = getInjNameRegistryContractForNetwork(
  Network.Mainnet
);
const resolverQuery = new QueryResolverAddress({ node }).toPayload();
const resolverResponse = await chainGrpcWasmApi.fetchSmartContractState(
  registryContractAddress,
  resolverQuery
);
const resolverAddress =
  InjNameServiceQueryTransformer.resolverAddressResponseToResolverAddress(
    resolverResponse
  );

// 이름에서 주소 가져오기
const addressQuery = new QueryInjectiveAddress({ node }).toPayload();
const addressResponse = await chainGrpcWasmApi.fetchSmartContractState(
  resolverAddress,
  addressQuery
);
const addressFromName =
  InjNameServiceQueryTransformer.injectiveAddressResponseToInjectiveAddress(
    addressResponse
  );

// 이름이 원래 주소로 다시 확인되는지 검증
if (addressFromName.toLowerCase() !== injectiveAddress.toLowerCase()) {
  throw new Error(
    `Verification failed: ${name} does not resolve back to ${injectiveAddress}`
  );
}
참고: 앞서 보여준 InjNameService 클래스를 사용하는 경우 이 검증을 다음과 같이 단순화할 수 있습니다: await injNameService.fetchInjAddress(name)

모범 사례

  1. 처리하기 전에 항상 도메인 이름을 정규화하세요 - 일관성을 보장합니다
  2. 역방향 확인을 검증하세요 - 이름이 실제로 주소로 다시 확인되는지 정방향 조회를 수행하여 확인합니다
  3. 오류를 우아하게 처리하세요 - 모든 주소에 .inj 이름이 있는 것은 아니며 모든 이름이 등록된 것도 아닙니다
  4. 적절한 네트워크 구성을 사용하세요 - 올바른 네트워크(메인넷 vs 테스트넷)를 쿼리하는지 확인하세요
  5. 적절한 경우 결과를 캐시하세요 - 불필요한 컨트랙트 쿼리를 줄입니다

종속성

Injective Name Service를 사용하려면 다음 패키지가 필요합니다:
{
  "dependencies": {
    "@injectivelabs/sdk-ts": "latest",
    "@injectivelabs/networks": "latest"
  }
}