hubii-core
hubii-core copied to clipboard
The home of hubii core (aka Omphalos UI), the reference desktop app for nahmii
hubii core (aka Omphalos UI)

hubii core is an Ethereum wallet manager and friendly user interface to the Ethereum scaling solution nahmii, by hubii. Send and recieve crypto assets and trustlessly make instant, cheap payments and trades, all within a secure desktop environment
Table of Contents
- Highlights
- Install
- Architecture
-
Develop
- Requirements
- Setup API credentials
- Install dependencies
- Run
- Lint
- Test
- Get Ropsten ETH
- Get Ropsten ERC20 tokens
- Build from source
-
Development guidelines
- Boy scout rule
- Ensuring stability when using complex selectors
- Gitflow
- Working with numbers
- Test Driven Development
- Containers as sub pages
- Debugging a production build
Highlights
- Open source
- Send, receive crypto assets on the Ethereum blockchain
- Manage all wallets & addresses in one application
- Retain full custody and control of private keys
- First class Ledger Nano S support
- First class Trezor support
- Instant payments and trades without compromising on security with nahmii (WIP)
Install
macOS 10.9+, Linux, and Windows 7+ are supported (64bit only)
Download the latest version of hubii core for your system on the official releases page
Architecture
hubii core is a multiplatform desktop application built with Electron, React, Redux and styled-components. The architecture is heavily influenced by the react-boilerplate project. To understand our design decisions in greater detail, we recommend you checkout the documentaion and reasoning outlined in that repository.
Develop
Requirements
- NodeJS LTS
- Yarn LTS
- Python
- A C++ compiler
Setup API credentials
-
Send an email with the subject line "API access" to [email protected], we'll get back to you within 24 hours
-
Add the credentials we provide to your PATH
Install dependencies
yarn
Run
yarn electron-dev
Lint
yarn lint
Test everything
yarn test
Test only what's changed since the last commit
yarn test:dev
Get Ropsten ETH
There are various faucents providing free Ropsten ETH:
- faucet.ropsten.be
-
wget https://faucet.ropsten.be/donate/<your ethereum address>
-
- faucent.metamask.io
- Follow instructions on the website
Get Ropsten ERC20 tokens
We recommend the ERC20 BOKKY token on Ropsten. To receive BOKKY, send Ropsten ETH to the BOKKY smart contract for BOKKY tokens in return, 1 for 1.
Build from source
# compiles and builds the app for your system architecture
# the binary will be created inside the dist folder
yarn && yarn electron-build
Development guidelines
Boy scout rule
During the early development of hubii core, different people with different opinions on testing and best practices touched the code base. As a result, you will notice some of the best practices below are not implemented everywhere you look. The majority of critical code has been refactored and we are confident in the foundations of the application, but we have a long way to go cleaning up less critical components and logic.
Instead of tackling this technical debt all at once, we ask that developers follow the "boy scout rule": leave the code you're working on in a better state than you found it. Over time, we will chip away at these smaller issues.
Ensuring stability when using complex selectors
The architecture of hubii core relies on the library reselect to sit inbetween the Redux store and React components. Reselect allows us to abstract a lot of the complex data processing away from the components, keeping them as simple as possible.
One thing to be careful about when composing a complex selector is that you considered all possible structures input selectors can take, for example a selector could either be 'loaded', 'loading', or 'errored'. Forgetting to check for an uncommmon state like 'errored' can be easy, and cause catastrophic failure for the user.
The best way to lower chances of this kind of failure occuring is to test your selector/component with every variation of its possible inputs. To make this as frictionless as possible, please maintain a mocks/selectors.js
file in a container's tests
folder, that contains samples of every variation of structure a selector could return (see containers/WalletHoc/tests/mocks/selectors.js
for an example).
Then when you or another developer wants to reach for a selector, when they're writing their tests they can be confident that they know exactly which inputs they need to test, and have the ability to effortlessly import the required mocked state.
Gitflow
Please obey by established Gitflow principles. Details can be obtained in post by Vincent Driessen or in Atlassian's Gitflow Workflow tutorial. Driessen's git-flow git extension is indispensable.
Working with numbers
During blockchain development, you'll often find yourself working with very small and very large numbers. When dealing with these types of numbers (notably Ether or token amounts), use the BigNumber library to ensure precision isn't lost. If you're interested to read more see this article for a concise explination.
Test Driven Development
Here is a video about TDD, introducing the motivations behind writing good unit tests.
index.test.js: Test the logics at the container
level. component
tests can be constructed similarly to this.
actions.test.js: Test any actions
reducer.test.js: Test the container reducer
saga.test.js: Test any saga
logic. We recommend and are currently migrating all our saga tests to use redux-saga-test-plan
Containers as sub pages
Some containers contain up to 3 levels of complex components. Combining all the logic of each component into a single container could make the code difficult to maintain and difficult to schedule development.
To isolate the complexities between the sub components, the parent container can use sub routes to wire up the sub components. This enable isolating the logics in the parent page container from their sub pages, as well as isolating the logics between the sub pages.
For example
<Tabs defaultActiveKey={history.location.pathname}>
<TabPane tab="Accounts" key={`${match.url}/accounts`}>
<Route path={`${match.url}/accounts`} component={AccountsContainer} />
</TabPane>
<TabPane tab="Contacts" key={`${match.url}/contacts`}>
Content of Tab Pane 2
</TabPane>
</Tabs>
The containers/Accounts
container is the parent page of a number of sub pages such as payment
, savings
, swap currencies
etc. Although it has quite a number of sub pages, it handles its own container logics and have the sub pages to handle by them own.
In order to let the sub pages know which account and currency is currently chosen, it dispatch the actions CHANGE_CURRENT_CURRENCY
or CHANGE_CURRENT_ACCOUNT
, so the sub pages can react respectively.
Take Swap Currency sub page for example, it connects the currentCurrency
with the state in the store
using reselect. Whenever there is an update to this currentCurrency
state, the swap currency container re-render the view to reflect the newly chosen currency from its parent container containers/Accounts
.
Sample codes from containers/SwapCurrencies
on connecting the props to the defined states from the store
.
import { makeSelectCurrentCurrency } from 'containers/Accounts/selectors';
const mapStateToProps = createStructuredSelector({
currentCurrency: makeSelectCurrentCurrency(),
});
Debugging a production build
The dev tools can be opened with Cmd+Alt+I
on macOS, or Ctrl+Shift+I
on Linux and Windows.