diff --git a/js/embark.js b/js/embark.js index 78339a41..74ff3ec9 100644 --- a/js/embark.js +++ b/js/embark.js @@ -393,19 +393,23 @@ EmbarkJS.Names.setProvider = function (provider, options) { }; // resolve resolves a name into an identifier of some kind -EmbarkJS.Names.resolve = function (name) { +EmbarkJS.Names.resolve = function (name, callback) { if (!this.currentNameSystems) { throw new Error('Name system provider not set; e.g EmbarkJS.Names.setProvider("ens")'); } - return this.currentNameSystems.resolve(name); + return this.currentNameSystems.resolve(name, callback); }; // the reverse of resolve, resolves using an identifier to get to a name -EmbarkJS.Names.lookup = function (identifier) { +EmbarkJS.Names.lookup = function (identifier, callback) { if (!this.currentNameSystems) { throw new Error('Name system provider not set; e.g EmbarkJS.Names.setProvider("ens")'); } - return this.currentNameSystems.lookup(identifier); + return this.currentNameSystems.lookup(identifier, callback); +}; + +EmbarkJS.Names.isAvailable = function () { + return this.currentNameSystems.isAvailable(); }; // To Implement @@ -417,7 +421,7 @@ EmbarkJS.Names.register = function(name, options) { 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/cmds/blockchain/geth_commands.js b/lib/cmds/blockchain/geth_commands.js index fa4c12d6..e93c47a2 100644 --- a/lib/cmds/blockchain/geth_commands.js +++ b/lib/cmds/blockchain/geth_commands.js @@ -21,7 +21,7 @@ class GethCommands { } if (config.syncmode || config.syncMode) { - cmd.push("--syncmode=" + config.syncmode || config.syncMode); + cmd.push("--syncmode=" + (config.syncmode || config.syncMode)); } if (config.account && config.account.password) { diff --git a/lib/modules/ens/embarkjs.js b/lib/modules/ens/embarkjs.js index 6979f865..0a987de6 100644 --- a/lib/modules/ens/embarkjs.js +++ b/lib/modules/ens/embarkjs.js @@ -1,6 +1,7 @@ +/*global EmbarkJS, web3*/ + import namehash from 'eth-ens-namehash'; -/*global EmbarkJS*/ let __embarkENS = {}; // resolver interface @@ -153,56 +154,90 @@ __embarkENS.resolverInterface = [ } ]; +const providerNotSetError = 'ENS provider not set'; const NoDecodeAddrError = 'Error: Couldn\'t decode address from ABI: 0x'; const NoDecodeStringError = 'ERROR: The returned value is not a convertible string: 0x0'; +__embarkENS.registryAddresses = { + // Mainnet + "1": "0x314159265dd8dbb310642f98f50c066173c1259b", + // Ropsten + "3": "0x112234455c3a32fd11230c42e7bccd4a84e02010", + // Rinkeby + "4": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A" +}; + __embarkENS.setProvider = function (config) { const self = this; + const ERROR_MESSAGE = 'ENS is not available in this chain'; EmbarkJS.onReady(() => { - self.ens = new EmbarkJS.Contract({abi: config.abi, address: config.address}); + web3.eth.net.getId((err, id) => { + if (err) { + if (err.message.indexOf('Provider not set or invalid') > -1) { + console.warn(ERROR_MESSAGE); + return; + } + console.error(err); + } + if (!self.registryAddresses[id]) { + console.warn(ERROR_MESSAGE); + return; + } + self.isAvailable = true; + self.ens = new EmbarkJS.Contract({abi: config.abi, address: self.registryAddresses[id]}); + }); }); }; -__embarkENS.resolve = function (name) { - const self = this; - - if (self.ens === undefined) return; - - let node = namehash.hash(name); - - return self.ens.methods.resolver(node).call().then((resolverAddress) => { - let resolverContract = new EmbarkJS.Contract({abi: self.resolverInterface, address: resolverAddress}); - return resolverContract.methods.addr(node).call(); - }).then((addr) => { - return addr; - }).catch((err) => { - if (err === NoDecodeAddrError) { - console.log(name + " is not registered"); - return "0x"; - } - return err; - }); -}; - -__embarkENS.lookup = function (address) { - const self = this; - - if (!self.ens) { - console.log("ENS provider not set. Exiting."); - return; +__embarkENS.resolve = function (name, callback) { + callback = callback || function () {}; + if (!this.ens) { + return callback(providerNotSetError); } - if (address.startsWith("0x")) address = address.slice(2); + let node = namehash.hash(name); + function cb(err, addr) { + if (err === NoDecodeAddrError) { + return callback(name + " is not registered", "0x"); + } + callback(err, addr); + } + + return this.ens.methods.resolver(node).call((err, resolverAddress) => { + if (err) { + return cb(err); + } + let resolverContract = new EmbarkJS.Contract({abi: this.resolverInterface, address: resolverAddress}); + resolverContract.methods.addr(node).call(cb); + }); +}; + +__embarkENS.lookup = function (address, callback) { + callback = callback || function () {}; + if (!this.ens) { + return callback(providerNotSetError); + } + if (address.startsWith("0x")) { + address = address.slice(2); + } let node = namehash.hash(address.toLowerCase() + ".addr.reverse"); - return self.ens.methods.resolver(node).call().then((resolverAddress) => { - let resolverContract = new EmbarkJS.Contract({abi: self.resolverInterface, address: resolverAddress}); - return resolverContract.methods.name(node).call(); - }).catch((err) => { + function cb(err, name) { if (err === NoDecodeStringError || err === NoDecodeAddrError) { - console.log('Address does not resolve to name. Try syncing chain.'); - return ""; + return callback('Address does not resolve to name. Try syncing chain.'); } - return err; + return callback(err, name); + } + + return this.ens.methods.resolver(node).call((err, resolverAddress) => { + if (err) { + return cb(err); + } + let resolverContract = new EmbarkJS.Contract({abi: this.resolverInterface, address: resolverAddress}); + resolverContract.methods.name(node).call(cb); }); }; + +__embarkENS.isAvailable = function () { + return Boolean(this.isAvailable); +}; diff --git a/templates/demo/app/components/ens.js b/templates/demo/app/components/ens.js new file mode 100644 index 00000000..73260272 --- /dev/null +++ b/templates/demo/app/components/ens.js @@ -0,0 +1,121 @@ +import EmbarkJS from 'Embark/EmbarkJS'; +import React from 'react'; +import {Alert, Form, FormGroup, FormControl, Button} from 'react-bootstrap'; + +window.EmbarkJS = EmbarkJS; + +class ENS extends React.Component { + + constructor(props) { + super(props); + + this.state = { + valueResolve: 'ethereumfoundation.eth', + responseResolve: null, + isResolveError: false, + valueLookup: '0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359', + responseLookup: null, + isLookupError: false, + embarkLogs: [] + }; + } + + handleChange(stateName, e) { + this.setState({[stateName]: e.target.value}); + } + + resolveName(e) { + e.preventDefault(); + const embarkLogs = this.state.embarkLogs; + embarkLogs.push(`EmbarkJS.Names.resolve('${this.state.valueResolve}', console.log)`); + + this.setState({ + embarkLogs: embarkLogs + }); + EmbarkJS.Names.resolve(this.state.valueResolve, (err, result) => { + if (err) { + return this.setState({ + responseResolve: err, + isResolveError: true + }); + } + this.setState({ + responseResolve: result, + isResolveError: false + }); + }); + } + + lookupAddress(e) { + e.preventDefault(); + const embarkLogs = this.state.embarkLogs; + embarkLogs.push(`EmbarkJS.Names.resolve('${this.state.valueLookup}', console.log)`); + + this.setState({ + embarkLogs: embarkLogs + }); + EmbarkJS.Names.lookup(this.state.valueLookup, (err, result) => { + if (err) { + return this.setState({ + responseLookup: err, + isLookupError: true + }); + } + this.setState({ + responseLookup: result, + isLookupError: false + }); + }); + } + + render() { + return ( + { + !this.props.enabled ? + + ENS provider might not be set + : '' + } +

