Skip to content

Commit

Permalink
feat(suite-native): token definitions redux logic (#11318)
Browse files Browse the repository at this point in the history
Closes #8434
  • Loading branch information
PeKne authored Feb 27, 2024
1 parent e43684a commit 7e77f60
Show file tree
Hide file tree
Showing 21 changed files with 229 additions and 66 deletions.
4 changes: 1 addition & 3 deletions packages/suite-desktop/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./libDev"
},
"compilerOptions": { "outDir": "./libDev" },
"include": ["./src", "./e2e", "**/*.json"],
"references": []
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ export const TxDetailModal = ({ tx, rbfForm, onCancel }: TxDetailModalProps) =>
);
const account = useSelector(state => selectAccountByKey(state, accountKey));
const network = account && getAccountNetwork(account);
const isPhishingTransaction = useSelector(state => selectIsPhishingTransaction(state, tx));
const isPhishingTransaction = useSelector(state =>
selectIsPhishingTransaction(state, tx.txid, accountKey),
);

return (
<StyledModal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export const TransactionItem = memo(
);
};
const isPhishingTransaction = useSelector(state =>
selectIsPhishingTransaction(state, transaction),
selectIsPhishingTransaction(state, transaction.txid, accountKey),
);

const dataTestBase = `@transaction-item/${index}${
Expand Down
1 change: 1 addition & 0 deletions suite-common/wallet-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ export * from './token-definitions/tokenDefinitionsSelectors';
export * from './token-definitions/tokenDefinitionsReducer';
export * from './token-definitions/tokenDefinitionsThunks';
export * from './token-definitions/tokenDefinitionsMiddleware';
export * from './token-definitions/tokenDefinitionsTypes';
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { NetworkSymbol } from '@suite-common/wallet-config';
import { D, pipe } from '@mobily/ts-belt';

import { NetworkSymbol, isEthereumBasedNetwork, networks } from '@suite-common/wallet-config';

import { TokenDefinitionsRootState } from './tokenDefinitionsTypes';

Expand All @@ -12,3 +14,27 @@ export const selectSpecificTokenDefinition = (
networkSymbol: NetworkSymbol,
contractAddress: string,
) => state.wallet.tokenDefinitions?.[networkSymbol]?.[contractAddress];

export const selectShouldFetchTokenDefinition = (
state: TokenDefinitionsRootState,
networkSymbol: NetworkSymbol,
contractAddress: string,
) => {
const tokenDefinition = selectSpecificTokenDefinition(state, networkSymbol, contractAddress);
const network = networks[networkSymbol];

return isEthereumBasedNetwork(network) && (!tokenDefinition || tokenDefinition.error);
};

export const selectKnownNetworkTokens = (
state: TokenDefinitionsRootState,
networkSymbol: NetworkSymbol,
) => {
const networkTokenDefinitions = selectTokenDefinitions(state, networkSymbol);

return pipe(
networkTokenDefinitions,
D.filter(tokenDefinition => !!tokenDefinition.isTokenKnown),
D.keys,
);
};
12 changes: 2 additions & 10 deletions suite-common/wallet-core/src/transactions/transactionsReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
findTransaction,
getConfirmations,
isPending,
getIsZeroValuePhishing,
getIsPhishingTransaction,
} from '@suite-common/wallet-utils';
import { createReducerWithExtraDeps } from '@suite-common/redux-utils';
Expand Down Expand Up @@ -288,22 +287,15 @@ export const selectTransactionConfirmations = (
return getConfirmations(transaction, blockchainHeight);
};

export const selectIsTransactionZeroValuePhishing = (
state: TransactionsRootState,
export const selectIsPhishingTransaction = (
state: TokenDefinitionsRootState & TransactionsRootState,
txid: string,
accountKey: AccountKey,
) => {
const transaction = selectTransactionByTxidAndAccountKey(state, txid, accountKey);

if (!transaction) return false;

return getIsZeroValuePhishing(transaction);
};

export const selectIsPhishingTransaction = (
state: TokenDefinitionsRootState,
transaction: WalletAccountTransaction,
) => {
const tokenDefinitions = selectTokenDefinitions(state, transaction.symbol);

if (!tokenDefinitions) return false;
Expand Down
45 changes: 22 additions & 23 deletions suite-native/fiat-rates/src/fiatRatesMiddleware.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { isAnyOf } from '@reduxjs/toolkit';

import { createMiddlewareWithExtraDeps } from '@suite-common/redux-utils';
import { transactionsActions, accountsActions, blockchainActions } from '@suite-common/wallet-core';
import {
transactionsActions,
accountsActions,
blockchainActions,
getTokenDefinitionThunk,
} from '@suite-common/wallet-core';
import { TokenAddress } from '@suite-common/wallet-types';

import {
Expand Down Expand Up @@ -29,28 +34,6 @@ export const prepareFiatRatesMiddleware = createMiddlewareWithExtraDeps(
);
}

// Fetch fiat rates for all tokens of newly discovered ETH account.
if (
accountsActions.createIndexLabeledAccount.match(action) &&
action.payload.symbol === 'eth'
) {
const localCurrency = selectLocalCurrency(getState());

const { tokens } = action.payload;
tokens?.forEach(token => {
dispatch(
updateFiatRatesThunk({
ticker: {
symbol: 'eth',
tokenAddress: token.contract as TokenAddress,
},
rateType: 'current',
localCurrency,
}),
);
});
}

if (transactionsActions.addTransaction.match(action)) {
// fetch historical rates for each added transaction
const { account, transactions } = action.payload;
Expand Down Expand Up @@ -83,6 +66,22 @@ export const prepareFiatRatesMiddleware = createMiddlewareWithExtraDeps(
);
}

// If there is a new valid token present, download its fiat rates.
if (getTokenDefinitionThunk.fulfilled.match(action)) {
const { networkSymbol, contractAddress } = action.meta.arg;
const localCurrency = selectLocalCurrency(getState());
dispatch(
updateFiatRatesThunk({
ticker: {
symbol: networkSymbol,
tokenAddress: contractAddress as TokenAddress,
},
rateType: 'current',
localCurrency,
}),
);
}

return next(action);
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
AccountsRootState,
selectAccountsByNetworkAndDeviceState,
PORTFOLIO_TRACKER_DEVICE_STATE,
selectKnownNetworkTokens,
} from '@suite-common/wallet-core';
import { Box, Button, Divider, VStack } from '@suite-native/atoms';
import { useAccountLabelForm, AccountFormValues } from '@suite-native/accounts';
Expand All @@ -26,6 +27,7 @@ import { TokenAddress, TokenInfoBranded, TokenSymbol } from '@suite-common/walle
import { selectAnyOfTokensHasFiatRates } from '@suite-native/ethereum-tokens';
import { FiatRatesRootState } from '@suite-native/fiat-rates';
import { SettingsSliceRootState } from '@suite-native/module-settings';
import { TokenDefinitionsRootState } from '@suite-common/wallet-core/src/token-definitions/tokenDefinitionsTypes';

import { importAccountThunk } from '../accountsImportThunks';
import { AccountImportOverview } from './AccountImportOverview';
Expand Down Expand Up @@ -56,6 +58,14 @@ export const AccountImportSummaryForm = ({
const navigation = useNavigation<NavigationProp>();
const showImportError = useShowImportError(networkSymbol, navigation);

const areTokensDisplayed = useSelector((state: SettingsSliceRootState & FiatRatesRootState) =>
selectAnyOfTokensHasFiatRates(state, (accountInfo?.tokens as TokenInfoBranded[]) ?? []),
);

const knownTokens = useSelector((state: TokenDefinitionsRootState) =>
selectKnownNetworkTokens(state, networkSymbol),
);

const deviceNetworkAccounts = useSelector((state: AccountsRootState) =>
selectAccountsByNetworkAndDeviceState(state, PORTFOLIO_TRACKER_DEVICE_STATE, networkSymbol),
);
Expand All @@ -80,14 +90,16 @@ export const AccountImportSummaryForm = ({
}),
).unwrap();

// Report to analytics only those tokens that are known.
const validTokens =
accountInfo.tokens?.filter(({ contract }) => knownTokens.includes(contract)) ?? [];

analytics.report({
type: EventType.AssetsSync,
payload: {
assetSymbol: networkSymbol,
tokenSymbols: accountInfo?.tokens?.map(token => token.symbol as TokenSymbol),
tokenAddresses: accountInfo?.tokens?.map(
token => token.contract as TokenAddress,
),
tokenSymbols: validTokens.map(token => token.symbol as TokenSymbol),
tokenAddresses: validTokens.map(token => token.contract as TokenAddress),
},
});

Expand All @@ -109,10 +121,6 @@ export const AccountImportSummaryForm = ({
}
});

const areTokensDisplayed = useSelector((state: SettingsSliceRootState & FiatRatesRootState) =>
selectAnyOfTokensHasFiatRates(state, (accountInfo?.tokens as TokenInfoBranded[]) ?? []),
);

return (
<Form form={form}>
<VStack spacing="large">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
StackToStackCompositeScreenProps,
} from '@suite-native/navigation';
import TrezorConnect, { AccountInfo } from '@trezor/connect';
import { TokenAddress } from '@suite-common/wallet-types';
import { getTokenDefinitionThunk } from '@suite-common/wallet-core';
import { networks } from '@suite-common/wallet-config';

import { AccountImportLoader } from '../components/AccountImportLoader';
import { useShowImportError } from '../useShowImportError';
Expand Down Expand Up @@ -85,18 +86,15 @@ export const AccountImportLoadingScreen = ({
if (!ignore) {
if (fetchedAccountInfo?.success) {
if (networkSymbol === 'eth') {
fetchedAccountInfo.payload.tokens?.forEach(token => {
fetchedAccountInfo.payload.tokens?.forEach(token =>
dispatch(
updateFiatRatesThunk({
ticker: {
symbol: 'eth',
tokenAddress: token.contract as TokenAddress,
},
rateType: 'current',
localCurrency: fiatCurrency,
getTokenDefinitionThunk({
networkSymbol: 'eth',
chainId: networks.eth.chainId,
contractAddress: token.contract,
}),
);
});
),
);
}
setAccountInfo(fetchedAccountInfo.payload);
} else {
Expand Down
1 change: 1 addition & 0 deletions suite-native/state/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@suite-native/module-settings": "workspace:*",
"@suite-native/storage": "workspace:*",
"@suite-native/toasts": "workspace:*",
"@suite-native/token-definitions": "workspace:*",
"@trezor/connect": "workspace:*",
"@trezor/transport-native": "workspace:*",
"@trezor/utils": "workspace:*",
Expand Down
3 changes: 3 additions & 0 deletions suite-native/state/src/reducers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
prepareBlockchainReducer,
prepareDeviceReducer,
prepareDiscoveryReducer,
prepareTokenDefinitionsReducer,
prepareTransactionsReducer,
} from '@suite-common/wallet-core';
import { prepareFiatRatesReducer } from '@suite-native/fiat-rates';
Expand Down Expand Up @@ -36,6 +37,7 @@ const analyticsReducer = prepareAnalyticsReducer(extraDependencies);
const messageSystemReducer = prepareMessageSystemReducer(extraDependencies);
const deviceReducer = prepareDeviceReducer(extraDependencies);
const discoveryReducer = prepareDiscoveryReducer(extraDependencies);
const tokenDefinitionsReducer = prepareTokenDefinitionsReducer(extraDependencies);

export const prepareRootReducers = async () => {
const appSettingsPersistedReducer = await preparePersistReducer({
Expand All @@ -51,6 +53,7 @@ export const prepareRootReducers = async () => {
fiat: fiatRatesReducer,
transactions: transactionsReducer,
discovery: discoveryReducer,
tokenDefinitions: tokenDefinitionsReducer,
});

const walletPersistedReducer = await preparePersistReducer({
Expand Down
2 changes: 2 additions & 0 deletions suite-native/state/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { prepareButtonRequestMiddleware, prepareDeviceMiddleware } from '@suite-
import { prepareDiscoveryMiddleware } from '@suite-native/discovery';
import { prepareTransactionCacheMiddleware } from '@suite-native/accounts';
import { blockchainMiddleware } from '@suite-native/blockchain';
import { tokenDefinitionsMiddleware } from '@suite-native/token-definitions';

import { extraDependencies } from './extraDependencies';
import { prepareRootReducers } from './reducers';
Expand All @@ -18,6 +19,7 @@ const middlewares: Middleware[] = [
prepareButtonRequestMiddleware(extraDependencies),
prepareDiscoveryMiddleware(extraDependencies),
prepareTransactionCacheMiddleware(extraDependencies),
tokenDefinitionsMiddleware,
];

if (__DEV__) {
Expand Down
1 change: 1 addition & 0 deletions suite-native/state/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
{ "path": "../module-settings" },
{ "path": "../storage" },
{ "path": "../toasts" },
{ "path": "../token-definitions" },
{ "path": "../../packages/connect" },
{
"path": "../../packages/transport-native"
Expand Down
18 changes: 18 additions & 0 deletions suite-native/token-definitions/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "@suite-native/token-definitions",
"version": "1.0.0",
"private": true,
"license": "See LICENSE.md in repo root",
"sideEffects": false,
"main": "src/index",
"scripts": {
"lint:js": "yarn g:eslint '**/*.{ts,tsx,js}'",
"type-check": "yarn g:tsc --build"
},
"dependencies": {
"@reduxjs/toolkit": "1.9.5",
"@suite-common/redux-utils": "workspace:*",
"@suite-common/wallet-config": "workspace:*",
"@suite-common/wallet-core": "workspace:*"
}
}
1 change: 1 addition & 0 deletions suite-native/token-definitions/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './tokenDefinitionsMiddleware';
Loading

0 comments on commit 7e77f60

Please sign in to comment.