/* 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 . */ /** * @file Registry.js * * @author Samuel Furter * @date 2018 */ "use strict"; var _ = require('underscore'); var Contract = require('web3-eth-contract'); var namehash = require('eth-ens-namehash'); var PromiEvent = require('web3-core-promievent'); var formatters = require('web3-core-helpers').formatters; var utils = require('web3-utils'); var REGISTRY_ABI = require('../resources/ABI/Registry'); var RESOLVER_ABI = require('../resources/ABI/Resolver'); /** * A wrapper around the ENS registry contract. * * @method Registry * @param {Ens} ens * @constructor */ function Registry(ens) { var self = this; this.ens = ens; this.contract = ens.checkNetwork().then(function (address) { var contract = new Contract(REGISTRY_ABI, address); contract.setProvider(self.ens.eth.currentProvider); return contract; }); } /** * Returns the address of the owner of an ENS name. * * @deprecated Please use the "getOwner" method instead of "owner" * * @method owner * * @param {string} name * @param {function} callback * * @callback callback callback(error, result) * @returns {Promise} */ Registry.prototype.owner = function (name, callback) { console.warn('Deprecated: Please use the "getOwner" method instead of "owner".'); return this.getOwner(name, callback); }; /** * Returns the address of the owner of an ENS name. * * @method getOwner * * @param {string} name * @param {function} callback * * @callback callback callback(error, result) * @returns {Promise} */ Registry.prototype.getOwner = function (name, callback) { var promiEvent = new PromiEvent(true); this.contract.then(function (contract) { return contract.methods.owner(namehash.hash(name)).call(); }).then(function (receipt) { if (_.isFunction(callback)) { // It's required to pass the receipt to the first argument to be backward compatible and to have the required consistency callback(receipt, receipt); return; } promiEvent.resolve(receipt); }).catch(function (error) { if (_.isFunction(callback)) { callback(error, null); return; } promiEvent.reject(error); }); return promiEvent.eventEmitter; }; /** * Returns the address of the owner of an ENS name. * * @method setOwner * * @param {string} name * @param {string} address * @param {TransactionConfig} txConfig * @param {function} callback * * @callback callback callback(error, result) * @returns {PromiEvent} */ Registry.prototype.setOwner = function (name, address, txConfig, callback) { var promiEvent = new PromiEvent(true); this.contract.then(function (contract) { return contract.methods.setOwner(namehash.hash(name), formatters.inputAddressFormatter(address)).send(txConfig); }).then(function (receipt) { if (_.isFunction(callback)) { // It's required to pass the receipt to the first argument to be backward compatible and to have the required consistency callback(receipt, receipt); return; } promiEvent.resolve(receipt); }).catch(function (error) { if (_.isFunction(callback)) { callback(error, null); return; } promiEvent.reject(error); }); return promiEvent.eventEmitter; }; /** * Returns the TTL of the given node by his name * * @method getTTL * * @param {string} name * @param {function} callback * * @callback callback callback(error, result) * @returnss {Promise} */ Registry.prototype.getTTL = function (name, callback) { var promiEvent = new PromiEvent(true); this.contract.then(function (contract) { return contract.methods.ttl(namehash.hash(name)).call(); }).then(function (receipt) { if (_.isFunction(callback)) { // It's required to pass the receipt to the first argument to be backward compatible and to have the required consistency callback(receipt, receipt); return; } promiEvent.resolve(receipt); }).catch(function (error) { if (_.isFunction(callback)) { callback(error, null); return; } promiEvent.reject(error); }); return promiEvent.eventEmitter; }; /** * Returns the address of the owner of an ENS name. * * @method setTTL * * @param {string} name * @param {number} ttl * @param {TransactionConfig} txConfig * @param {function} callback * * @callback callback callback(error, result) * @returns {PromiEvent} */ Registry.prototype.setTTL = function (name, ttl, txConfig, callback) { var promiEvent = new PromiEvent(true); this.contract.then(function (contract) { return contract.methods.setTTL(namehash.hash(name), ttl).send(txConfig); }).then(function (receipt) { if (_.isFunction(callback)) { // It's required to pass the receipt to the first argument to be backward compatible and to have the required consistency callback(receipt, receipt); return; } promiEvent.resolve(receipt); }).catch(function (error) { if (_.isFunction(callback)) { callback(error, null); return; } promiEvent.reject(error); }); return promiEvent.eventEmitter; }; /** * Returns the address of the owner of an ENS name. * * @method setSubnodeOwner * * @param {string} name * @param {string} label * @param {string} address * @param {TransactionConfig} txConfig * @param {function} callback * * @callback callback callback(error, result) * @returns {PromiEvent} */ Registry.prototype.setSubnodeOwner = function (name, label, address, txConfig, callback) { var promiEvent = new PromiEvent(true); if (!utils.isHexStrict(label)) { label = utils.sha3(label); } this.contract.then(function (contract) { return contract.methods.setSubnodeOwner(namehash.hash(name), label, formatters.inputAddressFormatter(address)).send(txConfig); }).then(function (receipt) { if (_.isFunction(callback)) { // It's required to pass the receipt to the first argument to be backward compatible and to have the required consistency callback(receipt, receipt); return; } promiEvent.resolve(receipt); }).catch(function (error) { if (_.isFunction(callback)) { callback(error, null); return; } promiEvent.reject(error); }); return promiEvent.eventEmitter; }; /** * Sets the owner, resolver, and TTL for an ENS record in a single operation. * * @method setRecord * * @param {string} name * @param {string} owner * @param {string} resolver * @param {string | number} ttl * @param {TransactionConfig} txConfig * @param {function} callback * * @callback callback callback(error, result) * @returns {PromiEvent} */ Registry.prototype.setRecord = function (name, owner, resolver, ttl, txConfig, callback) { var promiEvent = new PromiEvent(true); this.contract.then(function (contract) { return contract.methods.setRecord(namehash.hash(name), formatters.inputAddressFormatter(owner), formatters.inputAddressFormatter(resolver), ttl).send(txConfig); }).then(function (receipt) { if (_.isFunction(callback)) { // It's required to pass the receipt to the first argument to be backward compatible and to have the required consistency callback(receipt, receipt); return; } promiEvent.resolve(receipt); }).catch(function (error) { if (_.isFunction(callback)) { callback(error, null); return; } promiEvent.reject(error); }); return promiEvent.eventEmitter; }; /** * Sets the owner, resolver and TTL for a subdomain, creating it if necessary. * * @method setSubnodeRecord * * @param {string} name * @param {string} label * @param {string} owner * @param {string} resolver * @param {string | number} ttl * @param {TransactionConfig} txConfig * @param {function} callback * * @callback callback callback(error, result) * @returns {PromiEvent} */ Registry.prototype.setSubnodeRecord = function (name, label, owner, resolver, ttl, txConfig, callback) { var promiEvent = new PromiEvent(true); if (!utils.isHexStrict(label)) { label = utils.sha3(label); } this.contract.then(function (contract) { return contract.methods.setSubnodeRecord(namehash.hash(name), label, formatters.inputAddressFormatter(owner), formatters.inputAddressFormatter(resolver), ttl).send(txConfig); }).then(function (receipt) { if (_.isFunction(callback)) { // It's required to pass the receipt to the first argument to be backward compatible and to have the required consistency callback(receipt, receipt); return; } promiEvent.resolve(receipt); }).catch(function (error) { if (_.isFunction(callback)) { callback(error, null); return; } promiEvent.reject(error); }); return promiEvent.eventEmitter; }; /** * Sets or clears an approval by the given operator. * * @method setApprovalForAll * * @param {string} operator * @param {boolean} approved * @param {TransactionConfig} txConfig * @param {function} callback * * @callback callback callback(error, result) * @returns {PromiEvent} */ Registry.prototype.setApprovalForAll = function (operator, approved, txConfig, callback) { var promiEvent = new PromiEvent(true); this.contract.then(function (contract) { return contract.methods.setApprovalForAll(formatters.inputAddressFormatter(operator), approved).send(txConfig); }).then(function (receipt) { if (_.isFunction(callback)) { // It's required to pass the receipt to the first argument to be backward compatible and to have the required consistency callback(receipt, receipt); return; } promiEvent.resolve(receipt); }).catch(function (error) { if (_.isFunction(callback)) { callback(error, null); return; } promiEvent.reject(error); }); return promiEvent.eventEmitter; }; /** * Returns true if the operator is approved * * @method isApprovedForAll * * @param {string} owner * @param {string} operator * @param {function} callback * * @callback callback callback(error, result) * @returns {Promise} */ Registry.prototype.isApprovedForAll = function (owner, operator, callback) { var promiEvent = new PromiEvent(true); this.contract.then(function (contract) { return contract.methods.isApprovedForAll(formatters.inputAddressFormatter(owner), formatters.inputAddressFormatter(operator)).call(); }).then(function (receipt) { if (_.isFunction(callback)) { // It's required to pass the receipt to the first argument to be backward compatible and to have the required consistency callback(receipt, receipt); return; } promiEvent.resolve(receipt); }).catch(function (error) { if (_.isFunction(callback)) { callback(error, null); return; } promiEvent.reject(error); }); return promiEvent.eventEmitter; }; /** * Returns true if the record exists * * @method recordExists * * @param {string} name * @param {function} callback * * @callback callback callback(error, result) * @returns {Promise} */ Registry.prototype.recordExists = function (name, callback) { var promiEvent = new PromiEvent(true); this.contract.then(function (contract) { return contract.methods.recordExists(namehash.hash(name)).call(); }).then(function (receipt) { if (_.isFunction(callback)) { // It's required to pass the receipt to the first argument to be backward compatible and to have the required consistency callback(receipt, receipt); return; } promiEvent.resolve(receipt); }).catch(function (error) { if (_.isFunction(callback)) { callback(error, null); return; } promiEvent.reject(error); }); return promiEvent.eventEmitter; }; /** * Returns the resolver contract associated with a name. * * @deprecated Please use the "getResolver" method instead of "resolver" * * @method resolver * * @param {string} name * @param {function} callback * * @callback callback callback(error, result) * @returns {Promise} */ Registry.prototype.resolver = function (name, callback) { console.warn('Deprecated: Please use the "getResolver" method instead of "resolver".'); return this.getResolver(name, callback); }; /** * Returns the resolver contract associated with a name. * * @method getResolver * * @param {string} name * @param {function} callback * * @callback callback callback(error, result) * @returns {Promise} */ Registry.prototype.getResolver = function (name, callback) { var self = this; return this.contract.then(function (contract) { return contract.methods.resolver(namehash.hash(name)).call(); }).then(function (address) { var contract = new Contract(RESOLVER_ABI, address); contract.setProvider(self.ens.eth.currentProvider); if (_.isFunction(callback)) { // It's required to pass the contract to the first argument to be backward compatible and to have the required consistency callback(contract, contract); return; } return contract; }).catch(function (error) { if (_.isFunction(callback)) { callback(error, null); return; } throw error; }); }; /** * Returns the address of the owner of an ENS name. * * @method setResolver * * @param {string} name * @param {string} address * @param {TransactionConfig} txConfig * @param {function} callback * * @callback callback callback(error, result) * @returns {PromiEvent} */ Registry.prototype.setResolver = function (name, address, txConfig, callback) { var promiEvent = new PromiEvent(true); this.contract.then(function (contract) { return contract.methods.setResolver(namehash.hash(name), formatters.inputAddressFormatter(address)).send(txConfig); }).then(function (receipt) { if (_.isFunction(callback)) { // It's required to pass the receipt to the first argument to be backward compatible and to have the required consistency callback(receipt, receipt); return; } promiEvent.resolve(receipt); }).catch(function (error) { if (_.isFunction(callback)) { callback(error, null); return; } promiEvent.reject(error); }); return promiEvent.eventEmitter; }; module.exports = Registry;