namehash.ts 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. import { concat, hexlify } from "@ethersproject/bytes";
  2. import { nameprep, toUtf8Bytes } from "@ethersproject/strings";
  3. import { keccak256 } from "@ethersproject/keccak256";
  4. import { Logger } from "@ethersproject/logger";
  5. import { version } from "./_version";
  6. const logger = new Logger(version);
  7. const Zeros = new Uint8Array(32);
  8. Zeros.fill(0);
  9. const Partition = new RegExp("^((.*)\\.)?([^.]+)$");
  10. export function isValidName(name: string): boolean {
  11. try {
  12. const comps = name.split(".");
  13. for (let i = 0; i < comps.length; i++) {
  14. if (nameprep(comps[i]).length === 0) {
  15. throw new Error("empty")
  16. }
  17. }
  18. return true;
  19. } catch (error) { }
  20. return false;
  21. }
  22. export function namehash(name: string): string {
  23. /* istanbul ignore if */
  24. if (typeof(name) !== "string") {
  25. logger.throwArgumentError("invalid ENS name; not a string", "name", name);
  26. }
  27. let current = name;
  28. let result: string | Uint8Array = Zeros;
  29. while (current.length) {
  30. const partition = current.match(Partition);
  31. if (partition == null || partition[2] === "") {
  32. logger.throwArgumentError("invalid ENS address; missing component", "name", name);
  33. }
  34. const label = toUtf8Bytes(nameprep(partition[3]));
  35. result = keccak256(concat([result, keccak256(label)]));
  36. current = partition[2] || "";
  37. }
  38. return hexlify(result);
  39. }
  40. export function dnsEncode(name: string): string {
  41. return hexlify(concat(name.split(".").map((comp) => {
  42. // We jam in an _ prefix to fill in with the length later
  43. // Note: Nameprep throws if the component is over 63 bytes
  44. const bytes = toUtf8Bytes("_" + nameprep(comp));
  45. bytes[0] = bytes.length - 1;
  46. return bytes;
  47. }))) + "00";
  48. }