Resolve a name

+
+ + {this.state.responseResolve && + + Resolved address: {this.state.responseResolve} + } + this.handleChange('valueResolve', e)}/> + + +
+ +

Lookup an address

+
+ + {this.state.responseLookup && + + Looked up domain: {this.state.responseLookup} + } + this.handleChange('valueLookup', e)}/> + + +
+ +

Embark Calls

+

Javascript calls being made:

+
+ { + this.state.embarkLogs.map((item, i) =>

{item}

) + } +
+
+ ); + } +} + +export default ENS; diff --git a/templates/demo/app/dapp.css b/templates/demo/app/dapp.css index 3d355697..401124e8 100644 --- a/templates/demo/app/dapp.css +++ b/templates/demo/app/dapp.css @@ -50,4 +50,8 @@ div { input.form-control { margin-right: 5px; -} \ No newline at end of file +} + +.alert-result { + margin-left: 0; +} diff --git a/templates/demo/app/dapp.js b/templates/demo/app/dapp.js index a598da26..e7a7bb92 100644 --- a/templates/demo/app/dapp.js +++ b/templates/demo/app/dapp.js @@ -1,11 +1,12 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { Tabs, Tab } from 'react-bootstrap'; +import {Tabs, Tab} from 'react-bootstrap'; import EmbarkJS from 'Embark/EmbarkJS'; import Blockchain from './components/blockchain'; import Whisper from './components/whisper'; import Storage from './components/storage'; +import ENS from './components/ens'; import './dapp.css'; @@ -16,56 +17,61 @@ class App extends React.Component { this.state = { whisperEnabled: false, - storageEnabled: false - } + storageEnabled: false, + ensEnabled: false + }; } - componentDidMount(){ + componentDidMount() { EmbarkJS.onReady(() => { if (EmbarkJS.isNewWeb3()) { - EmbarkJS.Messages.Providers.whisper.getWhisperVersion((err, version) => { - if(!err) - this.setState({whisperEnabled: true}) - else - console.log(err); + EmbarkJS.Messages.Providers.whisper.getWhisperVersion((err, _version) => { + if (err) { + return console.log(err); + } + this.setState({whisperEnabled: true}); }); } else { if (EmbarkJS.Messages.providerName === 'whisper') { - EmbarkJS.Messages.getWhisperVersion((err, version) => { - if(!err) - this.setState({whisperEnabled: true}) - else - console.log(err); + EmbarkJS.Messages.getWhisperVersion((err, _version) => { + if (err) { + return console.log(err); + } + this.setState({whisperEnabled: true}); }); } } this.setState({ - storageEnabled: true + storageEnabled: true, + ensEnabled: EmbarkJS.Names.isAvailable() }); }); } - _renderStatus(title, available){ + _renderStatus(title, available) { let className = available ? 'pull-right status-online' : 'pull-right status-offline'; return - {title} + {title} ; } - render(){ + render() { return (

Embark - Usage Example

- + - + - - + + + + +
);