2017-08-15 13:56:29 +00:00
# MyEtherWallet V4+ (ALPHA - VISIT [V3](https://github.com/kvhnuke/etherwallet) for the production site)
2017-04-12 05:06:09 +00:00
2017-11-07 23:59:27 +00:00
[![Greenkeeper badge ](https://badges.greenkeeper.io/MyEtherWallet/MyEtherWallet.svg )](https://greenkeeper.io/)
2017-04-12 05:06:09 +00:00
#### Run:
```bash
npm run dev # run app in dev mode
```
#### Build:
```bash
npm run build # build app
```
It generates app in `dist` folder.
2017-12-07 02:11:50 +00:00
#### Unit Tests:
2017-04-12 05:06:09 +00:00
```bash
npm run test # run tests with Jest
```
2017-12-07 02:11:50 +00:00
#### Integration Tests:
```bash
npm run test:int # run tests with Jest
```
2017-09-20 00:47:46 +00:00
#### Dev (HTTPS):
1. Create your own SSL Certificate (Heroku has a [nice guide here ](https://devcenter.heroku.com/articles/ssl-certificate-self ))
2. Move the `.key` and `.crt` files into `webpack_config/server.*`
3. Run the following command:
```bash
npm run dev:https
```
2017-12-07 02:11:50 +00:00
#### Address Derivation Checker:
2017-12-19 17:23:57 +00:00
2017-12-07 02:11:50 +00:00
EthereumJS-Util previously contained a bug that would incorrectly derive addresses from private keys with a 1/128 probability of occurring. A summary of this issue can be found [here ](https://www.reddit.com/r/ethereum/comments/48rt6n/using_myetherwalletcom_just_burned_me_for/d0m4c6l/ ).
2017-12-19 17:23:57 +00:00
As a reactionary measure, the address derivation checker was created.
2017-12-07 02:11:50 +00:00
To test for correct address derivation, the address derivation checker uses multiple sources of address derivation (EthereumJS and PyEthereum) to ensure that multiple official implementations derive the same address for any given private key.
2017-08-24 16:41:47 +00:00
##### The derivation checker utility assumes that you have:
2017-12-19 17:23:57 +00:00
2017-08-24 16:41:47 +00:00
1. Docker installed/available
2. [dternyak/eth-priv-to-addr ](https://hub.docker.com/r/dternyak/eth-priv-to-addr/ ) pulled from DockerHub
##### Docker setup instructions:
2017-12-19 17:23:57 +00:00
2017-10-31 06:25:22 +00:00
1. Install docker (on macOS, [Docker for Mac ](https://docs.docker.com/docker-for-mac/ ) is suggested)
2017-08-24 16:41:47 +00:00
2. `docker pull dternyak/eth-priv-to-addr`
2017-09-20 00:47:46 +00:00
2017-08-24 16:41:47 +00:00
##### Run Derivation Checker
2017-12-19 17:23:57 +00:00
2017-12-07 02:11:50 +00:00
The derivation checker utility runs as part of the integration test suite.
2017-08-24 16:41:47 +00:00
```bash
2017-12-07 02:11:50 +00:00
npm run test:int
2017-08-24 16:41:47 +00:00
```
2017-04-12 05:06:09 +00:00
## Folder structure:
```
2017-04-12 05:09:28 +00:00
│
2017-10-14 19:14:24 +00:00
├── common
2017-04-27 03:59:16 +00:00
│ ├── actions - application actions
2017-10-31 06:25:22 +00:00
│ ├── api - Services and XHR utils
2017-04-12 05:06:09 +00:00
│ ├── components - components according to "Redux philosophy"
│ ├── config - frontend config depending on REACT_WEBPACK_ENV
│ ├── containers - containers according to "Redux philosophy"
│ ├── reducers - application reducers
│ ├── routing - application routing
2017-10-14 19:14:24 +00:00
│ ├── index.tsx - entry
2017-04-12 05:06:09 +00:00
│ ├── index.html
2017-04-12 22:38:25 +00:00
├── static
2017-04-12 05:06:09 +00:00
├── webpack_config - Webpack configuration
├── jest_config - Jest configuration
2017-04-27 03:59:16 +00:00
```
2017-07-11 03:03:08 +00:00
2017-07-15 04:16:36 +00:00
## Style Guides and Philosophies
The following are guides for developers to follow for writing compliant code.
2017-07-27 17:05:09 +00:00
### Redux and Actions
2017-10-14 19:14:24 +00:00
Each reducer has one file in `reducers/[namespace].ts` that contains the reducer
and initial state, one file in `actions/[namespace].ts` that contains the action
2017-07-27 17:05:09 +00:00
creators and their return types, and optionally one file in
2017-10-14 19:14:24 +00:00
`sagas/[namespace].ts` that handles action side effects using
2017-07-27 17:05:09 +00:00
[`redux-saga` ](https://github.com/redux-saga/redux-saga ).
The files should be laid out as follows:
#### Reducer
* State should be explicitly defined and exported
2017-10-14 19:14:24 +00:00
* Initial state should match state typing, define every key
2017-07-27 17:05:09 +00:00
2017-10-14 19:14:24 +00:00
```ts
import { NamespaceAction } from "actions/[namespace]";
import { TypeKeys } from 'actions/[namespace]/constants';
2017-07-27 17:05:09 +00:00
2017-10-14 19:14:24 +00:00
export interface State { /* definition for state object */ };
2017-07-27 17:05:09 +00:00
export const INITIAL_STATE: State = { /* Initial state shape */ };
2017-10-14 19:14:24 +00:00
export function [namespace](
2017-07-27 17:05:09 +00:00
state: State = INITIAL_STATE,
action: NamespaceAction
): State {
switch (action.type) {
2017-10-14 19:14:24 +00:00
case TypeKeys.NAMESPACE_NAME_OF_ACTION:
2017-07-27 17:05:09 +00:00
return {
...state,
// Alterations to state
2017-12-19 17:23:57 +00:00
};
2017-07-27 17:05:09 +00:00
default:
return state;
}
}
```
#### Actions
2017-12-19 17:23:57 +00:00
2017-10-14 19:14:24 +00:00
* Define each action creator in `actionCreator.ts`
* Define each action object type in `actionTypes.ts`
2017-12-19 17:23:57 +00:00
* Export a union of all of the action types for use by the reducer
* Define each action type as a string enum in `constants.ts`
* Export `actionCreators` and `actionTypes` from module file `index.ts`
2017-07-27 17:05:09 +00:00
2017-10-14 19:14:24 +00:00
```
├── common
├── actions - application actions
├── [namespace] - action namespace
├── actionCreators.ts - action creators
├── actionTypes.ts - action interfaces / types
├── constants.ts - string enum
├── index.ts - exports all action creators and action object types
```
2017-12-19 17:23:57 +00:00
2017-10-14 19:14:24 +00:00
##### constants.ts
2017-12-19 17:23:57 +00:00
2017-10-14 19:14:24 +00:00
```ts
export enum TypeKeys {
NAMESPACE_NAME_OF_ACTION = 'NAMESPACE_NAME_OF_ACTION'
}
```
2017-12-19 17:23:57 +00:00
2017-10-14 19:14:24 +00:00
##### actionTypes.ts
2017-12-19 17:23:57 +00:00
2017-10-14 19:14:24 +00:00
```ts
2017-07-27 17:05:09 +00:00
/*** Name of action ** */
2017-10-14 19:14:24 +00:00
export interface NameOfActionAction {
2017-12-19 17:23:57 +00:00
type: TypeKeys.NAMESPACE_NAME_OF_ACTION;
/* Rest of the action object shape */
}
2017-07-27 17:05:09 +00:00
/*** Action Union ** */
2017-12-19 17:23:57 +00:00
export type NamespaceAction = ActionOneAction | ActionTwoAction | ActionThreeAction;
2017-07-27 17:05:09 +00:00
```
2017-12-19 17:23:57 +00:00
2017-10-14 19:14:24 +00:00
##### actionCreators.ts
2017-12-19 17:23:57 +00:00
2017-10-14 19:14:24 +00:00
```ts
import * as interfaces from './actionTypes';
import { TypeKeys } from './constants';
2017-07-27 17:05:09 +00:00
2017-10-14 19:14:24 +00:00
export interface TNameOfAction = typeof nameOfAction;
export function nameOfAction(): interfaces.NameOfActionAction {
return {
type: TypeKeys.NAMESPACE_NAME_OF_ACTION,
payload: {}
};
};
```
2017-12-19 17:23:57 +00:00
2017-10-14 19:14:24 +00:00
##### index.ts
2017-12-19 17:23:57 +00:00
2017-10-14 19:14:24 +00:00
```ts
export * from './actionCreators';
export * from './actionTypes';
```
2017-11-17 18:49:00 +00:00
### Typing Redux-Connected Components
Components that receive props directly from redux as a result of the `connect`
function should use AppState for typing, rather than manually defining types.
This makes refactoring reducers easier by catching mismatches or changes of
types in components, and reduces the chance for inconsistency. It's also less
code overall.
```
// Do this
import { AppState } from 'reducers';
interface Props {
wallet: AppState['wallet']['inst'];
rates: AppState['rates']['rates'];
// ...
}
// Not this
import { IWallet } from 'libs/wallet';
import { Rates } from 'libs/rates';
interface Props {
wallet: IWallet;
rates: Rates;
// ...
}
```
However, if you have a sub-component that takes in props from a connected
component, it's OK to manually specify the type. Especially if you go from
being type-or-null to guaranteeing the prop will be passed (because of a
conditional render.)
2017-10-14 19:14:24 +00:00
### Higher Order Components
2017-07-27 17:05:09 +00:00
2017-10-14 19:14:24 +00:00
#### Typing Injected Props
2017-12-19 17:23:57 +00:00
Props made available through higher order components can be tricky to type. You can inherit the injected props, and in the case of react router, specialize the generic in `withRouter` so it can omit all of its injected props from the component.
2017-10-14 19:14:24 +00:00
2017-10-24 01:46:40 +00:00
```ts
2017-12-19 17:23:57 +00:00
import { RouteComponentProps } from 'react-router-dom';
interface MyComponentProps extends RouteComponentProps< {}> {
2017-10-14 19:14:24 +00:00
name: string;
countryCode?: string;
}
```
2017-10-24 01:46:40 +00:00
```ts
2017-10-14 19:14:24 +00:00
class MyComponent extends React.Component< MyComponentProps , { } > {
render() {
2017-12-19 17:23:57 +00:00
const { name, countryCode, location } = this.props; // location being the one of the injected props from the withRouter HOC
2017-10-14 19:14:24 +00:00
...
}
}
2017-12-19 17:23:57 +00:00
export default withRouter< Props > (MyComponent);
2017-10-14 19:14:24 +00:00
```
2017-07-27 17:05:09 +00:00
2017-10-24 01:46:40 +00:00
## Event Handlers
Event handlers such as `onChange` and `onClick` , should be properly typed. For example, if you have an event listener on an input element inside a form:
2017-12-19 17:23:57 +00:00
2017-10-24 01:46:40 +00:00
```ts
public onValueChange = (e: React.FormEvent< HTMLInputElement > ) => {
if (this.props.onChange) {
this.props.onChange(
e.currentTarget.value,
this.props.unit
);
}
};
```
2017-12-19 17:23:57 +00:00
2017-11-17 18:49:00 +00:00
Where you type the event as a `React.FormEvent` of type `HTML<TYPE>Element` .
2017-10-24 01:46:40 +00:00
## Class names
2017-11-17 18:49:00 +00:00
Dynamic class names should use the `classnames` module to simplify how they are created instead of using string template literals with expressions inside.
2017-10-24 01:46:40 +00:00
2017-07-15 04:16:36 +00:00
### Styling
Legacy styles are housed under `common/assets/styles` and written with LESS.
However, going forward, each styled component should create a a `.scss` file of
the same name in the same folder, and import it like so:
2017-10-14 19:14:24 +00:00
```ts
2017-12-19 17:23:57 +00:00
import React from 'react';
2017-07-15 04:16:36 +00:00
2017-12-19 17:23:57 +00:00
import './MyComponent.scss';
2017-07-15 04:16:36 +00:00
2017-10-14 19:14:24 +00:00
export default class MyComponent extends React.component< {}, {}> {
2017-12-19 17:23:57 +00:00
render() {
return (
< div className = "MyComponent" >
< div className = "MyComponent-child" > Hello!< / div >
< / div >
);
}
2017-07-15 04:16:36 +00:00
}
```
These style modules adhere to [SuitCSS naming convention ](https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md ):
```scss
.MyComponent {
2017-12-19 17:23:57 +00:00
/* Styles */
2017-07-15 04:16:36 +00:00
2017-12-19 17:23:57 +00:00
& -child {
/* Styles */
2017-07-15 04:16:36 +00:00
2017-12-19 17:23:57 +00:00
& .is-hidden {
display: none;
}
}
2017-07-15 04:16:36 +00:00
}
```
All elements inside of a component should extend its parent class namespace, or
create a new namespace (Potentially breaking that out into its own component.)
Variables and mixins can be imported from the files in `common/styles` :
```scss
2017-12-19 17:23:57 +00:00
@import 'sass/colors';
2017-07-15 04:16:36 +00:00
code {
2017-12-19 17:23:57 +00:00
color: $code-color;
2017-07-15 04:16:36 +00:00
}
```
#### Converting Styles
When working on a module that has styling in Less, try to do the following:
* Screenshot the component in question
* Create a new SCSS file in the same directory
* Remove styling from LESS file, convert it to the SCSS file (Mostly s/@/$)
* Convert class names to SuitCSS naming convention
* Convert any utility classes from `etherewallet-utilities.less` into mixins
* Convert as many element selectors to class name selectors as possible
* Convert as many `<br/>` tags or ` ` s to margins
* Ensure that there has been little to no deviation from screenshot
2017-09-25 02:55:23 +00:00
2017-11-28 05:43:30 +00:00
#### Adding Icon-fonts
2017-12-19 17:23:57 +00:00
2017-11-28 05:43:30 +00:00
1. Download chosen icon-font
2017-12-19 17:23:57 +00:00
1. Declare css font-family:
```
@font -face {
font-family: 'social-media';
src: url('../assets/fonts/social-media.eot');
src: url('../assets/fonts/social-media.eot') format('embedded-opentype'),
url('../assets/fonts/social-media.woff2') format('woff2'),
url('../assets/fonts/social-media.woff') format('woff'),
url('../assets/fonts/social-media.ttf') format('truetype'),
url('../assets/fonts/social-media.svg') format('svg');
font-weight: normal;
font-style: normal;
}
```
2017-11-28 05:43:30 +00:00
1. Create classes for each icon using their unicode character
2017-12-19 17:23:57 +00:00
```
.sm-logo-facebook:before {
content: '\ea02';
}
```
* [How to get unicode icon values? ](https://stackoverflow.com/questions/27247145/get-the-unicode-icon-value-from-a-custom-font )
2017-11-28 05:43:30 +00:00
1. Write some markup:
2017-12-19 17:23:57 +00:00
```
< a href = "/" >
< i className = {`sm-icon sm-logo- $ { text } sm-24px ` } / >
Hello World
< / a >
```
2017-09-25 02:55:23 +00:00
## Thanks & Support
< a href = "https://browserstack.com/" >
< img src = "https://i.imgur.com/Rib9y9E.png" align = "left" / >
< / a >
Cross browser testing and debugging provided by the very lovely team at BrowserStack.