/*
This file is part of web3.js.
web3.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
web3.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see .
*/
import { Web3Context, Web3ContextObject } from 'web3-core';
import { ENSNetworkNotSyncedError, ENSUnsupportedNetworkError, RevertInstructionError } from 'web3-errors';
import { isSyncing } from 'web3-eth';
import { Contract } from 'web3-eth-contract';
import { getId } from 'web3-net';
import {
Address,
DEFAULT_RETURN_FORMAT,
EthExecutionAPI,
FMT_NUMBER,
PayableCallOptions,
SupportedProviders,
TransactionReceipt,
Web3NetAPI,
} from 'web3-types';
import { PublicResolverAbi } from './abi/ens/PublicResolver.js';
import { networkIds, registryAddresses } from './config.js';
import { Registry } from './registry.js';
import { Resolver } from './resolver.js';
/**
* This class is designed to interact with the ENS system on the Ethereum blockchain.
* For using ENS package, first install Web3 package using: `npm i web3` or `yarn add web3` based on your package manager, after that ENS features can be used as mentioned in following snippet.
* ```ts
*
* import { Web3 } from 'web3';
*
* const web3 = new Web3('https://127.0.0.1:4545');
*
* console.log(await web3.eth.ens.getAddress('ethereum.eth'))
* ```
* For using individual package install `web3-eth-ens` packages using: `npm i web3-eth-ens` or `yarn add web3-eth-ens`. This is more efficient approach for building lightweight applications.
*
* ```ts
*import { ENS } from 'web3-eth-ens';
*
* const ens = new ENS(undefined,'https://127.0.0.1:4545');
*
* console.log(await ens.getAddress('vitalik.eth'));
* ```
*/
export class ENS extends Web3Context {
/**
* The registryAddress property can be used to define a custom registry address when you are connected to an unknown chain. It defaults to the main registry address.
*/
public registryAddress: string;
private readonly _registry: Registry;
private readonly _resolver: Resolver;
private _detectedAddress?: string;
private _lastSyncCheck?: number;
/**
* Use to create an instance of ENS
* @param registryAddr - (Optional) The address of the ENS registry (default: mainnet registry address)
* @param provider - (Optional) The provider to use for the ENS instance
* @example
* ```ts
* const ens = new ENS(
* "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e",
* "http://localhost:8545"
* );
*
* console.log( ens.defaultChain);
* > mainnet
* ```
*/
public constructor(
registryAddr?: string,
provider?:
| SupportedProviders
| Web3ContextObject
| string,
) {
super(provider ?? '');
this.registryAddress = registryAddr ?? registryAddresses.main; // will default to main registry address
this._registry = new Registry(this.getContextObject(), registryAddr);
this._resolver = new Resolver(this._registry);
}
/**
* Returns the Resolver by the given address
* @param name - The name of the ENS domain
* @returns - An contract instance of the resolver
*
* @example
* ```ts
* const resolver = await ens.getResolver('resolver');
*
* console.log(resolver.options.address);
* > '0x1234567890123456789012345678901234567890'
* ```
*/
public async getResolver(name: string): Promise> {
return this._registry.getResolver(name);
}
/**
* Returns true if the record exists
* @param name - The ENS name
* @returns - Returns `true` if node exists in this ENS registry. This will return `false` for records that are in the legacy ENS registry but have not yet been migrated to the new one.
* @example
* ```ts
* const exists = await web3.eth.ens.recordExists('ethereum.eth');
* ```
*/
public async recordExists(name: string): Promise {
return this._registry.recordExists(name);
}
/**
* Returns the caching TTL (time-to-live) of an ENS name.
* @param name - The ENS name
* @returns - Returns the caching TTL (time-to-live) of a name.
* @example
* ```ts
* const owner = await web3.eth.ens.getTTL('ethereum.eth');
* ```
*/
public async getTTL(name: string): Promise {
return this._registry.getTTL(name);
}
/**
* Returns the owner by the given name and current configured or detected Registry
* @param name - The ENS name
* @returns - Returns the address of the owner of the name.
* @example
* ```ts
* const owner = await web3.eth.ens.getOwner('ethereum.eth');
* ```
*/
public async getOwner(name: string): Promise {
return this._registry.getOwner(name);
}
/**
* Resolves an ENS name to an Ethereum address.
* @param ENSName - The ENS name to resolve
* @param coinType - (Optional) The coin type, defaults to 60 (ETH)
* @returns - The Ethereum address of the given name
* ```ts
* const address = await web3.eth.ens.getAddress('ethereum.eth');
* console.log(address);
* > '0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359'
* ```
*/
public async getAddress(ENSName: string, coinType = 60) {
return this._resolver.getAddress(ENSName, coinType);
}
/**
* ERC-634 - Returns the text content stored in the resolver for the specified key.
* @param ENSName - The ENS name to resolve
* @param key - The key to resolve https://github.com/ethereum/ercs/blob/master/ERCS/erc-634.md#global-keys
* @returns - The value content stored in the resolver for the specified key
*/
public async getText(ENSName: string, key: string): Promise {
return this._resolver.getText(ENSName, key);
}
/**
* Resolves the name of an ENS node.
* @param ENSName - The node to resolve
* @returns - The name
*/
public async getName(ENSName: string): Promise {
return this._resolver.getName(ENSName);
}
/**
* Returns the X and Y coordinates of the curve point for the public key.
* @param ENSName - The ENS name
* @returns - The X and Y coordinates of the curve point for the public key
* @example
* ```ts
* const key = await web3.eth.ens.getPubkey('ethereum.eth');
* console.log(key);
* > {
* "0": "0x0000000000000000000000000000000000000000000000000000000000000000",
* "1": "0x0000000000000000000000000000000000000000000000000000000000000000",
* "x": "0x0000000000000000000000000000000000000000000000000000000000000000",
* "y": "0x0000000000000000000000000000000000000000000000000000000000000000"
* }
* ```
*/
public async getPubkey(ENSName: string) {
return this._resolver.getPubkey(ENSName);
}
/**
* Returns the content hash object associated with an ENS node.
* @param ENSName - The ENS name
* @returns - The content hash object associated with an ENS node
* @example
* ```ts
* const hash = await web3.eth.ens.getContenthash('ethereum.eth');
* console.log(hash);
* > 'QmaEBknbGT4bTQiQoe2VNgBJbRfygQGktnaW5TbuKixjYL'
* ```
*/
public async getContenthash(ENSName: string) {
return this._resolver.getContenthash(ENSName);
}
/**
* Checks if the current used network is synced and looks for ENS support there.
* Throws an error if not.
* @returns - The address of the ENS registry if the network has been detected successfully
* @example
* ```ts
* console.log(await web3.eth.ens.checkNetwork());
* > '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e'
* ```
*/
public async checkNetwork() {
const now = Date.now() / 1000;
if (!this._lastSyncCheck || now - this._lastSyncCheck > 3600) {
const syncInfo = await isSyncing(this);
if (!(typeof syncInfo === 'boolean' && !syncInfo)) {
throw new ENSNetworkNotSyncedError();
}
this._lastSyncCheck = now;
}
if (this._detectedAddress) {
return this._detectedAddress;
}
const networkType = await getId(this, {
...DEFAULT_RETURN_FORMAT,
number: FMT_NUMBER.HEX,
}); // get the network from provider
const addr = registryAddresses[networkIds[networkType]];
if (typeof addr === 'undefined') {
throw new ENSUnsupportedNetworkError(networkType);
}
this._detectedAddress = addr;
return this._detectedAddress;
}
/**
* Returns true if the related Resolver does support the given signature or interfaceId.
* @param ENSName - The ENS name
* @param interfaceId - The signature of the function or the interfaceId as described in the ENS documentation
* @returns - `true` if the related Resolver does support the given signature or interfaceId.
* @example
* ```ts
* const supports = await web3.eth.ens.supportsInterface('ethereum.eth', 'addr(bytes32');
* console.log(supports);
* > true
* ```
*/
public async supportsInterface(ENSName: string, interfaceId: string) {
return this._resolver.supportsInterface(ENSName, interfaceId);
}
/**
* @returns - Returns all events that can be emitted by the ENS registry.
*/
public get events() {
return this._registry.events;
}
/**
* Sets the address of an ENS name in his resolver.
* @param name - The ENS name
* @param address - The address to set
* @param txConfig - (Optional) The transaction config
* @returns - The transaction receipt
* ```ts
* const receipt = await ens.setAddress('web3js.eth','0xe2597eb05cf9a87eb1309e86750c903ec38e527e');
*```
*/
public async setAddress(
name: string,
address: Address,
txConfig: PayableCallOptions
): Promise {
return this._resolver.setAddress(name, address, txConfig);
}
}