* Refactor BaseNode to be an interface INode * Initial contract commit * Remove redundant fallback ABI function * First working iteration of Contract generator to be used in ENS branch * Hide abi to clean up logging output * Strip 0x prefix from output decode * Handle unnamed output params * Implement ability to supply output mappings to ABI functions * Fix null case in outputMapping * Add flow typing * Add .call method to functions * Partial commit for type refactor * Temp contract type fix -- waiting for NPM modularization * Remove empty files * Cleanup contract * Add call request to node interface * Fix output mapping types * Revert destructuring overboard * Add sendCallRequest to rpcNode class and add typing * Use enum for selecting ABI methods * Add transaction capability to contracts * Cleanup privaite/public members * Remove broadcasting step from a contract transaction * Cleanup uneeded types * Refactor ens-base to typescript and add typings for ENS smart contracts * Migrate ens-name-search to TS * Add IResolveDomainRequest * Fix rest of TSC errors * Add definition file for bn.js * Remove types-bn * Fix some typings * make isBN a static property * progress commit -- swap out bignumber.js for bn.js * Swap out bignumber for bn in vendor * Change modn to number return * Start to strip out units lib for a string manipulation based lib * Convert codebase to only base units * Get rid of useless component * Handle only wei in values * Use unit conversion in sidebar * Automatically strip hex prefix, and handle decimal edge case * Handle base 16 wei in transactions * Make a render callback component for dealing with unit conversion * Switch contracts to use bn.js, and get transaction values from signedTx instead of state * Get send transaction working with bn.js * Remove redundant hex stripping, return base value of tokens * Cleanup unit file * Re-implement toFixed for strings * Use formatNumber in codebase * Cleanup code * Undo package test changes * Update snapshot and remove console logs * Use TokenValue / Wei more consistently where applicable * Add typing to deterministicWallets, fix confirmation modal, make UnitDisplay more flexible * Split different ENS modes into their own components * Fix Abi typedef * Remove redundant moment type package * Add Aux helper component * Split out resolve components * Make 'to' parameter optional * Change import type * Change typing to be base domain request * Split handling of resolving into object handler * Fix countdown component * Adjust element spacing * Implement reveal search functionality * Add unit display for highest bidder * Fill out forbidden/NYA modes * ENS wallet component skeleton * Clean up prop handling in UnitDisplay * Change instanceof to typeof check, change boolean of displayBalance * Add ENS wallet component * Cleanup spacing * Convert ConfModal for bidding in ENS * Make ui component for placing bids * Fix destructure in placeBid * Pass through entire wallet * Remove text center * Display inline notification ENS isValid & add some ENS tests * Add export of Aux * Reformat with prettier * progress... * Add ENSUnlockLayout * Add RevealBid component * organize NameResolve components * Merge ENS with transaction-refactor changes * Fix address resolution * Update styles * convert ens name to lowercase before checking * Add overflow-y:scroll to table * update ens snapshots & tests * cast 'undefined' state argument as any for testing * clean up components * Connect unitconverter to redux state * remove unnecessary type assertion * fix spinner size * remove old bidmodal * validate bidmask before opening modal * progress... * Update styles * Add saga / actions for placing a bid * Update types & clean up dead code * Delete old test * Dispatch PlaceBidRequested acitons * Progress commit -- get ENS bidding ready for tx generation via sagas * Seperate ENS action creators and types * Add reducer & actions for ENS fields * Add preliminary sagas for bid mask and bid value * Initial commit * Add loading indicator * Remove some bidding components * Revert bidding files * Remove more bidding code * Remove rest of bidding code * Fix ENS error message * Revert value saga changes * Remove error param from setting 'To' field * Fix existing ENS test * Cleanup address resolution, remove dead code * Remove error messages from unimplemented ENS * Fix last character being not set bug * Remove error state from Meta * Rename isGenesisAddress to isCreationAddress
MyEtherWallet V4+ (ALPHA - VISIT V3 for the production site)
Run:
npm run dev # run app in dev mode
Build:
npm run build # build app
It generates app in dist
folder.
Unit Tests:
npm run test # run tests with Jest
Integration Tests:
npm run test:int # run tests with Jest
Dev (HTTPS):
- Create your own SSL Certificate (Heroku has a nice guide here)
- Move the
.key
and.crt
files intowebpack_config/server.*
- Run the following command:
npm run dev:https
Address Derivation Checker:
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.
As a reactionary measure, the address derivation checker was created.
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.
The derivation checker utility assumes that you have:
- Docker installed/available
- dternyak/eth-priv-to-addr pulled from DockerHub
Docker setup instructions:
- Install docker (on macOS, Docker for Mac is suggested)
docker pull dternyak/eth-priv-to-addr
Run Derivation Checker
The derivation checker utility runs as part of the integration test suite.
npm run test:int
Folder structure:
│
├── common
│ ├── actions - application actions
│ ├── api - Services and XHR utils
│ ├── 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
│ ├── index.tsx - entry
│ ├── index.html
├── static
├── webpack_config - Webpack configuration
├── jest_config - Jest configuration
Style Guides and Philosophies
The following are guides for developers to follow for writing compliant code.
Redux and Actions
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
creators and their return types, and optionally one file in
sagas/[namespace].ts
that handles action side effects using
redux-saga
.
The files should be laid out as follows:
Reducer
- State should be explicitly defined and exported
- Initial state should match state typing, define every key
import { NamespaceAction } from "actions/[namespace]";
import { TypeKeys } from 'actions/[namespace]/constants';
export interface State { /* definition for state object */ };
export const INITIAL_STATE: State = { /* Initial state shape */ };
export function [namespace](
state: State = INITIAL_STATE,
action: NamespaceAction
): State {
switch (action.type) {
case TypeKeys.NAMESPACE_NAME_OF_ACTION:
return {
...state,
// Alterations to state
};
default:
return state;
}
}
Actions
- Define each action creator in
actionCreator.ts
- Define each action object type in
actionTypes.ts
- 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
andactionTypes
from module fileindex.ts
├── 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
constants.ts
export enum TypeKeys {
NAMESPACE_NAME_OF_ACTION = 'NAMESPACE_NAME_OF_ACTION'
}
actionTypes.ts
/*** Name of action ***/
export interface NameOfActionAction {
type: TypeKeys.NAMESPACE_NAME_OF_ACTION;
/* Rest of the action object shape */
}
/*** Action Union ***/
export type NamespaceAction = ActionOneAction | ActionTwoAction | ActionThreeAction;
actionCreators.ts
import * as interfaces from './actionTypes';
import { TypeKeys } from './constants';
export interface TNameOfAction = typeof nameOfAction;
export function nameOfAction(): interfaces.NameOfActionAction {
return {
type: TypeKeys.NAMESPACE_NAME_OF_ACTION,
payload: {}
};
};
index.ts
export * from './actionCreators';
export * from './actionTypes';
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.)
Higher Order Components
Typing Injected Props
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.
import { RouteComponentProps } from 'react-router-dom';
interface MyComponentProps extends RouteComponentProps<{}> {
name: string;
countryCode?: string;
}
class MyComponent extends React.Component<MyComponentProps, {}> {
render() {
const { name, countryCode, location } = this.props; // location being the one of the injected props from the withRouter HOC
...
}
}
export default withRouter<Props>(MyComponent);
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:
public onValueChange = (e: React.FormEvent<HTMLInputElement>) => {
if (this.props.onChange) {
this.props.onChange(
e.currentTarget.value,
this.props.unit
);
}
};
Where you type the event as a React.FormEvent
of type HTML<TYPE>Element
.
Class names
Dynamic class names should use the classnames
module to simplify how they are created instead of using string template literals with expressions inside.
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:
import React from 'react';
import './MyComponent.scss';
export default class MyComponent extends React.component<{}, {}> {
render() {
return (
<div className="MyComponent">
<div className="MyComponent-child">Hello!</div>
</div>
);
}
}
These style modules adhere to SuitCSS naming convention:
.MyComponent {
/* Styles */
&-child {
/* Styles */
&.is-hidden {
display: none;
}
}
}
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
:
@import 'sass/colors';
code {
color: $code-color;
}
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
Adding Icon-fonts
- Download chosen icon-font
- 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; }
- Create classes for each icon using their unicode character
.sm-logo-facebook:before { content: '\ea02'; }
- Write some markup:
<a href="/"> <i className={`sm-icon sm-logo-${text} sm-24px`} /> Hello World </a>
Thanks & Support
Cross browser testing and debugging provided by the very lovely team at BrowserStack.