diff --git a/CHANGELOG.md b/CHANGELOG.md index f1b12b33e4e..29e7aad08e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -142,6 +142,7 @@ Released with 1.0.0-beta.37 code base. ### Added - ENS module extended with the possibility to add a custom registry (#3301) +- Missing ENS Registry methods and Resolver.supportsInterface method added (#3325) ### Changed diff --git a/docs/web3-eth-ens.rst b/docs/web3-eth-ens.rst index c8ba666fb04..5292340213d 100644 --- a/docs/web3-eth-ens.rst +++ b/docs/web3-eth-ens.rst @@ -1,10 +1,11 @@ .. _eth-ens: -========= +============ web3.eth.ens -========= +============ The ``web3.eth.ens`` functions let you interacting with ENS. +We recommend reading the `documentation ENS `_ is providing to get deeper insights about the internals of the name service. ------------------------------------------------------------------------------ @@ -38,7 +39,7 @@ Example ------------------------------------------------------------------------------ registry -===================== +======== .. code-block:: javascript @@ -52,6 +53,22 @@ Returns ``Registry`` - The current ENS registry. +- ``contract: Contract`` - The ``Registry`` contract with the interface we know from the :ref:`Contract ` object. +- ``owner(name, callback): Promise`` - Deprecated please use ``getOwner`` +- ``getOwner(name, callback): Promise`` +- ``setOwner(name, address, txConfig, callback): PromiEvent`` +- ``resolver(name, callback): Promise`` - Deprecated please use ``getResolver`` +- ``getResolver(name, callback): Promise`` +- ``setResolver(name, address, txConfig, callback): PromiEvent`` +- ``getTTL(name, callback): Promise`` +- ``setTTL(name, ttl, txConfig, callback): PromiEvent`` +- ``setSubnodeOwner(name, label, address, txConfig, callback): PromiEvent`` +- ``setRecord(name, owner, resolver, ttl, txConfig, callback): PromiEvent`` +- ``setSubnodeRecord(name, label, owner, resolver, ttl, txConfig, callback): PromiEvent`` +- ``setApprovalForAll(operator, approved, txConfig, callback): PromiEvent`` +- ``isApprovedForAll(owner, operator, callback): Promise`` +- ``recordExists(name, callback): Promise`` + ------- Example ------- @@ -60,28 +77,49 @@ Example web3.eth.ens.registry; > { - ens: ENS, contract: Contract, - owner: Function(name), - resolve: Function(name) + owner: Function(name, callback), // Deprecated + getOwner: Function(name, callback), + setOwner: Function(name, address, txConfig, callback), + resolver: Function(name, callback), // Deprecated + getResolver: Function(name, callback), + setResolver: Function(name, address, txConfig, callback), + getTTL: Function(name, callback), + setTTL: Function(name, ttl, txConfig, callback), + setSubnodeOwner: Function(name, label, address, txConfig, callback), + setRecord(name, owner, resolver, ttl, txConfig, callback), + setSubnodeRecord(name, label, owner, resolver, ttl, txConfig, callback), + setApprovalForAll(operator, approved, txConfig, callback), + isApprovedForAll(owner, operator, txConfig, callback), + recordExists(name, callback) } ------------------------------------------------------------------------------ resolver -===================== +======== .. code-block:: javascript - web3.eth.ens.resolver(name); + web3.eth.ens.resolver(name [, callback]); Returns the resolver contract to an Ethereum address. +.. note:: + This method is deprecated please use ``getResolver`` + +---------- +Parameters +---------- + +1. ``name`` - ``String``: The ENS name. +2. ``callback`` - ``Function``: (optional) Optional callback + ------- Returns ------- -``Reslver`` - The ENS resolver for this name. +``Promise`` - The ENS resolver for this name. ------- Example @@ -96,12 +134,454 @@ Example ------------------------------------------------------------------------------ +getResolver +=========== + +.. code-block:: javascript + + web3.eth.ens.getResolver(name [, callback]); + +Returns the resolver contract to an Ethereum address. + +---------- +Parameters +---------- + +1. ``name`` - ``String``: The ENS name. +2. ``callback`` - ``Function``: (optional) Optional callback + +------- +Returns +------- + +``Promise`` - The ENS resolver for this name. + +------- +Example +------- + +.. code-block:: javascript + + web3.eth.ens.getResolver('ethereum.eth').then(function (contract) { + console.log(contract); + }); + > Contract + +------------------------------------------------------------------------------ + +setResolver +=========== + +.. code-block:: javascript + + web3.eth.ens.setResolver(name, address [, txConfig ] [, callback]); + +Does set the resolver contract address of a name. + +---------- +Parameters +---------- + +1. ``name`` - ``String``: The ENS name. +2. ``address`` - ``String``: The contract address of the deployed ``Resolver`` contract. +3. ``txConfig`` - ``Object``: (optional) The transaction options as described ::ref::`here ` +4. ``callback`` - ``Function``: (optional) Optional callback + +------- +Returns +------- + +``PromiEvent`` + +------- +Example +------- + +.. code-block:: javascript + + web3.eth.ens.setResolver('ethereum.eth', '0x...', {...}).then(function (receipt) { + console.log(receipt); + }); + > {...} + +------------------------------------------------------------------------------ + +getOwner +======== + +.. code-block:: javascript + + web3.eth.ens.getOwner(name [, callback]); + +Returns the owner of a name. + +---------- +Parameters +---------- + +1. ``name`` - ``String``: The ENS name. +2. ``callback`` - ``Function``: (optional) Optional callback + +------- +Returns +------- + +`Promise`` - The address of the registrar (EOA or CA). + +------- +Example +------- + +.. code-block:: javascript + + web3.eth.ens.getOwner('ethereum.eth').then(function (owner) { + console.log(owner); + }); + > '0x...' + + +------------------------------------------------------------------------------ + +setOwner +======== + +.. code-block:: javascript + + web3.eth.ens.setOwner(name [, txConfig ] [, callback]); + +Does set the owner of the given name. + +---------- +Parameters +---------- + +1. ``name`` - ``String``: The ENS name. +2. ``txConfig`` - ``Object``: (optional) The transaction options as described ::ref::`here ` +3. ``callback`` - ``Function``: (optional) Optional callback + +------- +Returns +------- + +``PromiEvent`` + +------- +Example +------- + +.. code-block:: javascript + + web3.eth.ens.setOwner('ethereum.eth', {...}).then(function (receipt) { + console.log(receipt); + }); + > {...} + +------------------------------------------------------------------------------ + +getTTL +====== + +.. code-block:: javascript + + web3.eth.ens.getTTL(name [, callback]); + +Returns the caching TTL (time-to-live) of a name. + +---------- +Parameters +---------- + +1. ``name`` - ``String``: The ENS name. +2. ``callback`` - ``Function``: (optional) Optional callback + +------- +Returns +------- + +``Promise`` + +------- +Example +------- + +.. code-block:: javascript + + web3.eth.ens.getTTL('ethereum.eth').then(function (ttl) { + console.log(ttl); + }); + > 100000 + +------------------------------------------------------------------------------ + +setTTL +====== + +.. code-block:: javascript + + web3.eth.ens.setTTL(name, ttl [, txConfig ] [, callback]); + +Does set the caching TTL (time-to-live) of a name. + +---------- +Parameters +---------- + +1. ``name`` - ``String``: The ENS name. +2. ``ttl`` - ``Number``: The TTL value (uint64) +3. ``txConfig`` - ``Object``: (optional) The transaction options as described ::ref::`here ` +4. ``callback`` - ``Function``: (optional) Optional callback + +------- +Returns +------- + +``PromiEvent`` + +------- +Example +------- + +.. code-block:: javascript + + web3.eth.ens.setTTL('ethereum.eth', 10000, {...}).then(function (receipt) { + console.log(receipt); + }); + > {...} + +------------------------------------------------------------------------------ + +setSubnodeOwner +=============== + +.. code-block:: javascript + + web3.eth.ens.setSubnodeOwner(name, label, address [, txConfig ] [, callback]); + +Creates a new subdomain of the given node, assigning ownership of it to the specified owner + +---------- +Parameters +---------- + +1. ``name`` - ``String``: The ENS name. +2. ``label`` - ``String``: The name of the sub-domain or the sha3 hash of it +3. ``address`` - ``String``: The registrar of this sub-domain +4. ``txConfig`` - ``Object``: (optional) The transaction options as described ::ref::`here ` +5. ``callback`` - ``Function``: (optional) Optional callback + +------- +Returns +------- + +``PromiEvent`` + +------- +Example +------- + +.. code-block:: javascript + + web3.eth.ens.setSubnodeOwner('ethereum.eth', 'web3', '0x...', {...}).then(function (receipt) { + console.log(receipt); // successfully defined the owner of web3.ethereum.eth + }); + > {...} + +------------------------------------------------------------------------------ + +setRecord +========= + +.. code-block:: javascript + + web3.eth.ens.setRecord(name, owner, resolver, ttl, [, txConfig ] [, callback]); + +Sets the owner, resolver, and TTL for an ENS record in a single operation. + +---------- +Parameters +---------- + +1. ``name`` - ``String``: The ENS name. +2. ``owner`` - ``String``: The owner of the name record +3. ``resolver`` - ``String``: The resolver address of the name record +4. ``ttl`` - ``String | Number``: Time to live value (uint64) +5. ``txConfig`` - ``Object``: (optional) The transaction options as described ::ref::`here ` +6. ``callback`` - ``Function``: (optional) Optional callback + +------- +Returns +------- + +``PromiEvent`` + +------- +Example +------- + +.. code-block:: javascript + + web3.eth.ens.setRecord('ethereum.eth', '0x...', '0x...', 1000000, {...}).then(function (receipt) { + console.log(receipt); // successfully registered ethereum.eth + }); + > {...} + +------------------------------------------------------------------------------ + +setSubnodeRecord +================ + +.. code-block:: javascript + + web3.eth.ens.setSubnodeRecord(name, label, owner, resolver, ttl, [, txConfig ] [, callback]); + +Sets the owner, resolver and TTL for a subdomain, creating it if necessary. + +---------- +Parameters +---------- + +1. ``name`` - ``String``: The ENS name. +2. ``label`` - ``String``: The name of the sub-domain or the sha3 hash of it +3. ``owner`` - ``String``: The owner of the name record +4. ``resolver`` - ``String``: The resolver address of the name record +5. ``ttl`` - ``String | Number``: Time to live value (uint64) +6. ``txConfig`` - ``Object``: (optional) The transaction options as described ::ref::`here ` +7. ``callback`` - ``Function``: (optional) Optional callback + +------- +Returns +------- + +``PromiEvent`` + +------- +Example +------- + +.. code-block:: javascript + + web3.eth.ens.setSubnodeRecord('ethereum.eth', 'web3', '0x...', '0x...', 1000000, {...}).then(function (receipt) { + console.log(receipt); // successfully registered web3.ethereum.eth + }); + > {...} + +------------------------------------------------------------------------------ + +setApprovalForAll +================= + +.. code-block:: javascript + + web3.eth.ens.setApprovalForAll(operator, approved, [, txConfig ] [, callback]); + +Sets or clears an approval. Approved accounts can execute all ENS registry operations on behalf of the caller. + +---------- +Parameters +---------- + +1. ``operator`` - ``String``: The operator address +2. ``approved`` - ``Boolean`` +3. ``txConfig`` - ``Object``: (optional) The transaction options as described ::ref::`here ` +4. ``callback`` - ``Function``: (optional) Optional callback + +------- +Returns +------- + +``PromiEvent`` + +------- +Example +------- + +.. code-block:: javascript + + web3.eth.ens.setApprovalForAll('0x...', true, {...}).then(function (receipt) { + console.log(receipt); + }); + > {...} + +------------------------------------------------------------------------------ + +isApprovedForAll +================ + +.. code-block:: javascript + + web3.eth.ens.isApprovedForAll(owner, operator [, callback]); + +Returns ``true`` if the operator is approved to make ENS registry operations on behalf of the owner. + +---------- +Parameters +---------- + +1. ``owner`` - ``String``: The owner address. +2. ``operator`` - ``String``: The operator address. +3. ``callback`` - ``Function``: (optional) Optional callback + +------- +Returns +------- + +``Promise`` + +------- +Example +------- + +.. code-block:: javascript + + web3.eth.ens.isApprovedForAll('0x0...', '0x0...').then(function (isApproved) { + console.log(isApproved); + }) + > true + +------------------------------------------------------------------------------ + +recordExists +============ + +.. code-block:: javascript + + web3.eth.ens.recordExists(name [, callback]); + +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. + +---------- +Parameters +---------- + +1. ``name`` - ``String``: The ENS name. +2. ``callback`` - ``Function``: (optional) Optional callback + +------- +Returns +------- + +``Promise`` + +------- +Example +------- + +.. code-block:: javascript + + web3.eth.ens.recordExists('0x0...', '0x0...').then(function (isExisting) { + console.log(isExisting); + }) + > true + +------------------------------------------------------------------------------ + getAddress ===================== .. code-block:: javascript - web3.eth.ens.getAddress(ENSName); + web3.eth.ens.getAddress(ENSName [, callback]); Resolves an ENS name to an Ethereum address. @@ -110,6 +590,7 @@ Parameters ---------- 1. ``ENSName`` - ``String``: The ENS name to resolve. +2. ``callback`` - ``Function``: (optional) Optional callback ------- Returns @@ -135,7 +616,7 @@ setAddress .. code-block:: javascript - web3.eth.ens.setAddress(ENSName, address, options); + web3.eth.ens.setAddress(ENSName, address [, txConfig ] [, callback]); Sets the address of an ENS name in his resolver. @@ -145,13 +626,17 @@ Parameters 1. ``ENSName`` - ``String``: The ENS name. 2. ``address`` - ``String``: The address to set. -3. ``options`` - ``Object``: The options used for sending. - * ``from`` - ``String``: The address the transaction should be sent from. - * ``gasPrice`` - ``String`` (optional): The gas price in wei to use for this transaction. - * ``gas`` - ``Number`` (optional): The maximum gas provided for this transaction (gas limit). +3. ``txConfig`` - ``Object``: (optional) The transaction options as described ::ref::`here ` +4. ``callback`` - ``Function``: (optional) Optional callback Emits an ``AddrChanged`` event. +------- +Returns +------- + +``PromiEvent`` + ------- Example ------- @@ -205,7 +690,7 @@ Example }); - For further information on the handling of contract events please see here contract-events_. +For further information on the handling of contract events please see :ref:`here `. ------------------------------------------------------------------------------ @@ -214,7 +699,7 @@ getPubkey .. code-block:: javascript - web3.eth.ens.getPubkey(ENSName); + web3.eth.ens.getPubkey(ENSName [, callback]); Returns the X and Y coordinates of the curve point for the public key. @@ -223,12 +708,13 @@ Parameters ---------- 1. ``ENSName`` - ``String``: The ENS name. +2. ``callback`` - ``Function``: (optional) Optional callback ------- Returns ------- -``Object`` - The X and Y coordinates. +``Promise>`` - The X and Y coordinates. ------- Example @@ -253,7 +739,7 @@ setPubkey .. code-block:: javascript - web3.eth.ens.setPubkey(ENSName, x, y, options); + web3.eth.ens.setPubkey(ENSName, x, y [, txConfig ] [, callback]); Sets the SECP256k1 public key associated with an ENS node @@ -264,14 +750,17 @@ Parameters 1. ``ENSName`` - ``String``: The ENS name. 2. ``x`` - ``String``: The X coordinate of the public key. 3. ``y`` - ``String``: The Y coordinate of the public key. -4. ``options`` - ``Object``: The options used for sending. - * ``from`` - ``String``: The address the transaction should be sent from. - * ``gasPrice`` - ``String`` (optional): The gas price in wei to use for this transaction. - * ``gas`` - ``Number`` (optional): The maximum gas provided for this transaction (gas limit). - +4. ``txConfig`` - ``Object``: (optional) The transaction options as described ::ref::`here ` +5. ``callback`` - ``Function``: (optional) Optional callback Emits an ``PubkeyChanged`` event. +------- +Returns +------- + +``PromiEvent`` + ------- Example ------- @@ -327,7 +816,7 @@ Example }); - For further information on the handling of contract events please see here contract-events_. +For further information on the handling of contract events please see :ref:`here `. ------------------------------------------------------------------------------ @@ -336,7 +825,7 @@ getContent .. code-block:: javascript - web3.eth.ens.getContent(ENSName); + web3.eth.ens.getContent(ENSName [, callback]); Returns the content hash associated with an ENS node. @@ -345,12 +834,13 @@ Parameters ---------- 1. ``ENSName`` - ``String``: The ENS name. +2. ``callback`` - ``Function``: (optional) Optional callback ------- Returns ------- -``String`` - The content hash associated with an ENS node. +``Promise`` - The content hash associated with an ENS node. ------- Example @@ -370,7 +860,7 @@ setContent .. code-block:: javascript - web3.eth.ens.setContent(ENSName, hash, options); + web3.eth.ens.setContent(ENSName, hash [, txConfig ] [, callback]); Sets the content hash associated with an ENS node. @@ -380,14 +870,17 @@ Parameters 1. ``ENSName`` - ``String``: The ENS name. 2. ``hash`` - ``String``: The content hash to set. -3. ``options`` - ``Object``: The options used for sending. - * ``from`` - ``String``: The address the transaction should be sent from. - * ``gasPrice`` - ``String`` (optional): The gas price in wei to use for this transaction. - * ``gas`` - ``Number`` (optional): The maximum gas provided for this transaction (gas limit). - +3. ``txConfig`` - ``Object``: (optional) The transaction options as described ::ref::`here ` +4. ``callback`` - ``Function``: (optional) Optional callback Emits an ``ContentChanged`` event. +------- +Returns +------- + +``PromiEvent`` + ------- Example ------- @@ -441,7 +934,7 @@ Example }); - For further information on the handling of contract events please see here contract-events_. +For further information on the handling of contract events please see :ref:`here `. ------------------------------------------------------------------------------ @@ -450,7 +943,7 @@ getMultihash .. code-block:: javascript - web3.eth.ens.getMultihash(ENSName); + web3.eth.ens.getMultihash(ENSName [, callback]); Returns the multihash associated with an ENS node. @@ -459,12 +952,13 @@ Parameters ---------- 1. ``ENSName`` - ``String``: The ENS name. +2. ``callback`` - ``Function``: (optional) Optional callback ------- Returns ------- -``String`` - The associated multihash. +``Promise`` - The associated multihash. ------- Example @@ -479,12 +973,48 @@ Example ------------------------------------------------------------------------------ +supportsInterface +================= + +.. code-block:: javascript + + web3.eth.ens.supportsInterface(name, interfaceId [, callback]); + +Returns ``true`` if the related ``Resolver`` does support the given signature or interfaceId. + +---------- +Parameters +---------- + +1. ``name`` - ``String``: The ENS name. +2. ``interfaceId`` - ``String``: The signature of the function or the interfaceId as described in the ENS documentation +3. ``callback`` - ``Function``: (optional) Optional callback + +------- +Returns +------- + +``Promise`` + +------- +Example +------- + +.. code-block:: javascript + + web3.eth.ens.supportsInterface('ethereum.eth', 'addr(bytes32').then(function (result) { + console.log(result); + }); + > true + +------------------------------------------------------------------------------ + setMultihash ===================== .. code-block:: javascript - web3.eth.ens.setMultihash(ENSName, hash, options); + web3.eth.ens.setMultihash(ENSName, hash [, txConfig ] [, callback]); Sets the multihash associated with an ENS node. @@ -494,14 +1024,17 @@ Parameters 1. ``ENSName`` - ``String``: The ENS name. 2. ``hash`` - ``String``: The multihash to set. -3. ``options`` - ``Object``: The options used for sending. - * ``from`` - ``String``: The address the transaction should be sent from. - * ``gasPrice`` - ``String`` (optional): The gas price in wei to use for this transaction. - * ``gas`` - ``Number`` (optional): The maximum gas provided for this transaction (gas limit). - +3. ``txConfig`` - ``Object``: (optional) The transaction options as described ::ref::`here ` +4. ``callback`` - ``Function``: (optional) Optional callback Emits an ``MultihashChanged``event. +------- +Returns +------- + +``PromiEvent`` + ------- Example ------- @@ -540,7 +1073,7 @@ Example .on('error', console.error); - For further information on the handling of contract events please see here contract-events_. +For further information on the handling of contract events please see :ref:`here `. ------------------------------------------------------------------------------ @@ -559,6 +1092,12 @@ Known resolver events 5. ABIChanged(node bytes32, contentType uint256) 6. PubkeyChanged(node bytes32, x bytes32, y bytes32) +------- +Returns +------- + +``PromiEvent`` + ------- Example ------- @@ -648,7 +1187,5 @@ Example address: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' } -For further information on the handling of contract events please see here contract-events_. - ------------------------------------------------------------------------------- +For further information on the handling of contract events please see :ref:`here `. diff --git a/packages/web3-eth-contract/types/index.d.ts b/packages/web3-eth-contract/types/index.d.ts index 6f141abaf35..336f15fc487 100644 --- a/packages/web3-eth-contract/types/index.d.ts +++ b/packages/web3-eth-contract/types/index.d.ts @@ -21,6 +21,7 @@ import BN = require('bn.js'); import {Common, PromiEvent, provider, hardfork, chain, BlockNumber, PastLogsOptions, LogsOptions} from 'web3-core'; import {AbiItem} from 'web3-utils'; +// TODO: Add generic type! export class Contract { constructor( jsonInterface: AbiItem[], diff --git a/packages/web3-eth-ens/src/ENS.js b/packages/web3-eth-ens/src/ENS.js index 2bef09a51a2..7eaf0330d52 100644 --- a/packages/web3-eth-ens/src/ENS.js +++ b/packages/web3-eth-ens/src/ENS.js @@ -20,16 +20,18 @@ "use strict"; +var _ = require('underscore'); var config = require('./config'); var formatters = require('web3-core-helpers').formatters; +var utils = require('web3-utils'); var Registry = require('./contracts/Registry'); var ResolverMethodHandler = require('./lib/ResolverMethodHandler'); /** * Constructs a new instance of ENS * - * @method ENS - * @param {Object} eth + * @param {Eth} eth + * * @constructor */ function ENS(eth) { @@ -70,20 +72,263 @@ function ENS(eth) { } /** + * Returns true if the given interfaceId is supported and otherwise false. + * + * @method supportsInterface + * + * @param {string} name + * @param {string} interfaceId + * @param {function} callback + * + * @callback callback callback(error, result) + * @returns {Promise} + */ +ENS.prototype.supportsInterface = function (name, interfaceId, callback) { + return this.getResolver(name).then(function (resolver) { + if (!utils.isHexStrict(interfaceId)) { + interfaceId = utils.sha3(interfaceId).slice(0,10); + } + + return resolver.methods.supportsInterface(interfaceId).call(callback); + }).catch(function(error) { + if (_.isFunction(callback)) { + callback(error, null); + + return; + } + + throw error; + }); +}; + +/** + * Returns the Resolver by the given address + * + * @deprecated Please use the "getResolver" method instead of "resolver" + * + * @method resolver + * * @param {string} name + * @param {function} callback + * + * @callback callback callback(error, result) + * @returns {Promise} + */ +ENS.prototype.resolver = function (name, callback) { + return this.registry.resolver(name, callback); +}; + +/** + * Returns the Resolver by the given address + * + * @method getResolver + * + * @param {string} name + * @param {function} callback + * + * @callback callback callback(error, result) * @returns {Promise} */ -ENS.prototype.resolver = function (name) { - return this.registry.resolver(name); +ENS.prototype.getResolver = function (name, callback) { + return this.registry.getResolver(name, callback); +}; + +/** + * Does set the resolver of the given name + * + * @method setResolver + * + * @param {string} name + * @param {string} address + * @param {TransactionConfig} txConfig + * @param {function} callback + * + * @callback callback callback(error, result) + * @returns {PromiEvent} + */ +ENS.prototype.setResolver = function (name, address, txConfig, callback) { + return this.registry.setResolver(name, address, txConfig, callback); +}; + +/** + * 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} + */ +ENS.prototype.setRecord = function (name, owner, resolver, ttl, txConfig, callback) { + return this.registry.setRecord(name, owner, resolver, ttl, txConfig, callback); +}; + +/** + * 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} + */ +ENS.prototype.setSubnodeRecord = function (name, label, owner, resolver, ttl, txConfig, callback) { + return this.registry.setSubnodeRecord(name, label, owner, resolver, ttl, txConfig, callback); +}; + +/** + * 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} + */ +ENS.prototype.setApprovalForAll = function (operator, approved, txConfig, callback) { + return this.registry.setApprovalForAll(operator, approved, txConfig, callback); +}; + +/** + * 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} + */ +ENS.prototype.isApprovedForAll = function (owner, operator, callback) { + return this.registry.isApprovedForAll(owner, operator, callback); +}; + +/** + * Returns true if the record exists + * + * @method recordExists + * + * @param {string} name + * @param {function} callback + * + * @callback callback callback(error, result) + * @returns {Promise} + */ +ENS.prototype.recordExists = function (name, callback) { + return this.registry.recordExists(name, callback); +}; + +/** + * 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} + */ +ENS.prototype.setSubnodeOwner = function (name, label, address, txConfig, callback) { + return this.registry.setSubnodeOwner(name, label, address, txConfig, callback); +}; + +/** + * Returns the address of the owner of an ENS name. + * + * @method getTTL + * + * @param {string} name + * @param {function} callback + * + * @callback callback callback(error, result) + * @returns {PromiEvent} + */ +ENS.prototype.getTTL = function (name, callback) { + return this.registry.getTTL(name, callback); +}; + +/** + * 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} + */ +ENS.prototype.setTTL = function (name, ttl, txConfig, callback) { + return this.registry.setTTL(name, ttl, txConfig, callback); +}; + +/** + * Returns the owner by the given name and current configured or detected Registry + * + * @method getOwner + * + * @param {string} name + * @param {function} callback + * + * @callback callback callback(error, result) + * @returns {PromiEvent} + */ +ENS.prototype.getOwner = function (name, callback) { + return this.registry.getOwner(name, callback); +}; + +/** + * 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} + */ +ENS.prototype.setOwner = function (name, address, txConfig, callback) { + return this.registry.setOwner(name, address, txConfig, callback); }; /** * Returns the address record associated with a name. * * @method getAddress + * * @param {string} name * @param {function} callback - * @return {eventifiedPromise} + * + * @callback callback callback(error, result) + * @returns {PromiEvent} */ ENS.prototype.getAddress = function (name, callback) { return this.resolverMethodHandler.method(name, 'addr', []).call(callback); @@ -93,23 +338,29 @@ ENS.prototype.getAddress = function (name, callback) { * Sets a new address * * @method setAddress + * * @param {string} name * @param {string} address - * @param {Object} sendOptions + * @param {TransactionConfig} txConfig * @param {function} callback - * @returns {eventifiedPromise} + * + * @callback callback callback(error, result) + * @returns {PromiEvent} */ -ENS.prototype.setAddress = function (name, address, sendOptions, callback) { - return this.resolverMethodHandler.method(name, 'setAddr', [address]).send(sendOptions, callback); +ENS.prototype.setAddress = function (name, address, txConfig, callback) { + return this.resolverMethodHandler.method(name, 'setAddr', [address]).send(txConfig, callback); }; /** * Returns the public key * * @method getPubkey + * * @param {string} name * @param {function} callback - * @returns {eventifiedPromise} + * + * @callback callback callback(error, result) + * @returns {PromiEvent} */ ENS.prototype.getPubkey = function (name, callback) { return this.resolverMethodHandler.method(name, 'pubkey', [], callback).call(callback); @@ -119,24 +370,30 @@ ENS.prototype.getPubkey = function (name, callback) { * Set the new public key * * @method setPubkey + * * @param {string} name * @param {string} x * @param {string} y - * @param {Object} sendOptions + * @param {TransactionConfig} txConfig * @param {function} callback - * @returns {eventifiedPromise} + * + * @callback callback callback(error, result) + * @returns {PromiEvent} */ -ENS.prototype.setPubkey = function (name, x, y, sendOptions, callback) { - return this.resolverMethodHandler.method(name, 'setPubkey', [x, y]).send(sendOptions, callback); +ENS.prototype.setPubkey = function (name, x, y, txConfig, callback) { + return this.resolverMethodHandler.method(name, 'setPubkey', [x, y]).send(txConfig, callback); }; /** * Returns the content * * @method getContent + * * @param {string} name * @param {function} callback - * @returns {eventifiedPromise} + * + * @callback callback callback(error, result) + * @returns {PromiEvent} */ ENS.prototype.getContent = function (name, callback) { return this.resolverMethodHandler.method(name, 'content', []).call(callback); @@ -146,23 +403,29 @@ ENS.prototype.getContent = function (name, callback) { * Set the content * * @method setContent + * * @param {string} name * @param {string} hash * @param {function} callback - * @param {Object} sendOptions - * @returns {eventifiedPromise} + * @param {TransactionConfig} txConfig + * + * @callback callback callback(error, result) + * @returns {PromiEvent} */ -ENS.prototype.setContent = function (name, hash, sendOptions, callback) { - return this.resolverMethodHandler.method(name, 'setContent', [hash]).send(sendOptions, callback); +ENS.prototype.setContent = function (name, hash, txConfig, callback) { + return this.resolverMethodHandler.method(name, 'setContent', [hash]).send(txConfig, callback); }; /** * Get the multihash * * @method getMultihash + * * @param {string} name * @param {function} callback - * @returns {eventifiedPromise} + * + * @callback callback callback(error, result) + * @returns {PromiEvent} */ ENS.prototype.getMultihash = function (name, callback) { return this.resolverMethodHandler.method(name, 'multihash', []).call(callback); @@ -172,21 +435,24 @@ ENS.prototype.getMultihash = function (name, callback) { * Set the multihash * * @method setMultihash + * * @param {string} name * @param {string} hash - * @param {Object} sendOptions + * @param {TransactionConfig} txConfig * @param {function} callback - * @returns {eventifiedPromise} + * + * @callback callback callback(error, result) + * @returns {PromiEvent} */ -ENS.prototype.setMultihash = function (name, hash, sendOptions, callback) { - return this.resolverMethodHandler.method(name, 'multihash', [hash]).send(sendOptions, callback); +ENS.prototype.setMultihash = function (name, hash, txConfig, callback) { + return this.resolverMethodHandler.method(name, 'multihash', [hash]).send(txConfig, callback); }; /** * Checks if the current used network is synced and looks for ENS support there. * Throws an error if not. * - * @returns {Promise} + * @returns {Promise} */ ENS.prototype.checkNetwork = async function () { var now = new Date() / 1000; diff --git a/packages/web3-eth-ens/src/contracts/Registry.js b/packages/web3-eth-ens/src/contracts/Registry.js index 783761f8019..6e375bdfae7 100644 --- a/packages/web3-eth-ens/src/contracts/Registry.js +++ b/packages/web3-eth-ens/src/contracts/Registry.js @@ -24,6 +24,8 @@ 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('../ressources/ABI/Registry'); var RESOLVER_ABI = require('../ressources/ABI/Resolver'); @@ -49,30 +51,442 @@ function Registry(ens) { /** * 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 - * @return {Promise} + * + * @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) { - contract.methods.owner(namehash.hash(name)).call() - .then(function (receipt) { - promiEvent.resolve(receipt); - - if (_.isFunction(callback)) { - callback(receipt); - } - }) - .catch(function (error) { - promiEvent.reject(error); - - if (_.isFunction(callback)) { - callback(error); - } - }); + 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; @@ -81,11 +495,34 @@ Registry.prototype.owner = function (name, callback) { /** * 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 - * @return {Promise} + * @param {function} callback + * + * @callback callback callback(error, result) + * @returns {Promise} */ -Registry.prototype.resolver = function (name) { +Registry.prototype.getResolver = function (name, callback) { var self = this; return this.contract.then(function (contract) { @@ -93,8 +530,64 @@ Registry.prototype.resolver = function (name) { }).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; diff --git a/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js b/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js index 39ee146d65a..069e82474cb 100644 --- a/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js +++ b/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js @@ -70,9 +70,15 @@ ResolverMethodHandler.prototype.call = function (callback) { var promiEvent = new PromiEvent(); var preparedArguments = this.parent.prepareArguments(this.ensName, this.methodArguments); - this.parent.registry.resolver(this.ensName).then(function (resolver) { + this.parent.registry.getResolver(this.ensName).then(function (resolver) { self.parent.handleCall(promiEvent, resolver.methods[self.methodName], preparedArguments, callback); - }).catch(function (error) { + }).catch(function(error) { + if (_.isFunction(callback)) { + callback(error, null); + + return; + } + promiEvent.reject(error); }); @@ -92,9 +98,15 @@ ResolverMethodHandler.prototype.send = function (sendOptions, callback) { var promiEvent = new PromiEvent(); var preparedArguments = this.parent.prepareArguments(this.ensName, this.methodArguments); - this.parent.registry.resolver(this.ensName).then(function (resolver) { + this.parent.registry.getResolver(this.ensName).then(function (resolver) { self.parent.handleSend(promiEvent, resolver.methods[self.methodName], preparedArguments, sendOptions, callback); - }).catch(function (error) { + }).catch(function(error) { + if (_.isFunction(callback)) { + callback(error, null); + + return; + } + promiEvent.reject(error); }); @@ -112,18 +124,23 @@ ResolverMethodHandler.prototype.send = function (sendOptions, callback) { */ ResolverMethodHandler.prototype.handleCall = function (promiEvent, method, preparedArguments, callback) { method.apply(this, preparedArguments).call() - .then(function (receipt) { - promiEvent.resolve(receipt); - + .then(function (result) { if (_.isFunction(callback)) { - callback(receipt); + // It's required to pass the receipt to the second argument to be backwards compatible and to have the required consistency + callback(result, result); + + return; } - }).catch(function (error) { - promiEvent.reject(error); + promiEvent.resolve(result); + }).catch(function (error) { if (_.isFunction(callback)) { - callback(error); + callback(error, null); + + return; } + + promiEvent.reject(error); }); return promiEvent; @@ -152,16 +169,20 @@ ResolverMethodHandler.prototype.handleSend = function (promiEvent, method, prepa promiEvent.resolve(receipt); if (_.isFunction(callback)) { - callback(receipt); + // It's required to pass the receipt to the second argument to be backwards compatible and to have the required consistency + callback(receipt, receipt); } }) .on('error', function (error) { promiEvent.eventEmitter.emit('error', error); - promiEvent.reject(error); if (_.isFunction(callback)) { - callback(error); + callback(error, null); + + return; } + + promiEvent.reject(error); }); return promiEvent; @@ -172,6 +193,7 @@ ResolverMethodHandler.prototype.handleSend = function (promiEvent, method, prepa * * @param {string} name * @param {array} methodArguments + * * @returns {array} */ ResolverMethodHandler.prototype.prepareArguments = function (name, methodArguments) { diff --git a/packages/web3-eth-ens/src/ressources/ABI/Registry.js b/packages/web3-eth-ens/src/ressources/ABI/Registry.js index 5524362483e..092788a55b3 100644 --- a/packages/web3-eth-ens/src/ressources/ABI/Registry.js +++ b/packages/web3-eth-ens/src/ressources/ABI/Registry.js @@ -199,6 +199,163 @@ var REGISTRY = [ ], "name": "NewTTL", "type": "event" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "bytes32", + "name": "node", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "resolver", + "type": "address" + }, + { + "internalType": "uint64", + "name": "ttl", + "type": "uint64" + } + ], + "name": "setRecord", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "bytes32", + "name": "node", + "type": "bytes32" + } + ], + "name": "recordExists", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "bytes32", + "name": "node", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "label", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "resolver", + "type": "address" + }, + { + "internalType": "uint64", + "name": "ttl", + "type": "uint64" + } + ], + "name": "setSubnodeRecord", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" } ]; diff --git a/packages/web3-eth-ens/types/index.d.ts b/packages/web3-eth-ens/types/index.d.ts index 4f3b6b62351..5c50d7b8976 100644 --- a/packages/web3-eth-ens/types/index.d.ts +++ b/packages/web3-eth-ens/types/index.d.ts @@ -17,24 +17,171 @@ * @date 2018 */ -import { PromiEvent, TransactionConfig } from 'web3-core'; +import { PromiEvent, TransactionConfig, TransactionReceipt } from 'web3-core'; +import { TransactionRevertInstructionError } from 'web3-core-helpers'; import { Eth } from 'web3-eth'; import { Contract } from 'web3-eth-contract'; +// TODO: Define as soon as implemented the generic contract export class Ens { constructor(eth: Eth); registryAddress: string | null; registry: Registry; - resolver(name: string): Promise; - + /** + * @deprecated This callback signature is deprecated + */ + supportsInterface( + name: string, + interfaceId: string, + callback?: (value: any) => void + ): Promise; supportsInterface( name: string, interfaceId: string, - callback?: (error: Error, supportsInterface: boolean) => void + callback?: (error: Error, supported: boolean) => void ): Promise; + /** + * @deprecated Please use the "getResolver" method instead of "resolver" + */ + resolver( + name: string, + callback?: (error: Error, contract: Contract) => void + ): Promise; + /** + * @deprecated Please use the "getResolver" method instead of "resolver" + */ + resolver( + name: string, + callback?: (value: any) => void + ): Promise; + + /** + * @deprecated This callback signature is deprecated + */ + getResolver( + name: string, + callback?: (value: any) => void + ): Promise; + getResolver( + name: string, + callback?: (error: Error, contract: Contract) => void + ): Promise; + + setResolver( + name: string, + address: string, + txConfig?: TransactionConfig, + callback?: (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => void + ): PromiEvent + + setSubnodeOwner( + name: string, + label: string, + address: string, + txConfig?: TransactionConfig, + callback?: (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => void + ): PromiEvent + + setRecord( + name: string, + owner: string, + resolver: string, + ttl: number | string, + txConfig?: TransactionConfig, + callback?: (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => void + ): PromiEvent + + setSubnodeRecord( + name: string, + label: string, + owner: string, + resolver: string, + ttl: number | string, + txConfig?: TransactionConfig, + callback?: (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => void + ): PromiEvent + + setApprovalForAll( + operator: string, + approved: boolean, + txConfig?: TransactionConfig, + callback?: (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => void + ): PromiEvent + + /** + * @deprecated This callback signature is deprecated + */ + isApprovedForAll( + owner: string, + operator: string, + callback?: (value: any) => void + ): Promise; + isApprovedForAll( + owner: string, + operator: string, + callback?: (error: Error, result: boolean) => void + ): Promise; + + /** + * @deprecated This callback signature is deprecated + */ + recordExists( + name: string, + callback?: (value: any) => void + ): Promise; + recordExists( + name: string, + callback?: (error: Error, result: boolean) => void + ): Promise; + + /** + * @deprecated This callback signature is deprecated + */ + getTTL( + name: string, + callback?: (value: any) => void + ): Promise; + getTTL( + name: string, + callback?: (error: Error, ttl: string) => void + ): Promise; + + setTTL( + name: string, + ttl: string | number, + txConfig?: TransactionConfig, + callback?: (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => void + ): PromiEvent; + + /** + * @deprecated This callback signature is deprecated + */ + getOwner( + name: string, + callback?: (value: any) => void + ): Promise; + getOwner( + name: string, + callback?: (error: Error, owner: string) => void + ): Promise; + + setOwner( + name: string, + address: string, + txConfig?: TransactionConfig, + callback?: (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => void + ): PromiEvent; + + /** + * @deprecated This callback signature is deprecated + */ + getAddress( + name: string, + callback?: (value: any) => void + ): Promise; getAddress( name: string, callback?: (error: Error, address: string) => void @@ -43,10 +190,17 @@ export class Ens { setAddress( name: string, address: string, - sendOptions: TransactionConfig, - callback?: (error: Error, result: any) => void - ): PromiEvent; + txConfig?: TransactionConfig, + callback?: (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => void + ): PromiEvent; + /** + * @deprecated This callback signature is deprecated + */ + getPubkey( + name: string, + callback?: (value: any) => void + ): Promise<{ [x: string]: string }>; getPubkey( name: string, callback?: (error: Error, result: { [x: string]: string }) => void @@ -56,10 +210,18 @@ export class Ens { name: string, x: string, y: string, - sendOptions: TransactionConfig, - callback?: (error: Error, result: any) => void - ): PromiEvent; + txConfig?: TransactionConfig, + callback?: (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => void + ): PromiEvent; + /** + * @deprecated This callback signature is deprecated + */ + getText( + name: string, + key: string, + callback?: (value: any) => void + ): Promise; getText( name: string, key: string, @@ -70,10 +232,17 @@ export class Ens { name: string, key: string, value: string, - sendOptions: TransactionConfig, - callback?: (error: Error, result: any) => void - ): PromiEvent; + txConfig?: TransactionConfig, + callback?: (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => void + ): PromiEvent; + /** + * @deprecated This callback signature is deprecated + */ + getContent( + name: string, + callback?: (value: any) => void + ): Promise; getContent( name: string, callback?: (error: Error, contentHash: string) => void @@ -82,10 +251,17 @@ export class Ens { setContent( name: string, hash: string, - sendOptions: TransactionConfig, - callback?: (error: Error, result: any) => void - ): PromiEvent; + txConfig?: TransactionConfig, + callback?: (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => void + ): PromiEvent; + /** + * @deprecated This callback signature is deprecated + */ + getMultihash( + name: string, + callback?: (value: any) => void + ): Promise; getMultihash( name: string, callback?: (error: Error, multihash: string) => void @@ -94,10 +270,17 @@ export class Ens { setMultihash( name: string, hash: string, - sendOptions: TransactionConfig, - callback?: (error: Error, result: any) => void - ): PromiEvent; + txConfig?: TransactionConfig, + callback?: (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => void + ): PromiEvent; + /** + * @deprecated This callback signature is deprecated + */ + getContenthash( + name: string, + callback?: (value: any) => void + ): Promise; getContenthash( name: string, callback?: (error: Error, contenthash: string) => void @@ -106,9 +289,9 @@ export class Ens { setContenthash( name: string, hash: string, - sendOptions: TransactionConfig, - callback?: (error: Error, result: any) => void - ): PromiEvent; + txConfig?: TransactionConfig, + callback?: (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => void + ): PromiEvent; } export class Registry { @@ -118,10 +301,98 @@ export class Registry { contract: Contract | null; + /** + * @deprecated Please use the "getOwner" method instead of "owner" + */ owner( name: string, callback?: (error: Error, address: string) => void ): Promise; + /** + * @deprecated Please use the "getOwner" method instead of "owner" + */ + owner( + name: string, + callback?: (value: any) => void + ): Promise; - resolver(name: string): Promise; + /** + * @deprecated This callback signature is deprecated + */ + getOwner( + name: string, + callback?: (value: any) => void + ): Promise; + getOwner( + name: string, + callback?: (error: Error, address: string) => void + ): Promise; + + setOwner( + name: string, + address: string, + txConfig?: TransactionConfig, + callback?: (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => void + ): PromiEvent; + + /** + * @deprecated This callback signature is deprecated + */ + getTTl( + name: string, + callback?: (value: any) => void + ): Promise; + getTTl( + name: string, + callback?: (error: Error, ttl: string) => void + ): Promise; + + setTTL( + name: string, + ttl: string | number, + txConfig?: TransactionConfig, + callback?: (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => void + ): PromiEvent; + + setSubnodeOwner( + name: string, + label: string, + address: string, + txConfig?: TransactionConfig, + callback?: (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => void + ): PromiEvent + + /** + * @deprecated Please use the "getResolver" method instead of "resolver" + */ + resolver( + name: string, + callback?: (error: Error, contract: Contract) => void + ): Promise; + /** + * @deprecated Please use the "getResolver" method instead of "resolver" + */ + resolver( + name: string, + callback?: (value: any) => void + ): Promise; + + /** + * @deprecated This callback signature is deprecated + */ + getResolver( + name: string, + callback?: (value: any) => void + ): Promise; + getResolver( + name: string, + callback?: (error: Error, contract: Contract) => void + ): Promise; + + setResolver( + name: string, + address: string, + txConfig?: TransactionConfig, + callback?: (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => void + ): PromiEvent } diff --git a/packages/web3-eth-ens/types/tests/ens-test.ts b/packages/web3-eth-ens/types/tests/ens-test.ts index 762f7e5e0e1..1606779da8a 100644 --- a/packages/web3-eth-ens/types/tests/ens-test.ts +++ b/packages/web3-eth-ens/types/tests/ens-test.ts @@ -17,6 +17,9 @@ * @date 2018 */ +import { TransactionRevertInstructionError } from 'web3-core-helpers'; +import { TransactionReceipt } from 'web3-core'; +import { Contract } from 'web3-eth-contract'; import { Ens } from 'web3-eth-ens'; import { Eth } from 'web3-eth'; @@ -30,6 +33,97 @@ ens.registry; // $ExpectType Promise ens.resolver('name'); +// $ExpectType Promise +ens.resolver('name', (value: any) => {}); +// $ExpectType Promise +ens.resolver('name', (error: Error, contract: Contract) => {}); +// $ExpectType Promise +ens.getResolver('name'); +// $ExpectType Promise +ens.getResolver('name', (error: Error, contract: Contract) => {}); +// $ExpectType Promise +ens.getResolver('name', (value: any) => {}); + +// $ExpectType PromiEvent +ens.setResolver('name', '0x0...'); +// $ExpectType PromiEvent +ens.setResolver('name', '0x0...', {}); +// $ExpectType PromiEvent +ens.setResolver('name', '0x0...', {}, (error: Error, receipt: TransactionReceipt) => {}); + +// $ExpectType PromiEvent +ens.setSubnodeOwner('name', 'label', '0x...'); +// $ExpectType PromiEvent +ens.setSubnodeOwner('name', 'label', '0x...', {}); +// $ExpectType PromiEvent +ens.setSubnodeOwner('name', 'label', '0x...', {}, (error: Error, receipt: TransactionReceipt) => {}); + +// $ExpectType PromiEvent +ens.setRecord('name', 'owner', 'resolver', '100000'); +// $ExpectType PromiEvent +ens.setRecord('name', 'owner', 'resolver', 100000); +// $ExpectType PromiEvent +ens.setRecord('name', 'owner', 'resolver', 100000, {}); +// $ExpectType PromiEvent +ens.setRecord('name', 'owner', 'resolver', 100000, {}, (error: Error, receipt: TransactionReceipt) => {}); + +// $ExpectType PromiEvent +ens.setSubnodeRecord('name', 'label', 'owner', 'resolver', '100000'); +// $ExpectType PromiEvent +ens.setSubnodeRecord('name', 'label', 'owner', 'resolver', 100000); +// $ExpectType PromiEvent +ens.setSubnodeRecord('name', 'label', 'owner', 'resolver', 100000, {}); +// $ExpectType PromiEvent +ens.setSubnodeRecord('name', 'label', 'owner', 'resolver', 100000, {}, (error: Error, receipt: TransactionReceipt) => {}); + +// $ExpectType PromiEvent +ens.setApprovalForAll('name', true); +// $ExpectType PromiEvent +ens.setApprovalForAll('name', false, {}); +// $ExpectType PromiEvent +ens.setApprovalForAll('name', true, {}, (error: Error, receipt: TransactionReceipt) => {}); + +// $ExpectType Promise +ens.isApprovedForAll('owner', 'operator'); +// $ExpectType Promise +ens.isApprovedForAll('owner', 'operator', (error: Error, result: boolean) => {}); +// $ExpectType Promise +ens.isApprovedForAll('owner', 'operator', (value: any) => {}); + +// $ExpectType Promise +ens.recordExists('name'); +// $ExpectType Promise +ens.recordExists('name', (error: Error, result: boolean) => {}); +// $ExpectType Promise +ens.recordExists('name', (value: any) => {}); + +// $ExpectType Promise +ens.getTTL('name'); +// $ExpectType Promise +ens.getTTL('name', (error: Error, ttl: string) => {}); +// $ExpectType Promise +ens.getTTL('name', (value: any) => {}); + +// $ExpectType PromiEvent +ens.setTTL('name', 10000); +// $ExpectType PromiEvent +ens.setTTL('name', 10000, {}); +// $ExpectType PromiEvent +ens.setTTL('name', '0xa', {}, (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => {}); + +// $ExpectType Promise +ens.getOwner('name'); +// $ExpectType Promise +ens.getOwner('name', (value: any) => {}); +// $ExpectType Promise +ens.getOwner('name', (error: Error, owner: string) => {}); + +// $ExpectType PromiEvent +ens.setOwner('name', '0x...'); +// $ExpectType PromiEvent +ens.setOwner('name', '0x...', {}); +// $ExpectType PromiEvent +ens.setOwner('name', '0x...', {}, (error: Error | TransactionRevertInstructionError, receipt: TransactionReceipt) => {}); // $ExpectType Promise ens.supportsInterface('name', 'interfaceId'); @@ -39,63 +133,93 @@ ens.supportsInterface( 'interfaceId', (error: Error, supportsInterface: boolean) => {} ); +// $ExpectType Promise +ens.supportsInterface( + 'name', + 'interfaceId', + (value: any) => {} +); // $ExpectType Promise ens.getAddress('name'); // $ExpectType Promise ens.getAddress('name', (error: Error, address: string) => {}); +// $ExpectType Promise +ens.getAddress('name', (value: any) => {}); -// $ExpectType PromiEvent +// $ExpectType PromiEvent +ens.setAddress('name', 'address'); +// $ExpectType PromiEvent ens.setAddress('name', 'address', {}); -// $ExpectType PromiEvent +// $ExpectType PromiEvent ens.setAddress('name', 'address', {}, (error: Error, result: any) => {}); // $ExpectType Promise<{ [x: string]: string; }> ens.getPubkey('name'); // $ExpectType Promise<{ [x: string]: string; }> ens.getPubkey('name', (error: Error, result: { [x: string]: string }) => {}); +// $ExpectType Promise<{ [x: string]: string; }> +ens.getPubkey('name', (value: any) => {}); -// $ExpectType PromiEvent +// $ExpectType PromiEvent +ens.setPubkey('name', 'x', 'y'); +// $ExpectType PromiEvent ens.setPubkey('name', 'x', 'y', {}); -// $ExpectType PromiEvent +// $ExpectType PromiEvent ens.setPubkey('name', 'x', 'y', {}, (error: Error, result: any) => {}); // $ExpectType Promise ens.getText('name', 'key'); // $ExpectType Promise ens.getText('name', 'key', (error: Error, ensName: string) => {}); +// $ExpectType Promise +ens.getText('name', 'key', (value: any) => {}); -// $ExpectType PromiEvent +// $ExpectType PromiEvent +ens.setText('name', 'key', 'value'); +// $ExpectType PromiEvent ens.setText('name', 'key', 'value', {}); -// $ExpectType PromiEvent +// $ExpectType PromiEvent ens.setText('name', 'key', 'value', {}, (error: Error, result: any) => {}); // $ExpectType Promise ens.getContent('name'); // $ExpectType Promise ens.getContent('name', (error: Error, contentHash: string) => {}); +// $ExpectType Promise +ens.getContent('name', (value: any) => {}); -// $ExpectType PromiEvent +// $ExpectType PromiEvent +ens.setContent('name', 'hash'); +// $ExpectType PromiEvent ens.setContent('name', 'hash', {}); -// $ExpectType PromiEvent +// $ExpectType PromiEvent ens.setContent('name', 'hash', {}, (error: Error, result: any) => {}); // $ExpectType Promise ens.getMultihash('name'); // $ExpectType Promise ens.getMultihash('name', (error: Error, multihash: string) => {}); +// $ExpectType Promise +ens.getMultihash('name', (value: any) => {}); -// $ExpectType PromiEvent -ens.setMultihash('name', 'hash', {}); -// $ExpectType PromiEvent +// $ExpectType PromiEvent +ens.setMultihash('name', 'hash'); +// $ExpectType PromiEvent ens.setMultihash('name', 'hash', {}, (error: Error, result: any) => {}); +// $ExpectType PromiEvent +ens.setMultihash('name', 'hash', {}); // $ExpectType Promise ens.getContenthash('name'); // $ExpectType Promise ens.getContenthash('name', (error: Error, contenthash: string) => {}); +// $ExpectType Promise +ens.getContenthash('name', (value: any) => {}); -// $ExpectType PromiEvent +// $ExpectType PromiEvent +ens.setContenthash('name', 'hash'); +// $ExpectType PromiEvent ens.setContenthash('name', 'hash', {}); -// $ExpectType PromiEvent +// $ExpectType PromiEvent ens.setContenthash('name', 'hash', {}, (error: Error, result: any) => {}); diff --git a/scripts/ci.sh b/scripts/ci.sh index 2bee77af154..b3e857f2694 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -23,6 +23,7 @@ elif [ "$TEST" = "unit_and_e2e_clients" ]; then npm run test:e2e:ganache npm run test:e2e:geth:insta npm run test:e2e:geth:auto + npm run test:e2e:ens npm run test:unit npm run coveralls diff --git a/test/e2e.ens.js b/test/e2e.ens.js index 8916a34df75..c53d0dcaf2c 100644 --- a/test/e2e.ens.js +++ b/test/e2e.ens.js @@ -25,7 +25,7 @@ describe('ENS [ @E2E ]', function () { }); it('should return the subnode owner of "resolver"', async function () { - const owner = await web3.eth.ens.registry.owner('resolver'); + const owner = await web3.eth.ens.registry.getOwner('resolver'); assert.equal( owner, @@ -34,7 +34,7 @@ describe('ENS [ @E2E ]', function () { }); it('should fetch the registered resolver for the subnode "resolver"', async function () { - const resolver = await web3.eth.ens.registry.resolver('resolver'); + const resolver = await web3.eth.ens.registry.getResolver('resolver'); assert.equal(resolver.options.address, resolverAddr); }); diff --git a/test/eth.ens.js b/test/eth.ens.js index f7fca0bf6b6..7121155b9d9 100644 --- a/test/eth.ens.js +++ b/test/eth.ens.js @@ -1,16 +1,846 @@ var chai = require('chai'); var assert = chai.assert; +var FakeIpcProvider = require('./helpers/FakeIpcProvider'); var FakeHttpProvider = require('./helpers/FakeHttpProvider'); var Web3 = require('../packages/web3'); var sha3 = require('../packages/web3-utils').sha3; var formatters = require('web3-core-helpers').formatters; +var abiCoder = require('web3-eth-abi'); +var utils = require('web3-utils'); +var namehash = require('eth-ens-namehash'); var asciiToHex = require('../packages/web3-utils').asciiToHex; +/** + * Injects the required validations and results for the `eth_sendTransaction` call + * + * @method prepareProviderForSetter + * + * @param {FakeIpcProvider} provider + * @param {String} signature + * @param {Array} types + * @param {Array} params + * @param {Boolean} error + * + * @returns {void} + */ +function prepareProviderForSetter(provider, signature, types, params, error) { + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_sendTransaction'); + assert.deepEqual( + payload.params, + [{ + from: '0x0123456701234567012345670123456701234567', + gas: '0x64', + gasPrice: '0x64', + nonce: '0x1', + data: sha3(signature).slice(0, 10) + abiCoder.encodeParameters(types, params).substr(2), + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e' + }] + ); + }); + provider.injectResult('0x1234000000000000000000000000000000000000000000000000000000056789'); + + provider.injectValidation(function (payload) { + assert.equal(payload.method, 'eth_getTransactionReceipt'); + assert.deepEqual(payload.params, ['0x1234000000000000000000000000000000000000000000000000000000056789']); + }); + provider.injectResult(null); + + provider.injectValidation(function (payload) { + assert.equal(payload.method, 'eth_subscribe'); + assert.deepEqual(payload.params, ['newHeads']); + }); + provider.injectResult('0x1234567'); + + // fake newBlock + provider.injectNotification({ + method: 'eth_subscription', + params: { + subscription: '0x1234567', + result: { + blockNumber: '0x10' + } + } + }); + + provider.injectValidation(function (payload) { + assert.equal(payload.method, 'eth_getTransactionReceipt'); + assert.deepEqual(payload.params, ['0x1234000000000000000000000000000000000000000000000000000000056789']); + }); + provider.injectResult({ + contractAddress: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + cumulativeGasUsed: '0xa', + transactionIndex: '0x3', + blockNumber: '0xa', + blockHash: '0xbf1234', + gasUsed: '0x0', + status: error ? '0x0' : '0x1' + }); + provider.injectValidation(function (payload) { + assert.equal(payload.method, 'eth_unsubscribe'); + assert.deepEqual(payload.params, ['0x1234567']); + }); + provider.injectResult('0x321'); +} + +/** + * Checks if the receipt got mapped as expected and not manipulated in a strange way within the ENS module + * + * @method isExpectedReceipt + * + * @param {Object} receipt + * + * @returns {void} + */ +function isExpectedReceipt(receipt) { + assert.equal(receipt.contractAddress, '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e'); + assert.equal(receipt.cumulativeGasUsed, 10); + assert.equal(receipt.transactionIndex, 3); + assert.equal(receipt.blockNumber, 10); + assert.equal(receipt.blockHash, '0xbf1234'); + assert.equal(receipt.gasUsed, 0); +} + describe('ens', function () { - var provider; - var web3; + let provider; + let web3; + const hashedName = namehash.hash('foobar.eth'); + const name = 'foobar.eth'; + + describe('setters', function () { + beforeEach(function () { + provider = new FakeIpcProvider(); + web3 = new Web3(provider); + + provider.injectResult({ + timestamp: Math.floor(new Date() / 1000) - 60, + }); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_getBlockByNumber'); + assert.deepEqual(payload.params, ['latest', false]); + }); + + provider.injectResult(1); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'net_version'); + assert.deepEqual(payload.params, []); + }); + + provider.injectResult({ + hash: '0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3', + blockNumber: '0x0' + }); + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_getBlockByNumber'); + assert.deepEqual(payload.params, ['0x0', false]); + }); + }); + + it('should set the property "registryAddress" to "null" and not throw any error', function() { + web3.eth.ens.registryAddress = null; + + assert.equal(web3.eth.ens.registryAddress, null); + }); + + it('should set the owner record for a name', async function () { + const signature = 'setOwner(bytes32,address)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'address'], + [hashedName, '0x0123456701234567012345670123456701234567'], + false + ); + + const receipt = await web3.eth.ens.setOwner( + name, + '0x0123456701234567012345670123456701234567', + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + }); + + isExpectedReceipt(receipt); + }); + + it('should set the owner record for a name and throw the expected error (callback)', function (done) { + const signature = 'setOwner(bytes32,address)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'address'], + [hashedName, '0x0123456701234567012345670123456701234567'], + true + ); + + web3.eth.ens.setOwner( + name, + '0x0123456701234567012345670123456701234567', + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + }, + function (error, result) { + assert(error.message.includes('Transaction has been reverted by the EVM')); + assert.equal(result, null); + + done(); + } + ); + }); + + it('should set the owner record for a name and throw the expected error (promise)', async function () { + const signature = 'setOwner(bytes32,address)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'address'], + [hashedName, '0x0123456701234567012345670123456701234567'], + true + ); + + try { + await web3.eth.ens.setOwner( + name, + '0x0123456701234567012345670123456701234567', + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + } + ); + + assert.fail(); + } catch (error) { + assert(error.message.includes('Transaction has been reverted by the EVM')); + } + }); + + it('should set the record for a name', async function () { + const signature = 'setRecord(bytes32,address,address,uint64)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'address', 'address', 'uint64'], + [ + hashedName, + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567', + 10000 + ], + false + ); + + const receipt = await web3.eth.ens.setRecord( + name, + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567', + 10000, + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + }); + + isExpectedReceipt(receipt); + }); + + it('should set the record for a name and throw the expected error (callback)', function (done) { + const signature = 'setRecord(bytes32,address,address,uint64)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'address', 'address', 'uint64'], + [ + hashedName, + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567', + 10000 + ], + true + ); + + web3.eth.ens.setRecord( + name, + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567', + 10000, + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + }, + function (error, result) { + assert(error.message.includes('Transaction has been reverted by the EVM')); + assert.equal(result, null); + + done(); + } + ); + }); + + it('should set the record for a name and throw the expected error (promise)', async function () { + const signature = 'setRecord(bytes32,address,address,uint64)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'address', 'address', 'uint64'], + [ + hashedName, + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567', + 10000 + ], + true + ); + + try { + await web3.eth.ens.setRecord( + name, + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567', + 10000, + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + } + ); + + assert.fail(); + } catch (error) { + assert(error.message.includes('Transaction has been reverted by the EVM')); + } + }); + + it('should set the owner, resolver, and ttl for a name', async function () { + const signature = 'setSubnodeRecord(bytes32,bytes32,address,address,uint64)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'bytes32', 'address', 'address', 'uint64'], + [ + hashedName, + utils.sha3('label'), + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567', + 10000 + ], + false + ); + + const receipt = await web3.eth.ens.setSubnodeRecord( + name, + 'label', + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567', + 10000, + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + }); + + isExpectedReceipt(receipt); + }); + + it('should set the owner, resolver, and ttl for a name with already hashed label', async function () { + const signature = 'setSubnodeRecord(bytes32,bytes32,address,address,uint64)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'bytes32', 'address', 'address', 'uint64'], + [ + hashedName, + utils.sha3('label'), + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567', + 10000 + ], + false + ); + + const receipt = await web3.eth.ens.setSubnodeRecord( + name, + utils.sha3('label'), + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567', + 10000, + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + }); + + isExpectedReceipt(receipt); + }); + + it('should set the owner, resolver, and ttl for a name and throw the expected error (callback)', function (done) { + const signature = 'setSubnodeRecord(bytes32,bytes32,address,address,uint64)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'bytes32', 'address', 'address', 'uint64'], + [ + hashedName, + utils.sha3('label'), + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567', + 10000 + ], + true + ); + + web3.eth.ens.setSubnodeRecord( + name, + 'label', + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567', + 10000, + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + }, + function (error, result) { + assert(error.message.includes('Transaction has been reverted by the EVM')); + assert.equal(result, null); + + done(); + } + ); + }); + + it('should set the owner, resolver, and ttl for a name and throw the expected error (promise)', async function () { + const signature = 'setSubnodeRecord(bytes32,bytes32,address,address,uint64)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'bytes32', 'address', 'address', 'uint64'], + [ + hashedName, + utils.sha3('label'), + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567', + 10000 + ], + true + ); + + try { + await web3.eth.ens.setSubnodeRecord( + name, + 'label', + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567', + 10000, + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + } + ); + + assert.fail(); + } catch (error) { + assert(error.message.includes('Transaction has been reverted by the EVM')); + } + }); + + it('should set an approval by the given operator', async function () { + const signature = 'setApprovalForAll(address,bool)'; + + prepareProviderForSetter( + provider, + signature, + ['address', 'bool'], + [ + '0x0123456701234567012345670123456701234567', + true + ], + false + ); + + const receipt = await web3.eth.ens.setApprovalForAll( + '0x0123456701234567012345670123456701234567', + true, + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + }); + + isExpectedReceipt(receipt); + }); + + it('should set an approval by the given operator and throw the expected error (callback)', function (done) { + const signature = 'setApprovalForAll(address,bool)'; + + prepareProviderForSetter( + provider, + signature, + ['address', 'bool'], + [ + '0x0123456701234567012345670123456701234567', + true + ], + true + ); + + web3.eth.ens.setApprovalForAll( + '0x0123456701234567012345670123456701234567', + true, + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + }, + function (error, result) { + assert(error.message.includes('Transaction has been reverted by the EVM')); + assert.equal(result, null); + + done(); + } + ); + }); + + it('should set an approval by the given operator and throw the expected error (promise)', async function () { + const signature = 'setApprovalForAll(address,bool)'; + + prepareProviderForSetter( + provider, + signature, + ['address', 'bool'], + [ + '0x0123456701234567012345670123456701234567', + true + ], + true + ); + + try { + await web3.eth.ens.setApprovalForAll( + '0x0123456701234567012345670123456701234567', + true, + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + } + ); + + assert.fail(); + } catch (error) { + assert(error.message.includes('Transaction has been reverted by the EVM')); + } + }); + + it('should set the owner, resolver, and TTL for an record', async function () { + const signature = 'setResolver(bytes32,address)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'address'], + [hashedName, '0x0123456701234567012345670123456701234567'], + false + ); + + const receipt = await web3.eth.ens.setResolver( + name, + '0x0123456701234567012345670123456701234567', + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + }); + + isExpectedReceipt(receipt); + }); + + it('should set the owner, resolver, and TTL for an record and throw the expected error (callback)', function (done) { + const signature = 'setResolver(bytes32,address)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'address'], + [hashedName, '0x0123456701234567012345670123456701234567'], + true + ); + + web3.eth.ens.setResolver( + name, + '0x0123456701234567012345670123456701234567', + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + }, + function (error, result) { + assert(error.message.includes('Transaction has been reverted by the EVM')); + assert.equal(result, null); + + done(); + } + ); + }); + + it('should set the owner, resolver, and TTL for an record and throw the expected error (promise)', async function () { + const signature = 'setResolver(bytes32,address)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'address'], + [hashedName, '0x0123456701234567012345670123456701234567'], + true + ); + + try { + await web3.eth.ens.setResolver( + name, + '0x0123456701234567012345670123456701234567', + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + } + ); + + assert.fail(); + } catch (error) { + assert(error.message.includes('Transaction has been reverted by the EVM')); + } + }); - describe('in normal operation', function () { + it('should set the TTL (caching time) record for a name', async function () { + const signature = 'setTTL(bytes32,uint64)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'uint64'], + [hashedName, '1'], + false + ); + + const receipt = await web3.eth.ens.setTTL( + name, + '1', + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + }); + + isExpectedReceipt(receipt); + }); + + it('should call the TTL (caching time) record setter for a name and throw the expected error (callback)', function (done) { + const signature = 'setTTL(bytes32,uint64)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'uint64'], + [hashedName, '1'], + true + ); + + web3.eth.ens.setTTL( + name, + '1', + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + }, + function (error, result) { + assert(error.message.includes('Transaction has been reverted by the EVM')); + assert.equal(result, null); + + done(); + } + ); + }); + + it('should call the TTL (caching time) record setter for a name and throw the expected error (promise)', async function () { + const signature = 'setTTL(bytes32,uint64)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'uint64'], + [hashedName, '1'], + true + ); + + try { + await web3.eth.ens.setTTL( + name, + '1', + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + } + ); + + assert.fail(); + } catch (error) { + assert(error.message.includes('Transaction has been reverted by the EVM')); + } + }); + + it('should create a new sub node with the specified label and owner', async function () { + const signature = 'setSubnodeOwner(bytes32,bytes32,address)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'bytes32', 'address'], + [hashedName, utils.sha3('label'), '0x0123456701234567012345670123456701234567'], + false + ); + + const receipt = await web3.eth.ens.setSubnodeOwner( + name, + 'label', + '0x0123456701234567012345670123456701234567', + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + }); + + isExpectedReceipt(receipt); + }); + + it('should create a new sub node with the specified hashed label and owner', async function () { + const signature = 'setSubnodeOwner(bytes32,bytes32,address)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'bytes32', 'address'], + [hashedName, utils.sha3('label'), '0x0123456701234567012345670123456701234567'], + false + ); + + const receipt = await web3.eth.ens.setSubnodeOwner( + name, + utils.sha3('label'), + '0x0123456701234567012345670123456701234567', + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + }); + + isExpectedReceipt(receipt); + }); + + it('should create a new sub node with the specified label and owner and throw the expected error (callback)', function (done) { + const signature = 'setSubnodeOwner(bytes32,bytes32,address)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'bytes32', 'address'], + [hashedName, utils.sha3('label'), '0x0123456701234567012345670123456701234567'], + true + ); + + web3.eth.ens.setSubnodeOwner( + name, + 'label', + '0x0123456701234567012345670123456701234567', + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + }, + function (error, result) { + assert(error.message.includes('Transaction has been reverted by the EVM')); + assert.equal(result, null); + + done(); + } + ); + }); + + it('should create a new sub node with the specified label and owner and throw the expected error (promise)', async function () { + const signature = 'setSubnodeOwner(bytes32,bytes32,address)'; + + prepareProviderForSetter( + provider, + signature, + ['bytes32', 'bytes32', 'address'], + [hashedName, utils.sha3('label'), '0x0123456701234567012345670123456701234567'], + true + ); + + try { + await web3.eth.ens.setSubnodeOwner( + name, + 'label', + '0x0123456701234567012345670123456701234567', + { + from: '0x0123456701234567012345670123456701234567', + gas: 100, + gasPrice: 100, + nonce: 1 + } + ); + + assert.fail(); + } catch (error) { + assert(error.message.includes('Transaction has been reverted by the EVM')); + } + }); + }); + + describe('getters', function () { beforeEach(function () { provider = new FakeHttpProvider(); web3 = new Web3(provider); @@ -43,52 +873,72 @@ describe('ens', function () { }); }); - it('should return the owner record for a name', function (done) { - var signature = 'owner(bytes32)'; + it('should call supportsInterface with the interfaceId and return "true" (promise)', async function () { + const resolverSignature = 'resolver(bytes32)'; + const supportsInterfaceSignature = 'supportsInterface(bytes4)'; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + data: sha3(resolverSignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', }, 'latest']); }); provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); - web3.eth.ens.registry.owner('foobar.eth').then(function (owner) { - assert.equal(owner, '0x0123456701234567012345670123456701234567'); - done(); - }).catch(function (err) { - throw err; + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(supportsInterfaceSignature).slice(0, 10) + sha3('addr(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); + + const owner = await web3.eth.ens.supportsInterface('foobar.eth', '0x3b3b57de'); + + assert.equal(owner, true); }); - it('should fetch the resolver for a name', function (done) { - var signature = 'resolver(bytes32)'; + it('should call supportsInterface with the interfaceId and return "true" (callback)', function (done) { + const resolverSignature = 'resolver(bytes32)'; + const supportsInterfaceSignature = 'supportsInterface(bytes4)'; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + data: sha3(resolverSignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', }, 'latest']); }); provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); - web3.eth.ens.registry.resolver('foobar.eth').then(function (resolver) { - assert.equal(resolver.options.address, '0x0123456701234567012345670123456701234567'); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(supportsInterfaceSignature).slice(0, 10) + sha3('addr(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); + + web3.eth.ens.supportsInterface('foobar.eth', '0x3b3b57de', function (error, owner) { + assert.equal(owner, true); + done(); - }).catch(function (err) { - throw err; }); + }); - it('should return the addr record for a name', function (done) { - var resolverSig = 'resolver(bytes32)'; - var addrSig = 'addr(bytes32)'; + it('should call supportsInterface with the signature and throw the expected error (callback)', function (done) { + const resolverSignature = 'resolver(bytes32)'; + const supportsInterfaceSignature = 'supportsInterface(bytes4)'; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -104,23 +954,34 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3(addrSig).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + data: sha3(supportsInterfaceSignature).slice(0, 10) + sha3('addr(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); - provider.injectResult('0x0000000000000000000000001234567012345670123456701234567012345670'); - web3.eth.ens.getAddress('foobar.eth').then(function (addr) { - assert.equal(addr, '0x1234567012345670123456701234567012345670'); - done(); - }).catch(function (err) { - throw err; + provider.error.push(null); + provider.error.push(null); + + provider.injectError({ + code: 1234, + message: 'ERROR' }); + + web3.eth.ens.supportsInterface( + 'foobar.eth', + 'addr(bytes32)', + function (error, supported) { + assert.equal(supported, null); + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + + done(); + }); }); - it('should return x and y from an public key for en specific ens name', function (done) { - var resolverSignature = 'resolver(bytes32)'; - var pubkeySignature = 'pubkey(bytes32)'; + it('should call supportsInterface with the signature and throw the expected error (promise)', async function () { + const resolverSignature = 'resolver(bytes32)'; + const supportsInterfaceSignature = 'supportsInterface(bytes4)'; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -136,130 +997,1171 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3(pubkeySignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + data: sha3(supportsInterfaceSignature).slice(0, 10) + sha3('addr(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); - var pubkeyCoordinateAsHex = asciiToHex('0x0000000000000000000000000000000000000000000000000000000000000000'); - provider.injectResult([ - pubkeyCoordinateAsHex, - pubkeyCoordinateAsHex - ]); + provider.error.push(null); + provider.error.push(null); - web3.eth.ens.getPubkey('foobar.eth').then(function (result) { - assert.equal(result[0][0], '0x3078303030303030303030303030303030303030303030303030303030303030'); - assert.equal(result[0][1], '0x3030303030303030303030303030303030303030303030303030303030303030'); - done(); + provider.injectError({ + code: 1234, + message: 'ERROR' }); + + try { + await web3.eth.ens.supportsInterface('foobar.eth', 'addr(bytes32)'); + + assert.fail(); + } catch (error) { + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + } }); - it('should get the content of an resolver', function (done) { - var resolverSignature = 'resolver(bytes32)'; - var contentSignature = 'content(bytes32)'; + it('should call getTTL and return the expected result (promise)', async function () { + const signature = 'ttl(bytes32)'; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3(resolverSignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', }, 'latest']); }); - provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); + + const ttl = await web3.eth.ens.getTTL('foobar.eth'); + + assert.equal(ttl, 1); + }); + + it('should call getTTL and return the expected result (callback)', function (done) { + const signature = 'ttl(bytes32)'; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3(contentSignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', - to: '0x0123456701234567012345670123456701234567', + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', }, 'latest']); }); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); + + web3.eth.ens.getTTL('foobar.eth', function (error, ttl) { + assert.equal(ttl, 1); - web3.eth.ens.getContent('foobar.eth').then(function (result) { - assert.equal(result, '0x0000000000000000000000000000000000000000000000000000000000000000'); done(); }); + }); - }); + it('should call getTTL and throw the expected error (callback)', function (done) { + const signature = 'ttl(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + + provider.error.push(null); - it("won't resolve on an unknown network", function (done) { - provider = new FakeHttpProvider(); - web3 = new Web3(provider); + provider.injectError({ + code: 1234, + message: 'ERROR' + }); - provider.injectResult({ - timestamp: Math.floor(new Date() / 1000) - 60, - }); - provider.injectValidation(function (payload) { - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'eth_getBlockByNumber'); - assert.deepEqual(payload.params, ['latest', false]); - }); + web3.eth.ens.getTTL( + 'foobar.eth', + function (error, ttl) { + assert.equal(ttl, null); + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); - provider.injectResult(1); - provider.injectValidation(function (payload) { - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'net_version'); - assert.deepEqual(payload.params, []); + done(); + }); }); - provider.injectResult({ - hash: '0x0123456701234567012345670123456701234567012345670123456701234567', - blockNumber: '0x0' - }); - provider.injectValidation(function (payload) { - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'eth_getBlockByNumber'); - assert.deepEqual(payload.params, ['0x0', false]); - }); + it('should call getTTL and throw the expected error (promise)', async function () { + const signature = 'ttl(bytes32)'; - web3.eth.ens.getAddress('foobar.eth').then(function () { - assert.isTrue(false, 'Should throw error'); - done(); - }).catch(function (e) { - assert.isTrue(e instanceof Error, 'Should throw error'); - done(); - }); - }); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); - it("won't resolve when out of date", function (done) { - provider = new FakeHttpProvider(); - web3 = new Web3(provider); + provider.error.push(null); - provider.injectResult({ - timestamp: Math.floor(new Date() / 1000) - 3660, - }); - provider.injectValidation(function (payload) { - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'eth_getBlockByNumber'); - assert.deepEqual(payload.params, ['latest', false]); - }); + provider.injectError({ + code: 1234, + message: 'ERROR' + }); - web3.eth.ens.getAddress('foobar.eth').then(function () { - assert.isTrue(false, 'Should throw error'); - done(); - }).catch(function (e) { - assert.isTrue(e instanceof Error, 'Should throw error'); - done(); - }); - }); + try { + await web3.eth.ens.getTTL('foobar.eth'); - it('should only check if the connected node is synced if at least a hour is gone', async function () { - provider = new FakeHttpProvider(); - web3 = new Web3(provider); - web3.eth.ens._lastSyncCheck = new Date() / 1000; + assert.fail(); + } catch (error) { + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + } + }); - try { - await web3.eth.ens.checkNetwork(); + it('should call isApprovedForAll and return the expected result (promise)', async function () { + const signature = 'isApprovedForAll(address,address)'; - assert.fail(); - } catch (error) { - return true; - } + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '00000000000000000000000001234567012345670123456701234567012345670000000000000000000000000123456701234567012345670123456701234567', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); + + const isApproved = await web3.eth.ens.isApprovedForAll( + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567' + ); + + assert.equal(isApproved, true); + }); + + it('should call isApprovedForAll and return the expected result (callback)', function (done) { + const signature = 'isApprovedForAll(address,address)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '00000000000000000000000001234567012345670123456701234567012345670000000000000000000000000123456701234567012345670123456701234567', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); + + web3.eth.ens.isApprovedForAll( + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567', + function (error, isApproved) { + assert.equal(isApproved, true); + + done(); + } + ); + }); + + it('should call isApprovedForAll and throws the expected error (callback)', function (done) { + const signature = 'isApprovedForAll(address,address)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '00000000000000000000000001234567012345670123456701234567012345670000000000000000000000000123456701234567012345670123456701234567', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + + provider.error.push(null); + + provider.injectError({ + code: 1234, + message: 'ERROR' + }); + + web3.eth.ens.isApprovedForAll( + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567', + function (error, isApproved) { + assert.equal(isApproved, null); + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + + done(); + }); + }); + + it('should call isApprovedForAll and throws the expected error (promise)', async function () { + const signature = 'isApprovedForAll(address,address)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '00000000000000000000000001234567012345670123456701234567012345670000000000000000000000000123456701234567012345670', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + + provider.error.push(null); + + provider.injectError({ + code: 1234, + message: 'ERROR' + }); + + try { + await web3.eth.ens.isApprovedForAll( + '0x0123456701234567012345670123456701234567', + '0x0123456701234567012345670123456701234567' + ); + + assert.fail(); + } catch (error) { + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + } + }); + + it('should call recordExists and return the expected result (promise)', async function () { + const signature = 'recordExists(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); + + const exists = await web3.eth.ens.recordExists(name); + + assert.equal(exists, true); + }); + + it('should call recordExists and return the expected result (callback)', function (done) { + const signature = 'recordExists(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); + + web3.eth.ens.recordExists( + name, + function (error, exists) { + assert.equal(exists, true); + + done(); + } + ); + }); + + it('should call recordExists and throws the expected error (callback)', function (done) { + const signature = 'recordExists(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + + provider.error.push(null); + + provider.injectError({ + code: 1234, + message: 'ERROR' + }); + + web3.eth.ens.recordExists( + name, + function (error, isApproved) { + assert.equal(isApproved, null); + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + + done(); + }); + }); + + it('should call recordExists and throws the expected error (promise)', async function () { + const signature = 'recordExists(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + + provider.error.push(null); + + provider.injectError({ + code: 1234, + message: 'ERROR' + }); + + try { + await web3.eth.ens.recordExists(name); + + assert.fail(); + } catch (error) { + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + } + }); + + it('should return the owner record for a name (owner)', async function () { + const signature = 'owner(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + const owner = await web3.eth.ens.registry.owner('foobar.eth'); + + assert.equal(owner, '0x0123456701234567012345670123456701234567'); + }); + + it('should call getOwner and return the expected owner (promise)', async function () { + const signature = 'owner(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + const owner = await web3.eth.ens.getOwner('foobar.eth'); + + assert.equal(owner, '0x0123456701234567012345670123456701234567'); + }); + + it('should call getOwner and return the expected owner (callback)', function (done) { + const signature = 'owner(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + web3.eth.ens.getOwner('foobar.eth', function (error, owner) { + assert.equal(owner, '0x0123456701234567012345670123456701234567'); + assert.equal(error, '0x0123456701234567012345670123456701234567'); // For backward compatibility + done(); + }); + }); + + it('should call getOwner and throw the expected error (callback)', function (done) { + const signature = 'owner(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + + provider.error.push(null); + + provider.injectError({ + code: 1234, + message: 'ERROR' + }); + + web3.eth.ens.getOwner('foobar.eth', function (error, owner) { + assert.equal(owner, null); + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + + done(); + }); + }); + + it('should call getOwner and throw the error on requesting of registry contract (callback)', function (done) { + const signature = 'owner(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + + provider.injectError({ + code: 1234, + message: 'ERROR' + }); + + web3.eth.ens.getOwner('foobar.eth', function (error, owner) { + assert.equal(owner, null); + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + + done(); + }); + }); + + it('should call getOwner and throw the error on requesting of registry contract (promise)', async function () { + const signature = 'owner(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + + provider.injectError({ + code: 1234, + message: 'ERROR' + }); + + try { + await web3.eth.ens.getOwner('foobar.eth'); + + assert.fail(); + } catch (error) { + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + } + }); + + it('should call resolver and return the expected resolver (promise)', async function () { + const signature = 'resolver(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + const resolver = await web3.eth.ens.resolver('foobar.eth'); + + assert.equal(resolver.options.address, '0x0123456701234567012345670123456701234567'); + }); + + it('should call resolver and return the expected resolver (callback)', function (done) { + const signature = 'resolver(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + web3.eth.ens.resolver('foobar.eth', function (error, resolver) { + assert.equal(resolver.options.address, '0x0123456701234567012345670123456701234567'); + assert.equal(error.options.address, '0x0123456701234567012345670123456701234567'); // For backward compatibility + + done(); + }); + }); + + it('should call getResolver and return the expected resolver (promise)', async function () { + const signature = 'resolver(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + const resolver = await web3.eth.ens.getResolver('foobar.eth'); + + assert.equal(resolver.options.address, '0x0123456701234567012345670123456701234567'); + }); + + it('should call getResolver and throw the expected error (promise)', async function () { + const signature = 'resolver(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + + provider.error.push(null); + + provider.injectError({ + code: 1234, + message: 'ERROR' + }); + + try { + await web3.eth.ens.getResolver('foobar.eth'); + + assert.fail(); + } catch (error) { + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + } + }); + + it('should call getResolver and throw the expected error on the contract registry call (promise)', async function () { + const signature = 'resolver(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + + provider.injectError({ + code: 1234, + message: 'ERROR' + }); + + try { + await web3.eth.ens.getResolver('foobar.eth'); + + assert.fail(); + } catch (error) { + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + } + }); + + it('should call getResolver and throw the expected error (callback)', function (done) { + const signature = 'resolver(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(signature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + + provider.error.push(null); + + provider.injectError({ + code: 1234, + message: 'ERROR' + }); + + web3.eth.ens.getResolver('foobar.eth', function (error, resolver) { + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + assert.equal(resolver, null); + + done(); + }); + }); + + it('should call getAddress and return the expected address (promise)', async function () { + const resolverSig = 'resolver(bytes32)'; + const addrSig = 'addr(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(resolverSig).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(addrSig).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000001234567012345670123456701234567012345670'); + + const addr = await web3.eth.ens.getAddress('foobar.eth'); + + assert.equal(addr, '0x1234567012345670123456701234567012345670'); + }); + + it('should call getAddress and return the expected address (callback)', function (done) { + const resolverSig = 'resolver(bytes32)'; + const addrSig = 'addr(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(resolverSig).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(addrSig).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000001234567012345670123456701234567012345670'); + + web3.eth.ens.getAddress('foobar.eth', function (error, addr) { + assert.equal(error, '0x1234567012345670123456701234567012345670'); // For backward compatibility + assert.equal(addr, '0x1234567012345670123456701234567012345670'); + + done(); + }); + }); + + it('should call getAddress and throw the expected error (promise)', async function () { + const resolverSig = 'resolver(bytes32)'; + const addrSig = 'addr(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(resolverSig).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(addrSig).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + + provider.error.push(null); + provider.error.push(null); + provider.error.push(null); + provider.error.push(null); + + provider.injectError({ + code: 1234, + message: 'ERROR' + }); + + try { + await web3.eth.ens.getAddress('foobar.eth'); + + assert.fail(); + } catch (error) { + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + } + + }); + + it('should call getAddress and throw the expected error (callback)', function (done) { + const resolverSig = 'resolver(bytes32)'; + const addrSig = 'addr(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(resolverSig).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(addrSig).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + + provider.error.push(null); + provider.error.push(null); + provider.error.push(null); + provider.error.push(null); + + provider.injectError({ + code: 1234, + message: 'ERROR' + }); + + web3.eth.ens.getAddress('foobar.eth', function (error, addr) { + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + assert.equal(addr, null); + + done(); + }); + }); + + it('should call getPubkey and return the expected X and Y value (promise)', async function () { + const resolverSignature = 'resolver(bytes32)'; + const pubkeySignature = 'pubkey(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(resolverSignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(pubkeySignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + + const pubkeyCoordinateAsHex = asciiToHex('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectResult([ + pubkeyCoordinateAsHex, + pubkeyCoordinateAsHex + ]); + + const result = await web3.eth.ens.getPubkey('foobar.eth'); + + assert.equal(result[0][0], '0x3078303030303030303030303030303030303030303030303030303030303030'); + assert.equal(result[0][1], '0x3030303030303030303030303030303030303030303030303030303030303030'); + }); + + it('should call getPubkey and return the expected X and Y value (callback)', function (done) { + const resolverSignature = 'resolver(bytes32)'; + const pubkeySignature = 'pubkey(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(resolverSignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(pubkeySignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + + const pubkeyCoordinateAsHex = asciiToHex('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectResult([ + pubkeyCoordinateAsHex, + pubkeyCoordinateAsHex + ]); + + web3.eth.ens.getPubkey( + 'foobar.eth', + function (error, result) { + assert.equal(result[0][0], '0x3078303030303030303030303030303030303030303030303030303030303030'); + assert.equal(result[0][1], '0x3030303030303030303030303030303030303030303030303030303030303030'); + assert.equal(error[0][0], '0x3078303030303030303030303030303030303030303030303030303030303030'); + assert.equal(error[0][1], '0x3030303030303030303030303030303030303030303030303030303030303030'); + + done(); + } + ); + + }); + + it('should call getPubkey and throw the expected error (callback)', function (done) { + const resolverSignature = 'resolver(bytes32)'; + const pubkeySignature = 'pubkey(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(resolverSignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(pubkeySignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + + const pubkeyCoordinateAsHex = asciiToHex('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectResult([ + pubkeyCoordinateAsHex, + pubkeyCoordinateAsHex + ]); + + provider.error.push(null); + provider.error.push(null); + provider.error.push(null); + provider.error.push(null); + + provider.injectError({ + code: 1234, + message: 'ERROR' + }); + + web3.eth.ens.getPubkey( + 'foobar.eth', + function (error, result) { + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + assert.equal(result, null); + + done(); + } + ); + }); + + it('should call getPubkey and throw the expected error (promise)', async function () { + const resolverSignature = 'resolver(bytes32)'; + const pubkeySignature = 'pubkey(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(resolverSignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(pubkeySignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + + const pubkeyCoordinateAsHex = asciiToHex('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectResult([ + pubkeyCoordinateAsHex, + pubkeyCoordinateAsHex + ]); + + provider.error.push(null); + provider.error.push(null); + provider.error.push(null); + provider.error.push(null); + + provider.injectError({ + code: 1234, + message: 'ERROR' + }); + + try { + await web3.eth.ens.getPubkey('foobar.eth'); + + assert.fail(); + } catch (error) { + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + } + }); + + it('should call getContent and return the expected content of the resolver (promise)', async function () { + const resolverSignature = 'resolver(bytes32)'; + const contentSignature = 'content(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(resolverSignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(contentSignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + + const result = await web3.eth.ens.getContent('foobar.eth'); + + assert.equal(result, '0x0000000000000000000000000000000000000000000000000000000000000000'); + }); + + it('should call getContent and return the expected content of the resolver (callback)', function () { + const resolverSignature = 'resolver(bytes32)'; + const contentSignature = 'content(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(resolverSignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(contentSignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + + web3.eth.ens.getContent( + 'foobar.eth', + function (error, result) { + assert.equal(result, '0x0000000000000000000000000000000000000000000000000000000000000000'); + assert.equal(error, '0x0000000000000000000000000000000000000000000000000000000000000000'); + + } + ); + }); + + it('should call getContent and throw the expected error (promise)', async function () { + const resolverSignature = 'resolver(bytes32)'; + const contentSignature = 'content(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(resolverSignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(contentSignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + + provider.error.push(null); + provider.error.push(null); + provider.error.push(null); + provider.error.push(null); + + provider.injectError({ + code: 1234, + message: 'ERROR' + }); + + try { + await web3.eth.ens.getContent('foobar.eth'); + + assert.fail(); + } catch (error) { + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + } + }); + + it('should call getContent and throw the expected error (callback)', function () { + const resolverSignature = 'resolver(bytes32)'; + const contentSignature = 'content(bytes32)'; + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(resolverSignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000123456701234567012345670123456701234567'); + + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: sha3(contentSignature).slice(0, 10) + '1757b5941987904c18c7594de32c1726cda093fdddacb738cfbc4a7cd1ef4370', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + + provider.error.push(null); + provider.error.push(null); + provider.error.push(null); + provider.error.push(null); + + provider.injectError({ + code: 1234, + message: 'ERROR' + }); + + web3.eth.ens.getContent( + 'foobar.eth', + function (error, result) { + assert.equal(error.code, 1234); + assert.equal(error.message, 'ERROR'); + assert.equal(result, null); + } + ); + }); + }); + + describe('checkNetwork', function () { + it("won't resolve on an unknown network", async function () { + provider = new FakeHttpProvider(); + web3 = new Web3(provider); + + provider.injectResult({ + timestamp: Math.floor(new Date() / 1000) - 60, + }); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_getBlockByNumber'); + assert.deepEqual(payload.params, ['latest', false]); + }); + + provider.injectResult(1); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'net_version'); + assert.deepEqual(payload.params, []); + }); + + provider.injectResult({ + hash: '0x0123456701234567012345670123456701234567012345670123456701234567', + blockNumber: '0x0' + }); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_getBlockByNumber'); + assert.deepEqual(payload.params, ['0x0', false]); + }); + + try { + await web3.eth.ens.getAddress('foobar.eth'); + assert.fail(); + } catch (err) { + assert.isTrue(err instanceof Error, 'Should throw error'); + } + }); + + it("won't resolve when out of date", async function () { + provider = new FakeHttpProvider(); + web3 = new Web3(provider); + + provider.injectResult({ + timestamp: Math.floor(new Date() / 1000) - 3660, + }); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_getBlockByNumber'); + assert.deepEqual(payload.params, ['latest', false]); + }); + + try { + await web3.eth.ens.getAddress('foobar.eth'); + assert.fail(); + } catch (err) { + assert.isTrue(err instanceof Error, 'Should throw error'); + } + }); + + it('should only check if the connected node is synced if at least a hour is gone', async function () { + provider = new FakeHttpProvider(); + web3 = new Web3(provider); + web3.eth.ens._lastSyncCheck = new Date() / 1000; + + try { + await web3.eth.ens.checkNetwork(); + + assert.fail(); + } catch (error) { + return true; + } + }); }); describe('custom registry address', function () {