diff --git a/lib/modules/ens/ENSFunctions.js b/lib/modules/ens/ENSFunctions.js index bde805d7..e13f8f62 100644 --- a/lib/modules/ens/ENSFunctions.js +++ b/lib/modules/ens/ENSFunctions.js @@ -1,47 +1,49 @@ +/*global web3*/ const namehash = require('eth-ens-namehash'); +// Price of ENS registration contract functions +const ENS_GAS_PRICE = 700000; -const reverseAddrSuffix = '.addr.reverse'; -const voidAddress = '0x0000000000000000000000000000000000000000'; -const NoDecodeAddrError = 'Error: Couldn\'t decode address from ABI: 0x'; -const NoDecodeStringError = 'ERROR: The returned value is not a convertible string: 0x0'; +const reverseAddressSuffix = '.addr.reverse'; +const voidAddr = '0x0000000000000000000000000000000000000000'; +const NoDecodeAddrErr = 'Error: Couldn\'t decode address from ABI: 0x'; +const NoDecodeStringErr = 'ERROR: The returned value is not a convertible string: 0x0'; -function registerSubDomain(ens, registrar, resolver, defaultAccount, subdomain, rootDomain, reverseNode, address, logger, callback) { +function registerSubDomain(ens, registrar, resolver, defaultAccount, subdomain, rootDomain, reverseNode, address, logger, secureSend, callback) { const subnode = namehash.hash(subdomain); + const rootNode = namehash.hash(rootDomain); const node = namehash.hash(`${subdomain}.${rootDomain}`); - const toSend = registrar.methods.register(subnode, defaultAccount); + // FIXME Registrar calls a function in ENS and in privatenet it doesn't work for soem reason + // const toSend = registrar.methods.register(subnode, defaultAccount); + const toSend = ens.methods.setSubnodeOwner(rootNode, subnode, defaultAccount); let transaction; - toSend.estimateGas() - // Register domain - .then(gasEstimated => { - return toSend.send({gas: gasEstimated + 1000, from: defaultAccount}); - }) - // Set resolver for the node + secureSend(web3, toSend, {from: defaultAccount, gas: ENS_GAS_PRICE}, false) + // Set resolver for the node .then(transac => { if (transac.status !== "0x1" && transac.status !== "0x01" && transac.status !== true) { logger.warn('Failed transaction', transac); return callback('Failed to register. Check gas cost.'); } transaction = transac; - return ens.methods.setResolver(node, resolver.options.address).send({from: defaultAccount}); + return secureSend(web3, ens.methods.setResolver(node, resolver.options.address), {from: defaultAccount, gas: ENS_GAS_PRICE}, false); }) // Set address for node .then(_result => { - return resolver.methods.setAddr(node, address).send({from: defaultAccount}); + return secureSend(web3, resolver.methods.setAddr(node, address), {from: defaultAccount, gas: ENS_GAS_PRICE}, false); }) // Set resolver for the reverse node .then(_result => { - return ens.methods.setResolver(reverseNode, resolver.options.address).send({from: defaultAccount}); + return secureSend(web3, ens.methods.setResolver(reverseNode, resolver.options.address), {from: defaultAccount, gas: ENS_GAS_PRICE}, false); }) // Set name for reverse node .then(_result => { - return resolver.methods.setName(reverseNode, subdomain + '.embark.eth').send({from: defaultAccount}); + return secureSend(web3, resolver.methods.setName(reverseNode, `${subdomain}.${rootDomain}`), {from: defaultAccount, gas: ENS_GAS_PRICE}, false); }) .then(_result => { callback(null, transaction); }) .catch(err => { - logger.error(err); + logger.error(err.message || err); callback('Failed to register with error: ' + (err.message || err)); }); } @@ -51,10 +53,10 @@ function lookupAddress(address, ens, utils, createResolverContract, callback) { address = address.slice(2); } - let node = utils.soliditySha3(address.toLowerCase() + reverseAddrSuffix); + let node = utils.soliditySha3(address.toLowerCase() + reverseAddressSuffix); function cb(err, name) { - if (err === NoDecodeStringError || err === NoDecodeAddrError) { + if (err === NoDecodeStringErr || err === NoDecodeAddrErr) { return callback('Address does not resolve to name. Try syncing chain.'); } return callback(err, name); @@ -64,7 +66,7 @@ function lookupAddress(address, ens, utils, createResolverContract, callback) { if (err) { return cb(err); } - if (resolverAddress === voidAddress) { + if (resolverAddress === voidAddr) { return cb('Address not associated to a resolver'); } createResolverContract(resolverAddress, (_, resolverContract) => { @@ -78,7 +80,7 @@ function resolveName(name, ens, createResolverContract, callback) { let node = namehash.hash(name); function cb(err, addr) { - if (err === NoDecodeAddrError) { + if (err === NoDecodeAddrErr) { return callback(name + " is not registered", "0x"); } callback(err, addr); @@ -88,7 +90,7 @@ function resolveName(name, ens, createResolverContract, callback) { if (err) { return cb(err); } - if (resolverAddress === voidAddress) { + if (resolverAddress === voidAddr) { return cb('Name not yet registered'); } createResolverContract(resolverAddress, (_, resolverContract) => { diff --git a/lib/modules/ens/index.js b/lib/modules/ens/index.js index 040d0f83..2112b710 100644 --- a/lib/modules/ens/index.js +++ b/lib/modules/ens/index.js @@ -4,6 +4,7 @@ const namehash = require('eth-ens-namehash'); const async = require('async'); const embarkJsUtils = require('embarkjs').Utils; const reverseAddrSuffix = '.addr.reverse'; +const ENSFunctions = require('./ENSFunctions'); const MAINNET_ID = '1'; const ROPSTEN_ID = '3'; @@ -212,19 +213,88 @@ class ENS { registerConfigDomains(config, cb) { const self = this; - const register = require('./register'); const secureSend = embarkJsUtils.secureSend; self.events.request("blockchain:defaultAccount:get", (defaultAccount) => { async.each(Object.keys(self.registration.subdomains), (subDomainName, eachCb) => { const address = self.registration.subdomains[subDomainName]; const reverseNode = utils.soliditySha3(address.toLowerCase().substr(2) + reverseAddrSuffix); - register(self.ensContract, self.registrarContract, self.resolverContract, defaultAccount, subDomainName, self.registration.rootDomain, - reverseNode, address, self.logger, secureSend, eachCb); + ENSFunctions.registerSubDomain(self.ensContract, self.registrarContract, self.resolverContract, defaultAccount, + subDomainName, self.registration.rootDomain, reverseNode, address, self.logger, secureSend, eachCb); }, cb); }); } + createResolverContract(config, callback) { + this.events.request("blockchain:contract:create", { + abi: config.resolverAbi, + address: config.resolverAddress + }, (resolver) => { + callback(null, resolver); + }); + } + + registerAPI() { + let self = this; + + const createInternalResolverContract = function(resolverAddress, callback) { + self.createResolverContract({resolverAbi: self.ensConfig.Resolver.abiDefinition, resolverAddress}, callback); + }; + + self.embark.registerAPICall( + 'get', + '/embark-api/ens/resolve', + (req, res) => { + async.waterfall([ + function(callback) { + ENSFunctions.resolveName(req.query.name, self.ensContract, createInternalResolverContract.bind(self), callback); + } + ], function(error, address) { + if (error) { + return res.send({error: error.message}); + } + res.send({address}); + }); + } + ); + + self.embark.registerAPICall( + 'get', + '/embark-api/ens/lookup', + (req, res) => { + async.waterfall([ + function(callback) { + ENSFunctions.lookupAddress(req.query.address, self.ensContract, utils, createInternalResolverContract.bind(self), callback); + } + ], function(error, name) { + if (error) { + return res.send({error: error || error.message}); + } + res.send({name}); + }); + } + ); + + self.embark.registerAPICall( + 'post', + '/embark-api/ens/register', + (req, res) => { + self.events.request("blockchain:defaultAccount:get", (defaultAccount) => { + const secureSend = embarkJsUtils.secureSend; + const {subdomain, address} = req.body; + const reverseNode = utils.soliditySha3(address.toLowerCase().substr(2) + reverseAddrSuffix); + ENSFunctions.registerSubDomain(self.ensContract, self.registrarContract, self.resolverContract, defaultAccount, + subdomain, self.registration.rootDomain, reverseNode, address, self.logger, secureSend, (error) => { + if (error) { + return res.send({error: error || error.message}); + } + res.send({name: `${req.body.subdomain}.${self.registration.rootDomain}`, address: req.body.address}); + }); + }); + } + ); + } + addENSToEmbarkJS() { const self = this; @@ -238,7 +308,7 @@ class ENS { } }); - let code = fs.readFileSync(utils.joinPath(__dirname, 'register.js')).toString(); + let code = fs.readFileSync(utils.joinPath(__dirname, 'ENSFunctions.js')).toString(); code += "\n" + fs.readFileSync(utils.joinPath(__dirname, 'embarkjs.js')).toString(); code += "\nEmbarkJS.Names.registerProvider('ens', __embarkENS);"; @@ -353,6 +423,7 @@ class ENS { self.logger.error(err.message || err); return cb(err); } + self.registerAPI(); self.setProviderAndRegisterDomains(cb); }); });