diff --git a/js/embark.js b/js/embark.js index cff85842a..cf2fae889 100644 --- a/js/embark.js +++ b/js/embark.js @@ -376,12 +376,14 @@ EmbarkJS.Names.lookup = function (identifier) { // To Implement -/* + // register a name EmbarkJS.Names.register = function(name, options) { - + if (!this.currentNameSystems) { + throw new Error('Name system provider not set; e.g EmbarkJS.Names.setProvider("ens")'); + } + return this.currentNameSystems.register(name, options); } -*/ EmbarkJS.Utils = { fromAscii: function (str) { diff --git a/lib/modules/ens/contracts/ENS.sol b/lib/modules/ens/contracts/ENS.sol new file mode 100644 index 000000000..61e0edac3 --- /dev/null +++ b/lib/modules/ens/contracts/ENS.sol @@ -0,0 +1,26 @@ +pragma solidity ^0.4.18; + +interface ENS { + + // Logged when the owner of a node assigns a new owner to a subnode. + event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); + + // Logged when the owner of a node transfers ownership to a new account. + event Transfer(bytes32 indexed node, address owner); + + // Logged when the resolver for a node changes. + event NewResolver(bytes32 indexed node, address resolver); + + // Logged when the TTL of a node changes + event NewTTL(bytes32 indexed node, uint64 ttl); + + + function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public; + function setResolver(bytes32 node, address resolver) public; + function setOwner(bytes32 node, address owner) public; + function setTTL(bytes32 node, uint64 ttl) public; + function owner(bytes32 node) public view returns (address); + function resolver(bytes32 node) public view returns (address); + function ttl(bytes32 node) public view returns (uint64); + +} diff --git a/lib/modules/ens/contracts/ENSRegistry.sol b/lib/modules/ens/contracts/ENSRegistry.sol new file mode 100644 index 000000000..251c11006 --- /dev/null +++ b/lib/modules/ens/contracts/ENSRegistry.sol @@ -0,0 +1,99 @@ +pragma solidity ^0.4.18; + +import './ENS.sol'; + +/** + * The ENS registry contract. + */ +contract ENSRegistry is ENS { + struct Record { + address owner; + address resolver; + uint64 ttl; + } + + mapping (bytes32 => Record) records; + + // Permits modifications only by the owner of the specified node. + modifier only_owner(bytes32 node) { + require(records[node].owner == msg.sender); + _; + } + + /** + * @dev Constructs a new ENS registrar. + */ + function ENSRegistry() public { + records[0x0].owner = msg.sender; + } + + /** + * @dev Transfers ownership of a node to a new address. May only be called by the current owner of the node. + * @param node The node to transfer ownership of. + * @param owner The address of the new owner. + */ + function setOwner(bytes32 node, address owner) public only_owner(node) { + Transfer(node, owner); + records[node].owner = owner; + } + + /** + * @dev Transfers ownership of a subnode keccak256(node, label) to a new address. May only be called by the owner of the parent node. + * @param node The parent node. + * @param label The hash of the label specifying the subnode. + * @param owner The address of the new owner. + */ + function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public only_owner(node) { + var subnode = keccak256(node, label); + NewOwner(node, label, owner); + records[subnode].owner = owner; + } + + /** + * @dev Sets the resolver address for the specified node. + * @param node The node to update. + * @param resolver The address of the resolver. + */ + function setResolver(bytes32 node, address resolver) public only_owner(node) { + NewResolver(node, resolver); + records[node].resolver = resolver; + } + + /** + * @dev Sets the TTL for the specified node. + * @param node The node to update. + * @param ttl The TTL in seconds. + */ + function setTTL(bytes32 node, uint64 ttl) public only_owner(node) { + NewTTL(node, ttl); + records[node].ttl = ttl; + } + + /** + * @dev Returns the address that owns the specified node. + * @param node The specified node. + * @return address of the owner. + */ + function owner(bytes32 node) public view returns (address) { + return records[node].owner; + } + + /** + * @dev Returns the address of the resolver for the specified node. + * @param node The specified node. + * @return address of the resolver. + */ + function resolver(bytes32 node) public view returns (address) { + return records[node].resolver; + } + + /** + * @dev Returns the TTL of a node, and any records associated with it. + * @param node The specified node. + * @return ttl of the node. + */ + function ttl(bytes32 node) public view returns (uint64) { + return records[node].ttl; + } + +} diff --git a/lib/modules/ens/embarkjs.js b/lib/modules/ens/embarkjs.js index 1f37856cf..09286a1ae 100644 --- a/lib/modules/ens/embarkjs.js +++ b/lib/modules/ens/embarkjs.js @@ -3,96 +3,7 @@ import namehash from 'eth-ens-namehash'; /*global web3*/ let __embarkENS = {}; -// registry interface for later -__embarkENS.registryInterface = [ - { - "constant": true, - "inputs": [ - { - "name": "node", - "type": "bytes32" - } - ], - "name": "resolver", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "node", - "type": "bytes32" - } - ], - "name": "owner", - "outputs": [ - { - "name": "", - "type": "address" - } - ], - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "resolver", - "type": "address" - } - ], - "name": "setResolver", - "outputs": [], - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "label", - "type": "bytes32" - }, - { - "name": "owner", - "type": "address" - } - ], - "name": "setSubnodeOwner", - "outputs": [], - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "node", - "type": "bytes32" - }, - { - "name": "owner", - "type": "address" - } - ], - "name": "setOwner", - "outputs": [], - "type": "function" - } -]; - +// resolver interface __embarkENS.resolverInterface = [ { "constant": true, @@ -242,35 +153,11 @@ __embarkENS.resolverInterface = [ } ]; -__embarkENS.registryAddresses = { - // Mainnet - "1": "0x314159265dd8dbb310642f98f50c066173c1259b", - // Ropsten - "3": "0x112234455c3a32fd11230c42e7bccd4a84e02010", - // Rinkeby - "4": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A" +__embarkENS.setProvider = function (config) { + this.ens = new web3.eth.Contract(config.abi, config.address); }; -__embarkENS.setProvider = function () { - const self = this; - // get network id and then assign ENS contract based on that - let registryAddresses = this.registryAddresses; - this.ens = null; - web3.eth.net.getId().then(id => { - if (registryAddresses[id] !== undefined) { - self.ens = new web3.eth.Contract(self.registryInterface, registryAddresses[id]); - } - // todo: deploy at this point - }).catch(e => { - if (e.message.indexOf('Provider not set or invalid') > -1) { - console.warn('ENS is not available in this chain'); - return; - } - console.error(e); - }); -}; - -__embarkENS.resolve = function(name) { +__embarkENS.resolve = function (name) { const self = this; if (self.ens === undefined) return; @@ -285,11 +172,13 @@ __embarkENS.resolve = function(name) { }).catch(err => err); }; -__embarkENS.lookup = function(address) { +__embarkENS.lookup = function (address) { const self = this; - if (self.ens === undefined) return; - + if (!self.ens) { + console.log("ENS provider not set. Exiting."); + return; + } if (address.startsWith("0x")) address = address.slice(2); let node = namehash.hash(address.toLowerCase() + ".addr.reverse"); @@ -297,8 +186,5 @@ __embarkENS.lookup = function(address) { return self.ens.methods.resolver(node).call().then((resolverAddress) => { let resolverContract = new web3.eth.Contract(self.resolverInterface, resolverAddress); return resolverContract.methods.name(node).call(); - }).then((name) => { - if (name === "" || name === undefined) throw Error("ENS name not found"); - return name; }).catch(err => err); }; diff --git a/lib/modules/ens/index.js b/lib/modules/ens/index.js index 0b0c66569..585c34bb1 100644 --- a/lib/modules/ens/index.js +++ b/lib/modules/ens/index.js @@ -3,13 +3,26 @@ const utils = require('../../utils/utils.js'); class ENS { constructor(embark, _options) { + const self = this; this.logger = embark.logger; this.events = embark.events; this.namesConfig = embark.config.namesystemConfig; this.embark = embark; + this.ensRegistry = null; + this.ensResolver = null; this.addENSToEmbarkJS(); - this.addSetProvider(); + this.configureENSRegistry(); + self.embark.registerActionForEvent("contracts:deploy:afterAll", (cb) => { + self.events.request('contracts:contract', "ENSRegistry", (contract) => { + let config = { + abi: contract.abiDefinition, + address: contract.deployedAddress + }; + self.addSetProvider(config); + cb(); + }); + }); } addENSToEmbarkJS() { @@ -23,6 +36,7 @@ class ENS { return; } + // get namehash, import it into file self.events.request("version:get:eth-ens-namehash", function(EnsNamehashVersion) { let currentEnsNamehashVersion = require('../../../package.json').dependencies["eth-ens-namehash"]; if (EnsNamehashVersion !== currentEnsNamehashVersion) { @@ -39,10 +53,41 @@ class ENS { this.embark.addCodeToEmbarkJS(code); } - addSetProvider() { - let config = JSON.stringify({}); + configureENSRegistry() { + const self = this; + self.embark.registerContractConfiguration({ + "default": { + "gas": "auto", + "ENSRegistry": { + "deploy": true, + "args": [] + } + }, + "ropsten": { + "ENSRegistry": { + "address": "0x112234455c3a32fd11230c42e7bccd4a84e02010", + "args": [] + } + }, + "rinkeby": { + "ENSRegistry": { + "address": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A", + "args": [] + } + }, + "livenet": { + "ENSRegistry": { + "address": "0x314159265dd8dbb310642f98f50c066173c1259b", + "args": [] + } + } + }); + self.embark.events.request("config:contractsFiles:add", self.embark.pathToFile('./contracts/ENSRegistry.sol')); + } - let code = "\nEmbarkJS.Names.setProvider('ens'," + config + ");"; + addSetProvider(config) { + + let code = "\nEmbarkJS.Names.setProvider('ens'," + JSON.stringify(config) + ");"; let shouldInit = (namesConfig) => { return (namesConfig.provider === 'ens' && namesConfig.enabled === true);