All v3 Nodes & Networks (#202)

* Add all v3s nodes, create node libs for etherscan and infura.

* Add all network configs for alternatives.

* Color and animate nav border on network selection.

* Address PR comments.

* Persist network selection to local storage.

* Modifiy TransactionSucceeded to link to network-specific explorer.

* - Reload on Node Change to reset state. Should be refactored in the future so that we are not forcing clients to reload.
This commit is contained in:
William O'Beirne 2017-09-19 20:47:08 -04:00 committed by Daniel Ternyak
parent ef1c321ada
commit e80d0a68a9
32 changed files with 993 additions and 596 deletions

View File

@ -1,13 +1,18 @@
import React from 'react';
import { ETHTxExplorer } from 'config/data';
import type { BlockExplorerConfig } from 'config.data';
import translate from 'translations';
export type TransactionSucceededProps = {
txHash: string
txHash: string,
blockExplorer: BlockExplorerConfig
};
const TransactionSucceeded = ({ txHash }: TransactionSucceededProps) => {
const TransactionSucceeded = ({
txHash,
blockExplorer
}: TransactionSucceededProps) => {
// const checkTxLink = `https://www.myetherwallet.com?txHash=${txHash}/#check-tx-status`;
const txHashLink = ETHTxExplorer(txHash);
const txHashLink = blockExplorer.tx(txHash);
return (
<div>

View File

@ -39,7 +39,7 @@ const tabs = [
}
];
export default class TabsOptions extends Component {
export default class Navigation extends Component {
constructor(props) {
super(props);
this.state = {
@ -49,7 +49,8 @@ export default class TabsOptions extends Component {
}
static propTypes = {
location: PropTypes.object
location: PropTypes.object,
color: PropTypes.string
};
scrollLeft() {}
@ -57,12 +58,19 @@ export default class TabsOptions extends Component {
scrollRight() {}
render() {
const { location } = this.props;
const { location, color } = this.props;
const borderStyle = {};
if (color) {
borderStyle.borderTopColor = color;
}
return (
<nav
role="navigation"
aria-label="main navigation"
className="Navigation"
style={borderStyle}
>
{this.state.showLeftArrow &&
<a

View File

@ -5,6 +5,7 @@
position: relative;
overflow-y: hidden;
border-top: .25rem solid $brand-primary;
transition: border 300ms ease;
&-scroll {
-ms-overflow-style: -ms-autohiding-scrollbar;

View File

@ -7,6 +7,7 @@ import { Dropdown } from 'components/ui';
import {
languages,
NODES,
NETWORKS,
VERSION,
ANNOUNCEMENT_TYPE,
ANNOUNCEMENT_MESSAGE
@ -32,6 +33,7 @@ export default class Header extends Component {
const selectedLanguage =
languages.find(l => l.sign === languageSelection) || languages[0];
const selectedNode = NODES[nodeSelection];
const selectedNetwork = NETWORKS[selectedNode.network];
return (
<div className="Header">
@ -107,7 +109,10 @@ export default class Header extends Component {
</section>
</section>
<Navigation location={this.props.location} />
<Navigation
location={this.props.location}
color={selectedNetwork.color}
/>
</div>
);
}

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[]

View File

@ -1,5 +1,5 @@
// @flow
import { RPCNode } from 'libs/nodes';
import { RPCNode, InfuraNode, EtherscanNode } from 'libs/nodes';
// Displays in the header
export const VERSION = '4.0.0 (Alpha 0.0.2)';
@ -19,6 +19,7 @@ const etherScan = 'https://etherscan.io';
const blockChainInfo = 'https://blockchain.info';
const ethPlorer = 'https://ethplorer.io';
// TODO: Stop exporting these! Everything should use active node config.
export const ETHTxExplorer = (txHash: string): string =>
`${etherScan}/tx/${txHash}`;
export const BTCTxExplorer = (txHash: string): string =>
@ -148,14 +149,17 @@ export type NetworkContract = {
abi: string
};
type BlockExplorerConfig = {
name: string,
tx: Function,
address: Function
};
export type NetworkConfig = {
name: string,
unit: string,
blockExplorer?: {
name: string,
tx: Function,
address: Function
},
color: string,
blockExplorer?: BlockExplorerConfig,
tokenExplorer?: {
name: string,
address: Function
@ -172,22 +176,92 @@ export type NodeConfig = {
estimateGas: ?boolean
};
// Must be a website that follows the ethplorer convention of /tx/[hash] and
// address/[address] to generate the correct functions.
function makeExplorer(url): BlockExplorerConfig {
return {
name: url,
tx: hash => `${url}/tx/${hash}`,
address: address => `${url}/address/${address}`
};
}
export const NETWORKS: { [key: string]: NetworkConfig } = {
ETH: {
name: 'ETH',
unit: 'ETH',
chainId: 1,
blockExplorer: {
name: etherScan,
tx: ETHTxExplorer,
address: ETHAddressExplorer
},
color: '#0e97c0',
blockExplorer: makeExplorer('https://etherscan.io'),
tokenExplorer: {
name: ethPlorer,
address: ETHTokenExplorer
},
tokens: require('./tokens/eth').default,
tokens: require('./tokens/eth.json'),
contracts: require('./contracts/eth.json')
},
ETC: {
name: 'ETC',
unit: 'ETC',
chainId: 61,
color: '#669073',
blockExplorer: makeExplorer('https://gastracker.io'),
tokens: require('./tokens/etc.json'),
contracts: require('./contracts/etc.json')
},
Ropsten: {
name: 'Ropsten',
unit: 'ETH',
chainId: 3,
color: '#adc101',
blockExplorer: makeExplorer('https://ropsten.etherscan.io'),
tokens: require('./tokens/ropsten.json'),
contracts: require('./contracts/ropsten.json')
},
Kovan: {
name: 'Kovan',
unit: 'ETH',
chainId: 42,
color: '#adc101',
blockExplorer: makeExplorer('https://kovan.etherscan.io'),
tokens: require('./tokens/ropsten.json'),
contracts: require('./contracts/ropsten.json')
},
Rinkeby: {
name: 'Rinkeby',
unit: 'ETH',
chainId: 4,
color: '#adc101',
blockExplorer: makeExplorer('https://rinkeby.etherscan.io'),
tokens: require('./tokens/rinkeby.json'),
contracts: require('./contracts/rinkeby.json')
},
RSK: {
name: 'RSK',
unit: 'RSK',
chainId: 31,
color: '#ff794f',
blockExplorer: makeExplorer('https://explorer.rsk.co'),
tokens: require('./tokens/rsk.json'),
contracts: require('./contracts/rsk.json')
},
EXP: {
name: 'EXP',
unit: 'EXP',
chainId: 2,
color: '#673ab7',
blockExplorer: makeExplorer('http://www.gander.tech'),
tokens: require('./tokens/exp.json'),
contracts: require('./contracts/exp.json')
},
UBQ: {
name: 'UBQ',
unit: 'UBQ',
chainId: 8,
color: '#b37aff',
blockExplorer: makeExplorer('https://ubiqscan.io/en'),
tokens: require('./tokens/ubq.json'),
contracts: require('./contracts/ubq.json')
}
};
@ -197,5 +271,71 @@ export const NODES: { [key: string]: NodeConfig } = {
lib: new RPCNode('https://api.myetherapi.com/eth'),
service: 'MyEtherWallet',
estimateGas: true
},
eth_ethscan: {
network: 'ETH',
service: 'Etherscan.io',
lib: new EtherscanNode('https://api.etherscan.io/api'),
estimateGas: false
},
eth_infura: {
network: 'ETH',
service: 'infura.io',
lib: new InfuraNode('https://mainnet.infura.io/mew'),
estimateGas: false
},
etc_epool: {
network: 'ETC',
service: 'Epool.io',
lib: new RPCNode('https://mewapi.epool.io'),
estimateGas: false
},
rop_mew: {
network: 'Ropsten',
service: 'MyEtherWallet',
lib: new RPCNode('https://api.myetherapi.com/rop'),
estimateGas: false
},
rop_infura: {
network: 'Ropsten',
service: 'infura.io',
lib: new InfuraNode('https://ropsten.infura.io/mew'),
estimateGas: false
},
kov_ethscan: {
network: 'Kovan',
service: 'Etherscan.io',
lib: new EtherscanNode('https://kovan.etherscan.io/api'),
estimateGas: false
},
rin_ethscan: {
network: 'Rinkeby',
service: 'Etherscan.io',
lib: new EtherscanNode('https://rinkeby.etherscan.io/api'),
estimateGas: false
},
rin_infura: {
network: 'Rinkeby',
service: 'infura.io',
lib: new InfuraNode('https://rinkeby.infura.io/mew'),
estimateGas: false
},
rsk: {
network: 'RSK',
service: 'GK2.sk',
lib: new RPCNode('https://rsk-test.gk2.sk/'),
estimateGas: true
},
exp: {
network: 'EXP',
service: 'Expanse.tech',
lib: new RPCNode('https://node.expanse.tech/'),
estimateGas: true
},
ubq: {
network: 'UBQ',
service: 'ubiqscan.io',
lib: new RPCNode('https://pyrus2.ubiqscan.io'),
estimateGas: true
}
};

View File

@ -0,0 +1,8 @@
[
{
"address": "0x085fb4f24031eaedbc2b611aa528f22343eb52db",
"symbol": "BEC",
"decimal": 8,
"type": "default"
}
]

View File

@ -1,439 +0,0 @@
export default [
{
address: '0xAf30D2a7E90d7DC361c8C4585e9BB7D2F6f15bc7',
symbol: '1ST',
decimal: 18
},
{
address: '0x422866a8F0b032c5cf1DfBDEf31A20F4509562b0',
symbol: 'ADST',
decimal: 0
},
{
address: '0xD0D6D6C5Fe4a677D343cC433536BB717bAe167dD',
symbol: 'ADT',
decimal: 9
},
{
address: '0x4470bb87d77b963a013db939be332f927f2b992e',
symbol: 'ADX',
decimal: 4
},
{
address: '0x960b236A07cf122663c4303350609A66A7B288C0',
symbol: 'ANT',
decimal: 18
},
{
address: '0xAc709FcB44a43c35F0DA4e3163b117A17F3770f5',
symbol: 'ARC',
decimal: 18
},
{
address: '0x0D8775F648430679A709E98d2b0Cb6250d2887EF',
symbol: 'BAT',
decimal: 18
},
{
address: '0x74C1E4b8caE59269ec1D85D3D4F324396048F4ac',
symbol: 'BeerCoin 🍺 ',
decimal: 0
},
{
address: '0x1e797Ce986C3CFF4472F7D38d5C4aba55DfEFE40',
symbol: 'BCDN',
decimal: 15
},
{
address: '0xdD6Bf56CA2ada24c683FAC50E37783e55B57AF9F',
symbol: 'BNC',
decimal: 12
},
{
address: '0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C',
symbol: 'BNT',
decimal: 18
},
{
address: '0x5af2be193a6abca9c8817001f45744777db30756',
symbol: 'BQX',
decimal: 8
},
{
address: '0x12FEF5e57bF45873Cd9B62E9DBd7BFb99e32D73e',
symbol: 'CFI',
decimal: 18
},
{
address: '0xAef38fBFBF932D1AeF3B808Bc8fBd8Cd8E1f8BC5',
symbol: 'CRB',
decimal: 8
},
{
address: '0xbf4cfd7d1edeeea5f6600827411b41a21eb08abd',
symbol: 'CTL',
decimal: 2
},
{
address: '0xE4c94d45f7Aef7018a5D66f44aF780ec6023378e',
symbol: 'CryptoCarbon',
decimal: 6
},
{
address: '0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413',
symbol: 'DAO',
decimal: 16
},
{
address: '0x5c40eF6f527f4FbA68368774E6130cE6515123f2',
symbol: 'DAO_extraBalance',
decimal: 0
},
{
address: '0xcC4eF9EEAF656aC1a2Ab886743E98e97E090ed38',
symbol: 'DDF',
decimal: 18
},
{
address: '0xE0B7927c4aF23765Cb51314A0E0521A9645F0E2A',
symbol: 'DGD',
decimal: 9
},
{
address: '0x55b9a11c2e8351b4Ffc7b11561148bfaC9977855',
symbol: 'DGX 1.0',
decimal: 9
},
{
address: '0x2e071D2966Aa7D8dECB1005885bA1977D6038A65',
symbol: 'DICE',
decimal: 16
},
{
address: '0x621d78f2ef2fd937bfca696cabaf9a779f59b3ed',
symbol: 'DRP',
decimal: 2
},
{
address: '0x08711D3B02C8758F2FB3ab4e80228418a7F8e39c',
symbol: 'EDG',
decimal: 0
},
{
address: '0xB802b24E0637c2B87D2E8b7784C055BBE921011a',
symbol: 'EMV',
decimal: 2
},
{
address: '0x190e569bE071F40c704e15825F285481CB74B6cC',
symbol: 'FAM',
decimal: 12
},
{
address: '0xBbB1BD2D741F05E144E6C4517676a15554fD4B8D',
symbol: 'FUN',
decimal: 8
},
{
address: '0x6810e776880C02933D47DB1b9fc05908e5386b96',
symbol: 'GNO',
decimal: 18
},
{
address: '0xa74476443119A942dE498590Fe1f2454d7D4aC0d',
symbol: 'GNT',
decimal: 18
},
{
address: '0xf7B098298f7C69Fc14610bf71d5e02c60792894C',
symbol: 'GUP',
decimal: 3
},
{
address: '0x1D921EeD55a6a9ccaA9C79B1A4f7B25556e44365',
symbol: 'GT',
decimal: 0
},
{
address: '0x14F37B574242D366558dB61f3335289a5035c506',
symbol: 'HKG',
decimal: 3
},
{
address: '0xcbCC0F036ED4788F63FC0fEE32873d6A7487b908',
symbol: 'HMQ',
decimal: 8
},
{
address: '0x888666CA69E0f178DED6D75b5726Cee99A87D698',
symbol: 'ICN',
decimal: 18
},
{
address: '0xc1E6C6C681B286Fb503B36a9dD6c1dbFF85E73CF',
symbol: 'JET',
decimal: 18
},
{
address: '0x773450335eD4ec3DB45aF74f34F2c85348645D39',
symbol: 'JetCoins',
decimal: 18
},
{
address: '0xfa05A73FfE78ef8f1a739473e462c54bae6567D9',
symbol: 'LUN',
decimal: 18
},
{
address: '0x93E682107d1E9defB0b5ee701C71707a4B2E46Bc',
symbol: 'MCAP',
decimal: 8
},
{
address: '0xB63B606Ac810a52cCa15e44bB630fd42D8d1d83d',
symbol: 'MCO',
decimal: 8
},
{
address: '0x40395044ac3c0c57051906da938b54bd6557f212',
symbol: 'MGO',
decimal: 8
},
{
address: '0xd0b171Eb0b0F2CbD35cCD97cDC5EDC3ffe4871aa',
symbol: 'MDA',
decimal: 18
},
{
address: '0xe23cd160761f63FC3a1cF78Aa034b6cdF97d3E0C',
symbol: 'MIT',
decimal: 18
},
{
address: '0xC66eA802717bFb9833400264Dd12c2bCeAa34a6d',
symbol: 'MKR',
decimal: 18
},
{
address: '0xBEB9eF514a379B997e0798FDcC901Ee474B6D9A1',
symbol: 'MLN',
decimal: 18
},
{
address: '0x1a95B271B0535D15fa49932Daba31BA612b52946',
symbol: 'MNE',
decimal: 8
},
{
address: '0x68AA3F232dA9bdC2343465545794ef3eEa5209BD',
symbol: 'MSP',
decimal: 18
},
{
address: '0xf433089366899d83a9f26a773d59ec7ecf30355e',
symbol: 'MTL',
decimal: 8
},
{
address: '0xa645264C5603E96c3b0B078cdab68733794B0A71',
symbol: 'MYST',
decimal: 8
},
{
address: '0xcfb98637bcae43C13323EAa1731cED2B716962fD',
symbol: 'NET',
decimal: 18
},
{
address: '0x1776e1F26f98b1A5dF9cD347953a26dd3Cb46671',
symbol: 'NMR',
decimal: 18
},
{
address: '0x45e42D659D9f9466cD5DF622506033145a9b89Bc',
symbol: 'NxC',
decimal: 3
},
{
address: '0x701C244b988a513c945973dEFA05de933b23Fe1D',
symbol: 'OAX',
decimal: 18
},
{
address: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07',
symbol: 'OMG',
decimal: 18
},
{
address: '0xB97048628DB6B661D4C2aA833e95Dbe1A905B280',
symbol: 'PAY',
decimal: 18
},
{
address: '0x8Ae4BF2C33a8e667de34B54938B0ccD03Eb8CC06',
symbol: 'PTOY',
decimal: 8
},
{
address: '0xD8912C10681D8B21Fd3742244f44658dBA12264E',
symbol: 'PLU',
decimal: 18
},
{
address: '0x671AbBe5CE652491985342e85428EB1b07bC6c64',
symbol: 'QAU',
decimal: 8
},
{
address: '0x697beac28B09E122C4332D163985e8a73121b97F',
symbol: 'QRL',
decimal: 8
},
{
address: '0x48c80F1f4D53D5951e5D5438B54Cba84f29F32a5',
symbol: 'REP',
decimal: 18
},
{
address: '0x607F4C5BB672230e8672085532f7e901544a7375',
symbol: 'RLC',
decimal: 9
},
{
address: '0xcCeD5B8288086BE8c38E23567e684C3740be4D48',
symbol: 'RLT',
decimal: 10
},
{
address: '0x4993CB95c7443bdC06155c5f5688Be9D8f6999a5',
symbol: 'ROUND',
decimal: 18
},
{
address: '0xa1ccc166faf0e998b3e33225a1a0301b1c86119d',
symbol: 'SGEL',
decimal: 18
},
{
address: '0xd248B0D48E44aaF9c49aea0312be7E13a6dc1468',
symbol: 'SGT',
decimal: 1
},
{
address: '0xef2e9966eb61bb494e5375d5df8d67b7db8a780d',
symbol: 'SHIT',
decimal: 0
},
{
address: '0x2bDC0D42996017fCe214b21607a515DA41A9E0C5',
symbol: 'SKIN',
decimal: 6
},
{
address: '0x4994e81897a920c0FEA235eb8CEdEEd3c6fFF697',
symbol: 'SKO1',
decimal: 18
},
{
address: '0xaeC2E87E0A235266D9C5ADc9DEb4b2E29b54D009',
symbol: 'SNGLS',
decimal: 0
},
{
address: '0x983f6d60db79ea8ca4eb9968c6aff8cfa04b3c63',
symbol: 'SNM',
decimal: 18
},
{
address: '0x744d70fdbe2ba4cf95131626614a1763df805b9e',
symbol: 'SNT',
decimal: 18
},
{
address: '0x1dCE4Fa03639B7F0C38ee5bB6065045EdCf9819a',
symbol: 'SRC',
decimal: 8
},
{
address: '0xb64ef51c888972c908cfacf59b47c1afbc0ab8ac',
symbol: 'STORJ',
decimal: 8
},
{
address: '0xB9e7F8568e08d5659f5D29C4997173d84CdF2607',
symbol: 'SWT',
decimal: 18
},
{
address: '0xf4134146af2d511dd5ea8cdb1c4ac88c57d60404',
symbol: 'SNC',
decimal: 18
},
{
address: '0xE7775A6e9Bcf904eb39DA2b68c5efb4F9360e08C',
symbol: 'TaaS',
decimal: 6
},
{
address: '0xa7f976C360ebBeD4465c2855684D1AAE5271eFa9',
symbol: 'TFL',
decimal: 8
},
{
address: '0x6531f133e6DeeBe7F2dcE5A0441aA7ef330B4e53',
symbol: 'TIME',
decimal: 8
},
{
address: '0xaAAf91D9b90dF800Df4F55c205fd6989c977E73a',
symbol: 'TKN',
decimal: 8
},
{
address: '0xCb94be6f13A1182E4A4B6140cb7bf2025d28e41B',
symbol: 'TRST',
decimal: 6
},
{
address: '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7',
symbol: 'Unicorn 🦄 ',
decimal: 0
},
{
address: '0x5c543e7AE0A1104f78406C340E9C64FD9fCE5170',
symbol: 'VSL',
decimal: 18
},
{
address: '0x82665764ea0b58157E1e5E9bab32F68c76Ec0CdF',
symbol: 'VSM',
decimal: 0
},
{
address: '0x8f3470A7388c05eE4e7AF3d01D8C722b0FF52374',
symbol: 'VERI',
decimal: 18
},
{
address: '0xeDBaF3c5100302dCddA53269322f3730b1F0416d',
symbol: 'VRS',
decimal: 5
},
{
address: '0x667088b212ce3d06a1b553a7221E1fD19000d9aF',
symbol: 'WINGS',
decimal: 18
},
{
address: '0x4DF812F6064def1e5e029f1ca858777CC98D2D81',
symbol: 'XAUR',
decimal: 8
},
{
address: '0xb110ec7b1dcb8fab8dedbf28f53bc63ea5bedd84',
symbol: 'XID',
decimal: 8
}
];

View File

@ -0,0 +1,437 @@
[
{
"address": "0xAf30D2a7E90d7DC361c8C4585e9BB7D2F6f15bc7",
"symbol": "1ST",
"decimal": 18
},
{
"address": "0x422866a8F0b032c5cf1DfBDEf31A20F4509562b0",
"symbol": "ADST",
"decimal": 0
},
{
"address": "0xD0D6D6C5Fe4a677D343cC433536BB717bAe167dD",
"symbol": "ADT",
"decimal": 9
},
{
"address": "0x4470bb87d77b963a013db939be332f927f2b992e",
"symbol": "ADX",
"decimal": 4
},
{
"address": "0x960b236A07cf122663c4303350609A66A7B288C0",
"symbol": "ANT",
"decimal": 18
},
{
"address": "0xAc709FcB44a43c35F0DA4e3163b117A17F3770f5",
"symbol": "ARC",
"decimal": 18
},
{
"address": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF",
"symbol": "BAT",
"decimal": 18
},
{
"address": "0x74C1E4b8caE59269ec1D85D3D4F324396048F4ac",
"symbol": "BeerCoin 🍺 ",
"decimal": 0
},
{
"address": "0x1e797Ce986C3CFF4472F7D38d5C4aba55DfEFE40",
"symbol": "BCDN",
"decimal": 15
},
{
"address": "0xdD6Bf56CA2ada24c683FAC50E37783e55B57AF9F",
"symbol": "BNC",
"decimal": 12
},
{
"address": "0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C",
"symbol": "BNT",
"decimal": 18
},
{
"address": "0x5af2be193a6abca9c8817001f45744777db30756",
"symbol": "BQX",
"decimal": 8
},
{
"address": "0x12FEF5e57bF45873Cd9B62E9DBd7BFb99e32D73e",
"symbol": "CFI",
"decimal": 18
},
{
"address": "0xAef38fBFBF932D1AeF3B808Bc8fBd8Cd8E1f8BC5",
"symbol": "CRB",
"decimal": 8
},
{
"address": "0xbf4cfd7d1edeeea5f6600827411b41a21eb08abd",
"symbol": "CTL",
"decimal": 2
},
{
"address": "0xE4c94d45f7Aef7018a5D66f44aF780ec6023378e",
"symbol": "CryptoCarbon",
"decimal": 6
},
{
"address": "0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413",
"symbol": "DAO",
"decimal": 16
},
{
"address": "0x5c40eF6f527f4FbA68368774E6130cE6515123f2",
"symbol": "DAO_extraBalance",
"decimal": 0
},
{
"address": "0xcC4eF9EEAF656aC1a2Ab886743E98e97E090ed38",
"symbol": "DDF",
"decimal": 18
},
{
"address": "0xE0B7927c4aF23765Cb51314A0E0521A9645F0E2A",
"symbol": "DGD",
"decimal": 9
},
{
"address": "0x55b9a11c2e8351b4Ffc7b11561148bfaC9977855",
"symbol": "DGX 1.0",
"decimal": 9
},
{
"address": "0x2e071D2966Aa7D8dECB1005885bA1977D6038A65",
"symbol": "DICE",
"decimal": 16
},
{
"address": "0x621d78f2ef2fd937bfca696cabaf9a779f59b3ed",
"symbol": "DRP",
"decimal": 2
},
{
"address": "0x08711D3B02C8758F2FB3ab4e80228418a7F8e39c",
"symbol": "EDG",
"decimal": 0
},
{
"address": "0xB802b24E0637c2B87D2E8b7784C055BBE921011a",
"symbol": "EMV",
"decimal": 2
},
{
"address": "0x190e569bE071F40c704e15825F285481CB74B6cC",
"symbol": "FAM",
"decimal": 12
},
{
"address": "0xBbB1BD2D741F05E144E6C4517676a15554fD4B8D",
"symbol": "FUN",
"decimal": 8
},
{
"address": "0x6810e776880C02933D47DB1b9fc05908e5386b96",
"symbol": "GNO",
"decimal": 18
},
{
"address": "0xa74476443119A942dE498590Fe1f2454d7D4aC0d",
"symbol": "GNT",
"decimal": 18
},
{
"address": "0xf7B098298f7C69Fc14610bf71d5e02c60792894C",
"symbol": "GUP",
"decimal": 3
},
{
"address": "0x1D921EeD55a6a9ccaA9C79B1A4f7B25556e44365",
"symbol": "GT",
"decimal": 0
},
{
"address": "0x14F37B574242D366558dB61f3335289a5035c506",
"symbol": "HKG",
"decimal": 3
},
{
"address": "0xcbCC0F036ED4788F63FC0fEE32873d6A7487b908",
"symbol": "HMQ",
"decimal": 8
},
{
"address": "0x888666CA69E0f178DED6D75b5726Cee99A87D698",
"symbol": "ICN",
"decimal": 18
},
{
"address": "0xc1E6C6C681B286Fb503B36a9dD6c1dbFF85E73CF",
"symbol": "JET",
"decimal": 18
},
{
"address": "0x773450335eD4ec3DB45aF74f34F2c85348645D39",
"symbol": "JetCoins",
"decimal": 18
},
{
"address": "0xfa05A73FfE78ef8f1a739473e462c54bae6567D9",
"symbol": "LUN",
"decimal": 18
},
{
"address": "0x93E682107d1E9defB0b5ee701C71707a4B2E46Bc",
"symbol": "MCAP",
"decimal": 8
},
{
"address": "0xB63B606Ac810a52cCa15e44bB630fd42D8d1d83d",
"symbol": "MCO",
"decimal": 8
},
{
"address": "0x40395044ac3c0c57051906da938b54bd6557f212",
"symbol": "MGO",
"decimal": 8
},
{
"address": "0xd0b171Eb0b0F2CbD35cCD97cDC5EDC3ffe4871aa",
"symbol": "MDA",
"decimal": 18
},
{
"address": "0xe23cd160761f63FC3a1cF78Aa034b6cdF97d3E0C",
"symbol": "MIT",
"decimal": 18
},
{
"address": "0xC66eA802717bFb9833400264Dd12c2bCeAa34a6d",
"symbol": "MKR",
"decimal": 18
},
{
"address": "0xBEB9eF514a379B997e0798FDcC901Ee474B6D9A1",
"symbol": "MLN",
"decimal": 18
},
{
"address": "0x1a95B271B0535D15fa49932Daba31BA612b52946",
"symbol": "MNE",
"decimal": 8
},
{
"address": "0x68AA3F232dA9bdC2343465545794ef3eEa5209BD",
"symbol": "MSP",
"decimal": 18
},
{
"address": "0xf433089366899d83a9f26a773d59ec7ecf30355e",
"symbol": "MTL",
"decimal": 8
},
{
"address": "0xa645264C5603E96c3b0B078cdab68733794B0A71",
"symbol": "MYST",
"decimal": 8
},
{
"address": "0xcfb98637bcae43C13323EAa1731cED2B716962fD",
"symbol": "NET",
"decimal": 18
},
{
"address": "0x1776e1F26f98b1A5dF9cD347953a26dd3Cb46671",
"symbol": "NMR",
"decimal": 18
},
{
"address": "0x45e42D659D9f9466cD5DF622506033145a9b89Bc",
"symbol": "NxC",
"decimal": 3
},
{
"address": "0x701C244b988a513c945973dEFA05de933b23Fe1D",
"symbol": "OAX",
"decimal": 18
},
{
"address": "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07",
"symbol": "OMG",
"decimal": 18
},
{
"address": "0xB97048628DB6B661D4C2aA833e95Dbe1A905B280",
"symbol": "PAY",
"decimal": 18
},
{
"address": "0x8Ae4BF2C33a8e667de34B54938B0ccD03Eb8CC06",
"symbol": "PTOY",
"decimal": 8
},
{
"address": "0xD8912C10681D8B21Fd3742244f44658dBA12264E",
"symbol": "PLU",
"decimal": 18
},
{
"address": "0x671AbBe5CE652491985342e85428EB1b07bC6c64",
"symbol": "QAU",
"decimal": 8
},
{
"address": "0x697beac28B09E122C4332D163985e8a73121b97F",
"symbol": "QRL",
"decimal": 8
},
{
"address": "0x48c80F1f4D53D5951e5D5438B54Cba84f29F32a5",
"symbol": "REP",
"decimal": 18
},
{
"address": "0x607F4C5BB672230e8672085532f7e901544a7375",
"symbol": "RLC",
"decimal": 9
},
{
"address": "0xcCeD5B8288086BE8c38E23567e684C3740be4D48",
"symbol": "RLT",
"decimal": 10
},
{
"address": "0x4993CB95c7443bdC06155c5f5688Be9D8f6999a5",
"symbol": "ROUND",
"decimal": 18
},
{
"address": "0xa1ccc166faf0e998b3e33225a1a0301b1c86119d",
"symbol": "SGEL",
"decimal": 18
},
{
"address": "0xd248B0D48E44aaF9c49aea0312be7E13a6dc1468",
"symbol": "SGT",
"decimal": 1
},
{
"address": "0xef2e9966eb61bb494e5375d5df8d67b7db8a780d",
"symbol": "SHIT",
"decimal": 0
},
{
"address": "0x2bDC0D42996017fCe214b21607a515DA41A9E0C5",
"symbol": "SKIN",
"decimal": 6
},
{
"address": "0x4994e81897a920c0FEA235eb8CEdEEd3c6fFF697",
"symbol": "SKO1",
"decimal": 18
},
{
"address": "0xaeC2E87E0A235266D9C5ADc9DEb4b2E29b54D009",
"symbol": "SNGLS",
"decimal": 0
},
{
"address": "0x983f6d60db79ea8ca4eb9968c6aff8cfa04b3c63",
"symbol": "SNM",
"decimal": 18
},
{
"address": "0x744d70fdbe2ba4cf95131626614a1763df805b9e",
"symbol": "SNT",
"decimal": 18
},
{
"address": "0x1dCE4Fa03639B7F0C38ee5bB6065045EdCf9819a",
"symbol": "SRC",
"decimal": 8
},
{
"address": "0xb64ef51c888972c908cfacf59b47c1afbc0ab8ac",
"symbol": "STORJ",
"decimal": 8
},
{
"address": "0xB9e7F8568e08d5659f5D29C4997173d84CdF2607",
"symbol": "SWT",
"decimal": 18
},
{
"address": "0xf4134146af2d511dd5ea8cdb1c4ac88c57d60404",
"symbol": "SNC",
"decimal": 18
},
{
"address": "0xE7775A6e9Bcf904eb39DA2b68c5efb4F9360e08C",
"symbol": "TaaS",
"decimal": 6
},
{
"address": "0xa7f976C360ebBeD4465c2855684D1AAE5271eFa9",
"symbol": "TFL",
"decimal": 8
},
{
"address": "0x6531f133e6DeeBe7F2dcE5A0441aA7ef330B4e53",
"symbol": "TIME",
"decimal": 8
},
{
"address": "0xaAAf91D9b90dF800Df4F55c205fd6989c977E73a",
"symbol": "TKN",
"decimal": 8
},
{
"address": "0xCb94be6f13A1182E4A4B6140cb7bf2025d28e41B",
"symbol": "TRST",
"decimal": 6
},
{
"address": "0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7",
"symbol": "Unicorn 🦄 ",
"decimal": 0
},
{
"address": "0x5c543e7AE0A1104f78406C340E9C64FD9fCE5170",
"symbol": "VSL",
"decimal": 18
},
{
"address": "0x82665764ea0b58157E1e5E9bab32F68c76Ec0CdF",
"symbol": "VSM",
"decimal": 0
},
{
"address": "0x8f3470A7388c05eE4e7AF3d01D8C722b0FF52374",
"symbol": "VERI",
"decimal": 18
},
{
"address": "0xeDBaF3c5100302dCddA53269322f3730b1F0416d",
"symbol": "VRS",
"decimal": 5
},
{
"address": "0x667088b212ce3d06a1b553a7221E1fD19000d9aF",
"symbol": "WINGS",
"decimal": 18
},
{
"address": "0x4DF812F6064def1e5e029f1ca858777CC98D2D81",
"symbol": "XAUR",
"decimal": 8
},
{
"address": "0xb110ec7b1dcb8fab8dedbf28f53bc63ea5bedd84",
"symbol": "XID",
"decimal": 8
}
]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1,14 @@
[
{
"address": "0x3C67f7D4decF7795225f51b54134F81137385f83",
"symbol": "GUP",
"decimal": 3,
"type": "default"
},
{
"address": "0x8667559254241ddeD4d11392f868d72092765367",
"symbol": "Aeternity",
"decimal": 18,
"type": "default"
}
]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1,14 @@
[
{
"address": "0xd245207cfbf6eb6f34970db2a807ab1d178fde6c",
"symbol": "APX",
"decimal": 8,
"type": "default"
},
{
"address": "0x4b4899a10f3e507db207b0ee2426029efa168a67",
"symbol": "QWARK",
"decimal": 8,
"type": "default"
}
]

View File

@ -0,0 +1,29 @@
// @flow
import RPCClient from '../rpc/client';
import type { EtherscanRequest } from './types';
import type { JsonRpcResponse } from '../rpc/types';
export default class EtherscanClient extends RPCClient {
encodeRequest(request: EtherscanRequest): string {
const encoded = new URLSearchParams();
Object.keys(request).forEach(key => {
encoded.set(key, request[key]);
});
return encoded.toString();
}
async call(request: EtherscanRequest): Promise<JsonRpcResponse> {
return fetch(this.endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
body: this.encodeRequest(request)
}).then(r => r.json());
}
async batch(requests: EtherscanRequest[]): Promise<JsonRpcResponse[]> {
const promises = requests.map(req => this.call(req));
return Promise.all(promises);
}
}

View File

@ -0,0 +1,14 @@
import RPCNode from '../rpc';
import EtherscanClient from './client';
import EtherscanRequests from './requests';
export default class EtherscanNode extends RPCNode {
client: EtherscanClient;
requests: EtherscanRequests;
constructor(endpoint: string) {
super(endpoint);
this.client = new EtherscanClient(endpoint);
this.requests = new EtherscanRequests();
}
}

View File

@ -0,0 +1,67 @@
// @flow
import ERC20 from 'libs/erc20';
import RPCRequests from '../rpc/requests';
import type {
CallRequest,
GetBalanceRequest,
GetTokenBalanceRequest,
EstimateGasRequest,
GetTransactionCountRequest,
SendRawTxRequest
} from './types';
import type { Token } from 'config/data';
export default class EtherscanRequests extends RPCRequests {
sendRawTx(signedTx: string): SendRawTxRequest {
return {
module: 'proxy',
method: 'eth_sendRawTransaction',
hex: signedTx
};
}
estimateGas<T: *>(transaction: T): EstimateGasRequest {
return {
module: 'proxy',
method: 'eth_estimateGas',
to: transaction.to,
value: transaction.value,
data: transaction.data,
from: transaction.from
};
}
getBalance(address: string): GetBalanceRequest {
return {
module: 'account',
action: 'balance',
tag: 'latest',
address
};
}
ethCall<T: *>(transaction: T): CallRequest {
return {
module: 'proxy',
action: 'eth_call',
to: transaction.to,
data: transaction.data
};
}
getTransactionCount(address: string): GetTransactionCountRequest {
return {
module: 'proxy',
action: 'eth_getTransactionCount',
tag: 'latest',
address
};
}
getTokenBalance(address: string, token: Token): GetTokenBalanceRequest {
return this.ethCall({
to: token.address,
data: ERC20.balanceOf(address)
});
}
}

View File

@ -0,0 +1,42 @@
export type EtherscanReqBase = {
module: string,
action: string
};
export type SendRawTxRequest = EtherscanReqBase & {
module: 'proxy',
method: 'eth_sendRawTransaction',
hex: string
};
export type GetBalanceRequest = EtherscanReqBase & {
module: 'account',
action: 'balance',
address: string,
tag: 'latest'
};
export type CallRequest = EtherscanReqBase & {
module: 'proxy',
action: 'eth_call',
to: string,
data: string
};
export type GetTokenBalanceRequest = CallRequest;
export type EstimateGasRequest = EtherscanReqBase & {
module: 'proxy',
method: 'eth_estimateGas',
to: string,
value: string | number,
data: string,
from: string
};
export type GetTransactionCountRequest = EtherscanReqBase & {
module: 'proxy',
action: 'eth_getTransactionCount',
address: string,
tag: 'latest'
};

View File

@ -1,2 +1,4 @@
// @flow
export { default as RPCNode } from './rpc';
export { default as InfuraNode } from './infura';
export { default as EtherscanNode } from './etherscan';

View File

@ -0,0 +1,9 @@
import RPCClient from '../rpc/client';
import Big from 'bignumber.js';
import { randomBytes } from 'crypto';
export default class InfuraClient extends RPCClient {
id(): string {
return new Big('0x' + randomBytes(5).toString('hex')).toNumber();
}
}

View File

@ -0,0 +1,11 @@
import RPCNode from '../rpc';
import InfuraClient from './client';
export default class InfuraNode extends RPCNode {
client: InfuraClient;
constructor(endpoint: string) {
super(endpoint);
this.client = new InfuraClient(endpoint);
}
}

View File

@ -1,88 +1,6 @@
// @flow
import { randomBytes } from 'crypto';
import ERC20 from 'libs/erc20';
import { hexEncodeData } from './utils';
import type {
RPCRequest,
JsonRpcResponse,
CallRequest,
GetBalanceRequest,
GetTokenBalanceRequest,
EstimateGasRequest,
GetTransactionCountRequest,
SendRawTxRequest
} from './types';
import type { Token } from 'config/data';
// FIXME is it safe to generate that much entropy?
function id(): string {
return randomBytes(16).toString('hex');
}
export function sendRawTx(signedTx: string): SendRawTxRequest {
return {
id: id(),
jsonrpc: '2.0',
method: 'eth_sendRawTransaction',
params: [signedTx]
};
}
export function estimateGas<T: *>(transaction: T): EstimateGasRequest {
return {
id: id(),
jsonrpc: '2.0',
method: 'eth_estimateGas',
params: [transaction]
};
}
export function getBalance(address: string): GetBalanceRequest {
return {
id: id(),
jsonrpc: '2.0',
method: 'eth_getBalance',
params: [hexEncodeData(address), 'pending']
};
}
export function ethCall<T: *>(transaction: T): CallRequest {
return {
id: id(),
jsonrpc: '2.0',
method: 'eth_call',
params: [transaction, 'pending']
};
}
export function getTransactionCount(
address: string
): GetTransactionCountRequest {
return {
id: id(),
jsonrpc: '2.0',
method: 'eth_getTransactionCount',
params: [address, 'pending']
};
}
export function getTokenBalance(
address: string,
token: Token
): GetTokenBalanceRequest {
return {
id: id(),
jsonrpc: '2.0',
method: 'eth_call',
params: [
{
to: token.address,
data: ERC20.balanceOf(address)
},
'pending'
]
};
}
import type { RPCRequest, JsonRpcResponse } from './types';
export default class RPCClient {
endpoint: string;
@ -90,13 +8,25 @@ export default class RPCClient {
this.endpoint = endpoint;
}
id(): string {
return randomBytes(16).toString('hex');
}
decorateRequest(req: RPCRequest) {
return {
...req,
id: this.id(),
jsonrpc: '2.0'
};
}
async call(request: RPCRequest): Promise<JsonRpcResponse> {
return fetch(this.endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
body: JSON.stringify(this.decorateRequest(request))
}).then(r => r.json());
}
@ -106,7 +36,7 @@ export default class RPCClient {
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requests)
body: JSON.stringify(requests.map(this.decorateRequest))
}).then(r => r.json());
}
}

View File

@ -2,55 +2,58 @@
import Big from 'bignumber.js';
import type { INode } from '../INode';
import type { TransactionWithoutGas } from 'libs/messages';
import RPCClient, {
getBalance,
estimateGas,
getTransactionCount,
getTokenBalance,
sendRawTx
} from './client';
import type { Token } from 'config/data';
import RPCClient from './client';
import RPCRequests from './requests';
import { Wei } from 'libs/units';
import type { Token } from 'config/data';
export default class RpcNode implements INode {
client: RPCClient;
requests: RPCRequests;
constructor(endpoint: string) {
this.client = new RPCClient(endpoint);
this.requests = new RPCRequests();
}
getBalance(address: string): Promise<Wei> {
return this.client.call(getBalance(address)).then(response => {
if (response.error) {
throw new Error(response.error.message);
}
return new Wei(String(response.result));
});
return this.client
.call(this.requests.getBalance(address))
.then(response => {
if (response.error) {
throw new Error(response.error.message);
}
return new Wei(String(response.result));
});
}
estimateGas(transaction: TransactionWithoutGas): Promise<Big> {
return this.client.call(estimateGas(transaction)).then(response => {
if (response.error) {
throw new Error(response.error.message);
}
return new Big(String(response.result));
});
return this.client
.call(this.requests.estimateGas(transaction))
.then(response => {
if (response.error) {
throw new Error(response.error.message);
}
return new Big(String(response.result));
});
}
getTokenBalance(address: string, token: Token): Promise<Big> {
return this.client.call(getTokenBalance(address, token)).then(response => {
if (response.error) {
// TODO - Error handling
return new Big(0);
}
return new Big(String(response.result)).div(
new Big(10).pow(token.decimal)
);
});
return this.client
.call(this.requests.getTokenBalance(address, token))
.then(response => {
if (response.error) {
// TODO - Error handling
return new Big(0);
}
return new Big(String(response.result)).div(
new Big(10).pow(token.decimal)
);
});
}
getTokenBalances(address: string, tokens: Token[]): Promise<Big[]> {
return this.client
.batch(tokens.map(t => getTokenBalance(address, t)))
.batch(tokens.map(t => this.requests.getTokenBalance(address, t)))
.then(response => {
return response.map((item, idx) => {
// FIXME wrap in maybe-like
@ -66,23 +69,27 @@ export default class RpcNode implements INode {
}
getTransactionCount(address: string): Promise<string> {
return this.client.call(getTransactionCount(address)).then(response => {
if (response.error) {
throw new Error(response.error.message);
}
return response.result;
});
return this.client
.call(this.requests.getTransactionCount(address))
.then(response => {
if (response.error) {
throw new Error(response.error.message);
}
return response.result;
});
}
sendRawTx(signedTx: string): Promise<string> {
return this.client.call(sendRawTx(signedTx)).then(response => {
if (response.error) {
throw new Error(response.error.message);
}
if (response.errorMessage) {
throw new Error(response.errorMessage);
}
return response.result;
});
return this.client
.call(this.requests.sendRawTx(signedTx))
.then(response => {
if (response.error) {
throw new Error(response.error.message);
}
if (response.errorMessage) {
throw new Error(response.errorMessage);
}
return response.result;
});
}
}

View File

@ -0,0 +1,62 @@
// @flow
import ERC20 from 'libs/erc20';
import { hexEncodeData } from './utils';
import type {
CallRequest,
GetBalanceRequest,
GetTokenBalanceRequest,
EstimateGasRequest,
GetTransactionCountRequest,
SendRawTxRequest
} from './types';
import type { Token } from 'config/data';
export default class RPCRequests {
sendRawTx(signedTx: string): SendRawTxRequest {
return {
method: 'eth_sendRawTransaction',
params: [signedTx]
};
}
estimateGas<T: *>(transaction: T): EstimateGasRequest {
return {
method: 'eth_estimateGas',
params: [transaction]
};
}
getBalance(address: string): GetBalanceRequest {
return {
method: 'eth_getBalance',
params: [hexEncodeData(address), 'pending']
};
}
ethCall<T: *>(transaction: T): CallRequest {
return {
method: 'eth_call',
params: [transaction, 'pending']
};
}
getTransactionCount(address: string): GetTransactionCountRequest {
return {
method: 'eth_getTransactionCount',
params: [address, 'pending']
};
}
getTokenBalance(address: string, token: Token): GetTokenBalanceRequest {
return {
method: 'eth_call',
params: [
{
to: token.address,
data: ERC20.balanceOf(address)
},
'pending'
]
};
}
}

View File

@ -25,8 +25,6 @@ export type JSONRPC2 = '2.0';
export type JsonRpcResponse = JsonRpcSuccess | JsonRpcError;
type RPCRequestBase = {
id: string,
jsonrpc: JSONRPC2,
method: string
};

View File

@ -4,10 +4,11 @@ import type { Yield, Return, Next } from 'sagas/types';
// @HACK For now we reload the app when doing a language swap to force non-connected
// data to reload. Also the use of timeout to avoid using additional actions for now.
function* handleLanguageChange(): Generator<Yield, Return, Next> {
function* reload(): Generator<Yield, Return, Next> {
yield setTimeout(() => location.reload(), 250);
}
export default function* handleConfigChanges(): Generator<Yield, Return, Next> {
yield takeEvery('CONFIG_LANGUAGE_CHANGE', handleLanguageChange);
yield takeEvery('CONFIG_NODE_CHANGE', reload);
yield takeEvery('CONFIG_LANGUAGE_CHANGE', reload);
}

View File

@ -26,7 +26,7 @@ import {
import { INode } from 'libs/nodes/INode';
import { determineKeystoreType } from 'libs/keystore';
import type { Wei } from 'libs/units';
import { getNodeLib } from 'selectors/config';
import { getNodeLib, getNetworkConfig } from 'selectors/config';
import { getWalletInst, getTokens } from 'selectors/wallet';
import TransactionSucceeded from 'components/ExtendedNotifications/TransactionSucceeded';
@ -168,9 +168,17 @@ function* broadcastTx(
const signedTx = action.payload.signedTx;
try {
const node: INode = yield select(getNodeLib);
const network = yield select(getNetworkConfig);
const txHash = yield apply(node, node.sendRawTx, [signedTx]);
yield put(
showNotification('success', <TransactionSucceeded txHash={txHash} />, 0)
showNotification(
'success',
<TransactionSucceeded
txHash={txHash}
blockExplorer={network.blockExplorer}
/>,
0
)
);
yield put({
type: 'WALLET_BROADCAST_TX_SUCCEEDED',

View File

@ -60,6 +60,7 @@ const configureStore = () => {
throttle(() => {
saveState({
config: {
nodeSelection: store.getState().config.nodeSelection,
languageSelection: store.getState().config.languageSelection
},
swap: store.getState().swap,

18
package-lock.json generated
View File

@ -1641,6 +1641,18 @@
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz",
"integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE="
},
"bip39": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/bip39/-/bip39-2.4.0.tgz",
"integrity": "sha512-1++HywqIyPtWDo7gm4v0ylYbwkLvHkuwVSKbBlZBbTCP/mnkyrlARBny906VLAwxJbC5xw9EvuJasHFIZaIFMQ==",
"requires": {
"create-hash": "1.1.3",
"pbkdf2": "3.0.12",
"randombytes": "2.0.5",
"safe-buffer": "5.1.1",
"unorm": "1.4.1"
}
},
"bip66": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz",
@ -10139,7 +10151,6 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz",
"integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==",
"dev": true,
"requires": {
"safe-buffer": "5.1.1"
}
@ -12232,6 +12243,11 @@
"through2-filter": "2.0.0"
}
},
"unorm": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/unorm/-/unorm-1.4.1.tgz",
"integrity": "sha1-NkIA1fE2RsqLzURJAnEzVhR5IwA="
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",