Resolve custom token conflicts (#767)

* Remove custom token if it conflicts with symbol or address.

* Refactor deduping to utils function. Add unit tests for said function.

* Fix tscheck
This commit is contained in:
William O'Beirne 2018-01-11 01:50:31 -05:00 committed by Daniel Ternyak
parent 7d2c3e1990
commit 418b186642
3 changed files with 74 additions and 2 deletions

View File

@ -19,6 +19,7 @@ import RootReducer from './reducers';
import promiseMiddleware from 'redux-promise-middleware';
import { getNodeConfigFromId } from 'utils/node';
import { getNetworkConfigFromId } from 'utils/network';
import { dedupeCustomTokens } from 'utils/tokens';
import sagas from './sagas';
import { gasPricetoBase } from 'libs/units';
@ -59,7 +60,6 @@ const configureStore = () => {
}
: { ...swapInitialState };
const localCustomTokens = loadStatePropertyOrEmptyObject<CustomTokenState>('customTokens');
const savedTransactionState = loadStatePropertyOrEmptyObject<TransactionState>('transaction');
const savedConfigState = loadStatePropertyOrEmptyObject<ConfigState>('config');
@ -82,6 +82,13 @@ const configureStore = () => {
}
}
// Dedupe custom tokens initially
const savedCustomTokensState =
loadStatePropertyOrEmptyObject<CustomTokenState>('customTokens') || customTokensInitialState;
const initialNetwork =
(savedConfigState && savedConfigState.network) || configInitialState.network;
const customTokens = dedupeCustomTokens(initialNetwork.tokens, savedCustomTokensState);
const persistedInitialState = {
config: {
...configInitialState,
@ -100,7 +107,7 @@ const configureStore = () => {
: transactionInitialState.fields.gasPrice
}
},
customTokens: localCustomTokens || customTokensInitialState,
customTokens,
// ONLY LOAD SWAP STATE FROM LOCAL STORAGE IF STEP WAS 3
swap: swapState
};

18
common/utils/tokens.ts Normal file
View File

@ -0,0 +1,18 @@
import { Token } from 'config/data';
export function dedupeCustomTokens(networkTokens: Token[], customTokens: Token[]): Token[] {
if (!customTokens.length) {
return [];
}
// If any tokens have the same symbol or contract address, remove them
const tokenCollisionMap = networkTokens.reduce((prev, token) => {
prev[token.symbol] = true;
prev[token.address] = true;
return prev;
}, {});
return customTokens.filter(token => {
return !tokenCollisionMap[token.address] && !tokenCollisionMap[token.symbol];
});
}

47
spec/utils/tokens.spec.ts Normal file
View File

@ -0,0 +1,47 @@
import { dedupeCustomTokens } from 'utils/tokens';
describe('dedupeCustomTokens', () => {
const networkTokens = [
{
address: '0x48c80F1f4D53D5951e5D5438B54Cba84f29F32a5',
symbol: 'REP',
decimal: 18
},
{
address: '0xa74476443119A942dE498590Fe1f2454d7D4aC0d',
symbol: 'GNT',
decimal: 18
}
];
const DUPLICATE_ADDRESS = {
address: networkTokens[0].address,
symbol: 'REP2',
decimal: 18
};
const DUPLICATE_SYMBOL = {
address: '0x0',
symbol: networkTokens[1].symbol,
decimal: 18
};
const NONDUPLICATE_CUSTOM = {
address: '0x7cB57B5A97eAbe94205C07890BE4c1aD31E486A8',
symbol: 'MEW',
decimal: 0
};
const customTokens = [DUPLICATE_ADDRESS, DUPLICATE_SYMBOL, NONDUPLICATE_CUSTOM];
const dedupedTokens = dedupeCustomTokens(networkTokens, customTokens);
it('Should remove duplicate address custom tokens', () => {
expect(dedupedTokens.includes(DUPLICATE_ADDRESS)).toBeFalsy();
});
it('Should remove duplicate symbol custom tokens', () => {
expect(dedupedTokens.includes(DUPLICATE_SYMBOL)).toBeFalsy();
});
it('Should not remove custom tokens that arent duplicates', () => {
expect(dedupedTokens.includes(NONDUPLICATE_CUSTOM)).toBeTruthy();
});
});