From d8b5c602904e3881d62fcad005b692c9a0ea2bc1 Mon Sep 17 00:00:00 2001 From: cgewecke Date: Thu, 19 Mar 2020 20:44:24 -0700 Subject: [PATCH 01/21] Upgrade ensdomains/resolver (dev dep) to 0.2.4 --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 708f6450d00..4ed2bf65b0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -837,9 +837,9 @@ } }, "@ensdomains/resolver": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/@ensdomains/resolver/-/resolver-0.1.13.tgz", - "integrity": "sha512-VcMygGO/b0H4AXkN4CRAHw0CZd5XvTJW8YdIdZEmpJGs/O3eMzBzxpgJJ7UerD7U098rbBDSJmj0zjGudV0/aQ==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@ensdomains/resolver/-/resolver-0.2.4.tgz", + "integrity": "sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA==", "dev": true }, "@evocateur/libnpmaccess": { diff --git a/package.json b/package.json index c54e9e1d5e5..f01b08ebca8 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "@babel/core": "^7.6.4", "@babel/preset-env": "^7.6.3", "@ensdomains/ens": "^0.4.0", - "@ensdomains/resolver": "^0.1.13", + "@ensdomains/resolver": "^0.2.4", "@types/bignumber.js": "^4.0.2", "@types/bn.js": "^4.11.5", "@types/node": "^12.6.1", From 4397656d94afc08697f0c9181c1cab6a529f0afc Mon Sep 17 00:00:00 2001 From: cgewecke Date: Fri, 20 Mar 2020 09:48:50 -0700 Subject: [PATCH 02/21] Add PublicResolver ABI --- .../src/ressources/ABI/PublicResolver.js | 772 ++++++++++++++++++ 1 file changed, 772 insertions(+) create mode 100644 packages/web3-eth-ens/src/ressources/ABI/PublicResolver.js diff --git a/packages/web3-eth-ens/src/ressources/ABI/PublicResolver.js b/packages/web3-eth-ens/src/ressources/ABI/PublicResolver.js new file mode 100644 index 00000000000..ead8bac20ed --- /dev/null +++ b/packages/web3-eth-ens/src/ressources/ABI/PublicResolver.js @@ -0,0 +1,772 @@ +"use strict"; + +// This ABI taken from @ensdomains/resolver@0.2.4 +// @ensdomains/resolver/build/contracts/PublicResolver.json +var PUBLIC_RESOLVER = [ + { + "constant": true, + "inputs": [ + { + "name": "interfaceID", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "node", + "type": "bytes32" + }, + { + "name": "data", + "type": "bytes" + } + ], + "name": "setDNSRecords", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "node", + "type": "bytes32" + }, + { + "name": "key", + "type": "string" + }, + { + "name": "value", + "type": "string" + } + ], + "name": "setText", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "node", + "type": "bytes32" + }, + { + "name": "interfaceID", + "type": "bytes4" + } + ], + "name": "interfaceImplementer", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "node", + "type": "bytes32" + }, + { + "name": "contentTypes", + "type": "uint256" + } + ], + "name": "ABI", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "node", + "type": "bytes32" + }, + { + "name": "x", + "type": "bytes32" + }, + { + "name": "y", + "type": "bytes32" + } + ], + "name": "setPubkey", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "node", + "type": "bytes32" + }, + { + "name": "hash", + "type": "bytes" + } + ], + "name": "setContenthash", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "node", + "type": "bytes32" + } + ], + "name": "addr", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "node", + "type": "bytes32" + }, + { + "name": "name", + "type": "bytes32" + } + ], + "name": "hasDNSRecords", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "node", + "type": "bytes32" + }, + { + "name": "key", + "type": "string" + } + ], + "name": "text", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "node", + "type": "bytes32" + }, + { + "name": "contentType", + "type": "uint256" + }, + { + "name": "data", + "type": "bytes" + } + ], + "name": "setABI", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "node", + "type": "bytes32" + } + ], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "node", + "type": "bytes32" + }, + { + "name": "name", + "type": "string" + } + ], + "name": "setName", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "node", + "type": "bytes32" + }, + { + "name": "coinType", + "type": "uint256" + }, + { + "name": "a", + "type": "bytes" + } + ], + "name": "setAddr", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "node", + "type": "bytes32" + }, + { + "name": "name", + "type": "bytes32" + }, + { + "name": "resource", + "type": "uint16" + } + ], + "name": "dnsRecord", + "outputs": [ + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "node", + "type": "bytes32" + } + ], + "name": "clearDNSZone", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "node", + "type": "bytes32" + } + ], + "name": "contenthash", + "outputs": [ + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "node", + "type": "bytes32" + } + ], + "name": "pubkey", + "outputs": [ + { + "name": "x", + "type": "bytes32" + }, + { + "name": "y", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "node", + "type": "bytes32" + }, + { + "name": "a", + "type": "address" + } + ], + "name": "setAddr", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "node", + "type": "bytes32" + }, + { + "name": "interfaceID", + "type": "bytes4" + }, + { + "name": "implementer", + "type": "address" + } + ], + "name": "setInterface", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "node", + "type": "bytes32" + }, + { + "name": "coinType", + "type": "uint256" + } + ], + "name": "addr", + "outputs": [ + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "bytes32" + }, + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "address" + } + ], + "name": "authorisations", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "name": "_ens", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "target", + "type": "address" + }, + { + "indexed": false, + "name": "isAuthorised", + "type": "bool" + } + ], + "name": "AuthorisationChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": true, + "name": "indexedKey", + "type": "string" + }, + { + "indexed": false, + "name": "key", + "type": "string" + } + ], + "name": "TextChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": false, + "name": "x", + "type": "bytes32" + }, + { + "indexed": false, + "name": "y", + "type": "bytes32" + } + ], + "name": "PubkeyChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": false, + "name": "name", + "type": "string" + } + ], + "name": "NameChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": true, + "name": "interfaceID", + "type": "bytes4" + }, + { + "indexed": false, + "name": "implementer", + "type": "address" + } + ], + "name": "InterfaceChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": false, + "name": "name", + "type": "bytes" + }, + { + "indexed": false, + "name": "resource", + "type": "uint16" + }, + { + "indexed": false, + "name": "record", + "type": "bytes" + } + ], + "name": "DNSRecordChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": false, + "name": "name", + "type": "bytes" + }, + { + "indexed": false, + "name": "resource", + "type": "uint16" + } + ], + "name": "DNSRecordDeleted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + } + ], + "name": "DNSZoneCleared", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": false, + "name": "hash", + "type": "bytes" + } + ], + "name": "ContenthashChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": false, + "name": "a", + "type": "address" + } + ], + "name": "AddrChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": false, + "name": "coinType", + "type": "uint256" + }, + { + "indexed": false, + "name": "newAddress", + "type": "bytes" + } + ], + "name": "AddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": true, + "name": "contentType", + "type": "uint256" + } + ], + "name": "ABIChanged", + "type": "event" + }, + { + "constant": false, + "inputs": [ + { + "name": "node", + "type": "bytes32" + }, + { + "name": "target", + "type": "address" + }, + { + "name": "isAuthorised", + "type": "bool" + } + ], + "name": "setAuthorisation", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "name": "results", + "type": "bytes[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } +]; + +module.exports = PUBLIC_RESOLVER; From 99b3befe78776255dbcd8d9a3e938d36f7460231 Mon Sep 17 00:00:00 2001 From: cgewecke Date: Fri, 20 Mar 2020 15:40:42 -0700 Subject: [PATCH 03/21] Select resolver ABI via EIP165 (Supports Interface) --- .../web3-eth-ens/src/contracts/Registry.js | 46 ++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/packages/web3-eth-ens/src/contracts/Registry.js b/packages/web3-eth-ens/src/contracts/Registry.js index 6e375bdfae7..122fcf8e469 100644 --- a/packages/web3-eth-ens/src/contracts/Registry.js +++ b/packages/web3-eth-ens/src/contracts/Registry.js @@ -28,6 +28,13 @@ 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'); +var PUBLIC_RESOLVER_ABI = require('../ressources/ABI/PublicResolver'); + +// Value taken from EIP 1577 (Content Hash) specification +// Support for this interface is used as a switch to decide whether to +// instantiate the Resolver contract as a PublicResolver or legacy Resolver. +// Both contracts implement EIP 165 (Supports Interface). +var CONTENT_HASH_INTERFACE_ID = "0xbc1c58d1"; /** @@ -527,8 +534,9 @@ Registry.prototype.getResolver = function (name, callback) { return this.contract.then(function (contract) { return contract.methods.resolver(namehash.hash(name)).call(); - }).then(function (address) { - var contract = new Contract(RESOLVER_ABI, address); + }).then(async function (address) { + var abi = await self._getResolverABI(address); + var contract = new Contract(abi, address); contract.setProvider(self.ens.eth.currentProvider); if (_.isFunction(callback)) { @@ -550,6 +558,40 @@ Registry.prototype.getResolver = function (name, callback) { }); }; +/** + * Returns either PublicResolver ABI or legacy Resolver ABI based on + * whether the contract at
supports the `contentHash` interface. + * Defaults to legacy Resolver if something goes wrong while checking. + * + * @method _getResolverABI + * + * @param {string} address resolver address + * @returns {object} resolver ABI + */ +Registry.prototype._getResolverABI = async function(address){ + var isNewResolver = false; + + try { + // Both ABIs implement EIP 165. + const resolver = new Contract(RESOLVER_ABI, address); + resolver.setProvider(this.ens.eth.currentProvider); + isNewResolver = await resolver + .methods + .supportsInterface(CONTENT_HASH_INTERFACE_ID) + .call(); + + } catch(err){ + var msg = `Could not identify ABI of resolver contract at "${address}". ` + + `Defaulting to legacy resolver ABI.` + + console.warn(msg); + } + + if (isNewResolver) return PUBLIC_RESOLVER_ABI; + + return RESOLVER_ABI; +} + /** * Returns the address of the owner of an ENS name. * From b01ad073651d8ed94b3094f5e025ce551e4a223f Mon Sep 17 00:00:00 2001 From: cgewecke Date: Fri, 20 Mar 2020 15:43:08 -0700 Subject: [PATCH 04/21] Update ens.js injection tests with additional resolver call --- test/eth.ens.js | 148 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/test/eth.ens.js b/test/eth.ens.js index 792cfe61f00..69a29b433a6 100644 --- a/test/eth.ens.js +++ b/test/eth.ens.js @@ -103,6 +103,8 @@ function isExpectedReceipt(receipt) { } describe('ens', function () { + this.timeout(5000); + let provider; let web3; const hashedName = namehash.hash('foobar.eth'); @@ -887,6 +889,16 @@ describe('ens', function () { }); 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(supportsInterfaceSignature).slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); @@ -917,6 +929,16 @@ describe('ens', function () { }); 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(supportsInterfaceSignature).slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); @@ -1624,6 +1646,16 @@ describe('ens', function () { }); 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('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); @@ -1653,6 +1685,16 @@ describe('ens', function () { }); 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('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); @@ -1685,6 +1727,16 @@ describe('ens', function () { }); 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('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); @@ -1698,6 +1750,7 @@ describe('ens', function () { provider.error.push(null); provider.error.push(null); provider.error.push(null); + provider.error.push(null); provider.injectError({ code: 1234, @@ -1729,6 +1782,16 @@ describe('ens', function () { }); 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('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); @@ -1742,6 +1805,7 @@ describe('ens', function () { provider.error.push(null); provider.error.push(null); provider.error.push(null); + provider.error.push(null); provider.injectError({ code: 1234, @@ -1771,6 +1835,16 @@ describe('ens', function () { }); 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('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); @@ -1806,6 +1880,16 @@ describe('ens', function () { }); 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('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); @@ -1849,6 +1933,16 @@ describe('ens', function () { }); 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('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); @@ -1868,6 +1962,7 @@ describe('ens', function () { provider.error.push(null); provider.error.push(null); provider.error.push(null); + provider.error.push(null); provider.injectError({ code: 1234, @@ -1900,6 +1995,16 @@ describe('ens', function () { }); 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('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); @@ -1919,6 +2024,7 @@ describe('ens', function () { provider.error.push(null); provider.error.push(null); provider.error.push(null); + provider.error.push(null); provider.injectError({ code: 1234, @@ -1949,6 +2055,16 @@ describe('ens', function () { }); 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('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); @@ -1979,6 +2095,16 @@ describe('ens', function () { }); 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('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); @@ -2014,6 +2140,16 @@ describe('ens', function () { }); 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('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); @@ -2027,6 +2163,7 @@ describe('ens', function () { provider.error.push(null); provider.error.push(null); provider.error.push(null); + provider.error.push(null); provider.injectError({ code: 1234, @@ -2057,6 +2194,16 @@ describe('ens', function () { }); 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('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); @@ -2072,6 +2219,7 @@ describe('ens', function () { provider.error.push(null); provider.error.push(null); provider.error.push(null); + provider.error.push(null); provider.injectError({ code: 1234, From d0d84721c458598a9258b63e3180a8c72d3fd4db Mon Sep 17 00:00:00 2001 From: cgewecke Date: Sat, 21 Mar 2020 10:04:25 -0700 Subject: [PATCH 05/21] Add error handling for mismatched resolver ABI & method calls --- packages/web3-core-helpers/src/errors.js | 3 +++ packages/web3-core-helpers/types/index.d.ts | 1 + .../types/tests/errors-test.ts | 3 +++ .../src/lib/ResolverMethodHandler.js | 7 +++++++ test/e2e.ens.js | 20 +++++++++++++++++++ 5 files changed, 34 insertions(+) diff --git a/packages/web3-core-helpers/src/errors.js b/packages/web3-core-helpers/src/errors.js index d6bb1d22c4d..816604e2021 100644 --- a/packages/web3-core-helpers/src/errors.js +++ b/packages/web3-core-helpers/src/errors.js @@ -106,5 +106,8 @@ module.exports = { }, TransactionOutOfGasError: function(receipt) { return this.TransactionError('Transaction ran out of gas. Please provide more gas:\n' + JSON.stringify(receipt, null, 2), receipt); + }, + ResolverMethodMissingError: function(address, name) { + return new Error(`The resolver at ${address} does not implement requested method: "${name}".`); } }; diff --git a/packages/web3-core-helpers/types/index.d.ts b/packages/web3-core-helpers/types/index.d.ts index 914c5d2e465..2995efba578 100644 --- a/packages/web3-core-helpers/types/index.d.ts +++ b/packages/web3-core-helpers/types/index.d.ts @@ -80,6 +80,7 @@ export class errors { static ContractCodeNotStoredError(receipt: object): TransactionError static TransactionRevertedWithoutReasonError(receipt: object): TransactionError static TransactionOutOfGasError(receipt: object): TransactionError + static ResolverMethodMissingError(address: string, name: string): Error } export class WebsocketProviderBase { diff --git a/packages/web3-core-helpers/types/tests/errors-test.ts b/packages/web3-core-helpers/types/tests/errors-test.ts index 5f00b754684..01dab2938a4 100644 --- a/packages/web3-core-helpers/types/tests/errors-test.ts +++ b/packages/web3-core-helpers/types/tests/errors-test.ts @@ -76,3 +76,6 @@ errors.TransactionRevertedWithoutReasonError({}); // $ExpectType TransactionError errors.TransactionOutOfGasError({}); + +// $ExpectType Error +errors.ResolverMethodMissingError('0x0000000000000000000000000000000000000001', 'content'); diff --git a/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js b/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js index 069e82474cb..ad41e1d0789 100644 --- a/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js +++ b/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js @@ -22,6 +22,7 @@ var PromiEvent = require('web3-core-promievent'); var namehash = require('eth-ens-namehash'); +var errors = require('web3-core-helpers').errors; var _ = require('underscore'); /** @@ -71,6 +72,9 @@ ResolverMethodHandler.prototype.call = function (callback) { var preparedArguments = this.parent.prepareArguments(this.ensName, this.methodArguments); this.parent.registry.getResolver(this.ensName).then(function (resolver) { + if (!resolver.methods[self.methodName]){ + throw errors.ResolverMethodMissingError(resolver.options.address, self.methodName); + } self.parent.handleCall(promiEvent, resolver.methods[self.methodName], preparedArguments, callback); }).catch(function(error) { if (_.isFunction(callback)) { @@ -99,6 +103,9 @@ ResolverMethodHandler.prototype.send = function (sendOptions, callback) { var preparedArguments = this.parent.prepareArguments(this.ensName, this.methodArguments); this.parent.registry.getResolver(this.ensName).then(function (resolver) { + if (!resolver.methods[self.methodName]){ + throw errors.ResolverMethodMissingError(resolver.options.address, self.methodName); + } self.parent.handleSend(promiEvent, resolver.methods[self.methodName], preparedArguments, sendOptions, callback); }).catch(function(error) { if (_.isFunction(callback)) { diff --git a/test/e2e.ens.js b/test/e2e.ens.js index bb77f32fcd9..163fc26a0d7 100644 --- a/test/e2e.ens.js +++ b/test/e2e.ens.js @@ -50,5 +50,25 @@ describe('ENS [ @E2E ]', function () { '0x0000000000000000000000000000000000000001' ); }); + + it('should error when calling "getContent" if resolver does not support it', async function () { + try { + await web3.eth.ens.getContent('resolver'); + assert.fail(); + } catch(err){ + assert(err.message.includes(resolverAddr)); + assert(err.message.includes('does not implement requested method: "content"')) + } + }) + + it('should error when calling "setContent" if resolver does not support it', async function () { + try { + await web3.eth.ens.setContent('resolver', web3.utils.sha3('test')); + assert.fail(); + } catch(err){ + assert(err.message.includes(resolverAddr)); + assert(err.message.includes('does not implement requested method: "setContent"')) + } + }) }); From 01cc1248ffbbe9fb6497e2b61e2987e4c05dda0e Mon Sep 17 00:00:00 2001 From: cgewecke Date: Sat, 21 Mar 2020 12:57:07 -0700 Subject: [PATCH 06/21] Draft: get/set content hash --- packages/web3-eth-ens/package-lock.json | 107 ++++++++++++++++++ packages/web3-eth-ens/package.json | 1 + packages/web3-eth-ens/src/ENS.js | 49 +++++++- .../src/lib/ResolverMethodHandler.js | 14 ++- packages/web3-eth-ens/src/lib/contentHash.js | 79 +++++++++++++ test/e2e.ens.js | 101 ++++++++++++++++- 6 files changed, 344 insertions(+), 7 deletions(-) create mode 100644 packages/web3-eth-ens/src/lib/contentHash.js diff --git a/packages/web3-eth-ens/package-lock.json b/packages/web3-eth-ens/package-lock.json index fb2edd50069..3c15304255f 100644 --- a/packages/web3-eth-ens/package-lock.json +++ b/packages/web3-eth-ens/package-lock.json @@ -84,6 +84,19 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "base-x": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", + "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -94,6 +107,15 @@ "concat-map": "0.0.1" } }, + "buffer": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.5.0.tgz", + "integrity": "sha512-9FTEDjLjwoAkEwyMGDjYJQN2gfRgOKBKRfiglhvibGbpeeU/pQn1bJxQqm32OD/AIeEuHxU9roxXxg34Byp/Ww==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", @@ -154,6 +176,34 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, + "cids": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.4.tgz", + "integrity": "sha512-jbjoM2woxvURbO3O9qTmCEWYX5nHHN43tSgDAO707pyjtLw7M42ZAbGqp6hRJe+tpxhZ6+uORSa7ZrnRO7zNdA==", + "requires": { + "buffer": "^5.5.0", + "class-is": "^1.1.0", + "multibase": "~0.6.0", + "multicodec": "^1.0.0", + "multihashes": "~0.4.15" + }, + "dependencies": { + "multicodec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.1.tgz", + "integrity": "sha512-yrrU/K8zHyAH2B0slNVeq3AiwluflHpgQ3TAzwNJcuO2AoPyXgBT2EDkdbP1D8B/yFOY+S2hDYmFlI1vhVFkQw==", + "requires": { + "buffer": "^5.5.0", + "varint": "^5.0.0" + } + } + } + }, + "class-is": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", + "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==" + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -191,6 +241,21 @@ "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + }, + "content-hash": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/content-hash/-/content-hash-2.5.2.tgz", + "integrity": "sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==", + "requires": { + "cids": "^0.7.1", + "multicodec": "^0.5.5", + "multihashes": "^0.4.15" + } + }, + "definitelytyped-header-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/definitelytyped-header-parser/-/definitelytyped-header-parser-1.2.0.tgz", + "integrity": "sha512-xpg8uu/2YD/reaVsZV4oJ4g7UDYFqQGWvT1W9Tsj6q4VtWBSaig38Qgah0ZMnQGF9kAsAim08EXDO1nSi0+Nog==", "dev": true, "requires": { "nice-try": "^1.0.4", @@ -454,6 +519,11 @@ "punycode": "2.1.0" } }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -628,6 +698,33 @@ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true + } + "multibase": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz", + "integrity": "sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==", + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "multicodec": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.7.tgz", + "integrity": "sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==", + "requires": { + "varint": "^5.0.0" + } + }, + "multihashes": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.17.tgz", + "integrity": "sha512-5K5brXK5myhEHgfB8B+Hf470KRdcZcUJ0QSZWyMkwXe2kw7Dh8Fb5tepplEkXAhBcTbEIOe2I9cmIZ4/E1lhfw==", + "requires": { + "buffer": "^5.5.0", + "multibase": "^0.6.0", + "varint": "^5.0.0" + } }, "once": { "version": "1.4.0", @@ -757,6 +854,11 @@ "path-parse": "^1.0.6" } }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -956,6 +1058,11 @@ } } }, + "varint": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz", + "integrity": "sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8=" + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/packages/web3-eth-ens/package.json b/packages/web3-eth-ens/package.json index 028fa81045c..eb824f1cf9b 100644 --- a/packages/web3-eth-ens/package.json +++ b/packages/web3-eth-ens/package.json @@ -13,6 +13,7 @@ }, "main": "src/index.js", "dependencies": { + "content-hash": "^2.5.2", "eth-ens-namehash": "2.0.8", "underscore": "1.9.1", "web3-core": "1.2.7", diff --git a/packages/web3-eth-ens/src/ENS.js b/packages/web3-eth-ens/src/ENS.js index 7eaf0330d52..d2cf472c2e8 100644 --- a/packages/web3-eth-ens/src/ENS.js +++ b/packages/web3-eth-ens/src/ENS.js @@ -26,6 +26,7 @@ var formatters = require('web3-core-helpers').formatters; var utils = require('web3-utils'); var Registry = require('./contracts/Registry'); var ResolverMethodHandler = require('./lib/ResolverMethodHandler'); +var contentHash = require('./lib/contentHash'); /** * Constructs a new instance of ENS @@ -363,7 +364,7 @@ ENS.prototype.setAddress = function (name, address, txConfig, callback) { * @returns {PromiEvent} */ ENS.prototype.getPubkey = function (name, callback) { - return this.resolverMethodHandler.method(name, 'pubkey', [], callback).call(callback); + return this.resolverMethodHandler.method(name, 'pubkey', [], null, callback).call(callback); }; /** @@ -416,6 +417,52 @@ ENS.prototype.setContent = function (name, hash, txConfig, callback) { return this.resolverMethodHandler.method(name, 'setContent', [hash]).send(txConfig, callback); }; +/** + * Returns the content + * + * @method getContent + * + * @param {string} name + * @param {function} callback + * + * @callback callback callback(error, result) + * @returns {PromiEvent} + */ +ENS.prototype.getContentHash = function (name, callback) { + return this.resolverMethodHandler.method(name, 'contenthash', [], contentHash.decode).call(callback); +}; + +/** + * Set the content + * + * @method setContent + * + * @param {string} name + * @param {string} hash + * @param {function} callback + * @param {TransactionConfig} txConfig + * + * @callback callback callback(error, result) + * @returns {PromiEvent} + */ +ENS.prototype.setContentHash = function (name, hash, txConfig, callback) { + var encoded; + try { + encoded = contentHash.encode(hash); + } catch(err){ + var error = new Error(`Could not encode ${hash}. See docs for supported hash protocols.`); + + if (_.isFunction(callback)) { + callback(error, null); + + return; + } + + throw error; + } + return this.resolverMethodHandler.method(name, 'setContenthash', [encoded]).send(txConfig, callback); +}; + /** * Get the multihash * diff --git a/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js b/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js index ad41e1d0789..579686b860c 100644 --- a/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js +++ b/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js @@ -42,14 +42,15 @@ function ResolverMethodHandler(registry) { * @param {function} callback * @returns {Object} */ -ResolverMethodHandler.prototype.method = function (ensName, methodName, methodArguments, callback) { +ResolverMethodHandler.prototype.method = function (ensName, methodName, methodArguments, outputFormatter, callback) { return { call: this.call.bind({ ensName: ensName, methodName: methodName, methodArguments: methodArguments, callback: callback, - parent: this + parent: this, + outputFormatter: outputFormatter }), send: this.send.bind({ ensName: ensName, @@ -70,12 +71,13 @@ ResolverMethodHandler.prototype.call = function (callback) { var self = this; var promiEvent = new PromiEvent(); var preparedArguments = this.parent.prepareArguments(this.ensName, this.methodArguments); + var outputFormatter = this.outputFormatter || null; this.parent.registry.getResolver(this.ensName).then(function (resolver) { if (!resolver.methods[self.methodName]){ throw errors.ResolverMethodMissingError(resolver.options.address, self.methodName); } - self.parent.handleCall(promiEvent, resolver.methods[self.methodName], preparedArguments, callback); + self.parent.handleCall(promiEvent, resolver.methods[self.methodName], preparedArguments, outputFormatter, callback); }).catch(function(error) { if (_.isFunction(callback)) { callback(error, null); @@ -129,9 +131,13 @@ ResolverMethodHandler.prototype.send = function (sendOptions, callback) { * @param {function} callback * @returns {eventifiedPromise} */ -ResolverMethodHandler.prototype.handleCall = function (promiEvent, method, preparedArguments, callback) { +ResolverMethodHandler.prototype.handleCall = function (promiEvent, method, preparedArguments, outputFormatter, callback) { method.apply(this, preparedArguments).call() .then(function (result) { + if (outputFormatter){ + result = outputFormatter(result); + } + if (_.isFunction(callback)) { // It's required to pass the receipt to the second argument to be backwards compatible and to have the required consistency callback(result, result); diff --git a/packages/web3-eth-ens/src/lib/contentHash.js b/packages/web3-eth-ens/src/lib/contentHash.js new file mode 100644 index 00000000000..f3f0862d69c --- /dev/null +++ b/packages/web3-eth-ens/src/lib/contentHash.js @@ -0,0 +1,79 @@ +/* + Adapted from ensdomains/ui + Permalink: https://github.com/ensdomains/ui/blob/3e62e440b53466eeec9dd1c63d73924eefbd88c1/src/utils/contents.js#L1-L85 +*/ + +const contentHash = require('content-hash'); +const supportedCodecs = ['ipfs-ns', 'swarm-ns', 'onion', 'onion3'] + +function decode(encoded) { + let decoded = null; + let protocolType = null; + let error = null; + + if (encoded && encoded.error) { + return { protocolType: null, decoded: encoded.error } + } + if (encoded) { + try { + decoded = contentHash.decode(encoded) + const codec = contentHash.getCodec(encoded) + if (codec === 'ipfs-ns') { + protocolType = 'ipfs' + } else if (codec === 'swarm-ns') { + protocolType = 'bzz' + } else if (codec === 'onion') { + protocolType = 'onion' + } else if (codec === 'onion3') { + protocolType = 'onion3' + } else { + decoded = encoded + } + } catch (e) { + error = e.message + } + } + return { protocolType, decoded, error } +} + +function encode(text) { + let content, contentType + let encoded = false + if (!!text) { + let matched = text.match(/^(ipfs|bzz|onion|onion3):\/\/(.*)/) || text.match(/\/(ipfs)\/(.*)/) + if (matched) { + contentType = matched[1] + content = matched[2] + } + + try { + if (contentType === 'ipfs') { + if(content.length >= 4) { + encoded = '0x' + contentHash.fromIpfs(content) + } + } else if (contentType === 'bzz') { + if(content.length >= 4) { + encoded = '0x' + contentHash.fromSwarm(content) + } + } else if (contentType === 'onion') { + if(content.length == 16) { + encoded = '0x' + contentHash.encode('onion', content); + } + } else if (contentType === 'onion3') { + if(content.length == 56) { + encoded = '0x' + contentHash.encode('onion3', content); + } + } else { + throw new Error('Could not encode content hash: unsupported content type'); + } + } catch (err) { + throw err; + } + } + return encoded +} + +module.exports = { + decode: decode, + encode: encode +} diff --git a/test/e2e.ens.js b/test/e2e.ens.js index 163fc26a0d7..1e997e2613c 100644 --- a/test/e2e.ens.js +++ b/test/e2e.ens.js @@ -3,7 +3,7 @@ const utils = require('./helpers/test.utils'); const Web3 = utils.getWeb3(); const assert = require('assert'); -describe('ENS [ @E2E ]', function () { +describe.only('ENS [ @E2E ]', function () { this.timeout(50000); let web3; @@ -12,6 +12,7 @@ describe('ENS [ @E2E ]', function () { let addresses; let registryAddr; let resolverAddr; + let options; before(async function(){ web3 = new Web3('http://localhost:8545'); @@ -22,6 +23,12 @@ describe('ENS [ @E2E ]', function () { registryAddr = addresses.registry; resolverAddr = addresses.resolver; web3.eth.ens.registryAddress = registryAddr; + + options = { + from: account, + gas: 4000000, + gasPrice: 1 + } }); it('custom registry got defined in the ENS module', function () { @@ -69,6 +76,96 @@ describe('ENS [ @E2E ]', function () { assert(err.message.includes(resolverAddr)); assert(err.message.includes('does not implement requested method: "setContent"')) } - }) + }); + + // This test must be run before any contentHashes are set + it('getContentHash return object keys are null if no contentHash is set', async function(){ + const val = await web3.eth.ens.getContentHash('resolver'); + + assert.equal(val.protocolType, null); + assert.equal(val.decoded, null); + assert.equal(val.error, null); + }); + + /** + * NB: hash values for these tests are borrowed from unit tests at @ensdomains/ui + * Link: https://github.com/ensdomains/ui/blob/3e62e440b53466eeec9dd1c63d73924eefbd88c1/src/utils/contents.test.js#L1-L151 + */ + it('should get/set an IPFS contentHash (ipfs://)', async function(){ + const prefix = "ipfs://" + const hash = "QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"; + + await web3.eth.ens.setContentHash('resolver', prefix + hash, options); + const val = await web3.eth.ens.getContentHash('resolver'); + + assert.equal(val.protocolType, 'ipfs'); + assert.equal(val.decoded, hash); + }); + + it('should get/set an IPFS contentHash (/ipfs/)', async function(){ + const prefix = "/ipfs/" + const hash = "QmaEBknbGT4bTQiQoe2VNgBJbRfygQGktnaW5TbuKixjYL"; + + await web3.eth.ens.setContentHash('resolver', prefix + hash, options); + const val = await web3.eth.ens.getContentHash('resolver'); + + assert.equal(val.protocolType, 'ipfs'); + assert.equal(val.decoded, hash); + }); + + it('should get/set a bzz contentHash', async function(){ + const prefix = "bzz://"; + const hash = "d1de9994b4d039f6548d191eb26786769f580809256b4685ef316805265ea162"; + + await web3.eth.ens.setContentHash('resolver', prefix + hash, options); + const val = await web3.eth.ens.getContentHash('resolver'); + + assert.equal(val.protocolType, 'bzz'); + assert.equal(val.decoded, hash); + }); + + it('should get/set an onion contentHash', async function(){ + const prefix = "onion://" + const hash = "3g2upl4pq6kufc4m"; + + await web3.eth.ens.setContentHash('resolver', prefix + hash, options); + const val = await web3.eth.ens.getContentHash('resolver'); + + assert.equal(val.protocolType, 'onion'); + assert.equal(val.decoded, hash); + }); + + it('should get/set an onion3 contentHash', async function(){ + const prefix = "onion3://" + const hash = "p53lf57qovyuvwsc6xnrppyply3vtqm7l6pcobkmyqsiofyeznfu5uqd"; + + await web3.eth.ens.setContentHash('resolver', prefix + hash, options); + const val = await web3.eth.ens.getContentHash('resolver'); + + assert.equal(val.protocolType, 'onion3'); + assert.equal(val.decoded, hash); + }); + + it('setContentHash errors when encoding an invalid contentHash (promise)', async function(){ + // Missing required protocol prefix + const hash = "p53lf57qovyuvwsc6xnrppyply3vtqm7l6pcobkmyqsiofyeznfu5uqd"; + + try { + await web3.eth.ens.setContentHash('resolver', hash, options); + assert.fail(); + } catch(err) { + assert(err.message.includes(`Could not encode ${hash}`)); + } + }); + + it('setContentHash errors when encoding an invalid contentHash (callback)', function(done){ + // Missing required protocol prefix + const hash = "p53lf57qovyuvwsc6xnrppyply3vtqm7l6pcobkmyqsiofyeznfu5uqd"; + + web3.eth.ens.setContentHash('resolver', hash, options, function(err, result){ + assert(err.message.includes(`Could not encode ${hash}`)); + done(); + }); + }); }); From 88b83b95cf53690e11b2f9e7be7d8beea1596e73 Mon Sep 17 00:00:00 2001 From: cgewecke Date: Sun, 22 Mar 2020 10:46:59 -0700 Subject: [PATCH 07/21] Fix jshint warnings (where possible) --- packages/web3-core-helpers/src/errors.js | 2 +- packages/web3-eth-ens/src/ENS.js | 2 +- .../web3-eth-ens/src/contracts/Registry.js | 20 +++---- packages/web3-eth-ens/src/lib/contentHash.js | 58 ++++++++++--------- 4 files changed, 44 insertions(+), 38 deletions(-) diff --git a/packages/web3-core-helpers/src/errors.js b/packages/web3-core-helpers/src/errors.js index 816604e2021..a093a61a662 100644 --- a/packages/web3-core-helpers/src/errors.js +++ b/packages/web3-core-helpers/src/errors.js @@ -108,6 +108,6 @@ module.exports = { return this.TransactionError('Transaction ran out of gas. Please provide more gas:\n' + JSON.stringify(receipt, null, 2), receipt); }, ResolverMethodMissingError: function(address, name) { - return new Error(`The resolver at ${address} does not implement requested method: "${name}".`); + return new Error('The resolver at ' + address + 'does not implement requested method: "' + name + '".'); } }; diff --git a/packages/web3-eth-ens/src/ENS.js b/packages/web3-eth-ens/src/ENS.js index d2cf472c2e8..f85a1808a9c 100644 --- a/packages/web3-eth-ens/src/ENS.js +++ b/packages/web3-eth-ens/src/ENS.js @@ -450,7 +450,7 @@ ENS.prototype.setContentHash = function (name, hash, txConfig, callback) { try { encoded = contentHash.encode(hash); } catch(err){ - var error = new Error(`Could not encode ${hash}. See docs for supported hash protocols.`); + var error = new Error('Could not encode ' + hash + '. See docs for supported hash protocols.'); if (_.isFunction(callback)) { callback(error, null); diff --git a/packages/web3-eth-ens/src/contracts/Registry.js b/packages/web3-eth-ens/src/contracts/Registry.js index 122fcf8e469..0df9f56c6fc 100644 --- a/packages/web3-eth-ens/src/contracts/Registry.js +++ b/packages/web3-eth-ens/src/contracts/Registry.js @@ -535,7 +535,7 @@ Registry.prototype.getResolver = function (name, callback) { return this.contract.then(function (contract) { return contract.methods.resolver(namehash.hash(name)).call(); }).then(async function (address) { - var abi = await self._getResolverABI(address); + var abi = await self.getResolverABI(address); var contract = new Contract(abi, address); contract.setProvider(self.ens.eth.currentProvider); @@ -563,17 +563,17 @@ Registry.prototype.getResolver = function (name, callback) { * whether the contract at
supports the `contentHash` interface. * Defaults to legacy Resolver if something goes wrong while checking. * - * @method _getResolverABI + * @method getResolverABI * * @param {string} address resolver address * @returns {object} resolver ABI */ -Registry.prototype._getResolverABI = async function(address){ +Registry.prototype.getResolverABI = async function(address){ var isNewResolver = false; try { // Both ABIs implement EIP 165. - const resolver = new Contract(RESOLVER_ABI, address); + var resolver = new Contract(RESOLVER_ABI, address); resolver.setProvider(this.ens.eth.currentProvider); isNewResolver = await resolver .methods @@ -581,16 +581,16 @@ Registry.prototype._getResolverABI = async function(address){ .call(); } catch(err){ - var msg = `Could not identify ABI of resolver contract at "${address}". ` + - `Defaulting to legacy resolver ABI.` - - console.warn(msg); + console.warn( 'Could not identify ABI of resolver contract at "' + address + '". ' + + 'Defaulting to legacy resolver ABI.'); } - if (isNewResolver) return PUBLIC_RESOLVER_ABI; + if (isNewResolver){ + return PUBLIC_RESOLVER_ABI; + } return RESOLVER_ABI; -} +}; /** * Returns the address of the owner of an ENS name. diff --git a/packages/web3-eth-ens/src/lib/contentHash.js b/packages/web3-eth-ens/src/lib/contentHash.js index f3f0862d69c..e861cbe29ba 100644 --- a/packages/web3-eth-ens/src/lib/contentHash.js +++ b/packages/web3-eth-ens/src/lib/contentHash.js @@ -3,64 +3,70 @@ Permalink: https://github.com/ensdomains/ui/blob/3e62e440b53466eeec9dd1c63d73924eefbd88c1/src/utils/contents.js#L1-L85 */ -const contentHash = require('content-hash'); -const supportedCodecs = ['ipfs-ns', 'swarm-ns', 'onion', 'onion3'] +var contentHash = require('content-hash'); function decode(encoded) { - let decoded = null; - let protocolType = null; - let error = null; + var decoded = null; + var protocolType = null; + var error = null; if (encoded && encoded.error) { - return { protocolType: null, decoded: encoded.error } + return { + protocolType: null, + decoded: encoded.error + }; } if (encoded) { try { - decoded = contentHash.decode(encoded) - const codec = contentHash.getCodec(encoded) + decoded = contentHash.decode(encoded); + var codec = contentHash.getCodec(encoded); if (codec === 'ipfs-ns') { - protocolType = 'ipfs' + protocolType = 'ipfs'; } else if (codec === 'swarm-ns') { - protocolType = 'bzz' + protocolType = 'bzz'; } else if (codec === 'onion') { - protocolType = 'onion' + protocolType = 'onion'; } else if (codec === 'onion3') { - protocolType = 'onion3' + protocolType = 'onion3'; } else { - decoded = encoded + decoded = encoded; } } catch (e) { - error = e.message + error = e.message; } } - return { protocolType, decoded, error } + return { + protocolType: protocolType, + decoded: decoded, + error: error + }; } function encode(text) { - let content, contentType - let encoded = false + var content, contentType; + var encoded = false; if (!!text) { - let matched = text.match(/^(ipfs|bzz|onion|onion3):\/\/(.*)/) || text.match(/\/(ipfs)\/(.*)/) + var matched = text.match(/^(ipfs|bzz|onion|onion3):\/\/(.*)/) || text.match(/\/(ipfs)\/(.*)/); if (matched) { - contentType = matched[1] - content = matched[2] + contentType = matched[1]; + content = matched[2]; } try { if (contentType === 'ipfs') { if(content.length >= 4) { - encoded = '0x' + contentHash.fromIpfs(content) + encoded = '0x' + contentHash.fromIpfs(content); } } else if (contentType === 'bzz') { if(content.length >= 4) { - encoded = '0x' + contentHash.fromSwarm(content) + encoded = '0x' + contentHash.fromSwarm(content); } } else if (contentType === 'onion') { - if(content.length == 16) { + if(content.length === 16) { encoded = '0x' + contentHash.encode('onion', content); } } else if (contentType === 'onion3') { - if(content.length == 56) { + if(content.length === 56) { encoded = '0x' + contentHash.encode('onion3', content); } } else { @@ -70,10 +76,10 @@ function encode(text) { throw err; } } - return encoded + return encoded; } module.exports = { decode: decode, encode: encode -} +}; From dd1318581dce99090e4e1279dea3ace2c5cc6e0f Mon Sep 17 00:00:00 2001 From: cgewecke Date: Sun, 22 Mar 2020 10:50:18 -0700 Subject: [PATCH 08/21] Add "unsupported abi" injection tests for contenthash & setContenthash --- test/e2e.ens.js | 2 +- test/eth.ens.js | 143 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 1 deletion(-) diff --git a/test/e2e.ens.js b/test/e2e.ens.js index 1e997e2613c..e6abb046978 100644 --- a/test/e2e.ens.js +++ b/test/e2e.ens.js @@ -3,7 +3,7 @@ const utils = require('./helpers/test.utils'); const Web3 = utils.getWeb3(); const assert = require('assert'); -describe.only('ENS [ @E2E ]', function () { +describe('ENS [ @E2E ]', function () { this.timeout(50000); let web3; diff --git a/test/eth.ens.js b/test/eth.ens.js index 69a29b433a6..a65b9f2f6a0 100644 --- a/test/eth.ens.js +++ b/test/eth.ens.js @@ -2235,6 +2235,149 @@ describe('ens', function () { } ); }); + + it('should error if resolver ABI does not support contenthash (promise)', async function () { + const resolverSignature = 'resolver(bytes32)'; + const contentSignature = 'contenthash(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('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + + try { + await web3.eth.ens.getContentHash('foobar.eth'); + + assert.fail(); + } catch (error) { + assert(error.message.includes('does not implement requested method: "contenthash"')); + } + }); + + it('should error if resolver ABI does not support contenthash (callback)', function (done) { + const resolverSignature = 'resolver(bytes32)'; + const contentSignature = 'contenthash(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('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + + web3.eth.ens.getContentHash( + 'foobar.eth', + function (error, result) { + assert(error.message.includes('does not implement requested method: "contenthash"')); + assert.equal(result, null); + done(); + } + ); + }); + + it('should error if resolver ABI does not support setContenthash (promise)', async function () { + const resolverSignature = 'resolver(bytes32)'; + const contentSignature = 'setContentHash(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('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + + try { + await web3.eth.ens.setContentHash( + 'foobar.eth', + 'ipfs://QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn' + ); + + assert.fail(); + } catch (error) { + assert(error.message.includes('does not implement requested method: "setContenthash"')); + } + }); + + it('should error if resolver ABI does not support setContenthash (callback)', function (done) { + const resolverSignature = 'resolver(bytes32)'; + const contentSignature = 'setContenthash(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('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + to: '0x0123456701234567012345670123456701234567', + }, 'latest']); + }); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + + web3.eth.ens.setContentHash( + 'foobar.eth', + 'ipfs://QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn', + { + from: '0x0123456701234567012345670123456701234567', + gas: 4000000, + gasPrice: 1 + }, + function (error, result) { + assert(error.message.includes('does not implement requested method: "setContenthash"')); + assert.equal(result, null); + done(); + } + ); + }); }); describe('checkNetwork', function () { From d2d40c826d9df4e69e9240b8147985e6b8b39ede Mon Sep 17 00:00:00 2001 From: cgewecke Date: Sun, 22 Mar 2020 13:48:24 -0700 Subject: [PATCH 09/21] Update contentHash typescript & tests --- packages/web3-eth-ens/types/index.d.ts | 14 ++++++++++---- packages/web3-eth-ens/types/tests/ens-test.ts | 12 ++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/web3-eth-ens/types/index.d.ts b/packages/web3-eth-ens/types/index.d.ts index 5c50d7b8976..c47f21fac03 100644 --- a/packages/web3-eth-ens/types/index.d.ts +++ b/packages/web3-eth-ens/types/index.d.ts @@ -22,6 +22,12 @@ import { TransactionRevertInstructionError } from 'web3-core-helpers'; import { Eth } from 'web3-eth'; import { Contract } from 'web3-eth-contract'; +export interface ContentHash { + protocolType: 'ipfs' | 'bzz' | 'onion' | 'onion3' | null, + decoded: string | null, + error?: Error | null +} + // TODO: Define as soon as implemented the generic contract export class Ens { constructor(eth: Eth); @@ -279,12 +285,12 @@ export class Ens { */ getContenthash( name: string, - callback?: (value: any) => void - ): Promise; + callback?: (value: ContentHash) => void + ): Promise; getContenthash( name: string, - callback?: (error: Error, contenthash: string) => void - ): Promise; + callback?: (error: Error, contenthash: ContentHash) => void + ): Promise; setContenthash( name: string, diff --git a/packages/web3-eth-ens/types/tests/ens-test.ts b/packages/web3-eth-ens/types/tests/ens-test.ts index 1606779da8a..17d0af5bcdd 100644 --- a/packages/web3-eth-ens/types/tests/ens-test.ts +++ b/packages/web3-eth-ens/types/tests/ens-test.ts @@ -20,7 +20,7 @@ import { TransactionRevertInstructionError } from 'web3-core-helpers'; import { TransactionReceipt } from 'web3-core'; import { Contract } from 'web3-eth-contract'; -import { Ens } from 'web3-eth-ens'; +import { Ens, ContentHash } from 'web3-eth-ens'; import { Eth } from 'web3-eth'; const ens = new Ens(new Eth('http://localhost:8545')); @@ -210,12 +210,12 @@ ens.setMultihash('name', 'hash', {}, (error: Error, result: any) => {}); // $ExpectType PromiEvent ens.setMultihash('name', 'hash', {}); -// $ExpectType Promise +// $ExpectType Promise ens.getContenthash('name'); -// $ExpectType Promise -ens.getContenthash('name', (error: Error, contenthash: string) => {}); -// $ExpectType Promise -ens.getContenthash('name', (value: any) => {}); +// $ExpectType Promise +ens.getContenthash('name', (error: Error, contenthash: ContentHash) => {}); +// $ExpectType Promise +ens.getContenthash('name', (value: ContentHash) => {}); // $ExpectType PromiEvent ens.setContenthash('name', 'hash'); From 60c91ac920a603153e12142b1ab86aa1b3bac5d3 Mon Sep 17 00:00:00 2001 From: cgewecke Date: Sun, 22 Mar 2020 16:06:37 -0700 Subject: [PATCH 10/21] Update docs for getContentHash / setContentHash --- docs/web3-eth-ens.rst | 128 +++++++++++++++++++++++++++++++ packages/web3-eth-ens/src/ENS.js | 8 +- 2 files changed, 132 insertions(+), 4 deletions(-) diff --git a/docs/web3-eth-ens.rst b/docs/web3-eth-ens.rst index 5292340213d..5222c99f77e 100644 --- a/docs/web3-eth-ens.rst +++ b/docs/web3-eth-ens.rst @@ -938,6 +938,134 @@ For further information on the handling of contract events please see :ref:`here ------------------------------------------------------------------------------ +getContentHash +===================== + +.. code-block:: javascript + + web3.eth.ens.getContentHash(ENSName [, callback]); + +Returns the content hash object associated with an ENS node. + +---------- +Parameters +---------- + +1. ``ENSName`` - ``String``: The ENS name. +2. ``callback`` - ``Function``: (optional) Optional callback + +------- +Returns +------- + +``Promise`` - The content hash object associated with an ENS node. + +------- +Example +------- + +.. code-block:: javascript + + web3.eth.ens.getContentHash('ethereum.eth').then(function (result) { + console.log(result); + }); + > { + "protocolType": "ipfs", + "decoded": "QmaEBknbGT4bTQiQoe2VNgBJbRfygQGktnaW5TbuKixjYL" + } + +------------------------------------------------------------------------------ + +setContentHash +===================== + +.. code-block:: javascript + + web3.eth.ens.setContentHash(ENSName, hash [, txConfig ] [, callback]); + +Sets the content hash associated with an ENS node. + +---------- +Parameters +---------- + +1. ``ENSName`` - ``String``: The ENS name. +2. ``hash`` - ``String``: The content hash to set. +3. ``txConfig`` - ``Object``: (optional) The transaction options as described ::ref::`here ` +4. ``callback`` - ``Function``: (optional) Optional callback + +Emits a ``ContenthashChanged`` event. + +Supports the following protocols as valid ``hash`` inputs: + +1. ``ipfs://`` - example: ipfs://QmaEBknbGT4bTQiQoe2VNgBJbRfygQGktnaW5TbuKixjYL +2. ``/ipfs/`` - example: /ipfs/QmaEBknbGT4bTQiQoe2VNgBJbRfygQGktnaW5TbuKixjYL +3. ``bzz://`` - example: bzz://d1de9994b4d039f6548d191eb26786769f580809256b4685ef316805265ea162 +4. ``onion://`` - example: onion://3g2upl4pq6kufc4m +5. ``onion3://`` - exmaple: onion3://p53lf57qovyuvwsc6xnrppyply3vtqm7l6pcobkmyqsiofyeznfu5uqd + +------- +Returns +------- + +``PromiEvent`` + +------- +Example +------- + +.. code-block:: javascript + + web3.eth.ens.setContentHash( + 'ethereum.eth', + 'ipfs://QmaEBknbGT4bTQiQoe2VNgBJbRfygQGktnaW5TbuKixjYL', + { + from: '0x9CC9a2c777605Af16872E0997b3Aeb91d96D5D8c' + } + ).then(function (result) { + console.log(result.events); + }); + > ContenthashChanged(...) + + // Or using the event emitter + + web3.eth.ens.setContentHash( + 'ethereum.eth', + 'ipfs://QmaEBknbGT4bTQiQoe2VNgBJbRfygQGktnaW5TbuKixjYL', + { + from: '0x9CC9a2c777605Af16872E0997b3Aeb91d96D5D8c' + } + ) + .on('transactionHash', function(hash){ + ... + }) + .on('confirmation', function(confirmationNumber, receipt){ + ... + }) + .on('receipt', function(receipt){ + ... + }) + .on('error', console.error); + + // Or listen to the ContenthashChanged event on the resolver + + web3.eth.ens.resolver('ethereum.eth').then(function (resolver) { + resolver.events.ContenthashChanged({fromBlock: 0}, function(error, event) { + console.log(event); + }) + .on('data', function(event){ + console.log(event); + }) + .on('changed', function(event){ + // remove event from local database + }) + .on('error', console.error); + }); + + +For further information on the handling of contract events please see :ref:`here `. + + getMultihash ===================== diff --git a/packages/web3-eth-ens/src/ENS.js b/packages/web3-eth-ens/src/ENS.js index f85a1808a9c..4c5df34a1ca 100644 --- a/packages/web3-eth-ens/src/ENS.js +++ b/packages/web3-eth-ens/src/ENS.js @@ -418,22 +418,22 @@ ENS.prototype.setContent = function (name, hash, txConfig, callback) { }; /** - * Returns the content + * Returns the contentHash * - * @method getContent + * @method getContentHash * * @param {string} name * @param {function} callback * * @callback callback callback(error, result) - * @returns {PromiEvent} + * @returns {PromiEvent} */ ENS.prototype.getContentHash = function (name, callback) { return this.resolverMethodHandler.method(name, 'contenthash', [], contentHash.decode).call(callback); }; /** - * Set the content + * Set the contentHash * * @method setContent * From 600f1cf202d29c4d71fcee9f8774e37d9b77c94d Mon Sep 17 00:00:00 2001 From: cgewecke Date: Mon, 6 Apr 2020 18:20:38 -0700 Subject: [PATCH 11/21] Use single, extended Resolver ABI --- .../src/ressources/ABI/PublicResolver.js | 772 ------------------ .../src/ressources/ABI/Resolver.js | 470 +++++++++-- 2 files changed, 381 insertions(+), 861 deletions(-) delete mode 100644 packages/web3-eth-ens/src/ressources/ABI/PublicResolver.js diff --git a/packages/web3-eth-ens/src/ressources/ABI/PublicResolver.js b/packages/web3-eth-ens/src/ressources/ABI/PublicResolver.js deleted file mode 100644 index ead8bac20ed..00000000000 --- a/packages/web3-eth-ens/src/ressources/ABI/PublicResolver.js +++ /dev/null @@ -1,772 +0,0 @@ -"use strict"; - -// This ABI taken from @ensdomains/resolver@0.2.4 -// @ensdomains/resolver/build/contracts/PublicResolver.json -var PUBLIC_RESOLVER = [ - { - "constant": true, - "inputs": [ - { - "name": "interfaceID", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "pure", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "data", - "type": "bytes" - } - ], - "name": "setDNSRecords", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "key", - "type": "string" - }, - { - "name": "value", - "type": "string" - } - ], - "name": "setText", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "interfaceID", - "type": "bytes4" - } - ], - "name": "interfaceImplementer", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "contentTypes", - "type": "uint256" - } - ], - "name": "ABI", - "outputs": [ - { - "name": "", - "type": "uint256" - }, - { - "name": "", - "type": "bytes" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "x", - "type": "bytes32" - }, - { - "name": "y", - "type": "bytes32" - } - ], - "name": "setPubkey", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "hash", - "type": "bytes" - } - ], - "name": "setContenthash", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "node", - "type": "bytes32" - } - ], - "name": "addr", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "name", - "type": "bytes32" - } - ], - "name": "hasDNSRecords", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "key", - "type": "string" - } - ], - "name": "text", - "outputs": [ - { - "name": "", - "type": "string" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "contentType", - "type": "uint256" - }, - { - "name": "data", - "type": "bytes" - } - ], - "name": "setABI", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "node", - "type": "bytes32" - } - ], - "name": "name", - "outputs": [ - { - "name": "", - "type": "string" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "name", - "type": "string" - } - ], - "name": "setName", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "coinType", - "type": "uint256" - }, - { - "name": "a", - "type": "bytes" - } - ], - "name": "setAddr", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "name", - "type": "bytes32" - }, - { - "name": "resource", - "type": "uint16" - } - ], - "name": "dnsRecord", - "outputs": [ - { - "name": "", - "type": "bytes" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "node", - "type": "bytes32" - } - ], - "name": "clearDNSZone", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "node", - "type": "bytes32" - } - ], - "name": "contenthash", - "outputs": [ - { - "name": "", - "type": "bytes" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "node", - "type": "bytes32" - } - ], - "name": "pubkey", - "outputs": [ - { - "name": "x", - "type": "bytes32" - }, - { - "name": "y", - "type": "bytes32" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "a", - "type": "address" - } - ], - "name": "setAddr", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "interfaceID", - "type": "bytes4" - }, - { - "name": "implementer", - "type": "address" - } - ], - "name": "setInterface", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "coinType", - "type": "uint256" - } - ], - "name": "addr", - "outputs": [ - { - "name": "", - "type": "bytes" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "", - "type": "bytes32" - }, - { - "name": "", - "type": "address" - }, - { - "name": "", - "type": "address" - } - ], - "name": "authorisations", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "name": "_ens", - "type": "address" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "node", - "type": "bytes32" - }, - { - "indexed": true, - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "name": "target", - "type": "address" - }, - { - "indexed": false, - "name": "isAuthorised", - "type": "bool" - } - ], - "name": "AuthorisationChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "node", - "type": "bytes32" - }, - { - "indexed": true, - "name": "indexedKey", - "type": "string" - }, - { - "indexed": false, - "name": "key", - "type": "string" - } - ], - "name": "TextChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "node", - "type": "bytes32" - }, - { - "indexed": false, - "name": "x", - "type": "bytes32" - }, - { - "indexed": false, - "name": "y", - "type": "bytes32" - } - ], - "name": "PubkeyChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "node", - "type": "bytes32" - }, - { - "indexed": false, - "name": "name", - "type": "string" - } - ], - "name": "NameChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "node", - "type": "bytes32" - }, - { - "indexed": true, - "name": "interfaceID", - "type": "bytes4" - }, - { - "indexed": false, - "name": "implementer", - "type": "address" - } - ], - "name": "InterfaceChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "node", - "type": "bytes32" - }, - { - "indexed": false, - "name": "name", - "type": "bytes" - }, - { - "indexed": false, - "name": "resource", - "type": "uint16" - }, - { - "indexed": false, - "name": "record", - "type": "bytes" - } - ], - "name": "DNSRecordChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "node", - "type": "bytes32" - }, - { - "indexed": false, - "name": "name", - "type": "bytes" - }, - { - "indexed": false, - "name": "resource", - "type": "uint16" - } - ], - "name": "DNSRecordDeleted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "node", - "type": "bytes32" - } - ], - "name": "DNSZoneCleared", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "node", - "type": "bytes32" - }, - { - "indexed": false, - "name": "hash", - "type": "bytes" - } - ], - "name": "ContenthashChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "node", - "type": "bytes32" - }, - { - "indexed": false, - "name": "a", - "type": "address" - } - ], - "name": "AddrChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "node", - "type": "bytes32" - }, - { - "indexed": false, - "name": "coinType", - "type": "uint256" - }, - { - "indexed": false, - "name": "newAddress", - "type": "bytes" - } - ], - "name": "AddressChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "node", - "type": "bytes32" - }, - { - "indexed": true, - "name": "contentType", - "type": "uint256" - } - ], - "name": "ABIChanged", - "type": "event" - }, - { - "constant": false, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "target", - "type": "address" - }, - { - "name": "isAuthorised", - "type": "bool" - } - ], - "name": "setAuthorisation", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "name": "results", - "type": "bytes[]" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - } -]; - -module.exports = PUBLIC_RESOLVER; diff --git a/packages/web3-eth-ens/src/ressources/ABI/Resolver.js b/packages/web3-eth-ens/src/ressources/ABI/Resolver.js index 9bd8da24603..2976f3943b3 100644 --- a/packages/web3-eth-ens/src/ressources/ABI/Resolver.js +++ b/packages/web3-eth-ens/src/ressources/ABI/Resolver.js @@ -1,23 +1,158 @@ "use strict"; +// This ABI taken from @ensdomains/resolver@0.2.4 +// @ensdomains/resolver/build/contracts/Resolver.json var RESOLVER = [ { - "constant": true, + "anonymous": false, "inputs": [ { - "name": "interfaceID", - "type": "bytes4" + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": false, + "name": "a", + "type": "address" } ], - "name": "supportsInterface", - "outputs": [ + "name": "AddrChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { - "name": "", - "type": "bool" + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": false, + "name": "coinType", + "type": "uint256" + }, + { + "indexed": false, + "name": "newAddress", + "type": "bytes" } ], - "payable": false, - "type": "function" + "name": "AddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": false, + "name": "name", + "type": "string" + } + ], + "name": "NameChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": true, + "name": "contentType", + "type": "uint256" + } + ], + "name": "ABIChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": false, + "name": "x", + "type": "bytes32" + }, + { + "indexed": false, + "name": "y", + "type": "bytes32" + } + ], + "name": "PubkeyChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": true, + "name": "indexedKey", + "type": "string" + }, + { + "indexed": false, + "name": "key", + "type": "string" + } + ], + "name": "TextChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": false, + "name": "hash", + "type": "bytes" + } + ], + "name": "ContenthashChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "node", + "type": "bytes32" + }, + { + "indexed": false, + "name": "hash", + "type": "bytes32" + } + ], + "name": "ContentChanged", + "type": "event" }, { "constant": true, @@ -34,33 +169,39 @@ var RESOLVER = [ "name": "ABI", "outputs": [ { - "name": "contentType", + "name": "", "type": "uint256" }, { - "name": "data", + "name": "", "type": "bytes" } ], "payable": false, + "stateMutability": "view", "type": "function" }, { - "constant": false, + "constant": true, "inputs": [ { "name": "node", "type": "bytes32" }, { - "name": "hash", + "name": "coinType", + "type": "uint256" + } + ], + "name": "addr", + "outputs": [ + { + "name": "", "type": "bytes" } ], - "name": "setMultihash", - "outputs": [], "payable": false, - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { @@ -71,7 +212,26 @@ var RESOLVER = [ "type": "bytes32" } ], - "name": "multihash", + "name": "addr", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "node", + "type": "bytes32" + } + ], + "name": "contenthash", "outputs": [ { "name": "", @@ -83,12 +243,53 @@ var RESOLVER = [ "type": "function" }, { - "constant": false, + "constant": true, "inputs": [ { "name": "node", "type": "bytes32" - }, + } + ], + "name": "dnsrr", + "outputs": [ + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "node", + "type": "bytes32" + } + ], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "node", + "type": "bytes32" + } + ], + "name": "pubkey", + "outputs": [ { "name": "x", "type": "bytes32" @@ -98,9 +299,8 @@ var RESOLVER = [ "type": "bytes32" } ], - "name": "setPubkey", - "outputs": [], "payable": false, + "stateMutability": "view", "type": "function" }, { @@ -109,16 +309,21 @@ var RESOLVER = [ { "name": "node", "type": "bytes32" + }, + { + "name": "key", + "type": "string" } ], - "name": "content", + "name": "text", "outputs": [ { - "name": "ret", - "type": "bytes32" + "name": "", + "type": "string" } ], "payable": false, + "stateMutability": "view", "type": "function" }, { @@ -127,16 +332,21 @@ var RESOLVER = [ { "name": "node", "type": "bytes32" + }, + { + "name": "interfaceID", + "type": "bytes4" } ], - "name": "addr", + "name": "interfaceImplementer", "outputs": [ { - "name": "ret", + "name": "", "type": "address" } ], "payable": false, + "stateMutability": "view", "type": "function" }, { @@ -158,24 +368,25 @@ var RESOLVER = [ "name": "setABI", "outputs": [], "payable": false, + "stateMutability": "nonpayable", "type": "function" }, { - "constant": true, + "constant": false, "inputs": [ { "name": "node", "type": "bytes32" - } - ], - "name": "name", - "outputs": [ + }, { - "name": "ret", - "type": "string" + "name": "addr", + "type": "address" } ], + "name": "setAddr", + "outputs": [], "payable": false, + "stateMutability": "nonpayable", "type": "function" }, { @@ -186,13 +397,18 @@ var RESOLVER = [ "type": "bytes32" }, { - "name": "name", - "type": "string" + "name": "coinType", + "type": "uint256" + }, + { + "name": "a", + "type": "bytes" } ], - "name": "setName", + "name": "setAddr", "outputs": [], "payable": false, + "stateMutability": "nonpayable", "type": "function" }, { @@ -204,24 +420,58 @@ var RESOLVER = [ }, { "name": "hash", + "type": "bytes" + } + ], + "name": "setContenthash", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "node", "type": "bytes32" + }, + { + "name": "data", + "type": "bytes" } ], - "name": "setContent", + "name": "setDnsrr", "outputs": [], "payable": false, + "stateMutability": "nonpayable", "type": "function" }, { - "constant": true, + "constant": false, "inputs": [ { "name": "node", "type": "bytes32" + }, + { + "name": "_name", + "type": "string" } ], - "name": "pubkey", - "outputs": [ + "name": "setName", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "node", + "type": "bytes32" + }, { "name": "x", "type": "bytes32" @@ -231,7 +481,10 @@ var RESOLVER = [ "type": "bytes32" } ], + "name": "setPubkey", + "outputs": [], "payable": false, + "stateMutability": "nonpayable", "type": "function" }, { @@ -242,114 +495,153 @@ var RESOLVER = [ "type": "bytes32" }, { - "name": "addr", - "type": "address" + "name": "key", + "type": "string" + }, + { + "name": "value", + "type": "string" } ], - "name": "setAddr", + "name": "setText", "outputs": [], "payable": false, + "stateMutability": "nonpayable", "type": "function" }, { + "constant": false, "inputs": [ { - "name": "ensAddr", + "name": "node", + "type": "bytes32" + }, + { + "name": "interfaceID", + "type": "bytes4" + }, + { + "name": "implementer", "type": "address" } ], + "name": "setInterface", + "outputs": [], "payable": false, - "type": "constructor" + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, + "constant": true, "inputs": [ { - "indexed": true, - "name": "node", - "type": "bytes32" - }, + "name": "interfaceID", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ { - "indexed": false, - "name": "a", - "type": "address" + "name": "", + "type": "bool" } ], - "name": "AddrChanged", - "type": "event" + "payable": false, + "stateMutability": "pure", + "type": "function" }, { - "anonymous": false, + "constant": false, + "inputs": [ + { + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "name": "results", + "type": "bytes[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, "inputs": [ { - "indexed": true, "name": "node", "type": "bytes32" - }, + } + ], + "name": "content", + "outputs": [ { - "indexed": false, - "name": "hash", + "name": "", "type": "bytes32" } ], - "name": "ContentChanged", - "type": "event" + "payable": false, + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, + "constant": true, "inputs": [ { - "indexed": true, "name": "node", "type": "bytes32" - }, + } + ], + "name": "multihash", + "outputs": [ { - "indexed": false, - "name": "name", - "type": "string" + "name": "", + "type": "bytes" } ], - "name": "NameChanged", - "type": "event" + "payable": false, + "stateMutability": "view", + "type": "function" }, { - "anonymous": false, + "constant": false, "inputs": [ { - "indexed": true, "name": "node", "type": "bytes32" }, { - "indexed": true, - "name": "contentType", - "type": "uint256" + "name": "hash", + "type": "bytes32" } ], - "name": "ABIChanged", - "type": "event" + "name": "setContent", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, + "constant": false, "inputs": [ { - "indexed": true, "name": "node", "type": "bytes32" }, { - "indexed": false, - "name": "x", - "type": "bytes32" - }, - { - "indexed": false, - "name": "y", - "type": "bytes32" + "name": "hash", + "type": "bytes" } ], - "name": "PubkeyChanged", - "type": "event" + "name": "setMultihash", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" } ]; From b40af90e607139838206ed5957d1d0568a5104b0 Mon Sep 17 00:00:00 2001 From: cgewecke Date: Mon, 6 Apr 2020 19:40:57 -0700 Subject: [PATCH 12/21] Call supportsInterface for each method --- .../web3-eth-ens/src/contracts/Registry.js | 47 +--------- .../src/lib/ResolverMethodHandler.js | 52 +++++++++-- test/eth.ens.js | 92 +++++++++---------- 3 files changed, 90 insertions(+), 101 deletions(-) diff --git a/packages/web3-eth-ens/src/contracts/Registry.js b/packages/web3-eth-ens/src/contracts/Registry.js index 0df9f56c6fc..c6040fd0b6b 100644 --- a/packages/web3-eth-ens/src/contracts/Registry.js +++ b/packages/web3-eth-ens/src/contracts/Registry.js @@ -28,14 +28,6 @@ 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'); -var PUBLIC_RESOLVER_ABI = require('../ressources/ABI/PublicResolver'); - -// Value taken from EIP 1577 (Content Hash) specification -// Support for this interface is used as a switch to decide whether to -// instantiate the Resolver contract as a PublicResolver or legacy Resolver. -// Both contracts implement EIP 165 (Supports Interface). -var CONTENT_HASH_INTERFACE_ID = "0xbc1c58d1"; - /** * A wrapper around the ENS registry contract. @@ -534,9 +526,8 @@ Registry.prototype.getResolver = function (name, callback) { return this.contract.then(function (contract) { return contract.methods.resolver(namehash.hash(name)).call(); - }).then(async function (address) { - var abi = await self.getResolverABI(address); - var contract = new Contract(abi, address); + }).then(function (address) { + var contract = new Contract(RESOLVER_ABI, address); contract.setProvider(self.ens.eth.currentProvider); if (_.isFunction(callback)) { @@ -558,40 +549,6 @@ Registry.prototype.getResolver = function (name, callback) { }); }; -/** - * Returns either PublicResolver ABI or legacy Resolver ABI based on - * whether the contract at
supports the `contentHash` interface. - * Defaults to legacy Resolver if something goes wrong while checking. - * - * @method getResolverABI - * - * @param {string} address resolver address - * @returns {object} resolver ABI - */ -Registry.prototype.getResolverABI = async function(address){ - var isNewResolver = false; - - try { - // Both ABIs implement EIP 165. - var resolver = new Contract(RESOLVER_ABI, address); - resolver.setProvider(this.ens.eth.currentProvider); - isNewResolver = await resolver - .methods - .supportsInterface(CONTENT_HASH_INTERFACE_ID) - .call(); - - } catch(err){ - console.warn( 'Could not identify ABI of resolver contract at "' + address + '". ' + - 'Defaulting to legacy resolver ABI.'); - } - - if (isNewResolver){ - return PUBLIC_RESOLVER_ABI; - } - - return RESOLVER_ABI; -}; - /** * Returns the address of the owner of an ENS name. * diff --git a/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js b/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js index 579686b860c..be702ae9a0a 100644 --- a/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js +++ b/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js @@ -25,6 +25,19 @@ var namehash = require('eth-ens-namehash'); var errors = require('web3-core-helpers').errors; var _ = require('underscore'); +// These ids obtained at ensdomains docs: +// https://docs.ens.domains/contract-developer-guide/writing-a-resolver +var interfaceIds = { + addr: "0x3b3b57de", + setAddr: "0x3b3b57de", + pubkey: "0xc8690233", + setPubkey: "0xc8690233", + contenthash: "0xbc1c58d1", + setContenthash: "0xbc1c58d1", + content: "0xd8389dc5", + setContent: "0xd8389dc5" +}; + /** * @param {Registry} registry * @constructor @@ -73,10 +86,8 @@ ResolverMethodHandler.prototype.call = function (callback) { var preparedArguments = this.parent.prepareArguments(this.ensName, this.methodArguments); var outputFormatter = this.outputFormatter || null; - this.parent.registry.getResolver(this.ensName).then(function (resolver) { - if (!resolver.methods[self.methodName]){ - throw errors.ResolverMethodMissingError(resolver.options.address, self.methodName); - } + this.parent.registry.getResolver(this.ensName).then(async function (resolver) { + await self.parent.checkInterfaceSupport(resolver, self.methodName); self.parent.handleCall(promiEvent, resolver.methods[self.methodName], preparedArguments, outputFormatter, callback); }).catch(function(error) { if (_.isFunction(callback)) { @@ -104,10 +115,8 @@ ResolverMethodHandler.prototype.send = function (sendOptions, callback) { var promiEvent = new PromiEvent(); var preparedArguments = this.parent.prepareArguments(this.ensName, this.methodArguments); - this.parent.registry.getResolver(this.ensName).then(function (resolver) { - if (!resolver.methods[self.methodName]){ - throw errors.ResolverMethodMissingError(resolver.options.address, self.methodName); - } + this.parent.registry.getResolver(this.ensName).then(async function (resolver) { + await self.parent.checkInterfaceSupport(resolver, self.methodName); self.parent.handleSend(promiEvent, resolver.methods[self.methodName], preparedArguments, sendOptions, callback); }).catch(function(error) { if (_.isFunction(callback)) { @@ -221,4 +230,31 @@ ResolverMethodHandler.prototype.prepareArguments = function (name, methodArgumen return [node]; }; +/** + * + * + * @param {Contract} resolver + * @param {string} methodName + * + * @returns {Promise} + */ +ResolverMethodHandler.prototype.checkInterfaceSupport = async function (resolver, methodName) { + // Skip validation for undocumented interface ids (ex: multihash) + if (!interfaceIds[methodName]) return; + + var supported = false; + try { + supported = await resolver + .methods + .supportsInterface(interfaceIds[methodName]) + .call(); + } catch(err) { + console.warn('Could not verify interface of resolver contract at "' + resolver.options.address + '". '); + } + + if (!supported){ + throw errors.ResolverMethodMissingError(resolver.options.address, methodName); + } +}; + module.exports = ResolverMethodHandler; diff --git a/test/eth.ens.js b/test/eth.ens.js index a65b9f2f6a0..13d5905e079 100644 --- a/test/eth.ens.js +++ b/test/eth.ens.js @@ -889,16 +889,6 @@ describe('ens', function () { }); 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(supportsInterfaceSignature).slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', - to: '0x0123456701234567012345670123456701234567', - }, 'latest']); - }); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); - provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); @@ -929,16 +919,6 @@ describe('ens', function () { }); 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(supportsInterfaceSignature).slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', - to: '0x0123456701234567012345670123456701234567', - }, 'latest']); - }); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); - provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); @@ -1635,6 +1615,7 @@ describe('ens', function () { it('should call getAddress and return the expected address (promise)', async function () { const resolverSig = 'resolver(bytes32)'; const addrSig = 'addr(bytes32)'; + const addrInterfaceId = "3b3b57de"; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -1650,11 +1631,11 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + data: sha3('supportsInterface(bytes4)').slice(0, 10) + addrInterfaceId + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -1674,6 +1655,7 @@ describe('ens', function () { it('should call getAddress and return the expected address (callback)', function (done) { const resolverSig = 'resolver(bytes32)'; const addrSig = 'addr(bytes32)'; + const addrInterfaceId = "3b3b57de"; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -1689,11 +1671,11 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + data: sha3('supportsInterface(bytes4)').slice(0, 10) + addrInterfaceId + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -1716,6 +1698,7 @@ describe('ens', function () { it('should call getAddress and throw the expected error (promise)', async function () { const resolverSig = 'resolver(bytes32)'; const addrSig = 'addr(bytes32)'; + const addrInterfaceId = "3b3b57de"; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -1731,11 +1714,11 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + data: sha3('supportsInterface(bytes4)').slice(0, 10) + addrInterfaceId + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -1771,6 +1754,7 @@ describe('ens', function () { it('should call getAddress and throw the expected error (callback)', function (done) { const resolverSig = 'resolver(bytes32)'; const addrSig = 'addr(bytes32)'; + const addrInterfaceId = "3b3b57de"; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -1786,11 +1770,11 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + data: sha3('supportsInterface(bytes4)').slice(0, 10) + addrInterfaceId + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -1824,6 +1808,7 @@ describe('ens', function () { it('should call getPubkey and return the expected X and Y value (promise)', async function () { const resolverSignature = 'resolver(bytes32)'; const pubkeySignature = 'pubkey(bytes32)'; + const pubkeyInterfaceId = "c8690233"; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -1839,11 +1824,11 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + data: sha3('supportsInterface(bytes4)').slice(0, 10) + pubkeyInterfaceId + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -1869,6 +1854,7 @@ describe('ens', function () { it('should call getPubkey and return the expected X and Y value (callback)', function (done) { const resolverSignature = 'resolver(bytes32)'; const pubkeySignature = 'pubkey(bytes32)'; + const pubkeyInterfaceId = "c8690233"; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -1884,11 +1870,11 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + data: sha3('supportsInterface(bytes4)').slice(0, 10) + pubkeyInterfaceId + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -1922,6 +1908,7 @@ describe('ens', function () { it('should call getPubkey and throw the expected error (callback)', function (done) { const resolverSignature = 'resolver(bytes32)'; const pubkeySignature = 'pubkey(bytes32)'; + const pubkeyInterfaceId = "c8690233"; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -1937,11 +1924,11 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + data: sha3('supportsInterface(bytes4)').slice(0, 10) + pubkeyInterfaceId + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -1984,6 +1971,7 @@ describe('ens', function () { it('should call getPubkey and throw the expected error (promise)', async function () { const resolverSignature = 'resolver(bytes32)'; const pubkeySignature = 'pubkey(bytes32)'; + const pubkeyInterfaceId = "c8690233"; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -1999,11 +1987,11 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + data: sha3('supportsInterface(bytes4)').slice(0, 10) + pubkeyInterfaceId + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -2044,6 +2032,7 @@ describe('ens', function () { it('should call getContent and return the expected content of the resolver (promise)', async function () { const resolverSignature = 'resolver(bytes32)'; const contentSignature = 'content(bytes32)'; + const contentInterfaceId = 'd8389dc5'; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -2059,11 +2048,11 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + data: sha3('supportsInterface(bytes4)').slice(0, 10) + contentInterfaceId + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -2084,6 +2073,7 @@ describe('ens', function () { it('should call getContent and return the expected content of the resolver (callback)', function () { const resolverSignature = 'resolver(bytes32)'; const contentSignature = 'content(bytes32)'; + const contentInterfaceId = 'd8389dc5'; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -2099,11 +2089,11 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + data: sha3('supportsInterface(bytes4)').slice(0, 10) + contentInterfaceId + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -2129,6 +2119,7 @@ describe('ens', function () { it('should call getContent and throw the expected error (promise)', async function () { const resolverSignature = 'resolver(bytes32)'; const contentSignature = 'content(bytes32)'; + const contentInterfaceId = 'd8389dc5'; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -2144,11 +2135,11 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + data: sha3('supportsInterface(bytes4)').slice(0, 10) + contentInterfaceId + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -2183,6 +2174,7 @@ describe('ens', function () { it('should call getContent and throw the expected error (callback)', function () { const resolverSignature = 'resolver(bytes32)'; const contentSignature = 'content(bytes32)'; + const contentInterfaceId = 'd8389dc5'; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -2198,11 +2190,11 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + data: sha3('supportsInterface(bytes4)').slice(0, 10) + contentInterfaceId + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); - provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000001'); provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -2239,6 +2231,7 @@ describe('ens', function () { it('should error if resolver ABI does not support contenthash (promise)', async function () { const resolverSignature = 'resolver(bytes32)'; const contentSignature = 'contenthash(bytes32)'; + const contenthashInterfaceId = 'bc1c58d1'; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -2254,7 +2247,7 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + data: sha3('supportsInterface(bytes4)').slice(0, 10) + contenthashInterfaceId + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); @@ -2272,6 +2265,7 @@ describe('ens', function () { it('should error if resolver ABI does not support contenthash (callback)', function (done) { const resolverSignature = 'resolver(bytes32)'; const contentSignature = 'contenthash(bytes32)'; + const contenthashInterfaceId = 'bc1c58d1'; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -2287,7 +2281,7 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + data: sha3('supportsInterface(bytes4)').slice(0, 10) + contenthashInterfaceId + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); @@ -2306,6 +2300,7 @@ describe('ens', function () { it('should error if resolver ABI does not support setContenthash (promise)', async function () { const resolverSignature = 'resolver(bytes32)'; const contentSignature = 'setContentHash(bytes32)'; + const contenthashInterfaceId = 'bc1c58d1'; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -2321,7 +2316,7 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + data: sha3('supportsInterface(bytes4)').slice(0, 10) + contenthashInterfaceId + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); @@ -2342,6 +2337,7 @@ describe('ens', function () { it('should error if resolver ABI does not support setContenthash (callback)', function (done) { const resolverSignature = 'resolver(bytes32)'; const contentSignature = 'setContenthash(bytes32)'; + const contenthashInterfaceId = 'bc1c58d1'; provider.injectValidation(function (payload) { assert.equal(payload.jsonrpc, '2.0'); @@ -2357,7 +2353,7 @@ describe('ens', function () { assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ - data: sha3('supportsInterface(bytes4)').slice(0, 10) + sha3('contenthash(bytes32)').slice(2, 10) + '00000000000000000000000000000000000000000000000000000000', + data: sha3('supportsInterface(bytes4)').slice(0, 10) + contenthashInterfaceId + '00000000000000000000000000000000000000000000000000000000', to: '0x0123456701234567012345670123456701234567', }, 'latest']); }); From ba5f85fa14d60796bcceebeb8dc2ae49498b89a0 Mon Sep 17 00:00:00 2001 From: cgewecke Date: Mon, 6 Apr 2020 19:51:44 -0700 Subject: [PATCH 13/21] Undo contenthash camel-casing (per EIP convention) --- packages/web3-eth-ens/src/ENS.js | 16 ++++++------ test/e2e.ens.js | 42 ++++++++++++++++---------------- test/eth.ens.js | 10 ++++---- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/packages/web3-eth-ens/src/ENS.js b/packages/web3-eth-ens/src/ENS.js index 4c5df34a1ca..604df14329d 100644 --- a/packages/web3-eth-ens/src/ENS.js +++ b/packages/web3-eth-ens/src/ENS.js @@ -26,7 +26,7 @@ var formatters = require('web3-core-helpers').formatters; var utils = require('web3-utils'); var Registry = require('./contracts/Registry'); var ResolverMethodHandler = require('./lib/ResolverMethodHandler'); -var contentHash = require('./lib/contentHash'); +var contenthash = require('./lib/contentHash'); /** * Constructs a new instance of ENS @@ -418,9 +418,9 @@ ENS.prototype.setContent = function (name, hash, txConfig, callback) { }; /** - * Returns the contentHash + * Returns the contenthash * - * @method getContentHash + * @method getContenthash * * @param {string} name * @param {function} callback @@ -428,12 +428,12 @@ ENS.prototype.setContent = function (name, hash, txConfig, callback) { * @callback callback callback(error, result) * @returns {PromiEvent} */ -ENS.prototype.getContentHash = function (name, callback) { - return this.resolverMethodHandler.method(name, 'contenthash', [], contentHash.decode).call(callback); +ENS.prototype.getContenthash = function (name, callback) { + return this.resolverMethodHandler.method(name, 'contenthash', [], contenthash.decode).call(callback); }; /** - * Set the contentHash + * Set the contenthash * * @method setContent * @@ -445,10 +445,10 @@ ENS.prototype.getContentHash = function (name, callback) { * @callback callback callback(error, result) * @returns {PromiEvent} */ -ENS.prototype.setContentHash = function (name, hash, txConfig, callback) { +ENS.prototype.setContenthash = function (name, hash, txConfig, callback) { var encoded; try { - encoded = contentHash.encode(hash); + encoded = contenthash.encode(hash); } catch(err){ var error = new Error('Could not encode ' + hash + '. See docs for supported hash protocols.'); diff --git a/test/e2e.ens.js b/test/e2e.ens.js index e6abb046978..2460588765f 100644 --- a/test/e2e.ens.js +++ b/test/e2e.ens.js @@ -79,8 +79,8 @@ describe('ENS [ @E2E ]', function () { }); // This test must be run before any contentHashes are set - it('getContentHash return object keys are null if no contentHash is set', async function(){ - const val = await web3.eth.ens.getContentHash('resolver'); + it('getContenthash return object keys are null if no contentHash is set', async function(){ + const val = await web3.eth.ens.getContenthash('resolver'); assert.equal(val.protocolType, null); assert.equal(val.decoded, null); @@ -91,78 +91,78 @@ describe('ENS [ @E2E ]', function () { * NB: hash values for these tests are borrowed from unit tests at @ensdomains/ui * Link: https://github.com/ensdomains/ui/blob/3e62e440b53466eeec9dd1c63d73924eefbd88c1/src/utils/contents.test.js#L1-L151 */ - it('should get/set an IPFS contentHash (ipfs://)', async function(){ + it('should get/set an IPFS contenthash (ipfs://)', async function(){ const prefix = "ipfs://" const hash = "QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"; - await web3.eth.ens.setContentHash('resolver', prefix + hash, options); - const val = await web3.eth.ens.getContentHash('resolver'); + await web3.eth.ens.setContenthash('resolver', prefix + hash, options); + const val = await web3.eth.ens.getContenthash('resolver'); assert.equal(val.protocolType, 'ipfs'); assert.equal(val.decoded, hash); }); - it('should get/set an IPFS contentHash (/ipfs/)', async function(){ + it('should get/set an IPFS contenthash (/ipfs/)', async function(){ const prefix = "/ipfs/" const hash = "QmaEBknbGT4bTQiQoe2VNgBJbRfygQGktnaW5TbuKixjYL"; - await web3.eth.ens.setContentHash('resolver', prefix + hash, options); - const val = await web3.eth.ens.getContentHash('resolver'); + await web3.eth.ens.setContenthash('resolver', prefix + hash, options); + const val = await web3.eth.ens.getContenthash('resolver'); assert.equal(val.protocolType, 'ipfs'); assert.equal(val.decoded, hash); }); - it('should get/set a bzz contentHash', async function(){ + it('should get/set a bzz contenthash', async function(){ const prefix = "bzz://"; const hash = "d1de9994b4d039f6548d191eb26786769f580809256b4685ef316805265ea162"; - await web3.eth.ens.setContentHash('resolver', prefix + hash, options); - const val = await web3.eth.ens.getContentHash('resolver'); + await web3.eth.ens.setContenthash('resolver', prefix + hash, options); + const val = await web3.eth.ens.getContenthash('resolver'); assert.equal(val.protocolType, 'bzz'); assert.equal(val.decoded, hash); }); - it('should get/set an onion contentHash', async function(){ + it('should get/set an onion contenthash', async function(){ const prefix = "onion://" const hash = "3g2upl4pq6kufc4m"; - await web3.eth.ens.setContentHash('resolver', prefix + hash, options); - const val = await web3.eth.ens.getContentHash('resolver'); + await web3.eth.ens.setContenthash('resolver', prefix + hash, options); + const val = await web3.eth.ens.getContenthash('resolver'); assert.equal(val.protocolType, 'onion'); assert.equal(val.decoded, hash); }); - it('should get/set an onion3 contentHash', async function(){ + it('should get/set an onion3 contenthash', async function(){ const prefix = "onion3://" const hash = "p53lf57qovyuvwsc6xnrppyply3vtqm7l6pcobkmyqsiofyeznfu5uqd"; - await web3.eth.ens.setContentHash('resolver', prefix + hash, options); - const val = await web3.eth.ens.getContentHash('resolver'); + await web3.eth.ens.setContenthash('resolver', prefix + hash, options); + const val = await web3.eth.ens.getContenthash('resolver'); assert.equal(val.protocolType, 'onion3'); assert.equal(val.decoded, hash); }); - it('setContentHash errors when encoding an invalid contentHash (promise)', async function(){ + it('setContenthash errors when encoding an invalid contenthash (promise)', async function(){ // Missing required protocol prefix const hash = "p53lf57qovyuvwsc6xnrppyply3vtqm7l6pcobkmyqsiofyeznfu5uqd"; try { - await web3.eth.ens.setContentHash('resolver', hash, options); + await web3.eth.ens.setContenthash('resolver', hash, options); assert.fail(); } catch(err) { assert(err.message.includes(`Could not encode ${hash}`)); } }); - it('setContentHash errors when encoding an invalid contentHash (callback)', function(done){ + it('setContentHash errors when encoding an invalid contenthash (callback)', function(done){ // Missing required protocol prefix const hash = "p53lf57qovyuvwsc6xnrppyply3vtqm7l6pcobkmyqsiofyeznfu5uqd"; - web3.eth.ens.setContentHash('resolver', hash, options, function(err, result){ + web3.eth.ens.setContenthash('resolver', hash, options, function(err, result){ assert(err.message.includes(`Could not encode ${hash}`)); done(); }); diff --git a/test/eth.ens.js b/test/eth.ens.js index 13d5905e079..bf5482abead 100644 --- a/test/eth.ens.js +++ b/test/eth.ens.js @@ -2254,7 +2254,7 @@ describe('ens', function () { provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); try { - await web3.eth.ens.getContentHash('foobar.eth'); + await web3.eth.ens.getContenthash('foobar.eth'); assert.fail(); } catch (error) { @@ -2287,7 +2287,7 @@ describe('ens', function () { }); provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); - web3.eth.ens.getContentHash( + web3.eth.ens.getContenthash( 'foobar.eth', function (error, result) { assert(error.message.includes('does not implement requested method: "contenthash"')); @@ -2299,7 +2299,7 @@ describe('ens', function () { it('should error if resolver ABI does not support setContenthash (promise)', async function () { const resolverSignature = 'resolver(bytes32)'; - const contentSignature = 'setContentHash(bytes32)'; + const contentSignature = 'setContenthash(bytes32)'; const contenthashInterfaceId = 'bc1c58d1'; provider.injectValidation(function (payload) { @@ -2323,7 +2323,7 @@ describe('ens', function () { provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); try { - await web3.eth.ens.setContentHash( + await web3.eth.ens.setContenthash( 'foobar.eth', 'ipfs://QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn' ); @@ -2359,7 +2359,7 @@ describe('ens', function () { }); provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000000'); - web3.eth.ens.setContentHash( + web3.eth.ens.setContenthash( 'foobar.eth', 'ipfs://QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn', { From 5acf99774b1c2d258f0d61e79cc1a07be818e45e Mon Sep 17 00:00:00 2001 From: cgewecke Date: Mon, 6 Apr 2020 19:58:55 -0700 Subject: [PATCH 14/21] Add ENS license to decoding utils --- packages/web3-eth-ens/src/lib/contentHash.js | 30 ++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/packages/web3-eth-ens/src/lib/contentHash.js b/packages/web3-eth-ens/src/lib/contentHash.js index e861cbe29ba..bd0cbc8486d 100644 --- a/packages/web3-eth-ens/src/lib/contentHash.js +++ b/packages/web3-eth-ens/src/lib/contentHash.js @@ -1,6 +1,32 @@ /* - Adapted from ensdomains/ui - Permalink: https://github.com/ensdomains/ui/blob/3e62e440b53466eeec9dd1c63d73924eefbd88c1/src/utils/contents.js#L1-L85 +Adapted from ensdomains/ui +https://github.com/ensdomains/ui/blob/3e62e440b53466eeec9dd1c63d73924eefbd88c1/src/utils/contents.js#L1-L85 + +BSD 2-Clause License + +Copyright (c) 2019, Ethereum Name Service +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ var contentHash = require('content-hash'); From beed2cdfa8011bf4d6352627bd9d7075ff0f5003 Mon Sep 17 00:00:00 2001 From: cgewecke Date: Mon, 6 Apr 2020 20:22:23 -0700 Subject: [PATCH 15/21] Add E2E test for pubkey methods --- test/e2e.ens.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/e2e.ens.js b/test/e2e.ens.js index 2460588765f..13b3cc4145d 100644 --- a/test/e2e.ens.js +++ b/test/e2e.ens.js @@ -58,6 +58,17 @@ describe('ENS [ @E2E ]', function () { ); }); + it('should get/set a publickey', async function(){ + const x = "0x3078303030303030303030303030303030303030303030303030303030303030"; + const y = "0x3030303030303030303030303030303030303030303030303030303030303030"; + + await web3.eth.ens.setPubkey('resolver', x, y, options); + const coords = await web3.eth.ens.getPubkey('resolver'); + + assert.equal(coords.x, x); + assert.equal(coords.y, y); + }); + it('should error when calling "getContent" if resolver does not support it', async function () { try { await web3.eth.ens.getContent('resolver'); From fbd432ffbcdf1c47f35f31d16cc0627a82714075 Mon Sep 17 00:00:00 2001 From: cgewecke Date: Tue, 7 Apr 2020 10:25:51 -0700 Subject: [PATCH 16/21] Fix Registry.js diff --- packages/web3-eth-ens/src/contracts/Registry.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/web3-eth-ens/src/contracts/Registry.js b/packages/web3-eth-ens/src/contracts/Registry.js index c6040fd0b6b..6e375bdfae7 100644 --- a/packages/web3-eth-ens/src/contracts/Registry.js +++ b/packages/web3-eth-ens/src/contracts/Registry.js @@ -29,6 +29,7 @@ var utils = require('web3-utils'); var REGISTRY_ABI = require('../ressources/ABI/Registry'); var RESOLVER_ABI = require('../ressources/ABI/Resolver'); + /** * A wrapper around the ENS registry contract. * From cea4e0d4218906dc883c5e7b38e2505de55d3ca5 Mon Sep 17 00:00:00 2001 From: cgewecke Date: Tue, 7 Apr 2020 10:55:11 -0700 Subject: [PATCH 17/21] Update method signatures in docs --- docs/web3-eth-ens.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/web3-eth-ens.rst b/docs/web3-eth-ens.rst index 5222c99f77e..9ff6c459e0c 100644 --- a/docs/web3-eth-ens.rst +++ b/docs/web3-eth-ens.rst @@ -938,12 +938,12 @@ For further information on the handling of contract events please see :ref:`here ------------------------------------------------------------------------------ -getContentHash +getContenthash ===================== .. code-block:: javascript - web3.eth.ens.getContentHash(ENSName [, callback]); + web3.eth.ens.getContenthash(ENSName [, callback]); Returns the content hash object associated with an ENS node. @@ -966,7 +966,7 @@ Example .. code-block:: javascript - web3.eth.ens.getContentHash('ethereum.eth').then(function (result) { + web3.eth.ens.getContenthash('ethereum.eth').then(function (result) { console.log(result); }); > { @@ -976,12 +976,12 @@ Example ------------------------------------------------------------------------------ -setContentHash +setContenthash ===================== .. code-block:: javascript - web3.eth.ens.setContentHash(ENSName, hash [, txConfig ] [, callback]); + web3.eth.ens.setContenthash(ENSName, hash [, txConfig ] [, callback]); Sets the content hash associated with an ENS node. @@ -1016,7 +1016,7 @@ Example .. code-block:: javascript - web3.eth.ens.setContentHash( + web3.eth.ens.setContenthash( 'ethereum.eth', 'ipfs://QmaEBknbGT4bTQiQoe2VNgBJbRfygQGktnaW5TbuKixjYL', { @@ -1029,7 +1029,7 @@ Example // Or using the event emitter - web3.eth.ens.setContentHash( + web3.eth.ens.setContenthash( 'ethereum.eth', 'ipfs://QmaEBknbGT4bTQiQoe2VNgBJbRfygQGktnaW5TbuKixjYL', { From d4badc23f172b301937ee842effd12ca205fd6d3 Mon Sep 17 00:00:00 2001 From: cgewecke Date: Tue, 28 Apr 2020 18:23:19 -0700 Subject: [PATCH 18/21] Fix web3-eth-ens package-lock.json rebase break --- packages/web3-eth-ens/package-lock.json | 224 ++++++++++++------------ 1 file changed, 108 insertions(+), 116 deletions(-) diff --git a/packages/web3-eth-ens/package-lock.json b/packages/web3-eth-ens/package-lock.json index 3c15304255f..c9152aa8eb2 100644 --- a/packages/web3-eth-ens/package-lock.json +++ b/packages/web3-eth-ens/package-lock.json @@ -108,9 +108,9 @@ } }, "buffer": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.5.0.tgz", - "integrity": "sha512-9FTEDjLjwoAkEwyMGDjYJQN2gfRgOKBKRfiglhvibGbpeeU/pQn1bJxQqm32OD/AIeEuHxU9roxXxg34Byp/Ww==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" @@ -159,27 +159,10 @@ } } }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, "cids": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.4.tgz", - "integrity": "sha512-jbjoM2woxvURbO3O9qTmCEWYX5nHHN43tSgDAO707pyjtLw7M42ZAbGqp6hRJe+tpxhZ6+uORSa7ZrnRO7zNdA==", + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz", + "integrity": "sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==", "requires": { "buffer": "^5.5.0", "class-is": "^1.1.0", @@ -204,6 +187,23 @@ "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==" }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -220,9 +220,9 @@ "dev": true }, "command-exists": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.8.tgz", - "integrity": "sha512-PM54PkseWbiiD/mMsbvW351/u+dafwTJ0ye2qB60G1aGQP9j3xK2gmMDc+R34L3nDtx4qMCitXT75mkbkGJDLw==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", "dev": true }, "commander": { @@ -237,11 +237,6 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - }, "content-hash": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/content-hash/-/content-hash-2.5.2.tgz", @@ -252,10 +247,10 @@ "multihashes": "^0.4.15" } }, - "definitelytyped-header-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/definitelytyped-header-parser/-/definitelytyped-header-parser-1.2.0.tgz", - "integrity": "sha512-xpg8uu/2YD/reaVsZV4oJ4g7UDYFqQGWvT1W9Tsj6q4VtWBSaig38Qgah0ZMnQGF9kAsAim08EXDO1nSi0+Nog==", + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { "nice-try": "^1.0.4", @@ -279,6 +274,16 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, + "definitelytyped-header-parser": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/definitelytyped-header-parser/-/definitelytyped-header-parser-3.9.0.tgz", + "integrity": "sha512-slbwZ5h5lasB12t+9EAGYr060aCMqEXp6cwD7CoTriK40HNDYU56/XQ6S4sbjBK8ReGRMnB/uDx0elKkb4kuQA==", + "dev": true, + "requires": { + "@types/parsimmon": "^1.3.0", + "parsimmon": "^1.2.0" + } + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -286,34 +291,19 @@ "dev": true }, "dts-critic": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dts-critic/-/dts-critic-3.0.1.tgz", - "integrity": "sha512-3y34qsytqwEgfoUcYwxVm9Lv54Q+MPEXCOtZpwhl4TNM1SN/yjolWXz7Xw2U0BQv/rGhIdM2ONNTaAxRfQdJ6g==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/dts-critic/-/dts-critic-3.0.2.tgz", + "integrity": "sha512-wkRb9FOBXNwpB14nxHbevbyGm42KhA2YGtYsIrfDMvVWDaRMQVYodYtUbuNAH7WUPFMd0ywaqnmzGJl+E6yjsg==", "dev": true, "requires": { "command-exists": "^1.2.8", "definitelytyped-header-parser": "^3.8.2", + "rimraf": "^3.0.2", "semver": "^6.2.0", "typescript": "^3.7.5", "yargs": "^12.0.5" }, "dependencies": { - "definitelytyped-header-parser": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/definitelytyped-header-parser/-/definitelytyped-header-parser-3.9.0.tgz", - "integrity": "sha512-slbwZ5h5lasB12t+9EAGYr060aCMqEXp6cwD7CoTriK40HNDYU56/XQ6S4sbjBK8ReGRMnB/uDx0elKkb4kuQA==", - "dev": true, - "requires": { - "@types/parsimmon": "^1.3.0", - "parsimmon": "^1.2.0" - } - }, - "typescript": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", - "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", - "dev": true - }, "yargs": { "version": "12.0.5", "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", @@ -337,37 +327,19 @@ } }, "dtslint": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/dtslint/-/dtslint-3.4.1.tgz", - "integrity": "sha512-gIFYwlAO8vY17zGMqdJ7x2DA2swrQsKCwrtX0TUP4A36dlXjdFpj6NWMWc1HW5mYkWOkQFHwTWMOdkP6DLsrfA==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/dtslint/-/dtslint-3.4.2.tgz", + "integrity": "sha512-qvZN5jI849zG8cjirBzyetK2ZGRa3rO8ExhcirqDlkas251Wt8TlZFKvW8wDGQ++fHLA8omINNxWvPBCb8AXhA==", "dev": true, "requires": { "definitelytyped-header-parser": "3.9.0", - "dts-critic": "^3.0.0", + "dts-critic": "^3.0.2", "fs-extra": "^6.0.1", "json-stable-stringify": "^1.0.1", "strip-json-comments": "^2.0.1", "tslint": "5.14.0", - "typescript": "^3.9.0-dev.20200424", + "typescript": "^3.8.3", "yargs": "^15.1.0" - }, - "dependencies": { - "definitelytyped-header-parser": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/definitelytyped-header-parser/-/definitelytyped-header-parser-3.9.0.tgz", - "integrity": "sha512-slbwZ5h5lasB12t+9EAGYr060aCMqEXp6cwD7CoTriK40HNDYU56/XQ6S4sbjBK8ReGRMnB/uDx0elKkb4kuQA==", - "dev": true, - "requires": { - "@types/parsimmon": "^1.3.0", - "parsimmon": "^1.2.0" - } - }, - "typescript": { - "version": "3.9.0-dev.20200424", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.0-dev.20200424.tgz", - "integrity": "sha512-dlfK6Mtv78aQhWs8Umtq+twEP051mnXStu+TwOYlvkqMF/hdG626I5PMonLx11gLL2NmOftLTjM/ebAiAZqx7g==", - "dev": true - } } }, "emoji-regex": { @@ -483,9 +455,9 @@ } }, "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", "dev": true }, "has-ansi": { @@ -678,27 +650,6 @@ "minimist": "^1.2.5" } }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - } "multibase": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz", @@ -717,15 +668,47 @@ } }, "multihashes": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.17.tgz", - "integrity": "sha512-5K5brXK5myhEHgfB8B+Hf470KRdcZcUJ0QSZWyMkwXe2kw7Dh8Fb5tepplEkXAhBcTbEIOe2I9cmIZ4/E1lhfw==", + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.19.tgz", + "integrity": "sha512-ej74GAfA20imjj00RO5h34aY3pGUFyzn9FJZFWwdeUHlHTkKmv90FrNpvYT4jYf1XXCy5O/5EjVnxTaESgOM6A==", "requires": { "buffer": "^5.5.0", - "multibase": "^0.6.0", + "multibase": "^0.7.0", "varint": "^5.0.0" + }, + "dependencies": { + "multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + } } }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -846,14 +829,23 @@ "dev": true }, "resolve": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", - "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", "dev": true, "requires": { "path-parse": "^1.0.6" } }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, "safe-buffer": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", @@ -996,6 +988,11 @@ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, + "varint": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz", + "integrity": "sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8=" + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -1058,11 +1055,6 @@ } } }, - "varint": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz", - "integrity": "sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8=" - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -1220,9 +1212,9 @@ } }, "yargs-parser": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.2.tgz", - "integrity": "sha512-hlIPNR3IzC1YuL1c2UwwDKpXlNFBqD1Fswwh1khz5+d8Cq/8yc/Mn0i+rQXduu8hcrFKvO7Eryk+09NecTQAAQ==", + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, "requires": { "camelcase": "^5.0.0", From f037c317a40ad08a82341a459bdd3243fe88f4eb Mon Sep 17 00:00:00 2001 From: cgewecke Date: Tue, 28 Apr 2020 18:30:29 -0700 Subject: [PATCH 19/21] Remove extraneous mocha timeout in test/eth.ens.js --- test/eth.ens.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/eth.ens.js b/test/eth.ens.js index bf5482abead..fb79d62c7a1 100644 --- a/test/eth.ens.js +++ b/test/eth.ens.js @@ -103,8 +103,6 @@ function isExpectedReceipt(receipt) { } describe('ens', function () { - this.timeout(5000); - let provider; let web3; const hashedName = namehash.hash('foobar.eth'); From a6e19cbf0cc5014cabd7348b8d61a8aa38c07f50 Mon Sep 17 00:00:00 2001 From: cgewecke Date: Tue, 28 Apr 2020 18:49:34 -0700 Subject: [PATCH 20/21] Move interfaceIds to config --- packages/web3-eth-ens/src/config.js | 12 ++++++++++++ .../web3-eth-ens/src/lib/ResolverMethodHandler.js | 14 +------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/web3-eth-ens/src/config.js b/packages/web3-eth-ens/src/config.js index b4075241114..b12e5f5b717 100644 --- a/packages/web3-eth-ens/src/config.js +++ b/packages/web3-eth-ens/src/config.js @@ -32,6 +32,18 @@ var config = { rinkeby: "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", goerli: "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e" }, + // These ids obtained at ensdomains docs: + // https://docs.ens.domains/contract-developer-guide/writing-a-resolver + interfaceIds: { + addr: "0x3b3b57de", + setAddr: "0x3b3b57de", + pubkey: "0xc8690233", + setPubkey: "0xc8690233", + contenthash: "0xbc1c58d1", + setContenthash: "0xbc1c58d1", + content: "0xd8389dc5", + setContent: "0xd8389dc5" + } }; module.exports = config; diff --git a/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js b/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js index be702ae9a0a..247b3215f85 100644 --- a/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js +++ b/packages/web3-eth-ens/src/lib/ResolverMethodHandler.js @@ -24,19 +24,7 @@ var PromiEvent = require('web3-core-promievent'); var namehash = require('eth-ens-namehash'); var errors = require('web3-core-helpers').errors; var _ = require('underscore'); - -// These ids obtained at ensdomains docs: -// https://docs.ens.domains/contract-developer-guide/writing-a-resolver -var interfaceIds = { - addr: "0x3b3b57de", - setAddr: "0x3b3b57de", - pubkey: "0xc8690233", - setPubkey: "0xc8690233", - contenthash: "0xbc1c58d1", - setContenthash: "0xbc1c58d1", - content: "0xd8389dc5", - setContent: "0xd8389dc5" -}; +var interfaceIds = require('../config').interfaceIds; /** * @param {Registry} registry From efd5cbfdf56ad59f8518b127daf1f48194e02d0a Mon Sep 17 00:00:00 2001 From: cgewecke Date: Tue, 28 Apr 2020 19:05:41 -0700 Subject: [PATCH 21/21] Minimize changes to Resolver ABI --- .../src/ressources/ABI/Resolver.js | 464 +++++------------- 1 file changed, 113 insertions(+), 351 deletions(-) diff --git a/packages/web3-eth-ens/src/ressources/ABI/Resolver.js b/packages/web3-eth-ens/src/ressources/ABI/Resolver.js index 2976f3943b3..1d897391299 100644 --- a/packages/web3-eth-ens/src/ressources/ABI/Resolver.js +++ b/packages/web3-eth-ens/src/ressources/ABI/Resolver.js @@ -1,158 +1,67 @@ "use strict"; -// This ABI taken from @ensdomains/resolver@0.2.4 -// @ensdomains/resolver/build/contracts/Resolver.json var RESOLVER = [ { - "anonymous": false, + "constant": true, "inputs": [ { - "indexed": true, - "name": "node", - "type": "bytes32" - }, - { - "indexed": false, - "name": "a", - "type": "address" + "name": "interfaceID", + "type": "bytes4" } ], - "name": "AddrChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "node", - "type": "bytes32" - }, - { - "indexed": false, - "name": "coinType", - "type": "uint256" - }, + "name": "supportsInterface", + "outputs": [ { - "indexed": false, - "name": "newAddress", - "type": "bytes" + "name": "", + "type": "bool" } ], - "name": "AddressChanged", - "type": "event" + "payable": false, + "type": "function" }, { - "anonymous": false, + "constant": true, "inputs": [ { - "indexed": true, "name": "node", "type": "bytes32" }, { - "indexed": false, - "name": "name", - "type": "string" + "name": "contentTypes", + "type": "uint256" } ], - "name": "NameChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "node", - "type": "bytes32" - }, + "name": "ABI", + "outputs": [ { - "indexed": true, "name": "contentType", "type": "uint256" - } - ], - "name": "ABIChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "node", - "type": "bytes32" - }, - { - "indexed": false, - "name": "x", - "type": "bytes32" - }, - { - "indexed": false, - "name": "y", - "type": "bytes32" - } - ], - "name": "PubkeyChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "node", - "type": "bytes32" - }, - { - "indexed": true, - "name": "indexedKey", - "type": "string" - }, - { - "indexed": false, - "name": "key", - "type": "string" - } - ], - "name": "TextChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "node", - "type": "bytes32" }, { - "indexed": false, - "name": "hash", + "name": "data", "type": "bytes" } ], - "name": "ContenthashChanged", - "type": "event" + "payable": false, + "type": "function" }, { - "anonymous": false, + "constant": false, "inputs": [ { - "indexed": true, "name": "node", "type": "bytes32" }, { - "indexed": false, "name": "hash", - "type": "bytes32" + "type": "bytes" } ], - "name": "ContentChanged", - "type": "event" + "name": "setMultihash", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" }, { "constant": true, @@ -160,18 +69,10 @@ var RESOLVER = [ { "name": "node", "type": "bytes32" - }, - { - "name": "contentTypes", - "type": "uint256" } ], - "name": "ABI", + "name": "multihash", "outputs": [ - { - "name": "", - "type": "uint256" - }, { "name": "", "type": "bytes" @@ -182,26 +83,24 @@ var RESOLVER = [ "type": "function" }, { - "constant": true, + "constant": false, "inputs": [ { "name": "node", "type": "bytes32" }, { - "name": "coinType", - "type": "uint256" - } - ], - "name": "addr", - "outputs": [ + "name": "x", + "type": "bytes32" + }, { - "name": "", - "type": "bytes" + "name": "y", + "type": "bytes32" } ], + "name": "setPubkey", + "outputs": [], "payable": false, - "stateMutability": "view", "type": "function" }, { @@ -212,15 +111,14 @@ var RESOLVER = [ "type": "bytes32" } ], - "name": "addr", + "name": "content", "outputs": [ { - "name": "", - "type": "address" + "name": "ret", + "type": "bytes32" } ], "payable": false, - "stateMutability": "view", "type": "function" }, { @@ -231,34 +129,35 @@ var RESOLVER = [ "type": "bytes32" } ], - "name": "contenthash", + "name": "addr", "outputs": [ { - "name": "", - "type": "bytes" + "name": "ret", + "type": "address" } ], "payable": false, - "stateMutability": "view", "type": "function" }, { - "constant": true, + "constant": false, "inputs": [ { "name": "node", "type": "bytes32" - } - ], - "name": "dnsrr", - "outputs": [ + }, { - "name": "", + "name": "contentType", + "type": "uint256" + }, + { + "name": "data", "type": "bytes" } ], + "name": "setABI", + "outputs": [], "payable": false, - "stateMutability": "view", "type": "function" }, { @@ -272,58 +171,45 @@ var RESOLVER = [ "name": "name", "outputs": [ { - "name": "", + "name": "ret", "type": "string" } ], "payable": false, - "stateMutability": "view", "type": "function" }, { - "constant": true, + "constant": false, "inputs": [ { "name": "node", "type": "bytes32" - } - ], - "name": "pubkey", - "outputs": [ - { - "name": "x", - "type": "bytes32" }, { - "name": "y", - "type": "bytes32" + "name": "name", + "type": "string" } ], + "name": "setName", + "outputs": [], "payable": false, - "stateMutability": "view", "type": "function" }, { - "constant": true, + "constant": false, "inputs": [ { "name": "node", "type": "bytes32" }, { - "name": "key", - "type": "string" - } - ], - "name": "text", - "outputs": [ - { - "name": "", - "type": "string" + "name": "hash", + "type": "bytes32" } ], + "name": "setContent", + "outputs": [], "payable": false, - "stateMutability": "view", "type": "function" }, { @@ -332,43 +218,20 @@ var RESOLVER = [ { "name": "node", "type": "bytes32" - }, - { - "name": "interfaceID", - "type": "bytes4" } ], - "name": "interfaceImplementer", + "name": "pubkey", "outputs": [ { - "name": "", - "type": "address" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "node", + "name": "x", "type": "bytes32" }, { - "name": "contentType", - "type": "uint256" - }, - { - "name": "data", - "type": "bytes" + "name": "y", + "type": "bytes32" } ], - "name": "setABI", - "outputs": [], "payable": false, - "stateMutability": "nonpayable", "type": "function" }, { @@ -386,207 +249,124 @@ var RESOLVER = [ "name": "setAddr", "outputs": [], "payable": false, - "stateMutability": "nonpayable", "type": "function" }, { - "constant": false, "inputs": [ { - "name": "node", - "type": "bytes32" - }, - { - "name": "coinType", - "type": "uint256" - }, - { - "name": "a", - "type": "bytes" + "name": "ensAddr", + "type": "address" } ], - "name": "setAddr", - "outputs": [], "payable": false, - "stateMutability": "nonpayable", - "type": "function" + "type": "constructor" }, { - "constant": false, + "anonymous": false, "inputs": [ { + "indexed": true, "name": "node", "type": "bytes32" }, { - "name": "hash", - "type": "bytes" + "indexed": false, + "name": "a", + "type": "address" } ], - "name": "setContenthash", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" + "name": "AddrChanged", + "type": "event" }, { - "constant": false, + "anonymous": false, "inputs": [ { + "indexed": true, "name": "node", "type": "bytes32" }, { - "name": "data", - "type": "bytes" + "indexed": false, + "name": "hash", + "type": "bytes32" } ], - "name": "setDnsrr", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" + "name": "ContentChanged", + "type": "event" }, { - "constant": false, + "anonymous": false, "inputs": [ { + "indexed": true, "name": "node", "type": "bytes32" }, { - "name": "_name", + "indexed": false, + "name": "name", "type": "string" } ], - "name": "setName", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" + "name": "NameChanged", + "type": "event" }, { - "constant": false, + "anonymous": false, "inputs": [ { + "indexed": true, "name": "node", "type": "bytes32" }, { - "name": "x", - "type": "bytes32" - }, - { - "name": "y", - "type": "bytes32" + "indexed": true, + "name": "contentType", + "type": "uint256" } ], - "name": "setPubkey", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" + "name": "ABIChanged", + "type": "event" }, { - "constant": false, + "anonymous": false, "inputs": [ { + "indexed": true, "name": "node", "type": "bytes32" }, { - "name": "key", - "type": "string" - }, - { - "name": "value", - "type": "string" - } - ], - "name": "setText", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "node", + "indexed": false, + "name": "x", "type": "bytes32" }, { - "name": "interfaceID", - "type": "bytes4" - }, - { - "name": "implementer", - "type": "address" - } - ], - "name": "setInterface", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "interfaceID", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "pure", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "name": "results", - "type": "bytes[]" + "indexed": false, + "name": "y", + "type": "bytes32" } ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" + "name": "PubkeyChanged", + "type": "event" }, { - "constant": true, + "anonymous": false, "inputs": [ { + "indexed": true, "name": "node", "type": "bytes32" - } - ], - "name": "content", - "outputs": [ + }, { - "name": "", - "type": "bytes32" + "indexed": false, + "name": "hash", + "type": "bytes" } ], - "payable": false, - "stateMutability": "view", - "type": "function" + "name": "ContenthashChanged", + "type": "event" }, { "constant": true, @@ -596,7 +376,7 @@ var RESOLVER = [ "type": "bytes32" } ], - "name": "multihash", + "name": "contenthash", "outputs": [ { "name": "", @@ -607,24 +387,6 @@ var RESOLVER = [ "stateMutability": "view", "type": "function" }, - { - "constant": false, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "hash", - "type": "bytes32" - } - ], - "name": "setContent", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, { "constant": false, "inputs": [ @@ -637,7 +399,7 @@ var RESOLVER = [ "type": "bytes" } ], - "name": "setMultihash", + "name": "setContenthash", "outputs": [], "payable": false, "stateMutability": "nonpayable", @@ -645,4 +407,4 @@ var RESOLVER = [ } ]; -module.exports = RESOLVER; +module.exports = RESOLVER; \ No newline at end of file