Skip to content

Latest commit

 

History

History
1043 lines (650 loc) · 28.8 KB

README.md

File metadata and controls

1043 lines (650 loc) · 28.8 KB

@namehash/ens-utils

NPM Version

This repository contains all of the code for the NPM package @namehash/ens-utils that exports functions for parsing names, handling currency, numbers, prices, and time.

Module Description
nameparser Offers a way to process and normalize string inputs conform to the expected ENS name format configured.
currency Especially useful in applications dealing with financial transactions, crypto assets, or any domain where currency representation and conversion are crucial.
number Utility functions for converting between different numeric formats (string, Decimal, number, and bigint) and for performing approximate scaling of bigint values.
price This module provides a robust foundation for handling monetary values within a financial application, offering flexibility for currency operations, conversions, and formatting.
time Includes functions for time manipulation, formatting, and calculation.

Local Development

You must clone this respository, and install the dependencies using PNPM before you can run it locally:

  1. git clone https://github.com/namehash/ens-utils.git
  2. cd ens-utils
  3. pnpm install
  4. pnpm dev

Tests are automatically ran when a new Pull Request is opened. You can run them locally using pnpm test.

If you're developing locally, you can watch changes and run tests automatically using pnpm test:watch.

Continuous Deployment

This uses conventional commits to automatically trigger new releases to NPM on merge to main. Make sure the pull request contains a prefix.

We use Semantic Release in CI to check commits, and release a new version on NPM, tag on GitHub, and reply to any Pull Requests that they have been included in the version.

Install

npm install @namehash/ens-utils

NameParser

ENS names are crucial in the Ethereum ecosystem, serving as human-readable addresses that map to Ethereum addresses. However, user input can be unpredictable and may not always conform to the expected ENS name format.

The Name Parser module offers a way to process and normalize these inputs into a consistent format, applying transformations such as trimming whitespace, normalizing names, and appending assumed TLDs when necessary, helping user handle labels and name hashes.

It utilizes the @adraffy/ens-normalize library for normalization purposes.

Constants

The module defines several constants for use within the ENS ecosystem, such as:

LABEL_SEPARATOR

The character used to separate labels in an ENS name.

export const LABEL_SEPARATOR = ".";

ETH_TLD

The top-level domain for Ethereum names (eth).

export const ETH_TLD = "eth";

MIN_ETH_REGISTRABLE_LABEL_LENGTH

The minimum length of a label that can be registered under .eth.

export const MIN_ETH_REGISTRABLE_LABEL_LENGTH = 3;

Interfaces and Types

NameParserOptions

This interface defines the configuration options for the name parser.

Property Type Description
trimWhitespace boolean Whether to remove leading and trailing whitespace characters.
attemptEnsNormalization boolean Whether to attempt ENS normalization on the input. Uses ens_normalize for this purpose.
assumedTld string | null An optional label to be added as an assumed top-level domain. If null, disables any assumed TLD.

NameParserTransformation

A union type representing the types of transformations that can be performed on the input name.

type NameParserTransformation =
  | "trim_whitespace"
  | "assume_tld"
  | "ens_normalize";

ParsedName

This interface represents the result of parsing a name from user input.

Property Type Description
inputName string The original user input.
outputName ENSName The parsed and transformed ENS name.
transformations NameParserTransformation[] A list of transformations that were applied to the input name to construct the output name.

Normalization

The Normalization type represents the normalization status of an ENS name or label. It can be one of the following:

  • normalized: The name or label is normalized.
  • unnormalized: The name or label is not normalized.
  • unknown: The normalization status of the name or label is unknown.
export type Normalization =
  | "normalized" /** `normalized`: The name or label is normalized. */
  | "unnormalized" /** `unnormalized`: The name or label is not normalized. */
  | "unknown" /** `unknown`: The name or label is unknown because it cannot be looked up from its hash. */;

NamespaceRoot

The NamespaceRoot type identifies the root namespace of an ENS name, which can be:

  • ens: For names ending in .eth and the ENS root.
  • dns: For names belonging to the DNS namespace.
  • unknown: For names with an undetermined namespace root.
