Fetch tokens from IPFS hash on load / node change

This commit is contained in:
HenryNguyen5 2018-05-22 22:23:21 -04:00
parent 7f21b2014f
commit c62ce80f1d
22 changed files with 403 additions and 63 deletions

View File

@ -132,3 +132,21 @@ export function web3UnsetNode(): interfaces.Web3UnsetNodeAction {
type: TypeKeys.CONFIG_NODE_WEB3_UNSET
};
}
export function updateTokensRequested(
payload: interfaces.UpdateTokensRequested['payload']
): interfaces.UpdateTokensRequested {
return { type: TypeKeys.CONFIG_UPDATE_TOKENS_REQUESTED, payload };
}
export function updateTokensSucceeded(
payload: interfaces.UpdateTokensSucceeded['payload']
): interfaces.UpdateTokensSucceeded {
return { type: TypeKeys.CONFIG_UPDATE_TOKENS_SUCCEEDED, payload };
}
export function updateTokensFailed(
payload: interfaces.UpdateTokensFailed['payload']
): interfaces.UpdateTokensFailed {
return { type: TypeKeys.CONFIG_UDPATE_TOKENS_FAILED, payload };
}

View File

@ -1,6 +1,6 @@
import { TypeKeys } from './constants';
import { CustomNodeConfig, StaticNodeConfig } from 'types/node';
import { CustomNetworkConfig } from 'types/network';
import { CustomNetworkConfig, Token, StaticNetworkIds } from 'types/network';
export interface SetOnlineAction {
type: TypeKeys.CONFIG_SET_ONLINE;
@ -93,6 +93,23 @@ export interface Web3setNodeAction {
payload: { id: 'web3'; config: StaticNodeConfig };
}
export interface UpdateTokensRequested {
type: TypeKeys.CONFIG_UPDATE_TOKENS_REQUESTED;
payload: { id: StaticNetworkIds };
}
export interface UpdateTokensSucceeded {
type: TypeKeys.CONFIG_UPDATE_TOKENS_SUCCEEDED;
payload: { tokens: Token[]; id: StaticNetworkIds; hash: string | null };
}
export interface UpdateTokensFailed {
type: TypeKeys.CONFIG_UDPATE_TOKENS_FAILED;
payload: { id: StaticNetworkIds };
}
export type UpdateTokensAction = UpdateTokensRequested | UpdateTokensSucceeded | UpdateTokensFailed;
export type CustomNetworkAction = AddCustomNetworkAction | RemoveCustomNetworkAction;
export type CustomNodeAction = AddCustomNodeAction | RemoveCustomNodeAction;

View File

@ -20,5 +20,9 @@ export enum TypeKeys {
CONFIG_REMOVE_CUSTOM_NODE = 'CONFIG_REMOVE_CUSTOM_NODE',
CONFIG_ADD_CUSTOM_NETWORK = 'CONFIG_ADD_CUSTOM_NETWORK',
CONFIG_REMOVE_CUSTOM_NETWORK = 'CONFIG_REMOVE_CUSTOM_NETWORK'
CONFIG_REMOVE_CUSTOM_NETWORK = 'CONFIG_REMOVE_CUSTOM_NETWORK',
CONFIG_UPDATE_TOKENS_REQUESTED = 'CONFIG_UPDATE_TOKENS_REQUESTED',
CONFIG_UPDATE_TOKENS_SUCCEEDED = 'CONFIG_UPDATE_TOKENS_SUCCEEDED',
CONFIG_UDPATE_TOKENS_FAILED = 'CONFIG_UPDATE_TOKENS_FAILED'
}

View File

@ -5,6 +5,10 @@ import { GasPriceSetting } from 'types/network';
import { makeExplorer } from 'utils/helpers';
import NewTabLink from 'components/ui/NewTabLink';
// tslint:disable-next-line:no-http-string
export const IPFS_GATEWAY = 'http://127.0.0.1:8080';
export const IPFS_MULTISIG_CONTRACT_ADDRESS = '0x230ead3dbbd50248456a57afdd6570cdc8b4e439';
export const languages = require('./languages.json');
export const discordURL = 'https://discord.gg/VSaTXEA';

View File

@ -1,6 +1,6 @@
import Contract from 'libs/contracts';
interface ABIFunc<T, K = void> {
export interface ABIFunc<T, K = void> {
encodeInput(x: T): string;
decodeInput(argStr: string): T;
decodeOutput(argStr: string): K;

120
common/libs/ipfs-tokens.ts Normal file
View File

@ -0,0 +1,120 @@
import { IPFS_GATEWAY, IPFS_MULTISIG_CONTRACT_ADDRESS } from 'config';
import { Token, StaticNetworkConfig } from 'shared/types/network';
import Contract from 'libs/contracts';
import { ABIFunc } from './erc20';
import { shepherdProvider } from './nodes';
import bs58 from 'bs58';
import { handleValues } from './units';
const { processTokenJson } = require('../../shared/update-tokens-utils');
function makeIpfsGatewayUrl(ipfsHash: string) {
return `${IPFS_GATEWAY}/ipfs/${ipfsHash}`;
}
function getTokenList(ipfsHash: string): Promise<Token[]> {
return fetch(makeIpfsGatewayUrl(ipfsHash))
.then(r => r.json())
.then(processTokenJson);
}
type uint256 = any;
type bytes32 = any;
type uint8 = any;
interface GetEntryResponse {
digest: bytes32;
hashfunction: uint8;
size: uint8;
}
/**
* Encode a multihash structure into base58 encoded multihash string
*
* @param {Multihash} multihash
* @returns {(string|null)} base58 encoded multihash string
*/
function getMultihashFromBytes32(multihash: GetEntryResponse) {
const { digest, hashfunction, size } = multihash;
if (size === 0) {
return null;
}
// prepend hashFunction and digest size
const multihashBytes = Buffer.alloc(2 + digest.length);
multihashBytes[0] = hashfunction;
multihashBytes[1] = size;
multihashBytes.set(digest, 2);
return bs58.encode(multihashBytes);
}
function fetchLatestIpfsHash(key: number) {
interface IContract {
getEntry: ABIFunc<{ _key: uint256 }, GetEntryResponse>;
}
const abi = [
{
name: 'getEntry',
type: 'function',
constant: true,
payable: false,
stateMutability: 'view',
inputs: [
{
name: '_key',
type: 'uint256'
}
],
outputs: [
{
name: 'digest',
type: 'bytes32'
},
{
name: 'hashfunction',
type: 'uint8'
},
{
name: 'size',
type: 'uint8'
}
]
}
];
const contract = (new Contract(abi) as any) as IContract;
return shepherdProvider
.sendCallRequest({
data: contract.getEntry.encodeInput({ _key: key }),
to: IPFS_MULTISIG_CONTRACT_ADDRESS
})
.then(contract.getEntry.decodeOutput)
.then(({ digest, hashfunction, size }) => ({
digest,
hashfunction: handleValues(hashfunction).toNumber(),
size: handleValues(size).toNumber()
}))
.then(getMultihashFromBytes32);
}
export async function updateTokensForNetwork(network: StaticNetworkConfig) {
const { tokens: currTokenList, chainId: key, tokenListHash } = network;
if (!network.shouldCheckForTokenUpdates) {
return { tokens: currTokenList, hash: null };
}
const latestHash = await fetchLatestIpfsHash(key);
if (!latestHash) {
return { tokens: currTokenList, hash: null };
}
if (tokenListHash === latestHash) {
return { tokens: currTokenList, hash: null };
}
const latestList = await getTokenList(latestHash);
return { tokens: latestList, hash: latestHash };
}

View File

@ -1,7 +1,6 @@
import { Wei, TokenValue } from 'libs/units';
import { IHexStrTransaction } from 'libs/transaction';
import { Token } from 'types/network';
import { TransactionData, TransactionReceipt } from 'types/transactions';
import { IRPCProvider } from 'mycrypto-shepherd/dist/lib/types';
import { Token } from 'shared/types/network';
import { TokenValue } from 'libs/units';
export interface TxObj {
to: string;
@ -13,16 +12,8 @@ interface TokenBalanceResult {
error: string | null;
}
export interface INode {
ping(): Promise<boolean>;
getBalance(address: string): Promise<Wei>;
// alias for compatibility
export type INode = IRPCProvider & {
getTokenBalance(address: string, token: Token): Promise<TokenBalanceResult>;
getTokenBalances(address: string, tokens: Token[]): Promise<TokenBalanceResult[]>;
estimateGas(tx: Partial<IHexStrTransaction>): Promise<Wei>;
getTransactionCount(address: string): Promise<string>;
getTransactionByHash(txhash: string): Promise<TransactionData>;
getTransactionReceipt(txhash: string): Promise<TransactionReceipt>;
sendRawTx(tx: string): Promise<string>;
sendCallRequest(txObj: TxObj): Promise<string>;
getCurrentBlock(): Promise<string>;
}
};

View File

@ -1,7 +1,7 @@
import { shepherd, redux } from 'mycrypto-shepherd';
import { INode } from '.';
import { tokenBalanceHandler } from './tokenBalanceProxy';
import { IProviderConfig } from 'mycrypto-shepherd/dist/lib/ducks/providerConfigs';
import { INode } from './INode';
type DeepPartial<T> = Partial<{ [key in keyof T]: Partial<T[key]> }>;
const { selectors, store } = redux;

View File

@ -29,6 +29,10 @@ export default class RpcNode implements INode {
this.requests = new RPCRequests();
}
public getNetVersion(): Promise<string> {
return this.client.call(this.requests.getNetVersion()).then(({ result }) => result);
}
public ping(): Promise<boolean> {
return this.client
.call(this.requests.getNetVersion())
@ -42,6 +46,14 @@ export default class RpcNode implements INode {
.then(isValidCallRequest)
.then(response => response.result);
}
public sendCallRequests(txObjs: TxObj[]): Promise<string[]> {
return this.client
.batch(txObjs.map(this.requests.ethCall))
.then(r => r.map(isValidCallRequest))
.then(r => r.map(({ result }) => result));
}
public getBalance(address: string): Promise<Wei> {
return this.client
.call(this.requests.getBalance(address))

View File

@ -18,9 +18,10 @@ import {
TOMO_DEFAULT,
UBQ_DEFAULT
} from 'config/dpaths';
import { ConfigAction } from 'actions/config';
import { TypeKeys, UpdateTokensAction } from 'actions/config';
import { makeExplorer } from 'utils/helpers';
import { StaticNetworksState as State } from './types';
import { StaticNetworkConfig } from 'shared/types/network';
const testnetDefaultGasPrice = {
min: 0.1,
@ -44,6 +45,9 @@ export const INITIAL_STATE: State = {
address: ETHTokenExplorer
},
tokens: require('config/tokens/eth.json'),
updatingTokens: false,
shouldCheckForTokenUpdates: true,
tokenListHash: '',
contracts: require('config/contracts/eth.json'),
dPathFormats: {
[SecureWalletName.TREZOR]: ETH_TREZOR,
@ -64,6 +68,9 @@ export const INITIAL_STATE: State = {
origin: 'https://ropsten.etherscan.io'
}),
tokens: require('config/tokens/ropsten.json'),
updatingTokens: false,
shouldCheckForTokenUpdates: true,
tokenListHash: '',
contracts: require('config/contracts/ropsten.json'),
isTestnet: true,
dPathFormats: {
@ -84,6 +91,9 @@ export const INITIAL_STATE: State = {
origin: 'https://kovan.etherscan.io'
}),
tokens: require('config/tokens/ropsten.json'),
updatingTokens: false,
shouldCheckForTokenUpdates: true,
tokenListHash: '',
contracts: require('config/contracts/ropsten.json'),
isTestnet: true,
dPathFormats: {
@ -104,6 +114,9 @@ export const INITIAL_STATE: State = {
origin: 'https://rinkeby.etherscan.io'
}),
tokens: require('config/tokens/rinkeby.json'),
updatingTokens: false,
shouldCheckForTokenUpdates: true,
tokenListHash: '',
contracts: require('config/contracts/rinkeby.json'),
isTestnet: true,
dPathFormats: {
@ -125,6 +138,9 @@ export const INITIAL_STATE: State = {
addressPath: 'addr'
}),
tokens: require('config/tokens/etc.json'),
updatingTokens: false,
shouldCheckForTokenUpdates: true,
tokenListHash: '',
contracts: require('config/contracts/etc.json'),
dPathFormats: {
[SecureWalletName.TREZOR]: ETC_TREZOR,
@ -148,6 +164,9 @@ export const INITIAL_STATE: State = {
origin: 'https://ubiqscan.io/en'
}),
tokens: require('config/tokens/ubq.json'),
updatingTokens: false,
shouldCheckForTokenUpdates: true,
tokenListHash: '',
contracts: require('config/contracts/ubq.json'),
dPathFormats: {
[SecureWalletName.TREZOR]: UBQ_DEFAULT,
@ -171,6 +190,9 @@ export const INITIAL_STATE: State = {
origin: 'https://www.gander.tech'
}),
tokens: require('config/tokens/exp.json'),
updatingTokens: false,
shouldCheckForTokenUpdates: true,
tokenListHash: '',
contracts: require('config/contracts/exp.json'),
dPathFormats: {
[SecureWalletName.TREZOR]: EXP_DEFAULT,
@ -196,6 +218,9 @@ export const INITIAL_STATE: State = {
blockPath: 'blocks/block'
}),
tokens: [],
updatingTokens: false,
shouldCheckForTokenUpdates: false,
tokenListHash: '',
contracts: [],
dPathFormats: {
[SecureWalletName.TREZOR]: POA_DEFAULT,
@ -219,6 +244,9 @@ export const INITIAL_STATE: State = {
origin: 'https://explorer.tomocoin.io/#'
}),
tokens: [],
updatingTokens: false,
shouldCheckForTokenUpdates: false,
tokenListHash: '',
contracts: [],
dPathFormats: {
[SecureWalletName.LEDGER_NANO_S]: ETH_LEDGER,
@ -243,6 +271,9 @@ export const INITIAL_STATE: State = {
origin: 'https://explorer.ellaism.org'
}),
tokens: [],
updatingTokens: false,
shouldCheckForTokenUpdates: false,
tokenListHash: '',
contracts: [],
dPathFormats: {
[SecureWalletName.TREZOR]: ELLA_DEFAULT,
@ -256,8 +287,42 @@ export const INITIAL_STATE: State = {
}
};
export const staticNetworks = (state: State = INITIAL_STATE, action: ConfigAction) => {
function networkReducerHelper(state: State, action: UpdateTokensAction) {
const { payload } = action;
const networkId = payload.id;
const networkToUpdate = state[networkId];
return { networkId, networkToUpdate, payload };
}
export const staticNetworks = (state: State = INITIAL_STATE, action: UpdateTokensAction) => {
switch (action.type) {
case TypeKeys.CONFIG_UPDATE_TOKENS_REQUESTED: {
const { networkId, networkToUpdate } = networkReducerHelper(state, action);
const nextNetwork: StaticNetworkConfig = { ...networkToUpdate, updatingTokens: true };
return { ...state, [networkId]: nextNetwork };
}
case TypeKeys.CONFIG_UPDATE_TOKENS_SUCCEEDED: {
const { networkId, networkToUpdate } = networkReducerHelper(state, action);
const { tokens, hash } = action.payload;
const nextNetwork: StaticNetworkConfig = {
...networkToUpdate,
updatingTokens: false,
tokens,
tokenListHash: hash || networkToUpdate.tokenListHash
};
return { ...state, [networkId]: nextNetwork };
}
case TypeKeys.CONFIG_UDPATE_TOKENS_FAILED: {
const { networkId, networkToUpdate } = networkReducerHelper(state, action);
const nextNetwork: StaticNetworkConfig = { ...networkToUpdate, updatingTokens: false };
return { ...state, [networkId]: nextNetwork };
}
default:
return state;
}

View File

@ -1,9 +1,10 @@
import { network } from './network';
import { node } from './node';
import { web3 } from './web3';
import { updateTokens } from './update-tokens';
import { all } from 'redux-saga/effects';
import { SagaIterator } from 'redux-saga';
export default function*(): SagaIterator {
yield all([...network, ...node, ...web3]);
yield all([...network, ...node, ...web3, ...updateTokens]);
}

View File

@ -0,0 +1,50 @@
import { getNetworkConfig, getOffline } from 'selectors/config';
import { select, call, put, fork, takeEvery } from 'redux-saga/effects';
import { UnwrapEffects, ExtPromise } from 'shared/types/sagaHelpers';
import {
updateTokensSucceeded,
UpdateTokensRequested,
updateTokensFailed,
updateTokensRequested,
TypeKeys
} from 'actions/config';
import { updateTokensForNetwork } from 'libs/ipfs-tokens';
import { delay } from 'redux-saga';
export function* handleUpdatingTokens({ payload: { id } }: UpdateTokensRequested) {
const config: UnwrapEffects<typeof getNetworkConfig> = yield select(getNetworkConfig);
if (config.isCustom) {
return;
}
const appOffline: UnwrapEffects<typeof getOffline> = yield select(getOffline);
if (appOffline) {
return;
}
try {
const { hash, tokens }: ExtPromise<UnwrapEffects<typeof updateTokensForNetwork>> = yield call(
updateTokensForNetwork,
config
);
yield put(updateTokensSucceeded({ id, tokens, hash }));
} catch (e) {
console.error((e as Error).message);
yield put(updateTokensFailed({ id }));
}
}
export function* fireTokenUpdate() {
const config: UnwrapEffects<typeof getNetworkConfig> = yield select(getNetworkConfig);
if (config.isCustom) {
return;
}
// allow shepherdProvider async init to complete. TODO - don't export shepherdProvider as promise
yield call(delay, 300);
yield put(updateTokensRequested({ id: config.name }));
}
export const updateTokens = [
takeEvery(TypeKeys.CONFIG_UPDATE_TOKENS_REQUESTED, handleUpdatingTokens),
fork(fireTokenUpdate),
takeEvery([TypeKeys.CONFIG_NODE_CHANGE], fireTokenUpdate)
];

View File

@ -24,7 +24,8 @@ export function* handleNonceRequest(): SagaIterator {
const base10Nonce = Nonce(retrievedNonce);
yield put(inputNonce(base10Nonce.toString()));
yield put(getNonceSucceeded(retrievedNonce));
} catch {
} catch (e) {
console.error('Handle nonce request error:', e);
yield put(showNotification('warning', 'Your addresses nonce could not be fetched'));
yield put(getNonceFailed());
}

View File

@ -11,11 +11,14 @@ import {
getLanguageSelection,
getCustomNodeConfigs,
getSelectedNode,
getCustomNetworkConfigs
getCustomNetworkConfigs,
getStaticNetworkConfigs
} from 'selectors/config';
import RootReducer, { AppState } from 'reducers';
import { CustomNodeConfig } from 'types/node';
import { shepherd, makeProviderConfig, shepherdProvider, isAutoNode } from 'libs/nodes';
import { StaticNetworkConfig, StaticNetworkIds } from 'shared/types/network';
import { StaticNetworksState } from 'reducers/config/networks';
const appInitialState = RootReducer(undefined as any, { type: 'inital_state' });
type DeepPartial<T> = { [P in keyof T]?: DeepPartial<T[P]> };
@ -26,7 +29,8 @@ export function getConfigAndCustomTokensStateToSubscribe(
meta: { languageSelection: getLanguageSelection(state) },
nodes: { customNodes: getCustomNodeConfigs(state), selectedNode: getSelectedNode(state) },
networks: {
customNetworks: getCustomNetworkConfigs(state)
customNetworks: getCustomNetworkConfigs(state),
staticNetworks: getStaticNetworkConfigs(state)
}
};
@ -94,6 +98,24 @@ function rehydrateNetworks(
): ConfigState['networks'] {
const nextNetworkState = { ...initialState };
nextNetworkState.customNetworks = savedState.customNetworks;
// merge the states so that we just grab the tokenlist hash and tokens
const nextStaticNetworkState = Object.entries(savedState.staticNetworks).reduce<
StaticNetworksState
>(
(prev, [networkId, networkConfig]: [StaticNetworkIds, StaticNetworkConfig]) => {
const initialConfig = initialState.staticNetworks[networkId];
const nextConfig: StaticNetworkConfig = {
...initialConfig,
tokenListHash: networkConfig.tokenListHash,
tokens: networkConfig.tokens
};
return { ...prev, [networkId]: nextConfig };
},
{} as StaticNetworksState
);
nextNetworkState.staticNetworks = nextStaticNetworkState;
return nextNetworkState;
}

View File

@ -16,10 +16,12 @@
"bip39": "2.5.0",
"bn.js": "4.11.8",
"bootstrap-sass": "3.3.7",
"bs58": "4.0.1",
"classnames": "2.2.5",
"electron-updater": "2.21.4",
"ethereum-blockies-base64": "1.0.1",
"ethereumjs-abi": "git://github.com/ethereumjs/ethereumjs-abi.git#09c3c48fd3bed143df7fa8f36f6f164205e23796",
"ethereumjs-abi":
"git://github.com/ethereumjs/ethereumjs-abi.git#09c3c48fd3bed143df7fa8f36f6f164205e23796",
"ethereumjs-tx": "1.3.4",
"ethereumjs-util": "5.1.5",
"ethereumjs-wallet": "0.6.0",
@ -60,6 +62,7 @@
},
"devDependencies": {
"@types/bip39": "2.4.0",
"@types/bs58": "3.0.30",
"@types/classnames": "2.2.3",
"@types/enzyme": "3.1.8",
"@types/enzyme-adapter-react-16": "1.0.1",
@ -156,13 +159,19 @@
"prebuild": "check-node-version --package",
"build:downloadable": "webpack --mode=production --config webpack_config/webpack.html.js",
"prebuild:downloadable": "check-node-version --package",
"build:electron": "webpack --config webpack_config/webpack.electron-prod.js && node webpack_config/buildElectron.js",
"build:electron:osx": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=osx node webpack_config/buildElectron.js",
"build:electron:windows": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=windows node webpack_config/buildElectron.js",
"build:electron:linux": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=linux node webpack_config/buildElectron.js",
"build:electron":
"webpack --config webpack_config/webpack.electron-prod.js && node webpack_config/buildElectron.js",
"build:electron:osx":
"webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=osx node webpack_config/buildElectron.js",
"build:electron:windows":
"webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=windows node webpack_config/buildElectron.js",
"build:electron:linux":
"webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=linux node webpack_config/buildElectron.js",
"prebuild:electron": "check-node-version --package",
"jenkins:build:linux": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=JENKINS_LINUX node webpack_config/buildElectron.js",
"jenkins:build:mac": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=JENKINS_MAC node webpack_config/buildElectron.js",
"jenkins:build:linux":
"webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=JENKINS_LINUX node webpack_config/buildElectron.js",
"jenkins:build:mac":
"webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=JENKINS_MAC node webpack_config/buildElectron.js",
"jenkins:upload": "node jenkins/upload",
"test:coverage": "jest --config=jest_config/jest.config.json --coverage",
"test": "jest --config=jest_config/jest.config.json",
@ -175,13 +184,16 @@
"predev": "check-node-version --package",
"dev:https": "HTTPS=true node webpack_config/devServer.js",
"predev:https": "check-node-version --package",
"dev:electron": "concurrently --kill-others --names 'webpack,electron' 'BUILD_ELECTRON=true node webpack_config/devServer.js' 'webpack --config webpack_config/webpack.electron-dev.js && electron dist/electron-js/main.js'",
"dev:electron":
"concurrently --kill-others --names 'webpack,electron' 'BUILD_ELECTRON=true node webpack_config/devServer.js' 'webpack --config webpack_config/webpack.electron-dev.js && electron dist/electron-js/main.js'",
"tslint": "tslint --project . --exclude common/vendor/**/*",
"tscheck": "tsc --noEmit",
"start": "npm run dev",
"precommit": "lint-staged",
"formatAll": "find ./common/ -name '*.ts*' | xargs prettier --write --config ./.prettierrc --config-precedence file-override",
"prettier:diff": "prettier --write --config ./.prettierrc --list-different \"common/**/*.ts\" \"common/**/*.tsx\"",
"formatAll":
"find ./common/ -name '*.ts*' | xargs prettier --write --config ./.prettierrc --config-precedence file-override",
"prettier:diff":
"prettier --write --config ./.prettierrc --list-different \"common/**/*.ts\" \"common/**/*.tsx\"",
"prepush": "npm run tslint && npm run tscheck",
"update:tokens": "ts-node scripts/update-tokens"
},

View File

@ -1,8 +1,8 @@
import { GitCommit } from './types/GitCommit';
import { CommitStatus } from './types/CommitStatus';
import { RawTokenJSON } from './types/TokensJson';
import { GitCommit } from 'shared/types/GitCommit';
import { CommitStatus } from 'shared/types/CommitStatus';
import { RawTokenJSON } from 'shared/types/TokensJson';
const { processTokenJson } = require('./update-tokens-utils');
const { processTokenJson } = require('../shared/update-tokens-utils');
const https = require('https');
const fs = require('fs');
const path = require('path');

View File

@ -47,6 +47,9 @@ export interface GasPriceSetting {
interface StaticNetworkConfig {
isCustom: false; // used for type guards
shouldCheckForTokenUpdates: boolean;
tokenListHash: string;
updatingTokens: boolean;
name: StaticNetworkIds;
unit: string;
color?: string;

View File

@ -1,5 +1,5 @@
import { RawTokenJSON, ValidatedTokenJSON, NormalizedTokenJSON } from './types/TokensJson';
import { Token } from '../shared/types/network';
import { RawTokenJSON, ValidatedTokenJSON, NormalizedTokenJSON } from 'shared/types/TokensJson';
interface StrIdx<T> {
[key: string]: T;
}

View File

@ -43,23 +43,33 @@
core-js "^2.5.3"
regenerator-runtime "^0.11.1"
"@parity/qr-signer@0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@parity/qr-signer/-/qr-signer-0.2.0.tgz#5c6c41c03265608c117346f0a9d7ab89699352fa"
"@parity/qr-signer@0.2.1":
version "0.2.1"
resolved "https://registry.yarnpkg.com/@parity/qr-signer/-/qr-signer-0.2.1.tgz#f8b0e0ff5d8ee90b1788951c8524cdf8b1aadf27"
dependencies:
qrcode-generator "1.3.1"
react-qr-reader "2.0.1"
react-qr-reader "2.1.0"
"@sindresorhus/is@^0.7.0":
version "0.7.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd"
"@types/base-x@*":
version "1.0.29"
resolved "https://registry.yarnpkg.com/@types/base-x/-/base-x-1.0.29.tgz#8a2d73e4a5c3121757a5f8870cfa4509655186b6"
"@types/bip39@2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@types/bip39/-/bip39-2.4.0.tgz#eee31a14abc8ebbb41a1ff14575c447b18346cbc"
dependencies:
"@types/node" "*"
"@types/bs58@3.0.30":
version "3.0.30"
resolved "https://registry.yarnpkg.com/@types/bs58/-/bs58-3.0.30.tgz#916ba10992465e56f81afc735e7935fd749893e1"
dependencies:
"@types/base-x" "*"
"@types/cheerio@*":
version "0.22.7"
resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.7.tgz#4a92eafedfb2b9f4437d3a4410006d81114c66ce"
@ -1329,7 +1339,7 @@ base-x@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/base-x/-/base-x-1.1.0.tgz#42d3d717474f9ea02207f6d1aa1f426913eeb7ac"
base-x@^3.0.4:
base-x@^3.0.2, base-x@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.4.tgz#94c1788736da065edb1d68808869e357c977fa77"
dependencies:
@ -1660,6 +1670,12 @@ browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6:
caniuse-db "^1.0.30000639"
electron-to-chromium "^1.2.7"
bs58@4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a"
dependencies:
base-x "^3.0.2"
bs58@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/bs58/-/bs58-2.0.1.tgz#55908d58f1982aba2008fa1bed8f91998a29bf8d"
@ -6579,9 +6595,9 @@ jsprim@^1.2.2:
json-schema "0.2.3"
verror "1.10.0"
"jsqr@https://github.com/cozmo/jsQR.git":
jsqr@^1.0.1:
version "1.0.4"
resolved "https://github.com/cozmo/jsQR.git#d37c764bf43a41ed7c6aa1c17cbdf21b7f9cb69e"
resolved "https://registry.yarnpkg.com/jsqr/-/jsqr-1.0.4.tgz#e2ea353fa81007708efab7d95b2652a7254c10dd"
jssha@2.3.1:
version "2.3.1"
@ -7434,9 +7450,9 @@ mute-stream@0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
mycrypto-shepherd@1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/mycrypto-shepherd/-/mycrypto-shepherd-1.3.1.tgz#901d86e2278c08fd9a3a0aee7a13dea971dbbc38"
mycrypto-shepherd@1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/mycrypto-shepherd/-/mycrypto-shepherd-1.3.3.tgz#3bdefec7604f4d6f094e0282b807001d87fd98b6"
dependencies:
"@types/jest" "^22.2.2"
"@types/node" "^9.6.2"
@ -9077,17 +9093,17 @@ react-markdown@3.3.0:
unist-util-visit "^1.3.0"
xtend "^4.0.1"
react-onclickoutside@6.7.1, react-onclickoutside@^6.5.0:
react-onclickoutside@^6.5.0:
version "6.7.1"
resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.7.1.tgz#6a5b5b8b4eae6b776259712c89c8a2b36b17be93"
react-qr-reader@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/react-qr-reader/-/react-qr-reader-2.0.1.tgz#f7be785e8c880d7e68423fc129802994f70b6b58"
react-qr-reader@2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/react-qr-reader/-/react-qr-reader-2.1.0.tgz#f429c196675a710926da1cc9057223b79358da75"
dependencies:
jsqr "https://github.com/cozmo/jsQR.git"
jsqr "^1.0.1"
prop-types "^15.5.8"
webrtc-adapter "^5.0.6"
webrtc-adapter "^6.1.1"
react-reconciler@^0.7.0:
version "0.7.0"
@ -9786,7 +9802,7 @@ rst-selector-parser@^2.2.3:
lodash.flattendeep "^4.4.0"
nearley "^2.7.10"
rtcpeerconnection-shim@^1.1.13:
rtcpeerconnection-shim@^1.2.10:
version "1.2.11"
resolved "https://registry.yarnpkg.com/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.11.tgz#df2b2456020365daf26bf8c135523bca2deb252b"
dependencies:
@ -9950,10 +9966,14 @@ scss-tokenizer@^0.2.3:
js-base64 "^2.1.8"
source-map "^0.4.2"
sdp@^2.3.0, sdp@^2.6.0:
sdp@^2.6.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/sdp/-/sdp-2.7.0.tgz#02b64ea0c29d73179afa19794e466b123b1b29f3"
sdp@^2.7.0:
version "2.7.4"
resolved "https://registry.yarnpkg.com/sdp/-/sdp-2.7.4.tgz#cac76b0e2f16f55243d25bc0432f6bbb5488bfc1"
secp256k1@^3.0.1:
version "3.5.0"
resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.5.0.tgz#677d3b8a8e04e1a5fa381a1ae437c54207b738d0"
@ -11803,12 +11823,12 @@ webpack@4.5.0:
watchpack "^1.5.0"
webpack-sources "^1.0.1"
webrtc-adapter@^5.0.6:
version "5.0.6"
resolved "https://registry.yarnpkg.com/webrtc-adapter/-/webrtc-adapter-5.0.6.tgz#7946fca194dadf869bb6c8cae1011dfda03f40c7"
webrtc-adapter@^6.1.1:
version "6.1.5"
resolved "https://registry.yarnpkg.com/webrtc-adapter/-/webrtc-adapter-6.1.5.tgz#df72e4af5cb6675656c896db0d1187695359220b"
dependencies:
rtcpeerconnection-shim "^1.1.13"
sdp "^2.3.0"
rtcpeerconnection-shim "^1.2.10"
sdp "^2.7.0"
what-input@5.0.5:
version "5.0.5"