UNPKG

@authereum/resolution

Version:
681 lines (680 loc) 30.1 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); var bn_js_1 = __importDefault(require("bn.js")); var Ens_1 = __importDefault(require("./Ens")); var Zns_1 = __importDefault(require("./Zns")); var Cns_1 = __importDefault(require("./Cns")); var UdApi_1 = __importDefault(require("./UdApi")); var publicTypes_1 = require("./publicTypes"); var resolutionError_1 = __importStar(require("./errors/resolutionError")); var NamingService_1 = __importDefault(require("./NamingService")); var utils_1 = require("./utils"); var Eip1993Factories_1 = require("./utils/Eip1993Factories"); var DnsUtils_1 = __importDefault(require("./DnsUtils")); /** * Blockchain domain Resolution library - Resolution. * @example * ``` * import Resolution from '@unstoppabledomains/resolution'; * * let resolution = new Resolution({ blockchain: { * ens: { * url: "https://mainnet.infura.io/v3/12351245223", * network: "mainnet" * } * } * }); * * let domain = "brad.zil"; * resolution.addr(domain, "eth").then(addr => console.log(addr));; * ``` */ var Resolution = /** @class */ (function () { function Resolution(_a) { var _b = _a === void 0 ? {} : _a, _c = _b.blockchain, blockchain = _c === void 0 ? true : _c, _d = _b.api, api = _d === void 0 ? publicTypes_1.DefaultAPI : _d; this.blockchain = !!blockchain; if (blockchain) { if (blockchain === true) { blockchain = {}; } var web3provider = blockchain.web3Provider; if (web3provider) { console.warn('Usage of `web3Provider` option is deprecated. Use `provider` option instead for each individual blockchain'); } var ens = this.normalizeSource(blockchain.ens, web3provider); var zns = this.normalizeSource(blockchain.zns); var cns = this.normalizeSource(blockchain.cns, web3provider); if (ens) { this.ens = new Ens_1.default(ens); } if (zns) { this.zns = new Zns_1.default(zns); } if (cns) { this.cns = new Cns_1.default(cns); } } else { this.api = new UdApi_1.default(api); } } /** * Creates a resolution with configured infura id for ens and cns * @param infura infura project id * @param network ethereum network name */ Resolution.infura = function (infura, network) { if (network === void 0) { network = 'mainnet'; } return new this({ blockchain: { ens: { url: utils_1.signedInfuraLink(infura, network), network: network }, cns: { url: utils_1.signedInfuraLink(infura, network), network: network }, }, }); }; /** * Creates a resolution instance with configured provider * @param provider - any provider compatible with EIP-1193 * @see https://eips.ethereum.org/EIPS/eip-1193 */ Resolution.fromEip1193Provider = function (provider) { return new this({ blockchain: { zns: true, ens: { provider: provider }, cns: { provider: provider } }, }); }; /** * Create a resolution instance from web3 0.x version provider * @param provider - an 0.x version provider from web3 ( must implement sendAsync(payload, callback) ) * @see https://github.com/ethereum/web3.js/blob/0.20.7/lib/web3/httpprovider.js#L116 */ Resolution.fromWeb3Version0Provider = function (provider) { return this.fromEip1193Provider(Eip1993Factories_1.Eip1993Factories.fromWeb3Version0Provider(provider)); }; /** * Create a resolution instance from web3 1.x version provider * @param provider - an 1.x version provider from web3 ( must implement send(payload, callback) ) * @see https://github.com/ethereum/web3.js/blob/1.x/packages/web3-core-helpers/types/index.d.ts#L165 * @see https://github.com/ethereum/web3.js/blob/1.x/packages/web3-providers-http/src/index.js#L95 */ Resolution.fromWeb3Version1Provider = function (provider) { return this.fromEip1193Provider(Eip1993Factories_1.Eip1993Factories.fromWeb3Version1Provider(provider)); }; /** * Creates instance of resolution from provider that implements Ethers Provider#call interface. * This wrapper support only `eth_call` method for now, which is enough for all the current Resolution functionality * @param provider - provider object * @see https://github.com/ethers-io/ethers.js/blob/v4-legacy/providers/abstract-provider.d.ts#L91 * @see https://github.com/ethers-io/ethers.js/blob/v5.0.4/packages/abstract-provider/src.ts/index.ts#L224 * @see https://docs.ethers.io/ethers.js/v5-beta/api-providers.html#jsonrpcprovider-inherits-from-provider * @see https://github.com/ethers-io/ethers.js/blob/master/packages/providers/src.ts/json-rpc-provider.ts */ Resolution.fromEthersProvider = function (provider) { return this.fromEip1193Provider(Eip1993Factories_1.Eip1993Factories.fromEthersProvider(provider)); }; /** * Resolves the given domain * @async * @param domain - domain name to be resolved * @returns A promise that resolves in an object */ Resolution.prototype.resolve = function (domain) { return __awaiter(this, void 0, void 0, function () { var method, result; return __generator(this, function (_a) { switch (_a.label) { case 0: domain = this.prepareDomain(domain); method = this.getNamingMethodOrThrow(domain); return [4 /*yield*/, method.resolve(domain)]; case 1: result = _a.sent(); return [2 /*return*/, result || publicTypes_1.UnclaimedDomainResponse]; } }); }); }; /** * Resolves given domain name to a specific currency address if exists * @async * @param domain - domain name to be resolved * @param currencyTicker - currency ticker like BTC, ETH, ZIL * @deprecated since Resolution v1.7.0 * @returns A promise that resolves in an address or null */ Resolution.prototype.address = function (domain, currencyTicker) { return __awaiter(this, void 0, void 0, function () { var error_1; return __generator(this, function (_a) { switch (_a.label) { case 0: console.warn('Resolution#address is deprecated since v1.7.0, use Resolution#addr instead'); domain = this.prepareDomain(domain); _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4 /*yield*/, this.addressOrThrow(domain, currencyTicker)]; case 2: return [2 /*return*/, _a.sent()]; case 3: error_1 = _a.sent(); if (error_1 instanceof resolutionError_1.default) { return [2 /*return*/, null]; } else { throw error_1; } return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } }); }); }; /** * Resolves given domain name to a specific currency address if exists * @async * @param domain - domain name to be resolved * @param currencyTicker - currency ticker like BTC, ETH, ZIL * @throws [[ResolutionError]] if address is not found * @returns A promise that resolves in an address */ Resolution.prototype.addr = function (domain, currrencyTicker) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.record(domain, "crypto." + currrencyTicker.toUpperCase() + ".address")]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }; /** * Resolves given domain name to a verified twitter handle * @async * @param domain - domain name to be resolved * @throws [[ResolutionError]] if twitter is not found * @returns A promise that resolves in a verified twitter handle */ Resolution.prototype.twitter = function (domain) { return __awaiter(this, void 0, void 0, function () { var namingService, method; return __generator(this, function (_a) { domain = this.prepareDomain(domain); namingService = this.serviceName(domain); if (namingService !== 'CNS') { throw new resolutionError_1.default(resolutionError_1.ResolutionErrorCode.UnsupportedMethod, { domain: domain, methodName: 'twitter', }); } method = this.getNamingMethodOrThrow(domain); return [2 /*return*/, method.twitter(domain)]; }); }); }; /** * Resolve a chat id from the domain record * @param domain - domain name to be resolved * @throws [[ResolutionError]] * @returns A promise that resolves in chatId */ Resolution.prototype.chatId = function (domain) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.record(domain, 'gundb.username.value')]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }; /** * Resolve a gundb public key from the domain record * @param domain - domain name to be resolved * @throws [[ResolutionError]] * @returns a promise that resolves in gundb public key */ Resolution.prototype.chatPk = function (domain) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.record(domain, 'gundb.public_key.value')]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }; /** * Resolves the IPFS hash configured for domain records on ZNS * @param domain - domain name * @throws [[ResolutionError]] */ Resolution.prototype.ipfsHash = function (domain) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: domain = this.prepareDomain(domain); return [4 /*yield*/, this.getPreferableNewRecord(domain, 'dweb.ipfs.hash', 'ipfs.html.value')]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }; /** * Resolves the httpUrl attached to domain * @param domain - domain name */ Resolution.prototype.httpUrl = function (domain) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: domain = this.prepareDomain(domain); return [4 /*yield*/, this.getPreferableNewRecord(domain, 'browser.redirect_url', 'ipfs.redirect_domain.value')]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }; /** * Resolves the ipfs redirect url for a supported domain records * @deprecated since v1.0.15 use Resolution#httpUrl instead * @param domain - domain name * @throws [[ResolutionError]] * @returns A Promise that resolves in redirect url */ Resolution.prototype.ipfsRedirect = function (domain) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: console.warn('Resolution#ipfsRedirect is deprecated since v1.0.15, use Resolution#httpUrl instead'); return [4 /*yield*/, this.record(domain, 'ipfs.redirect_domain.value')]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }; /** * Resolves the ipfs email field from whois configurations * @param domain - domain name * @throws [[ResolutionError]] * @returns A Promise that resolves in an email address configured for this domain whois */ Resolution.prototype.email = function (domain) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.record(domain, 'whois.email.value')]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }; /** * @returns A specific currency address or throws an error * @param domain domain name * @param currencyTicker currency ticker such as * - ZIL * - BTC * - ETH * @throws [[ResolutionError]] if address is not found * @deprecated since v1.7.0 use Resolution#addr instead */ Resolution.prototype.addressOrThrow = function (domain, currencyTicker) { return __awaiter(this, void 0, void 0, function () { var method, addr, error_2; return __generator(this, function (_a) { switch (_a.label) { case 0: console.warn('Resolution#addressOrThrow is deprecated since v1.7.0, use Resolution#addr instead'); domain = this.prepareDomain(domain); method = this.getNamingMethodOrThrow(domain); _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4 /*yield*/, method.record(domain, "crypto." + currencyTicker.toUpperCase() + ".address")]; case 2: addr = _a.sent(); return [2 /*return*/, addr]; case 3: error_2 = _a.sent(); // re-throw an error for back compatability. old method throws deprecated UnspecifiedCurrency code since before v1.7.0 if (error_2 instanceof resolutionError_1.default && error_2.code === resolutionError_1.ResolutionErrorCode.RecordNotFound) { throw new resolutionError_1.default(resolutionError_1.ResolutionErrorCode.UnspecifiedCurrency, { domain: domain, currencyTicker: currencyTicker, }); } throw error_2; case 4: return [2 /*return*/]; } }); }); }; /** * @returns the resolver address for a specific domain * @param domain - domain to look for */ Resolution.prototype.resolver = function (domain) { return __awaiter(this, void 0, void 0, function () { var resolver; return __generator(this, function (_a) { switch (_a.label) { case 0: domain = this.prepareDomain(domain); return [4 /*yield*/, this.getNamingMethodOrThrow(domain).resolver(domain)]; case 1: resolver = _a.sent(); if (!resolver) { throw new resolutionError_1.default(resolutionError_1.ResolutionErrorCode.UnspecifiedResolver, { domain: domain }); } return [2 /*return*/, resolver]; } }); }); }; /** * @param domain - domain name * @returns An owner address of the domain */ Resolution.prototype.owner = function (domain) { return __awaiter(this, void 0, void 0, function () { var method; return __generator(this, function (_a) { switch (_a.label) { case 0: domain = this.prepareDomain(domain); method = this.getNamingMethodOrThrow(domain); return [4 /*yield*/, method.owner(domain)]; case 1: return [2 /*return*/, (_a.sent()) || null]; } }); }); }; /** * @param domain - domain name * @param recordKey - a name of a record to be resolved * @returns A record value promise for a given record name */ Resolution.prototype.record = function (domain, recordKey) { return __awaiter(this, void 0, void 0, function () { var method; return __generator(this, function (_a) { switch (_a.label) { case 0: domain = this.prepareDomain(domain); method = this.getNamingMethodOrThrow(domain); return [4 /*yield*/, method.record(domain, recordKey)]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }; /** * @param domain domain name * @param keys Array of record keys to be resolved * @returns A Promise with key-value mapping of domain records */ Resolution.prototype.records = function (domain, keys) { return __awaiter(this, void 0, void 0, function () { var method; return __generator(this, function (_a) { switch (_a.label) { case 0: domain = this.prepareDomain(domain); method = this.getNamingMethodOrThrow(domain); return [4 /*yield*/, method.records(domain, keys)]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }; /** * This method is only for ens at the moment. Reverse the ens address to a ens registered domain name * @async * @param address - address you wish to reverse * @param currencyTicker - currency ticker like BTC, ETH, ZIL * @returns Domain name attached to this address */ Resolution.prototype.reverse = function (address, currencyTicker) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, this.findNamingService(publicTypes_1.NamingServiceName.ENS).reverse(address, currencyTicker)]; }); }); }; /** * @returns Produces a namehash from supported naming service in hex format with 0x prefix. * Corresponds to ERC721 token id in case of Ethereum based naming service like ENS or CNS. * @param domain domain name to be converted * @param options formatting options * @throws [[ResolutionError]] with UnsupportedDomain error code if domain extension is unknown */ Resolution.prototype.namehash = function (domain, options) { if (options === void 0) { options = publicTypes_1.NamehashOptionsDefault; } domain = this.prepareDomain(domain); return this.formatNamehash(this.getNamingMethodOrThrow(domain).namehash(domain), options); }; /** * @returns a namehash of a subdomain with name label * @param parent namehash of a parent domain * @param label subdomain name * @param method "ENS", "CNS" or "ZNS" * @param options formatting options */ Resolution.prototype.childhash = function (parent, label, method, options) { if (options === void 0) { options = publicTypes_1.NamehashOptionsDefault; } return this.formatNamehash(this.findNamingService(method).childhash(parent, label), options); }; Resolution.prototype.formatNamehash = function (hash, options) { hash = hash.replace('0x', ''); if (options.format === 'dec') { return new bn_js_1.default(hash, 'hex').toString(10); } else { return options.prefix ? '0x' + hash : hash; } }; /** * Checks weather the domain name matches the hash * @param domain - domain name to check againt * @param hash - hash obtained from the blockchain */ Resolution.prototype.isValidHash = function (domain, hash) { domain = this.prepareDomain(domain); return this.namehash(domain) === hash; }; /** * Checks if the domain name is valid according to naming service rules * for valid domain names. * Example: ENS doesn't allow domains that start from '-' symbol. * @param domain - domain name to be checked */ Resolution.prototype.isSupportedDomain = function (domain) { domain = this.prepareDomain(domain); return !!this.getNamingMethod(domain); }; /** * Checks if the domain is supported by the specified network as well as if it is in valid format * @param domain - domain name to be checked */ Resolution.prototype.isSupportedDomainInNetwork = function (domain) { domain = this.prepareDomain(domain); var method = this.getNamingMethod(domain); return !!method && method.isSupportedNetwork(); }; /** * Returns the name of the service for a domain ENS | CNS | ZNS * @param domain - domain name to look for */ Resolution.prototype.serviceName = function (domain) { domain = this.prepareDomain(domain); return this.getNamingMethodOrThrow(domain).serviceName(domain); }; /** * Returns all record keys of the domain. * This method is strongly unrecommended for production use due to lack of support for many ethereum service providers and low performance * Method is not supported by ENS * @param domain - domain name */ Resolution.prototype.allRecords = function (domain) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: domain = this.prepareDomain(domain); return [4 /*yield*/, this.getNamingMethodOrThrow(domain).allRecords(domain)]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }; Resolution.prototype.dns = function (domain, types) { return __awaiter(this, void 0, void 0, function () { var dnsUtils, method, dnsRecordKeys, blockchainData; return __generator(this, function (_a) { switch (_a.label) { case 0: dnsUtils = new DnsUtils_1.default(); domain = this.prepareDomain(domain); method = this.getNamingMethodOrThrow(domain); dnsRecordKeys = this.getDnsRecordKeys(types); return [4 /*yield*/, method.records(domain, dnsRecordKeys)]; case 1: blockchainData = _a.sent(); return [2 /*return*/, dnsUtils.toList(blockchainData)]; } }); }); }; Resolution.prototype.getDnsRecordKeys = function (types) { var records = ['dns.ttl']; types.forEach(function (type) { records.push("dns." + type); records.push("dns." + type + ".ttl"); }); return records; }; Resolution.prototype.getPreferableNewRecord = function (domain, newRecord, oldRecord) { return __awaiter(this, void 0, void 0, function () { var records; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.records(domain, [newRecord, oldRecord])]; case 1: records = _a.sent(); return [2 /*return*/, NamingService_1.default.ensureRecordPresence(domain, newRecord, records[newRecord] || records[oldRecord])]; } }); }); }; Resolution.prototype.getNamingMethod = function (domain) { return this.getResolutionMethods().find(function (method) { return method.isSupportedDomain(domain); }); }; Resolution.prototype.getResolutionMethods = function () { return (this.blockchain ? [this.ens, this.zns, this.cns] : [this.api]).filter(function (v) { return v; }); }; Resolution.prototype.getNamingMethodOrThrow = function (domain) { var method = this.getNamingMethod(domain); if (!method) { throw new resolutionError_1.default(resolutionError_1.ResolutionErrorCode.UnsupportedDomain, { domain: domain, }); } return method; }; Resolution.prototype.findNamingService = function (name) { var service = this.getResolutionMethods().find(function (m) { return m.name === name; }); if (!service) { throw new resolutionError_1.default(resolutionError_1.ResolutionErrorCode.NamingServiceDown, { method: name, }); } return service; }; Resolution.prototype.prepareDomain = function (domain) { return domain ? domain.trim().toLowerCase() : ''; }; Resolution.prototype.normalizeSource = function (source, provider) { switch (typeof source) { case 'undefined': { return { provider: provider }; } case 'boolean': { return source ? { provider: provider } : false; } case 'string': { return { url: source }; } case 'object': { return __assign({ provider: provider }, source); } } throw new Error('Unsupported configuration'); }; return Resolution; }()); exports.Resolution = Resolution; exports.default = Resolution;