export type NamespaceRoot =
  | "ens" /** For now: Only given to names ending in "eth" and the ENS root */
  | "dns"
  | "unknown"; /** For now: Used for all other cases. Future enhancements will make this more specific. */

RegistrationPotential

The RegistrationPotential type indicates whether an ENS name is registrable, and it can be one of:

  • unregisterable: Direct subnames of .eth not long enough for current contracts.
  • invalid: Names are technically registerable but unnormalized.
  • registerable: Names that are eligible for registration.
  • unknown: Names with an undetermined registration potential.
export type RegistrationPotential =
  | "unregisterable" /** For now: Only given to direct subnames of .eth that are not long enough for current ETHRegistrarController contracts */
  | "invalid" /** Invalid names are technically registerable, but are unnormalized and should not be registered. */
  | "registerable"
  | "unknown"; /** For now: Used for all other cases. Future enhancements will make this more specific. */

DecentralizationStatus

The DecentralizationStatus type describes the decentralization status of an ENS name:

  • unruggable: Names guaranteed to be decentralized.
  • icann: Names under the jurisdiction of ICANN.
  • unknown: Names with an unknown decentralization status.
export type DecentralizationStatus =
  | "unruggable" /** For now: Only given to direct subnames of .eth, the name "eth", and the ENS root. */
  | "icann"
  | "unknown"; /** For now: Used for all other cases. Future enhancements will make this more specific. */

ENSName Interface

The ENSName interface represents an ENS name, including its labels, display name, and normalization status.

interface ENSName {
  name: string;
  labels: string[];
  displayName: string;
  displayLabels: string[];
  normalization: Normalization;
}

Functions

trimOuterWhitespace

Trims leading and trailing whitespace from each label in an array of labels.

Parameters

  • labels: The array of labels to trim the whitespaces from (string[]).

Returns

  • string[] - The array of labels without leading and trailing whitespaces.

assumeTld

Appends an assumed TLD to the last label if necessary, based on the configuration.

Parameters

  • labels: The array of labels to trim the whitespaces from (string[]).
  • assumedTld: An optional label to be added as an assumed top-level domain. (string).

Returns

  • string[] - The array of labels with TLD appended.

parseName

The main function that takes an input name and options, applying configured transformations to parse the name into a standardized ENS name format.

Parameters

  • inputName: The input name to be parsed (string).
  • options: The configured transformations to parse the name into a standardized ENS name format. (NameParserOptions | undefined).

Returns

  • ParsedName - This interface represents the result of parsing a name from user input.
Example
import { parseName } from "./nameparser";

const options = {
  trimWhitespace: true,
  attemptEnsNormalization: true,
  assumedTld: "eth",
};

const { inputName, outputName, transformations } = parseName(
  " example.eth ",
  options
);

This example demonstrates how to use the parseName function with the NameParserOptions to parse and normalize an ENS name input. The output would be a ParsedName object with the original input, the processed ENS name, and the transformations applied.

labelhash

Computes the Keccak-256 hash of a provided label.

Parameters

  • label: The text label to hash.

Returns

  • Keccak-256 hash of the label as a hexadecimal string.

Example

const hashedLabel = labelhash("example");
console.log(hashedLabel); // Outputs the Keccak-256 hash of "example"

isKeccak256Hash

Validates if a given string is a properly formatted Keccak-256 hash.

Parameters

  • hash: The hash string to validate.

Returns

  • true if the hash is a valid Keccak-256 hash, otherwise false.

encodeLabelhash

Encodes a given labelhash into a specific format, denoted by square brackets.

Parameters

  • labelhash: The labelhash value to encode.

Returns

  • The encoded labelhash.

decodeEncodedLabelhash

Decodes an encoded labelhash, extracting the original labelhash value.

Parameters

  • encodedLabelhash: The encoded labelhash to decode.

Returns

  • The labelhash value of the encoded labelhash.

isEncodedLabelhash

Checks if a label contains an encoded labelhash.

Parameters

  • label: The label to evaluate.

Returns

  • true if the label contains an encoded labelhash, otherwise false.

normalizeKeccak256Hash

