mirror of
https://github.com/status-im/embark-area-51.git
synced 2025-02-08 21:34:55 +00:00
Merge pull request #34 from status-im/features/backend_tab/ens-explorer
Features/backend tab/ens explorer
This commit is contained in:
commit
4c8eb3e614
@ -104,11 +104,18 @@ export const contractProfile = {
|
||||
failure: (error) => action(CONTRACT_PROFILE[FAILURE], {error})
|
||||
};
|
||||
|
||||
export const MESSAGE_VERSION = createRequestTypes('MESSAGE_VERSION');
|
||||
export const messageVersion = {
|
||||
request: () => action(MESSAGE_VERSION[REQUEST]),
|
||||
success: (messageVersion) => action(MESSAGE_VERSION[SUCCESS], {messageVersion}),
|
||||
failure: (error) => action(MESSAGE_VERSION[FAILURE], {error})
|
||||
export const VERSIONS = createRequestTypes('VERSIONS');
|
||||
export const versions = {
|
||||
request: () => action(VERSIONS[REQUEST]),
|
||||
success: (versions) => action(VERSIONS[SUCCESS], {versions}),
|
||||
failure: (error) => action(VERSIONS[FAILURE], {error})
|
||||
};
|
||||
|
||||
export const PLUGINS = createRequestTypes('PLUGINS');
|
||||
export const plugins = {
|
||||
request: () => action(PLUGINS[REQUEST]),
|
||||
success: (plugins) => action(PLUGINS[SUCCESS], {plugins}),
|
||||
failure: (error) => action(PLUGINS[FAILURE], {error})
|
||||
};
|
||||
|
||||
export const MESSAGE_SEND = createRequestTypes('MESSAGE_SEND');
|
||||
@ -125,6 +132,28 @@ export const messageListen = {
|
||||
failure: (error) => action(MESSAGE_LISTEN[FAILURE], {error})
|
||||
};
|
||||
|
||||
export const ENS_RECORD = createRequestTypes('ENS_RECORD');
|
||||
export const ensRecord = {
|
||||
resolve: (name) => action(ENS_RECORD[REQUEST], {name}),
|
||||
lookup: (address) => action(ENS_RECORD[REQUEST], {address}),
|
||||
success: (record, payload) => action(ENS_RECORD[SUCCESS], {ensRecords: [Object.assign(payload, record)]}),
|
||||
failure: (error) => action(ENS_RECORD[FAILURE], {error})
|
||||
};
|
||||
|
||||
export const ENS_RECORDS = createRequestTypes('ENS_RECORDS');
|
||||
export const ensRecords = {
|
||||
post: (subdomain, address) => action(ENS_RECORDS[REQUEST], {subdomain, address}),
|
||||
success: (record) => action(ENS_RECORDS[SUCCESS], {ensRecords: [record]}),
|
||||
failure: (error) => action(ENS_RECORDS[FAILURE], {error})
|
||||
};
|
||||
|
||||
export const FIDDLE = createRequestTypes('FIDDLE');
|
||||
export const fiddle = {
|
||||
request: (codeToCompile) => action(FIDDLE[REQUEST], {codeToCompile}),
|
||||
success: (fiddle) => action(FIDDLE[SUCCESS], {fiddles: [fiddle]}),
|
||||
failure: (error) => action(FIDDLE[FAILURE], {error})
|
||||
};
|
||||
|
||||
// Web Socket
|
||||
export const WATCH_NEW_PROCESS_LOGS = 'WATCH_NEW_PROCESS_LOGS';
|
||||
export const WATCH_NEW_CONTRACT_LOGS = 'WATCH_NEW_CONTRACT_LOGS';
|
||||
@ -149,11 +178,4 @@ export function initBlockHeader(){
|
||||
};
|
||||
}
|
||||
|
||||
export const FIDDLE = createRequestTypes('FIDDLE');
|
||||
export const fiddle = {
|
||||
request: (codeToCompile) => action(FIDDLE[REQUEST], {codeToCompile}),
|
||||
success: (fiddle) => action(FIDDLE[SUCCESS], {fiddle}),
|
||||
failure: (error) => action(FIDDLE[FAILURE], {error})
|
||||
};
|
||||
|
||||
|
||||
|
@ -68,22 +68,38 @@ export function fetchContract(payload) {
|
||||
return get(`/contract/${payload.contractName}`);
|
||||
}
|
||||
|
||||
export function communicationVersion() {
|
||||
return get(`/communication/version`);
|
||||
export function fetchVersions() {
|
||||
return get('/versions');
|
||||
}
|
||||
|
||||
export function fetchPlugins() {
|
||||
return get('/plugins');
|
||||
}
|
||||
|
||||
export function sendMessage(payload) {
|
||||
return post(`/communication/sendMessage`, payload.body);
|
||||
}
|
||||
|
||||
export function listenToChannel(channel) {
|
||||
return new WebSocket(`${constants.wsEndpoint}/communication/listenTo/${channel}`);
|
||||
}
|
||||
|
||||
export function fetchContractProfile(payload) {
|
||||
return get(`/profiler/${payload.contractName}`);
|
||||
}
|
||||
|
||||
export function fetchEnsRecord(payload) {
|
||||
if (payload.name) {
|
||||
return get('/ens/resolve', {params: payload});
|
||||
} else {
|
||||
return get('/ens/lookup', {params: payload});
|
||||
}
|
||||
}
|
||||
|
||||
export function postEnsRecord(payload) {
|
||||
return post('/ens/register', payload);
|
||||
}
|
||||
|
||||
export function listenToChannel(channel) {
|
||||
return new WebSocket(`${constants.wsEndpoint}/communication/listenTo/${channel}`);
|
||||
}
|
||||
|
||||
export function webSocketProcess(processName) {
|
||||
return new WebSocket(constants.wsEndpoint + '/process-logs/' + processName);
|
||||
}
|
||||
|
58
embark-ui/src/components/EnsLookup.js
Normal file
58
embark-ui/src/components/EnsLookup.js
Normal file
@ -0,0 +1,58 @@
|
||||
import React, {Component} from 'react';
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
Form
|
||||
} from "tabler-react";
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
class EnsLookup extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
address: '',
|
||||
showResult: false
|
||||
};
|
||||
}
|
||||
|
||||
handleChange(e) {
|
||||
this.setState({address: e.target.value, showResult: false});
|
||||
}
|
||||
|
||||
handleLookup() {
|
||||
this.setState({showResult: true});
|
||||
this.props.lookup(this.state.address);
|
||||
}
|
||||
|
||||
showResult() {
|
||||
let ensRecord = this.props.ensRecords.find((record) => record.address === this.state.address);
|
||||
if (ensRecord) {
|
||||
return <Alert type="success">The name is: {ensRecord.name}</Alert>;
|
||||
} else {
|
||||
return <Alert type="danger">We could not find a name for this address</Alert>;
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<React.Fragment>
|
||||
<h3>Lookup</h3>
|
||||
<Form.FieldSet>
|
||||
<Form.Group>
|
||||
<Form.Input placeholder="Enter an address" onChange={e => this.handleChange(e)}/>
|
||||
</Form.Group>
|
||||
<Button color="primary" onClick={() => this.handleLookup()}>Lookup</Button>
|
||||
{this.state.showResult && this.showResult()}
|
||||
</Form.FieldSet>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
EnsLookup.propTypes = {
|
||||
lookup: PropTypes.func,
|
||||
ensRecords: PropTypes.arrayOf(PropTypes.object)
|
||||
};
|
||||
|
||||
export default EnsLookup;
|
71
embark-ui/src/components/EnsRegister.js
Normal file
71
embark-ui/src/components/EnsRegister.js
Normal file
@ -0,0 +1,71 @@
|
||||
import React, {Component} from 'react';
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
Form, Grid
|
||||
} from "tabler-react";
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
class EnsRegister extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
subdomain: '',
|
||||
address: '',
|
||||
showResult: false
|
||||
};
|
||||
}
|
||||
|
||||
handleChange(e, name) {
|
||||
this.setState({
|
||||
showResult: false,
|
||||
[name]: e.target.value
|
||||
});
|
||||
}
|
||||
|
||||
handleRegister() {
|
||||
this.props.register(this.state.subdomain, this.state.address);
|
||||
this.setState({showResult: true});
|
||||
}
|
||||
|
||||
showResult() {
|
||||
if (this.props.ensErrors) {
|
||||
return <Alert type="danger">An error happened: {this.props.ensErrors}</Alert>;
|
||||
} else {
|
||||
return <Alert type="success">Successfully registered</Alert>;
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<React.Fragment>
|
||||
<h3>Register</h3>
|
||||
<Form.FieldSet>
|
||||
<Grid.Row>
|
||||
<Grid.Col md={6}>
|
||||
<Form.Group>
|
||||
<Form.Input placeholder="Enter a subdomain" onChange={e => this.handleChange(e, "subdomain")}/>
|
||||
</Form.Group>
|
||||
</Grid.Col>
|
||||
<Grid.Col md={6}>
|
||||
<Form.Group>
|
||||
<Form.Input placeholder="Enter an address" onChange={e => this.handleChange(e, "address")}/>
|
||||
</Form.Group>
|
||||
</Grid.Col>
|
||||
</Grid.Row>
|
||||
<Button color="primary" onClick={() => this.handleRegister()}>Register</Button>
|
||||
</Form.FieldSet>
|
||||
{this.state.showResult && this.showResult()}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
EnsRegister.propTypes = {
|
||||
register: PropTypes.func,
|
||||
ensRecords: PropTypes.arrayOf(PropTypes.object),
|
||||
ensErrors: PropTypes.string
|
||||
};
|
||||
|
||||
export default EnsRegister;
|
58
embark-ui/src/components/EnsResolve.js
Normal file
58
embark-ui/src/components/EnsResolve.js
Normal file
@ -0,0 +1,58 @@
|
||||
import React, {Component} from 'react';
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
Form
|
||||
} from "tabler-react";
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
class EnsResolve extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
name: '',
|
||||
showResult: false
|
||||
};
|
||||
}
|
||||
|
||||
handleChange(e) {
|
||||
this.setState({name: e.target.value, showResult: false});
|
||||
}
|
||||
|
||||
handleResolve() {
|
||||
this.setState({showResult: true});
|
||||
this.props.resolve(this.state.name);
|
||||
}
|
||||
|
||||
showResult() {
|
||||
let ensRecord = this.props.ensRecords.find((record) => record.name === this.state.name);
|
||||
if (ensRecord) {
|
||||
return <Alert type="success">The address is: {ensRecord.address}</Alert>;
|
||||
} else {
|
||||
return <Alert type="danger">We could not find an address for this name</Alert>;
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<React.Fragment>
|
||||
<h3>Resolve</h3>
|
||||
<Form.FieldSet>
|
||||
<Form.Group>
|
||||
<Form.Input placeholder="Enter a name" onChange={e => this.handleChange(e)}/>
|
||||
</Form.Group>
|
||||
<Button color="primary" onClick={() => this.handleResolve()}>Resolve</Button>
|
||||
{this.state.showResult && this.showResult()}
|
||||
</Form.FieldSet>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
EnsResolve.propTypes = {
|
||||
resolve: PropTypes.func,
|
||||
ensRecords: PropTypes.arrayOf(PropTypes.object)
|
||||
};
|
||||
|
||||
export default EnsResolve;
|
@ -10,9 +10,18 @@ import AccountsContainer from '../containers/AccountsContainer';
|
||||
import AccountContainer from '../containers/AccountContainer';
|
||||
import BlocksContainer from '../containers/BlocksContainer';
|
||||
import BlockContainer from '../containers/BlockContainer';
|
||||
import CommunicationContainer from '../containers/CommunicationContainer';
|
||||
import TransactionsContainer from '../containers/TransactionsContainer';
|
||||
import TransactionContainer from '../containers/TransactionContainer';
|
||||
import CommunicationContainer from '../containers/CommunicationContainer';
|
||||
import EnsContainer from '../containers/EnsContainer';
|
||||
|
||||
const groupItems = [
|
||||
{to: "/embark/explorer/accounts", icon: "users", value: "Accounts"},
|
||||
{to: "/embark/explorer/blocks", icon: "book-open", value: "Blocks"},
|
||||
{to: "/embark/explorer/transactions", icon: "activity", value: "Transactions"},
|
||||
{to: "/embark/explorer/communication", icon: "phone-call", value: "Communication"},
|
||||
{to: "/embark/explorer/ens", icon: "disc", value: "ENS"}
|
||||
];
|
||||
|
||||
const className = "d-flex align-items-center";
|
||||
|
||||
@ -22,38 +31,17 @@ const ExplorerLayout = () => (
|
||||
<Page.Title className="my-5">Explorer</Page.Title>
|
||||
<div>
|
||||
<List.Group transparent={true}>
|
||||
<List.GroupItem
|
||||
className={className}
|
||||
to="/embark/explorer/accounts"
|
||||
icon="users"
|
||||
RootComponent={withRouter(NavLink)}
|
||||
>
|
||||
Accounts
|
||||
</List.GroupItem>
|
||||
<List.GroupItem
|
||||
className={className}
|
||||
to="/embark/explorer/blocks"
|
||||
icon="book-open"
|
||||
RootComponent={withRouter(NavLink)}
|
||||
>
|
||||
Blocks
|
||||
</List.GroupItem>
|
||||
<List.GroupItem
|
||||
className={className}
|
||||
to="/embark/explorer/transactions"
|
||||
icon="activity"
|
||||
RootComponent={withRouter(NavLink)}
|
||||
>
|
||||
Transactions
|
||||
</List.GroupItem>
|
||||
<List.GroupItem
|
||||
className={className}
|
||||
to="/embark/explorer/communication"
|
||||
icon="phone-call"
|
||||
RootComponent={withRouter(NavLink)}
|
||||
>
|
||||
Communication
|
||||
</List.GroupItem>
|
||||
{groupItems.map((groupItem) => (
|
||||
<List.GroupItem
|
||||
key={groupItem.value}
|
||||
className={className}
|
||||
to={groupItem.to}
|
||||
icon={groupItem.icon}
|
||||
RootComponent={withRouter(NavLink)}
|
||||
>
|
||||
{groupItem.value}
|
||||
</List.GroupItem>
|
||||
))}
|
||||
</List.Group>
|
||||
</div>
|
||||
</Grid.Col>
|
||||
@ -63,9 +51,10 @@ const ExplorerLayout = () => (
|
||||
<Route exact path="/embark/explorer/accounts/:address" component={AccountContainer} />
|
||||
<Route exact path="/embark/explorer/blocks" component={BlocksContainer} />
|
||||
<Route exact path="/embark/explorer/blocks/:blockNumber" component={BlockContainer} />
|
||||
<Route exact path="/embark/explorer/communication" component={CommunicationContainer} />
|
||||
<Route exact path="/embark/explorer/transactions" component={TransactionsContainer} />
|
||||
<Route exact path="/embark/explorer/transactions/:hash" component={TransactionContainer} />
|
||||
<Route exact path="/embark/explorer/communication" component={CommunicationContainer} />
|
||||
<Route exact path="/embark/explorer/ens" component={EnsContainer} />
|
||||
</Switch>
|
||||
</Grid.Col>
|
||||
</Grid.Row>
|
||||
|
34
embark-ui/src/components/Versions.js
Normal file
34
embark-ui/src/components/Versions.js
Normal file
@ -0,0 +1,34 @@
|
||||
import PropTypes from "prop-types";
|
||||
import React from 'react';
|
||||
import {Grid, Card} from 'tabler-react';
|
||||
|
||||
const Version = ({version}) => (
|
||||
<Grid.Col sm={6} lg={3}>
|
||||
<Card className="p-3">
|
||||
<div className="d-flex align-items-center">
|
||||
<span className="stamp stamp-md mr-3 bg-info">
|
||||
<i className="fe fa-cube"></i>
|
||||
</span>
|
||||
<div>
|
||||
<h4 className="text-capitalize m-0">{version.name}: {version.value}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
);
|
||||
|
||||
Version.propTypes = {
|
||||
version: PropTypes.object
|
||||
};
|
||||
|
||||
const Versions = ({versions}) => (
|
||||
<Grid.Row cards>
|
||||
{versions.map((version) => <Version key={version.name} version={version} />)}
|
||||
</Grid.Row>
|
||||
);
|
||||
|
||||
Versions.propTypes = {
|
||||
versions: PropTypes.arrayOf(PropTypes.object)
|
||||
};
|
||||
|
||||
export default Versions;
|
@ -6,13 +6,22 @@ import React, {Component} from 'react';
|
||||
import history from '../history';
|
||||
import Layout from '../components/Layout';
|
||||
import routes from '../routes';
|
||||
import {contracts as contractsAction, initBlockHeader, processes as processesAction} from '../actions';
|
||||
|
||||
import {
|
||||
initBlockHeader,
|
||||
contracts as contractsAction,
|
||||
processes as processesAction,
|
||||
versions as versionsAction,
|
||||
plugins as pluginsAction
|
||||
} from '../actions';
|
||||
|
||||
class AppContainer extends Component {
|
||||
componentDidMount() {
|
||||
this.props.initBlockHeader();
|
||||
this.props.fetchProcesses();
|
||||
this.props.fetchContracts();
|
||||
this.props.fetchVersions();
|
||||
this.props.fetchPlugins();
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -29,7 +38,9 @@ class AppContainer extends Component {
|
||||
AppContainer.propTypes = {
|
||||
initBlockHeader: PropTypes.func,
|
||||
fetchContracts: PropTypes.func,
|
||||
fetchProcesses: PropTypes.func
|
||||
fetchProcesses: PropTypes.func,
|
||||
fetchPlugins: PropTypes.func,
|
||||
fetchVersions: PropTypes.func
|
||||
};
|
||||
|
||||
export default connect(
|
||||
@ -37,6 +48,8 @@ export default connect(
|
||||
{
|
||||
initBlockHeader,
|
||||
fetchProcesses: processesAction.request,
|
||||
fetchContracts: contractsAction.request
|
||||
fetchContracts: contractsAction.request,
|
||||
fetchVersions: versionsAction.request,
|
||||
fetchPlugins: pluginsAction.request
|
||||
},
|
||||
)(AppContainer);
|
||||
|
@ -1,17 +1,12 @@
|
||||
import PropTypes from "prop-types";
|
||||
import React, {Component} from 'react';
|
||||
import connect from "react-redux/es/connect/connect";
|
||||
import {Alert, Loader, Page} from 'tabler-react';
|
||||
import {messageSend, messageListen, messageVersion} from "../actions";
|
||||
import {Alert, Page} from 'tabler-react';
|
||||
import {messageSend, messageListen} from "../actions";
|
||||
import Communication from "../components/Communication";
|
||||
import Loading from "../components/Loading";
|
||||
import {getMessageVersion, getMessages, getMessageChannels} from "../reducers/selectors";
|
||||
import {getMessages, getMessageChannels, isOldWeb3, isWeb3Enabled} from "../reducers/selectors";
|
||||
|
||||
class CommunicationContainer extends Component {
|
||||
componentDidMount() {
|
||||
this.props.communicationVersion();
|
||||
}
|
||||
|
||||
sendMessage(topic, message) {
|
||||
this.props.messageSend({topic, message});
|
||||
}
|
||||
@ -20,27 +15,29 @@ class CommunicationContainer extends Component {
|
||||
this.props.messageListen(channel);
|
||||
}
|
||||
|
||||
render() {
|
||||
let isEnabledMessage = '';
|
||||
if (this.props.messageVersion === undefined || this.props.messageVersion === null) {
|
||||
isEnabledMessage =
|
||||
<Alert bsStyle="secondary "><Loader/> Checking Whisper support, please wait</Alert>;
|
||||
} else if (!this.props.messageVersion) {
|
||||
isEnabledMessage = <Alert type="warning">The node you are using does not support Whisper</Alert>;
|
||||
} else if (this.props.messageVersion === -1) {
|
||||
isEnabledMessage = <Alert type="warning">The node uses an unsupported version of Whisper</Alert>;
|
||||
}
|
||||
web3DisabledWarning() {
|
||||
return <Alert type="warning">The node you are using does not support Whisper</Alert>;
|
||||
}
|
||||
|
||||
if (!this.props.messages) {
|
||||
return <Loading/>;
|
||||
}
|
||||
web3Enabled() {
|
||||
return this.props.isOldWeb3 ? this.web3DisabledWarning() : this.showCommunication();
|
||||
}
|
||||
|
||||
web3OldWarning() {
|
||||
return <Alert type="warning">The node uses an unsupported version of Whisper</Alert>;
|
||||
}
|
||||
|
||||
showCommunication() {
|
||||
return <Communication listenToMessages={(channel) => this.listenToChannel(channel)}
|
||||
sendMessage={(channel, message) => this.sendMessage(channel, message)}
|
||||
channels={this.props.messages}
|
||||
subscriptions={this.props.messageChannels}/>;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Page.Content title="Communication explorer">
|
||||
{isEnabledMessage}
|
||||
<Communication listenToMessages={(channel) => this.listenToChannel(channel)}
|
||||
sendMessage={(channel, message) => this.sendMessage(channel, message)}
|
||||
channels={this.props.messages}
|
||||
subscriptions={this.props.messageChannels}/>
|
||||
{this.props.isWeb3Enabled ? this.web3Enabled() : this.web3DisabledWarning()}
|
||||
</Page.Content>
|
||||
);
|
||||
}
|
||||
@ -49,8 +46,8 @@ class CommunicationContainer extends Component {
|
||||
CommunicationContainer.propTypes = {
|
||||
messageSend: PropTypes.func,
|
||||
messageListen: PropTypes.func,
|
||||
communicationVersion: PropTypes.func,
|
||||
messageVersion: PropTypes.number,
|
||||
isOldWeb3: PropTypes.bool,
|
||||
isWeb3Enabled: PropTypes.bool,
|
||||
messages: PropTypes.object,
|
||||
messageChannels: PropTypes.array
|
||||
};
|
||||
@ -59,7 +56,8 @@ function mapStateToProps(state) {
|
||||
return {
|
||||
messages: getMessages(state),
|
||||
messageChannels: getMessageChannels(state),
|
||||
messageVersion: getMessageVersion(state)
|
||||
isOldWeb3: isOldWeb3(state),
|
||||
isWeb3Enabled: isWeb3Enabled(state)
|
||||
};
|
||||
}
|
||||
|
||||
@ -67,8 +65,7 @@ export default connect(
|
||||
mapStateToProps,
|
||||
{
|
||||
messageSend: messageSend.request,
|
||||
messageListen: messageListen.request,
|
||||
communicationVersion: messageVersion.request
|
||||
messageListen: messageListen.request
|
||||
}
|
||||
)(CommunicationContainer);
|
||||
|
||||
|
61
embark-ui/src/containers/EnsContainer.js
Normal file
61
embark-ui/src/containers/EnsContainer.js
Normal file
@ -0,0 +1,61 @@
|
||||
import PropTypes from "prop-types";
|
||||
import React, {Component} from 'react';
|
||||
import connect from "react-redux/es/connect/connect";
|
||||
import {Alert, Page} from "tabler-react";
|
||||
import {ensRecord, ensRecords} from "../actions";
|
||||
import EnsRegister from "../components/EnsRegister";
|
||||
import EnsLookup from "../components/EnsLookup";
|
||||
import EnsResolve from "../components/EnsResolve";
|
||||
import {getEnsRecords, isEnsEnabled, getEnsErrors} from "../reducers/selectors";
|
||||
|
||||
class EnsContainer extends Component {
|
||||
|
||||
showEns() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<EnsLookup lookup={this.props.lookup} ensRecords={this.props.ensRecords}/>
|
||||
<EnsResolve resolve={this.props.resolve} ensRecords={this.props.ensRecords}/>
|
||||
<EnsRegister register={this.props.register} ensRecords={this.props.ensRecords} ensErrors={this.props.ensErrors}/>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
showWarning() {
|
||||
return <Alert type="warning">Please enable Ens in Embark first</Alert>;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Page.Content title="Ens">
|
||||
{this.props.isEnsEnabled ? this.showEns() : this.showWarning()}
|
||||
</Page.Content>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
EnsContainer.propTypes = {
|
||||
ensRecords: PropTypes.array,
|
||||
resolve: PropTypes.func,
|
||||
lookup: PropTypes.func,
|
||||
register: PropTypes.func,
|
||||
isEnsEnabled: PropTypes.bool,
|
||||
ensErrors: PropTypes.string
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
ensRecords: getEnsRecords(state),
|
||||
ensErrors: getEnsErrors(state),
|
||||
isEnsEnabled: isEnsEnabled(state)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
{
|
||||
resolve: ensRecord.resolve,
|
||||
lookup: ensRecord.lookup,
|
||||
register: ensRecords.post
|
||||
}
|
||||
)(EnsContainer);
|
||||
|
@ -6,8 +6,9 @@ import {Page} from "tabler-react";
|
||||
import {commands as commandsAction} from "../actions";
|
||||
import DataWrapper from "../components/DataWrapper";
|
||||
import Processes from '../components/Processes';
|
||||
import Versions from '../components/Versions';
|
||||
import Console from '../components/Console';
|
||||
import {getProcesses, getCommands} from "../reducers/selectors";
|
||||
import {getProcesses, getCommands, getVersions} from "../reducers/selectors";
|
||||
|
||||
class HomeContainer extends Component {
|
||||
render() {
|
||||
@ -17,6 +18,9 @@ class HomeContainer extends Component {
|
||||
<DataWrapper shouldRender={this.props.processes.length > 0 } {...this.props} render={({processes}) => (
|
||||
<Processes processes={processes} />
|
||||
)} />
|
||||
<DataWrapper shouldRender={this.props.versions.length > 0 } {...this.props} render={({versions}) => (
|
||||
<Versions versions={versions} />
|
||||
)} />
|
||||
<Console postCommand={this.props.postCommand} commands={this.props.commands} />
|
||||
</React.Fragment>
|
||||
);
|
||||
@ -25,12 +29,16 @@ class HomeContainer extends Component {
|
||||
|
||||
HomeContainer.propTypes = {
|
||||
processes: PropTypes.arrayOf(PropTypes.object),
|
||||
versions: PropTypes.arrayOf(PropTypes.object),
|
||||
postCommand: PropTypes.func,
|
||||
commands: PropTypes.arrayOf(PropTypes.object)
|
||||
commands: PropTypes.arrayOf(PropTypes.object),
|
||||
error: PropTypes.string,
|
||||
loading: PropTypes.bool
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
versions: getVersions(state),
|
||||
processes: getProcesses(state),
|
||||
commands: getCommands(state),
|
||||
error: state.errorMessage,
|
||||
|
@ -42,7 +42,7 @@ function mapStateToProps(state) {
|
||||
}
|
||||
|
||||
TransactionsContainer.propTypes = {
|
||||
transactions: PropTypes.object,
|
||||
transactions: PropTypes.arrayOf(PropTypes.object),
|
||||
fetchTransactions: PropTypes.func,
|
||||
error: PropTypes.string,
|
||||
loading: PropTypes.bool
|
||||
|
@ -1,7 +1,8 @@
|
||||
import {combineReducers} from 'redux';
|
||||
import {REQUEST} from "../actions";
|
||||
import {REQUEST, SUCCESS} from "../actions";
|
||||
|
||||
const BN_FACTOR = 10000;
|
||||
const voidAddress = '0x0000000000000000000000000000000000000000';
|
||||
|
||||
const entitiesDefaultState = {
|
||||
accounts: [],
|
||||
@ -15,8 +16,10 @@ const entitiesDefaultState = {
|
||||
commands: [],
|
||||
messages: [],
|
||||
messageChannels: [],
|
||||
messageVersion: null,
|
||||
fiddle: null
|
||||
fiddles: [],
|
||||
versions: [],
|
||||
plugins: [],
|
||||
ensRecords: []
|
||||
};
|
||||
|
||||
const sorter = {
|
||||
@ -54,6 +57,11 @@ const filtrer = {
|
||||
return index === self.findIndex((t) => (
|
||||
t.blockNumber === tx.blockNumber && t.transactionIndex === tx.transactionIndex
|
||||
));
|
||||
},
|
||||
ensRecords: function(record, index, self) {
|
||||
return record.name && record.address && record.address !== voidAddress && index === self.findIndex((r) => (
|
||||
r.address=== record.address && r.name === record.name
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
@ -61,10 +69,7 @@ function entities(state = entitiesDefaultState, action) {
|
||||
for (let name of Object.keys(state)) {
|
||||
let filter = filtrer[name] || (() => true);
|
||||
let sort = sorter[name] || (() => true);
|
||||
if (action[name] && !Array.isArray(action[name])) {
|
||||
return {...state, [name]: action[name]};
|
||||
}
|
||||
if (action[name] && (!Array.isArray(action[name]) || action[name].length > 1)) {
|
||||
if (action[name] && action[name].length > 1) {
|
||||
return {...state, [name]: [...action[name], ...state[name]].filter(filter).sort(sort)};
|
||||
}
|
||||
if (action[name] && action[name].length === 1) {
|
||||
@ -90,6 +95,20 @@ function errorMessage(state = null, action) {
|
||||
return action.error || state;
|
||||
}
|
||||
|
||||
/* eslint multiline-ternary: "off" */
|
||||
function errorEntities(state = {}, action) {
|
||||
if (!action.type.endsWith(SUCCESS)) {
|
||||
return state;
|
||||
}
|
||||
let newState = {};
|
||||
for (let name of Object.keys(entitiesDefaultState)) {
|
||||
if (action[name] && action[name].length > 0) {
|
||||
newState[name] = action[name][0].error;
|
||||
}
|
||||
}
|
||||
return {...state, ...newState};
|
||||
}
|
||||
|
||||
function loading(_state = false, action) {
|
||||
return action.type.endsWith(REQUEST);
|
||||
}
|
||||
@ -97,7 +116,8 @@ function loading(_state = false, action) {
|
||||
const rootReducer = combineReducers({
|
||||
entities,
|
||||
loading,
|
||||
errorMessage
|
||||
errorMessage,
|
||||
errorEntities
|
||||
});
|
||||
|
||||
export default rootReducer;
|
||||
|
@ -62,8 +62,17 @@ export function getContractProfile(state, contractName) {
|
||||
return state.entities.contractProfiles.find((contractProfile => contractProfile.name === contractName));
|
||||
}
|
||||
|
||||
export function getMessageVersion(state) {
|
||||
return state.entities.messageVersion;
|
||||
export function getVersions(state) {
|
||||
return state.entities.versions;
|
||||
}
|
||||
|
||||
export function isWeb3Enabled(state) {
|
||||
return Boolean(state.entities.versions.find((version) => version.name === 'web3'));
|
||||
}
|
||||
|
||||
export function isOldWeb3(state) {
|
||||
const web3 = state.entities.versions.find((version) => version.name === 'web3');
|
||||
return web3 && parseInt(web3[0], 10) === 0;
|
||||
}
|
||||
|
||||
export function getMessageChannels(state) {
|
||||
@ -81,6 +90,18 @@ export function getMessages(state) {
|
||||
return messages;
|
||||
}
|
||||
|
||||
export function getFiddle(state){
|
||||
return state.entities.fiddle;
|
||||
export function getFiddle(state) {
|
||||
return state.entities.fiddles[state.entities.fiddles.length - 1];
|
||||
}
|
||||
|
||||
export function getEnsRecords(state) {
|
||||
return state.entities.ensRecords;
|
||||
}
|
||||
|
||||
export function getEnsErrors(state) {
|
||||
return state.errorEntities.ensRecords;
|
||||
}
|
||||
|
||||
export function isEnsEnabled(state) {
|
||||
return Boolean(state.entities.plugins.find((plugin) => plugin.name === 'ens'));
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ import {eventChannel} from 'redux-saga';
|
||||
import {all, call, fork, put, takeEvery, take} from 'redux-saga/effects';
|
||||
|
||||
const {account, accounts, block, blocks, transaction, transactions, processes, commands, processLogs,
|
||||
contracts, contract, contractProfile, messageSend, messageVersion, messageListen, contractLogs,
|
||||
fiddle} = actions;
|
||||
contracts, contract, contractProfile, messageSend, versions, plugins, messageListen, fiddle,
|
||||
ensRecord, ensRecords, contractLogs} = actions;
|
||||
|
||||
function *doRequest(entity, apiFn, payload) {
|
||||
const {response, error} = yield call(apiFn, payload);
|
||||
@ -16,6 +16,8 @@ function *doRequest(entity, apiFn, payload) {
|
||||
}
|
||||
}
|
||||
|
||||
export const fetchPlugins = doRequest.bind(null, plugins, api.fetchPlugins);
|
||||
export const fetchVersions = doRequest.bind(null, versions, api.fetchVersions);
|
||||
export const fetchAccount = doRequest.bind(null, account, api.fetchAccount);
|
||||
export const fetchBlock = doRequest.bind(null, block, api.fetchBlock);
|
||||
export const fetchTransaction = doRequest.bind(null, transaction, api.fetchTransaction);
|
||||
@ -30,6 +32,9 @@ export const fetchContracts = doRequest.bind(null, contracts, api.fetchContracts
|
||||
export const fetchContract = doRequest.bind(null, contract, api.fetchContract);
|
||||
export const fetchContractProfile = doRequest.bind(null, contractProfile, api.fetchContractProfile);
|
||||
export const fetchFiddle = doRequest.bind(null, fiddle, api.fetchFiddle);
|
||||
export const sendMessage = doRequest.bind(null, messageSend, api.sendMessage);
|
||||
export const fetchEnsRecord = doRequest.bind(null, ensRecord, api.fetchEnsRecord);
|
||||
export const postEnsRecord = doRequest.bind(null, ensRecords, api.postEnsRecord);
|
||||
|
||||
export function *watchFetchTransaction() {
|
||||
yield takeEvery(actions.TRANSACTION[actions.REQUEST], fetchTransaction);
|
||||
@ -83,6 +88,34 @@ export function *watchFetchContractProfile() {
|
||||
yield takeEvery(actions.CONTRACT_PROFILE[actions.REQUEST], fetchContractProfile);
|
||||
}
|
||||
|
||||
export function *watchFetchVersions() {
|
||||
yield takeEvery(actions.VERSIONS[actions.REQUEST], fetchVersions);
|
||||
}
|
||||
|
||||
export function *watchFetchPlugins() {
|
||||
yield takeEvery(actions.PLUGINS[actions.REQUEST], fetchPlugins);
|
||||
}
|
||||
|
||||
export function *watchSendMessage() {
|
||||
yield takeEvery(actions.MESSAGE_SEND[actions.REQUEST], sendMessage);
|
||||
}
|
||||
|
||||
export function *watchFetchEnsRecord() {
|
||||
yield takeEvery(actions.ENS_RECORD[actions.REQUEST], fetchEnsRecord);
|
||||
}
|
||||
|
||||
export function *watchPostEnsRecords() {
|
||||
yield takeEvery(actions.ENS_RECORDS[actions.REQUEST], postEnsRecord);
|
||||
}
|
||||
|
||||
export function *watchListenToMessages() {
|
||||
yield takeEvery(actions.MESSAGE_LISTEN[actions.REQUEST], listenToMessages);
|
||||
}
|
||||
|
||||
export function *watchFetchFiddle() {
|
||||
yield takeEvery(actions.FIDDLE[actions.REQUEST], fetchFiddle);
|
||||
}
|
||||
|
||||
function createChannel(socket) {
|
||||
return eventChannel(emit => {
|
||||
socket.onmessage = ((message) => {
|
||||
@ -134,12 +167,6 @@ export function *watchListenToContractLogs() {
|
||||
yield takeEvery(actions.WATCH_NEW_CONTRACT_LOGS, listenToContractLogs);
|
||||
}
|
||||
|
||||
export const sendMessage = doRequest.bind(null, messageSend, api.sendMessage);
|
||||
|
||||
export function *watchSendMessage() {
|
||||
yield takeEvery(actions.MESSAGE_SEND[actions.REQUEST], sendMessage);
|
||||
}
|
||||
|
||||
export function *listenToMessages(action) {
|
||||
const socket = api.listenToChannel(action.messageChannels[0]);
|
||||
const channel = yield call(createChannel, socket);
|
||||
@ -149,20 +176,6 @@ export function *listenToMessages(action) {
|
||||
}
|
||||
}
|
||||
|
||||
export function *watchListenToMessages() {
|
||||
yield takeEvery(actions.MESSAGE_LISTEN[actions.REQUEST], listenToMessages);
|
||||
}
|
||||
|
||||
export const fetchCommunicationVersion = doRequest.bind(null, messageVersion, api.communicationVersion);
|
||||
|
||||
export function *watchCommunicationVersion() {
|
||||
yield takeEvery(actions.MESSAGE_VERSION[actions.REQUEST], fetchCommunicationVersion);
|
||||
}
|
||||
|
||||
export function *watchFetchFiddle() {
|
||||
yield takeEvery(actions.FIDDLE[actions.REQUEST], fetchFiddle);
|
||||
}
|
||||
|
||||
export default function *root() {
|
||||
yield all([
|
||||
fork(watchInitBlockHeader),
|
||||
@ -176,7 +189,8 @@ export default function *root() {
|
||||
fork(watchFetchBlock),
|
||||
fork(watchFetchTransactions),
|
||||
fork(watchPostCommand),
|
||||
fork(watchCommunicationVersion),
|
||||
fork(watchFetchVersions),
|
||||
fork(watchFetchPlugins),
|
||||
fork(watchFetchBlocks),
|
||||
fork(watchFetchContracts),
|
||||
fork(watchListenToMessages),
|
||||
@ -184,7 +198,8 @@ export default function *root() {
|
||||
fork(watchFetchContract),
|
||||
fork(watchFetchTransaction),
|
||||
fork(watchFetchContractProfile),
|
||||
fork(watchFetchFiddle)
|
||||
fork(watchFetchFiddle),
|
||||
fork(watchFetchEnsRecord),
|
||||
fork(watchPostEnsRecords)
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -16,21 +16,19 @@ var Plugins = function(options) {
|
||||
};
|
||||
|
||||
Plugins.prototype.loadPlugins = function() {
|
||||
var pluginConfig;
|
||||
for (var pluginName in this.pluginList) {
|
||||
pluginConfig = this.pluginList[pluginName];
|
||||
for (let pluginName in this.pluginList) {
|
||||
let pluginConfig = this.pluginList[pluginName];
|
||||
this.loadPlugin(pluginName, pluginConfig);
|
||||
}
|
||||
};
|
||||
|
||||
Plugins.prototype.listPlugins = function() {
|
||||
const list = [];
|
||||
this.plugins.forEach(plugin => {
|
||||
return this.plugins.reduce((list, plugin) => {
|
||||
if (plugin.loaded) {
|
||||
list.push(plugin.name);
|
||||
}
|
||||
});
|
||||
return list;
|
||||
return list;
|
||||
}, []);
|
||||
};
|
||||
|
||||
// for services that act as a plugin but have core functionality
|
||||
|
106
lib/modules/ens/ENSFunctions.js
Normal file
106
lib/modules/ens/ENSFunctions.js
Normal file
@ -0,0 +1,106 @@
|
||||
const namehash = require('eth-ens-namehash');
|
||||
|
||||
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';
|
||||
|
||||
function registerSubDomain(ens, registrar, resolver, defaultAccount, subdomain, rootDomain, reverseNode, address, logger, callback) {
|
||||
const subnode = namehash.hash(subdomain);
|
||||
const node = namehash.hash(`${subdomain}.${rootDomain}`);
|
||||
const toSend = registrar.methods.register(subnode, defaultAccount);
|
||||
let transaction;
|
||||
|
||||
toSend.estimateGas()
|
||||
// Register domain
|
||||
.then(gasEstimated => {
|
||||
return toSend.send({gas: gasEstimated + 1000, from: defaultAccount});
|
||||
})
|
||||
// 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});
|
||||
})
|
||||
// Set address for node
|
||||
.then(_result => {
|
||||
return resolver.methods.setAddr(node, address).send({from: defaultAccount});
|
||||
})
|
||||
// Set resolver for the reverse node
|
||||
.then(_result => {
|
||||
return ens.methods.setResolver(reverseNode, resolver.options.address).send({from: defaultAccount});
|
||||
})
|
||||
// Set name for reverse node
|
||||
.then(_result => {
|
||||
return resolver.methods.setName(reverseNode, subdomain + '.embark.eth').send({from: defaultAccount});
|
||||
})
|
||||
.then(_result => {
|
||||
callback(null, transaction);
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error(err);
|
||||
callback('Failed to register with error: ' + (err.message || err));
|
||||
});
|
||||
}
|
||||
|
||||
function lookupAddress(address, ens, utils, createResolverContract, callback) {
|
||||
if (address.startsWith("0x")) {
|
||||
address = address.slice(2);
|
||||
}
|
||||
|
||||
let node = utils.soliditySha3(address.toLowerCase() + reverseAddrSuffix);
|
||||
|
||||
function cb(err, name) {
|
||||
if (err === NoDecodeStringError || err === NoDecodeAddrError) {
|
||||
return callback('Address does not resolve to name. Try syncing chain.');
|
||||
}
|
||||
return callback(err, name);
|
||||
}
|
||||
|
||||
return ens.methods.resolver(node).call((err, resolverAddress) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
if (resolverAddress === voidAddress) {
|
||||
return cb('Address not associated to a resolver');
|
||||
}
|
||||
createResolverContract(resolverAddress, (_, resolverContract) => {
|
||||
resolverContract.methods.name(node).call(cb);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function resolveName(name, ens, createResolverContract, callback) {
|
||||
let node = namehash.hash(name);
|
||||
|
||||
function cb(err, addr) {
|
||||
if (err === NoDecodeAddrError) {
|
||||
return callback(name + " is not registered", "0x");
|
||||
}
|
||||
callback(err, addr);
|
||||
}
|
||||
|
||||
return ens.methods.resolver(node).call((err, resolverAddress) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
if (resolverAddress === voidAddress) {
|
||||
return cb('Name not yet registered');
|
||||
}
|
||||
createResolverContract(resolverAddress, (_, resolverContract) => {
|
||||
resolverContract.methods.addr(node).call(cb);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
registerSubDomain,
|
||||
resolveName,
|
||||
lookupAddress
|
||||
};
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/*global EmbarkJS, web3, registerSubDomain, namehash*/
|
||||
/*global EmbarkJS, web3, lookupAddress, resolveName, registerSubDomain, reverseAddrSuffix*/
|
||||
|
||||
let __embarkENS = {};
|
||||
|
||||
@ -132,10 +132,6 @@ __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';
|
||||
const reverseAddrSuffix = '.addr.reverse';
|
||||
const voidAddress = '0x0000000000000000000000000000000000000000';
|
||||
|
||||
__embarkENS.registryAddresses = {
|
||||
// Mainnet
|
||||
@ -171,30 +167,17 @@ __embarkENS.setProvider = function (config) {
|
||||
});
|
||||
};
|
||||
|
||||
const createResolverContract = function (address, callback) {
|
||||
callback(null, new EmbarkJS.Contract({abi: __embarkENS.resolverInterface, address}));
|
||||
};
|
||||
|
||||
__embarkENS.resolve = function (name, callback) {
|
||||
callback = callback || function () {};
|
||||
if (!this.ens) {
|
||||
return callback(providerNotSetError);
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (resolverAddress === voidAddress) {
|
||||
return cb('Name not yet registered');
|
||||
}
|
||||
let resolverContract = new EmbarkJS.Contract({abi: this.resolverInterface, address: resolverAddress});
|
||||
resolverContract.methods.addr(node).call(cb);
|
||||
});
|
||||
return resolveName(name, this.ens, createResolverContract, callback);
|
||||
};
|
||||
|
||||
__embarkENS.lookup = function (address, callback) {
|
||||
@ -202,28 +185,8 @@ __embarkENS.lookup = function (address, callback) {
|
||||
if (!this.ens) {
|
||||
return callback(providerNotSetError);
|
||||
}
|
||||
if (address.startsWith("0x")) {
|
||||
address = address.slice(2);
|
||||
}
|
||||
let node = web3.utils.soliditySha3(address.toLowerCase() + reverseAddrSuffix);
|
||||
|
||||
function cb(err, name) {
|
||||
if (err === NoDecodeStringError || err === NoDecodeAddrError) {
|
||||
return callback('Address does not resolve to name. Try syncing chain.');
|
||||
}
|
||||
return callback(err, name);
|
||||
}
|
||||
|
||||
return this.ens.methods.resolver(node).call((err, resolverAddress) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
if (resolverAddress === voidAddress) {
|
||||
return cb('Address not associated to a resolver');
|
||||
}
|
||||
let resolverContract = new EmbarkJS.Contract({abi: this.resolverInterface, address: resolverAddress});
|
||||
resolverContract.methods.name(node).call(cb);
|
||||
});
|
||||
return lookupAddress(address, this.ens, web3.utils, createResolverContract.bind(this), callback);
|
||||
};
|
||||
|
||||
__embarkENS.registerSubDomain = function (name, address, callback) {
|
||||
@ -240,8 +203,9 @@ __embarkENS.registerSubDomain = function (name, address, callback) {
|
||||
}
|
||||
|
||||
// Register function generated by the index
|
||||
registerSubDomain(this.ens, this.registrar, this.resolver, web3.eth.defaultAccount, name, this.registration.rootDomain,
|
||||
web3.utils.soliditySha3(address.toLowerCase().substr(2) + reverseAddrSuffix), address, console, callback);
|
||||
registerSubDomain(this.ens, this.registrar, this.resolver, web3.eth.defaultAccount,
|
||||
name, this.registration.rootDomain, web3.utils.soliditySha3(address.toLowerCase().substr(2) + reverseAddrSuffix),
|
||||
address, console, callback);
|
||||
};
|
||||
|
||||
__embarkENS.isAvailable = function () {
|
||||
|
@ -2,6 +2,7 @@ const fs = require('../../core/fs.js');
|
||||
const utils = require('../../utils/utils.js');
|
||||
const namehash = require('eth-ens-namehash');
|
||||
const async = require('async');
|
||||
const ENSFunctions = require('./ENSFunctions');
|
||||
|
||||
const reverseAddrSuffix = '.addr.reverse';
|
||||
|
||||
@ -16,10 +17,10 @@ class ENS {
|
||||
|
||||
this.addENSToEmbarkJS();
|
||||
this.configureContracts();
|
||||
this.registerEvents();
|
||||
this.registerActionForEvents();
|
||||
}
|
||||
|
||||
registerEvents() {
|
||||
registerActionForEvents() {
|
||||
const self = this;
|
||||
self.embark.registerActionForEvent("contracts:deploy:afterAll", (cb) => {
|
||||
async.parallel([
|
||||
@ -51,58 +52,151 @@ class ENS {
|
||||
resolverAddress: results[2].deployedAddress
|
||||
};
|
||||
self.addSetProvider(config);
|
||||
self.registerAPI(config);
|
||||
|
||||
if (!self.env === 'development' || !self.registration || !self.registration.subdomains || !Object.keys(self.registration.subdomains).length) {
|
||||
return cb();
|
||||
}
|
||||
self.registerConfigDomains(config, cb);
|
||||
|
||||
self.registerConfigSubdomains(config, cb);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
registerConfigDomains(config, cb) {
|
||||
registerAPI(config) {
|
||||
let self = this;
|
||||
|
||||
const createInternalResolverContract = function(resolverAddress, callback) {
|
||||
this.createResolverContract({resolverAbi: config.resolverAbi, resolverAddress}, callback);
|
||||
};
|
||||
|
||||
self.embark.registerAPICall(
|
||||
'get',
|
||||
'/embark-api/ens/resolve',
|
||||
(req, res) => {
|
||||
async.waterfall([
|
||||
self.createRegistryContract.bind(this, config),
|
||||
function(ens, callback) {
|
||||
ENSFunctions.resolveName(req.query.name, ens, 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([
|
||||
self.createRegistryContract.bind(this, config),
|
||||
function(ens, callback) {
|
||||
ENSFunctions.lookupAddress(req.query.address, ens, 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.registerSubdomain(req.body.subdomain, req.body.address, config, (error) => {
|
||||
if (error) {
|
||||
return res.send({error: error || error.message});
|
||||
}
|
||||
res.send({name: `${req.body.subdomain}.${self.registration.rootDomain}`, address: req.body.address});
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
registerConfigSubdomains(config, callback) {
|
||||
async.each(Object.keys(this.registration.subdomains), (subdomain, eachCb) => {
|
||||
this.registerSubdomain(subdomain, this.registration.subdomains[subdomain], config, eachCb);
|
||||
}, callback);
|
||||
}
|
||||
|
||||
registerSubdomain(subdomain, address, config, callback) {
|
||||
const self = this;
|
||||
const register = require('./register');
|
||||
self.events.request("blockchain:defaultAccount:get", (defaultAccount) => {
|
||||
async.parallel([
|
||||
function createRegistryContract(paraCb) {
|
||||
self.events.request("blockchain:contract:create",
|
||||
{abi: config.registryAbi, address: config.registryAddress},
|
||||
(registry) => {
|
||||
paraCb(null, registry);
|
||||
});
|
||||
},
|
||||
function createRegistrarContract(paraCb) {
|
||||
self.events.request("blockchain:contract:create",
|
||||
{abi: config.registrarAbi, address: config.registrarAddress},
|
||||
(registrar) => {
|
||||
paraCb(null, registrar);
|
||||
});
|
||||
},
|
||||
function createResolverContract(paraCb) {
|
||||
self.events.request("blockchain:contract:create",
|
||||
{abi: config.resolverAbi, address: config.resolverAddress},
|
||||
(resolver) => {
|
||||
paraCb(null, resolver);
|
||||
});
|
||||
}
|
||||
], function (err, contracts) {
|
||||
async.parallel({
|
||||
ens: self.createRegistryContract.bind(this, config),
|
||||
registrar: self.createRegistrarContract.bind(this, config),
|
||||
resolver: self.createResolverContract.bind(this, config)
|
||||
}, function (err, contracts) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
return callback(err);
|
||||
}
|
||||
const [ens, registrar, resolver] = contracts;
|
||||
|
||||
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(ens, registrar, resolver, defaultAccount, subDomainName, self.registration.rootDomain,
|
||||
reverseNode, address, self.logger, eachCb);
|
||||
}, cb);
|
||||
const {ens, registrar, resolver} = contracts;
|
||||
|
||||
const reverseNode = utils.soliditySha3(address.toLowerCase().substr(2) + reverseAddrSuffix);
|
||||
ENSFunctions.registerSubDomain(ens, registrar, resolver, defaultAccount, subdomain,
|
||||
self.registration.rootDomain, reverseNode, address, self.logger, callback);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
registerSubdomains(subdomains, config, callback) {
|
||||
const self = this;
|
||||
|
||||
self.events.request("blockchain:defaultAccount:get", (defaultAccount) => {
|
||||
async.parallel({
|
||||
ens: self.createRegistryContract.bind(this, config),
|
||||
registrar: self.createRegistrarContract.bind(this, config),
|
||||
resolver: self.createResolverContract.bind(this, config)
|
||||
}, function (err, contracts) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
const {ens, registrar, resolver} = contracts;
|
||||
|
||||
async.each(Object.keys(subdomains), (subdomainName, eachCb) => {
|
||||
const address = subdomains[subdomainName];
|
||||
const reverseNode = utils.soliditySha3(address.toLowerCase().substr(2) + reverseAddrSuffix);
|
||||
ENSFunctions.registerSubDomain(ens, registrar, resolver, defaultAccount, subdomainName,
|
||||
self.registration.rootDomain, reverseNode, address, self.logger, eachCb);
|
||||
}, callback);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
createRegistryContract(config, callback) {
|
||||
this.events.request("blockchain:contract:create", {
|
||||
abi: config.registryAbi,
|
||||
address: config.registryAddress
|
||||
}, (registry) => {
|
||||
callback(null, registry);
|
||||
});
|
||||
}
|
||||
|
||||
createRegistrarContract(config, callback) {
|
||||
this.events.request("blockchain:contract:create", {
|
||||
abi: config.registrarAbi,
|
||||
address: config.registrarAddress
|
||||
}, (registrar) => {
|
||||
callback(null, registrar);
|
||||
});
|
||||
}
|
||||
|
||||
createResolverContract(config, callback) {
|
||||
this.events.request("blockchain:contract:create", {
|
||||
abi: config.resolverAbi,
|
||||
address: config.resolverAddress
|
||||
}, (resolver) => {
|
||||
callback(null, resolver);
|
||||
});
|
||||
}
|
||||
|
||||
addENSToEmbarkJS() {
|
||||
const self = this;
|
||||
// TODO: make this a shouldAdd condition
|
||||
@ -124,7 +218,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);";
|
||||
|
||||
|
@ -1,46 +0,0 @@
|
||||
const namehash = require('eth-ens-namehash');
|
||||
|
||||
function registerSubDomain(ens, registrar, resolver, defaultAccount, subdomain, rootDomain, reverseNode, address, logger, callback) {
|
||||
const subnode = namehash.hash(subdomain);
|
||||
const node = namehash.hash(`${subdomain}.${rootDomain}`);
|
||||
const toSend = registrar.methods.register(subnode, defaultAccount);
|
||||
let transaction;
|
||||
|
||||
toSend.estimateGas()
|
||||
// Register domain
|
||||
.then(gasEstimated => {
|
||||
return toSend.send({gas: gasEstimated + 1000, from: defaultAccount});
|
||||
})
|
||||
// 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});
|
||||
})
|
||||
// Set address for node
|
||||
.then(_result => {
|
||||
return resolver.methods.setAddr(node, address).send({from: defaultAccount});
|
||||
})
|
||||
// Set resolver for the reverse node
|
||||
.then(_result => {
|
||||
return ens.methods.setResolver(reverseNode, resolver.options.address).send({from: defaultAccount});
|
||||
})
|
||||
// Set name for reverse node
|
||||
.then(_result => {
|
||||
return resolver.methods.setName(reverseNode, subdomain + '.embark.eth').send({from: defaultAccount});
|
||||
})
|
||||
.then(_result => {
|
||||
callback(null, transaction);
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error(err);
|
||||
callback('Failed to register with error: ' + (err.message || err));
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = registerSubDomain;
|
||||
}
|
@ -11,6 +11,7 @@ class LibraryManager {
|
||||
this.determineVersions();
|
||||
|
||||
this.registerCommands();
|
||||
this.registerAPICommands();
|
||||
this.listenToCommandsToGetVersions();
|
||||
this.listenToCommandsToGetLibrary();
|
||||
}
|
||||
@ -49,6 +50,18 @@ class LibraryManager {
|
||||
});
|
||||
}
|
||||
|
||||
registerAPICommands() {
|
||||
const self = this;
|
||||
self.embark.registerAPICall(
|
||||
'get',
|
||||
'/embark-api/versions',
|
||||
(req, res) => {
|
||||
const versions = Object.keys(self.versions).map((name) => ({value: self.versions[name], name}));
|
||||
res.send(versions);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
listenToCommandsToGetVersions() {
|
||||
const self = this;
|
||||
for (let libName in this.versions) {
|
||||
|
@ -43,6 +43,13 @@ class Server {
|
||||
|
||||
if (self.plugins) {
|
||||
let apiCalls = self.plugins.getPluginsProperty("apiCalls", "apiCalls");
|
||||
|
||||
app.get('/embark-api/plugins', function(req, res) {
|
||||
res.send(JSON.stringify(self.plugins.plugins.map((plugin) => {
|
||||
return {name: plugin.name};
|
||||
})));
|
||||
});
|
||||
|
||||
for (let apiCall of apiCalls) {
|
||||
console.dir("adding " + apiCall.method + " " + apiCall.endpoint);
|
||||
app[apiCall.method].apply(app, [apiCall.endpoint, apiCall.cb]);
|
||||
|
@ -178,14 +178,6 @@ class Whisper {
|
||||
ws.send(JSON.stringify(result));
|
||||
});
|
||||
});
|
||||
|
||||
self.embark.registerAPICall(
|
||||
'get',
|
||||
'/embark-api/communication/version',
|
||||
(req, res) => {
|
||||
res.send(self.isOldWeb3 ? -1 : self.version || 0);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user