All files / ethers.js/src.ts/hash namehash.ts

100% Statements 101/101
89.47% Branches 17/19
100% Functions 6/6
100% Lines 101/101

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 1021x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 42668x 42668x 42668x 42668x 1x 75014x 75014x 75014x 75014x 75014x 42570x 42570x 75014x 785241x 785241x 785241x 785241x 98x 98x 98x 785241x 42570x 42570x 42570x 42570x 42570x 42570x 42570x 1x 1x 1x 1x 1x 75014x 75014x 75014x 75014x 32444x 32444x 75014x 1x 1x 1x 1x 1x 37488x 37488x 37488x 16222x 16222x 1x 1x 1x 1x 1x 37521x 37521x 37521x 37521x 37521x 37521x 37521x 37521x 21372x 21372x 21297x 21297x 21297x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x 7x 7x 7x 13x 13x 13x 13x 13x 13x 7x 7x  
 
import { keccak256 } from "../crypto/index.js";
import {
    concat, hexlify, assertArgument, toUtf8Bytes
} from "../utils/index.js";
 
 
import { ens_normalize } from "@adraffy/ens-normalize";
 
const Zeros = new Uint8Array(32);
Zeros.fill(0);
 
function checkComponent(comp: Uint8Array): Uint8Array {
    assertArgument(comp.length !== 0, "invalid ENS name; empty component", "comp", comp)
    return comp;
}
 
function ensNameSplit(name: string): Array<Uint8Array> {
    const bytes = toUtf8Bytes(ensNormalize(name));
    const comps: Array<Uint8Array> = [ ];
 
    if (name.length === 0) { return comps; }
 
    let last = 0;
    for (let i = 0; i < bytes.length; i++) {
        const d = bytes[i];
 
        // A separator (i.e. "."); copy this component
        if (d === 0x2e) {
            comps.push(checkComponent(bytes.slice(last, i)));
            last = i + 1;
        }
    }
 
    // There was a stray separator at the end of the name
    assertArgument(last < bytes.length, "invalid ENS name; empty component", "name", name);
 
    comps.push(checkComponent(bytes.slice(last)));
    return comps;
}
 
/**
 *  Returns the ENS %%name%% normalized.
 */
export function ensNormalize(name: string): string {
    try {
        if (name.length === 0) { throw new Error("empty label"); }
        return ens_normalize(name);
    } catch (error: any) {
        assertArgument(false, `invalid ENS name (${ error.message })`, "name", name);
    }
}
 
/**
 *  Returns ``true`` if %%name%% is a valid ENS name.
 */
export function isValidName(name: string): name is string {
    try {
        return (ensNameSplit(name).length !== 0);
    } catch (error) { }
    return false;
}
 
/**
 *  Returns the [[link-namehash]] for %%name%%.
 */
export function namehash(name: string): string {
    assertArgument(typeof(name) === "string", "invalid ENS name; not a string", "name", name);
 
    assertArgument(name.length, `invalid ENS name (empty label)`, "name", name);
 
    let result: string | Uint8Array = Zeros;
 
    const comps = ensNameSplit(name);
    while (comps.length) {
        result = keccak256(concat([ result, keccak256(<Uint8Array>(comps.pop()))] ));
    }
 
    return hexlify(result);
}
 
/**
 *  Returns the DNS encoded %%name%%.
 *
 *  This is used for various parts of ENS name resolution, such
 *  as the wildcard resolution.
 */
export function dnsEncode(name: string, _maxLength?: number): string {
    const length = (_maxLength != null) ? _maxLength: 63;
 
    assertArgument(length <= 255, "DNS encoded label cannot exceed 255", "length", length);
 
    return hexlify(concat(ensNameSplit(name).map((comp) => {
        assertArgument(comp.length <= length, `label ${ JSON.stringify(name) } exceeds ${ length } bytes`, "name", name);
 
        const bytes = new Uint8Array(comp.length + 1);
        bytes.set(comp, 1);
        bytes[0] = bytes.length - 1;
        return bytes;
    }))) + "00";
}