Normalizes a Keccak-256 hash to a consistent format, addressing prefix presence and letter casing.

Parameters

  • hash: The hash to normalize.
  • withPrefix: Whether to include the "0x" prefix in the normalized hash.

Returns

  • A normalized Keccak-256 hash.

Throws: Error if the hash is not a valid Keccak-256 hash.

normalizeEncodedLabelhash

Normalizes an encoded labelhash to a standard format, ensuring the labelhash component is properly normalized.

Parameters

  • label: The label containing an encoded labelhash to normalize.

Returns A normalized encoded labelhash.

More important functions

Label Operations

  • labelsEqual(labels1: string[], labels2: string[]): Checks if two sets of labels are equal.
  • getDisplayLabels(labels: string[]): Converts labels into a display-optimized form.
  • tryNormalize(labels: string[]): Attempts to normalize a set of labels.

ENS Name Operations

  • buildENSName(name: string): Builds an ENSName object from a string name.
  • getNamespaceRoot(name: ENSName): Identifies the namespace root of a name.
  • getDecentralizationStatus(name: ENSName): Identifies the decentralization status of a name.
  • getRegistrationPotential(name: ENSName): Identifies the registration potential of a name.

Utility Functions

  • isValidDNSTld(label: string): Identifies if a label represents a valid TLD in the DNS namespace.
  • ethRegistrarControllerLength(label: string): Calculates the length of a label as determined by the EthRegistrarController smart contracts.

Currency

The Currency module provides solutions for managing different currencies, their display rules and configurations within a software application. It is especially useful in applications dealing with financial transactions, crypto assets, or any domain where currency representation and conversion are crucial.

Enums

Currency

Defines the supported currencies with their string representations.

export enum Currency {
  Dai = "DAI",
  Eth = "ETH",
  Usd = "USD",
  Usdc = "USDC",
  Weth = "WETH",
  Gas = "GAS",
}

CurrencyDisplayRule

Specifies the rules for displaying currencies.

export enum CurrencyDisplayRule {
  NativeCurrency = "NativeCurrency",
  PreferredCurrency = "PreferredCurrency",
}

Types

SupportedPreferredCurrencies

A type that narrows down the Currency enum to only include Usd and Eth as the supported preferred currencies.

export type SupportedPreferredCurrencies = Currency.Usd | Currency.Eth;

CurrencyConfig

Defines the configuration for each currency including symbols, acronyms, decimals, and other display-related settings.

export interface CurrencyConfig {
  Symbol: string;
  Acronym: string;
  Decimals: bigint;
  DisplayDecimals: bigint;
  UnitOfMeasure: string;
  MaxDisplayValue: number;
  MinDisplayValue: number;
  OverflowDisplayPrice: string;
  ExtendedCurrencyNameSingular: string;
  ExtendedCurrencyNamePlural: string;
  OneUnitOfCurrency: string;
}

Constants

DEFAULT_PREFERRED_CURRENCY

Defines the default preferred currency as Currency.Usd.

export const DEFAULT_PREFERRED_CURRENCY = Currency.Usd;

PriceCurrencyFormat

A record mapping each Currency to its CurrencyConfig.

Example

import type { Currency, CurrencyConfig } from "@namehash/ens-utils";

export const PriceCurrencyFormat: Record<Currency, CurrencyConfig> = {
  /* Configuration for each currency */
};

Functions

getPrimaryDisplayCurrency

Determines the primary display currency based on the provided display rule, preferred currency, and native currency.

Parameters

  • rule: The display rule to apply (CurrencyDisplayRule).
  • preferredCurrency: The preferred currency (Currency).
  • nativeCurrency: The native currency (Currency).

Returns

  • Currency - The determined primary display currency.

getAlternateDisplayCurrency

Determines the alternate display currency based on the provided display rule, preferred currency, and native currency.

Parameters

  • Similar to getPrimaryDisplayCurrency.

Returns

  • Currency - The determined alternate display currency.

parseStringToCurrency

Converts a string to a Currency enum value, throwing an error if the input is not a valid currency.

Parameters

  • string: The string to parse.

Returns

  • Currency - The parsed currency.

Example

import { parseStringToCurrency } from "@namehash/ens-utils";

const ethStringToCurrency = parseStringToCurrency("eth");

// ethStringToCurrency equals Currency.Eth
console.log(ethStringToCurrency); // "Eth"

Number

The Number module was designed to facilitate working with different numerical types and precision scaling in TypeScript applications, this module is essential for applications that require precision arithmetic or need to handle large numbers (beyond the safe range of JavaScript's number type) by providing tools to convert and scale these values safely and effectively.

stringToBigInt

Converts a string to a bigint. Throws an error if the conversion is not possible.

Parameters

  • stringValue: String - The string value to convert to a bigint.

Returns

  • bigint - The string value converted to a bigint.

Example

import { stringToBigInt } from "@namehash/ens-utils";

const bigIntValue = stringToBigInt("12345");

decimalToBigInt

Converts a Decimal value to a bigint by first converting the Decimal to a number with fixed decimal places and rounding, then converting that number to a bigint. Uses Decimal from Decimal.js.

Parameters

  • decimalValue: Decimal - The Decimal value to convert to a bigint.

Returns

  • bigint - The Decimal value converted to a bigint.

Example

import { decimalToBigInt } from "@namehash/ens-utils";

const bigIntValue = decimalToBigInt(new Decimal(123.45));

numberToBigInt

Converts a number to a bigint after fixing it to zero decimal places. Throws an error if the conversion is not possible.

Parameters

  • numberValue: number - The bigint value to convert to a number.

Returns

  • bigint - The bigint value converted to a number.

Example

import { numberToBigInt } from "@namehash/ens-utils";

const bigIntValue = numberToBigInt(123.45);

bigIntToNumber

Converts a bigint to a number.

Parameters

  • bigIntValue: bigint - The bigint value to convert to a number.

Returns

  • number - The bigint value converted to a number.

Example

import { bigIntToNumber } from "@namehash/ens-utils";

const numberValue = bigIntToNumber(12345n);

approxScaleBigInt

Approximately scales a bigint value by a scale factor, using a specified number of digits of precision.

Parameters

  • bigIntValue: bigint - The value to scale.
  • scaleFactor: number - The factor to scale by.
  • digitsOfPrecision: bigint - The number of digits of precision to use. Must be non-negative.

Returns

  • bigint - The scaled value.

Example

import { approxScaleBigInt } from "@namehash/ens-utils";

const scaledValue = approxScaleBigInt(100n, 0.1, 1n); // === 10n

⚠️ Number Exceptions

  • stringToBigInt and numberToBigInt will throw an error if the input cannot be converted to a bigint.
  • approxScaleBigInt throws an error if digitsOfPrecision is negative or if calculations overflow, underflow, or result in non-finite numbers.

Time

This module consists of a collection of utility functions designed to handle and format time-related data in TypeScript.

  • Conversion between time units (e.g., milliseconds to seconds)
  • Current time retrieval
  • Time formatting (e.g., to human-readable forms, short date formats)
  • Calculation of time differences and descriptions relative to "now"

Constants

Constant Type Description
SECONDS_PER_YEAR number Defines the number of seconds in a year.
ONE_MINUTE_IN_SECONDS bigint Represents one minute in seconds as a BigInt.
ONE_HOUR_IN_SECONDS bigint Represents one hour in seconds as a BigInt.
ONE_DAY_IN_SECONDS bigint Represents one day in seconds as a BigInt.
ONE_WEEK_IN_SECONDS bigint Represents one week in seconds as a BigInt.

Functions

msToSeconds

Converts milliseconds to seconds.

Parameters

  • ms: bigint - The milliseconds to convert.

Returns

  • bigint - The converted time in seconds.

now

Retrieves the current time in seconds.

Returns

  • bigint - The current timestamp in seconds.

fromTimestampToDate

Formats a timestamp to a Date object.

Parameters

  • timestamp: bigint - The UNIX timestamp to format.
  • asSeconds: boolean (optional) - If the timestamp is in seconds (defaults to false).

Returns

  • Date - A Date object for the formatted timestamp.

timestampAsDistance

Formats a timestamp to a string representing the distance to now, optionally with a suffix.

Parameters

  • timestamp: bigint - The timestamp to format.
  • addSuffix: boolean (optional) - Whether to add a suffix.

Returns

  • string - The formatted distance string.

getShortTimestampFormat

Formats a timestamp into a short date format.

Parameters

  • timestamp: bigint - The timestamp to format.

Returns

  • string - The date formatted as a short string.

getTimestampDescription

Provides a description of a timestamp, formatted either as a relative distance to now or as a short date.

Parameters

  • timestamp: bigint - The timestamp to describe.
  • showAsDistance: boolean - Whether to show the timestamp as a distance from now.
  • withSufix: boolean (optional) - Whether to include a suffix in the description.

Returns string - A description of the timestamp.

getFormattedTimestamp

Converts a timestamp into a formatted string representing local date and time.

Parameters

  • timestamp: bigint - The timestamp to format.

Returns

  • string - The localized and formatted date and time string.

prettyTimestampDiffFromNow

Returns a pretty string representing the difference between a timestamp and the current time.

Parameters

  • timestamp: bigint - The timestamp to compare with the current time.

Returns

  • string - A human-readable description of the time difference.

Price

The Price module can be part of a financial application´ dealing with currency conversion, arithmetic operations on prices, formatting for display, and approximations. It primarily operates with a custom Price type, handling various currencies with support for arithmetic operations such as addition, subtraction, multiplication, and conversion between currencies using exchange rates.

Types and Interfaces

Price

Represents a monetary value in a specific currency.

import type { Currency } from "@namehash/ens-utils";

type Price = {
  value: bigint;
  currency: Currency;
};
  • value: The monetary value as a bigint.
  • currency: The currency of the value, defined by the Currency type.

ExchangeRates

Maps different currencies to their exchange rate in USD.

import type { Currency } from "@namehash/ens-utils";

interface ExchangeRates extends Partial<Record<Currency, number>> {}

An example ExchangeRates object:

{
  "ETH": 1737.16,
  "DAI": 0.99999703,
  "USDC": 1,
  "WETH": 1737.16,
  "USD": 1
}

Functions

priceAsNumber

Converts a Price object to its numeric representation considering its currency's decimals.

Parameters

  • price: Price - The Price to have its value returned as a number.

Returns number - A number representing the Price considering its Currency decimals.

Example

import { priceAsNumber } from "@namehash/ens-utils";

const tenUSDC = {
  value: 100000n,
  currency: Currency.Usdc,
};

const tenUsdcAsNumber = priceAsNumber(tenUSDC);

// tenUsdcDollarsAsNumber equals Number(1)

numberAsPrice

Converts a numeric value to a Price object in the specified currency.

Parameters

  • number: number - The number to be set as the Price value.
  • currency: Currency - The currency to be set as the Price currency.

Returns:

  • Price - A Price object containing a value and a currency.

Example

import { numberAsPrice } from "@namehash/ens-utils";

const fromNumberTenToEthValue = numberAsPrice(10, Currency.Eth);

// fromNumberTenToEthValue equals {
//   value: 10000000000000000000n,
//   currency: Currency.Eth
// }

addPrices

Adds multiple Price objects, ensuring they are in the same currency.

Parameters

  • prices: Array<Price> - An array of Price values.

Returns

  • Price - The summing of each prices Price.

Example

import { addPrices } from "@namehash/ens-utils";

const networkFee: Price = {
  value: X,
  currency: Currency.Eth,
};
const ethDomainPrice: Price = {
  value: Y,
  currency: Currency.Eth,
};

const totalCost = addPrices([networkFee, ethDomainPrice]);

// totalCost equals {
//   value: X + Y,
//   currency: Currency.Eth
// }

Throws: Error if trying to add prices of different currencies.

subtractPrices

Subtracts one Price object from another, given they are in the same currency.

Parameters

  • price1: Price - The Price to be subtracted from.
  • price2: Price - The Price to be subtracted.

Returns

  • Price - The price1 subtracted by price2.

Example

import { subtractPrices } from "@namehash/ens-utils";

const ethDomainPrice: Price = {
  value: X,
  currency: Currency.Eth,
};
const ethDomainPricePremium: Price = {
  value: Y,
  currency: Currency.Eth,
};

const totalCost = subtractPrices(ethDomainPrice, ethDomainPricePremium);

// totalCost equals {
//   value: X - Y,
//   currency: Currency.Eth
// }

Throws: Error if currencies do not match.

multiplyPriceByNumber

Multiplies a Price by a numeric value.

Parameters

  • price1: Price - The Price to be multiplied.
  • price2: number - A number to multiply price1 for.

Returns

  • Price - The price1, as a Price, having its value multiplied by price2.

Example

import { multiplyPriceByNumber } from "@namehash/ens-utils";

const ethDomainPrice: Price = {
  value: X,
  currency: Currency.Eth,
};
const multiplier = 2;

const totalCost = multiplyPriceByNumber(ethDomainPrice, multiplier);

// totalCost equals {
//   value: X * 2,
//   currency: Currency.Eth
// }

formattedPrice

Returns a string representing a Price formatted for display, with optional prefix or suffix.

Parameters

  • price: Price - The Price to format.
  • withPrefix = false: boolean - Wether to add a Currency prefix.
  • withSufix = false: boolean - Wether to add a Currency sufix.

Returns

  • string - A human-readable formatted Price string.

Example

import { formattedPrice } from "@namehash/ens-utils";

const fiveDollarsInEth = 5000000000000000000n;

const a = formattedPrice({
  price: { currency: Currency.Eth, value: fiveDollarsInEth },
});

const b = formattedPrice({
  price: { currency: Currency.Eth, value: fiveDollarsInEth },
  withSufix: true,
});

const c = formattedPrice({
  price: { currency: Currency.Eth, value: fiveDollarsInEth },
  withPrefix: true,
});

const d = formattedPrice({
  price: { currency: Currency.Eth, value: fiveDollarsInEth },
  withPrefix: true,
  withSufix: true,
});

// a equals 5.000
// b equals 5.000 ETH
// c equals Ξ5.000
// d equals Ξ5.000 ETH

approxScalePrice

Scales a Price object by a factor with a specified number of digits of precision.

Parameters

  • price: Price - The Price to scale.
  • scaleFactor: number - The factor to scale by.
  • digitsOfPrecision = 20n: bigint - The number of digits of precision to use. Must be non-negative.

Returns

  • Price - The price scaled by the scaleFactor considering the number of digitsOfPrecision.

Example

import { approxScalePrice } from "@namehash/ens-utils";

const decayedPrice = approxScalePrice(PREMIUM_START_PRICE, decayFactor);

// decayedPrice equals PREMIUM_START_PRICE scaled (up or down, depending on decayFactor value) by decayedPrice

convertCurrencyWithRates

Converts a Price from one currency to another using provided exchange rates.

Parameters

  • fromPrice: Price - The price to be converted to a new Currency.
  • toCurrency: Currency - The new Currency to convert fromPrice to.
  • exchangeRates: ExchangeRates - The exchange rates object. Refer to ExchangeRates

Returns

  • Price - The converted fromPrice into its toCurrency value, calculated based on the provided exchangeRates.

Example

import { convertCurrencyWithRates } from "@namehash/ens-utils";

const fromUsd = {
  value: 500n,
  currency: Currency.Usd,
};

const exchangeRatesRecord = {
  [Currency.Eth]: 2277.56570676,
  [Currency.Usd]: 1,
};

const fromUsdToEth = convertCurrencyWithRates(
  fromUsd,
  Currency.Eth,
  exchangeRatesRecord
);

// fromUsdToEth equals the Eth amount of $5 based on the provided currencies exchange rates

⚠️ Price Exceptions

  • Arithmetic Operations (add, subtract): Throws an error if currencies do not match.
  • Conversion Operations: Throws an error if exchange rates do not include the necessary currencies.

Contact us

Visit our website and get in contact.

License

Licensed under the MIT License, Copyright © 2023-present NameHash Labs.

See LICENSE for more information.